@tiptap/core 3.0.0-next.3 → 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
|
@@ -30,34 +30,36 @@ declare module '@tiptap/core' {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export const unsetMark: RawCommands['unsetMark'] =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
export const unsetMark: RawCommands['unsetMark'] =
|
|
34
|
+
(typeOrName, options = {}) =>
|
|
35
|
+
({ tr, state, dispatch }) => {
|
|
36
|
+
const { extendEmptyMarkRange = false } = options
|
|
37
|
+
const { selection } = tr
|
|
38
|
+
const type = getMarkType(typeOrName, state.schema)
|
|
39
|
+
const { $from, empty, ranges } = selection
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
if (!dispatch) {
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
if (empty && extendEmptyMarkRange) {
|
|
46
|
+
let { from, to } = selection
|
|
47
|
+
const attrs = $from.marks().find(mark => mark.type === type)?.attrs
|
|
48
|
+
const range = getMarkRange($from, type, attrs)
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
if (range) {
|
|
51
|
+
from = range.from
|
|
52
|
+
to = range.to
|
|
53
|
+
}
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
tr.removeMark(from, to, type)
|
|
56
|
+
} else {
|
|
57
|
+
ranges.forEach(range => {
|
|
58
|
+
tr.removeMark(range.$from.pos, range.$to.pos, type)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
tr.removeStoredMark(type)
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Mark, MarkType, Node, NodeType,
|
|
3
|
-
} from '@tiptap/pm/model'
|
|
1
|
+
import { Mark, MarkType, Node, NodeType } from '@tiptap/pm/model'
|
|
4
2
|
import { SelectionRange } from '@tiptap/pm/state'
|
|
5
3
|
|
|
6
4
|
import { getMarkType } from '../helpers/getMarkType.js'
|
|
@@ -32,117 +30,111 @@ declare module '@tiptap/core' {
|
|
|
32
30
|
}
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
export const updateAttributes: RawCommands['updateAttributes'] =
|
|
33
|
+
export const updateAttributes: RawCommands['updateAttributes'] =
|
|
34
|
+
(typeOrName, attributes = {}) =>
|
|
35
|
+
({ tr, state, dispatch }) => {
|
|
36
|
+
let nodeType: NodeType | null = null
|
|
37
|
+
let markType: MarkType | null = null
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
const schemaType = getSchemaTypeNameByName(
|
|
40
|
+
typeof typeOrName === 'string' ? typeOrName : typeOrName.name,
|
|
41
|
+
state.schema,
|
|
42
|
+
)
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
if (!schemaType) {
|
|
46
|
-
return false
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (schemaType === 'node') {
|
|
50
|
-
nodeType = getNodeType(typeOrName as NodeType, state.schema)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (schemaType === 'mark') {
|
|
54
|
-
markType = getMarkType(typeOrName as MarkType, state.schema)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (dispatch) {
|
|
58
|
-
tr.selection.ranges.forEach((range: SelectionRange) => {
|
|
44
|
+
if (!schemaType) {
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
59
47
|
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
if (schemaType === 'node') {
|
|
49
|
+
nodeType = getNodeType(typeOrName as NodeType, state.schema)
|
|
50
|
+
}
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
let trimmedTo: number
|
|
52
|
+
if (schemaType === 'mark') {
|
|
53
|
+
markType = getMarkType(typeOrName as MarkType, state.schema)
|
|
54
|
+
}
|
|
67
55
|
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
if (dispatch) {
|
|
57
|
+
tr.selection.ranges.forEach((range: SelectionRange) => {
|
|
58
|
+
const from = range.$from.pos
|
|
59
|
+
const to = range.$to.pos
|
|
70
60
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
lastNode = node
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
} else {
|
|
79
|
-
state.doc.nodesBetween(from, to, (node: Node, pos: number) => {
|
|
80
|
-
|
|
81
|
-
if (pos < from && nodeType && nodeType === node.type) {
|
|
82
|
-
trimmedFrom = Math.max(pos, from)
|
|
83
|
-
trimmedTo = Math.min(pos + node.nodeSize, to)
|
|
84
|
-
lastPos = pos
|
|
85
|
-
lastNode = node
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (pos >= from && pos <= to) {
|
|
61
|
+
let lastPos: number | undefined
|
|
62
|
+
let lastNode: Node | undefined
|
|
63
|
+
let trimmedFrom: number
|
|
64
|
+
let trimmedTo: number
|
|
89
65
|
|
|
66
|
+
if (tr.selection.empty) {
|
|
67
|
+
state.doc.nodesBetween(from, to, (node: Node, pos: number) => {
|
|
90
68
|
if (nodeType && nodeType === node.type) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
69
|
+
trimmedFrom = Math.max(pos, from)
|
|
70
|
+
trimmedTo = Math.min(pos + node.nodeSize, to)
|
|
71
|
+
lastPos = pos
|
|
72
|
+
lastNode = node
|
|
95
73
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
tr.addMark(
|
|
105
|
-
trimmedFrom2,
|
|
106
|
-
trimmedTo2,
|
|
107
|
-
markType.create({
|
|
108
|
-
...mark.attrs,
|
|
109
|
-
...attributes,
|
|
110
|
-
}),
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
})
|
|
74
|
+
})
|
|
75
|
+
} else {
|
|
76
|
+
state.doc.nodesBetween(from, to, (node: Node, pos: number) => {
|
|
77
|
+
if (pos < from && nodeType && nodeType === node.type) {
|
|
78
|
+
trimmedFrom = Math.max(pos, from)
|
|
79
|
+
trimmedTo = Math.min(pos + node.nodeSize, to)
|
|
80
|
+
lastPos = pos
|
|
81
|
+
lastNode = node
|
|
114
82
|
}
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
83
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
84
|
+
if (pos >= from && pos <= to) {
|
|
85
|
+
if (nodeType && nodeType === node.type) {
|
|
86
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
87
|
+
...node.attrs,
|
|
88
|
+
...attributes,
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (markType && node.marks.length) {
|
|
93
|
+
node.marks.forEach((mark: Mark) => {
|
|
94
|
+
if (markType === mark.type) {
|
|
95
|
+
const trimmedFrom2 = Math.max(pos, from)
|
|
96
|
+
const trimmedTo2 = Math.min(pos + node.nodeSize, to)
|
|
97
|
+
|
|
98
|
+
tr.addMark(
|
|
99
|
+
trimmedFrom2,
|
|
100
|
+
trimmedTo2,
|
|
101
|
+
markType.create({
|
|
102
|
+
...mark.attrs,
|
|
103
|
+
...attributes,
|
|
104
|
+
}),
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
125
110
|
})
|
|
126
111
|
}
|
|
127
112
|
|
|
128
|
-
if (
|
|
129
|
-
|
|
113
|
+
if (lastNode) {
|
|
114
|
+
if (lastPos !== undefined) {
|
|
115
|
+
tr.setNodeMarkup(lastPos, undefined, {
|
|
116
|
+
...lastNode.attrs,
|
|
117
|
+
...attributes,
|
|
118
|
+
})
|
|
119
|
+
}
|
|
130
120
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
121
|
+
if (markType && lastNode.marks.length) {
|
|
122
|
+
lastNode.marks.forEach((mark: Mark) => {
|
|
123
|
+
if (markType === mark.type) {
|
|
124
|
+
tr.addMark(
|
|
125
|
+
trimmedFrom,
|
|
126
|
+
trimmedTo,
|
|
127
|
+
markType.create({
|
|
128
|
+
...mark.attrs,
|
|
129
|
+
...attributes,
|
|
130
|
+
}),
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
}
|
|
142
135
|
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
136
|
+
})
|
|
137
|
+
}
|
|
146
138
|
|
|
147
|
-
|
|
148
|
-
}
|
|
139
|
+
return true
|
|
140
|
+
}
|
package/src/commands/wrapIn.ts
CHANGED
|
@@ -18,8 +18,10 @@ declare module '@tiptap/core' {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export const wrapIn: RawCommands['wrapIn'] =
|
|
22
|
-
|
|
21
|
+
export const wrapIn: RawCommands['wrapIn'] =
|
|
22
|
+
(typeOrName, attributes = {}) =>
|
|
23
|
+
({ state, dispatch }) => {
|
|
24
|
+
const type = getNodeType(typeOrName, state.schema)
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
+
return originalWrapIn(type, attributes)(state, dispatch)
|
|
27
|
+
}
|
|
@@ -18,8 +18,10 @@ declare module '@tiptap/core' {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export const wrapInList: RawCommands['wrapInList'] =
|
|
22
|
-
|
|
21
|
+
export const wrapInList: RawCommands['wrapInList'] =
|
|
22
|
+
(typeOrName, attributes = {}) =>
|
|
23
|
+
({ state, dispatch }) => {
|
|
24
|
+
const type = getNodeType(typeOrName, state.schema)
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
+
return originalWrapInList(type, attributes)(state, dispatch)
|
|
27
|
+
}
|
|
@@ -5,7 +5,7 @@ import { getTextBetween } from '../helpers/getTextBetween.js'
|
|
|
5
5
|
import { getTextSerializersFromSchema } from '../helpers/getTextSerializersFromSchema.js'
|
|
6
6
|
|
|
7
7
|
export type ClipboardTextSerializerOptions = {
|
|
8
|
-
blockSeparator?: string
|
|
8
|
+
blockSeparator?: string
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export const ClipboardTextSerializer = Extension.create<ClipboardTextSerializerOptions>({
|
|
@@ -33,9 +33,7 @@ export const ClipboardTextSerializer = Extension.create<ClipboardTextSerializerO
|
|
|
33
33
|
const range = { from, to }
|
|
34
34
|
|
|
35
35
|
return getTextBetween(doc, range, {
|
|
36
|
-
...(this.options.blockSeparator !== undefined
|
|
37
|
-
? { blockSeparator: this.options.blockSeparator }
|
|
38
|
-
: {}),
|
|
36
|
+
...(this.options.blockSeparator !== undefined ? { blockSeparator: this.options.blockSeparator } : {}),
|
|
39
37
|
textSerializers,
|
|
40
38
|
})
|
|
41
39
|
},
|
|
@@ -16,9 +16,7 @@ export const FocusEvents = Extension.create({
|
|
|
16
16
|
focus: (view, event: Event) => {
|
|
17
17
|
editor.isFocused = true
|
|
18
18
|
|
|
19
|
-
const transaction = editor.state.tr
|
|
20
|
-
.setMeta('focus', { event })
|
|
21
|
-
.setMeta('addToHistory', false)
|
|
19
|
+
const transaction = editor.state.tr.setMeta('focus', { event }).setMeta('addToHistory', false)
|
|
22
20
|
|
|
23
21
|
view.dispatch(transaction)
|
|
24
22
|
|
|
@@ -27,9 +25,7 @@ export const FocusEvents = Extension.create({
|
|
|
27
25
|
blur: (view, event: Event) => {
|
|
28
26
|
editor.isFocused = false
|
|
29
27
|
|
|
30
|
-
const transaction = editor.state.tr
|
|
31
|
-
.setMeta('blur', { event })
|
|
32
|
-
.setMeta('addToHistory', false)
|
|
28
|
+
const transaction = editor.state.tr.setMeta('blur', { event }).setMeta('addToHistory', false)
|
|
33
29
|
|
|
34
30
|
view.dispatch(transaction)
|
|
35
31
|
|
package/src/extensions/keymap.ts
CHANGED
|
@@ -11,54 +11,59 @@ export const Keymap = Extension.create({
|
|
|
11
11
|
name: 'keymap',
|
|
12
12
|
|
|
13
13
|
addKeyboardShortcuts() {
|
|
14
|
-
const handleBackspace = () =>
|
|
15
|
-
() =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
() =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
14
|
+
const handleBackspace = () =>
|
|
15
|
+
this.editor.commands.first(({ commands }) => [
|
|
16
|
+
() => commands.undoInputRule(),
|
|
17
|
+
|
|
18
|
+
// maybe convert first text block node to default node
|
|
19
|
+
() =>
|
|
20
|
+
commands.command(({ tr }) => {
|
|
21
|
+
const { selection, doc } = tr
|
|
22
|
+
const { empty, $anchor } = selection
|
|
23
|
+
const { pos, parent } = $anchor
|
|
24
|
+
const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor
|
|
25
|
+
const parentIsIsolating = $parentPos.parent.type.spec.isolating
|
|
26
|
+
|
|
27
|
+
const parentPos = $anchor.pos - $anchor.parentOffset
|
|
28
|
+
|
|
29
|
+
const isAtStart =
|
|
30
|
+
parentIsIsolating && $parentPos.parent.childCount === 1
|
|
31
|
+
? parentPos === $anchor.pos
|
|
32
|
+
: Selection.atStart(doc).from === pos
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
!empty ||
|
|
36
|
+
!parent.type.isTextblock ||
|
|
37
|
+
parent.textContent.length ||
|
|
38
|
+
!isAtStart ||
|
|
39
|
+
(isAtStart && $anchor.parent.type.name === 'paragraph') // prevent clearNodes when no nodes to clear, otherwise history stack is appended
|
|
40
|
+
) {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return commands.clearNodes()
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
() => commands.deleteSelection(),
|
|
48
|
+
() => commands.joinBackward(),
|
|
49
|
+
() => commands.selectNodeBackward(),
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
const handleDelete = () =>
|
|
53
|
+
this.editor.commands.first(({ commands }) => [
|
|
54
|
+
() => commands.deleteSelection(),
|
|
55
|
+
() => commands.deleteCurrentNode(),
|
|
56
|
+
() => commands.joinForward(),
|
|
57
|
+
() => commands.selectNodeForward(),
|
|
58
|
+
])
|
|
59
|
+
|
|
60
|
+
const handleEnter = () =>
|
|
61
|
+
this.editor.commands.first(({ commands }) => [
|
|
62
|
+
() => commands.newlineInCode(),
|
|
63
|
+
() => commands.createParagraphNear(),
|
|
64
|
+
() => commands.liftEmptyBlock(),
|
|
65
|
+
() => commands.splitBlock(),
|
|
66
|
+
])
|
|
62
67
|
|
|
63
68
|
const baseKeymap = {
|
|
64
69
|
Enter: handleEnter,
|
|
@@ -104,8 +109,7 @@ export const Keymap = Extension.create({
|
|
|
104
109
|
new Plugin({
|
|
105
110
|
key: new PluginKey('clearDocument'),
|
|
106
111
|
appendTransaction: (transactions, oldState, newState) => {
|
|
107
|
-
const docChanges = transactions.some(transaction => transaction.docChanged)
|
|
108
|
-
&& !oldState.doc.eq(newState.doc)
|
|
112
|
+
const docChanges = transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc)
|
|
109
113
|
|
|
110
114
|
const ignoreTr = transactions.some(transaction => transaction.getMeta('preventClearDocument'))
|
|
111
115
|
|
package/src/extensions/paste.ts
CHANGED
|
@@ -10,7 +10,7 @@ export const Tabindex = Extension.create({
|
|
|
10
10
|
new Plugin({
|
|
11
11
|
key: new PluginKey('tabindex'),
|
|
12
12
|
props: {
|
|
13
|
-
attributes: (): { [name: string]: string
|
|
13
|
+
attributes: (): { [name: string]: string } => (this.editor.isEditable ? { tabindex: '0' } : {}),
|
|
14
14
|
},
|
|
15
15
|
}),
|
|
16
16
|
]
|
|
@@ -8,10 +8,7 @@ import { Transform } from '@tiptap/pm/transform'
|
|
|
8
8
|
* @param transactions The transactions to combine
|
|
9
9
|
* @returns A new `Transform` with all steps of the passed transactions
|
|
10
10
|
*/
|
|
11
|
-
export function combineTransactionSteps(
|
|
12
|
-
oldDoc: ProseMirrorNode,
|
|
13
|
-
transactions: Transaction[],
|
|
14
|
-
): Transform {
|
|
11
|
+
export function combineTransactionSteps(oldDoc: ProseMirrorNode, transactions: Transaction[]): Transform {
|
|
15
12
|
const transform = new Transform(oldDoc)
|
|
16
13
|
|
|
17
14
|
transactions.forEach(transaction => {
|
|
@@ -5,10 +5,7 @@ import { EditorState, Transaction } from '@tiptap/pm/state'
|
|
|
5
5
|
* @param config The transaction and state to create the chainable state from
|
|
6
6
|
* @returns A chainable Editor state object
|
|
7
7
|
*/
|
|
8
|
-
export function createChainableState(config: {
|
|
9
|
-
transaction: Transaction
|
|
10
|
-
state: EditorState
|
|
11
|
-
}): EditorState {
|
|
8
|
+
export function createChainableState(config: { transaction: Transaction; state: EditorState }): EditorState {
|
|
12
9
|
const { state, transaction } = config
|
|
13
10
|
let { selection } = transaction
|
|
14
11
|
let { doc } = transaction
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Fragment, Node as ProseMirrorNode, ParseOptions, Schema,
|
|
3
|
-
} from '@tiptap/pm/model'
|
|
1
|
+
import { Fragment, Node as ProseMirrorNode, ParseOptions, Schema } from '@tiptap/pm/model'
|
|
4
2
|
|
|
5
3
|
import { Content } from '../types.js'
|
|
6
4
|
import { createNodeFromContent } from './createNodeFromContent.js'
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DOMParser,
|
|
3
|
-
Fragment,
|
|
4
|
-
Node as ProseMirrorNode,
|
|
5
|
-
ParseOptions,
|
|
6
|
-
Schema,
|
|
7
|
-
} from '@tiptap/pm/model'
|
|
1
|
+
import { DOMParser, Fragment, Node as ProseMirrorNode, ParseOptions, Schema } from '@tiptap/pm/model'
|
|
8
2
|
|
|
9
3
|
import { Content } from '../types.js'
|
|
10
4
|
import { elementFromString } from '../utilities/elementFromString.js'
|
|
@@ -67,7 +61,6 @@ export function createNodeFromContent(
|
|
|
67
61
|
}
|
|
68
62
|
|
|
69
63
|
if (isTextContent) {
|
|
70
|
-
|
|
71
64
|
// Check for invalid content
|
|
72
65
|
if (options.errorOnInvalidContent) {
|
|
73
66
|
let hasInvalidContent = false
|
|
@@ -106,7 +99,9 @@ export function createNodeFromContent(
|
|
|
106
99
|
}
|
|
107
100
|
|
|
108
101
|
if (options.errorOnInvalidContent && hasInvalidContent) {
|
|
109
|
-
throw new Error('[tiptap error]: Invalid HTML content', {
|
|
102
|
+
throw new Error('[tiptap error]: Invalid HTML content', {
|
|
103
|
+
cause: new Error(`Invalid element found: ${invalidContent}`),
|
|
104
|
+
})
|
|
110
105
|
}
|
|
111
106
|
}
|
|
112
107
|
|
|
@@ -117,7 +112,6 @@ export function createNodeFromContent(
|
|
|
117
112
|
}
|
|
118
113
|
|
|
119
114
|
return parser.parse(elementFromString(content), options.parseOptions)
|
|
120
|
-
|
|
121
115
|
}
|
|
122
116
|
|
|
123
117
|
return createNodeFromContent('', schema, options)
|
|
@@ -9,11 +9,7 @@ import { NodeWithPos, Predicate, Range } from '../types.js'
|
|
|
9
9
|
* @param predicate The predicate to match
|
|
10
10
|
* @returns An array of nodes with their positions
|
|
11
11
|
*/
|
|
12
|
-
export function findChildrenInRange(
|
|
13
|
-
node: ProseMirrorNode,
|
|
14
|
-
range: Range,
|
|
15
|
-
predicate: Predicate,
|
|
16
|
-
): NodeWithPos[] {
|
|
12
|
+
export function findChildrenInRange(node: ProseMirrorNode, range: Range, predicate: Predicate): NodeWithPos[] {
|
|
17
13
|
const nodesWithPos: NodeWithPos[] = []
|
|
18
14
|
|
|
19
15
|
// if (range.from === range.to) {
|
|
@@ -11,6 +11,8 @@ import { findParentNodeClosestToPos } from './findParentNodeClosestToPos.js'
|
|
|
11
11
|
* findParentNode(node => node.type.name === 'paragraph')
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
|
-
export function findParentNode(
|
|
14
|
+
export function findParentNode(
|
|
15
|
+
predicate: Predicate,
|
|
16
|
+
): (selection: Selection) => ReturnType<typeof findParentNodeClosestToPos> {
|
|
15
17
|
return (selection: Selection) => findParentNodeClosestToPos(selection.$from, predicate)
|
|
16
18
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AnyConfig, Extensions } from '../types.js'
|
|
2
|
+
import { getExtensionField } from './getExtensionField.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create a flattened array of extensions by traversing the `addExtensions` field.
|
|
6
|
+
* @param extensions An array of Tiptap extensions
|
|
7
|
+
* @returns A flattened array of Tiptap extensions
|
|
8
|
+
*/
|
|
9
|
+
export function flattenExtensions(extensions: Extensions): Extensions {
|
|
10
|
+
return (
|
|
11
|
+
extensions
|
|
12
|
+
.map(extension => {
|
|
13
|
+
const context = {
|
|
14
|
+
name: extension.name,
|
|
15
|
+
options: extension.options,
|
|
16
|
+
storage: extension.storage,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const addExtensions = getExtensionField<AnyConfig['addExtensions']>(extension, 'addExtensions', context)
|
|
20
|
+
|
|
21
|
+
if (addExtensions) {
|
|
22
|
+
return [extension, ...flattenExtensions(addExtensions())]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return extension
|
|
26
|
+
})
|
|
27
|
+
// `Infinity` will break TypeScript so we set a number that is probably high enough
|
|
28
|
+
.flat(10)
|
|
29
|
+
)
|
|
30
|
+
}
|
|
@@ -11,10 +11,7 @@ import { getSchemaTypeNameByName } from './getSchemaTypeNameByName.js'
|
|
|
11
11
|
* @param typeOrName The node or mark type or name
|
|
12
12
|
* @returns The attributes of the node or mark or an empty object
|
|
13
13
|
*/
|
|
14
|
-
export function getAttributes(
|
|
15
|
-
state: EditorState,
|
|
16
|
-
typeOrName: string | NodeType | MarkType,
|
|
17
|
-
): Record<string, any> {
|
|
14
|
+
export function getAttributes(state: EditorState, typeOrName: string | NodeType | MarkType): Record<string, any> {
|
|
18
15
|
const schemaType = getSchemaTypeNameByName(
|
|
19
16
|
typeof typeOrName === 'string' ? typeOrName : typeOrName.name,
|
|
20
17
|
state.schema,
|