@tiptap/y-tiptap 3.0.4 → 3.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/plugins/sync-plugin.d.ts +2 -0
- package/dist/y-tiptap.cjs +87 -16
- package/dist/y-tiptap.cjs.map +1 -1
- package/dist/y-tiptap.js +88 -17
- package/dist/y-tiptap.js.map +1 -1
- package/package.json +1 -1
package/dist/y-tiptap.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
2
|
import { Item, ContentType, Text, XmlElement, UndoManager } from 'yjs';
|
|
3
3
|
import { DecorationSet, Decoration } from 'prosemirror-view';
|
|
4
|
-
import { PluginKey, Plugin, TextSelection, AllSelection, NodeSelection } from 'prosemirror-state';
|
|
4
|
+
import { PluginKey, Plugin, TextSelection, AllSelection, NodeSelection, Selection } from 'prosemirror-state';
|
|
5
5
|
import 'y-protocols/awareness';
|
|
6
6
|
import { createMutex } from 'lib0/mutex';
|
|
7
7
|
import * as PModel from 'prosemirror-model';
|
|
@@ -296,7 +296,28 @@ const restoreRelativeSelection = (tr, relSel, binding) => {
|
|
|
296
296
|
relSel.anchor,
|
|
297
297
|
binding.mapping
|
|
298
298
|
);
|
|
299
|
-
|
|
299
|
+
// anchor is null when the referenced node was deleted or moved out of
|
|
300
|
+
// binding.type by a remote update; resolving null would throw.
|
|
301
|
+
if (anchor !== null) {
|
|
302
|
+
tr.setSelection(createSafeNodeSelection(tr, anchor));
|
|
303
|
+
}
|
|
304
|
+
} else if (relSel.type === 'nodeRange') {
|
|
305
|
+
const anchor = relativePositionToAbsolutePosition(
|
|
306
|
+
binding.doc,
|
|
307
|
+
binding.type,
|
|
308
|
+
relSel.anchor,
|
|
309
|
+
binding.mapping
|
|
310
|
+
);
|
|
311
|
+
const head = relativePositionToAbsolutePosition(
|
|
312
|
+
binding.doc,
|
|
313
|
+
binding.type,
|
|
314
|
+
relSel.head,
|
|
315
|
+
binding.mapping
|
|
316
|
+
);
|
|
317
|
+
const selection = createSafeNodeRangeSelection(tr, anchor, head, relSel.depth);
|
|
318
|
+
if (selection !== null) {
|
|
319
|
+
tr.setSelection(selection);
|
|
320
|
+
}
|
|
300
321
|
} else {
|
|
301
322
|
const anchor = relativePositionToAbsolutePosition(
|
|
302
323
|
binding.doc,
|
|
@@ -334,23 +355,65 @@ const createSafeNodeSelection = (tr, pos) => {
|
|
|
334
355
|
}
|
|
335
356
|
};
|
|
336
357
|
|
|
358
|
+
/**
|
|
359
|
+
* Safely reconstructs a NodeRangeSelection from resolved absolute positions.
|
|
360
|
+
*
|
|
361
|
+
* @param {import('prosemirror-state').Transaction} tr - The transaction whose document provides resolved positions.
|
|
362
|
+
* @param {number|null} anchor - Absolute document position marking the start (boundary) of the node range.
|
|
363
|
+
* Use `relativePositionToAbsolutePosition` before calling this function.
|
|
364
|
+
* @param {number|null} head - Absolute document position marking the end (boundary) of the node range.
|
|
365
|
+
* Use `relativePositionToAbsolutePosition` before calling this function.
|
|
366
|
+
* @param {number|undefined} depth - The nesting depth at which the range operates (e.g. 0 for
|
|
367
|
+
* top-level blocks, 1 for blocks nested inside a wrapper). Passed through to
|
|
368
|
+
* `Selection.fromJSON`; ignored by `@tiptap/extension-node-range` < v2.29 but
|
|
369
|
+
* properly stored starting from that version.
|
|
370
|
+
* @returns {import('prosemirror-state').Selection|null} Reconstructed selection, or null if
|
|
371
|
+
* anchor/head could not be resolved.
|
|
372
|
+
*/
|
|
373
|
+
const createSafeNodeRangeSelection = (tr, anchor, head, depth) => {
|
|
374
|
+
if (anchor === null || head === null) {
|
|
375
|
+
return null
|
|
376
|
+
}
|
|
377
|
+
const clampedAnchor = Math.min(Math.max(anchor, 0), tr.doc.content.size);
|
|
378
|
+
const clampedHead = Math.min(Math.max(head, 0), tr.doc.content.size);
|
|
379
|
+
try {
|
|
380
|
+
const selection = Selection.fromJSON(tr.doc, {
|
|
381
|
+
type: 'nodeRange',
|
|
382
|
+
anchor: clampedAnchor,
|
|
383
|
+
head: clampedHead,
|
|
384
|
+
depth
|
|
385
|
+
});
|
|
386
|
+
if (!selection.ranges.length) {
|
|
387
|
+
return TextSelection.near(tr.doc.resolve(clampedAnchor))
|
|
388
|
+
}
|
|
389
|
+
return selection
|
|
390
|
+
} catch (e) {
|
|
391
|
+
return TextSelection.near(tr.doc.resolve(clampedAnchor))
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
337
395
|
/**
|
|
338
396
|
* @param {ProsemirrorBinding} pmbinding
|
|
339
397
|
* @param {import('prosemirror-state').EditorState} state
|
|
340
398
|
*/
|
|
341
|
-
const getRelativeSelection = (pmbinding, state) =>
|
|
342
|
-
type
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
399
|
+
const getRelativeSelection = (pmbinding, state) => {
|
|
400
|
+
const type = /** @type {any} */ (state.selection).jsonID;
|
|
401
|
+
return {
|
|
402
|
+
type,
|
|
403
|
+
// `depth` is only meaningful for NodeRangeSelection; undefined for every other type.
|
|
404
|
+
depth: type === 'nodeRange' ? /** @type {any} */ (state.selection).depth : undefined,
|
|
405
|
+
anchor: absolutePositionToRelativePosition(
|
|
406
|
+
state.selection.anchor,
|
|
407
|
+
pmbinding.type,
|
|
408
|
+
pmbinding.mapping
|
|
409
|
+
),
|
|
410
|
+
head: absolutePositionToRelativePosition(
|
|
411
|
+
state.selection.head,
|
|
412
|
+
pmbinding.type,
|
|
413
|
+
pmbinding.mapping
|
|
414
|
+
)
|
|
415
|
+
}
|
|
416
|
+
};
|
|
354
417
|
|
|
355
418
|
/**
|
|
356
419
|
* Binding for prosemirror.
|
|
@@ -1609,7 +1672,11 @@ const relativePositionToAbsolutePosition = (y, documentType, relPos, mapping) =>
|
|
|
1609
1672
|
if (t instanceof Y.XmlText) {
|
|
1610
1673
|
pos += t._length;
|
|
1611
1674
|
} else {
|
|
1612
|
-
|
|
1675
|
+
const mapped = mapping.get(t);
|
|
1676
|
+
if (mapped == null) {
|
|
1677
|
+
return null
|
|
1678
|
+
}
|
|
1679
|
+
pos += /** @type {any} */ (mapped).nodeSize;
|
|
1613
1680
|
}
|
|
1614
1681
|
}
|
|
1615
1682
|
n = /** @type {Y.Item} */ (n.right);
|
|
@@ -1633,7 +1700,11 @@ const relativePositionToAbsolutePosition = (y, documentType, relPos, mapping) =>
|
|
|
1633
1700
|
if (contentType instanceof Y.XmlText) {
|
|
1634
1701
|
pos += contentType._length;
|
|
1635
1702
|
} else {
|
|
1636
|
-
|
|
1703
|
+
const mapped = mapping.get(contentType);
|
|
1704
|
+
if (mapped == null) {
|
|
1705
|
+
return null
|
|
1706
|
+
}
|
|
1707
|
+
pos += /** @type {any} */ (mapped).nodeSize;
|
|
1637
1708
|
}
|
|
1638
1709
|
}
|
|
1639
1710
|
n = n.right;
|