superdoc 2.4.0-next.1 → 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 (36) hide show
  1. package/dist/chunks/{FindReplaceSurface-Dx0llWqP.cjs → FindReplaceSurface-9VkPw_-X.cjs} +2 -3
  2. package/dist/chunks/{FindReplaceSurface-BEW-1NhM.es.js → FindReplaceSurface-BuvaIrQ5.es.js} +2 -3
  3. package/dist/chunks/{PasswordPromptSurface-BUUVC2ee.cjs → PasswordPromptSurface-Bu5xHm91.cjs} +1 -1
  4. package/dist/chunks/{PasswordPromptSurface-BA6HHqEa.es.js → PasswordPromptSurface-Bz9_sKhX.es.js} +1 -1
  5. package/dist/chunks/{PdfViewer-CNOtyS-I.es.js → PdfViewer-CdVGB6Fe.es.js} +2 -2
  6. package/dist/chunks/{PdfViewer-qpvzwYMz.cjs → PdfViewer-D4eD2dV1.cjs} +2 -2
  7. package/dist/chunks/{create-super-doc-ui-DXdWuTzm.cjs → create-super-doc-ui-ByvmsAAG.cjs} +343 -90
  8. package/dist/chunks/{create-super-doc-ui-D4kk9AjM.es.js → create-super-doc-ui-DBXOhHdW.es.js} +338 -91
  9. package/dist/collaboration-upgrade-engine.cjs +1 -1
  10. package/dist/collaboration-upgrade-engine.es.js +1 -1
  11. package/dist/document-api/src/types/track-changes.types.d.ts +1 -3
  12. package/dist/public/ui-react.cjs +1 -1
  13. package/dist/public/ui-react.es.js +1 -1
  14. package/dist/public/ui.cjs +1 -1
  15. package/dist/public/ui.es.js +1 -1
  16. package/dist/style.css +128 -128
  17. package/dist/style.layered.css +128 -128
  18. package/dist/superdoc/src/core/types/index.d.ts +125 -5
  19. package/dist/superdoc/src/helpers/v2-review-mutation-impact.d.ts +1 -0
  20. package/dist/superdoc/src/helpers/v2-review-mutation-reconciler.d.ts +1 -1
  21. package/dist/superdoc/src/internal/toolbar/compatibility-catalog.d.ts +1 -1
  22. package/dist/superdoc/src/public/index.d.cts +8 -0
  23. package/dist/superdoc/src/public/index.d.ts +4 -0
  24. package/dist/superdoc/src/public/ui/types.d.ts +25 -1
  25. package/dist/superdoc/src/stores/comments-store.d.ts +100 -22
  26. package/dist/superdoc/src/stores/superdoc-store.d.ts +300 -66
  27. package/dist/superdoc.cjs +594 -75
  28. package/dist/superdoc.es.js +594 -75
  29. package/dist-cdn/style.layered.css +1 -1
  30. package/dist-cdn/superdoc.min.css +1 -1
  31. package/dist-cdn/superdoc.min.js +37 -37
  32. package/package.json +2 -2
  33. /package/dist/chunks/{_plugin-vue_export-helper-BTwbGDKw.cjs → _plugin-vue_export-helper-CZ1Nl59K.cjs} +0 -0
  34. /package/dist/chunks/{_plugin-vue_export-helper-CInC0bKI.es.js → _plugin-vue_export-helper-DSMAhhwD.es.js} +0 -0
  35. /package/dist/chunks/{constants-CY3R3_kF.es.js → constants-BfH0br5u.es.js} +0 -0
  36. /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;
@@ -334,14 +395,21 @@ function getV2TrackedChangeMutationImpact(event) {
334
395
  });
335
396
  }
336
397
  for (const id of removedIds) upsertIds.delete(id);
337
- 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;
338
400
  return {
339
401
  upsertIds,
340
402
  removedIds,
341
403
  remappedPairs,
342
- reconcileMode: event.origin === "history" ? "authoritative" : "targeted"
404
+ reconcileMode: event.origin === "history" ? "authoritative" : "targeted",
405
+ ...allResolved ? { allResolved } : {}
343
406
  };
344
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
+ }
345
413
  var normalizeIds = (values) => new Set(Array.from(values ?? []).filter((value) => typeof value === "string" && value.length > 0));
346
414
  var itemId = (item) => {
347
415
  if (typeof item?.id === "string" && item.id.length > 0) return item.id;
@@ -352,10 +420,20 @@ var itemId = (item) => {
352
420
  var contextMatches = (left, right) => left?.adapter === right?.adapter && left?.documentId === right?.documentId && left?.editor === right?.editor && left?.reconcileToken === right?.reconcileToken;
353
421
  function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onReconciled }) {
354
422
  const pendingUpserts = /* @__PURE__ */ new Map();
423
+ let pendingAllResolved = null;
355
424
  let sequence = 0;
356
425
  let generation = 0;
357
426
  let flushInFlight = null;
358
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
+ };
359
437
  const isCurrent = (capturedGeneration, context) => generation === capturedGeneration && contextMatches(context, getContext());
360
438
  const clearResolved = (ids, snapshot) => {
361
439
  const clearedIds = /* @__PURE__ */ new Set();
@@ -369,6 +447,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
369
447
  const readySnapshot = (reconcileMode) => new Map([...pendingUpserts].filter(([, entry]) => entry.ready === true && entry.reconcileMode === reconcileMode));
370
448
  const markRenderGatedReady = () => {
371
449
  let changed = false;
450
+ if (pendingAllResolved?.gate === "render" && !pendingAllResolved.ready) {
451
+ pendingAllResolved.ready = true;
452
+ changed = true;
453
+ }
372
454
  for (const entry of pendingUpserts.values()) {
373
455
  if (entry.gate !== "render" || entry.ready) continue;
374
456
  entry.ready = true;
@@ -378,6 +460,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
378
460
  };
379
461
  const markEntriesReadyThrough = (maxVersion) => {
380
462
  let changed = false;
463
+ if (pendingAllResolved && pendingAllResolved.version <= maxVersion && !pendingAllResolved.ready) {
464
+ pendingAllResolved.ready = true;
465
+ changed = true;
466
+ }
381
467
  for (const entry of pendingUpserts.values()) {
382
468
  if (entry.version > maxVersion || entry.ready) continue;
383
469
  entry.ready = true;
@@ -428,14 +514,31 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
428
514
  };
429
515
  const flush = () => {
430
516
  if (flushInFlight) return flushInFlight;
517
+ const allResolvedSnapshot = pendingAllResolved?.ready ? pendingAllResolved : null;
431
518
  const targetedSnapshot = readySnapshot("targeted");
432
519
  const authoritativeSnapshot = readySnapshot("authoritative");
433
- if (targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
520
+ if (!allResolvedSnapshot && targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
434
521
  const context = getContext();
435
522
  if (!context?.adapter) return null;
436
523
  flushRequested = false;
437
524
  const capturedGeneration = generation;
438
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
+ }
439
542
  if (authoritativeSnapshot.size > 0) await reconcileAuthoritativeSnapshot(context, authoritativeSnapshot, capturedGeneration).catch(() => void 0);
440
543
  if (targetedSnapshot.size > 0) await reconcileTargetedSnapshot(context, targetedSnapshot, capturedGeneration).catch(() => void 0);
441
544
  }).catch(() => {}).finally(() => {
@@ -446,6 +549,15 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
446
549
  };
447
550
  const enqueueWithGate = (impact, gate) => {
448
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
+ }
449
561
  const reconcileMode = impact.reconcileMode === "authoritative" ? "authoritative" : "targeted";
450
562
  const removedIds = normalizeIds(impact.removedIds);
451
563
  const upsertIds = normalizeIds(impact.upsertIds);
@@ -460,7 +572,7 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
460
572
  else pendingUpserts.delete(id);
461
573
  }
462
574
  const context = getContext();
463
- if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter) try {
575
+ if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter && !impact.allResolved) try {
464
576
  Promise.resolve(reconcile(context, {
465
577
  upsertIds: /* @__PURE__ */ new Set(),
466
578
  removedIds
@@ -487,20 +599,34 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
487
599
  enqueueAfterPaint(impact, waitForPaint) {
488
600
  if (!impact || typeof waitForPaint !== "function") {
489
601
  enqueue(impact);
490
- return;
602
+ return Promise.resolve(false);
491
603
  }
492
604
  enqueueWithGate(impact, "exact-paint");
493
605
  const context = getContext();
494
- if (!context?.adapter) return;
495
606
  const capturedGeneration = generation;
496
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
+ });
497
620
  const impactedIds = new Set([...normalizeIds(impact.upsertIds), ...normalizeIds(impact.removedIds)]);
498
621
  const capturedEntries = new Map([...impactedIds].flatMap((id) => {
499
622
  const entry = pendingUpserts.get(id);
500
623
  return entry ? [[id, entry]] : [];
501
624
  }));
502
- Promise.resolve().then(() => waitForPaint()).then(() => {
503
- if (!isCurrent(capturedGeneration, context)) return;
625
+ Promise.resolve().then(() => waitForPaint()).then(async () => {
626
+ if (!isCurrent(capturedGeneration, context)) {
627
+ resolveSettlementsThrough(capturedSequence, false);
628
+ return;
629
+ }
504
630
  let madeReady = markRenderGatedReady();
505
631
  if (markEntriesReadyThrough(capturedSequence)) madeReady = true;
506
632
  for (const [id, entry] of capturedEntries) {
@@ -509,16 +635,35 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
509
635
  entry.ready = true;
510
636
  }
511
637
  if (flushInFlight && (madeReady || capturedSequence > 0)) flushRequested = true;
512
- 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);
513
650
  }).catch(() => {
514
- if (!isCurrent(capturedGeneration, context)) return;
651
+ if (!isCurrent(capturedGeneration, context)) {
652
+ resolveSettlementsThrough(capturedSequence, false);
653
+ return;
654
+ }
515
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);
516
658
  });
659
+ return completion;
517
660
  },
518
661
  onRender,
519
662
  reset() {
663
+ for (const waiter of settlementWaiters.splice(0)) waiter.resolve(false);
520
664
  generation += 1;
521
665
  pendingUpserts.clear();
666
+ pendingAllResolved = null;
522
667
  flushRequested = false;
523
668
  },
524
669
  getPendingIds() {
@@ -1401,67 +1546,6 @@ function collectEntityHitsFromChain(start, stopAt) {
1401
1546
  }
1402
1547
  return hits;
1403
1548
  }
1404
- const DOM_CLASS_NAMES = {
1405
- PAGE: "superdoc-page",
1406
- FRAGMENT: "superdoc-fragment",
1407
- LINE: "superdoc-line",
1408
- INLINE_SDT_WRAPPER: "superdoc-structured-content-inline",
1409
- INLINE_SDT_LABEL: "superdoc-structured-content-inline__label",
1410
- BLOCK_SDT: "superdoc-structured-content-block",
1411
- BLOCK_SDT_LABEL: "superdoc-structured-content__label",
1412
- TABLE_FRAGMENT: "superdoc-table-fragment",
1413
- DOCUMENT_SECTION: "superdoc-document-section",
1414
- SDT_GROUP_HOVER: "sdt-group-hover",
1415
- TOC_ENTRY: "superdoc-toc-entry",
1416
- TOC_GROUP_HOVER: "toc-group-hover",
1417
- IMAGE_FRAGMENT: "superdoc-image-fragment",
1418
- INLINE_IMAGE: "superdoc-inline-image",
1419
- LIST_MARKER: "superdoc-list-marker",
1420
- INLINE_IMAGE_CLIP_WRAPPER: "superdoc-inline-image-clip-wrapper",
1421
- ANNOTATION: "annotation",
1422
- ANNOTATION_CONTENT: "annotation-content",
1423
- ANNOTATION_CARET_ANCHOR: "annotation-caret-anchor"
1424
- };
1425
- const STRUCTURED_CONTENT_CHROME_LABEL_CLASS_NAMES = [DOM_CLASS_NAMES.INLINE_SDT_LABEL, DOM_CLASS_NAMES.BLOCK_SDT_LABEL];
1426
- const DATA_ATTRS = {
1427
- PM_START: "data-pm-start",
1428
- PM_END: "data-pm-end",
1429
- LAYOUT_EPOCH: "data-layout-epoch",
1430
- TABLE_BOUNDARIES: "data-table-boundaries",
1431
- SDT_ID: "data-sdt-id",
1432
- SDT_TYPE: "data-sdt-type",
1433
- FIELD_ID: "data-field-id",
1434
- FIELD_TYPE: "data-field-type",
1435
- DRAGGABLE: "data-draggable",
1436
- DISPLAY_LABEL: "data-display-label",
1437
- VARIANT: "data-variant",
1438
- TYPE: "data-type",
1439
- LAYOUT_BOUNDARY_SCHEMA: "data-layout-boundary-schema",
1440
- LAYOUT_FRAGMENT_ID: "data-layout-fragment-id",
1441
- LAYOUT_STORY: "data-layout-story",
1442
- LAYOUT_BLOCK_REF: "data-layout-block-ref"
1443
- };
1444
- const decodeLayoutStoryDataset = (raw) => {
1445
- if (!raw) return { kind: "unknown" };
1446
- if (raw === "body") return { kind: "body" };
1447
- const idx = raw.indexOf(":");
1448
- const kind = idx === -1 ? raw : raw.slice(0, idx);
1449
- const id = idx === -1 ? void 0 : raw.slice(idx + 1);
1450
- switch (kind) {
1451
- case "body":
1452
- case "header":
1453
- case "footer":
1454
- case "footnote":
1455
- case "endnote":
1456
- case "textbox": return id ? {
1457
- kind,
1458
- id
1459
- } : { kind };
1460
- default: return { kind: "unknown" };
1461
- }
1462
- };
1463
- const SDT_BLOCK_WITH_ID_SELECTOR = `.${DOM_CLASS_NAMES.BLOCK_SDT}[${DATA_ATTRS.SDT_ID}]`;
1464
- const DRAGGABLE_SELECTOR = `[${DATA_ATTRS.DRAGGABLE}="true"]`;
1465
1549
  var schemaBooleanOrNull = () => ({ oneOf: [{ type: "boolean" }, { type: "null" }] });
1466
1550
  var schemaStringOrNull = () => ({ oneOf: [{
1467
1551
  type: "string",
@@ -1716,6 +1800,30 @@ const INLINE_PROPERTY_KEYS_BY_STORAGE = {
1716
1800
  mark: INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "mark").map((entry) => entry.key),
1717
1801
  runAttribute: INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "runAttribute").map((entry) => entry.key)
1718
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
+ }
1719
1827
  var SUPERDOC_UI_REASON_VALUES = new Set(Object.values(SUPERDOC_UI_REASONS));
1720
1828
  function coerceSuperDocUIReason(reason, fallback) {
1721
1829
  return typeof reason === "string" && SUPERDOC_UI_REASON_VALUES.has(reason) ? reason : fallback;
@@ -1812,12 +1920,12 @@ const HEAVY_DOC_READ_POLICY = [
1812
1920
  {
1813
1921
  key: "trackChanges",
1814
1922
  match: "exact",
1815
- note: "audited: all-story tracked-changes list; stale-served during load"
1923
+ note: "audited: shared all-story tracked-changes catalog; stale-served during load"
1816
1924
  },
1817
1925
  {
1818
1926
  key: "trackChanges:all",
1819
1927
  match: "exact",
1820
- 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"
1821
1929
  },
1822
1930
  {
1823
1931
  key: "tables",
@@ -3276,6 +3384,63 @@ function createSuperDocUI(options) {
3276
3384
  };
3277
3385
  let documentMutationRevision = 0;
3278
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
+ };
3279
3444
  let authoritativeTrackChangesPendingToken = null;
3280
3445
  let authoritativeTrackChangesRetryTimer = null;
3281
3446
  let authoritativeTrackChangesFailureCount = 0;
@@ -3287,6 +3452,7 @@ function createSuperDocUI(options) {
3287
3452
  let scheduleAuthoritativeTrackChangesRetry = (_reconcileToken) => void 0;
3288
3453
  let postDecisionTrackChangesToken = null;
3289
3454
  let postDecisionTrackChangeIds = /* @__PURE__ */ new Set();
3455
+ let allTrackedChangesResolvedToken = null;
3290
3456
  let selectionEpoch = 0;
3291
3457
  let lastCoordinatorEditor = null;
3292
3458
  const contentToken = () => `${editorIdentityId(getEditor())}|m${documentMutationRevision}`;
@@ -3365,6 +3531,23 @@ function createSuperDocUI(options) {
3365
3531
  };
3366
3532
  notifyPostDecisionTrackChanges(receipt);
3367
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
+ };
3368
3551
  const markPostDecisionTrackChanges = (ids, receipt) => {
3369
3552
  if (ids.size === 0) return;
3370
3553
  const token = contentToken();
@@ -4043,6 +4226,7 @@ function createSuperDocUI(options) {
4043
4226
  detachSourceLoading = null;
4044
4227
  sourceLoadingSubscriptionHost = null;
4045
4228
  clearPostDecisionTrackChanges();
4229
+ allTrackedChangesResolvedToken = null;
4046
4230
  };
4047
4231
  const invalidateDocumentContent = () => {
4048
4232
  const carryAuthoritativeTrackChangesHold = authoritativeTrackChangesPendingToken !== null;
@@ -4050,6 +4234,15 @@ function createSuperDocUI(options) {
4050
4234
  if (carryAuthoritativeTrackChangesHold) authoritativeTrackChangesPendingToken = contentToken();
4051
4235
  clearPostDecisionTrackChanges();
4052
4236
  };
4237
+ const invalidateAfterCommandSettlement = () => {
4238
+ const carryAllResolvedCatalog = allTrackedChangesResolvedToken === contentToken();
4239
+ invalidateDocumentContent();
4240
+ if (carryAllResolvedCatalog) {
4241
+ replaceTrackedChangeItemsInCache([]);
4242
+ allTrackedChangesResolvedToken = contentToken();
4243
+ }
4244
+ recompute();
4245
+ };
4053
4246
  const insertText = (text) => {
4054
4247
  if (typeof text !== "string" || text.length === 0) return failedReceipt("insertText requires a non-empty string.", "INVALID_INPUT");
4055
4248
  if (readDocumentMode() === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
@@ -4253,7 +4446,17 @@ function createSuperDocUI(options) {
4253
4446
  const { value, status } = authoritativeTrackChangesPendingToken === token ? {
4254
4447
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4255
4448
  status: heldEntry?.hasSettled ? "stale" : "pending"
4256
- } : 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) => {
4257
4460
  return (raw && Array.isArray(raw.items) ? raw.items : []).map(projectTrackChangesItem).filter((item) => item != null);
4258
4461
  });
4259
4462
  return status === "ready" ? value : null;
@@ -4269,7 +4472,7 @@ function createSuperDocUI(options) {
4269
4472
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4270
4473
  status: heldEntry?.hasSettled ? "stale" : "pending"
4271
4474
  } : readAsync("trackChanges", token, () => {
4272
- if (listTrackedChanges) return listTrackedChanges.call(v2TrackedChanges);
4475
+ if (listTrackedChanges) return runUiTrackedChangesCatalogRead(() => tcApi?.list?.());
4273
4476
  return tcApi?.list ? tcApi.list({ in: "all" }) : void 0;
4274
4477
  }, (raw) => raw && Array.isArray(raw.items) ? raw.items : []);
4275
4478
  const items = (value ?? []).map(projectTrackChangesItem).filter((item) => item != null).filter((item) => {
@@ -4292,7 +4495,7 @@ function createSuperDocUI(options) {
4292
4495
  }
4293
4496
  const publicIdItems = allStoryItems ?? items;
4294
4497
  const selectionIdContext = buildStoryScopedTrackedChangeIdContext(publicIdItems, selectionStory(selection$1));
4295
- const selectionActiveChangeIds = postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
4498
+ const selectionActiveChangeIds = allTrackedChangesResolvedToken === token ? [] : postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
4296
4499
  const selectionPublicChangeIds = selectionActiveChangeIds.map((id) => selectionIdContext.toPublicId(id) ?? id);
4297
4500
  const explicitActiveIdContext = explicitActiveChange?.story ? buildStoryScopedTrackedChangeIdContext(publicIdItems, explicitActiveChange.story) : buildTrackedChangeIdContext(publicIdItems);
4298
4501
  const explicitActiveId = explicitActiveChange ? explicitActiveIdContext.toPublicId(explicitActiveChange.id) ?? explicitActiveChange.id : null;
@@ -6055,6 +6258,20 @@ function createSuperDocUI(options) {
6055
6258
  try {
6056
6259
  const off = next.subscribe((event) => {
6057
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);
6058
6275
  if (type === "source:complete" || type === "source:signals-complete") {
6059
6276
  if (authoritativeTrackChangesPendingToken !== null) {
6060
6277
  clearAuthoritativeTrackChangesRetry();
@@ -6070,6 +6287,13 @@ function createSuperDocUI(options) {
6070
6287
  if (type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
6071
6288
  const impact = type === "mutation:committed" ? getV2TrackedChangeMutationImpact(event) : null;
6072
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
+ }
6073
6297
  if (impact?.removedIds.size) markPostDecisionTrackChanges(new Set(impact.removedIds), event.receipt);
6074
6298
  const authoritativeHistoryImpact = impact?.reconcileMode === "authoritative" && impact.upsertIds.size > 0;
6075
6299
  if (authoritativeHistoryImpact) {
@@ -6303,7 +6527,7 @@ function createSuperDocUI(options) {
6303
6527
  }
6304
6528
  function resolveTrackDecisionTarget(command, payload) {
6305
6529
  if (command.scope === "all") return {
6306
- target: { scope: "all" },
6530
+ target: { kind: "all" },
6307
6531
  changeId: null
6308
6532
  };
6309
6533
  if (typeof payload === "string" && payload.length > 0) return {
@@ -6549,13 +6773,11 @@ function createSuperDocUI(options) {
6549
6773
  };
6550
6774
  const finalizeCommandSettlement = (promise, onSettled) => promise.then((settled) => {
6551
6775
  onSettled?.(settled);
6552
- invalidateDocumentContent();
6553
- recompute();
6776
+ invalidateAfterCommandSettlement();
6554
6777
  return settled;
6555
6778
  }, () => {
6556
6779
  onSettled?.(false);
6557
- invalidateDocumentContent();
6558
- recompute();
6780
+ invalidateAfterCommandSettlement();
6559
6781
  return false;
6560
6782
  });
6561
6783
  const settleCommandExecution = (result, onSettled) => {
@@ -6578,8 +6800,7 @@ function createSuperDocUI(options) {
6578
6800
  }
6579
6801
  onSettled?.(settled);
6580
6802
  lastCommandSettlement = Promise.resolve(settled);
6581
- invalidateDocumentContent();
6582
- recompute();
6803
+ invalidateAfterCommandSettlement();
6583
6804
  return settled;
6584
6805
  };
6585
6806
  const normalizeWorkflowReceipt = (value, fallback) => {
@@ -7741,6 +7962,14 @@ function createSuperDocUI(options) {
7741
7962
  if (typeof helper?.apply !== "function") return { reason: SUPERDOC_UI_REASONS.hostCapabilityUnavailable };
7742
7963
  return { helper };
7743
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
+ };
7744
7973
  const selection = {
7745
7974
  get: selectionSnap.get,
7746
7975
  getSnapshot: selectionSnap.getSnapshot,
@@ -8000,10 +8229,14 @@ function createSuperDocUI(options) {
8000
8229
  const op = commentsApi?.create;
8001
8230
  if (typeof op !== "function") return failedReceipt("comments.create is unavailable.");
8002
8231
  const fallback = failedReceipt("comments.create failed.");
8003
- return safeCall(() => settleWorkflowReceipt(op.call(commentsApi, {
8004
- target: capture.target ?? capture.selectionTarget,
8005
- text: input.text
8006
- }), 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);
8007
8240
  },
8008
8241
  createFromSelection: (input) => {
8009
8242
  const refusal = commentWriteRefusal();
@@ -8035,6 +8268,18 @@ function createSuperDocUI(options) {
8035
8268
  text: input.text
8036
8269
  }), fallback), fallback);
8037
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
+ },
8038
8283
  resolve: (commentId) => patchCommentStatus(commentId, "resolved"),
8039
8284
  reopen: (commentId) => patchCommentStatus(commentId, "active"),
8040
8285
  delete: (commentId) => {
@@ -8175,8 +8420,8 @@ function createSuperDocUI(options) {
8175
8420
  },
8176
8421
  accept: (changeId) => executeTrackDecision("accept", changeId),
8177
8422
  reject: (changeId) => executeTrackDecision("reject", changeId),
8178
- acceptAll: () => executeTrackDecisionTarget("accept", { scope: "all" }, null),
8179
- rejectAll: () => executeTrackDecisionTarget("reject", { scope: "all" }, null),
8423
+ acceptAll: () => executeTrackDecisionTarget("accept", { kind: "all" }, null),
8424
+ rejectAll: () => executeTrackDecisionTarget("reject", { kind: "all" }, null),
8180
8425
  next: () => navigateTrackChange(1),
8181
8426
  previous: () => navigateTrackChange(-1),
8182
8427
  navigateNext: () => navigateAndScroll(1),
@@ -8330,7 +8575,7 @@ function createSuperDocUI(options) {
8330
8575
  const callTrackDecisionTarget = (kind, target, changeId, story) => {
8331
8576
  if (reviewMutationsAreReadOnly()) return false;
8332
8577
  const tcApi = getDoc()?.trackChanges;
8333
- const isAllTarget = target.scope === "all";
8578
+ const isAllTarget = target.kind === "all" || target.scope === "all";
8334
8579
  const isRangeTarget = target.kind === "range";
8335
8580
  const isMultiIdTarget = target.kind === "ids";
8336
8581
  if (bulkTrackDecisionBlockedReason({
@@ -8433,6 +8678,7 @@ function createSuperDocUI(options) {
8433
8678
  success: false,
8434
8679
  reason: "not-reachable"
8435
8680
  };
8681
+ activateContentControlChrome(id);
8436
8682
  return { success: true };
8437
8683
  }
8438
8684
  };
@@ -9380,6 +9626,7 @@ function createSuperDocUI(options) {
9380
9626
  const destroy = () => {
9381
9627
  if (disposed) return;
9382
9628
  disposed = true;
9629
+ releaseSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost, uiTrackedChangesCatalogState);
9383
9630
  reviewMutationReconciler.reset();
9384
9631
  clearAuthoritativeTrackChangesRetry();
9385
9632
  if (foregroundAsyncRetryTimer) {
@@ -9642,6 +9889,12 @@ Object.defineProperty(exports, "BUILT_IN_COMMAND_IDS", {
9642
9889
  return BUILT_IN_COMMAND_IDS;
9643
9890
  }
9644
9891
  });
9892
+ Object.defineProperty(exports, "DOM_CLASS_NAMES", {
9893
+ enumerable: true,
9894
+ get: function() {
9895
+ return DOM_CLASS_NAMES;
9896
+ }
9897
+ });
9645
9898
  Object.defineProperty(exports, "composeAuthorColorResolver", {
9646
9899
  enumerable: true,
9647
9900
  get: function() {