@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/dist/index.d.ts CHANGED
@@ -1,4 +1,12 @@
1
- import { UniqueID } from './unique-id.js';
2
- export * from './unique-id.js';
3
- export default UniqueID;
4
- //# sourceMappingURL=index.d.ts.map
1
+ import { Extension } from '@tiptap/core';
2
+ import { Transaction } from '@tiptap/pm/state';
3
+
4
+ interface UniqueIDOptions {
5
+ attributeName: string;
6
+ types: string[];
7
+ generateID: () => any;
8
+ filterTransaction: ((transaction: Transaction) => boolean) | null;
9
+ }
10
+ declare const UniqueID: Extension<UniqueIDOptions, any>;
11
+
12
+ export { UniqueID, type UniqueIDOptions, UniqueID as default };
package/dist/index.js CHANGED
@@ -1,262 +1,243 @@
1
- import { Extension, combineTransactionSteps, getChangedRanges, findChildrenInRange, findChildren } from '@tiptap/core';
2
- import { Slice, Fragment } from '@tiptap/pm/model';
3
- import { Plugin, PluginKey } from '@tiptap/pm/state';
4
- import { v4 } from 'uuid';
1
+ // src/unique-id.ts
2
+ import { combineTransactionSteps, Extension, findChildren, findChildrenInRange, getChangedRanges } from "@tiptap/core";
3
+ import { Fragment, Slice } from "@tiptap/pm/model";
4
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
5
+ import { v4 as uuidv4 } from "uuid";
5
6
 
6
- /**
7
- * Removes duplicated values within an array.
8
- * Supports numbers, strings and objects.
9
- */
7
+ // src/helpers/removeDuplicates.ts
10
8
  function removeDuplicates(array, by = JSON.stringify) {
11
- const seen = {};
12
- return array.filter(item => {
13
- const key = by(item);
14
- return Object.prototype.hasOwnProperty.call(seen, key)
15
- ? false
16
- : (seen[key] = true);
17
- });
9
+ const seen = {};
10
+ return array.filter((item) => {
11
+ const key = by(item);
12
+ return Object.prototype.hasOwnProperty.call(seen, key) ? false : seen[key] = true;
13
+ });
18
14
  }
19
15
 
20
- /**
21
- * Returns a list of duplicated items within an array.
22
- */
16
+ // src/helpers/findDuplicates.ts
23
17
  function findDuplicates(items) {
24
- const filtered = items.filter((el, index) => items.indexOf(el) !== index);
25
- const duplicates = removeDuplicates(filtered);
26
- return duplicates;
18
+ const filtered = items.filter((el, index) => items.indexOf(el) !== index);
19
+ const duplicates = removeDuplicates(filtered);
20
+ return duplicates;
27
21
  }
28
22
 
29
- const UniqueID = Extension.create({
30
- name: 'uniqueID',
31
- // we’ll set a very high priority to make sure this runs first
32
- // and is compatible with `appendTransaction` hooks of other extensions
33
- priority: 10000,
34
- addOptions() {
35
- return {
36
- attributeName: 'id',
37
- types: [],
38
- generateID: () => v4(),
39
- filterTransaction: null,
40
- };
41
- },
42
- addGlobalAttributes() {
43
- return [
44
- {
45
- types: this.options.types,
46
- attributes: {
47
- [this.options.attributeName]: {
48
- default: null,
49
- parseHTML: element => element.getAttribute(`data-${this.options.attributeName}`),
50
- renderHTML: attributes => {
51
- if (!attributes[this.options.attributeName]) {
52
- return {};
53
- }
54
- return {
55
- [`data-${this.options.attributeName}`]: attributes[this.options.attributeName],
56
- };
57
- },
58
- },
59
- },
60
- },
61
- ];
62
- },
63
- // check initial content for missing ids
64
- onCreate() {
65
- const collab = this.editor.extensionManager.extensions.find(ext => ext.name === 'collaboration');
66
- const provider = (collab === null || collab === void 0 ? void 0 : collab.options) ? collab.options.provider : undefined;
67
- const createIds = () => {
68
- const { view, state } = this.editor;
69
- const { tr, doc } = state;
70
- const { types, attributeName, generateID } = this.options;
71
- const nodesWithoutId = findChildren(doc, node => {
72
- return types.includes(node.type.name) && node.attrs[attributeName] === null;
23
+ // src/unique-id.ts
24
+ var UniqueID = Extension.create({
25
+ name: "uniqueID",
26
+ // we’ll set a very high priority to make sure this runs first
27
+ // and is compatible with `appendTransaction` hooks of other extensions
28
+ priority: 1e4,
29
+ addOptions() {
30
+ return {
31
+ attributeName: "id",
32
+ types: [],
33
+ generateID: () => uuidv4(),
34
+ filterTransaction: null
35
+ };
36
+ },
37
+ addGlobalAttributes() {
38
+ return [
39
+ {
40
+ types: this.options.types,
41
+ attributes: {
42
+ [this.options.attributeName]: {
43
+ default: null,
44
+ parseHTML: (element) => element.getAttribute(`data-${this.options.attributeName}`),
45
+ renderHTML: (attributes) => {
46
+ if (!attributes[this.options.attributeName]) {
47
+ return {};
48
+ }
49
+ return {
50
+ [`data-${this.options.attributeName}`]: attributes[this.options.attributeName]
51
+ };
52
+ }
53
+ }
54
+ }
55
+ }
56
+ ];
57
+ },
58
+ // check initial content for missing ids
59
+ onCreate() {
60
+ const collab = this.editor.extensionManager.extensions.find((ext) => ext.name === "collaboration");
61
+ const provider = (collab == null ? void 0 : collab.options) ? collab.options.provider : void 0;
62
+ const createIds = () => {
63
+ const { view, state } = this.editor;
64
+ const { tr, doc } = state;
65
+ const { types, attributeName, generateID } = this.options;
66
+ const nodesWithoutId = findChildren(doc, (node) => {
67
+ return types.includes(node.type.name) && node.attrs[attributeName] === null;
68
+ });
69
+ nodesWithoutId.forEach(({ node, pos }) => {
70
+ tr.setNodeMarkup(pos, void 0, {
71
+ ...node.attrs,
72
+ [attributeName]: generateID()
73
+ });
74
+ });
75
+ tr.setMeta("addToHistory", false);
76
+ view.dispatch(tr);
77
+ if (provider) {
78
+ provider.off("synced", createIds);
79
+ }
80
+ };
81
+ if (collab) {
82
+ if (!provider) {
83
+ return createIds();
84
+ }
85
+ provider.on("synced", createIds);
86
+ } else {
87
+ return createIds();
88
+ }
89
+ },
90
+ addProseMirrorPlugins() {
91
+ let dragSourceElement = null;
92
+ let transformPasted = false;
93
+ return [
94
+ new Plugin({
95
+ key: new PluginKey("uniqueID"),
96
+ appendTransaction: (transactions, oldState, newState) => {
97
+ const hasDocChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
98
+ const filterTransactions = this.options.filterTransaction && transactions.some((tr2) => {
99
+ var _a, _b;
100
+ return !((_b = (_a = this.options).filterTransaction) == null ? void 0 : _b.call(_a, tr2));
101
+ });
102
+ const isCollabTransaction = transactions.find((tr2) => tr2.getMeta("y-sync$"));
103
+ if (isCollabTransaction) {
104
+ return;
105
+ }
106
+ if (!hasDocChanges || filterTransactions) {
107
+ return;
108
+ }
109
+ const { tr } = newState;
110
+ const { types, attributeName, generateID } = this.options;
111
+ const transform = combineTransactionSteps(oldState.doc, transactions);
112
+ const { mapping } = transform;
113
+ const changes = getChangedRanges(transform);
114
+ changes.forEach(({ newRange }) => {
115
+ const newNodes = findChildrenInRange(newState.doc, newRange, (node) => {
116
+ return types.includes(node.type.name);
73
117
  });
74
- nodesWithoutId.forEach(({ node, pos }) => {
75
- tr.setNodeMarkup(pos, undefined, {
76
- ...node.attrs,
77
- [attributeName]: generateID(),
118
+ const newIds = newNodes.map(({ node }) => node.attrs[attributeName]).filter((id) => id !== null);
119
+ newNodes.forEach(({ node, pos }, i) => {
120
+ var _a;
121
+ const id = (_a = tr.doc.nodeAt(pos)) == null ? void 0 : _a.attrs[attributeName];
122
+ if (id === null) {
123
+ tr.setNodeMarkup(pos, void 0, {
124
+ ...node.attrs,
125
+ [attributeName]: generateID()
126
+ });
127
+ return;
128
+ }
129
+ const nextNode = newNodes[i + 1];
130
+ if (nextNode && node.content.size === 0) {
131
+ tr.setNodeMarkup(nextNode.pos, void 0, {
132
+ ...nextNode.node.attrs,
133
+ [attributeName]: id
134
+ });
135
+ newIds[i + 1] = id;
136
+ if (nextNode.node.attrs[attributeName]) {
137
+ return;
138
+ }
139
+ const generatedId = generateID();
140
+ tr.setNodeMarkup(pos, void 0, {
141
+ ...node.attrs,
142
+ [attributeName]: generatedId
78
143
  });
144
+ newIds[i] = generatedId;
145
+ return tr;
146
+ }
147
+ const duplicatedNewIds = findDuplicates(newIds);
148
+ const { deleted } = mapping.invert().mapResult(pos);
149
+ const newNode = deleted && duplicatedNewIds.includes(id);
150
+ if (newNode) {
151
+ tr.setNodeMarkup(pos, void 0, {
152
+ ...node.attrs,
153
+ [attributeName]: generateID()
154
+ });
155
+ }
79
156
  });
80
- tr.setMeta('addToHistory', false);
81
- view.dispatch(tr);
82
- if (provider) {
83
- provider.off('synced', createIds);
157
+ });
158
+ if (!tr.steps.length) {
159
+ return;
160
+ }
161
+ tr.setStoredMarks(newState.tr.storedMarks);
162
+ return tr;
163
+ },
164
+ // we register a global drag handler to track the current drag source element
165
+ view(view) {
166
+ const handleDragstart = (event) => {
167
+ var _a;
168
+ dragSourceElement = ((_a = view.dom.parentElement) == null ? void 0 : _a.contains(event.target)) ? view.dom.parentElement : null;
169
+ };
170
+ window.addEventListener("dragstart", handleDragstart);
171
+ return {
172
+ destroy() {
173
+ window.removeEventListener("dragstart", handleDragstart);
84
174
  }
85
- };
86
- /**
87
- * We need to handle collaboration a bit different here
88
- * because we can't automatically add IDs when the provider is not yet synced
89
- * otherwise we end up with empty paragraphs
90
- */
91
- if (collab) {
92
- if (!provider) {
93
- return createIds();
175
+ };
176
+ },
177
+ props: {
178
+ // `handleDOMEvents` is called before `transformPasted`
179
+ // so we can do some checks before
180
+ handleDOMEvents: {
181
+ // only create new ids for dropped content
182
+ // or dropped content while holding `alt`
183
+ // or content is dragged from another editor
184
+ drop: (view, event) => {
185
+ var _a, _b;
186
+ if (dragSourceElement !== view.dom.parentElement || ((_a = event.dataTransfer) == null ? void 0 : _a.effectAllowed) === "copyMove" || ((_b = event.dataTransfer) == null ? void 0 : _b.effectAllowed) === "copy") {
187
+ dragSourceElement = null;
188
+ transformPasted = true;
189
+ }
190
+ return false;
191
+ },
192
+ // always create new ids on pasted content
193
+ paste: () => {
194
+ transformPasted = true;
195
+ return false;
94
196
  }
95
- provider.on('synced', createIds);
96
- }
97
- else {
98
- return createIds();
197
+ },
198
+ // we’ll remove ids for every pasted node
199
+ // so we can create a new one within `appendTransaction`
200
+ transformPasted: (slice) => {
201
+ if (!transformPasted) {
202
+ return slice;
203
+ }
204
+ const { types, attributeName } = this.options;
205
+ const removeId = (fragment) => {
206
+ const list = [];
207
+ fragment.forEach((node) => {
208
+ if (node.isText) {
209
+ list.push(node);
210
+ return;
211
+ }
212
+ if (!types.includes(node.type.name)) {
213
+ list.push(node.copy(removeId(node.content)));
214
+ return;
215
+ }
216
+ const nodeWithoutId = node.type.create(
217
+ {
218
+ ...node.attrs,
219
+ [attributeName]: null
220
+ },
221
+ removeId(node.content),
222
+ node.marks
223
+ );
224
+ list.push(nodeWithoutId);
225
+ });
226
+ return Fragment.from(list);
227
+ };
228
+ transformPasted = false;
229
+ return new Slice(removeId(slice.content), slice.openStart, slice.openEnd);
230
+ }
99
231
  }
100
- },
101
- addProseMirrorPlugins() {
102
- let dragSourceElement = null;
103
- let transformPasted = false;
104
- return [
105
- new Plugin({
106
- key: new PluginKey('uniqueID'),
107
- appendTransaction: (transactions, oldState, newState) => {
108
- const hasDocChanges = transactions.some(transaction => transaction.docChanged)
109
- && !oldState.doc.eq(newState.doc);
110
- const filterTransactions = this.options.filterTransaction
111
- && transactions.some(tr => { var _a, _b; return !((_b = (_a = this.options).filterTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, tr)); });
112
- const isCollabTransaction = transactions.find(tr => tr.getMeta('y-sync$'));
113
- if (isCollabTransaction) {
114
- return;
115
- }
116
- if (!hasDocChanges || filterTransactions) {
117
- return;
118
- }
119
- const { tr } = newState;
120
- const { types, attributeName, generateID } = this.options;
121
- const transform = combineTransactionSteps(oldState.doc, transactions);
122
- const { mapping } = transform;
123
- // get changed ranges based on the old state
124
- const changes = getChangedRanges(transform);
125
- changes.forEach(({ newRange }) => {
126
- const newNodes = findChildrenInRange(newState.doc, newRange, node => {
127
- return types.includes(node.type.name);
128
- });
129
- const newIds = newNodes
130
- .map(({ node }) => node.attrs[attributeName])
131
- .filter(id => id !== null);
132
- newNodes.forEach(({ node, pos }, i) => {
133
- var _a;
134
- // instead of checking `node.attrs[attributeName]` directly
135
- // we look at the current state of the node within `tr.doc`.
136
- // this helps to prevent adding new ids to the same node
137
- // if the node changed multiple times within one transaction
138
- const id = (_a = tr.doc.nodeAt(pos)) === null || _a === void 0 ? void 0 : _a.attrs[attributeName];
139
- if (id === null) {
140
- tr.setNodeMarkup(pos, undefined, {
141
- ...node.attrs,
142
- [attributeName]: generateID(),
143
- });
144
- return;
145
- }
146
- const nextNode = newNodes[i + 1];
147
- if (nextNode && node.content.size === 0) {
148
- tr.setNodeMarkup(nextNode.pos, undefined, {
149
- ...nextNode.node.attrs,
150
- [attributeName]: id,
151
- });
152
- newIds[i + 1] = id;
153
- if (nextNode.node.attrs[attributeName]) {
154
- return;
155
- }
156
- const generatedId = generateID();
157
- tr.setNodeMarkup(pos, undefined, {
158
- ...node.attrs,
159
- [attributeName]: generatedId,
160
- });
161
- newIds[i] = generatedId;
162
- return tr;
163
- }
164
- const duplicatedNewIds = findDuplicates(newIds);
165
- // check if the node doesn’t exist in the old state
166
- const { deleted } = mapping.invert().mapResult(pos);
167
- const newNode = deleted && duplicatedNewIds.includes(id);
168
- if (newNode) {
169
- tr.setNodeMarkup(pos, undefined, {
170
- ...node.attrs,
171
- [attributeName]: generateID(),
172
- });
173
- }
174
- });
175
- });
176
- if (!tr.steps.length) {
177
- return;
178
- }
179
- // `tr.setNodeMarkup` resets the stored marks
180
- // so we’ll restore them if they exist
181
- tr.setStoredMarks(newState.tr.storedMarks);
182
- return tr;
183
- },
184
- // we register a global drag handler to track the current drag source element
185
- view(view) {
186
- const handleDragstart = (event) => {
187
- var _a;
188
- dragSourceElement = ((_a = view.dom.parentElement) === null || _a === void 0 ? void 0 : _a.contains(event.target))
189
- ? view.dom.parentElement
190
- : null;
191
- };
192
- window.addEventListener('dragstart', handleDragstart);
193
- return {
194
- destroy() {
195
- window.removeEventListener('dragstart', handleDragstart);
196
- },
197
- };
198
- },
199
- props: {
200
- // `handleDOMEvents` is called before `transformPasted`
201
- // so we can do some checks before
202
- handleDOMEvents: {
203
- // only create new ids for dropped content
204
- // or dropped content while holding `alt`
205
- // or content is dragged from another editor
206
- drop: (view, event) => {
207
- var _a, _b;
208
- if (dragSourceElement !== view.dom.parentElement
209
- || ((_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.effectAllowed) === 'copyMove'
210
- || ((_b = event.dataTransfer) === null || _b === void 0 ? void 0 : _b.effectAllowed) === 'copy') {
211
- dragSourceElement = null;
212
- transformPasted = true;
213
- }
214
- return false;
215
- },
216
- // always create new ids on pasted content
217
- paste: () => {
218
- transformPasted = true;
219
- return false;
220
- },
221
- },
222
- // we’ll remove ids for every pasted node
223
- // so we can create a new one within `appendTransaction`
224
- transformPasted: slice => {
225
- if (!transformPasted) {
226
- return slice;
227
- }
228
- const { types, attributeName } = this.options;
229
- const removeId = (fragment) => {
230
- const list = [];
231
- fragment.forEach(node => {
232
- // don’t touch text nodes
233
- if (node.isText) {
234
- list.push(node);
235
- return;
236
- }
237
- // check for any other child nodes
238
- if (!types.includes(node.type.name)) {
239
- list.push(node.copy(removeId(node.content)));
240
- return;
241
- }
242
- // remove id
243
- const nodeWithoutId = node.type.create({
244
- ...node.attrs,
245
- [attributeName]: null,
246
- }, removeId(node.content), node.marks);
247
- list.push(nodeWithoutId);
248
- });
249
- return Fragment.from(list);
250
- };
251
- // reset check
252
- transformPasted = false;
253
- return new Slice(removeId(slice.content), slice.openStart, slice.openEnd);
254
- },
255
- },
256
- }),
257
- ];
258
- },
232
+ })
233
+ ];
234
+ }
259
235
  });
260
236
 
261
- export { UniqueID, UniqueID as default };
262
- //# sourceMappingURL=index.js.map
237
+ // src/index.ts
238
+ var index_default = UniqueID;
239
+ export {
240
+ UniqueID,
241
+ index_default as default
242
+ };
243
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","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":["uuidv4"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/unique-id.ts","../src/helpers/removeDuplicates.ts","../src/helpers/findDuplicates.ts","../src/index.ts"],"sourcesContent":["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","import { UniqueID } from './unique-id.js'\n\nexport * from './unique-id.js'\n\nexport default UniqueID\n"],"mappings":"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","names":["tr"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiptap/extension-unique-id",
3
3
  "description": "unique id extension for tiptap",
4
- "version": "2.24.2",
4
+ "version": "3.0.0-beta.10",
5
5
  "homepage": "https://tiptap.dev/api/extensions/unique-id",
6
6
  "keywords": [
7
7
  "tiptap",
@@ -15,30 +15,32 @@
15
15
  "type": "module",
16
16
  "exports": {
17
17
  ".": {
18
- "types": "./dist/index.d.ts",
18
+ "types": {
19
+ "import": "./dist/index.d.ts",
20
+ "require": "./dist/index.d.cts"
21
+ },
19
22
  "import": "./dist/index.js",
20
23
  "require": "./dist/index.cjs"
21
24
  }
22
25
  },
23
26
  "main": "dist/index.cjs",
24
27
  "module": "dist/index.js",
25
- "umd": "dist/index.umd.js",
26
28
  "types": "dist/index.d.ts",
27
29
  "files": [
28
30
  "src",
29
31
  "dist"
30
32
  ],
31
33
  "peerDependencies": {
32
- "@tiptap/core": "^2.7.0",
33
- "@tiptap/pm": "^2.7.0"
34
+ "@tiptap/core": "3.0.0-beta.10",
35
+ "@tiptap/pm": "3.0.0-beta.10"
34
36
  },
35
37
  "dependencies": {
36
38
  "uuid": "^10.0.0"
37
39
  },
38
40
  "devDependencies": {
39
- "@tiptap/core": "^2.24.2",
40
- "@tiptap/pm": "^2.24.2",
41
- "@types/uuid": "^10.0.0"
41
+ "@types/uuid": "^10.0.0",
42
+ "@tiptap/core": "3.0.0-beta.10",
43
+ "@tiptap/pm": "3.0.0-beta.10"
42
44
  },
43
45
  "repository": {
44
46
  "type": "git",
@@ -46,7 +48,7 @@
46
48
  "directory": "packages/extension-unique-id"
47
49
  },
48
50
  "scripts": {
49
- "clean": "rm -rf dist",
50
- "build": "npm run clean && rollup -c"
51
+ "build": "tsup",
52
+ "lint": "prettier ./src/ --check && eslint --cache --quiet --no-error-on-unmatched-pattern ./src/"
51
53
  }
52
- }
54
+ }