@tiptap/extension-unique-id 2.24.2 → 3.0.0-beta.10
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/dist/index.cjs +253 -250
- package/dist/index.cjs.map +1 -1
- package/dist/{unique-id.d.ts → index.d.cts} +5 -3
- package/dist/index.d.ts +12 -4
- package/dist/index.js +228 -247
- package/dist/index.js.map +1 -1
- package/package.json +13 -11
- package/src/helpers/removeDuplicates.ts +1 -3
- package/src/unique-id.ts +17 -25
- package/dist/helpers/findDuplicates.d.ts +0 -5
- package/dist/helpers/findDuplicates.d.ts.map +0 -1
- package/dist/helpers/removeDuplicates.d.ts +0 -9
- package/dist/helpers/removeDuplicates.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.umd.js +0 -268
- package/dist/index.umd.js.map +0 -1
- package/dist/unique-id.d.ts.map +0 -1
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Tiptap GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
CHANGED
|
@@ -1,267 +1,270 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
2
19
|
|
|
3
|
-
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
UniqueID: () => UniqueID,
|
|
24
|
+
default: () => index_default
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
4
27
|
|
|
5
|
-
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
28
|
+
// src/unique-id.ts
|
|
29
|
+
var import_core = require("@tiptap/core");
|
|
30
|
+
var import_model = require("@tiptap/pm/model");
|
|
31
|
+
var import_state = require("@tiptap/pm/state");
|
|
32
|
+
var import_uuid = require("uuid");
|
|
9
33
|
|
|
10
|
-
|
|
11
|
-
* Removes duplicated values within an array.
|
|
12
|
-
* Supports numbers, strings and objects.
|
|
13
|
-
*/
|
|
34
|
+
// src/helpers/removeDuplicates.ts
|
|
14
35
|
function removeDuplicates(array, by = JSON.stringify) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
: (seen[key] = true);
|
|
21
|
-
});
|
|
36
|
+
const seen = {};
|
|
37
|
+
return array.filter((item) => {
|
|
38
|
+
const key = by(item);
|
|
39
|
+
return Object.prototype.hasOwnProperty.call(seen, key) ? false : seen[key] = true;
|
|
40
|
+
});
|
|
22
41
|
}
|
|
23
42
|
|
|
24
|
-
|
|
25
|
-
* Returns a list of duplicated items within an array.
|
|
26
|
-
*/
|
|
43
|
+
// src/helpers/findDuplicates.ts
|
|
27
44
|
function findDuplicates(items) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
45
|
+
const filtered = items.filter((el, index) => items.indexOf(el) !== index);
|
|
46
|
+
const duplicates = removeDuplicates(filtered);
|
|
47
|
+
return duplicates;
|
|
31
48
|
}
|
|
32
49
|
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
50
|
+
// src/unique-id.ts
|
|
51
|
+
var UniqueID = import_core.Extension.create({
|
|
52
|
+
name: "uniqueID",
|
|
53
|
+
// we’ll set a very high priority to make sure this runs first
|
|
54
|
+
// and is compatible with `appendTransaction` hooks of other extensions
|
|
55
|
+
priority: 1e4,
|
|
56
|
+
addOptions() {
|
|
57
|
+
return {
|
|
58
|
+
attributeName: "id",
|
|
59
|
+
types: [],
|
|
60
|
+
generateID: () => (0, import_uuid.v4)(),
|
|
61
|
+
filterTransaction: null
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
addGlobalAttributes() {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
types: this.options.types,
|
|
68
|
+
attributes: {
|
|
69
|
+
[this.options.attributeName]: {
|
|
70
|
+
default: null,
|
|
71
|
+
parseHTML: (element) => element.getAttribute(`data-${this.options.attributeName}`),
|
|
72
|
+
renderHTML: (attributes) => {
|
|
73
|
+
if (!attributes[this.options.attributeName]) {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
[`data-${this.options.attributeName}`]: attributes[this.options.attributeName]
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
];
|
|
84
|
+
},
|
|
85
|
+
// check initial content for missing ids
|
|
86
|
+
onCreate() {
|
|
87
|
+
const collab = this.editor.extensionManager.extensions.find((ext) => ext.name === "collaboration");
|
|
88
|
+
const provider = (collab == null ? void 0 : collab.options) ? collab.options.provider : void 0;
|
|
89
|
+
const createIds = () => {
|
|
90
|
+
const { view, state } = this.editor;
|
|
91
|
+
const { tr, doc } = state;
|
|
92
|
+
const { types, attributeName, generateID } = this.options;
|
|
93
|
+
const nodesWithoutId = (0, import_core.findChildren)(doc, (node) => {
|
|
94
|
+
return types.includes(node.type.name) && node.attrs[attributeName] === null;
|
|
95
|
+
});
|
|
96
|
+
nodesWithoutId.forEach(({ node, pos }) => {
|
|
97
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
98
|
+
...node.attrs,
|
|
99
|
+
[attributeName]: generateID()
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
tr.setMeta("addToHistory", false);
|
|
103
|
+
view.dispatch(tr);
|
|
104
|
+
if (provider) {
|
|
105
|
+
provider.off("synced", createIds);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
if (collab) {
|
|
109
|
+
if (!provider) {
|
|
110
|
+
return createIds();
|
|
111
|
+
}
|
|
112
|
+
provider.on("synced", createIds);
|
|
113
|
+
} else {
|
|
114
|
+
return createIds();
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
addProseMirrorPlugins() {
|
|
118
|
+
let dragSourceElement = null;
|
|
119
|
+
let transformPasted = false;
|
|
120
|
+
return [
|
|
121
|
+
new import_state.Plugin({
|
|
122
|
+
key: new import_state.PluginKey("uniqueID"),
|
|
123
|
+
appendTransaction: (transactions, oldState, newState) => {
|
|
124
|
+
const hasDocChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
|
|
125
|
+
const filterTransactions = this.options.filterTransaction && transactions.some((tr2) => {
|
|
126
|
+
var _a, _b;
|
|
127
|
+
return !((_b = (_a = this.options).filterTransaction) == null ? void 0 : _b.call(_a, tr2));
|
|
128
|
+
});
|
|
129
|
+
const isCollabTransaction = transactions.find((tr2) => tr2.getMeta("y-sync$"));
|
|
130
|
+
if (isCollabTransaction) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!hasDocChanges || filterTransactions) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const { tr } = newState;
|
|
137
|
+
const { types, attributeName, generateID } = this.options;
|
|
138
|
+
const transform = (0, import_core.combineTransactionSteps)(oldState.doc, transactions);
|
|
139
|
+
const { mapping } = transform;
|
|
140
|
+
const changes = (0, import_core.getChangedRanges)(transform);
|
|
141
|
+
changes.forEach(({ newRange }) => {
|
|
142
|
+
const newNodes = (0, import_core.findChildrenInRange)(newState.doc, newRange, (node) => {
|
|
143
|
+
return types.includes(node.type.name);
|
|
77
144
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
145
|
+
const newIds = newNodes.map(({ node }) => node.attrs[attributeName]).filter((id) => id !== null);
|
|
146
|
+
newNodes.forEach(({ node, pos }, i) => {
|
|
147
|
+
var _a;
|
|
148
|
+
const id = (_a = tr.doc.nodeAt(pos)) == null ? void 0 : _a.attrs[attributeName];
|
|
149
|
+
if (id === null) {
|
|
150
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
151
|
+
...node.attrs,
|
|
152
|
+
[attributeName]: generateID()
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const nextNode = newNodes[i + 1];
|
|
157
|
+
if (nextNode && node.content.size === 0) {
|
|
158
|
+
tr.setNodeMarkup(nextNode.pos, void 0, {
|
|
159
|
+
...nextNode.node.attrs,
|
|
160
|
+
[attributeName]: id
|
|
161
|
+
});
|
|
162
|
+
newIds[i + 1] = id;
|
|
163
|
+
if (nextNode.node.attrs[attributeName]) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const generatedId = generateID();
|
|
167
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
168
|
+
...node.attrs,
|
|
169
|
+
[attributeName]: generatedId
|
|
82
170
|
});
|
|
171
|
+
newIds[i] = generatedId;
|
|
172
|
+
return tr;
|
|
173
|
+
}
|
|
174
|
+
const duplicatedNewIds = findDuplicates(newIds);
|
|
175
|
+
const { deleted } = mapping.invert().mapResult(pos);
|
|
176
|
+
const newNode = deleted && duplicatedNewIds.includes(id);
|
|
177
|
+
if (newNode) {
|
|
178
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
179
|
+
...node.attrs,
|
|
180
|
+
[attributeName]: generateID()
|
|
181
|
+
});
|
|
182
|
+
}
|
|
83
183
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
184
|
+
});
|
|
185
|
+
if (!tr.steps.length) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
tr.setStoredMarks(newState.tr.storedMarks);
|
|
189
|
+
return tr;
|
|
190
|
+
},
|
|
191
|
+
// we register a global drag handler to track the current drag source element
|
|
192
|
+
view(view) {
|
|
193
|
+
const handleDragstart = (event) => {
|
|
194
|
+
var _a;
|
|
195
|
+
dragSourceElement = ((_a = view.dom.parentElement) == null ? void 0 : _a.contains(event.target)) ? view.dom.parentElement : null;
|
|
196
|
+
};
|
|
197
|
+
window.addEventListener("dragstart", handleDragstart);
|
|
198
|
+
return {
|
|
199
|
+
destroy() {
|
|
200
|
+
window.removeEventListener("dragstart", handleDragstart);
|
|
88
201
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
202
|
+
};
|
|
203
|
+
},
|
|
204
|
+
props: {
|
|
205
|
+
// `handleDOMEvents` is called before `transformPasted`
|
|
206
|
+
// so we can do some checks before
|
|
207
|
+
handleDOMEvents: {
|
|
208
|
+
// only create new ids for dropped content
|
|
209
|
+
// or dropped content while holding `alt`
|
|
210
|
+
// or content is dragged from another editor
|
|
211
|
+
drop: (view, event) => {
|
|
212
|
+
var _a, _b;
|
|
213
|
+
if (dragSourceElement !== view.dom.parentElement || ((_a = event.dataTransfer) == null ? void 0 : _a.effectAllowed) === "copyMove" || ((_b = event.dataTransfer) == null ? void 0 : _b.effectAllowed) === "copy") {
|
|
214
|
+
dragSourceElement = null;
|
|
215
|
+
transformPasted = true;
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
},
|
|
219
|
+
// always create new ids on pasted content
|
|
220
|
+
paste: () => {
|
|
221
|
+
transformPasted = true;
|
|
222
|
+
return false;
|
|
98
223
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
224
|
+
},
|
|
225
|
+
// we’ll remove ids for every pasted node
|
|
226
|
+
// so we can create a new one within `appendTransaction`
|
|
227
|
+
transformPasted: (slice) => {
|
|
228
|
+
if (!transformPasted) {
|
|
229
|
+
return slice;
|
|
230
|
+
}
|
|
231
|
+
const { types, attributeName } = this.options;
|
|
232
|
+
const removeId = (fragment) => {
|
|
233
|
+
const list = [];
|
|
234
|
+
fragment.forEach((node) => {
|
|
235
|
+
if (node.isText) {
|
|
236
|
+
list.push(node);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (!types.includes(node.type.name)) {
|
|
240
|
+
list.push(node.copy(removeId(node.content)));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const nodeWithoutId = node.type.create(
|
|
244
|
+
{
|
|
245
|
+
...node.attrs,
|
|
246
|
+
[attributeName]: null
|
|
247
|
+
},
|
|
248
|
+
removeId(node.content),
|
|
249
|
+
node.marks
|
|
250
|
+
);
|
|
251
|
+
list.push(nodeWithoutId);
|
|
252
|
+
});
|
|
253
|
+
return import_model.Fragment.from(list);
|
|
254
|
+
};
|
|
255
|
+
transformPasted = false;
|
|
256
|
+
return new import_model.Slice(removeId(slice.content), slice.openStart, slice.openEnd);
|
|
257
|
+
}
|
|
103
258
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
let transformPasted = false;
|
|
108
|
-
return [
|
|
109
|
-
new state.Plugin({
|
|
110
|
-
key: new state.PluginKey('uniqueID'),
|
|
111
|
-
appendTransaction: (transactions, oldState, newState) => {
|
|
112
|
-
const hasDocChanges = transactions.some(transaction => transaction.docChanged)
|
|
113
|
-
&& !oldState.doc.eq(newState.doc);
|
|
114
|
-
const filterTransactions = this.options.filterTransaction
|
|
115
|
-
&& transactions.some(tr => { var _a, _b; return !((_b = (_a = this.options).filterTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, tr)); });
|
|
116
|
-
const isCollabTransaction = transactions.find(tr => tr.getMeta('y-sync$'));
|
|
117
|
-
if (isCollabTransaction) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (!hasDocChanges || filterTransactions) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const { tr } = newState;
|
|
124
|
-
const { types, attributeName, generateID } = this.options;
|
|
125
|
-
const transform = core.combineTransactionSteps(oldState.doc, transactions);
|
|
126
|
-
const { mapping } = transform;
|
|
127
|
-
// get changed ranges based on the old state
|
|
128
|
-
const changes = core.getChangedRanges(transform);
|
|
129
|
-
changes.forEach(({ newRange }) => {
|
|
130
|
-
const newNodes = core.findChildrenInRange(newState.doc, newRange, node => {
|
|
131
|
-
return types.includes(node.type.name);
|
|
132
|
-
});
|
|
133
|
-
const newIds = newNodes
|
|
134
|
-
.map(({ node }) => node.attrs[attributeName])
|
|
135
|
-
.filter(id => id !== null);
|
|
136
|
-
newNodes.forEach(({ node, pos }, i) => {
|
|
137
|
-
var _a;
|
|
138
|
-
// instead of checking `node.attrs[attributeName]` directly
|
|
139
|
-
// we look at the current state of the node within `tr.doc`.
|
|
140
|
-
// this helps to prevent adding new ids to the same node
|
|
141
|
-
// if the node changed multiple times within one transaction
|
|
142
|
-
const id = (_a = tr.doc.nodeAt(pos)) === null || _a === void 0 ? void 0 : _a.attrs[attributeName];
|
|
143
|
-
if (id === null) {
|
|
144
|
-
tr.setNodeMarkup(pos, undefined, {
|
|
145
|
-
...node.attrs,
|
|
146
|
-
[attributeName]: generateID(),
|
|
147
|
-
});
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
const nextNode = newNodes[i + 1];
|
|
151
|
-
if (nextNode && node.content.size === 0) {
|
|
152
|
-
tr.setNodeMarkup(nextNode.pos, undefined, {
|
|
153
|
-
...nextNode.node.attrs,
|
|
154
|
-
[attributeName]: id,
|
|
155
|
-
});
|
|
156
|
-
newIds[i + 1] = id;
|
|
157
|
-
if (nextNode.node.attrs[attributeName]) {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
const generatedId = generateID();
|
|
161
|
-
tr.setNodeMarkup(pos, undefined, {
|
|
162
|
-
...node.attrs,
|
|
163
|
-
[attributeName]: generatedId,
|
|
164
|
-
});
|
|
165
|
-
newIds[i] = generatedId;
|
|
166
|
-
return tr;
|
|
167
|
-
}
|
|
168
|
-
const duplicatedNewIds = findDuplicates(newIds);
|
|
169
|
-
// check if the node doesn’t exist in the old state
|
|
170
|
-
const { deleted } = mapping.invert().mapResult(pos);
|
|
171
|
-
const newNode = deleted && duplicatedNewIds.includes(id);
|
|
172
|
-
if (newNode) {
|
|
173
|
-
tr.setNodeMarkup(pos, undefined, {
|
|
174
|
-
...node.attrs,
|
|
175
|
-
[attributeName]: generateID(),
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
if (!tr.steps.length) {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
// `tr.setNodeMarkup` resets the stored marks
|
|
184
|
-
// so we’ll restore them if they exist
|
|
185
|
-
tr.setStoredMarks(newState.tr.storedMarks);
|
|
186
|
-
return tr;
|
|
187
|
-
},
|
|
188
|
-
// we register a global drag handler to track the current drag source element
|
|
189
|
-
view(view) {
|
|
190
|
-
const handleDragstart = (event) => {
|
|
191
|
-
var _a;
|
|
192
|
-
dragSourceElement = ((_a = view.dom.parentElement) === null || _a === void 0 ? void 0 : _a.contains(event.target))
|
|
193
|
-
? view.dom.parentElement
|
|
194
|
-
: null;
|
|
195
|
-
};
|
|
196
|
-
window.addEventListener('dragstart', handleDragstart);
|
|
197
|
-
return {
|
|
198
|
-
destroy() {
|
|
199
|
-
window.removeEventListener('dragstart', handleDragstart);
|
|
200
|
-
},
|
|
201
|
-
};
|
|
202
|
-
},
|
|
203
|
-
props: {
|
|
204
|
-
// `handleDOMEvents` is called before `transformPasted`
|
|
205
|
-
// so we can do some checks before
|
|
206
|
-
handleDOMEvents: {
|
|
207
|
-
// only create new ids for dropped content
|
|
208
|
-
// or dropped content while holding `alt`
|
|
209
|
-
// or content is dragged from another editor
|
|
210
|
-
drop: (view, event) => {
|
|
211
|
-
var _a, _b;
|
|
212
|
-
if (dragSourceElement !== view.dom.parentElement
|
|
213
|
-
|| ((_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.effectAllowed) === 'copyMove'
|
|
214
|
-
|| ((_b = event.dataTransfer) === null || _b === void 0 ? void 0 : _b.effectAllowed) === 'copy') {
|
|
215
|
-
dragSourceElement = null;
|
|
216
|
-
transformPasted = true;
|
|
217
|
-
}
|
|
218
|
-
return false;
|
|
219
|
-
},
|
|
220
|
-
// always create new ids on pasted content
|
|
221
|
-
paste: () => {
|
|
222
|
-
transformPasted = true;
|
|
223
|
-
return false;
|
|
224
|
-
},
|
|
225
|
-
},
|
|
226
|
-
// we’ll remove ids for every pasted node
|
|
227
|
-
// so we can create a new one within `appendTransaction`
|
|
228
|
-
transformPasted: slice => {
|
|
229
|
-
if (!transformPasted) {
|
|
230
|
-
return slice;
|
|
231
|
-
}
|
|
232
|
-
const { types, attributeName } = this.options;
|
|
233
|
-
const removeId = (fragment) => {
|
|
234
|
-
const list = [];
|
|
235
|
-
fragment.forEach(node => {
|
|
236
|
-
// don’t touch text nodes
|
|
237
|
-
if (node.isText) {
|
|
238
|
-
list.push(node);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
// check for any other child nodes
|
|
242
|
-
if (!types.includes(node.type.name)) {
|
|
243
|
-
list.push(node.copy(removeId(node.content)));
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
// remove id
|
|
247
|
-
const nodeWithoutId = node.type.create({
|
|
248
|
-
...node.attrs,
|
|
249
|
-
[attributeName]: null,
|
|
250
|
-
}, removeId(node.content), node.marks);
|
|
251
|
-
list.push(nodeWithoutId);
|
|
252
|
-
});
|
|
253
|
-
return model.Fragment.from(list);
|
|
254
|
-
};
|
|
255
|
-
// reset check
|
|
256
|
-
transformPasted = false;
|
|
257
|
-
return new model.Slice(removeId(slice.content), slice.openStart, slice.openEnd);
|
|
258
|
-
},
|
|
259
|
-
},
|
|
260
|
-
}),
|
|
261
|
-
];
|
|
262
|
-
},
|
|
259
|
+
})
|
|
260
|
+
];
|
|
261
|
+
}
|
|
263
262
|
});
|
|
264
263
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
264
|
+
// src/index.ts
|
|
265
|
+
var index_default = UniqueID;
|
|
266
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
267
|
+
0 && (module.exports = {
|
|
268
|
+
UniqueID
|
|
269
|
+
});
|
|
270
|
+
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/helpers/removeDuplicates.ts","../src/helpers/findDuplicates.ts","../src/unique-id.ts"],"sourcesContent":["/**\n * Removes duplicated values within an array.\n * Supports numbers, strings and objects.\n */\nexport function removeDuplicates<T>(array: T[], by = JSON.stringify): T[] {\n const seen: Record<any, any> = {}\n\n return array.filter(item => {\n const key = by(item)\n\n return Object.prototype.hasOwnProperty.call(seen, key)\n ? false\n : (seen[key] = true)\n })\n}\n","import { removeDuplicates } from './removeDuplicates.js'\n\n/**\n * Returns a list of duplicated items within an array.\n */\nexport function findDuplicates(items: any[]): any[] {\n const filtered = items.filter((el, index) => items.indexOf(el) !== index)\n const duplicates = removeDuplicates(filtered)\n\n return duplicates\n}\n","import {\n combineTransactionSteps,\n Extension,\n findChildren,\n findChildrenInRange,\n getChangedRanges,\n} from '@tiptap/core'\nimport { Fragment, Node as ProseMirrorNode, Slice } from '@tiptap/pm/model'\nimport { Plugin, PluginKey, Transaction } from '@tiptap/pm/state'\nimport { v4 as uuidv4 } from 'uuid'\n\nimport { findDuplicates } from './helpers/findDuplicates.js'\n\nexport interface UniqueIDOptions {\n attributeName: string,\n types: string[],\n generateID: () => any,\n filterTransaction: ((transaction: Transaction) => boolean) | null,\n}\n\nexport const UniqueID = Extension.create<UniqueIDOptions>({\n name: 'uniqueID',\n\n // we’ll set a very high priority to make sure this runs first\n // and is compatible with `appendTransaction` hooks of other extensions\n priority: 10000,\n\n addOptions() {\n return {\n attributeName: 'id',\n types: [],\n generateID: () => uuidv4(),\n filterTransaction: null,\n }\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n [this.options.attributeName]: {\n default: null,\n parseHTML: element => element.getAttribute(`data-${this.options.attributeName}`),\n renderHTML: attributes => {\n if (!attributes[this.options.attributeName]) {\n return {}\n }\n\n return {\n [`data-${this.options.attributeName}`]: attributes[this.options.attributeName],\n }\n },\n },\n },\n },\n ]\n },\n\n // check initial content for missing ids\n onCreate() {\n const collab = this.editor.extensionManager.extensions.find(ext => ext.name === 'collaboration')\n const provider = collab?.options ? collab.options.provider : undefined\n\n const createIds = () => {\n const { view, state } = this.editor\n const { tr, doc } = state\n const { types, attributeName, generateID } = this.options\n const nodesWithoutId = findChildren(doc, node => {\n return types.includes(node.type.name) && node.attrs[attributeName] === null\n })\n\n nodesWithoutId.forEach(({ node, pos }) => {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [attributeName]: generateID(),\n })\n })\n\n tr.setMeta('addToHistory', false)\n\n view.dispatch(tr)\n\n if (provider) {\n provider.off('synced', createIds)\n }\n }\n\n /**\n * We need to handle collaboration a bit different here\n * because we can't automatically add IDs when the provider is not yet synced\n * otherwise we end up with empty paragraphs\n */\n if (collab) {\n if (!provider) {\n return createIds()\n }\n\n provider.on('synced', createIds)\n } else {\n return createIds()\n }\n },\n\n addProseMirrorPlugins() {\n let dragSourceElement: Element | null = null\n let transformPasted = false\n\n return [\n new Plugin({\n key: new PluginKey('uniqueID'),\n\n appendTransaction: (transactions, oldState, newState) => {\n const hasDocChanges = transactions.some(transaction => transaction.docChanged)\n && !oldState.doc.eq(newState.doc)\n const filterTransactions = this.options.filterTransaction\n && transactions.some(tr => !this.options.filterTransaction?.(tr))\n\n const isCollabTransaction = transactions.find(tr => tr.getMeta('y-sync$'))\n\n if (isCollabTransaction) {\n return\n }\n\n if (!hasDocChanges || filterTransactions) {\n return\n }\n\n const { tr } = newState\n\n const { types, attributeName, generateID } = this.options\n const transform = combineTransactionSteps(oldState.doc, transactions as Transaction[])\n const { mapping } = transform\n\n // get changed ranges based on the old state\n const changes = getChangedRanges(transform)\n\n changes.forEach(({ newRange }) => {\n const newNodes = findChildrenInRange(newState.doc, newRange, node => {\n return types.includes(node.type.name)\n })\n\n const newIds = newNodes\n .map(({ node }) => node.attrs[attributeName])\n .filter(id => id !== null)\n\n newNodes.forEach(({ node, pos }, i) => {\n // instead of checking `node.attrs[attributeName]` directly\n // we look at the current state of the node within `tr.doc`.\n // this helps to prevent adding new ids to the same node\n // if the node changed multiple times within one transaction\n const id = tr.doc.nodeAt(pos)?.attrs[attributeName]\n\n if (id === null) {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [attributeName]: generateID(),\n })\n\n return\n }\n\n const nextNode = newNodes[i + 1]\n\n if (nextNode && node.content.size === 0) {\n tr.setNodeMarkup(nextNode.pos, undefined, {\n ...nextNode.node.attrs,\n [attributeName]: id,\n })\n newIds[i + 1] = id\n\n if (nextNode.node.attrs[attributeName]) {\n return\n }\n\n const generatedId = generateID()\n\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [attributeName]: generatedId,\n })\n newIds[i] = generatedId\n\n return tr\n }\n\n const duplicatedNewIds = findDuplicates(newIds)\n\n // check if the node doesn’t exist in the old state\n const { deleted } = mapping.invert().mapResult(pos)\n\n const newNode = deleted && duplicatedNewIds.includes(id)\n\n if (newNode) {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [attributeName]: generateID(),\n })\n }\n })\n\n })\n\n if (!tr.steps.length) {\n return\n }\n\n // `tr.setNodeMarkup` resets the stored marks\n // so we’ll restore them if they exist\n tr.setStoredMarks(newState.tr.storedMarks)\n\n return tr\n },\n\n // we register a global drag handler to track the current drag source element\n view(view) {\n const handleDragstart = (event: DragEvent) => {\n dragSourceElement = view.dom.parentElement?.contains(event.target as Element)\n ? view.dom.parentElement\n : null\n }\n\n window.addEventListener('dragstart', handleDragstart)\n\n return {\n destroy() {\n window.removeEventListener('dragstart', handleDragstart)\n },\n }\n },\n\n props: {\n // `handleDOMEvents` is called before `transformPasted`\n // so we can do some checks before\n handleDOMEvents: {\n // only create new ids for dropped content\n // or dropped content while holding `alt`\n // or content is dragged from another editor\n drop: (view, event) => {\n if (\n dragSourceElement !== view.dom.parentElement\n || event.dataTransfer?.effectAllowed === 'copyMove'\n || event.dataTransfer?.effectAllowed === 'copy'\n ) {\n dragSourceElement = null\n transformPasted = true\n }\n\n return false\n },\n // always create new ids on pasted content\n paste: () => {\n transformPasted = true\n\n return false\n },\n },\n\n // we’ll remove ids for every pasted node\n // so we can create a new one within `appendTransaction`\n transformPasted: slice => {\n if (!transformPasted) {\n return slice\n }\n\n const { types, attributeName } = this.options\n const removeId = (fragment: Fragment): Fragment => {\n const list: ProseMirrorNode[] = []\n\n fragment.forEach(node => {\n // don’t touch text nodes\n if (node.isText) {\n list.push(node)\n\n return\n }\n\n // check for any other child nodes\n if (!types.includes(node.type.name)) {\n list.push(node.copy(removeId(node.content)))\n\n return\n }\n\n // remove id\n const nodeWithoutId = node.type.create(\n {\n ...node.attrs,\n [attributeName]: null,\n },\n removeId(node.content),\n node.marks,\n )\n\n list.push(nodeWithoutId)\n })\n\n return Fragment.from(list)\n }\n\n // reset check\n transformPasted = false\n\n return new Slice(removeId(slice.content), slice.openStart, slice.openEnd)\n },\n },\n }),\n ]\n },\n\n})\n"],"names":["Extension","uuidv4","findChildren","Plugin","PluginKey","combineTransactionSteps","getChangedRanges","findChildrenInRange","Fragment","Slice"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/unique-id.ts","../src/helpers/removeDuplicates.ts","../src/helpers/findDuplicates.ts"],"sourcesContent":["import { UniqueID } from './unique-id.js'\n\nexport * from './unique-id.js'\n\nexport default UniqueID\n","import { combineTransactionSteps, Extension, findChildren, findChildrenInRange, getChangedRanges } from '@tiptap/core'\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Fragment, Slice } from '@tiptap/pm/model'\nimport type { Transaction } from '@tiptap/pm/state'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { v4 as uuidv4 } from 'uuid'\n\nimport { findDuplicates } from './helpers/findDuplicates.js'\n\nexport interface UniqueIDOptions {\n attributeName: string\n types: string[]\n generateID: () => any\n filterTransaction: ((transaction: Transaction) => boolean) | null\n}\n\nexport const UniqueID = Extension.create<UniqueIDOptions>({\n name: 'uniqueID',\n\n // we’ll set a very high priority to make sure this runs first\n // and is compatible with `appendTransaction` hooks of other extensions\n priority: 10000,\n\n addOptions() {\n return {\n attributeName: 'id',\n types: [],\n generateID: () => uuidv4(),\n filterTransaction: null,\n }\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n [this.options.attributeName]: {\n default: null,\n parseHTML: element => element.getAttribute(`data-${this.options.attributeName}`),\n renderHTML: attributes => {\n if (!attributes[this.options.attributeName]) {\n return {}\n }\n\n return {\n [`data-${this.options.attributeName}`]: attributes[this.options.attributeName],\n }\n },\n },\n },\n },\n ]\n },\n\n // check initial content for missing ids\n onCreate() {\n const collab = this.editor.extensionManager.extensions.find(ext => ext.name === 'collaboration')\n const provider = collab?.options ? collab.options.provider : undefined\n\n const createIds = () => {\n const { view, state } = this.editor\n const { tr, doc } = state\n const { types, attributeName, generateID } = this.options\n const nodesWithoutId = findChildren(doc, node => {\n return types.includes(node.type.name) && node.attrs[attributeName] === null\n })\n\n nodesWithoutId.forEach(({ node, pos }) => {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [attributeName]: generateID(),\n })\n })\n\n tr.setMeta('addToHistory', false)\n\n view.dispatch(tr)\n\n if (provider) {\n provider.off('synced', createIds)\n }\n }\n\n /**\n * We need to handle collaboration a bit different here\n * because we can't automatically add IDs when the provider is not yet synced\n * otherwise we end up with empty paragraphs\n */\n if (collab) {\n if (!provider) {\n return createIds()\n }\n\n provider.on('synced', createIds)\n } else {\n return createIds()\n }\n },\n\n addProseMirrorPlugins() {\n let dragSourceElement: Element | null = null\n let transformPasted = false\n\n return [\n new Plugin({\n key: new PluginKey('uniqueID'),\n\n appendTransaction: (transactions, oldState, newState) => {\n const hasDocChanges =\n transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc)\n const filterTransactions =\n this.options.filterTransaction && transactions.some(tr => !this.options.filterTransaction?.(tr))\n\n const isCollabTransaction = transactions.find(tr => tr.getMeta('y-sync$'))\n\n if (isCollabTransaction) {\n return\n }\n\n if (!hasDocChanges || filterTransactions) {\n return\n }\n\n const { tr } = newState\n\n const { types, attributeName, generateID } = this.options\n const transform = combineTransactionSteps(oldState.doc, transactions as Transaction[])\n const { mapping } = transform\n\n // get changed ranges based on the old state\n const changes = getChangedRanges(transform)\n\n changes.forEach(({ newRange }) => {\n const newNodes = findChildrenInRange(newState.doc, newRange, node => {\n return types.includes(node.type.name)\n })\n\n const newIds = newNodes.map(({ node }) => node.attrs[attributeName]).filter(id => id !== null)\n\n newNodes.forEach(({ node, pos }, i) => {\n // instead of checking `node.attrs[attributeName]` directly\n // we look at the current state of the node within `tr.doc`.\n // this helps to prevent adding new ids to the same node\n // if the node changed multiple times within one transaction\n const id = tr.doc.nodeAt(pos)?.attrs[attributeName]\n\n if (id === null) {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [attributeName]: generateID(),\n })\n\n return\n }\n\n const nextNode = newNodes[i + 1]\n\n if (nextNode && node.content.size === 0) {\n tr.setNodeMarkup(nextNode.pos, undefined, {\n ...nextNode.node.attrs,\n [attributeName]: id,\n })\n newIds[i + 1] = id\n\n if (nextNode.node.attrs[attributeName]) {\n return\n }\n\n const generatedId = generateID()\n\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [attributeName]: generatedId,\n })\n newIds[i] = generatedId\n\n return tr\n }\n\n const duplicatedNewIds = findDuplicates(newIds)\n\n // check if the node doesn’t exist in the old state\n const { deleted } = mapping.invert().mapResult(pos)\n\n const newNode = deleted && duplicatedNewIds.includes(id)\n\n if (newNode) {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [attributeName]: generateID(),\n })\n }\n })\n })\n\n if (!tr.steps.length) {\n return\n }\n\n // `tr.setNodeMarkup` resets the stored marks\n // so we’ll restore them if they exist\n tr.setStoredMarks(newState.tr.storedMarks)\n\n return tr\n },\n\n // we register a global drag handler to track the current drag source element\n view(view) {\n const handleDragstart = (event: DragEvent) => {\n dragSourceElement = view.dom.parentElement?.contains(event.target as Element)\n ? view.dom.parentElement\n : null\n }\n\n window.addEventListener('dragstart', handleDragstart)\n\n return {\n destroy() {\n window.removeEventListener('dragstart', handleDragstart)\n },\n }\n },\n\n props: {\n // `handleDOMEvents` is called before `transformPasted`\n // so we can do some checks before\n handleDOMEvents: {\n // only create new ids for dropped content\n // or dropped content while holding `alt`\n // or content is dragged from another editor\n drop: (view, event) => {\n if (\n dragSourceElement !== view.dom.parentElement ||\n event.dataTransfer?.effectAllowed === 'copyMove' ||\n event.dataTransfer?.effectAllowed === 'copy'\n ) {\n dragSourceElement = null\n transformPasted = true\n }\n\n return false\n },\n // always create new ids on pasted content\n paste: () => {\n transformPasted = true\n\n return false\n },\n },\n\n // we’ll remove ids for every pasted node\n // so we can create a new one within `appendTransaction`\n transformPasted: slice => {\n if (!transformPasted) {\n return slice\n }\n\n const { types, attributeName } = this.options\n const removeId = (fragment: Fragment): Fragment => {\n const list: ProseMirrorNode[] = []\n\n fragment.forEach(node => {\n // don’t touch text nodes\n if (node.isText) {\n list.push(node)\n\n return\n }\n\n // check for any other child nodes\n if (!types.includes(node.type.name)) {\n list.push(node.copy(removeId(node.content)))\n\n return\n }\n\n // remove id\n const nodeWithoutId = node.type.create(\n {\n ...node.attrs,\n [attributeName]: null,\n },\n removeId(node.content),\n node.marks,\n )\n\n list.push(nodeWithoutId)\n })\n\n return Fragment.from(list)\n }\n\n // reset check\n transformPasted = false\n\n return new Slice(removeId(slice.content), slice.openStart, slice.openEnd)\n },\n },\n }),\n ]\n },\n})\n","/**\n * Removes duplicated values within an array.\n * Supports numbers, strings and objects.\n */\nexport function removeDuplicates<T>(array: T[], by = JSON.stringify): T[] {\n const seen: Record<any, any> = {}\n\n return array.filter(item => {\n const key = by(item)\n\n return Object.prototype.hasOwnProperty.call(seen, key) ? false : (seen[key] = true)\n })\n}\n","import { removeDuplicates } from './removeDuplicates.js'\n\n/**\n * Returns a list of duplicated items within an array.\n */\nexport function findDuplicates(items: any[]): any[] {\n const filtered = items.filter((el, index) => items.indexOf(el) !== index)\n const duplicates = removeDuplicates(filtered)\n\n return duplicates\n}\n"],"mappings":"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","names":["uuidv4","tr"]}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Extension } from '@tiptap/core';
|
|
2
2
|
import { Transaction } from '@tiptap/pm/state';
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
interface UniqueIDOptions {
|
|
4
5
|
attributeName: string;
|
|
5
6
|
types: string[];
|
|
6
7
|
generateID: () => any;
|
|
7
8
|
filterTransaction: ((transaction: Transaction) => boolean) | null;
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
declare const UniqueID: Extension<UniqueIDOptions, any>;
|
|
11
|
+
|
|
12
|
+
export { UniqueID, type UniqueIDOptions, UniqueID as default };
|