import { NodeSelection, Plugin } from "prosemirror-state"; import { Decoration, DecorationSet } from "prosemirror-view"; import { CssClassName, WidgetKey } from "../constants"; import { el } from "../util/dom"; import { WedgeSelection } from "./WedgeSelection"; /** * A [plugin](http://prosemirror.net/docs/ref/#state.Plugin) that when enabled, * will captures clicks near and arrow-key-motion past places that don't have a * normally selectable position nearby, and creates a wedge selection for them. * * A wedge selection allows the user to insert content in places where there is * not yet space (e.g. inserting a paragraph after at table at the end of a * document). */ export class WedgePlugin extends Plugin { constructor() { super({ props: { decorations({ doc, selection }) { return selection instanceof WedgeSelection ? DecorationSet.create(doc, [ Decoration.widget(selection.head, el("div", CssClassName.WEDGE_CURSOR), { key: `${WidgetKey.WEDGE_CURSOR}` }) ]) : null; }, createSelectionBetween(_, $anchor, $head) { if ($anchor.pos == $head.pos && WedgeSelection.valid($head)) { return new WedgeSelection($head); } return; }, handleClick(view, pos, event) { const $pos = view.state.doc.resolve(pos); if (!WedgeSelection.valid($pos)) { return false; } // Don't trap clicks on selectable nodes. const posAtCords = view.posAtCoords({ left: event.clientX, top: event.clientY }); if (posAtCords != null && posAtCords.inside >= 0) { const node = view.state.doc.nodeAt(posAtCords.inside); if (node != null && NodeSelection.isSelectable(node)) { return false; } } view.dispatch(view.state.tr.setSelection(new WedgeSelection($pos))); return true; } } }); } }