@tiptap/core 3.22.1 → 3.22.2
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/dist/index.cjs +81 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +43 -5
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/commands/toggleList.ts +69 -7
- package/src/pasteRules/markPasteRule.ts +10 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiptap/core",
|
|
3
3
|
"description": "headless rich text editor",
|
|
4
|
-
"version": "3.22.
|
|
4
|
+
"version": "3.22.2",
|
|
5
5
|
"homepage": "https://tiptap.dev",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"tiptap",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"jsx-dev-runtime"
|
|
53
53
|
],
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@tiptap/pm": "^3.22.
|
|
55
|
+
"@tiptap/pm": "^3.22.2"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@tiptap/pm": "^3.22.
|
|
58
|
+
"@tiptap/pm": "^3.22.2"
|
|
59
59
|
},
|
|
60
60
|
"repository": {
|
|
61
61
|
"type": "git",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { NodeType } from '@tiptap/pm/model'
|
|
2
2
|
import type { Transaction } from '@tiptap/pm/state'
|
|
3
|
+
import { TextSelection } from '@tiptap/pm/state'
|
|
3
4
|
import { canJoin } from '@tiptap/pm/transform'
|
|
4
5
|
|
|
5
6
|
import { findParentNode } from '../helpers/findParentNode.js'
|
|
@@ -78,6 +79,21 @@ declare module '@tiptap/core' {
|
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
function createInnerSelectionForWholeDocList(tr: Transaction) {
|
|
83
|
+
const doc = tr.doc
|
|
84
|
+
const list = doc.firstChild
|
|
85
|
+
|
|
86
|
+
if (!list) {
|
|
87
|
+
return null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Place the selection inside the list node so that ProseMirror's
|
|
91
|
+
// liftListItem command can operate. AllSelection sits at the doc root.
|
|
92
|
+
const from = 1
|
|
93
|
+
const to = list.nodeSize - 1
|
|
94
|
+
|
|
95
|
+
return TextSelection.create(doc, from, to)
|
|
96
|
+
}
|
|
81
97
|
export const toggleList: RawCommands['toggleList'] =
|
|
82
98
|
(listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) =>
|
|
83
99
|
({ editor, tr, state, dispatch, chain, commands, can }) => {
|
|
@@ -96,17 +112,65 @@ export const toggleList: RawCommands['toggleList'] =
|
|
|
96
112
|
|
|
97
113
|
const parentList = findParentNode(node => isList(node.type.name, extensions))(selection)
|
|
98
114
|
|
|
99
|
-
|
|
115
|
+
// When the user presses Ctrl/Cmd+A, ProseMirror creates an `AllSelection`
|
|
116
|
+
// covering the entire document (0..doc.content.size). In that case
|
|
117
|
+
// `findParentNode` cannot detect the surrounding list because the
|
|
118
|
+
// selection sits at the document root. If the document consists of a
|
|
119
|
+
// single top-level list node, treat that list as the active list so the
|
|
120
|
+
// toggle logic can correctly lift or change it.
|
|
121
|
+
const isAllSelection = selection.from === 0 && selection.to === state.doc.content.size
|
|
122
|
+
const topLevelNodes = state.doc.content.content
|
|
123
|
+
const soleTopLevelNode = topLevelNodes.length === 1 ? topLevelNodes[0] : null
|
|
124
|
+
const allSelectionList =
|
|
125
|
+
isAllSelection && soleTopLevelNode && isList(soleTopLevelNode.type.name, extensions)
|
|
126
|
+
? {
|
|
127
|
+
node: soleTopLevelNode,
|
|
128
|
+
pos: 0,
|
|
129
|
+
depth: 0,
|
|
130
|
+
}
|
|
131
|
+
: null
|
|
132
|
+
|
|
133
|
+
const currentList = parentList ?? allSelectionList
|
|
134
|
+
|
|
135
|
+
const isInsideExistingList = !!parentList && range.depth >= 1 && range.depth - parentList.depth <= 1
|
|
136
|
+
|
|
137
|
+
const hasWholeDocSelectedList = !!allSelectionList
|
|
138
|
+
if ((isInsideExistingList || hasWholeDocSelectedList) && currentList) {
|
|
100
139
|
// remove list
|
|
101
|
-
if (
|
|
140
|
+
if (currentList.node.type === listType) {
|
|
141
|
+
if (isAllSelection && hasWholeDocSelectedList) {
|
|
142
|
+
return chain()
|
|
143
|
+
.command(({ tr: trx, dispatch: disp }) => {
|
|
144
|
+
// Ctrl/Cmd+A creates an AllSelection at the document root.
|
|
145
|
+
// When the whole document is a single top-level list, normalize the
|
|
146
|
+
// selection into that list before lifting, since liftListItem expects
|
|
147
|
+
// a selection inside a list item.
|
|
148
|
+
const nextSelection = createInnerSelectionForWholeDocList(trx)
|
|
149
|
+
|
|
150
|
+
if (!nextSelection) {
|
|
151
|
+
return false
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
trx.setSelection(nextSelection)
|
|
155
|
+
|
|
156
|
+
if (disp) {
|
|
157
|
+
disp(trx)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return true
|
|
161
|
+
})
|
|
162
|
+
.liftListItem(itemType)
|
|
163
|
+
.run()
|
|
164
|
+
}
|
|
165
|
+
|
|
102
166
|
return commands.liftListItem(itemType)
|
|
103
167
|
}
|
|
104
168
|
|
|
105
169
|
// change list type
|
|
106
|
-
if (isList(
|
|
170
|
+
if (isList(currentList.node.type.name, extensions) && listType.validContent(currentList.node.content)) {
|
|
107
171
|
return chain()
|
|
108
172
|
.command(() => {
|
|
109
|
-
tr.setNodeMarkup(
|
|
173
|
+
tr.setNodeMarkup(currentList.pos, listType)
|
|
110
174
|
|
|
111
175
|
return true
|
|
112
176
|
})
|
|
@@ -115,17 +179,16 @@ export const toggleList: RawCommands['toggleList'] =
|
|
|
115
179
|
.run()
|
|
116
180
|
}
|
|
117
181
|
}
|
|
182
|
+
|
|
118
183
|
if (!keepMarks || !marks || !dispatch) {
|
|
119
184
|
return (
|
|
120
185
|
chain()
|
|
121
186
|
// try to convert node to default node if needed
|
|
122
187
|
.command(() => {
|
|
123
188
|
const canWrapInList = can().wrapInList(listType, attributes)
|
|
124
|
-
|
|
125
189
|
if (canWrapInList) {
|
|
126
190
|
return true
|
|
127
191
|
}
|
|
128
|
-
|
|
129
192
|
return commands.clearNodes()
|
|
130
193
|
})
|
|
131
194
|
.wrapInList(listType, attributes)
|
|
@@ -148,7 +211,6 @@ export const toggleList: RawCommands['toggleList'] =
|
|
|
148
211
|
if (canWrapInList) {
|
|
149
212
|
return true
|
|
150
213
|
}
|
|
151
|
-
|
|
152
214
|
return commands.clearNodes()
|
|
153
215
|
})
|
|
154
216
|
.wrapInList(listType, attributes)
|
|
@@ -64,7 +64,16 @@ export function markPasteRule(config: {
|
|
|
64
64
|
|
|
65
65
|
tr.addMark(range.from + startSpaces, markEnd, config.type.create(attributes || {}))
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
// Only remove the stored mark if the match is not at the end of the
|
|
68
|
+
// pasted text. When a mark extends to the end of the content, removing
|
|
69
|
+
// it overrides the mark's `inclusive` behavior and incorrectly places
|
|
70
|
+
// the cursor outside the mark.
|
|
71
|
+
const isMatchAtEndOfText =
|
|
72
|
+
match.index !== undefined && match.input !== undefined && match.index + match[0].length >= match.input.length
|
|
73
|
+
|
|
74
|
+
if (!isMatchAtEndOfText) {
|
|
75
|
+
tr.removeStoredMark(config.type)
|
|
76
|
+
}
|
|
68
77
|
}
|
|
69
78
|
},
|
|
70
79
|
})
|