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
+ 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
+ `${DOM_CLASS_NAMES.BLOCK_SDT}${DATA_ATTRS.SDT_ID}`;
61
+ `${DATA_ATTRS.DRAGGABLE}`;
1
62
  function getParagraphInlineDirection(attrs) {
2
63
  const fromContext = attrs?.directionContext?.inlineDirection;
3
64
  if (fromContext != null) return fromContext;
@@ -115,14 +176,21 @@ function getV2TrackedChangeMutationImpact(event) {
115
176
  });
116
177
  }
117
178
  for (const id of removedIds) upsertIds.delete(id);
118
- if (upsertIds.size === 0 && removedIds.size === 0) return null;
179
+ const allResolved = readAllResolvedFact(event, payload);
180
+ if (upsertIds.size === 0 && removedIds.size === 0 && !allResolved) return null;
119
181
  return {
120
182
  upsertIds,
121
183
  removedIds,
122
184
  remappedPairs,
123
- reconcileMode: event.origin === "history" ? "authoritative" : "targeted"
185
+ reconcileMode: event.origin === "history" ? "authoritative" : "targeted",
186
+ ...allResolved ? { allResolved } : {}
124
187
  };
125
188
  }
189
+ function readAllResolvedFact(event, receipt) {
190
+ const fact = event?.trackedChangeAllResolved;
191
+ 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;
192
+ return fact;
193
+ }
126
194
  var normalizeIds = (values) => new Set(Array.from(values ?? []).filter((value) => typeof value === "string" && value.length > 0));
127
195
  var itemId = (item) => {
128
196
  if (typeof item?.id === "string" && item.id.length > 0) return item.id;
@@ -133,10 +201,20 @@ var itemId = (item) => {
133
201
  var contextMatches = (left, right) => left?.adapter === right?.adapter && left?.documentId === right?.documentId && left?.editor === right?.editor && left?.reconcileToken === right?.reconcileToken;
134
202
  function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onReconciled }) {
135
203
  const pendingUpserts = /* @__PURE__ */ new Map();
204
+ let pendingAllResolved = null;
136
205
  let sequence = 0;
137
206
  let generation = 0;
138
207
  let flushInFlight = null;
139
208
  let flushRequested = false;
209
+ const settlementWaiters = [];
210
+ const resolveSettlementsThrough = (version, value) => {
211
+ for (let index = settlementWaiters.length - 1; index >= 0; index -= 1) {
212
+ const waiter = settlementWaiters[index];
213
+ if (waiter.generation !== generation || waiter.version > version) continue;
214
+ settlementWaiters.splice(index, 1);
215
+ waiter.resolve(value === true && waiter.requiresAllResolved ? pendingAllResolved == null : value);
216
+ }
217
+ };
140
218
  const isCurrent = (capturedGeneration, context) => generation === capturedGeneration && contextMatches(context, getContext());
141
219
  const clearResolved = (ids, snapshot) => {
142
220
  const clearedIds = /* @__PURE__ */ new Set();
@@ -150,6 +228,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
150
228
  const readySnapshot = (reconcileMode) => new Map([...pendingUpserts].filter(([, entry]) => entry.ready === true && entry.reconcileMode === reconcileMode));
151
229
  const markRenderGatedReady = () => {
152
230
  let changed = false;
231
+ if (pendingAllResolved?.gate === "render" && !pendingAllResolved.ready) {
232
+ pendingAllResolved.ready = true;
233
+ changed = true;
234
+ }
153
235
  for (const entry of pendingUpserts.values()) {
154
236
  if (entry.gate !== "render" || entry.ready) continue;
155
237
  entry.ready = true;
@@ -159,6 +241,10 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
159
241
  };
160
242
  const markEntriesReadyThrough = (maxVersion) => {
161
243
  let changed = false;
244
+ if (pendingAllResolved && pendingAllResolved.version <= maxVersion && !pendingAllResolved.ready) {
245
+ pendingAllResolved.ready = true;
246
+ changed = true;
247
+ }
162
248
  for (const entry of pendingUpserts.values()) {
163
249
  if (entry.version > maxVersion || entry.ready) continue;
164
250
  entry.ready = true;
@@ -209,14 +295,31 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
209
295
  };
210
296
  const flush = () => {
211
297
  if (flushInFlight) return flushInFlight;
298
+ const allResolvedSnapshot = pendingAllResolved?.ready ? pendingAllResolved : null;
212
299
  const targetedSnapshot = readySnapshot("targeted");
213
300
  const authoritativeSnapshot = readySnapshot("authoritative");
214
- if (targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
301
+ if (!allResolvedSnapshot && targetedSnapshot.size === 0 && authoritativeSnapshot.size === 0) return null;
215
302
  const context = getContext();
216
303
  if (!context?.adapter) return null;
217
304
  flushRequested = false;
218
305
  const capturedGeneration = generation;
219
306
  flushInFlight = Promise.resolve().then(async () => {
307
+ if (allResolvedSnapshot) {
308
+ let result = null;
309
+ try {
310
+ result = await reconcile(context, {
311
+ upsertIds: /* @__PURE__ */ new Set(),
312
+ removedIds: /* @__PURE__ */ new Set(),
313
+ allResolved: allResolvedSnapshot.fact,
314
+ reconcileMode: "targeted"
315
+ });
316
+ } catch {}
317
+ if (!isCurrent(capturedGeneration, context)) return;
318
+ if (result?.ok === true) {
319
+ if (pendingAllResolved === allResolvedSnapshot) pendingAllResolved = null;
320
+ await notifyReconciled(context, /* @__PURE__ */ new Set(), result, true);
321
+ }
322
+ }
220
323
  if (authoritativeSnapshot.size > 0) await reconcileAuthoritativeSnapshot(context, authoritativeSnapshot, capturedGeneration).catch(() => void 0);
221
324
  if (targetedSnapshot.size > 0) await reconcileTargetedSnapshot(context, targetedSnapshot, capturedGeneration).catch(() => void 0);
222
325
  }).catch(() => {}).finally(() => {
@@ -227,6 +330,15 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
227
330
  };
228
331
  const enqueueWithGate = (impact, gate) => {
229
332
  if (!impact) return;
333
+ if (impact.allResolved) {
334
+ pendingUpserts.clear();
335
+ pendingAllResolved = {
336
+ fact: impact.allResolved,
337
+ version: ++sequence,
338
+ gate,
339
+ ready: false
340
+ };
341
+ }
230
342
  const reconcileMode = impact.reconcileMode === "authoritative" ? "authoritative" : "targeted";
231
343
  const removedIds = normalizeIds(impact.removedIds);
232
344
  const upsertIds = normalizeIds(impact.upsertIds);
@@ -241,7 +353,7 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
241
353
  else pendingUpserts.delete(id);
242
354
  }
243
355
  const context = getContext();
244
- if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter) try {
356
+ if (removedIds.size > 0 && upsertIds.size === 0 && context?.adapter && !impact.allResolved) try {
245
357
  Promise.resolve(reconcile(context, {
246
358
  upsertIds: /* @__PURE__ */ new Set(),
247
359
  removedIds
@@ -268,20 +380,34 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
268
380
  enqueueAfterPaint(impact, waitForPaint) {
269
381
  if (!impact || typeof waitForPaint !== "function") {
270
382
  enqueue(impact);
271
- return;
383
+ return Promise.resolve(false);
272
384
  }
273
385
  enqueueWithGate(impact, "exact-paint");
274
386
  const context = getContext();
275
- if (!context?.adapter) return;
276
387
  const capturedGeneration = generation;
277
388
  const capturedSequence = sequence;
389
+ if (!context?.adapter) {
390
+ markEntriesReadyThrough(capturedSequence);
391
+ return Promise.resolve(false);
392
+ }
393
+ const completion = new Promise((resolve) => {
394
+ settlementWaiters.push({
395
+ generation: capturedGeneration,
396
+ version: capturedSequence,
397
+ requiresAllResolved: Boolean(impact.allResolved),
398
+ resolve
399
+ });
400
+ });
278
401
  const impactedIds = new Set([...normalizeIds(impact.upsertIds), ...normalizeIds(impact.removedIds)]);
279
402
  const capturedEntries = new Map([...impactedIds].flatMap((id) => {
280
403
  const entry = pendingUpserts.get(id);
281
404
  return entry ? [[id, entry]] : [];
282
405
  }));
283
- Promise.resolve().then(() => waitForPaint()).then(() => {
284
- if (!isCurrent(capturedGeneration, context)) return;
406
+ Promise.resolve().then(() => waitForPaint()).then(async () => {
407
+ if (!isCurrent(capturedGeneration, context)) {
408
+ resolveSettlementsThrough(capturedSequence, false);
409
+ return;
410
+ }
285
411
  let madeReady = markRenderGatedReady();
286
412
  if (markEntriesReadyThrough(capturedSequence)) madeReady = true;
287
413
  for (const [id, entry] of capturedEntries) {
@@ -290,16 +416,35 @@ function createV2ReviewMutationReconciler({ getContext, reconcile, hydrate, onRe
290
416
  entry.ready = true;
291
417
  }
292
418
  if (flushInFlight && (madeReady || capturedSequence > 0)) flushRequested = true;
293
- flush();
419
+ const preceding = flushInFlight;
420
+ const pending = flush();
421
+ if (pending) await pending;
422
+ if (preceding) {
423
+ const followUp = flushInFlight;
424
+ if (followUp && followUp !== preceding) await followUp;
425
+ }
426
+ if (!isCurrent(capturedGeneration, context)) {
427
+ resolveSettlementsThrough(capturedSequence, false);
428
+ return;
429
+ }
430
+ resolveSettlementsThrough(capturedSequence, true);
294
431
  }).catch(() => {
295
- if (!isCurrent(capturedGeneration, context)) return;
432
+ if (!isCurrent(capturedGeneration, context)) {
433
+ resolveSettlementsThrough(capturedSequence, false);
434
+ return;
435
+ }
296
436
  for (const [id, entry] of capturedEntries) if (pendingUpserts.get(id) === entry) entry.gate = "render";
437
+ if (pendingAllResolved?.gate === "exact-paint") pendingAllResolved.gate = "render";
438
+ resolveSettlementsThrough(capturedSequence, false);
297
439
  });
440
+ return completion;
298
441
  },
299
442
  onRender,
300
443
  reset() {
444
+ for (const waiter of settlementWaiters.splice(0)) waiter.resolve(false);
301
445
  generation += 1;
302
446
  pendingUpserts.clear();
447
+ pendingAllResolved = null;
303
448
  flushRequested = false;
304
449
  },
305
450
  getPendingIds() {
@@ -1182,67 +1327,6 @@ function collectEntityHitsFromChain(start, stopAt) {
1182
1327
  }
1183
1328
  return hits;
1184
1329
  }
1185
- const DOM_CLASS_NAMES = {
1186
- PAGE: "superdoc-page",
1187
- FRAGMENT: "superdoc-fragment",
1188
- LINE: "superdoc-line",
1189
- INLINE_SDT_WRAPPER: "superdoc-structured-content-inline",
1190
- INLINE_SDT_LABEL: "superdoc-structured-content-inline__label",
1191
- BLOCK_SDT: "superdoc-structured-content-block",
1192
- BLOCK_SDT_LABEL: "superdoc-structured-content__label",
1193
- TABLE_FRAGMENT: "superdoc-table-fragment",
1194
- DOCUMENT_SECTION: "superdoc-document-section",
1195
- SDT_GROUP_HOVER: "sdt-group-hover",
1196
- TOC_ENTRY: "superdoc-toc-entry",
1197
- TOC_GROUP_HOVER: "toc-group-hover",
1198
- IMAGE_FRAGMENT: "superdoc-image-fragment",
1199
- INLINE_IMAGE: "superdoc-inline-image",
1200
- LIST_MARKER: "superdoc-list-marker",
1201
- INLINE_IMAGE_CLIP_WRAPPER: "superdoc-inline-image-clip-wrapper",
1202
- ANNOTATION: "annotation",
1203
- ANNOTATION_CONTENT: "annotation-content",
1204
- ANNOTATION_CARET_ANCHOR: "annotation-caret-anchor"
1205
- };
1206
- DOM_CLASS_NAMES.INLINE_SDT_LABEL, DOM_CLASS_NAMES.BLOCK_SDT_LABEL;
1207
- const DATA_ATTRS = {
1208
- PM_START: "data-pm-start",
1209
- PM_END: "data-pm-end",
1210
- LAYOUT_EPOCH: "data-layout-epoch",
1211
- TABLE_BOUNDARIES: "data-table-boundaries",
1212
- SDT_ID: "data-sdt-id",
1213
- SDT_TYPE: "data-sdt-type",
1214
- FIELD_ID: "data-field-id",
1215
- FIELD_TYPE: "data-field-type",
1216
- DRAGGABLE: "data-draggable",
1217
- DISPLAY_LABEL: "data-display-label",
1218
- VARIANT: "data-variant",
1219
- TYPE: "data-type",
1220
- LAYOUT_BOUNDARY_SCHEMA: "data-layout-boundary-schema",
1221
- LAYOUT_FRAGMENT_ID: "data-layout-fragment-id",
1222
- LAYOUT_STORY: "data-layout-story",
1223
- LAYOUT_BLOCK_REF: "data-layout-block-ref"
1224
- };
1225
- const decodeLayoutStoryDataset = (raw) => {
1226
- if (!raw) return { kind: "unknown" };
1227
- if (raw === "body") return { kind: "body" };
1228
- const idx = raw.indexOf(":");
1229
- const kind = idx === -1 ? raw : raw.slice(0, idx);
1230
- const id = idx === -1 ? void 0 : raw.slice(idx + 1);
1231
- switch (kind) {
1232
- case "body":
1233
- case "header":
1234
- case "footer":
1235
- case "footnote":
1236
- case "endnote":
1237
- case "textbox": return id ? {
1238
- kind,
1239
- id
1240
- } : { kind };
1241
- default: return { kind: "unknown" };
1242
- }
1243
- };
1244
- `${DOM_CLASS_NAMES.BLOCK_SDT}${DATA_ATTRS.SDT_ID}`;
1245
- `${DATA_ATTRS.DRAGGABLE}`;
1246
1330
  var schemaBooleanOrNull = () => ({ oneOf: [{ type: "boolean" }, { type: "null" }] });
1247
1331
  var schemaStringOrNull = () => ({ oneOf: [{
1248
1332
  type: "string",
@@ -1494,6 +1578,30 @@ const INLINE_PROPERTY_REGISTRY = [
1494
1578
  new Set(INLINE_PROPERTY_REGISTRY.map((entry) => entry.key));
1495
1579
  const INLINE_PROPERTY_BY_KEY = Object.fromEntries(INLINE_PROPERTY_REGISTRY.map((entry) => [entry.key, entry]));
1496
1580
  INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "mark").map((entry) => entry.key), INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "runAttribute").map((entry) => entry.key);
1581
+ var sharedUiTrackedChangesCatalogByHost = /* @__PURE__ */ new WeakMap();
1582
+ function acquireSharedUiTrackedChangesCatalog(host) {
1583
+ let state = sharedUiTrackedChangesCatalogByHost.get(host);
1584
+ if (!state) {
1585
+ state = {
1586
+ refCount: 0,
1587
+ generation: 0,
1588
+ abortController: new AbortController(),
1589
+ inFlight: null,
1590
+ activeMutationTokens: /* @__PURE__ */ new Set()
1591
+ };
1592
+ sharedUiTrackedChangesCatalogByHost.set(host, state);
1593
+ }
1594
+ state.refCount += 1;
1595
+ return state;
1596
+ }
1597
+ function releaseSharedUiTrackedChangesCatalog(host, state) {
1598
+ state.refCount = Math.max(0, state.refCount - 1);
1599
+ if (state.refCount > 0) return;
1600
+ state.abortController.abort("ui-controller-destroyed");
1601
+ state.inFlight = null;
1602
+ state.activeMutationTokens.clear();
1603
+ sharedUiTrackedChangesCatalogByHost.delete(host);
1604
+ }
1497
1605
  var SUPERDOC_UI_REASON_VALUES = new Set(Object.values(SUPERDOC_UI_REASONS));
1498
1606
  function coerceSuperDocUIReason(reason, fallback) {
1499
1607
  return typeof reason === "string" && SUPERDOC_UI_REASON_VALUES.has(reason) ? reason : fallback;
@@ -1590,12 +1698,12 @@ const HEAVY_DOC_READ_POLICY = [
1590
1698
  {
1591
1699
  key: "trackChanges",
1592
1700
  match: "exact",
1593
- note: "audited: all-story tracked-changes list; stale-served during load"
1701
+ note: "audited: shared all-story tracked-changes catalog; stale-served during load"
1594
1702
  },
1595
1703
  {
1596
1704
  key: "trackChanges:all",
1597
1705
  match: "exact",
1598
- note: "audited: all-story tracked-changes list; consumers already fail closed on non-ready"
1706
+ note: "audited: current-token validation over the shared all-story catalog; consumers fail closed on non-ready"
1599
1707
  },
1600
1708
  {
1601
1709
  key: "tables",
@@ -3054,6 +3162,63 @@ function createSuperDocUI(options) {
3054
3162
  };
3055
3163
  let documentMutationRevision = 0;
3056
3164
  let reviewMutationToken = {};
3165
+ const uiTrackedChangesCatalogHost = options.superdoc;
3166
+ const uiTrackedChangesCatalogState = acquireSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost);
3167
+ const supersedeUiTrackedChangesCatalogRead = () => {
3168
+ uiTrackedChangesCatalogState.abortController.abort("review-mutation-started");
3169
+ uiTrackedChangesCatalogState.inFlight = null;
3170
+ };
3171
+ const renewUiTrackedChangesCatalogRead = () => {
3172
+ uiTrackedChangesCatalogState.generation += 1;
3173
+ uiTrackedChangesCatalogState.abortController = new AbortController();
3174
+ uiTrackedChangesCatalogState.inFlight = null;
3175
+ };
3176
+ const beginUiReviewMutation = (token) => {
3177
+ const activeTokens = uiTrackedChangesCatalogState.activeMutationTokens;
3178
+ if (typeof token !== "string" || token.length === 0 || activeTokens.has(token)) return;
3179
+ const firstToken = activeTokens.size === 0;
3180
+ activeTokens.add(token);
3181
+ if (firstToken) supersedeUiTrackedChangesCatalogRead();
3182
+ };
3183
+ const settleUiReviewMutation = (token) => {
3184
+ const activeTokens = uiTrackedChangesCatalogState.activeMutationTokens;
3185
+ if (typeof token !== "string" || !activeTokens.delete(token)) return;
3186
+ if (activeTokens.size === 0) renewUiTrackedChangesCatalogRead();
3187
+ };
3188
+ const runUiTrackedChangesCatalogRead = (fallback) => {
3189
+ const v2TrackedChanges = getV2TrackedChanges();
3190
+ const listTrackedChanges = v2TrackedChanges?.listTrackedChanges;
3191
+ if (typeof listTrackedChanges !== "function") {
3192
+ if (getEditor()?.editorVersion === 2) return Promise.reject(/* @__PURE__ */ new Error("v2-tracked-changes-bridge-pending"));
3193
+ return fallback();
3194
+ }
3195
+ if (uiTrackedChangesCatalogState.activeMutationTokens.size > 0) return Promise.reject(/* @__PURE__ */ new Error("ui-review-catalog-superseded"));
3196
+ if ((getEditor()?.reviewHydration?.getDiagnostics?.())?.inFlight === true) return Promise.reject(/* @__PURE__ */ new Error("shell-review-hydration-in-flight"));
3197
+ const generation = uiTrackedChangesCatalogState.generation;
3198
+ const existing = uiTrackedChangesCatalogState.inFlight;
3199
+ if (existing?.generation === generation) return existing.promise;
3200
+ const signal = uiTrackedChangesCatalogState.abortController.signal;
3201
+ const validateResult = (result) => {
3202
+ if (signal.aborted || generation !== uiTrackedChangesCatalogState.generation || result?.reason === "review-hydration-superseded") throw new Error("ui-review-catalog-superseded");
3203
+ return result;
3204
+ };
3205
+ const rawResult = listTrackedChanges.call(v2TrackedChanges, {
3206
+ blocking: false,
3207
+ signal
3208
+ });
3209
+ if (!isPromiseLike(rawResult)) return validateResult(rawResult);
3210
+ const promise = Promise.resolve(rawResult).then(validateResult);
3211
+ uiTrackedChangesCatalogState.inFlight = {
3212
+ generation,
3213
+ promise
3214
+ };
3215
+ promise.then(() => {
3216
+ if (uiTrackedChangesCatalogState.inFlight?.promise === promise) uiTrackedChangesCatalogState.inFlight = null;
3217
+ }, () => {
3218
+ if (uiTrackedChangesCatalogState.inFlight?.promise === promise) uiTrackedChangesCatalogState.inFlight = null;
3219
+ });
3220
+ return promise;
3221
+ };
3057
3222
  let authoritativeTrackChangesPendingToken = null;
3058
3223
  let authoritativeTrackChangesRetryTimer = null;
3059
3224
  let authoritativeTrackChangesFailureCount = 0;
@@ -3065,6 +3230,7 @@ function createSuperDocUI(options) {
3065
3230
  let scheduleAuthoritativeTrackChangesRetry = (_reconcileToken) => void 0;
3066
3231
  let postDecisionTrackChangesToken = null;
3067
3232
  let postDecisionTrackChangeIds = /* @__PURE__ */ new Set();
3233
+ let allTrackedChangesResolvedToken = null;
3068
3234
  let selectionEpoch = 0;
3069
3235
  let lastCoordinatorEditor = null;
3070
3236
  const contentToken = () => `${editorIdentityId(getEditor())}|m${documentMutationRevision}`;
@@ -3143,6 +3309,23 @@ function createSuperDocUI(options) {
3143
3309
  };
3144
3310
  notifyPostDecisionTrackChanges(receipt);
3145
3311
  };
3312
+ const publishAllTrackedChangesResolved = (receipt) => {
3313
+ const previous = state.trackChanges;
3314
+ const changed = previous.items.length > 0 || previous.total !== 0 || previous.activeId !== null || previous.authors.length > 0;
3315
+ allTrackedChangesResolvedToken = contentToken();
3316
+ if (explicitActiveChange !== null) setExplicitActiveChange(null);
3317
+ state = {
3318
+ ...state,
3319
+ trackChanges: {
3320
+ ...previous,
3321
+ items: [],
3322
+ total: 0,
3323
+ activeId: null,
3324
+ authors: []
3325
+ }
3326
+ };
3327
+ if (changed) notifyPostDecisionTrackChanges(receipt);
3328
+ };
3146
3329
  const markPostDecisionTrackChanges = (ids, receipt) => {
3147
3330
  if (ids.size === 0) return;
3148
3331
  const token = contentToken();
@@ -3821,6 +4004,7 @@ function createSuperDocUI(options) {
3821
4004
  detachSourceLoading = null;
3822
4005
  sourceLoadingSubscriptionHost = null;
3823
4006
  clearPostDecisionTrackChanges();
4007
+ allTrackedChangesResolvedToken = null;
3824
4008
  };
3825
4009
  const invalidateDocumentContent = () => {
3826
4010
  const carryAuthoritativeTrackChangesHold = authoritativeTrackChangesPendingToken !== null;
@@ -3828,6 +4012,15 @@ function createSuperDocUI(options) {
3828
4012
  if (carryAuthoritativeTrackChangesHold) authoritativeTrackChangesPendingToken = contentToken();
3829
4013
  clearPostDecisionTrackChanges();
3830
4014
  };
4015
+ const invalidateAfterCommandSettlement = () => {
4016
+ const carryAllResolvedCatalog = allTrackedChangesResolvedToken === contentToken();
4017
+ invalidateDocumentContent();
4018
+ if (carryAllResolvedCatalog) {
4019
+ replaceTrackedChangeItemsInCache([]);
4020
+ allTrackedChangesResolvedToken = contentToken();
4021
+ }
4022
+ recompute();
4023
+ };
3831
4024
  const insertText = (text) => {
3832
4025
  if (typeof text !== "string" || text.length === 0) return failedReceipt("insertText requires a non-empty string.", "INVALID_INPUT");
3833
4026
  if (readDocumentMode() === "viewing") return failedReceipt("The document is read-only.", "DOCUMENT_READONLY");
@@ -4031,7 +4224,17 @@ function createSuperDocUI(options) {
4031
4224
  const { value, status } = authoritativeTrackChangesPendingToken === token ? {
4032
4225
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4033
4226
  status: heldEntry?.hasSettled ? "stale" : "pending"
4034
- } : readAsync("trackChanges:all", token, () => tcApi?.list ? tcApi.list({ in: "all" }) : void 0, (raw) => {
4227
+ } : readAsync("trackChanges:all", token, () => {
4228
+ if (!tcApi?.list) return void 0;
4229
+ const fallback = () => tcApi.list({ in: "all" });
4230
+ const bridgeOwnsCatalog = typeof getV2TrackedChanges()?.listTrackedChanges === "function";
4231
+ const shared = runUiTrackedChangesCatalogRead(fallback);
4232
+ if (!bridgeOwnsCatalog) return shared;
4233
+ return Promise.resolve(shared).then((raw) => {
4234
+ const record = isLooseObject(raw) ? raw : null;
4235
+ return (Array.isArray(record?.items) ? record.items : []).some((item) => readEntityStory(item) == null) ? fallback() : raw;
4236
+ });
4237
+ }, (raw) => {
4035
4238
  return (raw && Array.isArray(raw.items) ? raw.items : []).map(projectTrackChangesItem).filter((item) => item != null);
4036
4239
  });
4037
4240
  return status === "ready" ? value : null;
@@ -4047,7 +4250,7 @@ function createSuperDocUI(options) {
4047
4250
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4048
4251
  status: heldEntry?.hasSettled ? "stale" : "pending"
4049
4252
  } : readAsync("trackChanges", token, () => {
4050
- if (listTrackedChanges) return listTrackedChanges.call(v2TrackedChanges);
4253
+ if (listTrackedChanges) return runUiTrackedChangesCatalogRead(() => tcApi?.list?.());
4051
4254
  return tcApi?.list ? tcApi.list({ in: "all" }) : void 0;
4052
4255
  }, (raw) => raw && Array.isArray(raw.items) ? raw.items : []);
4053
4256
  const items = (value ?? []).map(projectTrackChangesItem).filter((item) => item != null).filter((item) => {
@@ -4070,7 +4273,7 @@ function createSuperDocUI(options) {
4070
4273
  }
4071
4274
  const publicIdItems = allStoryItems ?? items;
4072
4275
  const selectionIdContext = buildStoryScopedTrackedChangeIdContext(publicIdItems, selectionStory(selection$1));
4073
- const selectionActiveChangeIds = postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
4276
+ const selectionActiveChangeIds = allTrackedChangesResolvedToken === token ? [] : postDecisionIds ? selection$1.activeChangeIds.filter((id) => !postDecisionIds.has(id)) : selection$1.activeChangeIds;
4074
4277
  const selectionPublicChangeIds = selectionActiveChangeIds.map((id) => selectionIdContext.toPublicId(id) ?? id);
4075
4278
  const explicitActiveIdContext = explicitActiveChange?.story ? buildStoryScopedTrackedChangeIdContext(publicIdItems, explicitActiveChange.story) : buildTrackedChangeIdContext(publicIdItems);
4076
4279
  const explicitActiveId = explicitActiveChange ? explicitActiveIdContext.toPublicId(explicitActiveChange.id) ?? explicitActiveChange.id : null;
@@ -5833,6 +6036,20 @@ function createSuperDocUI(options) {
5833
6036
  try {
5834
6037
  const off = next.subscribe((event) => {
5835
6038
  const type = event?.type;
6039
+ if (type === "review-mutation:started") {
6040
+ beginUiReviewMutation(event.reviewMutation?.token);
6041
+ return;
6042
+ }
6043
+ if (type === "review-mutation:aborted") {
6044
+ settleUiReviewMutation(event.reviewMutation?.token);
6045
+ scheduleAsyncRefresh();
6046
+ return;
6047
+ }
6048
+ if (type === "mutation:rejected" && event.reviewMutation) {
6049
+ settleUiReviewMutation(event.reviewMutation.token);
6050
+ scheduleAsyncRefresh();
6051
+ }
6052
+ if (type === "mutation:committed" && event.reviewMutation) settleUiReviewMutation(event.reviewMutation.token);
5836
6053
  if (type === "source:complete" || type === "source:signals-complete") {
5837
6054
  if (authoritativeTrackChangesPendingToken !== null) {
5838
6055
  clearAuthoritativeTrackChangesRetry();
@@ -5848,6 +6065,13 @@ function createSuperDocUI(options) {
5848
6065
  if (type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
5849
6066
  const impact = type === "mutation:committed" ? getV2TrackedChangeMutationImpact(event) : null;
5850
6067
  const supersedesPendingReviewReconcile = type === "mutation:committed" && reviewMutationReconciler.getPendingIds().size > 0;
6068
+ if (impact?.allResolved) {
6069
+ reviewMutationReconciler.reset();
6070
+ replaceTrackedChangeItemsInCache([]);
6071
+ authoritativeTrackChangesPendingToken = null;
6072
+ publishAllTrackedChangesResolved(event.receipt);
6073
+ return;
6074
+ }
5851
6075
  if (impact?.removedIds.size) markPostDecisionTrackChanges(new Set(impact.removedIds), event.receipt);
5852
6076
  const authoritativeHistoryImpact = impact?.reconcileMode === "authoritative" && impact.upsertIds.size > 0;
5853
6077
  if (authoritativeHistoryImpact) {
@@ -6081,7 +6305,7 @@ function createSuperDocUI(options) {
6081
6305
  }
6082
6306
  function resolveTrackDecisionTarget(command, payload) {
6083
6307
  if (command.scope === "all") return {
6084
- target: { scope: "all" },
6308
+ target: { kind: "all" },
6085
6309
  changeId: null
6086
6310
  };
6087
6311
  if (typeof payload === "string" && payload.length > 0) return {
@@ -6327,13 +6551,11 @@ function createSuperDocUI(options) {
6327
6551
  };
6328
6552
  const finalizeCommandSettlement = (promise, onSettled) => promise.then((settled) => {
6329
6553
  onSettled?.(settled);
6330
- invalidateDocumentContent();
6331
- recompute();
6554
+ invalidateAfterCommandSettlement();
6332
6555
  return settled;
6333
6556
  }, () => {
6334
6557
  onSettled?.(false);
6335
- invalidateDocumentContent();
6336
- recompute();
6558
+ invalidateAfterCommandSettlement();
6337
6559
  return false;
6338
6560
  });
6339
6561
  const settleCommandExecution = (result, onSettled) => {
@@ -6356,8 +6578,7 @@ function createSuperDocUI(options) {
6356
6578
  }
6357
6579
  onSettled?.(settled);
6358
6580
  lastCommandSettlement = Promise.resolve(settled);
6359
- invalidateDocumentContent();
6360
- recompute();
6581
+ invalidateAfterCommandSettlement();
6361
6582
  return settled;
6362
6583
  };
6363
6584
  const normalizeWorkflowReceipt = (value, fallback) => {
@@ -7519,6 +7740,14 @@ function createSuperDocUI(options) {
7519
7740
  if (typeof helper?.apply !== "function") return { reason: SUPERDOC_UI_REASONS.hostCapabilityUnavailable };
7520
7741
  return { helper };
7521
7742
  };
7743
+ const activateContentControlChrome = (id) => {
7744
+ const host = getHost();
7745
+ if (typeof host?.getHandles !== "function") return;
7746
+ try {
7747
+ const contentControls$1 = (host.getHandles()?.editing)?.contentControls;
7748
+ if (typeof contentControls$1?.activate === "function") contentControls$1.activate({ id });
7749
+ } catch {}
7750
+ };
7522
7751
  const selection = {
7523
7752
  get: selectionSnap.get,
7524
7753
  getSnapshot: selectionSnap.getSnapshot,
@@ -7778,10 +8007,14 @@ function createSuperDocUI(options) {
7778
8007
  const op = commentsApi?.create;
7779
8008
  if (typeof op !== "function") return failedReceipt("comments.create is unavailable.");
7780
8009
  const fallback = failedReceipt("comments.create failed.");
7781
- return safeCall(() => settleWorkflowReceipt(op.call(commentsApi, {
7782
- target: capture.target ?? capture.selectionTarget,
7783
- text: input.text
7784
- }), fallback), fallback);
8010
+ return safeCall(() => {
8011
+ const target = capture && typeof capture === "object" ? capture.target ?? capture.selectionTarget : null;
8012
+ if (target == null) return failedReceipt("A range selection is required to comment.", "NO_SELECTION");
8013
+ return settleWorkflowReceipt(op.call(commentsApi, {
8014
+ target,
8015
+ text: input.text
8016
+ }), fallback);
8017
+ }, fallback);
7785
8018
  },
7786
8019
  createFromSelection: (input) => {
7787
8020
  const refusal = commentWriteRefusal();
@@ -7813,6 +8046,18 @@ function createSuperDocUI(options) {
7813
8046
  text: input.text
7814
8047
  }), fallback), fallback);
7815
8048
  },
8049
+ edit: (commentId, input) => {
8050
+ const refusal = commentWriteRefusal();
8051
+ if (refusal) return refusal;
8052
+ const commentsApi = getDoc()?.comments;
8053
+ const op = commentsApi?.patch;
8054
+ if (typeof op !== "function") return failedReceipt("comments.patch is unavailable.");
8055
+ const fallback = failedReceipt("comments.patch failed.");
8056
+ return safeCall(() => settleWorkflowReceipt(op.call(commentsApi, {
8057
+ commentId,
8058
+ text: input.text
8059
+ }), fallback), fallback);
8060
+ },
7816
8061
  resolve: (commentId) => patchCommentStatus(commentId, "resolved"),
7817
8062
  reopen: (commentId) => patchCommentStatus(commentId, "active"),
7818
8063
  delete: (commentId) => {
@@ -7953,8 +8198,8 @@ function createSuperDocUI(options) {
7953
8198
  },
7954
8199
  accept: (changeId) => executeTrackDecision("accept", changeId),
7955
8200
  reject: (changeId) => executeTrackDecision("reject", changeId),
7956
- acceptAll: () => executeTrackDecisionTarget("accept", { scope: "all" }, null),
7957
- rejectAll: () => executeTrackDecisionTarget("reject", { scope: "all" }, null),
8201
+ acceptAll: () => executeTrackDecisionTarget("accept", { kind: "all" }, null),
8202
+ rejectAll: () => executeTrackDecisionTarget("reject", { kind: "all" }, null),
7958
8203
  next: () => navigateTrackChange(1),
7959
8204
  previous: () => navigateTrackChange(-1),
7960
8205
  navigateNext: () => navigateAndScroll(1),
@@ -8108,7 +8353,7 @@ function createSuperDocUI(options) {
8108
8353
  const callTrackDecisionTarget = (kind, target, changeId, story) => {
8109
8354
  if (reviewMutationsAreReadOnly()) return false;
8110
8355
  const tcApi = getDoc()?.trackChanges;
8111
- const isAllTarget = target.scope === "all";
8356
+ const isAllTarget = target.kind === "all" || target.scope === "all";
8112
8357
  const isRangeTarget = target.kind === "range";
8113
8358
  const isMultiIdTarget = target.kind === "ids";
8114
8359
  if (bulkTrackDecisionBlockedReason({
@@ -8211,6 +8456,7 @@ function createSuperDocUI(options) {
8211
8456
  success: false,
8212
8457
  reason: "not-reachable"
8213
8458
  };
8459
+ activateContentControlChrome(id);
8214
8460
  return { success: true };
8215
8461
  }
8216
8462
  };
@@ -9158,6 +9404,7 @@ function createSuperDocUI(options) {
9158
9404
  const destroy = () => {
9159
9405
  if (disposed) return;
9160
9406
  disposed = true;
9407
+ releaseSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost, uiTrackedChangesCatalogState);
9161
9408
  reviewMutationReconciler.reset();
9162
9409
  clearAuthoritativeTrackChangesRetry();
9163
9410
  if (foregroundAsyncRetryTimer) {
@@ -9414,4 +9661,4 @@ var DEFAULT_FONT_SIZE_OPTIONS = [
9414
9661
  function commandIsActive(descriptor, selection) {
9415
9662
  return descriptor.activeMark ? selection.activeMarks.includes(descriptor.activeMark) : false;
9416
9663
  }
9417
- export { createV2ReviewMutationReconciler as a, isV2EditableTextMutationEvent as i, shallowEqual as n, getV2TrackedChangeMutationImpact as o, BUILT_IN_COMMAND_IDS as r, composeAuthorColorResolver as s, createSuperDocUI as t };
9664
+ export { createV2ReviewMutationReconciler as a, DOM_CLASS_NAMES as c, isV2EditableTextMutationEvent as i, shallowEqual as n, getV2TrackedChangeMutationImpact as o, BUILT_IN_COMMAND_IDS as r, composeAuthorColorResolver as s, createSuperDocUI as t };