import { Node, NodeType } from "prosemirror-model"; import { canJoin, findWrapping } from "prosemirror-transform"; import { TextShortcut } from "./TextShortcutPlugin"; // Build a text shortcut for automatically wrapping a textblock when a given // string is typed. The `regexp` argument is directly passed through to the // `TextShortcut` constructor. You'll probably want the regexp to start with // `^`, so that the pattern can only occur at the start of a textblock. // // `nodeType` is the type of node to wrap in. If it needs attributes, you can // either pass them directly, or pass a function that will compute them from the // regular expression match. // // By default, if there's a node with the same type above the newly wrapped // node, the rule will try to [join](#transform.Transform.join) those two nodes. // You can pass a join predicate, which takes a regular expression match and the // node before the wrapped node, and can return a boolean to indicate whether a // join should happen. export function wrappingTextShortcut( regexp: RegExp, nodeType: NodeType, getAttrs?: object | ((text: string[]) => object), joinPredicate?: (text: string[], node: Node) => boolean ) { return new TextShortcut(regexp, (state, match, start, end) => { const attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs; const tr = state.tr.delete(start, end); const $start = tr.doc.resolve(start); const range = $start.blockRange(); if (range != null) { const wrapping = findWrapping(range, nodeType, attrs); if (wrapping != null) { tr.wrap(range, wrapping); const before = tr.doc.resolve(start - 1).nodeBefore; if ( before != null && before.type == nodeType && canJoin(tr.doc, start - 1) && (joinPredicate === undefined || joinPredicate(match, before)) ) { tr.join(start - 1); } return tr; } } return null; }); }