superdoc 2.4.0-next.3 → 2.4.0-next.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/chunks/{FindReplaceSurface-BEW-1NhM.es.js → FindReplaceSurface-B_1Ksbr0.es.js} +1 -1
  2. package/dist/chunks/{FindReplaceSurface-Dx0llWqP.cjs → FindReplaceSurface-C-I4GcRE.cjs} +1 -1
  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-Dli6Wq70.es.js → create-super-doc-ui-BquF8bnZ.es.js} +71 -62
  8. package/dist/chunks/{create-super-doc-ui-BHMQEL2y.cjs → create-super-doc-ui-sMXbYzhs.cjs} +76 -61
  9. package/dist/collaboration-upgrade-engine.cjs +1 -1
  10. package/dist/collaboration-upgrade-engine.es.js +1 -1
  11. package/dist/public/ui-react.cjs +1 -1
  12. package/dist/public/ui-react.es.js +1 -1
  13. package/dist/public/ui.cjs +1 -1
  14. package/dist/public/ui.es.js +1 -1
  15. package/dist/style.css +23 -23
  16. package/dist/style.layered.css +23 -23
  17. package/dist/superdoc/src/stores/comments-store.d.ts +33 -15
  18. package/dist/superdoc/src/stores/superdoc-store.d.ts +99 -45
  19. package/dist/superdoc.cjs +289 -26
  20. package/dist/superdoc.es.js +289 -26
  21. package/dist-cdn/style.layered.css +1 -1
  22. package/dist-cdn/superdoc.min.css +1 -1
  23. package/dist-cdn/superdoc.min.js +36 -36
  24. package/package.json +2 -2
  25. /package/dist/chunks/{_plugin-vue_export-helper-BTwbGDKw.cjs → _plugin-vue_export-helper-CZ1Nl59K.cjs} +0 -0
  26. /package/dist/chunks/{_plugin-vue_export-helper-CInC0bKI.es.js → _plugin-vue_export-helper-DSMAhhwD.es.js} +0 -0
  27. /package/dist/chunks/{constants-CY3R3_kF.es.js → constants-BfH0br5u.es.js} +0 -0
  28. /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-BHMQEL2y.cjs");
7
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-sMXbYzhs.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) => ({
@@ -8155,7 +8165,7 @@ const useCommentsStore = defineStore("comments", () => {
8155
8165
  if (!adapter) return false;
8156
8166
  return v2TrackedChangesAdapter.value === adapter;
8157
8167
  };
8158
- 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", {
8159
8169
  commentItemCount: Array.isArray(commentItems) ? commentItems.length : null,
8160
8170
  trackedItemCount: Array.isArray(trackedChangeItems) ? trackedChangeItems.length : null
8161
8171
  }, () => {
@@ -8193,11 +8203,28 @@ const useCommentsStore = defineStore("comments", () => {
8193
8203
  ok: false,
8194
8204
  reason: "adapter-mapper-missing"
8195
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
+ }
8196
8223
  const fileType = (normalizedDocumentId ? superdocStore.getDocument(normalizedDocumentId) : null)?.type ?? null;
8197
8224
  let preparedInputs;
8198
8225
  let preparedParams;
8199
8226
  try {
8200
- preparedInputs = commentItems.filter((item) => !isSyntheticTrackedChangeCommentLaneItem(item)).map((item) => commentsAdapter.mapV2CommentToUseCommentInput(item, {
8227
+ preparedInputs = effectiveCommentItems.filter((item) => !isSyntheticTrackedChangeCommentLaneItem(item)).map((item) => commentsAdapter.mapV2CommentToUseCommentInput(item, {
8201
8228
  fileId: normalizedDocumentId,
8202
8229
  fileType
8203
8230
  })).filter(Boolean);
@@ -8226,8 +8253,9 @@ const useCommentsStore = defineStore("comments", () => {
8226
8253
  superdoc,
8227
8254
  adapter: commentsAdapter,
8228
8255
  documentId: normalizedDocumentId,
8229
- items: commentItems,
8230
- preparedInputs
8256
+ items: effectiveCommentItems,
8257
+ preparedInputs,
8258
+ pruneStale: !commentItemsArePartial
8231
8259
  });
8232
8260
  });
8233
8261
  return {
@@ -8236,12 +8264,19 @@ const useCommentsStore = defineStore("comments", () => {
8236
8264
  trackedItems: preparedParams.length
8237
8265
  };
8238
8266
  });
8239
- const hydrateCommentsFromV2 = async ({ superdoc, adapter, documentId, signal, hydrationGeneration } = {}) => 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 () => {
8240
8268
  const effectiveAdapter = adapter ?? getV2CommentsAdapter(superdoc);
8241
- 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 {
8242
8272
  ok: false,
8243
8273
  reason: "adapter-missing"
8244
8274
  };
8275
+ const hydrationIsCurrent = () => isCurrent?.() !== false && isCurrentV2CommentsAdapter(effectiveAdapter);
8276
+ if (!hydrationIsCurrent()) return {
8277
+ ok: false,
8278
+ reason: "adapter-stale"
8279
+ };
8245
8280
  if (signal?.aborted) return {
8246
8281
  ok: false,
8247
8282
  reason: "review-hydration-superseded",
@@ -8253,7 +8288,7 @@ const useCommentsStore = defineStore("comments", () => {
8253
8288
  const refreshOptions = {};
8254
8289
  if (signal) refreshOptions.signal = signal;
8255
8290
  if (typeof hydrationGeneration === "number") refreshOptions.hydrationGeneration = hydrationGeneration;
8256
- result = Object.keys(refreshOptions).length > 0 ? await effectiveAdapter.refresh(refreshOptions) : await effectiveAdapter.refresh();
8291
+ result = Object.keys(refreshOptions).length > 0 ? await read.call(effectiveAdapter, refreshOptions) : await read.call(effectiveAdapter);
8257
8292
  } catch (err) {
8258
8293
  return {
8259
8294
  ok: false,
@@ -8261,7 +8296,7 @@ const useCommentsStore = defineStore("comments", () => {
8261
8296
  detail: err?.message ?? String(err)
8262
8297
  };
8263
8298
  }
8264
- if (!isCurrentV2CommentsAdapter(effectiveAdapter)) return {
8299
+ if (!hydrationIsCurrent()) return {
8265
8300
  ok: false,
8266
8301
  reason: "adapter-stale"
8267
8302
  };
@@ -8281,16 +8316,18 @@ const useCommentsStore = defineStore("comments", () => {
8281
8316
  adapter: effectiveAdapter,
8282
8317
  documentId,
8283
8318
  items: result.items ?? [],
8319
+ pruneStale: !visibleWindow,
8284
8320
  hydrationGeneration
8285
8321
  });
8286
8322
  return {
8287
8323
  ok: true,
8288
8324
  items: result.items ?? [],
8289
8325
  reconciled: true,
8290
- ...typeof hydrationGeneration === "number" ? { hydrationGeneration } : {}
8326
+ ...typeof hydrationGeneration === "number" ? { hydrationGeneration } : {},
8327
+ ...result.visibleWindowSource != null ? { visibleWindowSource: result.visibleWindowSource } : {}
8291
8328
  };
8292
8329
  });
8293
- const reconcileCommentsFromV2 = ({ superdoc, adapter, documentId, items, preparedInputs = null, hydrationGeneration } = {}) => withInteractionSpan("store.comments.reconcile", "store-reconciliation", {
8330
+ const reconcileCommentsFromV2 = ({ superdoc, adapter, documentId, items, preparedInputs = null, pruneStale = true, hydrationGeneration } = {}) => withInteractionSpan("store.comments.reconcile", "store-reconciliation", {
8294
8331
  documentId: documentId ?? null,
8295
8332
  itemCount: Array.isArray(items) ? items.length : null,
8296
8333
  hydrationGeneration: hydrationGeneration ?? null
@@ -8408,6 +8445,7 @@ const useCommentsStore = defineStore("comments", () => {
8408
8445
  seenIncoming.add(cid);
8409
8446
  nextList.push(existing);
8410
8447
  }
8448
+ if (!input && !pruneStale) nextList.push(existing);
8411
8449
  }
8412
8450
  for (const [cid, input] of incomingByCommentId.entries()) {
8413
8451
  if (seenIncoming.has(cid)) continue;
@@ -9326,7 +9364,7 @@ const useCommentsStore = defineStore("comments", () => {
9326
9364
  success: Boolean(command(id))
9327
9365
  };
9328
9366
  };
9329
- const hydrateTrackedChangesFromV2 = async ({ superdoc, adapter, documentId, trackedChangesListMode = "all", refreshReason, blocking, signal, hydrationGeneration } = {}) => 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", {
9330
9368
  documentId: documentId ?? null,
9331
9369
  trackedChangesListMode,
9332
9370
  refreshReason: refreshReason ?? null,
@@ -9337,19 +9375,49 @@ const useCommentsStore = defineStore("comments", () => {
9337
9375
  ok: false,
9338
9376
  reason: "adapter-missing"
9339
9377
  };
9378
+ const hydrationIsCurrent = () => isCurrent?.() !== false && isCurrentV2TrackedChangesAdapter(effectiveAdapter);
9379
+ if (!hydrationIsCurrent()) return {
9380
+ ok: false,
9381
+ reason: "adapter-stale"
9382
+ };
9340
9383
  const syncGeneration = trackedChangeSyncGeneration(effectiveAdapter);
9384
+ const hydrationCanContinue = () => hydrationIsCurrent() && !signal?.aborted && trackedChangeSyncGeneration(effectiveAdapter) === syncGeneration;
9341
9385
  if (signal?.aborted) return {
9342
9386
  ok: false,
9343
9387
  reason: "review-hydration-superseded",
9344
9388
  lateResultDropped: false
9345
9389
  };
9390
+ const incrementalLiveIds = /* @__PURE__ */ new Set();
9391
+ const incrementalLiveAnchorKeys = /* @__PURE__ */ new Set();
9392
+ let incrementalPagesApplied = 0;
9393
+ let incrementalItemsApplied = 0;
9346
9394
  let result;
9347
9395
  try {
9348
9396
  const listOptions = { mode: trackedChangesListMode };
9397
+ if (Array.isArray(targetIds)) listOptions.targetIds = targetIds;
9349
9398
  if (refreshReason != null) listOptions.refreshReason = refreshReason;
9350
9399
  if (typeof blocking === "boolean") listOptions.blocking = blocking;
9351
9400
  if (signal) listOptions.signal = signal;
9352
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
+ }
9353
9421
  result = await effectiveAdapter.listTrackedChanges(listOptions);
9354
9422
  } catch (err) {
9355
9423
  return {
@@ -9358,7 +9426,7 @@ const useCommentsStore = defineStore("comments", () => {
9358
9426
  detail: err?.message ?? String(err)
9359
9427
  };
9360
9428
  }
9361
- if (!isCurrentV2TrackedChangesAdapter(effectiveAdapter)) return {
9429
+ if (!hydrationIsCurrent()) return {
9362
9430
  ok: false,
9363
9431
  reason: "adapter-stale"
9364
9432
  };
@@ -9379,7 +9447,35 @@ const useCommentsStore = defineStore("comments", () => {
9379
9447
  reason: "review-hydration-superseded",
9380
9448
  lateResultDropped: true
9381
9449
  };
9382
- reconcileTrackedChangesFromV2({
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({
9383
9479
  superdoc,
9384
9480
  adapter: effectiveAdapter,
9385
9481
  documentId,
@@ -9399,6 +9495,12 @@ const useCommentsStore = defineStore("comments", () => {
9399
9495
  if (result.visibleWindowFallbackReason != null) hydrationResult.visibleWindowFallbackReason = result.visibleWindowFallbackReason;
9400
9496
  if (typeof result.visibleTrackedChangeExpectedRows === "number") hydrationResult.visibleTrackedChangeExpectedRows = result.visibleTrackedChangeExpectedRows;
9401
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 }));
9402
9504
  if (typeof result.refreshReason === "string") hydrationResult.refreshReason = result.refreshReason;
9403
9505
  if (typeof result.blocking === "boolean") hydrationResult.blocking = result.blocking;
9404
9506
  if (typeof result.pageCount === "number") hydrationResult.pageCount = result.pageCount;
@@ -9407,6 +9509,11 @@ const useCommentsStore = defineStore("comments", () => {
9407
9509
  if (typeof result.pagesSkippedAfterAbort === "number") hydrationResult.pagesSkippedAfterAbort = result.pagesSkippedAfterAbort;
9408
9510
  if (typeof result.totalItems === "number") hydrationResult.totalItems = result.totalItems;
9409
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
+ }
9410
9517
  return hydrationResult;
9411
9518
  });
9412
9519
  const reconcileTrackedChangeMutationFromV2 = async ({ superdoc, adapter, documentId, upsertIds = [], removedIds = [], allResolved } = {}) => {
@@ -9561,7 +9668,7 @@ const useCommentsStore = defineStore("comments", () => {
9561
9668
  }
9562
9669
  };
9563
9670
  };
9564
- const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
9671
+ const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null, liveIds: suppliedLiveIds = null, liveAnchorKeys: suppliedLiveAnchorKeys = null, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
9565
9672
  documentId: documentId ?? null,
9566
9673
  itemCount: Array.isArray(items) ? items.length : null,
9567
9674
  pruneStale,
@@ -9570,8 +9677,9 @@ const useCommentsStore = defineStore("comments", () => {
9570
9677
  if (!adapter || !Array.isArray(items)) return;
9571
9678
  if (!isCurrentV2TrackedChangesAdapter(adapter)) return;
9572
9679
  const effectiveDocumentId = documentId ?? adapter.documentId ?? superdoc?.activeEditor?.documentId ?? null;
9573
- const liveAnchorKeys = /* @__PURE__ */ new Set();
9574
- 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;
9575
9683
  const trackedChangeIdentityIndex = createTrackedChangeBatchIdentityIndex(effectiveDocumentId == null ? null : String(effectiveDocumentId));
9576
9684
  const identitySpan = startInteractionSpan("store.trackedChanges.batchIdentity", "store-reconciliation", { itemCount: items.length });
9577
9685
  const paramsList = Array.isArray(preparedParams) ? preparedParams : items.map((item) => adapter.mapV2TrackedChangeToCommentParams(item));
@@ -9591,13 +9699,95 @@ const useCommentsStore = defineStore("comments", () => {
9591
9699
  broadcastChanges: false,
9592
9700
  trackedChangeIdentityIndex
9593
9701
  });
9702
+ appliedCount += 1;
9594
9703
  }
9595
9704
  } finally {
9596
9705
  endInteractionSpan(identitySpan, trackedChangeIdentityIndex.work());
9597
9706
  }
9598
- if (!effectiveDocumentId || !pruneStale) return;
9707
+ if (!effectiveDocumentId || !pruneStale) return {
9708
+ liveIds,
9709
+ liveAnchorKeys,
9710
+ appliedCount
9711
+ };
9599
9712
  pruneStaleTrackedChangeComments(liveIds, liveAnchorKeys, String(effectiveDocumentId), superdoc, { broadcastChanges: false });
9713
+ return {
9714
+ liveIds,
9715
+ liveAnchorKeys,
9716
+ appliedCount
9717
+ };
9600
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
+ };
9601
9791
  const getV2TrackedChangeRowCount = (documentId = null) => {
9602
9792
  const normalizedDocumentId = documentId == null ? null : String(documentId);
9603
9793
  return commentsList.value.filter((comment) => {
@@ -14570,7 +14760,7 @@ function usePasswordPrompt({ getSurfaceManager, getPasswordPromptConfig, onUnhan
14570
14760
  })
14571
14761
  });
14572
14762
  } else {
14573
- 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;
14574
14764
  const surfaceId = `password-prompt-${doc.id}`;
14575
14765
  handle = manager.open({
14576
14766
  id: surfaceId,
@@ -15219,7 +15409,7 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
15219
15409
  } else {
15220
15410
  let FindReplaceSurface;
15221
15411
  try {
15222
- FindReplaceSurface = (await Promise.resolve().then(() => require("./chunks/FindReplaceSurface-Dx0llWqP.cjs"))).default;
15412
+ FindReplaceSurface = (await Promise.resolve().then(() => require("./chunks/FindReplaceSurface-C-I4GcRE.cjs"))).default;
15223
15413
  } catch {
15224
15414
  opening = false;
15225
15415
  return;
@@ -17915,7 +18105,7 @@ var _sfc_main$20 = {
17915
18105
  __name: "SuperDoc",
17916
18106
  emits: ["selection-update"],
17917
18107
  setup(__props, { emit: __emit }) {
17918
- 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")));
17919
18109
  const getDocumentLoadPassword = (doc) => doc.password ?? proxy.$superdoc.config.password;
17920
18110
  const resolveDocumentV2Collaboration = (doc) => {
17921
18111
  const rawConfig = doc?.v2Collaboration;
@@ -18227,6 +18417,7 @@ var _sfc_main$20 = {
18227
18417
  const v2ReviewHydrationController = resolvedEditorIntegration.createReviewHydrationController({
18228
18418
  hydrateComments: (ctx) => commentsStore.hydrateCommentsFromV2?.(ctx),
18229
18419
  hydrateTrackedChanges: (ctx) => commentsStore.hydrateTrackedChangesFromV2?.(ctx),
18420
+ primeTrackedChanges: (ctx) => ctx.trackedChangesAdapter?.primeVisibleTrackedChanges?.(ctx.targetIds, ctx.plan),
18230
18421
  readReviewSnapshot: (ctx) => ctx.trackedChangesAdapter?.readReviewSnapshot?.(ctx.snapshot),
18231
18422
  validateReviewSnapshot: (_ctx, result) => result?.validate?.() ?? {
18232
18423
  ok: false,
@@ -18240,6 +18431,8 @@ var _sfc_main$20 = {
18240
18431
  commentItems: result.comments?.items,
18241
18432
  trackedChangeItems: result.trackedChanges?.items,
18242
18433
  trackedList: result.trackedChanges,
18434
+ sourceCoverageRevision: result.sourceCoverageRevision,
18435
+ evaluatedRevision: result.evaluatedRevision,
18243
18436
  patch: (callback) => commentsStore.$patch(callback)
18244
18437
  }) ?? {
18245
18438
  ok: false,
@@ -18917,6 +19110,12 @@ var _sfc_main$20 = {
18917
19110
  v2ReviewSidebarUnlocked.value = true;
18918
19111
  v2GeometryEpoch.value = v2GeometryPublisher.getLastEpoch();
18919
19112
  }
19113
+ },
19114
+ onCommittedPagePaint: (commit) => {
19115
+ v2ReviewHydrationController.onCommittedPagePaint?.({
19116
+ ...commit,
19117
+ documentId: commit?.payload?.documentId ?? null
19118
+ });
18920
19119
  }
18921
19120
  });
18922
19121
  const collectV2TrackedChangeRestampIds = (impactOrIds) => {
@@ -19140,7 +19339,7 @@ var _sfc_main$20 = {
19140
19339
  v2TypingReviewHydrationTimer = setTimeout(attempt, Math.min(V2_TYPING_REVIEW_HYDRATION_IDLE_MS, ceilingRemainingMs));
19141
19340
  };
19142
19341
  const v2RemoteReviewHydrationScheduler = createV2RemoteReviewHydrationScheduler({
19143
- hydrate: () => hydrateV2ReviewRowsFromHost(),
19342
+ hydrate: () => v2ReviewHydrationController.reconcileInBackground?.("remote-review-change"),
19144
19343
  getActiveDocumentId: () => {
19145
19344
  const activeEditor = proxy.$superdoc?.activeEditor ?? null;
19146
19345
  return activeEditor?.documentId ?? activeEditor?.options?.documentId ?? null;
@@ -19393,6 +19592,12 @@ var _sfc_main$20 = {
19393
19592
  onCommentsUpdate: onEditorCommentsUpdate,
19394
19593
  onFontsResolved: onFontsResolvedFn,
19395
19594
  onPageCountKnown: proxy.$superdoc.config.onPageCountKnown ?? null,
19595
+ onReviewWindowPlanned: (payload) => {
19596
+ v2ReviewHydrationController.onReviewWindowPlanned?.({
19597
+ ...payload,
19598
+ documentId: doc.id
19599
+ });
19600
+ },
19396
19601
  fontAssets: proxy.$superdoc.config.fonts,
19397
19602
  proofing: resolvedProofingConfig.value,
19398
19603
  isNewFile,
@@ -20355,7 +20560,7 @@ var _sfc_main$20 = {
20355
20560
  };
20356
20561
  }
20357
20562
  };
20358
- var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-e489229f"]]);
20563
+ var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-c3bc8a46"]]);
20359
20564
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
20360
20565
  var PINIA_DEVTOOLS_PLUGIN_ID = "dev.esm.pinia";
20361
20566
  var piniaDevtoolsSuppressionState = {
@@ -38821,6 +39026,11 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
38821
39026
  function createBuiltInToolbar(config) {
38822
39027
  return new BuiltInToolbar(config);
38823
39028
  }
39029
+ var STRUCTURED_CONTENT_FRAME_SELECTOR = [
39030
+ "[data-sdt-type=\"structuredContent\"][data-sdt-id]",
39031
+ "[data-sdt-type=\"structuredContent\"][data-sdt-container-id]",
39032
+ "[data-sdt-container-type=\"structuredContent\"][data-sdt-container-id]"
39033
+ ].join(", ");
38824
39034
  var DEFAULT_AWARENESS_PALETTE = Object.freeze([
38825
39035
  "#FF6B6B",
38826
39036
  "#4ECDC4",
@@ -38908,6 +39118,33 @@ function onCollaborationProviderSynced(provider, onSynced) {
38908
39118
  if (isCollaborationProviderSynced(provider)) finish();
38909
39119
  return cleanup;
38910
39120
  }
39121
+ function getClickedContentControlId(event, root) {
39122
+ const path = event.composedPath();
39123
+ if (!path.includes(root)) return null;
39124
+ const control = path.find((target$1) => target$1 instanceof HTMLElement && target$1.matches(STRUCTURED_CONTENT_FRAME_SELECTOR));
39125
+ if (!control) return null;
39126
+ 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));
39127
+ const containerId = control.getAttribute("data-sdt-container-id")?.trim() || null;
39128
+ const sdtId = control.getAttribute("data-sdt-id")?.trim() || null;
39129
+ return onBlockLabel ? containerId ?? sdtId : sdtId ?? containerId;
39130
+ }
39131
+ function getContentControlItems(result) {
39132
+ if (!result || typeof result !== "object") return [];
39133
+ const items = result.items;
39134
+ return Array.isArray(items) ? items : [];
39135
+ }
39136
+ function toSdtRef(item) {
39137
+ if (!item || typeof item.id !== "string" || item.kind !== "inline" && item.kind !== "block" || typeof item.controlType !== "string") return null;
39138
+ const tag = item.properties?.tag;
39139
+ const alias = item.properties?.alias;
39140
+ return {
39141
+ id: item.id,
39142
+ controlType: item.controlType,
39143
+ scope: item.kind,
39144
+ ...typeof tag === "string" && tag ? { tag } : {},
39145
+ ...typeof alias === "string" && alias ? { alias } : {}
39146
+ };
39147
+ }
38911
39148
  function isV2ActiveEditorFacade(editor) {
38912
39149
  return Boolean(editor && typeof editor === "object" && editor.editorVersion === 2);
38913
39150
  }
@@ -38961,6 +39198,10 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
38961
39198
  #v2LockUnsub = null;
38962
39199
  #pendingV2LockSeed = null;
38963
39200
  #mountWrapper = null;
39201
+ #contentControlClickRoot = null;
39202
+ #handleContentControlClick = (event) => {
39203
+ this.#emitContentControlClick(event);
39204
+ };
38964
39205
  #ui = null;
38965
39206
  #uiConfig = normalizeUiConfig({});
38966
39207
  get uiConfig() {
@@ -39044,8 +39285,28 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
39044
39285
  const container = typeof config.selector === "string" ? document.querySelector(config.selector) : config.selector;
39045
39286
  if (!(container instanceof HTMLElement)) throw new Error("SuperDoc: selector must be a valid CSS selector string or DOM element");
39046
39287
  this.#surfaceManager = new SurfaceManager({ getModuleConfig: () => this.#surfacesConfig });
39288
+ this.#contentControlClickRoot = container;
39289
+ container.addEventListener("click", this.#handleContentControlClick, true);
39047
39290
  this.#init(config, container);
39048
39291
  }
39292
+ async #emitContentControlClick(event) {
39293
+ const root = this.#contentControlClickRoot;
39294
+ if (!root) return;
39295
+ const id = getClickedContentControlId(event, root);
39296
+ const list = this.activeEditor?.doc?.contentControls?.list;
39297
+ if (!id || typeof list !== "function") return;
39298
+ try {
39299
+ const result = await list();
39300
+ if (this.#destroyed) return;
39301
+ const target$1 = toSdtRef(getContentControlItems(result).find((item) => item.id === id));
39302
+ if (target$1) this.emit("content-control:click", {
39303
+ target: target$1,
39304
+ source: "pointer"
39305
+ });
39306
+ } catch {
39307
+ return;
39308
+ }
39309
+ }
39049
39310
  async #init(config, container) {
39050
39311
  this.config = {
39051
39312
  ...this.config,
@@ -39092,7 +39353,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
39092
39353
  this.config.colors = shuffleArray(this.config.colors);
39093
39354
  this.userColorMap = /* @__PURE__ */ new Map();
39094
39355
  this.colorIndex = 0;
39095
- this.version = "2.4.0-next.3";
39356
+ this.version = "2.4.0-next.5";
39096
39357
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
39097
39358
  this.superdocId = config.superdocId || require_uuid.v4_default();
39098
39359
  this.colors = this.config.colors ?? [];
@@ -40620,6 +40881,8 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
40620
40881
  }
40621
40882
  destroy() {
40622
40883
  this.#destroyed = true;
40884
+ this.#contentControlClickRoot?.removeEventListener("click", this.#handleContentControlClick, true);
40885
+ this.#contentControlClickRoot = null;
40623
40886
  if (this.#abortUpgrade) {
40624
40887
  this.#abortUpgrade();
40625
40888
  this.#abortUpgrade = null;