UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

160 lines (156 loc) 6.89 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import { createElement } from 'react'; import { bind } from 'bind-event-listener'; import ReactDOM from 'react-dom'; // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead import uuid from 'uuid'; import { Decoration } from '@atlaskit/editor-prosemirror/view'; import { fg } from '@atlaskit/platform-feature-flags'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; import { DragHandle, DragHandleWithVisibility } from '../ui/drag-handle'; import { TYPE_HANDLE_DEC, TYPE_NODE_DEC, unmountDecorations } from './decorations-common'; import { getActiveBlockMarks, getMatchingBlockMarks } from './utils/marks'; export var emptyParagraphNodeDecorations = function emptyParagraphNodeDecorations() { var anchorName = "--node-anchor-paragraph-0"; var style = "anchor-name: ".concat(anchorName, "; margin-top: 0px;"); return Decoration.node(0, 2, _defineProperty({ style: style }, 'data-drag-handler-anchor-name', anchorName), { type: TYPE_NODE_DEC }); }; export var findHandleDec = function findHandleDec(decorations, from, to) { return decorations.find(from, to, function (spec) { return spec.type === TYPE_HANDLE_DEC; }); }; export var dragHandleDecoration = function dragHandleDecoration(_ref) { var api = _ref.api, formatMessage = _ref.formatMessage, pos = _ref.pos, anchorName = _ref.anchorName, nodeType = _ref.nodeType, nodeViewPortalProviderAPI = _ref.nodeViewPortalProviderAPI, handleOptions = _ref.handleOptions, anchorRectCache = _ref.anchorRectCache, editorState = _ref.editorState; unmountDecorations(nodeViewPortalProviderAPI, 'data-blocks-drag-handle-container', 'data-blocks-drag-handle-key'); var unbind; // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead var key = uuid(); var widgetSpec = editorExperiment('platform_editor_breakout_resizing', true) ? { side: -1, type: TYPE_HANDLE_DEC, // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead testid: "".concat(TYPE_HANDLE_DEC, "-").concat(uuid()), /** * sigh - `marks` influences the position that the widget is drawn (as described on the `side` property). * Exclude 'breakout' on purpose, so the widgets render at the top of the document to avoid z-index issues * Other block marks must be added, otherwise PM will split the DOM elements causing mutations and re-draws */ marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, pos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : expValEquals('platform_editor_clean_up_widget_mark_logic', 'isEnabled', true) ? [] : getActiveBlockMarks(editorState, pos), destroy: function destroy(node) { unbind && unbind(); } } : { side: -1, type: TYPE_HANDLE_DEC, // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead testid: "".concat(TYPE_HANDLE_DEC, "-").concat(uuid()), marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, pos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : expValEquals('platform_editor_clean_up_widget_mark_logic', 'isEnabled', true) ? [] : expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? getActiveBlockMarks(editorState, pos) : undefined, destroy: function destroy(node) { unbind && unbind(); } }; return Decoration.widget(pos, function (view, getPosUnsafe) { var element = document.createElement('span'); // inline decoration causes focus issues when refocusing Editor into first line element.style.display = 'block'; if (fg('confluence_remix_button_right_side_block_fg')) { element.setAttribute('data-blocks-decorator-widget', 'true'); } element.setAttribute('data-testid', 'block-ctrl-decorator-widget'); element.setAttribute('data-blocks-drag-handle-container', 'true'); element.setAttribute('data-blocks-drag-handle-key', key); var isTopLevelNode = true; var getPos = function getPos() { try { return getPosUnsafe(); } catch (_unused) { // Ignore errors from getPosUnsafe return undefined; } }; var newPos = getPos(); if (typeof newPos === 'number') { var $pos = view.state.doc.resolve(newPos); isTopLevelNode = ($pos === null || $pos === void 0 ? void 0 : $pos.parent.type.name) === 'doc'; } /* * We disable mouseover event to fix flickering issue on hover * However, the tooltip for nested drag handle is no long working. */ if (newPos === undefined || !isTopLevelNode) { if (fg('platform_editor_fix_widget_destroy')) { element.onmouseover = function (e) { e.stopPropagation(); }; } else { unbind = bind(element, { type: 'mouseover', listener: function listener(e) { e.stopPropagation(); } }); } } // There are times when global clear: "both" styles are applied to this decoration causing jumpiness // due to margins applied to other nodes eg. Headings element.style.clear = 'unset'; // temporarily re-instating ReactDOM.render to fix drag handle focus issue, fix to // follow via ED-26546 // previous under platform_editor_react18_plugin_portalprovider // nodeViewPortalProviderAPI.render( // () => // createElement(DragHandle, { // view, // api, // formatMessage, // getPos, // anchorName, // nodeType, // handleOptions, // isTopLevelNode, // }), // element, // key, // ); if (editorExperiment('platform_editor_controls', 'variant1')) { ReactDOM.render( /*#__PURE__*/createElement(DragHandleWithVisibility, { view: view, api: api, formatMessage: formatMessage, getPos: getPos, anchorName: anchorName, nodeType: nodeType, handleOptions: handleOptions, isTopLevelNode: isTopLevelNode, anchorRectCache: anchorRectCache }), element); } else { ReactDOM.render( /*#__PURE__*/createElement(DragHandle, { view: view, api: api, formatMessage: formatMessage, getPos: getPos, anchorName: anchorName, nodeType: nodeType, handleOptions: handleOptions, isTopLevelNode: isTopLevelNode, anchorRectCache: anchorRectCache }), element); } return element; }, widgetSpec); };