superdoc 2.3.0 → 2.4.0-next.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.
Files changed (63) hide show
  1. package/README.md +0 -1
  2. package/dist/chunks/{FindReplaceSurface-DLxnCQOB.cjs → FindReplaceSurface-9VkPw_-X.cjs} +3 -4
  3. package/dist/chunks/{FindReplaceSurface-BEW-1NhM.es.js → FindReplaceSurface-BuvaIrQ5.es.js} +2 -3
  4. package/dist/chunks/{PasswordPromptSurface-DMbfDvpQ.cjs → PasswordPromptSurface-Bu5xHm91.cjs} +2 -2
  5. package/dist/chunks/{PasswordPromptSurface-BA6HHqEa.es.js → PasswordPromptSurface-Bz9_sKhX.es.js} +1 -1
  6. package/dist/chunks/{PdfViewer-CNOtyS-I.es.js → PdfViewer-CdVGB6Fe.es.js} +2 -2
  7. package/dist/chunks/{PdfViewer-CoFiGAhm.cjs → PdfViewer-D4eD2dV1.cjs} +3 -3
  8. package/dist/chunks/blank-docx-DP8RUPW-.cjs +7 -0
  9. package/dist/chunks/blank-docx-XRX6Ker2.es.js +2 -0
  10. package/dist/chunks/{create-super-doc-ui-CXCqHc2m.cjs → create-super-doc-ui-ByvmsAAG.cjs} +672 -190
  11. package/dist/chunks/{create-super-doc-ui-fxF2Q8Ib.es.js → create-super-doc-ui-DBXOhHdW.es.js} +667 -191
  12. package/dist/chunks/{eventemitter3-B60Fsz-a.es.js → eventemitter3-Bt2s0X0a.es.js} +1 -1
  13. package/dist/chunks/{eventemitter3-DCfwFVNn.cjs → eventemitter3-DqY4aSMf.cjs} +1 -1
  14. package/dist/chunks/{jszip-DzmwAHr3.es.js → jszip-C8srOKAO.es.js} +2 -2
  15. package/dist/chunks/{jszip-BdUBlUeG.cjs → jszip-Cs9JBLlJ.cjs} +13 -1
  16. package/dist/chunks/{rolldown-runtime-_dR15c8t.cjs → rolldown-runtime-1Y-nnZJ3.cjs} +0 -28
  17. package/dist/chunks/{rolldown-runtime-BJVcqBbz.es.js → rolldown-runtime-D7PMmH3s.es.js} +1 -17
  18. package/dist/collaboration-upgrade-engine.cjs +1 -1
  19. package/dist/collaboration-upgrade-engine.es.js +1 -1
  20. package/dist/document-api/src/comments/comment-create-attribution.d.ts +2 -0
  21. package/dist/document-api/src/comments/comments.d.ts +13 -4
  22. package/dist/document-api/src/comments/comments.types.d.ts +39 -0
  23. package/dist/document-api/src/content-controls/content-controls.types.d.ts +2 -0
  24. package/dist/document-api/src/contract/metadata-types.d.ts +18 -0
  25. package/dist/document-api/src/contract/operation-definitions.d.ts +1 -1
  26. package/dist/document-api/src/index.d.ts +2 -2
  27. package/dist/document-api/src/types/track-changes.types.d.ts +1 -3
  28. package/dist/layout-engine/painters/dom/src/_test-utils.d.ts +3 -2
  29. package/dist/layout-engine/painters/dom/src/index.d.ts +24 -19
  30. package/dist/layout-engine/painters/dom/src/page-content.d.ts +107 -39
  31. package/dist/layout-engine/painters/dom/src/persistent-page-surface.d.ts +144 -0
  32. package/dist/layout-engine/painters/dom/src/pm-position-validation.d.ts +1 -1
  33. package/dist/layout-engine/painters/dom/src/renderer.d.ts +50 -106
  34. package/dist/layout-engine/painters/dom/src/sdt/boundaries.d.ts +1 -1
  35. package/dist/public/ui-react.cjs +2 -2
  36. package/dist/public/ui-react.es.js +1 -1
  37. package/dist/public/ui.cjs +1 -1
  38. package/dist/public/ui.es.js +1 -1
  39. package/dist/style.css +138 -131
  40. package/dist/style.layered.css +138 -131
  41. package/dist/superdoc/src/core/types/index.d.ts +383 -16
  42. package/dist/superdoc/src/helpers/floor.d.ts +1 -1
  43. package/dist/superdoc/src/helpers/v2-review-mutation-impact.d.ts +5 -0
  44. package/dist/superdoc/src/helpers/v2-review-mutation-reconciler.d.ts +1 -1
  45. package/dist/superdoc/src/internal/toolbar/built-in/constants.d.ts +0 -1
  46. package/dist/superdoc/src/internal/toolbar/compatibility-catalog.d.ts +1 -1
  47. package/dist/superdoc/src/public/index.d.cts +14 -0
  48. package/dist/superdoc/src/public/index.d.ts +7 -0
  49. package/dist/superdoc/src/public/ui/types.d.ts +25 -1
  50. package/dist/superdoc/src/stores/comments-store.d.ts +124 -22
  51. package/dist/superdoc/src/stores/superdoc-store.d.ts +372 -66
  52. package/dist/superdoc.cjs +5160 -668
  53. package/dist/superdoc.es.js +5163 -675
  54. package/dist-cdn/style.layered.css +1 -1
  55. package/dist-cdn/superdoc.min.css +1 -1
  56. package/dist-cdn/superdoc.min.js +37 -37
  57. package/package.json +5 -4
  58. package/dist/chunks/blank-docx-CJAXnJKp.es.js +0 -2
  59. package/dist/chunks/blank-docx-DA-G-3VB.cjs +0 -7
  60. /package/dist/chunks/{_plugin-vue_export-helper-BTwbGDKw.cjs → _plugin-vue_export-helper-CZ1Nl59K.cjs} +0 -0
  61. /package/dist/chunks/{_plugin-vue_export-helper-CInC0bKI.es.js → _plugin-vue_export-helper-DSMAhhwD.es.js} +0 -0
  62. /package/dist/chunks/{constants-CY3R3_kF.es.js → constants-BfH0br5u.es.js} +0 -0
  63. /package/dist/chunks/{constants-sbCZ2O_A.cjs → constants-D7TNtyJd.cjs} +0 -0
@@ -1,3 +1,64 @@
1
+ const DOM_CLASS_NAMES = {
2
+ PAGE: "superdoc-page",
3
+ FRAGMENT: "superdoc-fragment",
4
+ LINE: "superdoc-line",
5
+ INLINE_SDT_WRAPPER: "superdoc-structured-content-inline",
6
+ INLINE_SDT_LABEL: "superdoc-structured-content-inline__label",
7
+ BLOCK_SDT: "superdoc-structured-content-block",
8
+ BLOCK_SDT_LABEL: "superdoc-structured-content__label",
9
+ TABLE_FRAGMENT: "superdoc-table-fragment",
10
+ DOCUMENT_SECTION: "superdoc-document-section",
11
+ SDT_GROUP_HOVER: "sdt-group-hover",
12
+ TOC_ENTRY: "superdoc-toc-entry",
13
+ TOC_GROUP_HOVER: "toc-group-hover",
14
+ IMAGE_FRAGMENT: "superdoc-image-fragment",
15
+ INLINE_IMAGE: "superdoc-inline-image",
16
+ LIST_MARKER: "superdoc-list-marker",
17
+ INLINE_IMAGE_CLIP_WRAPPER: "superdoc-inline-image-clip-wrapper",
18
+ ANNOTATION: "annotation",
19
+ ANNOTATION_CONTENT: "annotation-content",
20
+ ANNOTATION_CARET_ANCHOR: "annotation-caret-anchor"
21
+ };
22
+ const STRUCTURED_CONTENT_CHROME_LABEL_CLASS_NAMES = [DOM_CLASS_NAMES.INLINE_SDT_LABEL, DOM_CLASS_NAMES.BLOCK_SDT_LABEL];
23
+ const DATA_ATTRS = {
24
+ PM_START: "data-pm-start",
25
+ PM_END: "data-pm-end",
26
+ LAYOUT_EPOCH: "data-layout-epoch",
27
+ TABLE_BOUNDARIES: "data-table-boundaries",
28
+ SDT_ID: "data-sdt-id",
29
+ SDT_TYPE: "data-sdt-type",
30
+ FIELD_ID: "data-field-id",
31
+ FIELD_TYPE: "data-field-type",
32
+ DRAGGABLE: "data-draggable",
33
+ DISPLAY_LABEL: "data-display-label",
34
+ VARIANT: "data-variant",
35
+ TYPE: "data-type",
36
+ LAYOUT_BOUNDARY_SCHEMA: "data-layout-boundary-schema",
37
+ LAYOUT_FRAGMENT_ID: "data-layout-fragment-id",
38
+ LAYOUT_STORY: "data-layout-story",
39
+ LAYOUT_BLOCK_REF: "data-layout-block-ref"
40
+ };
41
+ const decodeLayoutStoryDataset = (raw) => {
42
+ if (!raw) return { kind: "unknown" };
43
+ if (raw === "body") return { kind: "body" };
44
+ const idx = raw.indexOf(":");
45
+ const kind = idx === -1 ? raw : raw.slice(0, idx);
46
+ const id = idx === -1 ? void 0 : raw.slice(idx + 1);
47
+ switch (kind) {
48
+ case "body":
49
+ case "header":
50
+ case "footer":
51
+ case "footnote":
52
+ case "endnote":
53
+ case "textbox": return id ? {
54
+ kind,
55
+ id
56
+ } : { kind };
57
+ default: return { kind: "unknown" };
58
+ }
59
+ };
60
+ const SDT_BLOCK_WITH_ID_SELECTOR = `.${DOM_CLASS_NAMES.BLOCK_SDT}[${DATA_ATTRS.SDT_ID}]`;
61
+ const DRAGGABLE_SELECTOR = `[${DATA_ATTRS.DRAGGABLE}="true"]`;
1
62
  function getParagraphInlineDirection(attrs) {
2
63
  const fromContext = attrs?.directionContext?.inlineDirection;
3
64
  if (fromContext != null) return fromContext;
@@ -309,27 +370,46 @@ function getV2TrackedChangeMutationImpact(event) {
309
370
  if (!payload || typeof payload !== "object") return null;
310
371
  const upsertIds = /* @__PURE__ */ new Set();
311
372
  const removedIds = /* @__PURE__ */ new Set();
373
+ const remappedPairs = [];
312
374
  const collectEntity = (entry, into) => {
313
375
  if (entry?.kind !== "entity" || entry.entityType !== "trackedChange") return;
314
376
  if (typeof entry.entityId === "string" && entry.entityId.length > 0) into.add(entry.entityId);
315
377
  };
378
+ const readEntityId$1 = (entry) => {
379
+ if (entry?.kind !== "entity" || entry.entityType !== "trackedChange") return null;
380
+ return typeof entry.entityId === "string" && entry.entityId.length > 0 ? entry.entityId : null;
381
+ };
316
382
  if (Array.isArray(payload.inserted)) payload.inserted.forEach((entry) => collectEntity(entry, upsertIds));
317
383
  if (Array.isArray(payload.updated)) payload.updated.forEach((entry) => collectEntity(entry, upsertIds));
318
384
  if (Array.isArray(payload.trackedChangeRefs)) payload.trackedChangeRefs.forEach((entry) => collectEntity(entry, upsertIds));
319
385
  if (Array.isArray(payload.removed)) payload.removed.forEach((entry) => collectEntity(entry, removedIds));
320
386
  if (Array.isArray(payload.invalidatedRefs)) payload.invalidatedRefs.forEach((entry) => collectEntity(entry, removedIds));
321
387
  if (Array.isArray(payload.remappedRefs)) for (const mapping of payload.remappedRefs) {
322
- collectEntity(mapping?.from, removedIds);
323
- collectEntity(mapping?.to, upsertIds);
388
+ const fromId = readEntityId$1(mapping?.from);
389
+ const toId = readEntityId$1(mapping?.to);
390
+ if (fromId) removedIds.add(fromId);
391
+ if (toId) upsertIds.add(toId);
392
+ if (fromId && toId && fromId !== toId) remappedPairs.push({
393
+ from: fromId,
394
+ to: toId
395
+ });
324
396
  }
325
397
  for (const id of removedIds) upsertIds.delete(id);
326
- if (upsertIds.size === 0 && removedIds.size === 0) return null;
398
+ const allResolved = readAllResolvedFact(event, payload);
399
+ if (upsertIds.size === 0 && removedIds.size === 0 && !allResolved) return null;
327
400
  return {
328
401
  upsertIds,
329
402
  removedIds,
330
- reconcileMode: event.origin === "history" ? "authoritative" : "targeted"
403
+ remappedPairs,
404
+ reconcileMode: event.origin === "history" ? "authoritative" : "targeted",
405
+ ...allResolved ? { allResolved } : {}
331
406
  };
332
407
  }
408
+ function readAllResolvedFact(event, receipt) {
409
+ const fact = event?.trackedChangeAllResolved;
410
+ if (event?.origin === "history" || !fact || fact.schemaVersion !== 1 || fact.targetKind !== "all" || fact.decision !== "accept" && fact.decision !== "reject" || fact.remainingLogicalCount !== 0 || typeof fact.catalogRevision !== "string" || !fact.catalogRevision || typeof fact.sourceCoverageRevision !== "string" || !fact.sourceCoverageRevision || !Number.isSafeInteger(fact.logicalTargetCount) || fact.logicalTargetCount <= 0 || !Number.isSafeInteger(fact.physicalCarrierCount) || fact.physicalCarrierCount < fact.logicalTargetCount || typeof fact.txId !== "string" || fact.txId !== receipt.txId || typeof fact.documentEpoch !== "string" || !Number.isSafeInteger(fact.commitSequence) || typeof fact.packagePreviousRevision !== "string" || typeof fact.packageNextRevision !== "string" || fact.packagePreviousRevision === fact.packageNextRevision) return null;
411
+ return fact;
412
+ }
333
413
  var normalizeIds = (values) => new Set(Array.from(values ?? []).filter((value) => typeof value === "string" && value.length > 0));
334
414
  var itemId = (item) => {
335
415
  if (typeof item?.id === "string" && item.id.length > 0) return item.id;
@@ -340,10 +420,20 @@ var itemId = (item) => {
340
420
  var contextMatches = (left, right) => left?.adapter === right?.adapter && left?.documentId === right?.documentId && left?.editor === right?.editor && left?.reconcileToken === right?.reconcileToken;
341
421
  function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onReconciled }) {
342
422
  const pendingUpserts = /* @__PURE__ */ new Map();
423
+ let pendingAllResolved = null;
343
424
  let sequence = 0;
344
425
  let generation = 0;
345
426
  let flushInFlight = null;
346
427
  let flushRequested = false;
428
+ const settlementWaiters = [];
429
+ const resolveSettlementsThrough = (version, value) => {
430
+ for (let index = settlementWaiters.length - 1; index >= 0; index -= 1) {
431
+ const waiter = settlementWaiters[index];
432
+ if (waiter.generation !== generation || waiter.version > version) continue;
433
+ settlementWaiters.splice(index, 1);
434
+ waiter.resolve(value === true && waiter.requiresAllResolved ? pendingAllResolved == null : value);
435
+ }
436
+ };
347
437
  const isCurrent = (capturedGeneration, context) => generation === capturedGeneration && contextMatches(context, getContext());
348
438
  const clearResolved = (ids, snapshot) => {
349
439
  const clearedIds = /* @__PURE__ */ new Set();
@@ -357,6 +447,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
357
447
  const readySnapshot = (reconcileMode) => new Map([...pendingUpserts].filter(([, entry]) => entry.ready === true && entry.reconcileMode === reconcileMode));
358
448
  const markRenderGatedReady = () => {
359
449
  let changed = false;
450
+ if (pendingAllResolved?.gate === "render" && !pendingAllResolved.ready) {
451
+ pendingAllResolved.ready = true;
452
+ changed = true;
453
+ }
360
454
  for (const entry of pendingUpserts.values()) {
361
455
  if (entry.gate !== "render" || entry.ready) continue;
362
456
  entry.ready = true;
@@ -366,6 +460,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
366
460
  };
367
461
  const markEntriesReadyThrough = (maxVersion) => {
368
462
  let changed = false;
463
+ if (pendingAllResolved && pendingAllResolved.version <= maxVersion && !pendingAllResolved.ready) {
464
+ pendingAllResolved.ready = true;
465
+ changed = true;
466
+ }
369
467
  for (const entry of pendingUpserts.values()) {
370
468
  if (entry.version > maxVersion || entry.ready) continue;
371
469
  entry.ready = true;
@@ -416,14 +514,31 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
416
514
  };
417
515
  const flush = () => {
418
516
  if (flushInFlight) return flushInFlight;
517
+ const allResolvedSnapshot = pendingAllResolved?.ready ? pendingAllResolved : null;
419
518
  const targetedSnapshot = readySnapshot("targeted");
420
519
  const authoritativeSnapshot = readySnapshot("authoritative");
421
- if (targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
520
+ if (!allResolvedSnapshot && targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
422
521
  const context = getContext();
423
522
  if (!context?.adapter) return null;
424
523
  flushRequested = false;
425
524
  const capturedGeneration = generation;
426
525
  flushInFlight = Promise.resolve().then(async () => {
526
+ if (allResolvedSnapshot) {
527
+ let result = null;
528
+ try {
529
+ result = await reconcile(context, {
530
+ upsertIds: /* @__PURE__ */ new Set(),
531
+ removedIds: /* @__PURE__ */ new Set(),
532
+ allResolved: allResolvedSnapshot.fact,
533
+ reconcileMode: "targeted"
534
+ });
535
+ } catch {}
536
+ if (!isCurrent(capturedGeneration, context)) return;
537
+ if (result?.ok === true) {
538
+ if (pendingAllResolved === allResolvedSnapshot) pendingAllResolved = null;
539
+ await notifyReconciled(context, /* @__PURE__ */ new Set(), result, true);
540
+ }
541
+ }
427
542
  if (authoritativeSnapshot.size > 0) await reconcileAuthoritativeSnapshot(context, authoritativeSnapshot, capturedGeneration).catch(() => void 0);
428
543
  if (targetedSnapshot.size > 0) await reconcileTargetedSnapshot(context, targetedSnapshot, capturedGeneration).catch(() => void 0);
429
544
  }).catch(() => {}).finally(() => {
@@ -434,8 +549,18 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
434
549
  };
435
550
  const enqueueWithGate = (impact, gate) => {
436
551
  if (!impact) return;
552
+ if (impact.allResolved) {
553
+ pendingUpserts.clear();
554
+ pendingAllResolved = {
555
+ fact: impact.allResolved,
556
+ version: ++sequence,
557
+ gate,
558
+ ready: false
559
+ };
560
+ }
437
561
  const reconcileMode = impact.reconcileMode === "authoritative" ? "authoritative" : "targeted";
438
562
  const removedIds = normalizeIds(impact.removedIds);
563
+ const upsertIds = normalizeIds(impact.upsertIds);
439
564
  for (const id of removedIds) {
440
565
  const existing = pendingUpserts.get(id);
441
566
  if (existing?.reconcileMode === "authoritative") pendingUpserts.set(id, {
@@ -447,13 +572,13 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
447
572
  else pendingUpserts.delete(id);
448
573
  }
449
574
  const context = getContext();
450
- if (removedIds.size > 0 && context?.adapter) try {
575
+ if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter && !impact.allResolved) try {
451
576
  Promise.resolve(reconcile(context, {
452
577
  upsertIds: /* @__PURE__ */ new Set(),
453
578
  removedIds
454
579
  })).catch(() => void 0);
455
580
  } catch {}
456
- for (const id of normalizeIds(impact.upsertIds)) if (!removedIds.has(id)) {
581
+ for (const id of upsertIds) if (!removedIds.has(id)) {
457
582
  const existing = pendingUpserts.get(id);
458
583
  pendingUpserts.set(id, {
459
584
  version: ++sequence,
@@ -474,20 +599,34 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
474
599
  enqueueAfterPaint(impact, waitForPaint) {
475
600
  if (!impact || typeof waitForPaint !== "function") {
476
601
  enqueue(impact);
477
- return;
602
+ return Promise.resolve(false);
478
603
  }
479
604
  enqueueWithGate(impact, "exact-paint");
480
605
  const context = getContext();
481
- if (!context?.adapter) return;
482
606
  const capturedGeneration = generation;
483
607
  const capturedSequence = sequence;
608
+ if (!context?.adapter) {
609
+ markEntriesReadyThrough(capturedSequence);
610
+ return Promise.resolve(false);
611
+ }
612
+ const completion = new Promise((resolve) => {
613
+ settlementWaiters.push({
614
+ generation: capturedGeneration,
615
+ version: capturedSequence,
616
+ requiresAllResolved: Boolean(impact.allResolved),
617
+ resolve
618
+ });
619
+ });
484
620
  const impactedIds = new Set([...normalizeIds(impact.upsertIds), ...normalizeIds(impact.removedIds)]);
485
621
  const capturedEntries = new Map([...impactedIds].flatMap((id) => {
486
622
  const entry = pendingUpserts.get(id);
487
623
  return entry ? [[id, entry]] : [];
488
624
  }));
489
- Promise.resolve().then(() => waitForPaint()).then(() => {
490
- if (!isCurrent(capturedGeneration, context)) return;
625
+ Promise.resolve().then(() => waitForPaint()).then(async () => {
626
+ if (!isCurrent(capturedGeneration, context)) {
627
+ resolveSettlementsThrough(capturedSequence, false);
628
+ return;
629
+ }
491
630
  let madeReady = markRenderGatedReady();
492
631
  if (markEntriesReadyThrough(capturedSequence)) madeReady = true;
493
632
  for (const [id, entry] of capturedEntries) {
@@ -496,16 +635,35 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
496
635
  entry.ready = true;
497
636
  }
498
637
  if (flushInFlight && (madeReady || capturedSequence > 0)) flushRequested = true;
499
- flush();
638
+ const preceding = flushInFlight;
639
+ const pending = flush();
640
+ if (pending) await pending;
641
+ if (preceding) {
642
+ const followUp = flushInFlight;
643
+ if (followUp && followUp !== preceding) await followUp;
644
+ }
645
+ if (!isCurrent(capturedGeneration, context)) {
646
+ resolveSettlementsThrough(capturedSequence, false);
647
+ return;
648
+ }
649
+ resolveSettlementsThrough(capturedSequence, true);
500
650
  }).catch(() => {
501
- if (!isCurrent(capturedGeneration, context)) return;
651
+ if (!isCurrent(capturedGeneration, context)) {
652
+ resolveSettlementsThrough(capturedSequence, false);
653
+ return;
654
+ }
502
655
  for (const [id, entry] of capturedEntries) if (pendingUpserts.get(id) === entry) entry.gate = "render";
656
+ if (pendingAllResolved?.gate === "exact-paint") pendingAllResolved.gate = "render";
657
+ resolveSettlementsThrough(capturedSequence, false);
503
658
  });
659
+ return completion;
504
660
  },
505
661
  onRender,
506
662
  reset() {
663
+ for (const waiter of settlementWaiters.splice(0)) waiter.resolve(false);
507
664
  generation += 1;
508
665
  pendingUpserts.clear();
666
+ pendingAllResolved = null;
509
667
  flushRequested = false;
510
668
  },
511
669
  getPendingIds() {
@@ -1388,67 +1546,6 @@ function collectEntityHitsFromChain(start, stopAt) {
1388
1546
  }
1389
1547
  return hits;
1390
1548
  }
1391
- const DOM_CLASS_NAMES = {
1392
- PAGE: "superdoc-page",
1393
- FRAGMENT: "superdoc-fragment",
1394
- LINE: "superdoc-line",
1395
- INLINE_SDT_WRAPPER: "superdoc-structured-content-inline",
1396
- INLINE_SDT_LABEL: "superdoc-structured-content-inline__label",
1397
- BLOCK_SDT: "superdoc-structured-content-block",
1398
- BLOCK_SDT_LABEL: "superdoc-structured-content__label",
1399
- TABLE_FRAGMENT: "superdoc-table-fragment",
1400
- DOCUMENT_SECTION: "superdoc-document-section",
1401
- SDT_GROUP_HOVER: "sdt-group-hover",
1402
- TOC_ENTRY: "superdoc-toc-entry",
1403
- TOC_GROUP_HOVER: "toc-group-hover",
1404
- IMAGE_FRAGMENT: "superdoc-image-fragment",
1405
- INLINE_IMAGE: "superdoc-inline-image",
1406
- LIST_MARKER: "superdoc-list-marker",
1407
- INLINE_IMAGE_CLIP_WRAPPER: "superdoc-inline-image-clip-wrapper",
1408
- ANNOTATION: "annotation",
1409
- ANNOTATION_CONTENT: "annotation-content",
1410
- ANNOTATION_CARET_ANCHOR: "annotation-caret-anchor"
1411
- };
1412
- const STRUCTURED_CONTENT_CHROME_LABEL_CLASS_NAMES = [DOM_CLASS_NAMES.INLINE_SDT_LABEL, DOM_CLASS_NAMES.BLOCK_SDT_LABEL];
1413
- const DATA_ATTRS = {
1414
- PM_START: "data-pm-start",
1415
- PM_END: "data-pm-end",
1416
- LAYOUT_EPOCH: "data-layout-epoch",
1417
- TABLE_BOUNDARIES: "data-table-boundaries",
1418
- SDT_ID: "data-sdt-id",
1419
- SDT_TYPE: "data-sdt-type",
1420
- FIELD_ID: "data-field-id",
1421
- FIELD_TYPE: "data-field-type",
1422
- DRAGGABLE: "data-draggable",
1423
- DISPLAY_LABEL: "data-display-label",
1424
- VARIANT: "data-variant",
1425
- TYPE: "data-type",
1426
- LAYOUT_BOUNDARY_SCHEMA: "data-layout-boundary-schema",
1427
- LAYOUT_FRAGMENT_ID: "data-layout-fragment-id",
1428
- LAYOUT_STORY: "data-layout-story",
1429
- LAYOUT_BLOCK_REF: "data-layout-block-ref"
1430
- };
1431
- const decodeLayoutStoryDataset = (raw) => {
1432
- if (!raw) return { kind: "unknown" };
1433
- if (raw === "body") return { kind: "body" };
1434
- const idx = raw.indexOf(":");
1435
- const kind = idx === -1 ? raw : raw.slice(0, idx);
1436
- const id = idx === -1 ? void 0 : raw.slice(idx + 1);
1437
- switch (kind) {
1438
- case "body":
1439
- case "header":
1440
- case "footer":
1441
- case "footnote":
1442
- case "endnote":
1443
- case "textbox": return id ? {
1444
- kind,
1445
- id
1446
- } : { kind };
1447
- default: return { kind: "unknown" };
1448
- }
1449
- };
1450
- const SDT_BLOCK_WITH_ID_SELECTOR = `.${DOM_CLASS_NAMES.BLOCK_SDT}[${DATA_ATTRS.SDT_ID}]`;
1451
- const DRAGGABLE_SELECTOR = `[${DATA_ATTRS.DRAGGABLE}="true"]`;
1452
1549
  var schemaBooleanOrNull = () => ({ oneOf: [{ type: "boolean" }, { type: "null" }] });
1453
1550
  var schemaStringOrNull = () => ({ oneOf: [{
1454
1551
  type: "string",
@@ -1703,6 +1800,30 @@ const INLINE_PROPERTY_KEYS_BY_STORAGE = {
1703
1800
  mark: INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "mark").map((entry) => entry.key),
1704
1801
  runAttribute: INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "runAttribute").map((entry) => entry.key)
1705
1802
  };
1803
+ var sharedUiTrackedChangesCatalogByHost = /* @__PURE__ */ new WeakMap();
1804
+ function acquireSharedUiTrackedChangesCatalog(host) {
1805
+ let state = sharedUiTrackedChangesCatalogByHost.get(host);
1806
+ if (!state) {
1807
+ state = {
1808
+ refCount: 0,
1809
+ generation: 0,
1810
+ abortController: new AbortController(),
1811
+ inFlight: null,
1812
+ activeMutationTokens: /* @__PURE__ */ new Set()
1813
+ };
1814
+ sharedUiTrackedChangesCatalogByHost.set(host, state);
1815
+ }
1816
+ state.refCount += 1;
1817
+ return state;
1818
+ }
1819
+ function releaseSharedUiTrackedChangesCatalog(host, state) {
1820
+ state.refCount = Math.max(0, state.refCount - 1);
1821
+ if (state.refCount > 0) return;
1822
+ state.abortController.abort("ui-controller-destroyed");
1823
+ state.inFlight = null;
1824
+ state.activeMutationTokens.clear();
1825
+ sharedUiTrackedChangesCatalogByHost.delete(host);
1826
+ }
1706
1827
  var SUPERDOC_UI_REASON_VALUES = new Set(Object.values(SUPERDOC_UI_REASONS));
1707
1828
  function coerceSuperDocUIReason(reason, fallback) {
1708
1829
  return typeof reason === "string" && SUPERDOC_UI_REASON_VALUES.has(reason) ? reason : fallback;
@@ -1799,12 +1920,12 @@ const HEAVY_DOC_READ_POLICY = [
1799
1920
  {
1800
1921
  key: "trackChanges",
1801
1922
  match: "exact",
1802
- note: "audited: body tracked-changes list; stale-served during load"
1923
+ note: "audited: shared all-story tracked-changes catalog; stale-served during load"
1803
1924
  },
1804
1925
  {
1805
1926
  key: "trackChanges:all",
1806
1927
  match: "exact",
1807
- note: "audited: all-story tracked-changes list; consumers already fail closed on non-ready"
1928
+ note: "audited: current-token validation over the shared all-story catalog; consumers fail closed on non-ready"
1808
1929
  },
1809
1930
  {
1810
1931
  key: "tables",
@@ -1886,6 +2007,48 @@ function readEntityTarget(row) {
1886
2007
  const target = row.target;
1887
2008
  return target && typeof target === "object" ? target : null;
1888
2009
  }
2010
+ function isHostGeometryTarget(target) {
2011
+ if (!target || typeof target !== "object") return false;
2012
+ const record = target;
2013
+ const isTextPoint = (point) => {
2014
+ if (!point || typeof point !== "object") return false;
2015
+ const candidate = point;
2016
+ return candidate.kind === "text" && typeof candidate.blockId === "string" && typeof candidate.offset === "number";
2017
+ };
2018
+ const isTextSegment = (segment) => {
2019
+ if (!segment || typeof segment !== "object") return false;
2020
+ const candidate = segment;
2021
+ const range$1 = candidate.range;
2022
+ return typeof candidate.blockId === "string" && typeof range$1?.start === "number" && typeof range$1.end === "number";
2023
+ };
2024
+ if (Array.isArray(record.segments)) {
2025
+ const first = record.segments[0];
2026
+ const last = record.segments[record.segments.length - 1];
2027
+ return isTextSegment(first) && isTextSegment(last);
2028
+ }
2029
+ if (record.kind === "selection") return isTextPoint(record.start) && isTextPoint(record.end);
2030
+ if (record.kind !== "text" || typeof record.blockId !== "string") return false;
2031
+ const range = record.range;
2032
+ return typeof range?.start === "number" && typeof range.end === "number";
2033
+ }
2034
+ function readTrackedChangeNavigationTarget(row) {
2035
+ if (!row || typeof row !== "object") return null;
2036
+ const target = readEntityTarget(row);
2037
+ if (isHostGeometryTarget(target)) return target;
2038
+ const record = row;
2039
+ const navigationTarget = record.navigationTarget && typeof record.navigationTarget === "object" ? record.navigationTarget : null;
2040
+ if (navigationTarget?.kind === "block" && typeof navigationTarget.blockId === "string" && navigationTarget.blockId.length > 0) return {
2041
+ kind: "text",
2042
+ blockId: navigationTarget.blockId,
2043
+ range: {
2044
+ start: 0,
2045
+ end: 0
2046
+ },
2047
+ ...navigationTarget.story && typeof navigationTarget.story === "object" ? { story: navigationTarget.story } : {},
2048
+ ...record.address && typeof record.address === "object" ? { address: record.address } : {}
2049
+ };
2050
+ return target;
2051
+ }
1889
2052
  function storyLocatorSignature(story) {
1890
2053
  if (!story || typeof story !== "object") return "story:body";
1891
2054
  const record = story;
@@ -2092,6 +2255,7 @@ function buildTrackedChangeIdContext(items) {
2092
2255
  return context;
2093
2256
  }
2094
2257
  var storyScopedTrackedChangeIdContextCache = /* @__PURE__ */ new WeakMap();
2258
+ var declaredBodyItemsCache = /* @__PURE__ */ new WeakMap();
2095
2259
  function buildStoryScopedTrackedChangeIdContext(items, story) {
2096
2260
  const signature = storyLocatorSignature(story);
2097
2261
  let byStory = storyScopedTrackedChangeIdContextCache.get(items);
@@ -2105,6 +2269,56 @@ function buildStoryScopedTrackedChangeIdContext(items, story) {
2105
2269
  byStory.set(signature, context);
2106
2270
  return context;
2107
2271
  }
2272
+ function isTextboxStory(story) {
2273
+ return !!story && typeof story === "object" && story.storyType === "textbox";
2274
+ }
2275
+ function resolveStorylessCanonicalTrackedChangeId(items, selectionIds) {
2276
+ const storyless = selectionIds.filter((id) => items.some((item) => readEntityId(item) === id && readEntityStory(item) == null));
2277
+ if (storyless.length === 0) return null;
2278
+ if (storyless.length === 1) return storyless[0];
2279
+ const seen = /* @__PURE__ */ new Set();
2280
+ for (const id of storyless) {
2281
+ const row = items.find((item) => readEntityId(item) === id);
2282
+ if (!row) continue;
2283
+ for (const raw of readTrackChangeProvenanceIds(row)) {
2284
+ if (seen.has(raw)) return null;
2285
+ seen.add(raw);
2286
+ }
2287
+ }
2288
+ return storyless[0];
2289
+ }
2290
+ function declaredBodyItems(items) {
2291
+ const cached = declaredBodyItemsCache.get(items);
2292
+ if (cached) return cached;
2293
+ const declared = items.filter((item) => readEntityStory(item) != null);
2294
+ const result = declared.length === items.length ? items : declared;
2295
+ declaredBodyItemsCache.set(items, result);
2296
+ return result;
2297
+ }
2298
+ function resolveSelectionActiveChangeId(options) {
2299
+ const { selectionIds, publicIds, selection, bodyItems, allStoryItems } = options;
2300
+ if (selectionIds.length === 0) return null;
2301
+ const mapIds = (context) => {
2302
+ for (const id of selectionIds) {
2303
+ const publicId = context.toPublicId(id);
2304
+ if (publicId) return publicId;
2305
+ }
2306
+ return null;
2307
+ };
2308
+ const story = selectionStory(selection);
2309
+ const isBodySelection = storyLocatorSignature(story) === storyLocatorSignature(null);
2310
+ if (allStoryItems) {
2311
+ const scopedItems = isBodySelection ? declaredBodyItems(allStoryItems) : allStoryItems;
2312
+ const fromStory = mapIds(buildStoryScopedTrackedChangeIdContext(scopedItems, story));
2313
+ if (fromStory) return fromStory;
2314
+ const fromPublic = publicIds?.find((id) => scopedItems.some((item) => entityRowMatchesRequest(item, id, story)));
2315
+ if (fromPublic) return fromPublic;
2316
+ if (!isBodySelection) return isTextboxStory(story) ? resolveStorylessCanonicalTrackedChangeId(allStoryItems, selectionIds) : null;
2317
+ return mapIds(buildTrackedChangeIdContext(bodyItems));
2318
+ }
2319
+ if (isBodySelection) return mapIds(buildTrackedChangeIdContext(bodyItems)) ?? selectionIds[0] ?? null;
2320
+ return null;
2321
+ }
2108
2322
  function resolveActiveCommentId(items, commentId) {
2109
2323
  const item = items.find((candidate) => readEntityId(candidate) === commentId || candidate.importedId === commentId);
2110
2324
  if (!item) return null;
@@ -3082,11 +3296,14 @@ function createSuperDocUI(options) {
3082
3296
  let explicitActiveChange = null;
3083
3297
  let explicitActiveChangeRevision = 0;
3084
3298
  let queuedTrackChangeNavigationInvalidation = 0;
3299
+ let trackChangeRevealInvalidation = 0;
3300
+ const pendingTrackChangeRevealFocuses = /* @__PURE__ */ new Set();
3085
3301
  const explicitActiveChangesEqual = (left, right) => {
3086
3302
  if (left === right) return true;
3087
3303
  if (!left || !right) return false;
3088
3304
  return left.id === right.id && left.paintedEntityId === right.paintedEntityId && storyLocatorSignature(left.story) === storyLocatorSignature(right.story);
3089
3305
  };
3306
+ const hasPendingTrackChangeRevealFocus = (focus) => Array.from(pendingTrackChangeRevealFocuses).some((pendingFocus) => explicitActiveChangesEqual(pendingFocus, focus));
3090
3307
  const mirrorTrackedChangeFocusToHost = (next) => {
3091
3308
  const host = getHost();
3092
3309
  if (typeof host?.getHandles !== "function") return;
@@ -3115,6 +3332,7 @@ function createSuperDocUI(options) {
3115
3332
  const setExplicitActiveChange = (next, options$1) => {
3116
3333
  explicitActiveChange = next;
3117
3334
  explicitActiveChangeRevision += 1;
3335
+ trackChangeRevealInvalidation += 1;
3118
3336
  if (options$1?.invalidateQueuedNavigation !== false) queuedTrackChangeNavigationInvalidation += 1;
3119
3337
  };
3120
3338
  const listeners = /* @__PURE__ */ new Set();
@@ -3166,6 +3384,63 @@ function createSuperDocUI(options) {
3166
3384
  };
3167
3385
  let documentMutationRevision = 0;
3168
3386
  let reviewMutationToken = {};
3387
+ const uiTrackedChangesCatalogHost = options.superdoc;
3388
+ const uiTrackedChangesCatalogState = acquireSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost);
3389
+ const supersedeUiTrackedChangesCatalogRead = () => {
3390
+ uiTrackedChangesCatalogState.abortController.abort("review-mutation-started");
3391
+ uiTrackedChangesCatalogState.inFlight = null;
3392
+ };
3393
+ const renewUiTrackedChangesCatalogRead = () => {
3394
+ uiTrackedChangesCatalogState.generation += 1;
3395
+ uiTrackedChangesCatalogState.abortController = new AbortController();
3396
+ uiTrackedChangesCatalogState.inFlight = null;
3397
+ };
3398
+ const beginUiReviewMutation = (token) => {
3399
+ const activeTokens = uiTrackedChangesCatalogState.activeMutationTokens;
3400
+ if (typeof token !== "string" || token.length === 0 || activeTokens.has(token)) return;
3401
+ const firstToken = activeTokens.size === 0;
3402
+ activeTokens.add(token);
3403
+ if (firstToken) supersedeUiTrackedChangesCatalogRead();
3404
+ };
3405
+ const settleUiReviewMutation = (token) => {
3406
+ const activeTokens = uiTrackedChangesCatalogState.activeMutationTokens;
3407
+ if (typeof token !== "string" || !activeTokens.delete(token)) return;
3408
+ if (activeTokens.size === 0) renewUiTrackedChangesCatalogRead();
3409
+ };
3410
+ const runUiTrackedChangesCatalogRead = (fallback) => {
3411
+ const v2TrackedChanges = getV2TrackedChanges();
3412
+ const listTrackedChanges = v2TrackedChanges?.listTrackedChanges;
3413
+ if (typeof listTrackedChanges !== "function") {
3414
+ if (getEditor()?.editorVersion === 2) return Promise.reject(/* @__PURE__ */ new Error("v2-tracked-changes-bridge-pending"));
3415
+ return fallback();
3416
+ }
3417
+ if (uiTrackedChangesCatalogState.activeMutationTokens.size > 0) return Promise.reject(/* @__PURE__ */ new Error("ui-review-catalog-superseded"));
3418
+ if ((getEditor()?.reviewHydration?.getDiagnostics?.())?.inFlight === true) return Promise.reject(/* @__PURE__ */ new Error("shell-review-hydration-in-flight"));
3419
+ const generation = uiTrackedChangesCatalogState.generation;
3420
+ const existing = uiTrackedChangesCatalogState.inFlight;
3421
+ if (existing?.generation === generation) return existing.promise;
3422
+ const signal = uiTrackedChangesCatalogState.abortController.signal;
3423
+ const validateResult = (result) => {
3424
+ if (signal.aborted || generation !== uiTrackedChangesCatalogState.generation || result?.reason === "review-hydration-superseded") throw new Error("ui-review-catalog-superseded");
3425
+ return result;
3426
+ };
3427
+ const rawResult = listTrackedChanges.call(v2TrackedChanges, {
3428
+ blocking: false,
3429
+ signal
3430
+ });
3431
+ if (!isPromiseLike(rawResult)) return validateResult(rawResult);
3432
+ const promise = Promise.resolve(rawResult).then(validateResult);
3433
+ uiTrackedChangesCatalogState.inFlight = {
3434
+ generation,
3435
+ promise
3436
+ };
3437
+ promise.then(() => {
3438
+ if (uiTrackedChangesCatalogState.inFlight?.promise === promise) uiTrackedChangesCatalogState.inFlight = null;
3439
+ }, () => {
3440
+ if (uiTrackedChangesCatalogState.inFlight?.promise === promise) uiTrackedChangesCatalogState.inFlight = null;
3441
+ });
3442
+ return promise;
3443
+ };
3169
3444
  let authoritativeTrackChangesPendingToken = null;
3170
3445
  let authoritativeTrackChangesRetryTimer = null;
3171
3446
  let authoritativeTrackChangesFailureCount = 0;
@@ -3177,6 +3452,7 @@ function createSuperDocUI(options) {
3177
3452
  let scheduleAuthoritativeTrackChangesRetry = (_reconcileToken) => void 0;
3178
3453
  let postDecisionTrackChangesToken = null;
3179
3454
  let postDecisionTrackChangeIds = /* @__PURE__ */ new Set();
3455
+ let allTrackedChangesResolvedToken = null;
3180
3456
  let selectionEpoch = 0;
3181
3457
  let lastCoordinatorEditor = null;
3182
3458
  const contentToken = () => `${editorIdentityId(getEditor())}|m${documentMutationRevision}`;
@@ -3255,6 +3531,23 @@ function createSuperDocUI(options) {
3255
3531
  };
3256
3532
  notifyPostDecisionTrackChanges(receipt);
3257
3533
  };
3534
+ const publishAllTrackedChangesResolved = (receipt) => {
3535
+ const previous = state.trackChanges;
3536
+ const changed = previous.items.length > 0 || previous.total !== 0 || previous.activeId !== null || previous.authors.length > 0;
3537
+ allTrackedChangesResolvedToken = contentToken();
3538
+ if (explicitActiveChange !== null) setExplicitActiveChange(null);
3539
+ state = {
3540
+ ...state,
3541
+ trackChanges: {
3542
+ ...previous,
3543
+ items: [],
3544
+ total: 0,
3545
+ activeId: null,
3546
+ authors: []
3547
+ }
3548
+ };
3549
+ if (changed) notifyPostDecisionTrackChanges(receipt);
3550
+ };
3258
3551
  const markPostDecisionTrackChanges = (ids, receipt) => {
3259
3552
  if (ids.size === 0) return;
3260
3553
  const token = contentToken();
@@ -3520,7 +3813,7 @@ function createSuperDocUI(options) {
3520
3813
  const read = host?.getDocumentLoadingSnapshot;
3521
3814
  if (typeof read !== "function") return "unknown";
3522
3815
  const stage = safeCall(() => read.call(host), null)?.sourceStage;
3523
- if (stage === "opening" || stage === "ready-window" || stage === "source-loading") return "loading";
3816
+ if (stage === "opening" || stage === "bootstrap-ready" || stage === "source-loading") return "loading";
3524
3817
  if (stage === "source-complete" || stage === "source-failed" || stage === "source-cancelled") return "complete";
3525
3818
  return "unknown";
3526
3819
  };
@@ -3933,6 +4226,7 @@ function createSuperDocUI(options) {
3933
4226
  detachSourceLoading = null;
3934
4227
  sourceLoadingSubscriptionHost = null;
3935
4228
  clearPostDecisionTrackChanges();
4229
+ allTrackedChangesResolvedToken = null;
3936
4230
  };
3937
4231
  const invalidateDocumentContent = () => {
3938
4232
  const carryAuthoritativeTrackChangesHold = authoritativeTrackChangesPendingToken !== null;
@@ -3940,6 +4234,15 @@ function createSuperDocUI(options) {
3940
4234
  if (carryAuthoritativeTrackChangesHold) authoritativeTrackChangesPendingToken = contentToken();
3941
4235
  clearPostDecisionTrackChanges();
3942
4236
  };
4237
+ const invalidateAfterCommandSettlement = () => {
4238
+ const carryAllResolvedCatalog = allTrackedChangesResolvedToken === contentToken();
4239
+ invalidateDocumentContent();
4240
+ if (carryAllResolvedCatalog) {
4241
+ replaceTrackedChangeItemsInCache([]);
4242
+ allTrackedChangesResolvedToken = contentToken();
4243
+ }
4244
+ recompute();
4245
+ };
3943
4246
  const insertText = (text) => {
3944
4247
  if (typeof text !== "string" || text.length === 0) return failedReceipt("insertText requires a non-empty string.", "INVALID_INPUT");
3945
4248
  if (readDocumentMode() === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
@@ -4143,7 +4446,17 @@ function createSuperDocUI(options) {
4143
4446
  const { value, status } = authoritativeTrackChangesPendingToken === token ? {
4144
4447
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4145
4448
  status: heldEntry?.hasSettled ? "stale" : "pending"
4146
- } : readAsync("trackChanges:all", token, () => tcApi?.list ? tcApi.list({ in: "all" }) : void 0, (raw) => {
4449
+ } : readAsync("trackChanges:all", token, () => {
4450
+ if (!tcApi?.list) return void 0;
4451
+ const fallback = () => tcApi.list({ in: "all" });
4452
+ const bridgeOwnsCatalog = typeof getV2TrackedChanges()?.listTrackedChanges === "function";
4453
+ const shared = runUiTrackedChangesCatalogRead(fallback);
4454
+ if (!bridgeOwnsCatalog) return shared;
4455
+ return Promise.resolve(shared).then((raw) => {
4456
+ const record = isLooseObject(raw) ? raw : null;
4457
+ return (Array.isArray(record?.items) ? record.items : []).some((item) => readEntityStory(item) == null) ? fallback() : raw;
4458
+ });
4459
+ }, (raw) => {
4147
4460
  return (raw && Array.isArray(raw.items) ? raw.items : []).map(projectTrackChangesItem).filter((item) => item != null);
4148
4461
  });
4149
4462
  return status === "ready" ? value : null;
@@ -4159,9 +4472,9 @@ function createSuperDocUI(options) {
4159
4472
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4160
4473
  status: heldEntry?.hasSettled ? "stale" : "pending"
4161
4474
  } : readAsync("trackChanges", token, () => {
4162
- if (listTrackedChanges) return listTrackedChanges.call(v2TrackedChanges);
4163
- return tcApi?.list ? tcApi.list() : void 0;
4164
- }, (raw) => raw && Array.isArray(raw.items) ? raw.items.filter((item) => !listTrackedChanges || storyLocatorSignature(readEntityStory(item)) === "story:body") : []);
4475
+ if (listTrackedChanges) return runUiTrackedChangesCatalogRead(() => tcApi?.list?.());
4476
+ return tcApi?.list ? tcApi.list({ in: "all" }) : void 0;
4477
+ }, (raw) => raw && Array.isArray(raw.items) ? raw.items : []);
4165
4478
  const items = (value ?? []).map(projectTrackChangesItem).filter((item) => item != null).filter((item) => {
4166
4479
  const id = readEntityId(item);
4167
4480
  return !id || !postDecisionIds?.has(id);
@@ -4180,8 +4493,20 @@ function createSuperDocUI(options) {
4180
4493
  if (allStoryItems && !allStoryItems.some((row) => entityRowMatchesRequest(row, active.id, active.story))) setExplicitActiveChange(null);
4181
4494
  } else if (!items.some((item) => readEntityId(item) === active.id)) setExplicitActiveChange(null);
4182
4495
  }
4183
- const selectionActiveChangeIds = postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
4184
- const activeId = explicitActiveChange?.id ?? selectionActiveChangeIds[0] ?? null;
4496
+ const publicIdItems = allStoryItems ?? items;
4497
+ const selectionIdContext = buildStoryScopedTrackedChangeIdContext(publicIdItems, selectionStory(selection$1));
4498
+ const selectionActiveChangeIds = allTrackedChangesResolvedToken === token ? [] : postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
4499
+ const selectionPublicChangeIds = selectionActiveChangeIds.map((id) => selectionIdContext.toPublicId(id) ?? id);
4500
+ const explicitActiveIdContext = explicitActiveChange?.story ? buildStoryScopedTrackedChangeIdContext(publicIdItems, explicitActiveChange.story) : buildTrackedChangeIdContext(publicIdItems);
4501
+ const explicitActiveId = explicitActiveChange ? explicitActiveIdContext.toPublicId(explicitActiveChange.id) ?? explicitActiveChange.id : null;
4502
+ const selectionActiveId = resolveSelectionActiveChangeId({
4503
+ selectionIds: selectionActiveChangeIds,
4504
+ publicIds: selectionPublicChangeIds,
4505
+ selection: selection$1,
4506
+ bodyItems: items,
4507
+ allStoryItems
4508
+ });
4509
+ const activeId = explicitActiveId ?? selectionActiveId;
4185
4510
  return {
4186
4511
  status: combineStatus(listStatus, selection$1.status),
4187
4512
  items,
@@ -5845,13 +6170,18 @@ function createSuperDocUI(options) {
5845
6170
  const target = rawTarget && typeof rawTarget === "object" ? rawTarget : null;
5846
6171
  let next = null;
5847
6172
  if (target?.entityType === "trackedChange" && typeof target.entityId === "string" && target.entityId.length > 0) {
5848
- const story = target.story && storyLocatorSignature(target.story) !== storyLocatorSignature(null) ? target.story : void 0;
6173
+ const paintedEntityId = target.entityId;
6174
+ const targetStory = target.story && typeof target.story === "object" ? target.story : void 0;
6175
+ const allStoryItems = readAllStoryTrackChanges();
6176
+ const entityId = (allStoryItems ? targetStory ? buildStoryScopedTrackedChangeIdContext(allStoryItems, targetStory).toPublicId(paintedEntityId) : buildTrackedChangeIdContext(allStoryItems).toPublicId(paintedEntityId) : null) ?? paintedEntityId;
6177
+ const story = targetStory && storyLocatorSignature(targetStory) !== storyLocatorSignature(null) ? targetStory : void 0;
5849
6178
  next = {
5850
- id: target.entityId,
6179
+ id: entityId,
5851
6180
  ...story ? { story } : {},
5852
- ...typeof target.paintedEntityId === "string" && target.paintedEntityId.length > 0 ? { paintedEntityId: target.paintedEntityId } : {}
6181
+ ...typeof target.paintedEntityId === "string" && target.paintedEntityId.length > 0 ? { paintedEntityId: target.paintedEntityId } : entityId !== paintedEntityId ? { paintedEntityId } : {}
5853
6182
  };
5854
6183
  }
6184
+ if (rawTarget == null && next == null && explicitActiveChange != null && hasPendingTrackChangeRevealFocus(explicitActiveChange)) return false;
5855
6185
  if (explicitActiveChangesEqual(explicitActiveChange, next)) return false;
5856
6186
  setExplicitActiveChange(next);
5857
6187
  return true;
@@ -5928,6 +6258,20 @@ function createSuperDocUI(options) {
5928
6258
  try {
5929
6259
  const off = next.subscribe((event) => {
5930
6260
  const type = event?.type;
6261
+ if (type === "review-mutation:started") {
6262
+ beginUiReviewMutation(event.reviewMutation?.token);
6263
+ return;
6264
+ }
6265
+ if (type === "review-mutation:aborted") {
6266
+ settleUiReviewMutation(event.reviewMutation?.token);
6267
+ scheduleAsyncRefresh();
6268
+ return;
6269
+ }
6270
+ if (type === "mutation:rejected" && event.reviewMutation) {
6271
+ settleUiReviewMutation(event.reviewMutation.token);
6272
+ scheduleAsyncRefresh();
6273
+ }
6274
+ if (type === "mutation:committed" && event.reviewMutation) settleUiReviewMutation(event.reviewMutation.token);
5931
6275
  if (type === "source:complete" || type === "source:signals-complete") {
5932
6276
  if (authoritativeTrackChangesPendingToken !== null) {
5933
6277
  clearAuthoritativeTrackChangesRetry();
@@ -5943,6 +6287,13 @@ function createSuperDocUI(options) {
5943
6287
  if (type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
5944
6288
  const impact = type === "mutation:committed" ? getV2TrackedChangeMutationImpact(event) : null;
5945
6289
  const supersedesPendingReviewReconcile = type === "mutation:committed" && reviewMutationReconciler.getPendingIds().size > 0;
6290
+ if (impact?.allResolved) {
6291
+ reviewMutationReconciler.reset();
6292
+ replaceTrackedChangeItemsInCache([]);
6293
+ authoritativeTrackChangesPendingToken = null;
6294
+ publishAllTrackedChangesResolved(event.receipt);
6295
+ return;
6296
+ }
5946
6297
  if (impact?.removedIds.size) markPostDecisionTrackChanges(new Set(impact.removedIds), event.receipt);
5947
6298
  const authoritativeHistoryImpact = impact?.reconcileMode === "authoritative" && impact.upsertIds.size > 0;
5948
6299
  if (authoritativeHistoryImpact) {
@@ -6089,6 +6440,17 @@ function createSuperDocUI(options) {
6089
6440
  function readTrackDecisionTargetId(target) {
6090
6441
  return target && typeof target === "object" && typeof target.id === "string" ? String(target.id) : null;
6091
6442
  }
6443
+ function nonBodySelectionStoryLocator(selection$1) {
6444
+ const story = selectionStoryLocator(selection$1);
6445
+ return story && storyLocatorSignature(story) !== storyLocatorSignature(null) ? story : void 0;
6446
+ }
6447
+ function trackDecisionIdTarget(changeId, story) {
6448
+ return {
6449
+ kind: "id",
6450
+ id: changeId,
6451
+ ...story ? { story } : {}
6452
+ };
6453
+ }
6092
6454
  function trackDecisionRangeFromSelection(selection$1) {
6093
6455
  if (selection$1.empty) return null;
6094
6456
  const explicit = selection$1.selectionTarget;
@@ -6114,22 +6476,58 @@ function createSuperDocUI(options) {
6114
6476
  }
6115
6477
  };
6116
6478
  }
6479
+ function readBodyTrackChangeForDecision(activeId, story) {
6480
+ if (storyLocatorSignature(story) !== storyLocatorSignature(null)) return void 0;
6481
+ const trackChanges$1 = getDoc()?.trackChanges;
6482
+ const list = trackChanges$1?.list;
6483
+ if (typeof list !== "function") return void 0;
6484
+ const raw = safeCall(() => list.call(trackChanges$1), null);
6485
+ if (isPromiseLike(raw) || !raw || typeof raw !== "object") return void 0;
6486
+ const items = raw.items;
6487
+ if (!Array.isArray(items)) return void 0;
6488
+ return items.map(projectTrackChangesItem).find((item) => item != null && entityRowMatchesRequest(item, activeId, story));
6489
+ }
6490
+ function selectedTextCoversTrackChangeText(selection$1, item) {
6491
+ const selected = normalizeTrackDecisionText(selection$1.quotedText);
6492
+ if (!selected) return false;
6493
+ const payload = trackChangesItemPayload(item);
6494
+ return [
6495
+ payload.insertedText,
6496
+ payload.deletedText,
6497
+ payload.excerpt
6498
+ ].some((value) => normalizeTrackDecisionText(value) === selected);
6499
+ }
6500
+ function normalizeTrackDecisionText(value) {
6501
+ return typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
6502
+ }
6117
6503
  function activeChangePartialDecisionRoute() {
6118
6504
  const activeId = state.selection.activeChangeIds[0];
6119
6505
  if (!activeId) return "unavailable";
6120
- const items = readAllStoryTrackChanges();
6121
- if (!items) return "unavailable";
6122
6506
  const story = selectionStoryLocator(state.selection);
6123
- const item = items.find((candidate) => entityRowMatchesRequest(candidate, activeId, story));
6507
+ const item = (state.trackChanges.status === "ready" ? state.trackChanges.items.find((candidate) => entityRowMatchesRequest(candidate, activeId, story)) : void 0) ?? readBodyTrackChangeForDecision(activeId, story) ?? readAllStoryTrackChanges()?.find((candidate) => entityRowMatchesRequest(candidate, activeId, story));
6124
6508
  if (!item) return "unavailable";
6125
- const type = trackChangesItemPayload(item).type;
6126
- const grouping = trackChangesItemPayload(item).grouping;
6509
+ const change = trackChangesItemPayload(item);
6510
+ const type = change.type;
6511
+ const grouping = change.grouping;
6512
+ if (selectedTextCoversTrackChangeText(state.selection, item)) return "id";
6127
6513
  if (type === "replacement" && grouping === "replacement-pair") return "range";
6128
6514
  return (type === "insertion" || type === "deletion" || type === "insert" || type === "delete") && grouping === "standalone" ? "range" : "id";
6129
6515
  }
6516
+ function executeTrackDecisionRangeWithIdFallback(kind, rangeTarget, changeId, story) {
6517
+ const fallback = () => callTrackDecisionTarget(kind, trackDecisionIdTarget(changeId, story), changeId, story);
6518
+ try {
6519
+ const result = callTrackDecisionTarget(kind, rangeTarget, null);
6520
+ if (isPromiseLike(result)) return settleCommandExecution(Promise.resolve(result).then((settled) => {
6521
+ return commandResultSucceeded(commandResultFromOperationResult(settled)) ? settled : fallback();
6522
+ }));
6523
+ return settleCommandExecution(commandResultSucceeded(commandResultFromOperationResult(result)) ? result : fallback());
6524
+ } catch {
6525
+ return false;
6526
+ }
6527
+ }
6130
6528
  function resolveTrackDecisionTarget(command, payload) {
6131
6529
  if (command.scope === "all") return {
6132
- target: { scope: "all" },
6530
+ target: { kind: "all" },
6133
6531
  changeId: null
6134
6532
  };
6135
6533
  if (typeof payload === "string" && payload.length > 0) return {
@@ -6141,26 +6539,27 @@ function createSuperDocUI(options) {
6141
6539
  };
6142
6540
  if (payload && typeof payload === "object") {
6143
6541
  const record = payload;
6144
- if (record.target && typeof record.target === "object") return {
6145
- target: record.target,
6146
- changeId: readTrackDecisionTargetId(record.target)
6147
- };
6542
+ if (record.target && typeof record.target === "object") {
6543
+ const target = record.target;
6544
+ return {
6545
+ target,
6546
+ changeId: readTrackDecisionTargetId(target),
6547
+ story: target.story
6548
+ };
6549
+ }
6148
6550
  const id = typeof record.changeId === "string" ? record.changeId : record.id;
6149
6551
  if (typeof id === "string" && id.length > 0) return {
6150
- target: {
6151
- kind: "id",
6152
- id
6153
- },
6154
- changeId: id
6552
+ target: trackDecisionIdTarget(id, record.story),
6553
+ changeId: id,
6554
+ story: record.story
6155
6555
  };
6156
6556
  }
6157
6557
  const selectedId = state.selection.activeChangeIds[0];
6558
+ const story = nonBodySelectionStoryLocator(state.selection);
6158
6559
  return selectedId ? {
6159
- target: {
6160
- kind: "id",
6161
- id: selectedId
6162
- },
6163
- changeId: selectedId
6560
+ target: trackDecisionIdTarget(selectedId, story),
6561
+ changeId: selectedId,
6562
+ story
6164
6563
  } : null;
6165
6564
  }
6166
6565
  function executeTrackDecisionCommand(command, payload) {
@@ -6174,13 +6573,23 @@ function createSuperDocUI(options) {
6174
6573
  if (route === "unavailable") return false;
6175
6574
  if (route === "range") {
6176
6575
  const target = trackDecisionRangeFromSelection(state.selection);
6177
- return target ? executeTrackDecisionTarget(command.kind, target, null) : false;
6576
+ const story = nonBodySelectionStoryLocator(state.selection);
6577
+ return target ? executeTrackDecisionRangeWithIdFallback(command.kind, target, state.selection.activeChangeIds[0], story) : false;
6578
+ }
6579
+ if (route === "id") {
6580
+ const activeId = state.selection.activeChangeIds[0];
6581
+ const selectedStory = selectionStoryLocator(state.selection);
6582
+ const story = selectedStory && storyLocatorSignature(selectedStory) !== storyLocatorSignature(null) ? selectedStory : void 0;
6583
+ return executeTrackDecision(command.kind, story ? {
6584
+ id: activeId,
6585
+ story
6586
+ } : activeId);
6178
6587
  }
6179
6588
  }
6180
6589
  }
6181
6590
  const resolved = resolveTrackDecisionTarget(command, payload);
6182
6591
  if (!resolved) return false;
6183
- return executeTrackDecisionTarget(command.kind, resolved.target, resolved.changeId);
6592
+ return executeTrackDecisionTarget(command.kind, resolved.target, resolved.changeId, resolved.story);
6184
6593
  }
6185
6594
  function executeListToggleCommand(kind, payload) {
6186
6595
  const lists = getEditCommands()?.lists;
@@ -6364,13 +6773,11 @@ function createSuperDocUI(options) {
6364
6773
  };
6365
6774
  const finalizeCommandSettlement = (promise, onSettled) => promise.then((settled) => {
6366
6775
  onSettled?.(settled);
6367
- invalidateDocumentContent();
6368
- recompute();
6776
+ invalidateAfterCommandSettlement();
6369
6777
  return settled;
6370
6778
  }, () => {
6371
6779
  onSettled?.(false);
6372
- invalidateDocumentContent();
6373
- recompute();
6780
+ invalidateAfterCommandSettlement();
6374
6781
  return false;
6375
6782
  });
6376
6783
  const settleCommandExecution = (result, onSettled) => {
@@ -6393,8 +6800,7 @@ function createSuperDocUI(options) {
6393
6800
  }
6394
6801
  onSettled?.(settled);
6395
6802
  lastCommandSettlement = Promise.resolve(settled);
6396
- invalidateDocumentContent();
6397
- recompute();
6803
+ invalidateAfterCommandSettlement();
6398
6804
  return settled;
6399
6805
  };
6400
6806
  const normalizeWorkflowReceipt = (value, fallback) => {
@@ -7556,6 +7962,14 @@ function createSuperDocUI(options) {
7556
7962
  if (typeof helper?.apply !== "function") return { reason: SUPERDOC_UI_REASONS.hostCapabilityUnavailable };
7557
7963
  return { helper };
7558
7964
  };
7965
+ const activateContentControlChrome = (id) => {
7966
+ const host = getHost();
7967
+ if (typeof host?.getHandles !== "function") return;
7968
+ try {
7969
+ const contentControls$1 = (host.getHandles()?.editing)?.contentControls;
7970
+ if (typeof contentControls$1?.activate === "function") contentControls$1.activate({ id });
7971
+ } catch {}
7972
+ };
7559
7973
  const selection = {
7560
7974
  get: selectionSnap.get,
7561
7975
  getSnapshot: selectionSnap.getSnapshot,
@@ -7700,11 +8114,12 @@ function createSuperDocUI(options) {
7700
8114
  reason: SUPERDOC_UI_REASONS.hostCapabilityUnavailable
7701
8115
  };
7702
8116
  try {
7703
- const result = await Promise.resolve(scroll.call(host, {
8117
+ const input = {
7704
8118
  target,
7705
8119
  block: options$1?.block ?? "center",
7706
8120
  behavior: options$1?.behavior ?? "smooth"
7707
- }));
8121
+ };
8122
+ const result = await Promise.resolve(options$1?.shouldContinue ? scroll.call(host, input, options$1.shouldContinue) : scroll.call(host, input));
7708
8123
  if (result && typeof result === "object" && result.success === false) return {
7709
8124
  success: false,
7710
8125
  ok: false,
@@ -7734,19 +8149,32 @@ function createSuperDocUI(options) {
7734
8149
  story: requestedStory
7735
8150
  };
7736
8151
  };
7737
- const fromList = readEntityTarget(loaded.find((row) => entityRowMatchesRequest(row, id, requestedStory)));
7738
- if (fromList) return withRequestedStory(fromList);
8152
+ const readTarget = namespace === "trackChanges" ? readTrackedChangeNavigationTarget : readEntityTarget;
8153
+ const loadedRow = loaded.find((row) => entityRowMatchesRequest(row, id, requestedStory));
8154
+ const loadedRecord = loadedRow && typeof loadedRow === "object" ? loadedRow : null;
8155
+ const moveSide = namespace === "trackChanges" && loadedRecord?.type === "move" && (loadedRecord.subtype === "move-to" || loadedRecord.subtype === "move-from") ? loadedRecord.subtype : null;
8156
+ const trackedChangeLookupId = moveSide && typeof loadedRecord?.trackedChangeCanonicalId === "string" ? loadedRecord.trackedChangeCanonicalId : id;
8157
+ const readResolvedTarget = (row) => {
8158
+ if (!moveSide) return readTarget(row);
8159
+ const moveTarget = readEntityTarget(row);
8160
+ if (moveTarget?.kind !== "move") return null;
8161
+ const sideTarget = moveSide === "move-to" ? moveTarget.destination : moveTarget.source;
8162
+ return isHostGeometryTarget(sideTarget) ? sideTarget : null;
8163
+ };
8164
+ const fromList = readTarget(loadedRow);
8165
+ const listTargetIsAuthoritative = namespace !== "trackChanges" || !moveSide && isHostGeometryTarget(readEntityTarget(loadedRow));
8166
+ if (fromList && listTargetIsAuthoritative) return withRequestedStory(fromList);
7739
8167
  const api = getDoc()?.[namespace];
7740
8168
  const input = namespace === "comments" ? { commentId: id } : {
7741
- id,
8169
+ id: trackedChangeLookupId,
7742
8170
  ...requestedStory ? { story: requestedStory } : {}
7743
8171
  };
7744
8172
  const get = api?.get;
7745
- if (typeof get !== "function") return null;
8173
+ if (typeof get !== "function") return withRequestedStory(fromList);
7746
8174
  try {
7747
- return withRequestedStory(readEntityTarget(await Promise.resolve(get.call(api, input))));
8175
+ return withRequestedStory(readResolvedTarget(await Promise.resolve(get.call(api, input))) ?? fromList);
7748
8176
  } catch {
7749
- return null;
8177
+ return withRequestedStory(fromList);
7750
8178
  }
7751
8179
  };
7752
8180
  function patchCommentStatus(commentId, status) {
@@ -7801,10 +8229,14 @@ function createSuperDocUI(options) {
7801
8229
  const op = commentsApi?.create;
7802
8230
  if (typeof op !== "function") return failedReceipt("comments.create is unavailable.");
7803
8231
  const fallback = failedReceipt("comments.create failed.");
7804
- return safeCall(() => settleWorkflowReceipt(op.call(commentsApi, {
7805
- target: capture.target ?? capture.selectionTarget,
7806
- text: input.text
7807
- }), fallback), fallback);
8232
+ return safeCall(() => {
8233
+ const target = capture && typeof capture === "object" ? capture.target ?? capture.selectionTarget : null;
8234
+ if (target == null) return failedReceipt("A range selection is required to comment.", "NO_SELECTION");
8235
+ return settleWorkflowReceipt(op.call(commentsApi, {
8236
+ target,
8237
+ text: input.text
8238
+ }), fallback);
8239
+ }, fallback);
7808
8240
  },
7809
8241
  createFromSelection: (input) => {
7810
8242
  const refusal = commentWriteRefusal();
@@ -7836,6 +8268,18 @@ function createSuperDocUI(options) {
7836
8268
  text: input.text
7837
8269
  }), fallback), fallback);
7838
8270
  },
8271
+ edit: (commentId, input) => {
8272
+ const refusal = commentWriteRefusal();
8273
+ if (refusal) return refusal;
8274
+ const commentsApi = getDoc()?.comments;
8275
+ const op = commentsApi?.patch;
8276
+ if (typeof op !== "function") return failedReceipt("comments.patch is unavailable.");
8277
+ const fallback = failedReceipt("comments.patch failed.");
8278
+ return safeCall(() => settleWorkflowReceipt(op.call(commentsApi, {
8279
+ commentId,
8280
+ text: input.text
8281
+ }), fallback), fallback);
8282
+ },
7839
8283
  resolve: (commentId) => patchCommentStatus(commentId, "resolved"),
7840
8284
  reopen: (commentId) => patchCommentStatus(commentId, "active"),
7841
8285
  delete: (commentId) => {
@@ -7880,10 +8324,12 @@ function createSuperDocUI(options) {
7880
8324
  };
7881
8325
  const trackChangesSub = sliceHandle((s) => s.trackChanges);
7882
8326
  const navigateTrackChange = (step, options$1) => {
7883
- const rows = trackChangesSub.get().items.filter((item) => readEntityId(item) !== null);
7884
- if (rows.length === 0) return null;
8327
+ const allRows = trackChangesSub.get().items.filter((item) => readEntityId(item) !== null);
8328
+ if (allRows.length === 0) return null;
7885
8329
  const currentId = state.trackChanges.activeId;
7886
8330
  const currentStory = explicitActiveChange?.id === currentId ? explicitActiveChange.story : void 0;
8331
+ const bodyRows = allRows.filter((row) => readEntityRequestStory(row) == null);
8332
+ const rows = currentStory || bodyRows.length === 0 ? allRows : bodyRows;
7887
8333
  let currentIdx = currentId ? rows.findIndex((row) => entityRowMatchesRequest(row, currentId, currentStory)) : -1;
7888
8334
  if (currentIdx === -1 && currentId && currentStory) currentIdx = rows.findIndex((row) => entityRowMatchesRequest(row, currentId));
7889
8335
  const nextRow = rows[currentIdx === -1 ? step > 0 ? 0 : rows.length - 1 : (currentIdx + step + rows.length) % rows.length];
@@ -7908,33 +8354,41 @@ function createSuperDocUI(options) {
7908
8354
  if (activeId == null) return { success: false };
7909
8355
  const optimisticActiveChange = explicitActiveChange;
7910
8356
  const optimisticRevision = explicitActiveChangeRevision;
7911
- const isCurrent = () => explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
8357
+ const isCurrent = () => queuedTrackChangeNavigationInvalidation === requestedAtInvalidation && explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
7912
8358
  const rollback = () => {
7913
8359
  if (!isCurrent()) return;
7914
8360
  setExplicitActiveChange(previousActiveChange, { invalidateQueuedNavigation: false });
7915
8361
  recompute();
7916
8362
  };
7917
- const target = await resolveEntityTarget("trackChanges", activeId, trackChangesSub.get().items, optimisticActiveChange?.story ? { story: optimisticActiveChange.story } : void 0);
7918
- if (!isCurrent()) return { success: false };
7919
- if (!target) {
7920
- rollback();
7921
- return { success: false };
7922
- }
7923
- trackedChangeNavigationInFlight += 1;
8363
+ if (optimisticActiveChange) pendingTrackChangeRevealFocuses.add(optimisticActiveChange);
7924
8364
  try {
7925
- const result = await scrollTargetIntoView(target, { behavior: "auto" });
8365
+ const target = await resolveEntityTarget("trackChanges", activeId, trackChangesSub.get().items, optimisticActiveChange?.story ? { story: optimisticActiveChange.story } : void 0);
7926
8366
  if (!isCurrent()) return { success: false };
7927
- if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) {
8367
+ if (!target) {
7928
8368
  rollback();
7929
- mirrorTrackedChangeFocusToHost(previousActiveChange);
7930
- } else mirrorTrackedChangeFocusToHost(optimisticActiveChange);
7931
- return { success: result.ok };
7932
- } finally {
7933
- trackedChangeNavigationInFlight = Math.max(0, trackedChangeNavigationInFlight - 1);
7934
- if (trackedChangeNavigationInFlight === 0) {
7935
- if (!isCurrent()) mirrorTrackedChangeFocusToHost(explicitActiveChange);
7936
- else if (currentHostReviewSource) syncTrackedChangeFocusFromHostReviewTarget(readHostActiveReviewTarget(currentHostReviewSource));
8369
+ return { success: false };
8370
+ }
8371
+ trackedChangeNavigationInFlight += 1;
8372
+ try {
8373
+ const result = await scrollTargetIntoView(target, {
8374
+ behavior: "auto",
8375
+ shouldContinue: isCurrent
8376
+ });
8377
+ if (!isCurrent()) return { success: false };
8378
+ if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) {
8379
+ rollback();
8380
+ mirrorTrackedChangeFocusToHost(previousActiveChange);
8381
+ } else mirrorTrackedChangeFocusToHost(optimisticActiveChange);
8382
+ return { success: result.ok };
8383
+ } finally {
8384
+ trackedChangeNavigationInFlight = Math.max(0, trackedChangeNavigationInFlight - 1);
8385
+ if (trackedChangeNavigationInFlight === 0) {
8386
+ if (!isCurrent()) mirrorTrackedChangeFocusToHost(explicitActiveChange);
8387
+ else if (currentHostReviewSource) syncTrackedChangeFocusFromHostReviewTarget(readHostActiveReviewTarget(currentHostReviewSource));
8388
+ }
7937
8389
  }
8390
+ } finally {
8391
+ if (optimisticActiveChange) pendingTrackChangeRevealFocuses.delete(optimisticActiveChange);
7938
8392
  }
7939
8393
  };
7940
8394
  const navigateAndScroll = (step) => {
@@ -7966,8 +8420,8 @@ function createSuperDocUI(options) {
7966
8420
  },
7967
8421
  accept: (changeId) => executeTrackDecision("accept", changeId),
7968
8422
  reject: (changeId) => executeTrackDecision("reject", changeId),
7969
- acceptAll: () => executeTrackDecisionTarget("accept", { scope: "all" }, null),
7970
- rejectAll: () => executeTrackDecisionTarget("reject", { scope: "all" }, null),
8423
+ acceptAll: () => executeTrackDecisionTarget("accept", { kind: "all" }, null),
8424
+ rejectAll: () => executeTrackDecisionTarget("reject", { kind: "all" }, null),
7971
8425
  next: () => navigateTrackChange(1),
7972
8426
  previous: () => navigateTrackChange(-1),
7973
8427
  navigateNext: () => navigateAndScroll(1),
@@ -7976,7 +8430,7 @@ function createSuperDocUI(options) {
7976
8430
  if (!input || typeof input !== "object" || typeof input.x !== "number" || typeof input.y !== "number") return null;
7977
8431
  const hits = entityAt(input);
7978
8432
  if (hits.length === 0) return null;
7979
- const bodyItems = trackChangesSub.get().items;
8433
+ const items = trackChangesSub.get().items;
7980
8434
  let allStoryItems;
7981
8435
  for (const hit of hits) {
7982
8436
  if (hit.type !== "trackedChange") continue;
@@ -7985,7 +8439,7 @@ function createSuperDocUI(options) {
7985
8439
  if (allStoryItems === void 0) allStoryItems = readAllStoryTrackChanges();
7986
8440
  if (!allStoryItems) continue;
7987
8441
  candidates = allStoryItems;
7988
- } else candidates = bodyItems;
8442
+ } else candidates = items;
7989
8443
  const item = candidates.find((candidate) => entityRowMatchesRequest(candidate, hit.id, hit.story));
7990
8444
  if (item) return hit.story ? {
7991
8445
  id: item.id,
@@ -8019,10 +8473,12 @@ function createSuperDocUI(options) {
8019
8473
  if (!allStoryItems.some((row) => entityRowMatchesRequest(row, publicId, requested.story))) return false;
8020
8474
  requested.id = publicId;
8021
8475
  } else {
8022
- const bodyItems = trackChangesSub.get().items;
8023
- const publicId = buildTrackedChangeIdContext(bodyItems).toPublicId(requested.id) ?? requested.id;
8024
- if (!bodyItems.some((item) => readEntityId(item) === publicId)) return false;
8476
+ const items = trackChangesSub.get().items;
8477
+ const publicId = buildTrackedChangeIdContext(items).toPublicId(requested.id) ?? requested.id;
8478
+ const item = items.find((candidate) => readEntityId(candidate) === publicId);
8479
+ if (!item) return false;
8025
8480
  requested.id = publicId;
8481
+ requested.story = readEntityRequestStory(item);
8026
8482
  }
8027
8483
  if (paintedEntityId !== requested.id) requested.paintedEntityId = paintedEntityId;
8028
8484
  setExplicitActiveChange(requested);
@@ -8036,47 +8492,65 @@ function createSuperDocUI(options) {
8036
8492
  ok: false,
8037
8493
  reason: getEditor() ? SUPERDOC_UI_REASONS.documentApiUnavailable : SUPERDOC_UI_REASONS.notReady
8038
8494
  };
8495
+ queuedTrackChangeNavigationInvalidation += 1;
8496
+ trackChangeRevealInvalidation += 1;
8497
+ const requestedAtInvalidation = trackChangeRevealInvalidation;
8039
8498
  const loadedItems = trackChangesSub.get().items;
8040
- const story = readEntityRequestStory(loadedItems.find((item) => readEntityId(item) === changeId));
8041
- const target = await resolveEntityTarget("trackChanges", changeId, loadedItems, story ? { story } : void 0);
8042
- if (!target) return {
8043
- success: false,
8044
- ok: false,
8045
- reason: SUPERDOC_UI_REASONS.targetUnresolved
8046
- };
8499
+ const publicId = buildTrackedChangeIdContext(loadedItems).toPublicId(changeId) ?? changeId;
8500
+ const story = readEntityRequestStory(loadedItems.find((item) => readEntityId(item) === publicId));
8047
8501
  const previousActiveChange = explicitActiveChange;
8048
- const requestedActiveChange = story ? {
8049
- id: changeId,
8050
- story
8051
- } : { id: changeId };
8052
- setExplicitActiveChange(requestedActiveChange);
8053
- recompute();
8054
- const optimisticActiveChange = explicitActiveChange;
8055
- const optimisticRevision = explicitActiveChangeRevision;
8056
- const isCurrent = () => explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
8057
- const rollback = () => {
8058
- if (!isCurrent()) return;
8059
- setExplicitActiveChange(previousActiveChange, { invalidateQueuedNavigation: false });
8060
- recompute();
8502
+ const requestedActiveChange = {
8503
+ id: publicId,
8504
+ ...story ? { story } : {},
8505
+ ...publicId !== changeId ? { paintedEntityId: changeId } : {}
8061
8506
  };
8062
- trackedChangeNavigationInFlight += 1;
8507
+ pendingTrackChangeRevealFocuses.add(requestedActiveChange);
8063
8508
  try {
8064
- const result = await scrollTargetIntoView(target, { behavior: "auto" });
8065
- if (!isCurrent()) return {
8509
+ const target = await resolveEntityTarget("trackChanges", publicId, loadedItems, story ? { story } : void 0);
8510
+ if (trackChangeRevealInvalidation !== requestedAtInvalidation) return {
8066
8511
  success: false,
8067
8512
  ok: false
8068
8513
  };
8069
- if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) {
8070
- rollback();
8071
- mirrorTrackedChangeFocusToHost(previousActiveChange);
8072
- } else mirrorTrackedChangeFocusToHost(requestedActiveChange);
8073
- return result;
8074
- } finally {
8075
- trackedChangeNavigationInFlight = Math.max(0, trackedChangeNavigationInFlight - 1);
8076
- if (trackedChangeNavigationInFlight === 0) {
8077
- if (!isCurrent()) mirrorTrackedChangeFocusToHost(explicitActiveChange);
8078
- else if (currentHostReviewSource) syncTrackedChangeFocusFromHostReviewTarget(readHostActiveReviewTarget(currentHostReviewSource));
8514
+ if (!target) return {
8515
+ success: false,
8516
+ ok: false,
8517
+ reason: SUPERDOC_UI_REASONS.targetUnresolved
8518
+ };
8519
+ setExplicitActiveChange(requestedActiveChange);
8520
+ const revealInvalidation = trackChangeRevealInvalidation;
8521
+ const optimisticActiveChange = explicitActiveChange;
8522
+ const optimisticRevision = explicitActiveChangeRevision;
8523
+ const isCurrent = () => trackChangeRevealInvalidation === revealInvalidation && explicitActiveChange === optimisticActiveChange && explicitActiveChangeRevision === optimisticRevision;
8524
+ const rollback = () => {
8525
+ if (!isCurrent()) return;
8526
+ setExplicitActiveChange(previousActiveChange, { invalidateQueuedNavigation: false });
8527
+ recompute();
8528
+ };
8529
+ recompute();
8530
+ trackedChangeNavigationInFlight += 1;
8531
+ try {
8532
+ const result = await scrollTargetIntoView(target, {
8533
+ behavior: "auto",
8534
+ shouldContinue: isCurrent
8535
+ });
8536
+ if (!isCurrent()) return {
8537
+ success: false,
8538
+ ok: false
8539
+ };
8540
+ if (!result.ok && result.reason !== SUPERDOC_UI_REASONS.targetNotVisible) {
8541
+ rollback();
8542
+ mirrorTrackedChangeFocusToHost(previousActiveChange);
8543
+ } else mirrorTrackedChangeFocusToHost(requestedActiveChange);
8544
+ return result;
8545
+ } finally {
8546
+ trackedChangeNavigationInFlight = Math.max(0, trackedChangeNavigationInFlight - 1);
8547
+ if (trackedChangeNavigationInFlight === 0) {
8548
+ if (!isCurrent()) mirrorTrackedChangeFocusToHost(explicitActiveChange);
8549
+ else if (currentHostReviewSource) syncTrackedChangeFocusFromHostReviewTarget(readHostActiveReviewTarget(currentHostReviewSource));
8550
+ }
8079
8551
  }
8552
+ } finally {
8553
+ pendingTrackChangeRevealFocuses.delete(requestedActiveChange);
8080
8554
  }
8081
8555
  }
8082
8556
  };
@@ -8101,7 +8575,7 @@ function createSuperDocUI(options) {
8101
8575
  const callTrackDecisionTarget = (kind, target, changeId, story) => {
8102
8576
  if (reviewMutationsAreReadOnly()) return false;
8103
8577
  const tcApi = getDoc()?.trackChanges;
8104
- const isAllTarget = target.scope === "all";
8578
+ const isAllTarget = target.kind === "all" || target.scope === "all";
8105
8579
  const isRangeTarget = target.kind === "range";
8106
8580
  const isMultiIdTarget = target.kind === "ids";
8107
8581
  if (bulkTrackDecisionBlockedReason({
@@ -8204,6 +8678,7 @@ function createSuperDocUI(options) {
8204
8678
  success: false,
8205
8679
  reason: "not-reachable"
8206
8680
  };
8681
+ activateContentControlChrome(id);
8207
8682
  return { success: true };
8208
8683
  }
8209
8684
  };
@@ -8331,8 +8806,8 @@ function createSuperDocUI(options) {
8331
8806
  const rawHits = collectEntityHitsFromChain(startEls[0], container);
8332
8807
  for (let i = 1; i < startEls.length; i += 1) for (const hit of collectEntityHitsFromChain(startEls[i], container)) rawHits.push(hit);
8333
8808
  if (rawHits.length === 0) return rawHits;
8334
- const bodyItems = trackChangesSub.get().items;
8335
- const bodyIdContext = buildTrackedChangeIdContext(bodyItems);
8809
+ const items = trackChangesSub.get().items;
8810
+ const idContext = buildTrackedChangeIdContext(items);
8336
8811
  let allStoryItems;
8337
8812
  const seen = /* @__PURE__ */ new Set();
8338
8813
  const hits = [];
@@ -8352,7 +8827,7 @@ function createSuperDocUI(options) {
8352
8827
  publicId = buildStoryScopedTrackedChangeIdContext(allStoryItems, story).toPublicId(hit.id);
8353
8828
  if (!publicId || !allStoryItems.some((item) => entityRowMatchesRequest(item, publicId, story))) continue;
8354
8829
  } else {
8355
- publicId = bodyIdContext.toPublicId(hit.id);
8830
+ publicId = idContext.toPublicId(hit.id);
8356
8831
  if (!publicId) continue;
8357
8832
  }
8358
8833
  const key = `trackedChange:${publicId}`;
@@ -9151,6 +9626,7 @@ function createSuperDocUI(options) {
9151
9626
  const destroy = () => {
9152
9627
  if (disposed) return;
9153
9628
  disposed = true;
9629
+ releaseSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost, uiTrackedChangesCatalogState);
9154
9630
  reviewMutationReconciler.reset();
9155
9631
  clearAuthoritativeTrackChangesRetry();
9156
9632
  if (foregroundAsyncRetryTimer) {
@@ -9413,6 +9889,12 @@ Object.defineProperty(exports, "BUILT_IN_COMMAND_IDS", {
9413
9889
  return BUILT_IN_COMMAND_IDS;
9414
9890
  }
9415
9891
  });
9892
+ Object.defineProperty(exports, "DOM_CLASS_NAMES", {
9893
+ enumerable: true,
9894
+ get: function() {
9895
+ return DOM_CLASS_NAMES;
9896
+ }
9897
+ });
9416
9898
  Object.defineProperty(exports, "composeAuthorColorResolver", {
9417
9899
  enumerable: true,
9418
9900
  get: function() {