UNPKG

@atlaskit/editor-common

Version:

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

84 lines (82 loc) 2.91 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 const captureCursorCoords = (event, editorRef, posAtCoords, tr) => { const 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 const coords = posAtCoords({ left: rect.left, top: event.clientY }); if (coords && coords.inside > -1) { const $from = tr.doc.resolve(coords.inside); const start = $from.before(1); const side = event.clientX < rect.left ? Side.LEFT : Side.RIGHT; let position; if (side === Side.LEFT) { position = start; } else { const node = tr.doc.nodeAt(start); if (node) { position = start + node.nodeSize; } } return { position, side }; } } return null; }; export const setSelectionTopLevelBlocks = (tr, event, editorRef, posAtCoords, editorFocused) => { const cursorCoords = captureCursorCoords(event, editorRef, posAtCoords, tr); if (!cursorCoords) { return; } const $pos = cursorCoords.position !== undefined ? tr.doc.resolve(cursorCoords.position) : null; if ($pos === null) { return; } const 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) { const selectionTemp = Selection.findFrom($pos, cursorCoords.side === Side.LEFT ? 1 : -1, true); if (selectionTemp) { tr.setSelection(selectionTemp); } } }; export const setGapCursorAtPos = (position, side = Side.LEFT) => (state, dispatch) => { // @see ED-6231 if (position > state.doc.content.size) { return false; } const $pos = state.doc.resolve(position); if (GapCursorSelection.valid($pos)) { if (dispatch) { dispatch(state.tr.setSelection(new GapCursorSelection($pos, side))); } return true; } return false; };