@tiptap/core 3.0.0-next.2 → 3.0.0-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +5 -1
- package/dist/index.cjs +2402 -2540
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1355 -1273
- package/dist/index.d.ts +1355 -1273
- package/dist/index.js +2408 -2562
- package/dist/index.js.map +1 -1
- package/package.json +9 -5
- package/src/CommandManager.ts +2 -9
- package/src/Editor.ts +87 -72
- package/src/EventEmitter.ts +7 -10
- package/src/Extension.ts +8 -14
- package/src/ExtensionManager.ts +26 -125
- package/src/InputRule.ts +35 -48
- package/src/Mark.ts +9 -9
- package/src/Node.ts +9 -9
- package/src/NodePos.ts +1 -3
- package/src/NodeView.ts +10 -20
- package/src/PasteRule.ts +43 -55
- package/src/Tracker.ts +7 -9
- package/src/commands/blur.ts +14 -12
- package/src/commands/clearContent.ts +6 -4
- package/src/commands/clearNodes.ts +32 -30
- package/src/commands/command.ts +1 -1
- package/src/commands/createParagraphNear.ts +5 -3
- package/src/commands/cut.ts +12 -10
- package/src/commands/deleteCurrentNode.ts +23 -21
- package/src/commands/deleteNode.ts +18 -16
- package/src/commands/deleteRange.ts +10 -8
- package/src/commands/deleteSelection.ts +5 -3
- package/src/commands/enter.ts +6 -4
- package/src/commands/exitCode.ts +5 -3
- package/src/commands/extendMarkRange.ts +14 -12
- package/src/commands/first.ts +2 -4
- package/src/commands/focus.ts +45 -48
- package/src/commands/forEach.ts +2 -2
- package/src/commands/insertContent.ts +12 -14
- package/src/commands/insertContentAt.ts +101 -98
- package/src/commands/join.ts +20 -12
- package/src/commands/joinItemBackward.ts +16 -18
- package/src/commands/joinItemForward.ts +16 -18
- package/src/commands/joinTextblockBackward.ts +5 -3
- package/src/commands/joinTextblockForward.ts +5 -3
- package/src/commands/keyboardShortcut.ts +29 -34
- package/src/commands/lift.ts +10 -8
- package/src/commands/liftEmptyBlock.ts +6 -4
- package/src/commands/liftListItem.ts +6 -4
- package/src/commands/newlineInCode.ts +5 -3
- package/src/commands/resetAttributes.ts +36 -41
- package/src/commands/scrollIntoView.ts +9 -7
- package/src/commands/selectAll.ts +10 -8
- package/src/commands/selectNodeBackward.ts +5 -3
- package/src/commands/selectNodeForward.ts +5 -3
- package/src/commands/selectParentNode.ts +5 -3
- package/src/commands/selectTextblockEnd.ts +5 -3
- package/src/commands/selectTextblockStart.ts +5 -3
- package/src/commands/setContent.ts +25 -25
- package/src/commands/setMark.ts +55 -57
- package/src/commands/setMeta.ts +7 -5
- package/src/commands/setNode.ts +32 -30
- package/src/commands/setNodeSelection.ts +11 -9
- package/src/commands/setTextSelection.ts +15 -13
- package/src/commands/sinkListItem.ts +6 -4
- package/src/commands/splitBlock.ts +67 -76
- package/src/commands/splitListItem.ts +93 -106
- package/src/commands/toggleList.ts +73 -71
- package/src/commands/toggleMark.ts +11 -9
- package/src/commands/toggleNode.ts +18 -16
- package/src/commands/toggleWrap.ts +10 -8
- package/src/commands/undoInputRule.ts +31 -29
- package/src/commands/unsetAllMarks.ts +16 -14
- package/src/commands/unsetMark.ts +27 -25
- package/src/commands/updateAttributes.ts +92 -100
- package/src/commands/wrapIn.ts +6 -4
- package/src/commands/wrapInList.ts +6 -4
- package/src/extensions/clipboardTextSerializer.ts +2 -4
- package/src/extensions/focusEvents.ts +2 -6
- package/src/extensions/keymap.ts +54 -50
- package/src/extensions/paste.ts +0 -1
- package/src/extensions/tabindex.ts +1 -1
- package/src/helpers/combineTransactionSteps.ts +1 -4
- package/src/helpers/createChainableState.ts +1 -4
- package/src/helpers/createDocument.ts +1 -3
- package/src/helpers/createNodeFromContent.ts +4 -10
- package/src/helpers/findChildrenInRange.ts +1 -5
- package/src/helpers/findParentNode.ts +3 -1
- package/src/helpers/flattenExtensions.ts +30 -0
- package/src/helpers/getAttributes.ts +1 -4
- package/src/helpers/getAttributesFromExtensions.ts +28 -37
- package/src/helpers/getChangedRanges.ts +13 -11
- package/src/helpers/getExtensionField.ts +1 -4
- package/src/helpers/getMarkAttributes.ts +1 -4
- package/src/helpers/getMarkRange.ts +5 -15
- package/src/helpers/getMarkType.ts +1 -3
- package/src/helpers/getNodeAttributes.ts +1 -4
- package/src/helpers/getNodeType.ts +1 -3
- package/src/helpers/getRenderedAttributes.ts +1 -3
- package/src/helpers/getSchema.ts +2 -2
- package/src/helpers/getSchemaByResolvedExtensions.ts +45 -77
- package/src/helpers/getSplittedAttributes.ts +4 -4
- package/src/helpers/getTextContentFromNodes.ts +8 -11
- package/src/helpers/index.ts +4 -0
- package/src/helpers/injectExtensionAttributesToParseRule.ts +1 -1
- package/src/helpers/isActive.ts +1 -5
- package/src/helpers/isExtensionRulesEnabled.ts +1 -3
- package/src/helpers/isNodeEmpty.ts +2 -2
- package/src/helpers/resolveExtensions.ts +25 -0
- package/src/helpers/resolveFocusPosition.ts +3 -14
- package/src/helpers/rewriteUnknownContent.ts +149 -0
- package/src/helpers/sortExtensions.ts +26 -0
- package/src/inputRules/markInputRule.ts +1 -5
- package/src/inputRules/nodeInputRule.ts +2 -9
- package/src/inputRules/textInputRule.ts +1 -4
- package/src/inputRules/textblockTypeInputRule.ts +2 -8
- package/src/inputRules/wrappingInputRule.ts +13 -19
- package/src/pasteRules/markPasteRule.ts +1 -3
- package/src/pasteRules/nodePasteRule.ts +2 -8
- package/src/pasteRules/textPasteRule.ts +1 -4
- package/src/types.ts +212 -172
- package/src/utilities/createStyleTag.ts +3 -1
- package/src/utilities/deleteProps.ts +7 -11
- package/src/utilities/findDuplicates.ts +4 -1
- package/src/utilities/isFunction.ts +1 -0
- package/src/utilities/isMacOS.ts +1 -3
- package/src/utilities/isiOS.ts +5 -10
- package/src/utilities/mergeAttributes.ts +16 -6
- package/src/utilities/removeDuplicates.ts +1 -3
|
@@ -7,36 +7,38 @@ declare module '@tiptap/core' {
|
|
|
7
7
|
* Delete the node that currently has the selection anchor.
|
|
8
8
|
* @example editor.commands.deleteCurrentNode()
|
|
9
9
|
*/
|
|
10
|
-
deleteCurrentNode: () => ReturnType
|
|
10
|
+
deleteCurrentNode: () => ReturnType
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export const deleteCurrentNode: RawCommands['deleteCurrentNode'] =
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
export const deleteCurrentNode: RawCommands['deleteCurrentNode'] =
|
|
16
|
+
() =>
|
|
17
|
+
({ tr, dispatch }) => {
|
|
18
|
+
const { selection } = tr
|
|
19
|
+
const currentNode = selection.$anchor.node()
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// if there is content inside the current node, break out of this command
|
|
22
|
+
if (currentNode.content.size > 0) {
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
const $pos = tr.selection.$anchor
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
29
|
+
const node = $pos.node(depth)
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
if (node.type === currentNode.type) {
|
|
32
|
+
if (dispatch) {
|
|
33
|
+
const from = $pos.before(depth)
|
|
34
|
+
const to = $pos.after(depth)
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
tr.delete(from, to).scrollIntoView()
|
|
37
|
+
}
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
38
41
|
}
|
|
39
|
-
}
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
@@ -11,29 +11,31 @@ declare module '@tiptap/core' {
|
|
|
11
11
|
* @param typeOrName The type or name of the node.
|
|
12
12
|
* @example editor.commands.deleteNode('paragraph')
|
|
13
13
|
*/
|
|
14
|
-
deleteNode: (typeOrName: string | NodeType) => ReturnType
|
|
14
|
+
deleteNode: (typeOrName: string | NodeType) => ReturnType
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export const deleteNode: RawCommands['deleteNode'] =
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
export const deleteNode: RawCommands['deleteNode'] =
|
|
20
|
+
typeOrName =>
|
|
21
|
+
({ tr, state, dispatch }) => {
|
|
22
|
+
const type = getNodeType(typeOrName, state.schema)
|
|
23
|
+
const $pos = tr.selection.$anchor
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
26
|
+
const node = $pos.node(depth)
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
if (node.type === type) {
|
|
29
|
+
if (dispatch) {
|
|
30
|
+
const from = $pos.before(depth)
|
|
31
|
+
const to = $pos.after(depth)
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
tr.delete(from, to).scrollIntoView()
|
|
34
|
+
}
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
return true
|
|
37
|
+
}
|
|
35
38
|
}
|
|
36
|
-
}
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
@@ -8,17 +8,19 @@ declare module '@tiptap/core' {
|
|
|
8
8
|
* @param range The range to delete.
|
|
9
9
|
* @example editor.commands.deleteRange({ from: 1, to: 3 })
|
|
10
10
|
*/
|
|
11
|
-
deleteRange: (range: Range) => ReturnType
|
|
11
|
+
deleteRange: (range: Range) => ReturnType
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const deleteRange: RawCommands['deleteRange'] =
|
|
17
|
-
|
|
16
|
+
export const deleteRange: RawCommands['deleteRange'] =
|
|
17
|
+
range =>
|
|
18
|
+
({ tr, dispatch }) => {
|
|
19
|
+
const { from, to } = range
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
if (dispatch) {
|
|
22
|
+
tr.delete(from, to)
|
|
23
|
+
}
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
@@ -14,6 +14,8 @@ declare module '@tiptap/core' {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export const deleteSelection: RawCommands['deleteSelection'] =
|
|
18
|
-
|
|
19
|
-
}
|
|
17
|
+
export const deleteSelection: RawCommands['deleteSelection'] =
|
|
18
|
+
() =>
|
|
19
|
+
({ state, dispatch }) => {
|
|
20
|
+
return originalDeleteSelection(state, dispatch)
|
|
21
|
+
}
|
package/src/commands/enter.ts
CHANGED
|
@@ -7,11 +7,13 @@ declare module '@tiptap/core' {
|
|
|
7
7
|
* Trigger enter.
|
|
8
8
|
* @example editor.commands.enter()
|
|
9
9
|
*/
|
|
10
|
-
enter: () => ReturnType
|
|
10
|
+
enter: () => ReturnType
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export const enter: RawCommands['enter'] =
|
|
16
|
-
|
|
17
|
-
}
|
|
15
|
+
export const enter: RawCommands['enter'] =
|
|
16
|
+
() =>
|
|
17
|
+
({ commands }) => {
|
|
18
|
+
return commands.keyboardShortcut('Enter')
|
|
19
|
+
}
|
package/src/commands/exitCode.ts
CHANGED
|
@@ -14,6 +14,8 @@ declare module '@tiptap/core' {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export const exitCode: RawCommands['exitCode'] =
|
|
18
|
-
|
|
19
|
-
}
|
|
17
|
+
export const exitCode: RawCommands['exitCode'] =
|
|
18
|
+
() =>
|
|
19
|
+
({ state, dispatch }) => {
|
|
20
|
+
return originalExitCode(state, dispatch)
|
|
21
|
+
}
|
|
@@ -30,20 +30,22 @@ declare module '@tiptap/core' {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export const extendMarkRange: RawCommands['extendMarkRange'] =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
export const extendMarkRange: RawCommands['extendMarkRange'] =
|
|
34
|
+
(typeOrName, attributes = {}) =>
|
|
35
|
+
({ tr, state, dispatch }) => {
|
|
36
|
+
const type = getMarkType(typeOrName, state.schema)
|
|
37
|
+
const { doc, selection } = tr
|
|
38
|
+
const { $from, from, to } = selection
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
if (dispatch) {
|
|
41
|
+
const range = getMarkRange($from, type, attributes)
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
if (range && range.from <= from && range.to >= to) {
|
|
44
|
+
const newSelection = TextSelection.create(doc, range.from, range.to)
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
tr.setSelection(newSelection)
|
|
47
|
+
}
|
|
45
48
|
}
|
|
46
|
-
}
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
+
return true
|
|
51
|
+
}
|
package/src/commands/first.ts
CHANGED
|
@@ -8,15 +8,13 @@ declare module '@tiptap/core' {
|
|
|
8
8
|
* @param commands The commands to run.
|
|
9
9
|
* @example editor.commands.first([command1, command2])
|
|
10
10
|
*/
|
|
11
|
-
first: (commands: Command[] | ((props: CommandProps) => Command[])) => ReturnType
|
|
11
|
+
first: (commands: Command[] | ((props: CommandProps) => Command[])) => ReturnType
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export const first: RawCommands['first'] = commands => props => {
|
|
17
|
-
const items = typeof commands === 'function'
|
|
18
|
-
? commands(props)
|
|
19
|
-
: commands
|
|
17
|
+
const items = typeof commands === 'function' ? commands(props) : commands
|
|
20
18
|
|
|
21
19
|
for (let i = 0; i < items.length; i += 1) {
|
|
22
20
|
if (items[i](props)) {
|
package/src/commands/focus.ts
CHANGED
|
@@ -23,68 +23,65 @@ declare module '@tiptap/core' {
|
|
|
23
23
|
* @default { scrollIntoView: true }
|
|
24
24
|
*/
|
|
25
25
|
options?: {
|
|
26
|
-
scrollIntoView?: boolean
|
|
26
|
+
scrollIntoView?: boolean
|
|
27
27
|
},
|
|
28
|
-
) => ReturnType
|
|
28
|
+
) => ReturnType
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export const focus: RawCommands['focus'] =
|
|
34
|
-
|
|
35
|
-
view,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
scrollIntoView: true,
|
|
41
|
-
...options,
|
|
42
|
-
}
|
|
33
|
+
export const focus: RawCommands['focus'] =
|
|
34
|
+
(position = null, options = {}) =>
|
|
35
|
+
({ editor, view, tr, dispatch }) => {
|
|
36
|
+
options = {
|
|
37
|
+
scrollIntoView: true,
|
|
38
|
+
...options,
|
|
39
|
+
}
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
const delayedFocus = () => {
|
|
42
|
+
;(view.dom as HTMLElement).focus()
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
// For React we have to focus asynchronously. Otherwise wild things happen.
|
|
45
|
+
// see: https://github.com/ueberdosis/tiptap/issues/1520
|
|
46
|
+
requestAnimationFrame(() => {
|
|
47
|
+
if (!editor.isDestroyed) {
|
|
48
|
+
view.focus()
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
if (options?.scrollIntoView) {
|
|
51
|
+
editor.commands.scrollIntoView()
|
|
52
|
+
}
|
|
55
53
|
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
54
|
+
})
|
|
55
|
+
}
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
if ((view.hasFocus() && position === null) || position === false) {
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
// we don’t try to resolve a NodeSelection or CellSelection
|
|
62
|
+
if (dispatch && position === null && !isTextSelection(editor.state.selection)) {
|
|
63
|
+
delayedFocus()
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
// pass through tr.doc instead of editor.state.doc
|
|
68
|
+
// since transactions could change the editors state before this command has been run
|
|
69
|
+
const selection = resolveFocusPosition(tr.doc, position) || editor.state.selection
|
|
70
|
+
const isSameSelection = editor.state.selection.eq(selection)
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
if (dispatch) {
|
|
73
|
+
if (!isSameSelection) {
|
|
74
|
+
tr.setSelection(selection)
|
|
75
|
+
}
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
// `tr.setSelection` resets the stored marks
|
|
78
|
+
// so we’ll restore them if the selection is the same as before
|
|
79
|
+
if (isSameSelection && tr.storedMarks) {
|
|
80
|
+
tr.setStoredMarks(tr.storedMarks)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
delayedFocus()
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
return true
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
return true
|
|
90
|
-
}
|
package/src/commands/forEach.ts
CHANGED
|
@@ -23,24 +23,22 @@ declare module '@tiptap/core' {
|
|
|
23
23
|
/**
|
|
24
24
|
* Options for parsing the content.
|
|
25
25
|
*/
|
|
26
|
-
parseOptions?: ParseOptions
|
|
26
|
+
parseOptions?: ParseOptions
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Whether to update the selection after inserting the content.
|
|
30
30
|
*/
|
|
31
|
-
updateSelection?: boolean
|
|
32
|
-
applyInputRules?: boolean
|
|
33
|
-
applyPasteRules?: boolean
|
|
34
|
-
}
|
|
35
|
-
) => ReturnType
|
|
36
|
-
}
|
|
31
|
+
updateSelection?: boolean
|
|
32
|
+
applyInputRules?: boolean
|
|
33
|
+
applyPasteRules?: boolean
|
|
34
|
+
},
|
|
35
|
+
) => ReturnType
|
|
36
|
+
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export const insertContent: RawCommands['insertContent'] =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
value,
|
|
44
|
-
|
|
45
|
-
)
|
|
46
|
-
}
|
|
40
|
+
export const insertContent: RawCommands['insertContent'] =
|
|
41
|
+
(value, options) =>
|
|
42
|
+
({ tr, commands }) => {
|
|
43
|
+
return commands.insertContentAt({ from: tr.selection.from, to: tr.selection.to }, value, options)
|
|
44
|
+
}
|
|
@@ -60,122 +60,125 @@ const isFragment = (nodeOrFragment: ProseMirrorNode | Fragment): nodeOrFragment
|
|
|
60
60
|
return !('type' in nodeOrFragment)
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export const insertContentAt: RawCommands['insertContentAt'] =
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const { selection } = editor.state
|
|
63
|
+
export const insertContentAt: RawCommands['insertContentAt'] =
|
|
64
|
+
(position, value, options) =>
|
|
65
|
+
({ tr, dispatch, editor }) => {
|
|
66
|
+
if (dispatch) {
|
|
67
|
+
options = {
|
|
68
|
+
parseOptions: editor.options.parseOptions,
|
|
69
|
+
updateSelection: true,
|
|
70
|
+
applyInputRules: false,
|
|
71
|
+
applyPasteRules: false,
|
|
72
|
+
...options,
|
|
73
|
+
}
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
parseOptions: {
|
|
79
|
-
preserveWhitespace: 'full',
|
|
80
|
-
...options.parseOptions,
|
|
81
|
-
},
|
|
82
|
-
errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,
|
|
83
|
-
})
|
|
84
|
-
} catch (e) {
|
|
85
|
-
editor.emit('contentError', {
|
|
86
|
-
editor,
|
|
87
|
-
error: e as Error,
|
|
88
|
-
disableCollaboration: () => {
|
|
89
|
-
if (editor.storage.collaboration) {
|
|
90
|
-
editor.storage.collaboration.isDisabled = true
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
})
|
|
94
|
-
return false
|
|
95
|
-
}
|
|
75
|
+
let content: Fragment | ProseMirrorNode
|
|
76
|
+
const { selection } = editor.state
|
|
96
77
|
|
|
97
|
-
|
|
78
|
+
try {
|
|
79
|
+
content = createNodeFromContent(value, editor.schema, {
|
|
80
|
+
parseOptions: {
|
|
81
|
+
preserveWhitespace: 'full',
|
|
82
|
+
...options.parseOptions,
|
|
83
|
+
},
|
|
84
|
+
errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,
|
|
85
|
+
})
|
|
86
|
+
} catch (e) {
|
|
87
|
+
editor.emit('contentError', {
|
|
88
|
+
editor,
|
|
89
|
+
error: e as Error,
|
|
90
|
+
disableCollaboration: () => {
|
|
91
|
+
if (editor.storage.collaboration) {
|
|
92
|
+
editor.storage.collaboration.isDisabled = true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const nodes = isFragment(content) ? content : [content]
|
|
99
|
+
let { from, to } =
|
|
100
|
+
typeof position === 'number' ? { from: position, to: position } : { from: position.from, to: position.to }
|
|
102
101
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
let isOnlyTextContent = true
|
|
103
|
+
let isOnlyBlockContent = true
|
|
104
|
+
const nodes = isFragment(content) ? content : [content]
|
|
106
105
|
|
|
107
|
-
|
|
106
|
+
nodes.forEach(node => {
|
|
107
|
+
// check if added node is valid
|
|
108
|
+
node.check()
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
})
|
|
110
|
+
isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// example:
|
|
115
|
-
// replace an empty paragraph by an inserted image
|
|
116
|
-
// instead of inserting the image below the paragraph
|
|
117
|
-
if (from === to && isOnlyBlockContent) {
|
|
118
|
-
const { parent } = tr.doc.resolve(from)
|
|
119
|
-
const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount
|
|
112
|
+
isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false
|
|
113
|
+
})
|
|
120
114
|
|
|
121
|
-
if
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
// check if we can replace the wrapping node by
|
|
116
|
+
// the newly inserted content
|
|
117
|
+
// example:
|
|
118
|
+
// replace an empty paragraph by an inserted image
|
|
119
|
+
// instead of inserting the image below the paragraph
|
|
120
|
+
if (from === to && isOnlyBlockContent) {
|
|
121
|
+
const { parent } = tr.doc.resolve(from)
|
|
122
|
+
const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount
|
|
123
|
+
|
|
124
|
+
if (isEmptyTextBlock) {
|
|
125
|
+
from -= 1
|
|
126
|
+
to += 1
|
|
127
|
+
}
|
|
124
128
|
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
let newContent
|
|
128
|
-
|
|
129
|
-
// if there is only plain text we have to use `insertText`
|
|
130
|
-
// because this will keep the current marks
|
|
131
|
-
if (isOnlyTextContent) {
|
|
132
|
-
// if value is string, we can use it directly
|
|
133
|
-
// otherwise if it is an array, we have to join it
|
|
134
|
-
if (Array.isArray(value)) {
|
|
135
|
-
newContent = value.map(v => v.text || '').join('')
|
|
136
|
-
} else if (value instanceof Fragment) {
|
|
137
|
-
let text = ''
|
|
138
|
-
|
|
139
|
-
value.forEach(node => {
|
|
140
|
-
if (node.text) {
|
|
141
|
-
text += node.text
|
|
142
|
-
}
|
|
143
|
-
})
|
|
144
129
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
130
|
+
let newContent
|
|
131
|
+
|
|
132
|
+
// if there is only plain text we have to use `insertText`
|
|
133
|
+
// because this will keep the current marks
|
|
134
|
+
if (isOnlyTextContent) {
|
|
135
|
+
// if value is string, we can use it directly
|
|
136
|
+
// otherwise if it is an array, we have to join it
|
|
137
|
+
if (Array.isArray(value)) {
|
|
138
|
+
newContent = value.map(v => v.text || '').join('')
|
|
139
|
+
} else if (value instanceof Fragment) {
|
|
140
|
+
let text = ''
|
|
141
|
+
|
|
142
|
+
value.forEach(node => {
|
|
143
|
+
if (node.text) {
|
|
144
|
+
text += node.text
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
newContent = text
|
|
149
|
+
} else if (typeof value === 'object' && !!value && !!value.text) {
|
|
150
|
+
newContent = value.text
|
|
151
|
+
} else {
|
|
152
|
+
newContent = value as string
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
tr.insertText(newContent, from, to)
|
|
148
156
|
} else {
|
|
149
|
-
newContent =
|
|
150
|
-
}
|
|
157
|
+
newContent = content
|
|
151
158
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
newContent = content
|
|
159
|
+
const fromSelectionAtStart = selection.$from.parentOffset === 0
|
|
160
|
+
const isTextSelection = selection.$from.node().isText || selection.$from.node().isTextblock
|
|
155
161
|
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
if (fromSelectionAtStart && isTextSelection) {
|
|
163
|
+
from = Math.max(0, from - 1)
|
|
164
|
+
}
|
|
158
165
|
|
|
159
|
-
|
|
160
|
-
from = Math.max(0, from - 1)
|
|
166
|
+
tr.replaceWith(from, to, newContent)
|
|
161
167
|
}
|
|
162
168
|
|
|
163
|
-
|
|
164
|
-
|
|
169
|
+
// set cursor at end of inserted content
|
|
170
|
+
if (options.updateSelection) {
|
|
171
|
+
selectionToInsertionEnd(tr, tr.steps.length - 1, -1)
|
|
172
|
+
}
|
|
165
173
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
174
|
+
if (options.applyInputRules) {
|
|
175
|
+
tr.setMeta('applyInputRules', { from, text: newContent })
|
|
176
|
+
}
|
|
170
177
|
|
|
171
|
-
|
|
172
|
-
|
|
178
|
+
if (options.applyPasteRules) {
|
|
179
|
+
tr.setMeta('applyPasteRules', { from, text: newContent })
|
|
180
|
+
}
|
|
173
181
|
}
|
|
174
182
|
|
|
175
|
-
|
|
176
|
-
tr.setMeta('applyPasteRules', { from, text: newContent })
|
|
177
|
-
}
|
|
183
|
+
return true
|
|
178
184
|
}
|
|
179
|
-
|
|
180
|
-
return true
|
|
181
|
-
}
|
package/src/commands/join.ts
CHANGED
|
@@ -44,18 +44,26 @@ declare module '@tiptap/core' {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export const joinUp: RawCommands['joinUp'] =
|
|
48
|
-
|
|
49
|
-
}
|
|
47
|
+
export const joinUp: RawCommands['joinUp'] =
|
|
48
|
+
() =>
|
|
49
|
+
({ state, dispatch }) => {
|
|
50
|
+
return originalJoinUp(state, dispatch)
|
|
51
|
+
}
|
|
50
52
|
|
|
51
|
-
export const joinDown: RawCommands['joinDown'] =
|
|
52
|
-
|
|
53
|
-
}
|
|
53
|
+
export const joinDown: RawCommands['joinDown'] =
|
|
54
|
+
() =>
|
|
55
|
+
({ state, dispatch }) => {
|
|
56
|
+
return originalJoinDown(state, dispatch)
|
|
57
|
+
}
|
|
54
58
|
|
|
55
|
-
export const joinBackward: RawCommands['joinBackward'] =
|
|
56
|
-
|
|
57
|
-
}
|
|
59
|
+
export const joinBackward: RawCommands['joinBackward'] =
|
|
60
|
+
() =>
|
|
61
|
+
({ state, dispatch }) => {
|
|
62
|
+
return originalJoinBackward(state, dispatch)
|
|
63
|
+
}
|
|
58
64
|
|
|
59
|
-
export const joinForward: RawCommands['joinForward'] =
|
|
60
|
-
|
|
61
|
-
}
|
|
65
|
+
export const joinForward: RawCommands['joinForward'] =
|
|
66
|
+
() =>
|
|
67
|
+
({ state, dispatch }) => {
|
|
68
|
+
return originalJoinForward(state, dispatch)
|
|
69
|
+
}
|