UNPKG

@atlaskit/editor-plugin-synced-block

Version:

SyncedBlock plugin for @atlaskit/editor-core

145 lines (142 loc) • 9.52 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.SyncBlockRendererWrapper = void 0; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _react = _interopRequireWildcard(require("react")); var _bindEventListener = require("bind-event-listener"); var _syncBlock = require("@atlaskit/editor-common/sync-block"); var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider"); var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled"); var _getUnpublishedSourceType = require("./getUnpublishedSourceType"); var _SyncBlockLabel = require("./SyncBlockLabel"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } var SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper'; var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperComponent(_ref) { var _api$analytics, _syncBlockFetchResult, _syncBlockFetchResult2, _syncBlockFetchResult3, _syncBlockFetchResult4, _localSourceInfo$sour, _syncBlockFetchResult5, _localSourceInfo$prod; var syncedBlockRenderer = _ref.syncedBlockRenderer, syncBlockStore = _ref.syncBlockStore, node = _ref.node, resourceId = _ref.resourceId, localId = _ref.localId, api = _ref.api; var isSamePageSyncEnabled = (0, _isExperimentEnabled.isExperimentEnabled)('editor-synced-block-same-page-sync'); var syncBlockFetchResult = (0, _editorSyncedBlockProvider.useFetchSyncBlockData)(syncBlockStore, resourceId, localId, api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 ? void 0 : _api$analytics.fireAnalyticsEvent); var title = (0, _editorSyncedBlockProvider.useFetchSyncBlockTitle)(syncBlockStore, node); var contentUpdatedAt = syncBlockFetchResult === null || syncBlockFetchResult === void 0 || (_syncBlockFetchResult = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult === void 0 || (_syncBlockFetchResult = _syncBlockFetchResult.data) === null || _syncBlockFetchResult === void 0 ? void 0 : _syncBlockFetchResult.contentUpdatedAt; var isUnpublishedBlock = ((_syncBlockFetchResult2 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult2 === void 0 || (_syncBlockFetchResult2 = _syncBlockFetchResult2.data) === null || _syncBlockFetchResult2 === void 0 ? void 0 : _syncBlockFetchResult2.status) === 'unpublished'; var localSameDocumentSource = isSamePageSyncEnabled ? (_syncBlockFetchResult3 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult3 === void 0 ? void 0 : _syncBlockFetchResult3.localSameDocumentSource : undefined; var localSourceBlockInstanceId = localSameDocumentSource === null || localSameDocumentSource === void 0 ? void 0 : localSameDocumentSource.sourceBlockInstanceId; var _useState = (0, _react.useState)(), _useState2 = (0, _slicedToArray2.default)(_useState, 2), localSourceInfo = _useState2[0], setLocalSourceInfo = _useState2[1]; (0, _react.useEffect)(function () { var _syncBlockStore$sourc; var isMounted = true; if (!localSourceBlockInstanceId) { setLocalSourceInfo(undefined); return; } void ((_syncBlockStore$sourc = syncBlockStore.sourceManager) === null || _syncBlockStore$sourc === void 0 ? void 0 : _syncBlockStore$sourc.getSyncBlockSourceInfo(localSourceBlockInstanceId).then(function (sourceInfo) { if (isMounted) { setLocalSourceInfo(sourceInfo); } })); return function () { isMounted = false; }; }, [localSourceBlockInstanceId, syncBlockStore.sourceManager]); var isUnsyncedBlock = isUnpublishedBlock && !localSameDocumentSource || (syncBlockFetchResult === null || syncBlockFetchResult === void 0 || (_syncBlockFetchResult4 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult4 === void 0 || (_syncBlockFetchResult4 = _syncBlockFetchResult4.error) === null || _syncBlockFetchResult4 === void 0 ? void 0 : _syncBlockFetchResult4.type) === _editorSyncedBlockProvider.SyncBlockError.NotFound; // Prevent editing in the contentEditable renderer wrapper. We set // contentEditable="true" to enable text selection (creating an editable // island inside ProseMirror's contentEditable="false" nodeview wrapper), // but users must not be able to type into or modify the renderer content. var preventInput = (0, _react.useCallback)(function (e) { e.preventDefault(); }, []); // Browsers suppress link navigation on a plain click inside a // contentEditable region (they place the caret instead), which breaks links // rendered in the content — e.g. the "when the page is published" link in // the unpublished error card. Re-trigger navigation for _blank anchors // ourselves. A native listener (rather than an onClick on the div) is used // so we delegate link clicks without making the container itself interactive. var rendererRef = (0, _react.useRef)(null); var preventReferenceEditing = (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_blocks_patch_11'); (0, _react.useEffect)(function () { var container = rendererRef.current; if (!preventReferenceEditing || !container) { return; } return (0, _bindEventListener.bind)(container, { // Block native edits without intercepting ProseMirror's node deletion. type: 'beforeinput', listener: function listener(event) { return event.preventDefault(); } }); }, [preventReferenceEditing]); (0, _react.useEffect)(function () { var containerEl = rendererRef.current; if (!containerEl) { return; } var unbind = (0, _bindEventListener.bind)(containerEl, { type: 'click', listener: function listener(e) { // Let the browser handle modified/non-primary clicks (open-in-new-tab, // etc.) natively so we don't open a second tab on top of it. if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) { return; } var target = e.target instanceof Element ? e.target : null; var anchor = target === null || target === void 0 ? void 0 : target.closest('a[href]'); if (!(anchor instanceof HTMLAnchorElement) || e.defaultPrevented || anchor.target !== '_blank') { return; } window.open(anchor.href, '_blank', 'noopener,noreferrer'); } }); return unbind; }, []); return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", { ref: rendererRef, "data-testid": SyncBlockRendererWrapperDataId // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop , className: _syncBlock.SyncBlockSharedCssClassName.renderer, contentEditable: true, suppressContentEditableWarning: true // Prevent the contentEditable div from being keyboard-focusable. // It is only used to enable text selection, not as an input target. // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex , tabIndex: -1, onBeforeInput: preventInput, onPaste: preventInput // eslint-disable-next-line @atlaskit/design-system/no-direct-use-of-web-platform-drag-and-drop , onDrop: preventInput }, syncedBlockRenderer({ syncBlockFetchResult: syncBlockFetchResult, api: api, localId: localId })), /*#__PURE__*/_react.default.createElement(_SyncBlockLabel.SyncBlockLabel, { isSource: false, title: title, contentUpdatedAt: contentUpdatedAt, localId: localId, isUnsyncedBlock: isUnsyncedBlock, unpublishedInfo: localSameDocumentSource && isUnpublishedBlock ? { sourceType: (0, _getUnpublishedSourceType.getUnpublishedSourceType)({ sourceAri: (_localSourceInfo$sour = localSourceInfo === null || localSourceInfo === void 0 ? void 0 : localSourceInfo.sourceAri) !== null && _localSourceInfo$sour !== void 0 ? _localSourceInfo$sour : (_syncBlockFetchResult5 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult5 === void 0 || (_syncBlockFetchResult5 = _syncBlockFetchResult5.data) === null || _syncBlockFetchResult5 === void 0 ? void 0 : _syncBlockFetchResult5.sourceAri, sourceProduct: (_localSourceInfo$prod = localSourceInfo === null || localSourceInfo === void 0 ? void 0 : localSourceInfo.productType) !== null && _localSourceInfo$prod !== void 0 ? _localSourceInfo$prod : localSameDocumentSource.sourceProduct }), variant: 'local-reference' } : undefined })); }; var SyncBlockRendererWrapper = exports.SyncBlockRendererWrapper = /*#__PURE__*/_react.default.memo(SyncBlockRendererWrapperComponent);