UNPKG

@atlaskit/editor-plugin-expand

Version:

Expand plugin for @atlaskit/editor-core

196 lines (193 loc) 9.09 kB
import { getNextNodeExpandPos, isExpandCollapsed } from '@atlaskit/editor-common/expand'; import { backspace, bindKeymapWithCommand, moveDown, moveLeft, moveRight, moveUp, tab } from '@atlaskit/editor-common/keymaps'; import { GapCursorSelection, RelativeSelectionPos, Side } from '@atlaskit/editor-common/selection'; import { findExpand } from '@atlaskit/editor-common/transforms'; import { isEmptyNode, isPositionNearTableRow } from '@atlaskit/editor-common/utils'; import { keymap } from '@atlaskit/editor-prosemirror/keymap'; import { NodeSelection, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state'; import { isInTable } from '@atlaskit/editor-tables/utils'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { deleteExpand, focusIcon, focusTitle } from '../commands'; var isExpandNode = function isExpandNode(node) { return (node === null || node === void 0 ? void 0 : node.type.name) === 'expand' || (node === null || node === void 0 ? void 0 : node.type.name) === 'nestedExpand'; }; var isExpandSelected = function isExpandSelected(selection) { return selection instanceof NodeSelection && isExpandNode(selection.node); }; export function expandKeymap(api) { var list = {}; bindKeymapWithCommand( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion moveRight.common, function (state, dispatch, editorView) { var _api$selection; if (!editorView) { return false; } var selection = state.selection; var selectionSharedState = (api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : _api$selection.sharedState.currentState()) || {}; var selectionRelativeToNode = selectionSharedState.selectionRelativeToNode; if (isExpandSelected(selection) && selectionRelativeToNode === RelativeSelectionPos.Start) { return focusTitle(selection.from + 1)(state, dispatch, editorView); } return false; }, list); bindKeymapWithCommand( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion moveLeft.common, function (state, dispatch, editorView) { var _api$selection2; if (!editorView) { return false; } var selection = state.selection; var selectionSharedState = (api === null || api === void 0 || (_api$selection2 = api.selection) === null || _api$selection2 === void 0 ? void 0 : _api$selection2.sharedState.currentState()) || {}; var selectionRelativeToNode = selectionSharedState.selectionRelativeToNode; if (isExpandSelected(selection) && (selectionRelativeToNode === undefined || selectionRelativeToNode === RelativeSelectionPos.End)) { return focusTitle(selection.from + 1)(state, dispatch, editorView); } return false; }, list); bindKeymapWithCommand( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion tab.common, function (state, dispatch, editorView) { if (editorView && editorView.dom instanceof HTMLElement) { var from = state.selection.from; // if the node selected is an expand if (isExpandSelected(state.selection)) { var expand = editorView.nodeDOM(from); if (!expand) { return false; } return focusIcon(expand)(state, dispatch, editorView); } // if the text selection is inside an expand else if (state.selection instanceof TextSelection && !isInTable(state)) { var _expand = findExpand(state); if (_expand) { var expandNode = editorView.nodeDOM(_expand.pos); if (expandNode) { return focusIcon(expandNode)(state, dispatch, editorView); } } } } return false; }, list); bindKeymapWithCommand( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion moveUp.common, function (state, dispatch, editorView) { if (!editorView) { return false; } var selection = state.selection, schema = state.schema; var nodeBefore = selection.$from.nodeBefore; if (selection instanceof GapCursorSelection && selection.side === Side.RIGHT && nodeBefore && (nodeBefore.type === schema.nodes.expand || nodeBefore.type === schema.nodes.nestedExpand) && isExpandCollapsed(nodeBefore)) { var _$from = selection.$from; return focusTitle(Math.max(_$from.pos - 1, 0))(state, dispatch, editorView); } var $from = state.selection.$from; if (editorView.endOfTextblock('up')) { var expand = findExpand(state); // Moving UP in a table should move the cursor to the row above // however when an expand is in a table cell to the left of the // current table cell, arrow UP moves the cursor to the left // see ED-15425 if (isPositionNearTableRow($from, schema, 'before') && !expand) { return false; } var prevCursorPos = Math.max($from.pos - $from.parentOffset - 1, 0); // move cursor from expand's content to its title if (expand && expand.start === prevCursorPos) { return focusTitle(expand.start)(state, dispatch, editorView); } var sel = Selection.findFrom(state.doc.resolve(prevCursorPos), -1); var expandBefore = findExpand(state, sel); if (sel && expandBefore) { // moving cursor from outside of an expand to the title when it is collapsed if (isExpandCollapsed(expandBefore.node)) { return focusTitle(expandBefore.start)(state, dispatch, editorView); } // moving cursor from outside of an expand to the content when it is expanded else if (dispatch) { dispatch(state.tr.setSelection(sel)); } return true; } } return false; }, list); bindKeymapWithCommand( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion moveDown.common, function (state, dispatch, editorView) { if (!editorView) { return false; } var _state$schema$nodes = state.schema.nodes, expand = _state$schema$nodes.expand, nestedExpand = _state$schema$nodes.nestedExpand; var selection = state.selection; var nodeAfter = selection.$from.nodeAfter; if (selection instanceof GapCursorSelection && selection.side === Side.LEFT && nodeAfter && (nodeAfter.type === expand || nodeAfter.type === nestedExpand) && isExpandCollapsed(nodeAfter)) { var $from = selection.$from; return focusTitle($from.pos + 1)(state, dispatch, editorView); } if (expValEquals('platform_editor_lovability_navigation_fixes', 'isEnabled', true)) { var nextExpandPos = getNextNodeExpandPos(editorView, selection); if (nextExpandPos !== undefined) { return focusTitle(nextExpandPos)(state, dispatch, editorView); } } if (editorView.endOfTextblock('down')) { var _$from2 = state.selection.$from; if (_$from2.depth === 0) { return false; } var $after = state.doc.resolve(_$from2.after()); if ($after.nodeAfter && ($after.nodeAfter.type === expand || $after.nodeAfter.type === nestedExpand)) { return focusTitle($after.pos + 1)(state, dispatch, editorView); } } return false; }, list); bindKeymapWithCommand( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion backspace.common, function (state, dispatch, editorView) { var selection = state.selection; var $from = selection.$from; if (!editorView || !selection.empty) { return false; } var _state$schema$nodes2 = state.schema.nodes, expand = _state$schema$nodes2.expand, nestedExpand = _state$schema$nodes2.nestedExpand; var expandNode = findExpand(state); if (!expandNode) { // @see ED-7977 var sel = Selection.findFrom(state.doc.resolve(Math.max(selection.$from.pos - 1, 0)), -1); var expandBefore = findExpand(state, sel); if (expandBefore && (expandBefore.node.type === expand || expandBefore.node.type === nestedExpand) && isExpandCollapsed(expandBefore.node)) { return focusTitle(expandBefore.start)(state, dispatch, editorView); } return false; } var parentNode = state.doc.nodeAt($from.before(Math.max($from.depth - 1, 1))); // ED-10012 catch cases where the expand has another node nested within it and // the backspace should be applied only to the inner node instead of the expand if (parentNode && !isExpandNode(parentNode)) { return false; } var textSel = Selection.findFrom(state.doc.resolve(expandNode.pos), 1, true); if (textSel && selection.$from.pos === textSel.$from.pos && isEmptyNode(state.schema)(expandNode.node) && dispatch) { var _api$analytics; return deleteExpand(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions)(state, dispatch); } return false; }, list); return keymap(list); }