@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.
@@ -6,6 +6,7 @@ export function isVisible(item: Y.Item, snapshot?: Y.Snapshot): boolean;
6
6
  export function ySyncPlugin(yXmlFragment: Y.XmlFragment, { colors, colorMapping, permanentUserData, onFirstRender, mapping }?: YSyncOpts): any;
7
7
  export function getRelativeSelection(pmbinding: ProsemirrorBinding, state: import('prosemirror-state').EditorState): {
8
8
  type: any;
9
+ depth: any;
9
10
  anchor: any;
10
11
  head: any;
11
12
  };
@@ -44,6 +45,7 @@ export class ProsemirrorBinding {
44
45
  */
45
46
  beforeTransactionSelection: {
46
47
  type: any;
48
+ depth: any;
47
49
  anchor: any;
48
50
  head: any;
49
51
  };
package/dist/y-tiptap.cjs CHANGED
@@ -330,7 +330,28 @@ const restoreRelativeSelection = (tr, relSel, binding) => {
330
330
  relSel.anchor,
331
331
  binding.mapping
332
332
  );
333
- tr.setSelection(createSafeNodeSelection(tr, anchor));
333
+ // anchor is null when the referenced node was deleted or moved out of
334
+ // binding.type by a remote update; resolving null would throw.
335
+ if (anchor !== null) {
336
+ tr.setSelection(createSafeNodeSelection(tr, anchor));
337
+ }
338
+ } else if (relSel.type === 'nodeRange') {
339
+ const anchor = relativePositionToAbsolutePosition(
340
+ binding.doc,
341
+ binding.type,
342
+ relSel.anchor,
343
+ binding.mapping
344
+ );
345
+ const head = relativePositionToAbsolutePosition(
346
+ binding.doc,
347
+ binding.type,
348
+ relSel.head,
349
+ binding.mapping
350
+ );
351
+ const selection = createSafeNodeRangeSelection(tr, anchor, head, relSel.depth);
352
+ if (selection !== null) {
353
+ tr.setSelection(selection);
354
+ }
334
355
  } else {
335
356
  const anchor = relativePositionToAbsolutePosition(
336
357
  binding.doc,
@@ -368,23 +389,65 @@ const createSafeNodeSelection = (tr, pos) => {
368
389
  }
369
390
  };
370
391
 
392
+ /**
393
+ * Safely reconstructs a NodeRangeSelection from resolved absolute positions.
394
+ *
395
+ * @param {import('prosemirror-state').Transaction} tr - The transaction whose document provides resolved positions.
396
+ * @param {number|null} anchor - Absolute document position marking the start (boundary) of the node range.
397
+ * Use `relativePositionToAbsolutePosition` before calling this function.
398
+ * @param {number|null} head - Absolute document position marking the end (boundary) of the node range.
399
+ * Use `relativePositionToAbsolutePosition` before calling this function.
400
+ * @param {number|undefined} depth - The nesting depth at which the range operates (e.g. 0 for
401
+ * top-level blocks, 1 for blocks nested inside a wrapper). Passed through to
402
+ * `Selection.fromJSON`; ignored by `@tiptap/extension-node-range` < v2.29 but
403
+ * properly stored starting from that version.
404
+ * @returns {import('prosemirror-state').Selection|null} Reconstructed selection, or null if
405
+ * anchor/head could not be resolved.
406
+ */
407
+ const createSafeNodeRangeSelection = (tr, anchor, head, depth) => {
408
+ if (anchor === null || head === null) {
409
+ return null
410
+ }
411
+ const clampedAnchor = Math.min(Math.max(anchor, 0), tr.doc.content.size);
412
+ const clampedHead = Math.min(Math.max(head, 0), tr.doc.content.size);
413
+ try {
414
+ const selection = prosemirrorState.Selection.fromJSON(tr.doc, {
415
+ type: 'nodeRange',
416
+ anchor: clampedAnchor,
417
+ head: clampedHead,
418
+ depth
419
+ });
420
+ if (!selection.ranges.length) {
421
+ return prosemirrorState.TextSelection.near(tr.doc.resolve(clampedAnchor))
422
+ }
423
+ return selection
424
+ } catch (e) {
425
+ return prosemirrorState.TextSelection.near(tr.doc.resolve(clampedAnchor))
426
+ }
427
+ };
428
+
371
429
  /**
372
430
  * @param {ProsemirrorBinding} pmbinding
373
431
  * @param {import('prosemirror-state').EditorState} state
374
432
  */
375
- const getRelativeSelection = (pmbinding, state) => ({
376
- type: /** @type {any} */ (state.selection).jsonID,
377
- anchor: absolutePositionToRelativePosition(
378
- state.selection.anchor,
379
- pmbinding.type,
380
- pmbinding.mapping
381
- ),
382
- head: absolutePositionToRelativePosition(
383
- state.selection.head,
384
- pmbinding.type,
385
- pmbinding.mapping
386
- )
387
- });
433
+ const getRelativeSelection = (pmbinding, state) => {
434
+ const type = /** @type {any} */ (state.selection).jsonID;
435
+ return {
436
+ type,
437
+ // `depth` is only meaningful for NodeRangeSelection; undefined for every other type.
438
+ depth: type === 'nodeRange' ? /** @type {any} */ (state.selection).depth : undefined,
439
+ anchor: absolutePositionToRelativePosition(
440
+ state.selection.anchor,
441
+ pmbinding.type,
442
+ pmbinding.mapping
443
+ ),
444
+ head: absolutePositionToRelativePosition(
445
+ state.selection.head,
446
+ pmbinding.type,
447
+ pmbinding.mapping
448
+ )
449
+ }
450
+ };
388
451
 
389
452
  /**
390
453
  * Binding for prosemirror.
@@ -1643,7 +1706,11 @@ const relativePositionToAbsolutePosition = (y, documentType, relPos, mapping) =>
1643
1706
  if (t instanceof Y__namespace.XmlText) {
1644
1707
  pos += t._length;
1645
1708
  } else {
1646
- pos += /** @type {any} */ (mapping.get(t)).nodeSize;
1709
+ const mapped = mapping.get(t);
1710
+ if (mapped == null) {
1711
+ return null
1712
+ }
1713
+ pos += /** @type {any} */ (mapped).nodeSize;
1647
1714
  }
1648
1715
  }
1649
1716
  n = /** @type {Y.Item} */ (n.right);
@@ -1667,7 +1734,11 @@ const relativePositionToAbsolutePosition = (y, documentType, relPos, mapping) =>
1667
1734
  if (contentType instanceof Y__namespace.XmlText) {
1668
1735
  pos += contentType._length;
1669
1736
  } else {
1670
- pos += /** @type {any} */ (mapping.get(contentType)).nodeSize;
1737
+ const mapped = mapping.get(contentType);
1738
+ if (mapped == null) {
1739
+ return null
1740
+ }
1741
+ pos += /** @type {any} */ (mapped).nodeSize;
1671
1742
  }
1672
1743
  }
1673
1744
  n = n.right;