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
package/dist/superdoc.cjs CHANGED
@@ -4,9 +4,9 @@ const require_blank_docx = require("./chunks/blank-docx-DP8RUPW-.cjs");
4
4
  const require_eventemitter3 = require("./chunks/eventemitter3-DqY4aSMf.cjs");
5
5
  const require_uuid = require("./chunks/uuid-CFp0WGVU.cjs");
6
6
  const require_jszip = require("./chunks/jszip-Cs9JBLlJ.cjs");
7
- const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-BTwbGDKw.cjs");
8
- const require_constants = require("./chunks/constants-sbCZ2O_A.cjs");
9
- const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-DXdWuTzm.cjs");
7
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-ByvmsAAG.cjs");
8
+ const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-CZ1Nl59K.cjs");
9
+ const require_constants = require("./chunks/constants-D7TNtyJd.cjs");
10
10
  let vue = require("vue");
11
11
  vue = require_rolldown_runtime.__toESM(vue);
12
12
  require("y-websocket");
@@ -6327,6 +6327,7 @@ function createStubReviewHydrationController() {
6327
6327
  setContext() {},
6328
6328
  onRenderReadiness() {},
6329
6329
  hydrateNow() {},
6330
+ reconcileInBackground() {},
6330
6331
  invalidate() {},
6331
6332
  reset() {},
6332
6333
  getDiagnostics() {
@@ -6526,6 +6527,8 @@ var COMMENT_DRAFT_BLOCK_OPEN_TAG = /<(?:p|div|li|blockquote|pre|h[1-6])(?:\s[^>]
6526
6527
  var COMMENT_DRAFT_BLOCK_CLOSE_TAG = /<\/(?:p|div|li|blockquote|pre|h[1-6])\s*>/gi;
6527
6528
  var COMMENT_DRAFT_ANY_TAG = /<\/?[A-Za-z][A-Za-z0-9:-]*(?:\s[^>]*)?\s*\/?>/g;
6528
6529
  var COMMENT_DRAFT_ENTITY = /&(#x[0-9a-fA-F]+|#\d+|[a-zA-Z][a-zA-Z0-9]+);/g;
6530
+ var TRACKED_CHANGE_BACKGROUND_RECONCILE_BATCH_SIZE = 50;
6531
+ var TRACKED_CHANGE_BACKGROUND_RECONCILE_YIELD_TIMEOUT_MS = 50;
6529
6532
  var COMMENT_DRAFT_NAMED_ENTITIES = {
6530
6533
  amp: "&",
6531
6534
  apos: "'",
@@ -6542,6 +6545,13 @@ var shallowEqual = (a, b) => {
6542
6545
  if (aKeys.length !== bKeys.length) return false;
6543
6546
  return aKeys.every((key) => Object.prototype.hasOwnProperty.call(b, key) && Object.is(a[key], b[key]));
6544
6547
  };
6548
+ var yieldForTrackedChangeBackgroundReconcile = () => new Promise((resolve) => {
6549
+ if (typeof globalThis.requestIdleCallback === "function") {
6550
+ globalThis.requestIdleCallback(resolve, { timeout: TRACKED_CHANGE_BACKGROUND_RECONCILE_YIELD_TIMEOUT_MS });
6551
+ return;
6552
+ }
6553
+ setTimeout(resolve, 0);
6554
+ });
6545
6555
  var normalizeTrackedChangeDetailLines = (lines) => {
6546
6556
  if (!Array.isArray(lines)) return null;
6547
6557
  const normalized = lines.filter((line) => line && typeof line === "object").map((line) => ({
@@ -6728,8 +6738,17 @@ const useCommentsStore = defineStore("comments", () => {
6728
6738
  return viewingVisibility.commentsVisible || viewingVisibility.trackChangesVisible;
6729
6739
  });
6730
6740
  const v2CommentsAdapter = (0, vue.shallowRef)(null);
6741
+ const v2CommentSyncGenerations = /* @__PURE__ */ new WeakMap();
6742
+ const commentSyncGeneration = (adapter) => v2CommentSyncGenerations.get(adapter) ?? 0;
6743
+ const supersedeCommentSyncGeneration = (adapter) => {
6744
+ if (!adapter || typeof adapter !== "object" && typeof adapter !== "function") return 0;
6745
+ const next = commentSyncGeneration(adapter) + 1;
6746
+ v2CommentSyncGenerations.set(adapter, next);
6747
+ return next;
6748
+ };
6731
6749
  const setV2CommentsAdapter = (adapter) => {
6732
6750
  v2CommentsAdapter.value = adapter ?? null;
6751
+ if (adapter && !v2CommentSyncGenerations.has(adapter)) v2CommentSyncGenerations.set(adapter, 0);
6733
6752
  };
6734
6753
  const getV2CommentsAdapter = (superdoc) => {
6735
6754
  const fromFacade = superdoc?.activeEditor?.v2Comments ?? null;
@@ -6738,14 +6757,27 @@ const useCommentsStore = defineStore("comments", () => {
6738
6757
  };
6739
6758
  const isV2EditorActive = (superdoc) => superdoc?.activeEditor?.editorVersion === 2 || v2CommentsAdapter.value !== null;
6740
6759
  const v2TrackedChangesAdapter = (0, vue.shallowRef)(null);
6760
+ const v2TrackedChangeSyncGenerations = /* @__PURE__ */ new WeakMap();
6761
+ const trackedChangeSyncGeneration = (adapter) => v2TrackedChangeSyncGenerations.get(adapter) ?? 0;
6762
+ const supersedeTrackedChangeSyncGeneration = (adapter) => {
6763
+ if (!adapter || typeof adapter !== "object" && typeof adapter !== "function") return 0;
6764
+ const next = trackedChangeSyncGeneration(adapter) + 1;
6765
+ v2TrackedChangeSyncGenerations.set(adapter, next);
6766
+ return next;
6767
+ };
6741
6768
  const setV2TrackedChangesAdapter = (adapter) => {
6742
6769
  v2TrackedChangesAdapter.value = adapter ?? null;
6770
+ if (adapter && !v2TrackedChangeSyncGenerations.has(adapter)) v2TrackedChangeSyncGenerations.set(adapter, 0);
6743
6771
  };
6744
6772
  const getV2TrackedChangesAdapter = (superdoc) => {
6745
6773
  const fromFacade = superdoc?.activeEditor?.v2TrackedChanges ?? null;
6746
6774
  if (fromFacade) return fromFacade;
6747
6775
  return v2TrackedChangesAdapter.value;
6748
6776
  };
6777
+ const supersedeV2ReviewHydration = ({ commentsAdapter, trackedChangesAdapter } = {}) => ({
6778
+ commentsGeneration: supersedeCommentSyncGeneration(commentsAdapter ?? v2CommentsAdapter.value),
6779
+ trackedChangesGeneration: supersedeTrackedChangeSyncGeneration(trackedChangesAdapter ?? v2TrackedChangesAdapter.value)
6780
+ });
6749
6781
  const init = (config = {}) => {
6750
6782
  const updatedConfig = {
6751
6783
  ...commentsConfig,
@@ -7201,7 +7233,7 @@ const useCommentsStore = defineStore("comments", () => {
7201
7233
  }
7202
7234
  activeEditor?.commands?.setActiveComment({ commentId: activeComment.value });
7203
7235
  };
7204
- const handleTrackedChangeUpdate = ({ superdoc, params, broadcastChanges = true, documentState = void 0 }) => {
7236
+ const handleTrackedChangeUpdate = ({ superdoc, params, broadcastChanges = true, documentState = void 0, trackedChangeIdentityIndex = null }) => {
7205
7237
  const span = startInteractionSpan("store.trackedChanges.handleUpdate", "store-reconciliation", {
7206
7238
  event: params?.event ?? null,
7207
7239
  changeId: params?.changeId ?? null,
@@ -7304,6 +7336,17 @@ const useCommentsStore = defineStore("comments", () => {
7304
7336
  if (normalizedAnchorKey && commentAnchorKey) return commentAnchorKey === normalizedAnchorKey;
7305
7337
  return false;
7306
7338
  };
7339
+ if (trackedChangeIdentityIndex) {
7340
+ const candidates = trackedChangeIdentityIndex.candidates({
7341
+ changeId: normalizedChangeId,
7342
+ importedId: normalizedImportedId,
7343
+ anchorKey: normalizedAnchorKey,
7344
+ canonicalId: normalizedTrackedChangeCanonicalId,
7345
+ positionAliases: normalizedTrackedChangePositionAliases
7346
+ });
7347
+ for (const trackedComment of candidates) if (matchesId(trackedComment) && (!normalizedDocumentId || belongsToTrackedChangeSyncDocument(trackedComment, normalizedDocumentId))) return trackedComment;
7348
+ return null;
7349
+ }
7307
7350
  if (normalizedDocumentId) return commentsList.value.find((trackedComment) => matchesId(trackedComment) && belongsToTrackedChangeSyncDocument(trackedComment, normalizedDocumentId));
7308
7351
  return commentsList.value.find(matchesId);
7309
7352
  };
@@ -7372,6 +7415,7 @@ const useCommentsStore = defineStore("comments", () => {
7372
7415
  const existing = findTrackedChangeById();
7373
7416
  if (existing) {
7374
7417
  if (!updateExistingTrackedChange(existing)) return;
7418
+ trackedChangeIdentityIndex?.add(existing);
7375
7419
  emitTrackedChangeEvent({
7376
7420
  type: COMMENT_EVENTS.UPDATE,
7377
7421
  comment: getCommentEventPayload(existing)
@@ -7383,10 +7427,12 @@ const useCommentsStore = defineStore("comments", () => {
7383
7427
  comment,
7384
7428
  broadcastChanges
7385
7429
  });
7430
+ trackedChangeIdentityIndex?.add(comment);
7386
7431
  } else if (event === "update") {
7387
7432
  const existingTrackedChange = findTrackedChangeById();
7388
7433
  if (!existingTrackedChange) return;
7389
7434
  if (!updateExistingTrackedChange(existingTrackedChange)) return;
7435
+ trackedChangeIdentityIndex?.add(existingTrackedChange);
7390
7436
  emitTrackedChangeEvent({
7391
7437
  type: COMMENT_EVENTS.UPDATE,
7392
7438
  comment: getCommentEventPayload(existingTrackedChange)
@@ -8119,7 +8165,7 @@ const useCommentsStore = defineStore("comments", () => {
8119
8165
  if (!adapter) return false;
8120
8166
  return v2TrackedChangesAdapter.value === adapter;
8121
8167
  };
8122
- const applyReviewSnapshotFromV2 = ({ superdoc, commentsAdapter, trackedChangesAdapter, documentId, commentItems, trackedChangeItems, trackedList, patch } = {}) => withInteractionSpan("store.reviewSnapshot.apply", "store-reconciliation", {
8168
+ const applyReviewSnapshotFromV2 = ({ superdoc, commentsAdapter, trackedChangesAdapter, documentId, commentItems, trackedChangeItems, trackedList, sourceCoverageRevision, evaluatedRevision, patch } = {}) => withInteractionSpan("store.reviewSnapshot.apply", "store-reconciliation", {
8123
8169
  commentItemCount: Array.isArray(commentItems) ? commentItems.length : null,
8124
8170
  trackedItemCount: Array.isArray(trackedChangeItems) ? trackedChangeItems.length : null
8125
8171
  }, () => {
@@ -8157,11 +8203,28 @@ const useCommentsStore = defineStore("comments", () => {
8157
8203
  ok: false,
8158
8204
  reason: "adapter-mapper-missing"
8159
8205
  };
8206
+ let effectiveCommentItems = commentItems;
8207
+ let commentItemsArePartial = false;
8208
+ if (typeof commentsAdapter.seedReviewCatalog === "function") {
8209
+ const seeded = commentsAdapter.seedReviewCatalog(commentItems, {
8210
+ sourceCoverageRevision,
8211
+ evaluatedRevision
8212
+ });
8213
+ if (seeded?.ok !== true) return {
8214
+ ok: false,
8215
+ reason: seeded?.reason ?? "comment-catalog-seed-failed"
8216
+ };
8217
+ const selected = commentsAdapter.selectVisibleReviewComments?.();
8218
+ if (selected?.ok === true && Array.isArray(selected.items) && (!Array.isArray(selected.unresolvedIds) || selected.unresolvedIds.length === 0)) {
8219
+ effectiveCommentItems = selected.items;
8220
+ commentItemsArePartial = true;
8221
+ }
8222
+ }
8160
8223
  const fileType = (normalizedDocumentId ? superdocStore.getDocument(normalizedDocumentId) : null)?.type ?? null;
8161
8224
  let preparedInputs;
8162
8225
  let preparedParams;
8163
8226
  try {
8164
- preparedInputs = commentItems.filter((item) => !isSyntheticTrackedChangeCommentLaneItem(item)).map((item) => commentsAdapter.mapV2CommentToUseCommentInput(item, {
8227
+ preparedInputs = effectiveCommentItems.filter((item) => !isSyntheticTrackedChangeCommentLaneItem(item)).map((item) => commentsAdapter.mapV2CommentToUseCommentInput(item, {
8165
8228
  fileId: normalizedDocumentId,
8166
8229
  fileType
8167
8230
  })).filter(Boolean);
@@ -8190,8 +8253,9 @@ const useCommentsStore = defineStore("comments", () => {
8190
8253
  superdoc,
8191
8254
  adapter: commentsAdapter,
8192
8255
  documentId: normalizedDocumentId,
8193
- items: commentItems,
8194
- preparedInputs
8256
+ items: effectiveCommentItems,
8257
+ preparedInputs,
8258
+ pruneStale: !commentItemsArePartial
8195
8259
  });
8196
8260
  });
8197
8261
  return {
@@ -8200,15 +8264,31 @@ const useCommentsStore = defineStore("comments", () => {
8200
8264
  trackedItems: preparedParams.length
8201
8265
  };
8202
8266
  });
8203
- const hydrateCommentsFromV2 = async ({ superdoc, adapter, documentId } = {}) => withInteractionSpan("store.comments.hydrateFromV2", "comments-list", { documentId: documentId ?? null }, async () => {
8267
+ const hydrateCommentsFromV2 = async ({ superdoc, adapter, documentId, trackedChangesListMode = "all", isCurrent, signal, hydrationGeneration } = {}) => withInteractionSpan("store.comments.hydrateFromV2", "comments-list", { documentId: documentId ?? null }, async () => {
8204
8268
  const effectiveAdapter = adapter ?? getV2CommentsAdapter(superdoc);
8205
- if (!effectiveAdapter || typeof effectiveAdapter.refresh !== "function") return {
8269
+ const visibleWindow = trackedChangesListMode === "visible-window";
8270
+ const read = visibleWindow ? effectiveAdapter?.selectVisibleReviewComments : effectiveAdapter?.refresh;
8271
+ if (!effectiveAdapter || typeof read !== "function") return {
8206
8272
  ok: false,
8207
8273
  reason: "adapter-missing"
8208
8274
  };
8275
+ const hydrationIsCurrent = () => isCurrent?.() !== false && isCurrentV2CommentsAdapter(effectiveAdapter);
8276
+ if (!hydrationIsCurrent()) return {
8277
+ ok: false,
8278
+ reason: "adapter-stale"
8279
+ };
8280
+ if (signal?.aborted) return {
8281
+ ok: false,
8282
+ reason: "review-hydration-superseded",
8283
+ lateResultDropped: false
8284
+ };
8285
+ const syncGeneration = commentSyncGeneration(effectiveAdapter);
8209
8286
  let result;
8210
8287
  try {
8211
- result = await effectiveAdapter.refresh();
8288
+ const refreshOptions = {};
8289
+ if (signal) refreshOptions.signal = signal;
8290
+ if (typeof hydrationGeneration === "number") refreshOptions.hydrationGeneration = hydrationGeneration;
8291
+ result = Object.keys(refreshOptions).length > 0 ? await read.call(effectiveAdapter, refreshOptions) : await read.call(effectiveAdapter);
8212
8292
  } catch (err) {
8213
8293
  return {
8214
8294
  ok: false,
@@ -8216,25 +8296,41 @@ const useCommentsStore = defineStore("comments", () => {
8216
8296
  detail: err?.message ?? String(err)
8217
8297
  };
8218
8298
  }
8219
- if (!isCurrentV2CommentsAdapter(effectiveAdapter)) return {
8299
+ if (!hydrationIsCurrent()) return {
8220
8300
  ok: false,
8221
8301
  reason: "adapter-stale"
8222
8302
  };
8303
+ if (signal?.aborted || commentSyncGeneration(effectiveAdapter) !== syncGeneration) return {
8304
+ ok: false,
8305
+ reason: "review-hydration-superseded",
8306
+ lateResultDropped: true
8307
+ };
8223
8308
  if (!result?.ok) return result;
8309
+ if (signal?.aborted || commentSyncGeneration(effectiveAdapter) !== syncGeneration) return {
8310
+ ok: false,
8311
+ reason: "review-hydration-superseded",
8312
+ lateResultDropped: true
8313
+ };
8224
8314
  reconcileCommentsFromV2({
8225
8315
  superdoc,
8226
8316
  adapter: effectiveAdapter,
8227
8317
  documentId,
8228
- items: result.items ?? []
8318
+ items: result.items ?? [],
8319
+ pruneStale: !visibleWindow,
8320
+ hydrationGeneration
8229
8321
  });
8230
8322
  return {
8231
8323
  ok: true,
8232
- items: result.items ?? []
8324
+ items: result.items ?? [],
8325
+ reconciled: true,
8326
+ ...typeof hydrationGeneration === "number" ? { hydrationGeneration } : {},
8327
+ ...result.visibleWindowSource != null ? { visibleWindowSource: result.visibleWindowSource } : {}
8233
8328
  };
8234
8329
  });
8235
- const reconcileCommentsFromV2 = ({ superdoc, adapter, documentId, items, preparedInputs = null } = {}) => withInteractionSpan("store.comments.reconcile", "store-reconciliation", {
8330
+ const reconcileCommentsFromV2 = ({ superdoc, adapter, documentId, items, preparedInputs = null, pruneStale = true, hydrationGeneration } = {}) => withInteractionSpan("store.comments.reconcile", "store-reconciliation", {
8236
8331
  documentId: documentId ?? null,
8237
- itemCount: Array.isArray(items) ? items.length : null
8332
+ itemCount: Array.isArray(items) ? items.length : null,
8333
+ hydrationGeneration: hydrationGeneration ?? null
8238
8334
  }, () => {
8239
8335
  if (!adapter || !Array.isArray(items)) return { added: null };
8240
8336
  if (!isCurrentV2CommentsAdapter(adapter)) return {
@@ -8349,6 +8445,7 @@ const useCommentsStore = defineStore("comments", () => {
8349
8445
  seenIncoming.add(cid);
8350
8446
  nextList.push(existing);
8351
8447
  }
8448
+ if (!input && !pruneStale) nextList.push(existing);
8352
8449
  }
8353
8450
  for (const [cid, input] of incomingByCommentId.entries()) {
8354
8451
  if (seenIncoming.has(cid)) continue;
@@ -9008,7 +9105,7 @@ const useCommentsStore = defineStore("comments", () => {
9008
9105
  let removed = false;
9009
9106
  const targetIndex = targetComment ? commentsList.value.indexOf(targetComment) : -1;
9010
9107
  const targetIds = targetComment?.trackedChange ? collectTrackedChangeDecisionIds(targetComment) : /* @__PURE__ */ new Set();
9011
- if (targetIndex >= 0 && belongsToTrackedChangeSyncDocument(targetComment, normalizedDocumentId) && Array.from(normalizedDecidedIds).some((id) => targetIds.has(id))) {
9108
+ if (targetIndex >= 0 && belongsToTrackedChangeSyncDocument(targetComment, normalizedDocumentId) && Array.from(targetIds).some((id) => normalizedDecidedIds.has(id))) {
9012
9109
  targetIds.forEach((id) => removedIds.add(id));
9013
9110
  commentsList.value.splice(targetIndex, 1);
9014
9111
  removed = true;
@@ -9016,7 +9113,7 @@ const useCommentsStore = defineStore("comments", () => {
9016
9113
  if (!comment?.trackedChange) return true;
9017
9114
  if (!belongsToTrackedChangeSyncDocument(comment, normalizedDocumentId)) return true;
9018
9115
  const ids = collectTrackedChangeDecisionIds(comment);
9019
- if (!Array.from(normalizedDecidedIds).some((id) => ids.has(id))) return true;
9116
+ if (!Array.from(ids).some((id) => normalizedDecidedIds.has(id))) return true;
9020
9117
  removed = true;
9021
9118
  ids.forEach((id) => removedIds.add(id));
9022
9119
  return false;
@@ -9032,6 +9129,31 @@ const useCommentsStore = defineStore("comments", () => {
9032
9129
  removedIds
9033
9130
  };
9034
9131
  };
9132
+ const clearAllResolvedTrackedChangeRows = ({ adapter, documentId } = {}) => {
9133
+ const normalizedDocumentId = normalizeCommentId(documentId);
9134
+ if (!adapter || !normalizedDocumentId) return {
9135
+ removed: 0,
9136
+ removedIds: /* @__PURE__ */ new Set()
9137
+ };
9138
+ supersedeTrackedChangeSyncGeneration(adapter);
9139
+ const removedIds = /* @__PURE__ */ new Set();
9140
+ const activeId = normalizeCommentId(activeComment.value);
9141
+ let activeWasRemoved = false;
9142
+ const next = commentsList.value.filter((comment) => {
9143
+ if (!comment?.trackedChange || !belongsToTrackedChangeSyncDocument(comment, normalizedDocumentId)) return true;
9144
+ const aliases = collectTrackedChangeDecisionIds(comment);
9145
+ aliases.forEach((id) => removedIds.add(id));
9146
+ if (activeId && aliases.has(activeId)) activeWasRemoved = true;
9147
+ return false;
9148
+ });
9149
+ const removed = commentsList.value.length - next.length;
9150
+ if (removed > 0) commentsList.value = next;
9151
+ if (activeWasRemoved) clearActiveCommentSelection();
9152
+ return {
9153
+ removed,
9154
+ removedIds
9155
+ };
9156
+ };
9035
9157
  const clearV2ActiveTrackedChangeTarget = (adapter, decidedId) => {
9036
9158
  if (!decidedId || typeof adapter?.clearActiveTrackedChangeTargetIfMatches !== "function") return;
9037
9159
  try {
@@ -9242,7 +9364,7 @@ const useCommentsStore = defineStore("comments", () => {
9242
9364
  success: Boolean(command(id))
9243
9365
  };
9244
9366
  };
9245
- const hydrateTrackedChangesFromV2 = async ({ superdoc, adapter, documentId, trackedChangesListMode = "all", refreshReason, blocking } = {}) => withInteractionSpan("store.trackedChanges.hydrateFromV2", "tracked-change-list", {
9367
+ const hydrateTrackedChangesFromV2 = async ({ superdoc, adapter, documentId, trackedChangesListMode = "all", refreshReason, blocking, isCurrent, targetIds, reconciliationBatchSize = TRACKED_CHANGE_BACKGROUND_RECONCILE_BATCH_SIZE, signal, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.hydrateFromV2", "tracked-change-list", {
9246
9368
  documentId: documentId ?? null,
9247
9369
  trackedChangesListMode,
9248
9370
  refreshReason: refreshReason ?? null,
@@ -9253,11 +9375,49 @@ const useCommentsStore = defineStore("comments", () => {
9253
9375
  ok: false,
9254
9376
  reason: "adapter-missing"
9255
9377
  };
9378
+ const hydrationIsCurrent = () => isCurrent?.() !== false && isCurrentV2TrackedChangesAdapter(effectiveAdapter);
9379
+ if (!hydrationIsCurrent()) return {
9380
+ ok: false,
9381
+ reason: "adapter-stale"
9382
+ };
9383
+ const syncGeneration = trackedChangeSyncGeneration(effectiveAdapter);
9384
+ const hydrationCanContinue = () => hydrationIsCurrent() && !signal?.aborted && trackedChangeSyncGeneration(effectiveAdapter) === syncGeneration;
9385
+ if (signal?.aborted) return {
9386
+ ok: false,
9387
+ reason: "review-hydration-superseded",
9388
+ lateResultDropped: false
9389
+ };
9390
+ const incrementalLiveIds = /* @__PURE__ */ new Set();
9391
+ const incrementalLiveAnchorKeys = /* @__PURE__ */ new Set();
9392
+ let incrementalPagesApplied = 0;
9393
+ let incrementalItemsApplied = 0;
9256
9394
  let result;
9257
9395
  try {
9258
9396
  const listOptions = { mode: trackedChangesListMode };
9397
+ if (Array.isArray(targetIds)) listOptions.targetIds = targetIds;
9259
9398
  if (refreshReason != null) listOptions.refreshReason = refreshReason;
9260
9399
  if (typeof blocking === "boolean") listOptions.blocking = blocking;
9400
+ if (signal) listOptions.signal = signal;
9401
+ if (typeof hydrationGeneration === "number") listOptions.hydrationGeneration = hydrationGeneration;
9402
+ if (trackedChangesListMode === "background-reconcile") {
9403
+ listOptions.shouldContinue = hydrationCanContinue;
9404
+ listOptions.onPage = async (page) => {
9405
+ if (!hydrationCanContinue()) return;
9406
+ const pageItems = Array.isArray(page?.items) ? page.items : [];
9407
+ if (!reconcileTrackedChangesFromV2({
9408
+ superdoc,
9409
+ adapter: effectiveAdapter,
9410
+ documentId,
9411
+ items: pageItems,
9412
+ pruneStale: false,
9413
+ liveIds: incrementalLiveIds,
9414
+ liveAnchorKeys: incrementalLiveAnchorKeys,
9415
+ hydrationGeneration
9416
+ }) || !hydrationCanContinue()) return;
9417
+ incrementalPagesApplied += 1;
9418
+ incrementalItemsApplied += pageItems.length;
9419
+ };
9420
+ }
9261
9421
  result = await effectiveAdapter.listTrackedChanges(listOptions);
9262
9422
  } catch (err) {
9263
9423
  return {
@@ -9266,22 +9426,68 @@ const useCommentsStore = defineStore("comments", () => {
9266
9426
  detail: err?.message ?? String(err)
9267
9427
  };
9268
9428
  }
9269
- if (!isCurrentV2TrackedChangesAdapter(effectiveAdapter)) return {
9429
+ if (!hydrationIsCurrent()) return {
9270
9430
  ok: false,
9271
9431
  reason: "adapter-stale"
9272
9432
  };
9433
+ if (trackedChangeSyncGeneration(effectiveAdapter) !== syncGeneration) return {
9434
+ ok: false,
9435
+ reason: "review-hydration-superseded",
9436
+ lateResultDropped: true
9437
+ };
9438
+ if (signal?.aborted) return {
9439
+ ok: false,
9440
+ reason: "review-hydration-superseded",
9441
+ lateResultDropped: true
9442
+ };
9273
9443
  if (!result?.ok) return result;
9274
9444
  const pruneStale = !(trackedChangesListMode === "startup-page" || trackedChangesListMode === "interaction-prime" || trackedChangesListMode === "visible-window") && result.visibleWindowSource == null && result.complete === true && result.sourceCoverageComplete === true;
9275
- reconcileTrackedChangesFromV2({
9445
+ if (signal?.aborted || trackedChangeSyncGeneration(effectiveAdapter) !== syncGeneration) return {
9446
+ ok: false,
9447
+ reason: "review-hydration-superseded",
9448
+ lateResultDropped: true
9449
+ };
9450
+ if (trackedChangesListMode === "background-reconcile") if (incrementalPagesApplied > 0) {
9451
+ if (!hydrationCanContinue()) return {
9452
+ ok: false,
9453
+ reason: "reconciliation-stale"
9454
+ };
9455
+ const effectiveDocumentId = documentId ?? effectiveAdapter.documentId ?? superdoc?.activeEditor?.documentId ?? null;
9456
+ if (pruneStale && effectiveDocumentId) withInteractionSpan("store.trackedChanges.reconcile.finalPrune", "store-reconciliation", {
9457
+ documentId: effectiveDocumentId,
9458
+ liveIds: incrementalLiveIds.size,
9459
+ liveAnchorKeys: incrementalLiveAnchorKeys.size
9460
+ }, () => {
9461
+ if (!hydrationCanContinue()) return;
9462
+ pruneStaleTrackedChangeComments(incrementalLiveIds, incrementalLiveAnchorKeys, String(effectiveDocumentId), superdoc, { broadcastChanges: false });
9463
+ });
9464
+ } else {
9465
+ const reconcileResult = await reconcileTrackedChangesFromV2Incrementally({
9466
+ superdoc,
9467
+ adapter: effectiveAdapter,
9468
+ documentId,
9469
+ items: result.items ?? [],
9470
+ pruneStale,
9471
+ isCurrent: hydrationIsCurrent,
9472
+ batchSize: reconciliationBatchSize,
9473
+ hydrationGeneration
9474
+ });
9475
+ if (!reconcileResult.ok) return reconcileResult;
9476
+ incrementalItemsApplied = reconcileResult.appliedItems;
9477
+ }
9478
+ else reconcileTrackedChangesFromV2({
9276
9479
  superdoc,
9277
9480
  adapter: effectiveAdapter,
9278
9481
  documentId,
9279
9482
  items: result.items ?? [],
9280
- pruneStale
9483
+ pruneStale,
9484
+ hydrationGeneration
9281
9485
  });
9282
9486
  const hydrationResult = {
9283
9487
  ok: true,
9284
- items: result.items ?? []
9488
+ items: result.items ?? [],
9489
+ reconciled: true,
9490
+ ...typeof hydrationGeneration === "number" ? { hydrationGeneration } : {}
9285
9491
  };
9286
9492
  if (typeof result.complete === "boolean") hydrationResult.complete = result.complete;
9287
9493
  if (typeof result.sourceCoverageComplete === "boolean") hydrationResult.sourceCoverageComplete = result.sourceCoverageComplete;
@@ -9289,14 +9495,28 @@ const useCommentsStore = defineStore("comments", () => {
9289
9495
  if (result.visibleWindowFallbackReason != null) hydrationResult.visibleWindowFallbackReason = result.visibleWindowFallbackReason;
9290
9496
  if (typeof result.visibleTrackedChangeExpectedRows === "number") hydrationResult.visibleTrackedChangeExpectedRows = result.visibleTrackedChangeExpectedRows;
9291
9497
  if (typeof result.visibleTrackedChangeObservedRows === "number") hydrationResult.visibleTrackedChangeObservedRows = result.visibleTrackedChangeObservedRows;
9498
+ for (const key of [
9499
+ "visibleTrackedChangeRequestedIds",
9500
+ "visibleTrackedChangeSucceededIds",
9501
+ "visibleTrackedChangeFailedIds"
9502
+ ]) if (Array.isArray(result[key])) hydrationResult[key] = [...result[key]];
9503
+ if (Array.isArray(result.visibleWindowGetFailures)) hydrationResult.visibleWindowGetFailures = result.visibleWindowGetFailures.map((failure) => ({ ...failure }));
9292
9504
  if (typeof result.refreshReason === "string") hydrationResult.refreshReason = result.refreshReason;
9293
9505
  if (typeof result.blocking === "boolean") hydrationResult.blocking = result.blocking;
9294
9506
  if (typeof result.pageCount === "number") hydrationResult.pageCount = result.pageCount;
9507
+ if (typeof result.pagesStarted === "number") hydrationResult.pagesStarted = result.pagesStarted;
9508
+ if (typeof result.pagesCompleted === "number") hydrationResult.pagesCompleted = result.pagesCompleted;
9509
+ if (typeof result.pagesSkippedAfterAbort === "number") hydrationResult.pagesSkippedAfterAbort = result.pagesSkippedAfterAbort;
9295
9510
  if (typeof result.totalItems === "number") hydrationResult.totalItems = result.totalItems;
9296
9511
  if (typeof result.coalesced === "boolean") hydrationResult.coalesced = result.coalesced;
9512
+ if (typeof result.evaluatedRevision === "string") hydrationResult.evaluatedRevision = result.evaluatedRevision;
9513
+ if (trackedChangesListMode === "background-reconcile") {
9514
+ hydrationResult.incrementalPagesApplied = incrementalPagesApplied;
9515
+ hydrationResult.incrementalItemsApplied = incrementalItemsApplied;
9516
+ }
9297
9517
  return hydrationResult;
9298
9518
  });
9299
- const reconcileTrackedChangeMutationFromV2 = async ({ superdoc, adapter, documentId, upsertIds = [], removedIds = [] } = {}) => {
9519
+ const reconcileTrackedChangeMutationFromV2 = async ({ superdoc, adapter, documentId, upsertIds = [], removedIds = [], allResolved } = {}) => {
9300
9520
  const effectiveAdapter = adapter ?? getV2TrackedChangesAdapter(superdoc);
9301
9521
  if (!effectiveAdapter) return {
9302
9522
  ok: false,
@@ -9307,6 +9527,26 @@ const useCommentsStore = defineStore("comments", () => {
9307
9527
  reason: "adapter-stale"
9308
9528
  };
9309
9529
  const effectiveDocumentId = documentId ?? effectiveAdapter.documentId ?? superdoc?.activeEditor?.documentId ?? null;
9530
+ if (allResolved && effectiveDocumentId == null) return {
9531
+ ok: false,
9532
+ reason: "document-id-missing"
9533
+ };
9534
+ if (allResolved) return {
9535
+ ok: true,
9536
+ items: [],
9537
+ resolvedIds: [],
9538
+ unresolvedIds: [],
9539
+ allResolved: true,
9540
+ removedRows: withInteractionSpan("store.trackedChanges.allResolved", "store-reconciliation", {
9541
+ documentId: String(effectiveDocumentId),
9542
+ logicalTargetCount: allResolved.logicalTargetCount ?? null,
9543
+ physicalCarrierCount: allResolved.physicalCarrierCount ?? null
9544
+ }, () => clearAllResolvedTrackedChangeRows({
9545
+ adapter: effectiveAdapter,
9546
+ documentId: effectiveDocumentId
9547
+ })).removed
9548
+ };
9549
+ const syncGeneration = trackedChangeSyncGeneration(effectiveAdapter);
9310
9550
  const normalizedRemovedIds = new Set(Array.from(removedIds ?? []).map((id) => normalizeCommentId(id)).filter(Boolean));
9311
9551
  const normalizedUpsertIds = [...new Set(Array.from(upsertIds ?? []).map((id) => normalizeCommentId(id)).filter(Boolean))];
9312
9552
  if (normalizedRemovedIds.size > 0 && normalizedUpsertIds.length === 0 && effectiveDocumentId != null) pruneDecidedTrackedChangeRow({
@@ -9345,6 +9585,10 @@ const useCommentsStore = defineStore("comments", () => {
9345
9585
  ok: false,
9346
9586
  reason: "adapter-stale"
9347
9587
  };
9588
+ if (trackedChangeSyncGeneration(effectiveAdapter) !== syncGeneration) return {
9589
+ ok: false,
9590
+ reason: "generation-stale"
9591
+ };
9348
9592
  const resolvedIds = [];
9349
9593
  const unresolvedIds = [];
9350
9594
  const items = [];
@@ -9371,35 +9615,188 @@ const useCommentsStore = defineStore("comments", () => {
9371
9615
  failures: reads.map(({ result }) => result).filter((result) => !result?.ok)
9372
9616
  };
9373
9617
  };
9374
- const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
9618
+ const createTrackedChangeBatchIdentityIndex = (documentId) => {
9619
+ const byIdentityAlias = /* @__PURE__ */ new Map();
9620
+ const indexedRows = /* @__PURE__ */ new Set();
9621
+ let aliasLookups = 0;
9622
+ let candidateVisits = 0;
9623
+ const addAlias = (index, value, comment) => {
9624
+ const alias = normalizeCommentId(value);
9625
+ if (!alias) return;
9626
+ const bucket = index.get(alias) ?? /* @__PURE__ */ new Set();
9627
+ bucket.add(comment);
9628
+ index.set(alias, bucket);
9629
+ };
9630
+ const add = (comment) => {
9631
+ if (!comment?.trackedChange) return;
9632
+ if (documentId && !belongsToTrackedChangeSyncDocument(comment, documentId)) return;
9633
+ indexedRows.add(comment);
9634
+ addAlias(byIdentityAlias, comment.commentId, comment);
9635
+ addAlias(byIdentityAlias, comment.importedId, comment);
9636
+ addAlias(byIdentityAlias, comment.trackedChangeCanonicalId, comment);
9637
+ addAlias(byIdentityAlias, comment.trackedChangeAnchorKey, comment);
9638
+ getCommentAliasIds(comment).forEach((alias) => addAlias(byIdentityAlias, alias, comment));
9639
+ };
9640
+ commentsList.value.forEach(add);
9641
+ return {
9642
+ add,
9643
+ work: () => ({
9644
+ trackedRowsIndexed: indexedRows.size,
9645
+ invalidatedIdMembershipChecks: 0,
9646
+ incomingAliasLookups: aliasLookups,
9647
+ candidateVisits
9648
+ }),
9649
+ candidates({ changeId, importedId, anchorKey, canonicalId, positionAliases = [] } = {}) {
9650
+ const out = /* @__PURE__ */ new Set();
9651
+ const include = (value) => {
9652
+ const alias = normalizeCommentId(value);
9653
+ if (!alias) return;
9654
+ aliasLookups += 1;
9655
+ const bucket = byIdentityAlias.get(alias);
9656
+ if (!bucket) return;
9657
+ candidateVisits += bucket.size;
9658
+ bucket.forEach((comment) => out.add(comment));
9659
+ };
9660
+ new Set([
9661
+ changeId,
9662
+ importedId,
9663
+ canonicalId,
9664
+ anchorKey,
9665
+ ...positionAliases
9666
+ ]).forEach(include);
9667
+ return out;
9668
+ }
9669
+ };
9670
+ };
9671
+ const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null, liveIds: suppliedLiveIds = null, liveAnchorKeys: suppliedLiveAnchorKeys = null, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
9375
9672
  documentId: documentId ?? null,
9376
9673
  itemCount: Array.isArray(items) ? items.length : null,
9377
- pruneStale
9674
+ pruneStale,
9675
+ hydrationGeneration: hydrationGeneration ?? null
9378
9676
  }, () => {
9379
9677
  if (!adapter || !Array.isArray(items)) return;
9380
9678
  if (!isCurrentV2TrackedChangesAdapter(adapter)) return;
9381
9679
  const effectiveDocumentId = documentId ?? adapter.documentId ?? superdoc?.activeEditor?.documentId ?? null;
9382
- const liveAnchorKeys = /* @__PURE__ */ new Set();
9383
- const liveIds = /* @__PURE__ */ new Set();
9680
+ const liveAnchorKeys = suppliedLiveAnchorKeys instanceof Set ? suppliedLiveAnchorKeys : /* @__PURE__ */ new Set();
9681
+ const liveIds = suppliedLiveIds instanceof Set ? suppliedLiveIds : /* @__PURE__ */ new Set();
9682
+ let appliedCount = 0;
9683
+ const trackedChangeIdentityIndex = createTrackedChangeBatchIdentityIndex(effectiveDocumentId == null ? null : String(effectiveDocumentId));
9684
+ const identitySpan = startInteractionSpan("store.trackedChanges.batchIdentity", "store-reconciliation", { itemCount: items.length });
9384
9685
  const paramsList = Array.isArray(preparedParams) ? preparedParams : items.map((item) => adapter.mapV2TrackedChangeToCommentParams(item));
9385
- for (const params of paramsList) {
9386
- if (!params) continue;
9387
- if (params.event === "omit") {
9686
+ try {
9687
+ for (const params of paramsList) {
9688
+ if (!params) continue;
9689
+ if (params.event === "omit") {
9690
+ if (params.changeId != null) liveIds.add(String(params.changeId));
9691
+ continue;
9692
+ }
9693
+ if (effectiveDocumentId && params.documentId == null) params.documentId = effectiveDocumentId;
9388
9694
  if (params.changeId != null) liveIds.add(String(params.changeId));
9389
- continue;
9695
+ if (params.trackedChangeAnchorKey != null) liveAnchorKeys.add(String(params.trackedChangeAnchorKey));
9696
+ handleTrackedChangeUpdate({
9697
+ superdoc,
9698
+ params,
9699
+ broadcastChanges: false,
9700
+ trackedChangeIdentityIndex
9701
+ });
9702
+ appliedCount += 1;
9390
9703
  }
9391
- if (effectiveDocumentId && params.documentId == null) params.documentId = effectiveDocumentId;
9392
- if (params.changeId != null) liveIds.add(String(params.changeId));
9393
- if (params.trackedChangeAnchorKey != null) liveAnchorKeys.add(String(params.trackedChangeAnchorKey));
9394
- handleTrackedChangeUpdate({
9395
- superdoc,
9396
- params,
9397
- broadcastChanges: false
9398
- });
9704
+ } finally {
9705
+ endInteractionSpan(identitySpan, trackedChangeIdentityIndex.work());
9399
9706
  }
9400
- if (!effectiveDocumentId || !pruneStale) return;
9707
+ if (!effectiveDocumentId || !pruneStale) return {
9708
+ liveIds,
9709
+ liveAnchorKeys,
9710
+ appliedCount
9711
+ };
9401
9712
  pruneStaleTrackedChangeComments(liveIds, liveAnchorKeys, String(effectiveDocumentId), superdoc, { broadcastChanges: false });
9713
+ return {
9714
+ liveIds,
9715
+ liveAnchorKeys,
9716
+ appliedCount
9717
+ };
9402
9718
  });
9719
+ const reconcileTrackedChangesFromV2Incrementally = async ({ superdoc, adapter, documentId, items, pruneStale, isCurrent, batchSize = TRACKED_CHANGE_BACKGROUND_RECONCILE_BATCH_SIZE, hydrationGeneration } = {}) => {
9720
+ if (!adapter || !Array.isArray(items)) return {
9721
+ ok: false,
9722
+ reason: "reconcile-input-invalid"
9723
+ };
9724
+ const current = () => isCurrent?.() !== false && isCurrentV2TrackedChangesAdapter(adapter);
9725
+ if (!current()) return {
9726
+ ok: false,
9727
+ reason: "reconciliation-stale"
9728
+ };
9729
+ const effectiveBatchSize = Math.max(1, Math.floor(Number(batchSize) || TRACKED_CHANGE_BACKGROUND_RECONCILE_BATCH_SIZE));
9730
+ const effectiveDocumentId = documentId ?? adapter.documentId ?? superdoc?.activeEditor?.documentId ?? null;
9731
+ const liveIds = /* @__PURE__ */ new Set();
9732
+ const liveAnchorKeys = /* @__PURE__ */ new Set();
9733
+ let appliedItems = 0;
9734
+ let batchCount = 0;
9735
+ for (let offset = 0; offset < items.length; offset += effectiveBatchSize) {
9736
+ if (!current()) return {
9737
+ ok: false,
9738
+ reason: "reconciliation-stale",
9739
+ appliedItems,
9740
+ batchCount
9741
+ };
9742
+ const batch = items.slice(offset, offset + effectiveBatchSize);
9743
+ if (!reconcileTrackedChangesFromV2({
9744
+ superdoc,
9745
+ adapter,
9746
+ documentId: effectiveDocumentId,
9747
+ items: batch,
9748
+ pruneStale: false,
9749
+ liveIds,
9750
+ liveAnchorKeys,
9751
+ hydrationGeneration
9752
+ }) || !current()) return {
9753
+ ok: false,
9754
+ reason: "reconciliation-stale",
9755
+ appliedItems,
9756
+ batchCount
9757
+ };
9758
+ appliedItems += batch.length;
9759
+ batchCount += 1;
9760
+ if (offset + effectiveBatchSize < items.length) await yieldForTrackedChangeBackgroundReconcile();
9761
+ }
9762
+ if (!current()) return {
9763
+ ok: false,
9764
+ reason: "reconciliation-stale",
9765
+ appliedItems,
9766
+ batchCount
9767
+ };
9768
+ if (pruneStale && effectiveDocumentId) {
9769
+ withInteractionSpan("store.trackedChanges.reconcile.finalPrune", "store-reconciliation", {
9770
+ documentId: effectiveDocumentId,
9771
+ liveIds: liveIds.size,
9772
+ liveAnchorKeys: liveAnchorKeys.size
9773
+ }, () => {
9774
+ if (!current()) return;
9775
+ pruneStaleTrackedChangeComments(liveIds, liveAnchorKeys, String(effectiveDocumentId), superdoc, { broadcastChanges: false });
9776
+ });
9777
+ if (!current()) return {
9778
+ ok: false,
9779
+ reason: "reconciliation-stale",
9780
+ appliedItems,
9781
+ batchCount
9782
+ };
9783
+ }
9784
+ return {
9785
+ ok: true,
9786
+ appliedItems,
9787
+ batchCount,
9788
+ pruned: Boolean(pruneStale && effectiveDocumentId)
9789
+ };
9790
+ };
9791
+ const getV2TrackedChangeRowCount = (documentId = null) => {
9792
+ const normalizedDocumentId = documentId == null ? null : String(documentId);
9793
+ return commentsList.value.filter((comment) => {
9794
+ if (comment?.trackedChange !== true) return false;
9795
+ if (normalizedDocumentId == null) return true;
9796
+ const rowDocumentId = comment?.documentId ?? comment?.fileId ?? null;
9797
+ return rowDocumentId != null && String(rowDocumentId) === normalizedDocumentId;
9798
+ }).length;
9799
+ };
9403
9800
  const syncTrackedChangeComments = ({ superdoc, editor, broadcastChanges = true }) => {
9404
9801
  if (!superdoc || !editor) return;
9405
9802
  const activeDocumentId = editor?.options?.documentId != null ? String(editor.options.documentId) : null;
@@ -9966,6 +10363,7 @@ const useCommentsStore = defineStore("comments", () => {
9966
10363
  getV2CommentsAdapter,
9967
10364
  hydrateCommentsFromV2,
9968
10365
  applyReviewSnapshotFromV2,
10366
+ supersedeV2ReviewHydration,
9969
10367
  reconcileCommentsFromV2,
9970
10368
  isV2EditorActive,
9971
10369
  replyCommentV2,
@@ -9975,6 +10373,7 @@ const useCommentsStore = defineStore("comments", () => {
9975
10373
  v2TrackedChangesAdapter,
9976
10374
  setV2TrackedChangesAdapter,
9977
10375
  getV2TrackedChangesAdapter,
10376
+ getV2TrackedChangeRowCount,
9978
10377
  hydrateTrackedChangesFromV2,
9979
10378
  reconcileTrackedChangeMutationFromV2,
9980
10379
  reconcileTrackedChangesFromV2,
@@ -11304,7 +11703,7 @@ var _sfc_main$32 = {
11304
11703
  const willChangeActiveDialog = !props.comment.resolvedTime && (activeComment.value !== props.comment.commentId || isInstanceScopedDialog && currentFloatingInstanceId.value !== activeFloatingCommentInstanceId.value);
11305
11704
  let instantAlignmentTargetY = targetClientY;
11306
11705
  if (v2Adapter) {
11307
- const linkedTrackedChangeId = !isTrackedChange && String(props.comment?.trackedChangeParentId ?? "").trim() ? props.comment.trackedChangeParentId : null;
11706
+ const linkedTrackedChangeId = !isTrackedChange && !props.comment.resolvedTime && String(props.comment?.trackedChangeParentId ?? "").trim() ? props.comment.trackedChangeParentId : null;
11308
11707
  const trackedChangeAdapter = editor?.editorVersion === 2 && (isTrackedChange || linkedTrackedChangeId != null) ? editor?.v2TrackedChanges ?? null : null;
11309
11708
  const linkedTrackedChange = linkedTrackedChangeId != null ? commentsStore.getComment(linkedTrackedChangeId) : null;
11310
11709
  const trackedChangeTarget = isTrackedChange ? props.comment : linkedTrackedChange?.trackedChange ? linkedTrackedChange : linkedTrackedChangeId;
@@ -11990,7 +12389,7 @@ var _sfc_main$32 = {
11990
12389
  };
11991
12390
  }
11992
12391
  };
11993
- var CommentDialog_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$32, [["__scopeId", "data-v-05d69162"]]);
12392
+ var CommentDialog_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$32, [["__scopeId", "data-v-f26decd0"]]);
11994
12393
  var _hoisted_1$24 = { class: "comments-list" };
11995
12394
  var _hoisted_2$19 = { key: 0 };
11996
12395
  var _hoisted_3$15 = [
@@ -14361,7 +14760,7 @@ function usePasswordPrompt({ getSurfaceManager, getPasswordPromptConfig, onUnhan
14361
14760
  })
14362
14761
  });
14363
14762
  } else {
14364
- const PasswordPromptSurface = (await Promise.resolve().then(() => require("./chunks/PasswordPromptSurface-BUUVC2ee.cjs"))).default;
14763
+ const PasswordPromptSurface = (await Promise.resolve().then(() => require("./chunks/PasswordPromptSurface-Bu5xHm91.cjs"))).default;
14365
14764
  const surfaceId = `password-prompt-${doc.id}`;
14366
14765
  handle = manager.open({
14367
14766
  id: surfaceId,
@@ -15010,7 +15409,7 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
15010
15409
  } else {
15011
15410
  let FindReplaceSurface;
15012
15411
  try {
15013
- FindReplaceSurface = (await Promise.resolve().then(() => require("./chunks/FindReplaceSurface-Dx0llWqP.cjs"))).default;
15412
+ FindReplaceSurface = (await Promise.resolve().then(() => require("./chunks/FindReplaceSurface-9VkPw_-X.cjs"))).default;
15014
15413
  } catch {
15015
15414
  opening = false;
15016
15415
  return;
@@ -17706,7 +18105,7 @@ var _sfc_main$20 = {
17706
18105
  __name: "SuperDoc",
17707
18106
  emits: ["selection-update"],
17708
18107
  setup(__props, { emit: __emit }) {
17709
- const PdfViewer = (0, vue.defineAsyncComponent)(() => Promise.resolve().then(() => require("./chunks/PdfViewer-qpvzwYMz.cjs")));
18108
+ const PdfViewer = (0, vue.defineAsyncComponent)(() => Promise.resolve().then(() => require("./chunks/PdfViewer-D4eD2dV1.cjs")));
17710
18109
  const getDocumentLoadPassword = (doc) => doc.password ?? proxy.$superdoc.config.password;
17711
18110
  const resolveDocumentV2Collaboration = (doc) => {
17712
18111
  const rawConfig = doc?.v2Collaboration;
@@ -17846,7 +18245,7 @@ var _sfc_main$20 = {
17846
18245
  getSurfaceManager: getLinkPopoverSurfaceManager,
17847
18246
  getActiveEditor: () => proxy.$superdoc?.activeEditor,
17848
18247
  getUi: getSuperDocUI,
17849
- getResolver: () => proxy.$superdoc?.uiConfig?.linkPopover?.suppressed ? () => ({ type: "none" }) : proxy.$superdoc?.config?.modules?.links?.popoverResolver,
18248
+ getResolver: () => proxy.$superdoc?.uiConfig?.linkPopover?.suppressed ? () => ({ type: "none" }) : proxy.$superdoc?.uiConfig?.linkPopover?.options?.popoverResolver,
17850
18249
  getLayerElement: () => layers.value,
17851
18250
  emitException: (payload) => {
17852
18251
  proxy.$superdoc?.emit("exception", {
@@ -18018,6 +18417,7 @@ var _sfc_main$20 = {
18018
18417
  const v2ReviewHydrationController = resolvedEditorIntegration.createReviewHydrationController({
18019
18418
  hydrateComments: (ctx) => commentsStore.hydrateCommentsFromV2?.(ctx),
18020
18419
  hydrateTrackedChanges: (ctx) => commentsStore.hydrateTrackedChangesFromV2?.(ctx),
18420
+ primeTrackedChanges: (ctx) => ctx.trackedChangesAdapter?.primeVisibleTrackedChanges?.(ctx.targetIds, ctx.plan),
18021
18421
  readReviewSnapshot: (ctx) => ctx.trackedChangesAdapter?.readReviewSnapshot?.(ctx.snapshot),
18022
18422
  validateReviewSnapshot: (_ctx, result) => result?.validate?.() ?? {
18023
18423
  ok: false,
@@ -18031,6 +18431,8 @@ var _sfc_main$20 = {
18031
18431
  commentItems: result.comments?.items,
18032
18432
  trackedChangeItems: result.trackedChanges?.items,
18033
18433
  trackedList: result.trackedChanges,
18434
+ sourceCoverageRevision: result.sourceCoverageRevision,
18435
+ evaluatedRevision: result.evaluatedRevision,
18034
18436
  patch: (callback) => commentsStore.$patch(callback)
18035
18437
  }) ?? {
18036
18438
  ok: false,
@@ -18708,6 +19110,12 @@ var _sfc_main$20 = {
18708
19110
  v2ReviewSidebarUnlocked.value = true;
18709
19111
  v2GeometryEpoch.value = v2GeometryPublisher.getLastEpoch();
18710
19112
  }
19113
+ },
19114
+ onCommittedPagePaint: (commit) => {
19115
+ v2ReviewHydrationController.onCommittedPagePaint?.({
19116
+ ...commit,
19117
+ documentId: commit?.payload?.documentId ?? null
19118
+ });
18711
19119
  }
18712
19120
  });
18713
19121
  const collectV2TrackedChangeRestampIds = (impactOrIds) => {
@@ -18931,7 +19339,7 @@ var _sfc_main$20 = {
18931
19339
  v2TypingReviewHydrationTimer = setTimeout(attempt, Math.min(V2_TYPING_REVIEW_HYDRATION_IDLE_MS, ceilingRemainingMs));
18932
19340
  };
18933
19341
  const v2RemoteReviewHydrationScheduler = createV2RemoteReviewHydrationScheduler({
18934
- hydrate: () => hydrateV2ReviewRowsFromHost(),
19342
+ hydrate: () => v2ReviewHydrationController.reconcileInBackground?.("remote-review-change"),
18935
19343
  getActiveDocumentId: () => {
18936
19344
  const activeEditor = proxy.$superdoc?.activeEditor ?? null;
18937
19345
  return activeEditor?.documentId ?? activeEditor?.options?.documentId ?? null;
@@ -18940,6 +19348,23 @@ var _sfc_main$20 = {
18940
19348
  const onV2HostEvent = (document$1, event) => {
18941
19349
  if (!event) return;
18942
19350
  const documentId = document$1?.id ?? null;
19351
+ if (event.type === "review-mutation:started") {
19352
+ const activeEditor = proxy.$superdoc?.activeEditor ?? null;
19353
+ commentsStore.supersedeV2ReviewHydration?.({
19354
+ commentsAdapter: activeEditor?.v2Comments ?? null,
19355
+ trackedChangesAdapter: activeEditor?.v2TrackedChanges ?? null
19356
+ });
19357
+ v2ReviewHydrationController.beginMutation(event.reviewMutation);
19358
+ return;
19359
+ }
19360
+ if (event.type === "review-mutation:aborted") {
19361
+ v2ReviewHydrationController.settleMutation(event.reviewMutation?.token, {
19362
+ outcome: "aborted",
19363
+ resumeDomains: ["comments", "trackedChanges"],
19364
+ trackedRowCount: commentsStore.getV2TrackedChangeRowCount?.(documentId) ?? null
19365
+ });
19366
+ return;
19367
+ }
18943
19368
  if (event.type === "reviewTarget:changed") {
18944
19369
  syncSidebarActiveCommentFromV2ReviewTarget(event.next);
18945
19370
  return;
@@ -18958,6 +19383,11 @@ var _sfc_main$20 = {
18958
19383
  return;
18959
19384
  }
18960
19385
  if (event.type === "mutation:rejected") {
19386
+ if (event.reviewMutation?.token) v2ReviewHydrationController.settleMutation(event.reviewMutation.token, {
19387
+ outcome: "rejected",
19388
+ resumeDomains: ["comments", "trackedChanges"],
19389
+ trackedRowCount: commentsStore.getV2TrackedChangeRowCount?.(documentId) ?? null
19390
+ });
18961
19391
  maybeNotifyV2AuthorRequired(documentId, event);
18962
19392
  return;
18963
19393
  }
@@ -18973,7 +19403,22 @@ var _sfc_main$20 = {
18973
19403
  const readiness = (proxy.$superdoc?.activeEditor ?? null)?.documentMutationReadiness ?? null;
18974
19404
  const receipt = event.origin === "history" ? null : event.receipt;
18975
19405
  const canWaitForExactPaint = reviewImpact && typeof receipt?.txId === "string" && receipt.txId.length > 0 && typeof readiness?.whenPainted === "function";
18976
- v2ReviewMutationReconciler.enqueueAfterPaint(reviewImpact, canWaitForExactPaint ? () => readiness.whenPainted.call(readiness, receipt) : null);
19406
+ const reconciliation = v2ReviewMutationReconciler.enqueueAfterPaint(reviewImpact, canWaitForExactPaint ? () => readiness.whenPainted.call(readiness, receipt) : null);
19407
+ if (event.reviewMutation?.token) {
19408
+ const reviewMutation = event.reviewMutation;
19409
+ const allResolved = Boolean(reviewImpact?.allResolved ?? event.trackedChangeAllResolved);
19410
+ const settleReviewMutation = (reconciled) => {
19411
+ const reconciledAllResolved = allResolved && reconciled === true;
19412
+ v2ReviewHydrationController.settleMutation(reviewMutation.token, {
19413
+ outcome: "committed",
19414
+ allResolved: reconciledAllResolved,
19415
+ resumeDomains: reconciledAllResolved ? ["comments"] : ["comments", "trackedChanges"],
19416
+ trackedRowCount: commentsStore.getV2TrackedChangeRowCount?.(documentId) ?? null
19417
+ });
19418
+ };
19419
+ Promise.resolve(reconciliation).then(settleReviewMutation, () => settleReviewMutation(false));
19420
+ return;
19421
+ }
18977
19422
  if (reviewImpact?.reconcileMode === "authoritative" && reviewImpact.upsertIds.size > 0) {
18978
19423
  hydrateV2CommentRowsFromHost();
18979
19424
  return;
@@ -19147,6 +19592,12 @@ var _sfc_main$20 = {
19147
19592
  onCommentsUpdate: onEditorCommentsUpdate,
19148
19593
  onFontsResolved: onFontsResolvedFn,
19149
19594
  onPageCountKnown: proxy.$superdoc.config.onPageCountKnown ?? null,
19595
+ onReviewWindowPlanned: (payload) => {
19596
+ v2ReviewHydrationController.onReviewWindowPlanned?.({
19597
+ ...payload,
19598
+ documentId: doc.id
19599
+ });
19600
+ },
19150
19601
  fontAssets: proxy.$superdoc.config.fonts,
19151
19602
  proofing: resolvedProofingConfig.value,
19152
19603
  isNewFile,
@@ -19159,7 +19610,7 @@ var _sfc_main$20 = {
19159
19610
  jsonOverride: proxy.$superdoc.config.jsonOverride,
19160
19611
  viewOptions: proxy.$superdoc.config.viewOptions,
19161
19612
  contained: proxy.$superdoc.config.contained,
19162
- linkPopoverResolver: proxy.$superdoc.uiConfig.linkPopover.enabled ? proxy.$superdoc.config.modules?.links?.popoverResolver : void 0,
19613
+ linkPopoverResolver: proxy.$superdoc.uiConfig.linkPopover.options.popoverResolver,
19163
19614
  layoutEngineOptions: useLayoutEngine ? {
19164
19615
  ...proxy.$superdoc.config.layoutEngineOptions || {},
19165
19616
  proofing: resolvedProofingConfig.value,
@@ -19167,7 +19618,7 @@ var _sfc_main$20 = {
19167
19618
  zoom: (activeZoom.value ?? 100) / 100,
19168
19619
  emitCommentPositionsInViewing: isViewingMode() && shouldRenderCommentsInViewing.value,
19169
19620
  enableCommentsInViewing: isViewingCommentsVisible.value,
19170
- contentControlsChrome: !proxy.$superdoc.uiConfig.contentControls.enabled ? "none" : proxy.$superdoc.uiConfig.contentControls.options.chrome ?? (proxy.$superdoc.config.modules?.contentControls?.chrome === "none" ? void 0 : proxy.$superdoc.config.modules?.contentControls?.chrome),
19621
+ contentControlsChrome: proxy.$superdoc.uiConfig.contentControls.options.chrome,
19171
19622
  resolveTrackedChangeColor: require_create_super_doc_ui.composeAuthorColorResolver(proxy.$superdoc.config.modules?.trackChanges?.authorColors)
19172
19623
  } : void 0,
19173
19624
  permissionResolver: (payload = {}) => proxy.$superdoc.canPerformPermission({
@@ -20109,7 +20560,7 @@ var _sfc_main$20 = {
20109
20560
  };
20110
20561
  }
20111
20562
  };
20112
- var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-d75089d2"]]);
20563
+ var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-62293b70"]]);
20113
20564
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
20114
20565
  var PINIA_DEVTOOLS_PLUGIN_ID = "dev.esm.pinia";
20115
20566
  var piniaDevtoolsSuppressionState = {
@@ -32544,6 +32995,10 @@ function normalizeUiConfig(config = {}) {
32544
32995
  };
32545
32996
  const options = (key) => allDisabled ? {} : resolveOptions(ui, key);
32546
32997
  const rulerSuppressed = allDisabled || explicit("ruler") === false;
32998
+ const linkPopoverSuppressed = allDisabled || explicit("linkPopover") === false;
32999
+ const linkPopoverResolver = linkPopoverSuppressed ? void 0 : firstDefined(options("linkPopover").popoverResolver, config.modules?.links?.popoverResolver);
33000
+ const contentControlsEnabled = explicit("contentControls") ?? (!allDisabled && config.modules?.contentControls?.chrome !== "none");
33001
+ const legacyContentControlsChrome = config.modules?.contentControls?.chrome === "none" ? void 0 : config.modules?.contentControls?.chrome;
32547
33002
  const toolbarOptions = options("toolbar");
32548
33003
  const legacyToolbar = config.modules?.toolbar;
32549
33004
  const legacyToolbarOptions = isPlainObject$2(legacyToolbar) ? legacyToolbar : {};
@@ -32584,9 +33039,9 @@ function normalizeUiConfig(config = {}) {
32584
33039
  options: allDisabled ? {} : mergeDefined(legacySearch, options("search"))
32585
33040
  },
32586
33041
  linkPopover: {
32587
- enabled: explicit("linkPopover") ?? (!allDisabled && Boolean(config.modules?.links?.popoverResolver)),
32588
- suppressed: allDisabled || explicit("linkPopover") === false,
32589
- options: options("linkPopover")
33042
+ enabled: typeof linkPopoverResolver === "function",
33043
+ suppressed: linkPopoverSuppressed,
33044
+ options: mergeDefined(options("linkPopover"), { popoverResolver: linkPopoverResolver })
32590
33045
  },
32591
33046
  ruler: {
32592
33047
  enabled: explicit("ruler") ?? (!allDisabled && Boolean(config.rulers)),
@@ -32594,8 +33049,8 @@ function normalizeUiConfig(config = {}) {
32594
33049
  container: rulerSuppressed ? null : options("ruler").container ?? config.rulerContainer ?? null
32595
33050
  },
32596
33051
  contentControls: {
32597
- enabled: explicit("contentControls") ?? (!allDisabled && config.modules?.contentControls?.chrome !== "none"),
32598
- options: options("contentControls")
33052
+ enabled: contentControlsEnabled,
33053
+ options: contentControlsEnabled ? mergeDefined({ chrome: legacyContentControlsChrome }, options("contentControls")) : { chrome: "none" }
32599
33054
  }
32600
33055
  };
32601
33056
  }
@@ -34734,6 +35189,19 @@ var _sfc_main$11 = /* @__PURE__ */ Object.assign({ inheritAttrs: false }, {
34734
35189
  }
34735
35190
  });
34736
35191
  var SdTooltip_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$11, [["__scopeId", "data-v-2a872eae"]]);
35192
+ const refocusEditorSurface = (superToolbar, preferredEditor = null) => {
35193
+ if (typeof preferredEditor?.focus === "function") {
35194
+ preferredEditor.focus();
35195
+ return;
35196
+ }
35197
+ const focusHandle = superToolbar?.superdoc?.focus ?? superToolbar?.activeEditor?.focus;
35198
+ if (typeof focusHandle === "function") {
35199
+ focusHandle.call(superToolbar?.superdoc ?? superToolbar?.activeEditor, { preventScroll: true });
35200
+ return;
35201
+ }
35202
+ const editor = document.querySelector("[role=\"textbox\"][aria-label*=\"SuperDoc body\"], .ProseMirror");
35203
+ if (editor instanceof HTMLElement) editor.focus({ preventScroll: true });
35204
+ };
34737
35205
  var _hoisted_1$9 = [
34738
35206
  "onKeydown",
34739
35207
  "tabindex",
@@ -34876,6 +35344,7 @@ var _sfc_main$10 = {
34876
35344
  option
34877
35345
  });
34878
35346
  item.selectedValue.value = option.key;
35347
+ if (item.restoreEditorFocus) refocusEditorSurface(proxy?.$toolbar);
34879
35348
  };
34880
35349
  const handleComboboxCommand = (payload) => {
34881
35350
  emit("command", payload);
@@ -35223,7 +35692,7 @@ var _sfc_main$10 = {
35223
35692
  };
35224
35693
  }
35225
35694
  };
35226
- var ButtonGroup_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$10, [["__scopeId", "data-v-590293ab"]]);
35695
+ var ButtonGroup_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$10, [["__scopeId", "data-v-2bc00f65"]]);
35227
35696
  var DEFAULT_TOOLBAR_FONT_FAMILIES = [
35228
35697
  ["Arial", "sans-serif"],
35229
35698
  ["Arial Black", "sans-serif"],
@@ -36465,19 +36934,6 @@ var _sfc_main$2 = {
36465
36934
  }
36466
36935
  };
36467
36936
  var IconGrid_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$2, [["__scopeId", "data-v-52b0283a"]]);
36468
- const refocusEditorSurface = (superToolbar, preferredEditor = null) => {
36469
- if (typeof preferredEditor?.focus === "function") {
36470
- preferredEditor.focus();
36471
- return;
36472
- }
36473
- const focusHandle = superToolbar?.superdoc?.focus ?? superToolbar?.activeEditor?.focus;
36474
- if (typeof focusHandle === "function") {
36475
- focusHandle.call(superToolbar?.superdoc ?? superToolbar?.activeEditor, { preventScroll: true });
36476
- return;
36477
- }
36478
- const editor = document.querySelector("[role=\"textbox\"][aria-label*=\"SuperDoc body\"], .ProseMirror");
36479
- if (editor instanceof HTMLElement) editor.focus({ preventScroll: true });
36480
- };
36481
36937
  var closeDropdown$1 = (dropdown) => {
36482
36938
  dropdown.expand.value = false;
36483
36939
  };
@@ -37046,7 +37502,10 @@ const makeDefaultItems = ({ superToolbar, toolbarIcons: toolbarIcons$1, toolbarT
37046
37502
  linkItem: link$1,
37047
37503
  textTarget: selectionTarget,
37048
37504
  restoreSelection,
37049
- closePopover: () => closeDropdown(link$1),
37505
+ closePopover: () => {
37506
+ closeDropdown(link$1);
37507
+ refocusEditorSurface(superToolbar);
37508
+ },
37050
37509
  goToAnchor: () => {
37051
37510
  closeDropdown(link$1);
37052
37511
  const href = link$1.attributes.value?.href;
@@ -37269,6 +37728,7 @@ const makeDefaultItems = ({ superToolbar, toolbarIcons: toolbarIcons$1, toolbarT
37269
37728
  argument: e
37270
37729
  });
37271
37730
  setAlignmentIcon(alignment, e);
37731
+ refocusEditorSurface(superToolbar);
37272
37732
  };
37273
37733
  return (0, vue.h)("div", {}, [(0, vue.h)(AlignmentButtons_default, { onSelect: handleSelect })]);
37274
37734
  },
@@ -37720,6 +38180,7 @@ const makeDefaultItems = ({ superToolbar, toolbarIcons: toolbarIcons$1, toolbarT
37720
38180
  hideLabel: true,
37721
38181
  inlineTextInputVisible: false,
37722
38182
  suppressActiveHighlight: true,
38183
+ restoreEditorFocus: true,
37723
38184
  isWide: false,
37724
38185
  command: "setLineHeight",
37725
38186
  dropdownValueKey: "key",
@@ -38575,6 +39036,11 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
38575
39036
  function createBuiltInToolbar(config) {
38576
39037
  return new BuiltInToolbar(config);
38577
39038
  }
39039
+ var STRUCTURED_CONTENT_FRAME_SELECTOR = [
39040
+ "[data-sdt-type=\"structuredContent\"][data-sdt-id]",
39041
+ "[data-sdt-type=\"structuredContent\"][data-sdt-container-id]",
39042
+ "[data-sdt-container-type=\"structuredContent\"][data-sdt-container-id]"
39043
+ ].join(", ");
38578
39044
  var DEFAULT_AWARENESS_PALETTE = Object.freeze([
38579
39045
  "#FF6B6B",
38580
39046
  "#4ECDC4",
@@ -38662,6 +39128,33 @@ function onCollaborationProviderSynced(provider, onSynced) {
38662
39128
  if (isCollaborationProviderSynced(provider)) finish();
38663
39129
  return cleanup;
38664
39130
  }
39131
+ function getClickedContentControlId(event, root) {
39132
+ const path = event.composedPath();
39133
+ if (!path.includes(root)) return null;
39134
+ const control = path.find((target$1) => target$1 instanceof HTMLElement && target$1.matches(STRUCTURED_CONTENT_FRAME_SELECTOR));
39135
+ if (!control) return null;
39136
+ const onBlockLabel = path.some((target$1) => target$1 instanceof HTMLElement && target$1.classList.contains(require_create_super_doc_ui.DOM_CLASS_NAMES.BLOCK_SDT_LABEL));
39137
+ const containerId = control.getAttribute("data-sdt-container-id")?.trim() || null;
39138
+ const sdtId = control.getAttribute("data-sdt-id")?.trim() || null;
39139
+ return onBlockLabel ? containerId ?? sdtId : sdtId ?? containerId;
39140
+ }
39141
+ function getContentControlItems(result) {
39142
+ if (!result || typeof result !== "object") return [];
39143
+ const items = result.items;
39144
+ return Array.isArray(items) ? items : [];
39145
+ }
39146
+ function toSdtRef(item) {
39147
+ if (!item || typeof item.id !== "string" || item.kind !== "inline" && item.kind !== "block" || typeof item.controlType !== "string") return null;
39148
+ const tag = item.properties?.tag;
39149
+ const alias = item.properties?.alias;
39150
+ return {
39151
+ id: item.id,
39152
+ controlType: item.controlType,
39153
+ scope: item.kind,
39154
+ ...typeof tag === "string" && tag ? { tag } : {},
39155
+ ...typeof alias === "string" && alias ? { alias } : {}
39156
+ };
39157
+ }
38665
39158
  function isV2ActiveEditorFacade(editor) {
38666
39159
  return Boolean(editor && typeof editor === "object" && editor.editorVersion === 2);
38667
39160
  }
@@ -38715,6 +39208,10 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
38715
39208
  #v2LockUnsub = null;
38716
39209
  #pendingV2LockSeed = null;
38717
39210
  #mountWrapper = null;
39211
+ #contentControlClickRoot = null;
39212
+ #handleContentControlClick = (event) => {
39213
+ this.#emitContentControlClick(event);
39214
+ };
38718
39215
  #ui = null;
38719
39216
  #uiConfig = normalizeUiConfig({});
38720
39217
  get uiConfig() {
@@ -38798,8 +39295,28 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
38798
39295
  const container = typeof config.selector === "string" ? document.querySelector(config.selector) : config.selector;
38799
39296
  if (!(container instanceof HTMLElement)) throw new Error("SuperDoc: selector must be a valid CSS selector string or DOM element");
38800
39297
  this.#surfaceManager = new SurfaceManager({ getModuleConfig: () => this.#surfacesConfig });
39298
+ this.#contentControlClickRoot = container;
39299
+ container.addEventListener("click", this.#handleContentControlClick, true);
38801
39300
  this.#init(config, container);
38802
39301
  }
39302
+ async #emitContentControlClick(event) {
39303
+ const root = this.#contentControlClickRoot;
39304
+ if (!root) return;
39305
+ const id = getClickedContentControlId(event, root);
39306
+ const list = this.activeEditor?.doc?.contentControls?.list;
39307
+ if (!id || typeof list !== "function") return;
39308
+ try {
39309
+ const result = await list();
39310
+ if (this.#destroyed) return;
39311
+ const target$1 = toSdtRef(getContentControlItems(result).find((item) => item.id === id));
39312
+ if (target$1) this.emit("content-control:click", {
39313
+ target: target$1,
39314
+ source: "pointer"
39315
+ });
39316
+ } catch {
39317
+ return;
39318
+ }
39319
+ }
38803
39320
  async #init(config, container) {
38804
39321
  this.config = {
38805
39322
  ...this.config,
@@ -38846,7 +39363,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
38846
39363
  this.config.colors = shuffleArray(this.config.colors);
38847
39364
  this.userColorMap = /* @__PURE__ */ new Map();
38848
39365
  this.colorIndex = 0;
38849
- this.version = "2.4.0-next.1";
39366
+ this.version = "2.4.0-next.10";
38850
39367
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
38851
39368
  this.superdocId = config.superdocId || require_uuid.v4_default();
38852
39369
  this.colors = this.config.colors ?? [];
@@ -39728,8 +40245,8 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
39728
40245
  },
39729
40246
  {
39730
40247
  feature: "shell.tracked-change-sidebar.bulk",
39731
- status: "not-shipped",
39732
- reason: "bulk-tracked-change-decisions-omitted: acceptAll/rejectAll are matrix-disabled by default in the v2 host"
40248
+ status: "supported",
40249
+ reason: "SD-4039/SD-4040: the shipped v2 command posture exposes all-story Accept All and Reject All through the canonical doc.trackChanges.decide({ target: { kind: 'all' } }) mutation"
39733
40250
  },
39734
40251
  {
39735
40252
  feature: "shell.tracked-change-sidebar.non-body",
@@ -40374,6 +40891,8 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
40374
40891
  }
40375
40892
  destroy() {
40376
40893
  this.#destroyed = true;
40894
+ this.#contentControlClickRoot?.removeEventListener("click", this.#handleContentControlClick, true);
40895
+ this.#contentControlClickRoot = null;
40377
40896
  if (this.#abortUpgrade) {
40378
40897
  this.#abortUpgrade();
40379
40898
  this.#abortUpgrade = null;