@tiptap/core 3.0.0-next.3 → 3.0.0-next.5
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 +2627 -2651
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2423 -2688
- package/dist/index.d.ts +2423 -2688
- package/dist/index.js +2639 -2684
- package/dist/index.js.map +1 -1
- package/dist/jsx-runtime/jsx-runtime.cjs +56 -0
- package/dist/jsx-runtime/jsx-runtime.cjs.map +1 -0
- package/dist/jsx-runtime/jsx-runtime.d.cts +22 -0
- package/dist/jsx-runtime/jsx-runtime.d.ts +22 -0
- package/dist/jsx-runtime/jsx-runtime.js +26 -0
- package/dist/jsx-runtime/jsx-runtime.js.map +1 -0
- package/jsx-runtime/index.cjs +1 -0
- package/jsx-runtime/index.d.cts +1 -0
- package/jsx-runtime/index.d.ts +1 -0
- package/jsx-runtime/index.js +1 -0
- package/package.json +27 -6
- package/src/CommandManager.ts +2 -9
- package/src/Editor.ts +191 -94
- package/src/EventEmitter.ts +7 -10
- package/src/Extendable.ts +483 -0
- package/src/Extension.ts +5 -496
- package/src/ExtensionManager.ts +81 -135
- package/src/InputRule.ts +35 -48
- package/src/Mark.ts +135 -623
- package/src/MarkView.ts +66 -0
- package/src/Node.ts +325 -829
- 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 +12 -5
- 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 +51 -48
- package/src/commands/forEach.ts +2 -2
- package/src/commands/insertContent.ts +12 -14
- package/src/commands/insertContentAt.ts +105 -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 +37 -36
- 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/delete.ts +89 -0
- package/src/extensions/focusEvents.ts +2 -6
- package/src/extensions/index.ts +1 -0
- package/src/extensions/keymap.ts +58 -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 +11 -11
- 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/index.ts +3 -7
- 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/jsx-runtime.ts +64 -0
- 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 +529 -174
- package/src/utilities/createStyleTag.ts +3 -1
- package/src/utilities/deleteProps.ts +7 -11
- package/src/utilities/elementFromString.ts +3 -0
- package/src/utilities/findDuplicates.ts +4 -1
- package/src/utilities/index.ts +1 -0
- 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 +17 -7
- package/src/utilities/removeDuplicates.ts +1 -3
|
@@ -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
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { isTextSelection } from '../helpers/isTextSelection.js'
|
|
2
2
|
import { resolveFocusPosition } from '../helpers/resolveFocusPosition.js'
|
|
3
3
|
import { FocusPosition, RawCommands } from '../types.js'
|
|
4
|
+
import { isAndroid } from '../utilities/isAndroid.js'
|
|
5
|
+
import { isiOS } from '../utilities/isiOS.js'
|
|
4
6
|
|
|
5
7
|
declare module '@tiptap/core' {
|
|
6
8
|
interface Commands<ReturnType> {
|
|
@@ -23,68 +25,69 @@ declare module '@tiptap/core' {
|
|
|
23
25
|
* @default { scrollIntoView: true }
|
|
24
26
|
*/
|
|
25
27
|
options?: {
|
|
26
|
-
scrollIntoView?: boolean
|
|
28
|
+
scrollIntoView?: boolean
|
|
27
29
|
},
|
|
28
|
-
) => ReturnType
|
|
30
|
+
) => ReturnType
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
export const focus: RawCommands['focus'] =
|
|
34
|
-
|
|
35
|
-
view,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
scrollIntoView: true,
|
|
41
|
-
...options,
|
|
42
|
-
}
|
|
35
|
+
export const focus: RawCommands['focus'] =
|
|
36
|
+
(position = null, options = {}) =>
|
|
37
|
+
({ editor, view, tr, dispatch }) => {
|
|
38
|
+
options = {
|
|
39
|
+
scrollIntoView: true,
|
|
40
|
+
...options,
|
|
41
|
+
}
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
const delayedFocus = () => {
|
|
44
|
+
// focus within `requestAnimationFrame` breaks focus on iOS and Android
|
|
45
|
+
// so we have to call this
|
|
46
|
+
if (isiOS() || isAndroid()) {
|
|
47
|
+
;(view.dom as HTMLElement).focus()
|
|
48
|
+
}
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
// For React we have to focus asynchronously. Otherwise wild things happen.
|
|
51
|
+
// see: https://github.com/ueberdosis/tiptap/issues/1520
|
|
52
|
+
requestAnimationFrame(() => {
|
|
53
|
+
if (!editor.isDestroyed) {
|
|
54
|
+
view.focus()
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
if (options?.scrollIntoView) {
|
|
57
|
+
editor.commands.scrollIntoView()
|
|
58
|
+
}
|
|
55
59
|
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
60
|
+
})
|
|
61
|
+
}
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
if ((view.hasFocus() && position === null) || position === false) {
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
// we don’t try to resolve a NodeSelection or CellSelection
|
|
68
|
+
if (dispatch && position === null && !isTextSelection(editor.state.selection)) {
|
|
69
|
+
delayedFocus()
|
|
70
|
+
return true
|
|
71
|
+
}
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
// pass through tr.doc instead of editor.state.doc
|
|
74
|
+
// since transactions could change the editors state before this command has been run
|
|
75
|
+
const selection = resolveFocusPosition(tr.doc, position) || editor.state.selection
|
|
76
|
+
const isSameSelection = editor.state.selection.eq(selection)
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
if (dispatch) {
|
|
79
|
+
if (!isSameSelection) {
|
|
80
|
+
tr.setSelection(selection)
|
|
81
|
+
}
|
|
79
82
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
// `tr.setSelection` resets the stored marks
|
|
84
|
+
// so we’ll restore them if the selection is the same as before
|
|
85
|
+
if (isSameSelection && tr.storedMarks) {
|
|
86
|
+
tr.setStoredMarks(tr.storedMarks)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
delayedFocus()
|
|
84
90
|
}
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
return true
|
|
87
93
|
}
|
|
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,129 @@ 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 (
|
|
92
|
+
'collaboration' in editor.storage &&
|
|
93
|
+
typeof editor.storage.collaboration === 'object' &&
|
|
94
|
+
editor.storage.collaboration
|
|
95
|
+
) {
|
|
96
|
+
;(editor.storage.collaboration as any).isDisabled = true
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
98
102
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const nodes = isFragment(content) ? content : [content]
|
|
103
|
+
let { from, to } =
|
|
104
|
+
typeof position === 'number' ? { from: position, to: position } : { from: position.from, to: position.to }
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
let isOnlyTextContent = true
|
|
107
|
+
let isOnlyBlockContent = true
|
|
108
|
+
const nodes = isFragment(content) ? content : [content]
|
|
106
109
|
|
|
107
|
-
|
|
110
|
+
nodes.forEach(node => {
|
|
111
|
+
// check if added node is valid
|
|
112
|
+
node.check()
|
|
108
113
|
|
|
109
|
-
|
|
110
|
-
})
|
|
114
|
+
isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false
|
|
111
115
|
|
|
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
|
|
116
|
+
isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false
|
|
117
|
+
})
|
|
120
118
|
|
|
121
|
-
if
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
// check if we can replace the wrapping node by
|
|
120
|
+
// the newly inserted content
|
|
121
|
+
// example:
|
|
122
|
+
// replace an empty paragraph by an inserted image
|
|
123
|
+
// instead of inserting the image below the paragraph
|
|
124
|
+
if (from === to && isOnlyBlockContent) {
|
|
125
|
+
const { parent } = tr.doc.resolve(from)
|
|
126
|
+
const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount
|
|
127
|
+
|
|
128
|
+
if (isEmptyTextBlock) {
|
|
129
|
+
from -= 1
|
|
130
|
+
to += 1
|
|
131
|
+
}
|
|
124
132
|
}
|
|
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
133
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
134
|
+
let newContent
|
|
135
|
+
|
|
136
|
+
// if there is only plain text we have to use `insertText`
|
|
137
|
+
// because this will keep the current marks
|
|
138
|
+
if (isOnlyTextContent) {
|
|
139
|
+
// if value is string, we can use it directly
|
|
140
|
+
// otherwise if it is an array, we have to join it
|
|
141
|
+
if (Array.isArray(value)) {
|
|
142
|
+
newContent = value.map(v => v.text || '').join('')
|
|
143
|
+
} else if (value instanceof Fragment) {
|
|
144
|
+
let text = ''
|
|
145
|
+
|
|
146
|
+
value.forEach(node => {
|
|
147
|
+
if (node.text) {
|
|
148
|
+
text += node.text
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
newContent = text
|
|
153
|
+
} else if (typeof value === 'object' && !!value && !!value.text) {
|
|
154
|
+
newContent = value.text
|
|
155
|
+
} else {
|
|
156
|
+
newContent = value as string
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
tr.insertText(newContent, from, to)
|
|
148
160
|
} else {
|
|
149
|
-
newContent =
|
|
150
|
-
}
|
|
161
|
+
newContent = content
|
|
151
162
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
newContent = content
|
|
163
|
+
const fromSelectionAtStart = selection.$from.parentOffset === 0
|
|
164
|
+
const isTextSelection = selection.$from.node().isText || selection.$from.node().isTextblock
|
|
155
165
|
|
|
156
|
-
|
|
157
|
-
|
|
166
|
+
if (fromSelectionAtStart && isTextSelection) {
|
|
167
|
+
from = Math.max(0, from - 1)
|
|
168
|
+
}
|
|
158
169
|
|
|
159
|
-
|
|
160
|
-
from = Math.max(0, from - 1)
|
|
170
|
+
tr.replaceWith(from, to, newContent)
|
|
161
171
|
}
|
|
162
172
|
|
|
163
|
-
|
|
164
|
-
|
|
173
|
+
// set cursor at end of inserted content
|
|
174
|
+
if (options.updateSelection) {
|
|
175
|
+
selectionToInsertionEnd(tr, tr.steps.length - 1, -1)
|
|
176
|
+
}
|
|
165
177
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
178
|
+
if (options.applyInputRules) {
|
|
179
|
+
tr.setMeta('applyInputRules', { from, text: newContent })
|
|
180
|
+
}
|
|
170
181
|
|
|
171
|
-
|
|
172
|
-
|
|
182
|
+
if (options.applyPasteRules) {
|
|
183
|
+
tr.setMeta('applyPasteRules', { from, text: newContent })
|
|
184
|
+
}
|
|
173
185
|
}
|
|
174
186
|
|
|
175
|
-
|
|
176
|
-
tr.setMeta('applyPasteRules', { from, text: newContent })
|
|
177
|
-
}
|
|
187
|
+
return true
|
|
178
188
|
}
|
|
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
|
+
}
|
|
@@ -14,26 +14,24 @@ declare module '@tiptap/core' {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export const joinItemBackward: RawCommands['joinItemBackward'] =
|
|
18
|
-
|
|
19
|
-
dispatch,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const point = joinPoint(state.doc, state.selection.$from.pos, -1)
|
|
17
|
+
export const joinItemBackward: RawCommands['joinItemBackward'] =
|
|
18
|
+
() =>
|
|
19
|
+
({ state, dispatch, tr }) => {
|
|
20
|
+
try {
|
|
21
|
+
const point = joinPoint(state.doc, state.selection.$from.pos, -1)
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
if (point === null || point === undefined) {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
tr.join(point, 2)
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
if (dispatch) {
|
|
30
|
+
dispatch(tr)
|
|
31
|
+
}
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
return true
|
|
34
|
+
} catch {
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
38
37
|
}
|
|
39
|
-
}
|
|
@@ -14,26 +14,24 @@ declare module '@tiptap/core' {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export const joinItemForward: RawCommands['joinItemForward'] =
|
|
18
|
-
|
|
19
|
-
dispatch,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const point = joinPoint(state.doc, state.selection.$from.pos, +1)
|
|
17
|
+
export const joinItemForward: RawCommands['joinItemForward'] =
|
|
18
|
+
() =>
|
|
19
|
+
({ state, dispatch, tr }) => {
|
|
20
|
+
try {
|
|
21
|
+
const point = joinPoint(state.doc, state.selection.$from.pos, +1)
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
if (point === null || point === undefined) {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
tr.join(point, 2)
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
if (dispatch) {
|
|
30
|
+
dispatch(tr)
|
|
31
|
+
}
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
return true
|
|
34
|
+
} catch {
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
38
37
|
}
|
|
39
|
-
}
|
|
@@ -13,6 +13,8 @@ declare module '@tiptap/core' {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const joinTextblockBackward: RawCommands['joinTextblockBackward'] =
|
|
17
|
-
|
|
18
|
-
}
|
|
16
|
+
export const joinTextblockBackward: RawCommands['joinTextblockBackward'] =
|
|
17
|
+
() =>
|
|
18
|
+
({ state, dispatch }) => {
|
|
19
|
+
return originalCommand(state, dispatch)
|
|
20
|
+
}
|
|
@@ -13,6 +13,8 @@ declare module '@tiptap/core' {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const joinTextblockForward: RawCommands['joinTextblockForward'] =
|
|
17
|
-
|
|
18
|
-
}
|
|
16
|
+
export const joinTextblockForward: RawCommands['joinTextblockForward'] =
|
|
17
|
+
() =>
|
|
18
|
+
({ state, dispatch }) => {
|
|
19
|
+
return originalCommand(state, dispatch)
|
|
20
|
+
}
|