UNPKG

@atlaskit/editor-plugin-panel

Version:

Panel plugin for @atlaskit/editor-core.

91 lines (87 loc) 4.23 kB
import { isEmptyNode } from '@atlaskit/editor-common/utils'; import { keymap } from '@atlaskit/editor-prosemirror/keymap'; import { findParentNodeOfType, hasParentNodeOfType, setTextSelection } from '@atlaskit/editor-prosemirror/utils'; function findParentNode(selection, nodeType) { const parentPosition = findParentNodeOfType(nodeType)(selection); if (parentPosition) { return parentPosition.node; } return null; } function isInsideAnEmptyNode(selection, nodeType, schema) { const parentNode = findParentNode(selection, nodeType); return parentNode && isEmptyNode(schema)(parentNode); } // Somewhat broken and subverted: https://product-fabric.atlassian.net/browse/ED-6504 export function keymapPlugin() { const deleteCurrentItem = ($from, tr) => { return tr.delete($from.before($from.depth) - 1, $from.end($from.depth) + 1); }; const keymaps = { Backspace: (state, dispatch) => { var _$previousPos$nodeAft, _nodeBeforePanel$type, _nodeBeforePanel$type2; const { selection, schema: { nodes }, tr } = state; const { panel, blockquote, orderedList, bulletList, mediaSingle, mediaGroup, extension } = nodes; const { $from, $to } = selection; // Don't do anything if selection is a range if ($from.pos !== $to.pos) { return false; } // If not at the start of a panel, no joining will happen so allow default behaviour (backspacing characters etc..) if ($from.parentOffset !== 0) { return false; } const $previousPos = tr.doc.resolve(Math.max(0, $from.before($from.depth) - 1)); const previousNodeType = $previousPos.pos > 0 && $previousPos.parent && $previousPos.parent.type; const parentNodeType = $from.parent.type; const isPreviousNodeAPanel = previousNodeType === panel; const isParentNodeAPanel = parentNodeType === panel; const nodeBeforePanel = $previousPos === null || $previousPos === void 0 ? void 0 : $previousPos.nodeBefore; const isPreviousNodeMedia = previousNodeType === mediaSingle || previousNodeType === mediaGroup; const isPreviousNodeAList = previousNodeType === bulletList || previousNodeType === orderedList; // identifies if new position after backspace is at the start of a non-bodied extension node const isPreviousPosAtExtension = ((_$previousPos$nodeAft = $previousPos.nodeAfter) === null || _$previousPos$nodeAft === void 0 ? void 0 : _$previousPos$nodeAft.type) === extension; // Stops merging panels when deleting empty paragraph in between // Stops merging blockquotes with panels when deleting from start of blockquote if (isPreviousNodeAPanel && !isParentNodeAPanel && !isPreviousPosAtExtension || isInsideAnEmptyNode(selection, panel, state.schema) || hasParentNodeOfType(blockquote)(selection) && !isPreviousNodeAList && !isPreviousNodeMedia && !isPreviousPosAtExtension || // Lift line of panel content up and out of the panel, when backspacing // at the start of a panel, if the node before the panel is an 'isolating' node // (for e.g. a table, or an expand), otherwise the default prosemirror backspace // behaviour will fallback to 'select node backward' logic because the node // before is an isolating node. nodeBeforePanel !== null && nodeBeforePanel !== void 0 && (_nodeBeforePanel$type = nodeBeforePanel.type) !== null && _nodeBeforePanel$type !== void 0 && (_nodeBeforePanel$type2 = _nodeBeforePanel$type.spec) !== null && _nodeBeforePanel$type2 !== void 0 && _nodeBeforePanel$type2.isolating && hasParentNodeOfType(panel)(selection)) { const content = $from.node($from.depth).content; const insertPos = $previousPos.pos; deleteCurrentItem($from, tr).insert(insertPos, content); if (dispatch) { dispatch(setTextSelection(insertPos)(tr).scrollIntoView()); } return true; } const nodeType = $from.node().type; if (nodeType !== panel) { return false; } return true; } }; return keymap(keymaps); } export default keymapPlugin;