UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

96 lines (93 loc) 3.37 kB
import { Selection } from '@atlaskit/editor-prosemirror/state'; import { GapCursorSelection, Side } from './selection'; import { isValidTargetNode } from './utils/is-valid-target-node'; // This function captures clicks outside of the ProseMirror contentEditable area // see also description of "handleClick" in gap-cursor pm-plugin var captureCursorCoords = function captureCursorCoords(event, editorRef, posAtCoords, tr // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/max-params ) { var rect = editorRef.getBoundingClientRect(); // capture clicks before the first block element if (event.clientY < rect.top) { return { position: 0, side: Side.LEFT }; } if (rect.left > 0) { // calculate start position of a node that is vertically at the same level var coords = posAtCoords({ left: rect.left, top: event.clientY }); if (coords && coords.inside > -1) { var $from = tr.doc.resolve(coords.inside); var start = $from.before(1); var side = event.clientX < rect.left ? Side.LEFT : Side.RIGHT; var position; if (side === Side.LEFT) { position = start; } else { var node = tr.doc.nodeAt(start); if (node) { position = start + node.nodeSize; } } return { position: position, side: side }; } } return null; }; export var setSelectionTopLevelBlocks = function setSelectionTopLevelBlocks(tr, event, editorRef, posAtCoords, editorFocused // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/max-params ) { var cursorCoords = captureCursorCoords(event, editorRef, posAtCoords, tr); if (!cursorCoords) { return; } // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var $pos = cursorCoords.position !== undefined ? tr.doc.resolve(cursorCoords.position) : null; if ($pos === null) { return; } var isGapCursorAllowed = cursorCoords.side === Side.LEFT ? isValidTargetNode($pos.nodeAfter) : isValidTargetNode($pos.nodeBefore); if (isGapCursorAllowed && GapCursorSelection.valid($pos)) { // this forces PM to re-render the decoration node if we change the side of the gap cursor, it doesn't do it by default if (tr.selection instanceof GapCursorSelection) { tr.setSelection(Selection.near($pos)); } else { tr.setSelection(new GapCursorSelection($pos, cursorCoords.side)); } } // try to set text selection if the editor isnt focused // if the editor is focused, we are most likely dragging a selection outside. else if (editorFocused === false) { var selectionTemp = Selection.findFrom($pos, cursorCoords.side === Side.LEFT ? 1 : -1, true); if (selectionTemp) { tr.setSelection(selectionTemp); } } }; export var setGapCursorAtPos = function setGapCursorAtPos(position) { var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Side.LEFT; return function (state, dispatch) { // @see ED-6231 if (position > state.doc.content.size) { return false; } var $pos = state.doc.resolve(position); if (GapCursorSelection.valid($pos)) { if (dispatch) { dispatch(state.tr.setSelection(new GapCursorSelection($pos, side))); } return true; } return false; }; };