Files
tiptap/packages/core/src/inputRules/wrappingInputRule.ts
Dominik 8c6751f0c6 add precommit hook for linting and automatic eslint fixes + update eslint packages (#2862)
* chore: add precommit hook for eslint fixes, fix linting issues
* chore: add eslint import sort plugin
2022-06-08 14:10:25 +02:00

61 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Node as ProseMirrorNode, NodeType } from 'prosemirror-model'
import { canJoin, findWrapping } from 'prosemirror-transform'
import { InputRule, InputRuleFinder } from '../InputRule'
import { ExtendedRegExpMatchArray } from '../types'
import { callOrReturn } from '../utilities/callOrReturn'
/**
* Build an input rule for automatically wrapping a textblock when a
* given string is typed. When using a regular expresion youll
* probably want the regexp to start with `^`, so that the pattern can
* only occur at the start of a textblock.
*
* `type` is the type of node to wrap in.
*
* By default, if theres a node with the same type above the newly
* wrapped node, the rule will try to 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 wrappingInputRule(config: {
find: InputRuleFinder,
type: NodeType,
getAttributes?:
| Record<string, any>
| ((match: ExtendedRegExpMatchArray) => Record<string, any>)
| false
| null
,
joinPredicate?: (match: ExtendedRegExpMatchArray, node: ProseMirrorNode) => boolean,
}) {
return new InputRule({
find: config.find,
handler: ({ state, range, match }) => {
const attributes = callOrReturn(config.getAttributes, undefined, match) || {}
const tr = state.tr.delete(range.from, range.to)
const $start = tr.doc.resolve(range.from)
const blockRange = $start.blockRange()
const wrapping = blockRange && findWrapping(blockRange, config.type, attributes)
if (!wrapping) {
return null
}
tr.wrap(blockRange, wrapping)
const before = tr.doc.resolve(range.from - 1).nodeBefore
if (
before
&& before.type === config.type
&& canJoin(tr.doc, range.from - 1)
&& (!config.joinPredicate || config.joinPredicate(match, before))
) {
tr.join(range.from - 1)
}
},
})
}