feature(core): add exit handling for marks (#2925)

* feat(core): add exit handling for marks

* docs(core): add information about exitable marks
This commit is contained in:
Dominik
2022-08-22 15:23:44 +02:00
committed by GitHub
parent f558417a25
commit 5fed0f2fc6
4 changed files with 65 additions and 4 deletions

View File

@@ -3,7 +3,7 @@ import { Node as ProsemirrorNode, Schema } from 'prosemirror-model'
import { Plugin } from 'prosemirror-state'
import { Decoration, EditorView } from 'prosemirror-view'
import { NodeConfig } from '.'
import { Mark, NodeConfig } from '.'
import { Editor } from './Editor'
import { getAttributesFromExtensions } from './helpers/getAttributesFromExtensions'
import { getExtensionField } from './helpers/getExtensionField'
@@ -252,6 +252,13 @@ export class ExtensionManager {
context,
)
let defaultBindings: Record<string, () => boolean> = {}
// bind exit handling
if (extension.type === 'mark' && extension.config.exitable) {
defaultBindings.ArrowRight = () => Mark.handleExit({ editor, mark: (extension as Mark) })
}
if (addKeyboardShortcuts) {
const bindings = Object.fromEntries(
Object
@@ -261,11 +268,13 @@ export class ExtensionManager {
}),
)
const keyMapPlugin = keymap(bindings)
plugins.push(keyMapPlugin)
defaultBindings = { ...defaultBindings, ...bindings }
}
const keyMapPlugin = keymap(defaultBindings)
plugins.push(keyMapPlugin)
const addInputRules = getExtensionField<AnyConfig['addInputRules']>(
extension,
'addInputRules',

View File

@@ -304,6 +304,11 @@ declare module '@tiptap/core' {
parent: ParentConfig<MarkConfig<Options, Storage>>['excludes'],
}) => MarkSpec['excludes']),
/**
* Marks this Mark as exitable
*/
exitable?: boolean | (() => boolean),
/**
* Group
*/
@@ -486,4 +491,38 @@ export class Mark<Options = any, Storage = any> {
return extension
}
static handleExit({
editor,
mark,
}: {
editor: Editor
mark: Mark
}) {
const { tr } = editor.state
const currentPos = editor.state.selection.$from
const isAtEnd = currentPos.pos === currentPos.end()
if (isAtEnd) {
const currentMarks = currentPos.marks()
const isInMark = !!currentMarks.find(m => m?.type.name === mark.name)
if (!isInMark) {
return false
}
const removeMark = currentMarks.find(m => m?.type.name === mark.name)
if (removeMark) {
tr.removeStoredMark(removeMark)
}
tr.insertText(' ', currentPos.pos)
editor.view.dispatch(tr)
return true
}
return false
}
}