UNPKG

@atlaskit/editor-plugin-quick-insert

Version:

Quick insert plugin for @atlaskit/editor-core

186 lines (185 loc) • 8.52 kB
/* BlockControlQuickInsertButton.tsx generated by @compiled/babel-plugin v3.0.2 */ import "./BlockControlQuickInsertButton.compiled.css"; import { ax, ix } from "@compiled/react/runtime"; import React, { useCallback } from 'react'; import { useIntl } from 'react-intl'; import { ToolTipContent } from '@atlaskit/editor-common/keymaps'; import { messages } from '@atlaskit/editor-common/messages/block-controls'; import { isEmptyNode } from '@atlaskit/editor-common/utils'; import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state'; import { findParentNode, findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils'; import { CellSelection } from '@atlaskit/editor-tables/cell-selection'; import AddIcon from '@atlaskit/icon/core/add'; import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled'; import { Pressable } from '@atlaskit/primitives/compiled/pressable'; import Tooltip from '@atlaskit/tooltip/Tooltip'; var TEXT_PARENT_TYPES = ['paragraph', 'heading', 'blockquote', 'taskItem', 'decisionItem']; // @atlaskit/css intentionally restricts height and width values, so Compiled owns only the // dimensions that scale at runtime with the editor's dense-mode font-size custom property. var quickInsertButtonContainerStyles = { root: "_1e0c1txw _4t3i9xsi _1bsb9xsi", reservedDragHandleSpace: "_12l21xcw" }; var quickInsertButtonStyles = { root: "_19itglyw _2rko1rr0 _v564k6bl _1rjcze3t _18zrze3t _4cvr1h6o _bfhksm61 _vchhusvi _syazazsu _80omtlke _1e0c1txw _4t3i1osq _1bah1h6o _1bsb1osq _mizu1v1w _1ah3v77o _ra3xnqa1 _128mdkaa _irr31dpa _1ggl5xtf _1di6fcek" }; var createNewLine = function createNewLine(start) { return function (_ref) { var _tr$doc$nodeAt; var tr = _ref.tr; var nodeSize = (_tr$doc$nodeAt = tr.doc.nodeAt(start)) === null || _tr$doc$nodeAt === void 0 ? void 0 : _tr$doc$nodeAt.nodeSize; if (nodeSize === undefined) { return tr; } var position = start + nodeSize; tr.insert(position, tr.doc.type.schema.nodes.paragraph.create()); return tr.setSelection(TextSelection.near(tr.doc.resolve(position))); }; }; var isSelectionInNode = function isSelectionInNode(start, view) { var node = view.state.doc.nodeAt(start); if (!node) { return false; } var _view$state$selection = view.state.selection, $from = _view$state$selection.$from, $to = _view$state$selection.$to; return $from.pos >= start && $to.pos <= start + node.nodeSize; }; var isNonEditableBlock = function isNonEditableBlock(start, view) { var node = view.state.doc.nodeAt(start); if (!node) { return false; } if (node.type.name === 'mediaGroup' || node.type.name === 'mediaSingle') { return true; } return node.isBlock && (node.isAtom || node.isLeaf); }; var getNextEmptyParagraphPosition = function getNextEmptyParagraphPosition(start, view) { var node = view.state.doc.nodeAt(start); if (!node) { return undefined; } var positionAfterTarget = start + node.nodeSize; var nextNode = view.state.doc.resolve(positionAfterTarget).nodeAfter; if ((nextNode === null || nextNode === void 0 ? void 0 : nextNode.type) !== view.state.schema.nodes.paragraph || nextNode.marks.length > 0) { return undefined; } if (!isEmptyNode(view.state.schema)(nextNode)) { return undefined; } return positionAfterTarget + 1; }; var openQuickInsert = function openQuickInsert(api, view, start, openTypeAhead) { var isSelectionInsideNode = isSelectionInNode(start, view); var shouldCreateNewLine = !isSelectionInsideNode || isNonEditableBlock(start, view); var reusableParagraphPosition = shouldCreateNewLine && isExperimentEnabled('platform_editor_block_control_inp') ? getNextEmptyParagraphPosition(start, view) : undefined; if (shouldCreateNewLine && reusableParagraphPosition === undefined) { api.core.actions.execute(createNewLine(start)); } else if (reusableParagraphPosition !== undefined && // Only skip when the cursor is already collapsed in the reused paragraph. A range selection // that merely starts there must still be collapsed, otherwise opening the typeahead deletes // the selected content (openTypeAheadAtCursor calls deleteSelection for non-cursor ranges). !(view.state.selection.empty && view.state.selection.from === reusableParagraphPosition)) { api.core.actions.execute(function (_ref2) { var tr = _ref2.tr; tr.setSelection(TextSelection.create(tr.doc, reusableParagraphPosition)); return tr; }); } var codeBlock = view.state.schema.nodes.codeBlock; var selection = view.state.selection; var codeBlockParentNode = findParentNodeOfType(codeBlock)(selection); if (codeBlockParentNode) { api.core.actions.execute(createNewLine(codeBlockParentNode.pos)); } else if (isSelectionInsideNode && reusableParagraphPosition === undefined) { var currentSelection = view.state.selection; if ((currentSelection instanceof TextSelection || currentSelection instanceof NodeSelection && currentSelection.node.isInline) && currentSelection.from !== currentSelection.to) { var currentParagraphNode = findParentNode(function (node) { return TEXT_PARENT_TYPES.includes(node.type.name); })(currentSelection); if (currentParagraphNode) { var newPos = currentSelection.anchor === currentSelection.to ? currentParagraphNode.pos : currentParagraphNode.pos + currentParagraphNode.node.nodeSize - 1; api.core.actions.execute(function (_ref3) { var tr = _ref3.tr; tr.setSelection(TextSelection.create(view.state.selection.$from.doc, newPos)); return tr; }); } } if (currentSelection instanceof NodeSelection && currentSelection.$from.depth > 0) { if (isNonEditableBlock(view.state.selection.from, view)) { api.core.actions.execute(createNewLine(view.state.selection.from)); } else { api.core.actions.execute(function (_ref4) { var tr = _ref4.tr; createNewLine(view.state.selection.from)({ tr: tr }); tr.setSelection(TextSelection.create(tr.doc, view.state.selection.from)); return tr; }); } } if (currentSelection instanceof CellSelection) { var lastInlinePosition = TextSelection.near(view.state.selection.$to, -1); if (lastInlinePosition) { api.core.actions.execute(function (_ref5) { var tr = _ref5.tr; if (!(lastInlinePosition instanceof TextSelection)) { createNewLine(lastInlinePosition.from)({ tr: tr }); tr.setSelection(TextSelection.create(tr.doc, lastInlinePosition.to)); } else { tr.setSelection(lastInlinePosition); } return tr; }); } } } openTypeAhead(); }; export var BlockControlQuickInsertButton = function BlockControlQuickInsertButton(_ref6) { var api = _ref6.api, openTypeAhead = _ref6.openTypeAhead, _ref6$reserveDragHand = _ref6.reserveDragHandleSpace, reserveDragHandleSpace = _ref6$reserveDragHand === void 0 ? false : _ref6$reserveDragHand, start = _ref6.start, view = _ref6.view; var _useIntl = useIntl(), formatMessage = _useIntl.formatMessage; var label = formatMessage(messages.insert); var handleMouseDown = useCallback(function () { var _api$typeAhead; if ((_api$typeAhead = api.typeAhead) !== null && _api$typeAhead !== void 0 && _api$typeAhead.actions.isOpen(view.state)) { api.typeAhead.actions.close({ insertCurrentQueryAsRawText: false }); } }, [api, view]); var handleClick = useCallback(function () { return openQuickInsert(api, view, start, openTypeAhead); }, [api, openTypeAhead, start, view]); return /*#__PURE__*/React.createElement(Tooltip, { position: "top", content: /*#__PURE__*/React.createElement(ToolTipContent, { description: label }) }, /*#__PURE__*/React.createElement("span", { className: ax([quickInsertButtonContainerStyles.root, reserveDragHandleSpace && quickInsertButtonContainerStyles.reservedDragHandleSpace]) }, /*#__PURE__*/React.createElement(Pressable, { "aria-label": label, onClick: handleClick, onMouseDown: handleMouseDown, testId: "editor-quick-insert-button", type: "button", xcss: quickInsertButtonStyles.root }, /*#__PURE__*/React.createElement(AddIcon, { label: "", color: "var(--ds-icon-subtle, #505258)", size: "small" })))); };