superdoc 2.4.0-next.16 → 2.4.0-next.17

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.
@@ -3,7 +3,7 @@ import { t as blank_default } from "./chunks/blank-docx-DzQccOlW.es.js";
3
3
  import { t as import_eventemitter3 } from "./chunks/eventemitter3-DEIiXiH2.es.js";
4
4
  import { t as v4 } from "./chunks/uuid-H0Xcmmhy.es.js";
5
5
  import { a as init_dist$1, i as global, n as init_dist$2, o as Buffer, r as process$1, s as init_dist, t as require_jszip_min } from "./chunks/jszip-BzJ3CyxR.es.js";
6
- import { a as createV2ReviewMutationReconciler, i as isV2EditableTextMutationEvent, o as getV2TrackedChangeMutationImpact, s as DOM_CLASS_NAMES, t as createSuperDocUI } from "./chunks/create-super-doc-ui-BRBwfV-s.es.js";
6
+ import { a as getV2TrackedChangeMutationImpact, i as createV2ReviewMutationReconciler, o as DOM_CLASS_NAMES, t as createSuperDocUI } from "./chunks/create-super-doc-ui-BbNbi0cj.es.js";
7
7
  import { t as _plugin_vue_export_helper_default } from "./chunks/_plugin-vue_export-helper-BOaGB7Aw.es.js";
8
8
  import { t as PDF_TO_CSS_UNITS } from "./chunks/constants-B6VBlmKp.es.js";
9
9
  import * as Vue from "vue";
@@ -7761,6 +7761,7 @@ var useCommentsStore = defineStore("comments", () => {
7761
7761
  syncResolvedCommentsWithDocument();
7762
7762
  });
7763
7763
  watch(commentsList, () => {
7764
+ canonicalizeActiveCommentAlias();
7764
7765
  syncResolvedCommentsWithDocument();
7765
7766
  }, { deep: false });
7766
7767
  /**
@@ -8613,7 +8614,8 @@ var useCommentsStore = defineStore("comments", () => {
8613
8614
  superdoc,
8614
8615
  adapter,
8615
8616
  documentId: adapter.documentId ?? fileId,
8616
- items: outcome.items ?? []
8617
+ items: outcome.items ?? [],
8618
+ pruneStale: outcome.complete !== false
8617
8619
  });
8618
8620
  const successEvent = successEventBuilder?.({
8619
8621
  outcome,
@@ -9019,7 +9021,7 @@ var useCommentsStore = defineStore("comments", () => {
9019
9021
  trackedItems: preparedParams.length
9020
9022
  };
9021
9023
  });
9022
- const hydrateCommentsFromV2 = async ({ superdoc, adapter, documentId, trackedChangesListMode = "all", isCurrent, signal, hydrationGeneration } = {}) => withInteractionSpan("store.comments.hydrateFromV2", "comments-list", { documentId: documentId ?? null }, async () => {
9024
+ const hydrateCommentsFromV2 = async ({ superdoc, adapter, documentId, trackedChangesListMode = "all", commentIds, isCurrent, signal, hydrationGeneration } = {}) => withInteractionSpan("store.comments.hydrateFromV2", "comments-list", { documentId: documentId ?? null }, async () => {
9023
9025
  const effectiveAdapter = adapter ?? getV2CommentsAdapter(superdoc);
9024
9026
  const visibleWindow = trackedChangesListMode === "visible-window";
9025
9027
  const read = visibleWindow ? effectiveAdapter?.selectVisibleReviewComments : effectiveAdapter?.refresh;
@@ -9041,6 +9043,7 @@ var useCommentsStore = defineStore("comments", () => {
9041
9043
  let result;
9042
9044
  try {
9043
9045
  const refreshOptions = {};
9046
+ if (visibleWindow && Array.isArray(commentIds)) refreshOptions.targetIds = commentIds;
9044
9047
  if (signal) refreshOptions.signal = signal;
9045
9048
  if (typeof hydrationGeneration === "number") refreshOptions.hydrationGeneration = hydrationGeneration;
9046
9049
  result = Object.keys(refreshOptions).length > 0 ? await read.call(effectiveAdapter, refreshOptions) : await read.call(effectiveAdapter);
@@ -9071,7 +9074,7 @@ var useCommentsStore = defineStore("comments", () => {
9071
9074
  adapter: effectiveAdapter,
9072
9075
  documentId,
9073
9076
  items: result.items ?? [],
9074
- pruneStale: !visibleWindow,
9077
+ pruneStale: !visibleWindow || Array.isArray(commentIds) && (!Array.isArray(result.unresolvedIds) || result.unresolvedIds.length === 0),
9075
9078
  hydrationGeneration
9076
9079
  });
9077
9080
  return {
@@ -9304,6 +9307,27 @@ var useCommentsStore = defineStore("comments", () => {
9304
9307
  storySnapshots
9305
9308
  };
9306
9309
  };
9310
+ const reconcileAuthoritativeV2TrackedChangeSidebar = ({ superdoc, editor, documentId, refreshReason = "tracked-change-sidebar-authoritative" } = {}) => {
9311
+ const adapter = getV2TrackedChangesAdapter(superdoc) ?? editor?.v2TrackedChanges ?? null;
9312
+ if (!adapter || typeof adapter.listTrackedChanges !== "function" || typeof adapter.mapV2TrackedChangeToCommentParams !== "function") return false;
9313
+ const effectiveDocumentId = documentId ?? adapter.documentId ?? editor?.documentId ?? editor?.options?.documentId ?? superdoc?.activeEditor?.documentId ?? superdoc?.activeEditor?.options?.documentId ?? null;
9314
+ if (effectiveDocumentId == null) return false;
9315
+ const normalizedDocumentId = String(effectiveDocumentId);
9316
+ hydrateTrackedChangesFromV2({
9317
+ superdoc,
9318
+ adapter,
9319
+ documentId: normalizedDocumentId,
9320
+ trackedChangesListMode: "background-reconcile",
9321
+ refreshReason,
9322
+ blocking: false,
9323
+ isCurrent: () => {
9324
+ const activeEditor = superdoc?.activeEditor ?? null;
9325
+ const activeDocumentId = activeEditor?.documentId ?? activeEditor?.options?.documentId ?? null;
9326
+ return activeDocumentId == null || String(activeDocumentId) === normalizedDocumentId;
9327
+ }
9328
+ });
9329
+ return true;
9330
+ };
9307
9331
  /**
9308
9332
  * Bootstrap tracked-change comment threads after a DOCX import finishes.
9309
9333
  *
@@ -9341,6 +9365,12 @@ var useCommentsStore = defineStore("comments", () => {
9341
9365
  editor,
9342
9366
  structuralChanges: captured.structuralChanges
9343
9367
  });
9368
+ reconcileAuthoritativeV2TrackedChangeSidebar({
9369
+ superdoc,
9370
+ editor,
9371
+ documentId: editor?.options?.documentId,
9372
+ refreshReason: "import-bootstrap-authoritative"
9373
+ });
9344
9374
  return true;
9345
9375
  };
9346
9376
  const isCurrentImportedTrackedChangeBootstrap = (task) => {
@@ -10326,7 +10356,8 @@ var useCommentsStore = defineStore("comments", () => {
10326
10356
  lateResultDropped: true
10327
10357
  };
10328
10358
  if (!result?.ok) return result;
10329
- const pruneStale = !(trackedChangesListMode === "startup-page" || trackedChangesListMode === "interaction-prime" || trackedChangesListMode === "visible-window") && result.visibleWindowSource == null && result.complete === true && result.sourceCoverageComplete === true;
10359
+ const partialListMode = trackedChangesListMode === "startup-page" || trackedChangesListMode === "interaction-prime" || trackedChangesListMode === "visible-window";
10360
+ const pruneStale = trackedChangesListMode === "visible-window" && Array.isArray(targetIds) && (!Array.isArray(result.visibleTrackedChangeFailedIds) || result.visibleTrackedChangeFailedIds.length === 0) || !partialListMode && result.visibleWindowSource == null && result.complete === true && result.sourceCoverageComplete === true;
10330
10361
  if (signal?.aborted || trackedChangeSyncGeneration(effectiveAdapter) !== syncGeneration) return {
10331
10362
  ok: false,
10332
10363
  reason: "review-hydration-superseded",
@@ -10730,6 +10761,12 @@ var useCommentsStore = defineStore("comments", () => {
10730
10761
  broadcastChanges,
10731
10762
  structuralChanges: captured.structuralChanges
10732
10763
  });
10764
+ reconcileAuthoritativeV2TrackedChangeSidebar({
10765
+ superdoc,
10766
+ editor,
10767
+ documentId: activeDocumentId,
10768
+ refreshReason: "sync-authoritative"
10769
+ });
10733
10770
  };
10734
10771
  /**
10735
10772
  * Surface decidable whole-table structural tracked changes (table insert /
@@ -11200,6 +11237,16 @@ var useCommentsStore = defineStore("comments", () => {
11200
11237
  const syncActiveFloatingInstanceWithComment = (commentId) => {
11201
11238
  if (!doesFloatingInstanceBelongToComment(activeFloatingCommentInstanceId.value, commentId)) setActiveFloatingCommentInstance(null);
11202
11239
  };
11240
+ function canonicalizeActiveCommentAlias() {
11241
+ const activeId = normalizeCommentId(activeComment.value);
11242
+ if (!activeId) return false;
11243
+ const comment = getComment(activeId);
11244
+ const canonicalId = normalizeCommentId(comment?.commentId);
11245
+ if (!canonicalId || canonicalId === activeId) return false;
11246
+ activeComment.value = canonicalId;
11247
+ syncActiveFloatingInstanceWithComment(canonicalId);
11248
+ return true;
11249
+ }
11203
11250
  const setViewingVisibility = ({ documentMode, commentsVisible, trackChangesVisible } = {}) => {
11204
11251
  if (typeof documentMode === "string") viewingVisibility.documentMode = documentMode;
11205
11252
  if (typeof commentsVisible === "boolean") viewingVisibility.commentsVisible = commentsVisible;
@@ -13896,6 +13943,12 @@ var FloatingComments_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13896
13943
  setup(__props) {
13897
13944
  const ESTIMATED_HEIGHT = 110;
13898
13945
  const OBSERVER_MARGIN = 600;
13946
+ const SCROLL_OWNER_OVERFLOW_VALUES = /* @__PURE__ */ new Set([
13947
+ "auto",
13948
+ "scroll",
13949
+ "hidden",
13950
+ "clip"
13951
+ ]);
13899
13952
  const resolveCollisions = (positions, activeIndex, gap) => {
13900
13953
  if (activeIndex >= 0) {
13901
13954
  positions[activeIndex].top = positions[activeIndex].anchorTop;
@@ -14300,6 +14353,8 @@ var FloatingComments_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14300
14353
  let activeLayoutContinuityFrame = null;
14301
14354
  let directDecisionContinuity = null;
14302
14355
  let directDecisionSourceId = null;
14356
+ let ownerScrollContinuityResetFrame = null;
14357
+ const ownerScrollTargets = /* @__PURE__ */ new Set();
14303
14358
  const releaseDirectDecisionContinuity = () => {
14304
14359
  directDecisionContinuity = null;
14305
14360
  directDecisionSourceId = null;
@@ -14363,6 +14418,36 @@ var FloatingComments_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14363
14418
  }
14364
14419
  setInstantLayoutTransitionsDisabled(false);
14365
14420
  };
14421
+ const releaseDecisionContinuityForOwnerScroll = () => {
14422
+ if (!directDecisionContinuity && !sidebarContinuityAnchor) return;
14423
+ releaseDirectDecisionContinuity();
14424
+ clearSidebarContinuityAnchor();
14425
+ setInstantLayoutTransitionsDisabled(true);
14426
+ sidebarOffsetY.value = 0;
14427
+ if (ownerScrollContinuityResetFrame != null) cancelAnimationFrame(ownerScrollContinuityResetFrame);
14428
+ ownerScrollContinuityResetFrame = requestAnimationFrame(() => {
14429
+ ownerScrollContinuityResetFrame = null;
14430
+ if (!directDecisionContinuity && !sidebarContinuityAnchor) setInstantLayoutTransitionsDisabled(false);
14431
+ });
14432
+ };
14433
+ const handleOwnerScroll = () => {
14434
+ releaseDecisionContinuityForOwnerScroll();
14435
+ refreshViewportWindow();
14436
+ };
14437
+ const registerOwnerScrollListeners = () => {
14438
+ const addTarget = (target) => {
14439
+ if (!target?.addEventListener || ownerScrollTargets.has(target)) return;
14440
+ target.addEventListener("scroll", handleOwnerScroll, { passive: true });
14441
+ ownerScrollTargets.add(target);
14442
+ };
14443
+ addTarget(props.parent);
14444
+ for (let ancestor = floatingCommentsContainer.value?.parentElement; ancestor; ancestor = ancestor.parentElement) if (SCROLL_OWNER_OVERFLOW_VALUES.has(window.getComputedStyle(ancestor).overflowY)) addTarget(ancestor);
14445
+ addTarget(window);
14446
+ };
14447
+ const unregisterOwnerScrollListeners = () => {
14448
+ for (const target of ownerScrollTargets) target.removeEventListener?.("scroll", handleOwnerScroll);
14449
+ ownerScrollTargets.clear();
14450
+ };
14366
14451
  const scheduleSidebarContinuityAlignment = () => {
14367
14452
  if (!sidebarContinuityAnchor || continuityAlignmentScheduled) return;
14368
14453
  continuityAlignmentScheduled = true;
@@ -14615,7 +14700,7 @@ var FloatingComments_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14615
14700
  });
14616
14701
  onMounted(() => {
14617
14702
  setupObserver();
14618
- props.parent?.addEventListener?.("scroll", refreshViewportWindow, { passive: true });
14703
+ registerOwnerScrollListeners();
14619
14704
  window.addEventListener("resize", refreshViewportWindow, { passive: true });
14620
14705
  document.addEventListener("pointerdown", releaseDirectDecisionContinuityForUnrelatedPointer, true);
14621
14706
  nextTick(observePlaceholders);
@@ -14629,7 +14714,11 @@ var FloatingComments_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14629
14714
  cancelAnimationFrame(activeLayoutContinuityFrame);
14630
14715
  activeLayoutContinuityFrame = null;
14631
14716
  }
14632
- props.parent?.removeEventListener?.("scroll", refreshViewportWindow);
14717
+ if (ownerScrollContinuityResetFrame != null) {
14718
+ cancelAnimationFrame(ownerScrollContinuityResetFrame);
14719
+ ownerScrollContinuityResetFrame = null;
14720
+ }
14721
+ unregisterOwnerScrollListeners();
14633
14722
  window.removeEventListener("resize", refreshViewportWindow);
14634
14723
  document.removeEventListener("pointerdown", releaseDirectDecisionContinuityForUnrelatedPointer, true);
14635
14724
  if (viewportFrame != null) {
@@ -14697,7 +14786,7 @@ var FloatingComments_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14697
14786
  }), 128))], 4)], 36);
14698
14787
  };
14699
14788
  }
14700
- }, [["__scopeId", "data-v-a0a841ce"]]);
14789
+ }, [["__scopeId", "data-v-d8d03209"]]);
14701
14790
  //#endregion
14702
14791
  //#region src/components/CommentsLayer/PdfCommentsLayer.vue
14703
14792
  var _hoisted_1$22 = {
@@ -15373,6 +15462,19 @@ var VALID_COMMENTS_DISPLAY_MODES = /* @__PURE__ */ new Set([
15373
15462
  "inline"
15374
15463
  ]);
15375
15464
  /**
15465
+ * Whether a context-menu event landed inside the tracked-change carrier that
15466
+ * is already visually active. The review visual owner maintains this marker,
15467
+ * so the right-click path can stay synchronous and avoid a catalog lookup or
15468
+ * document-wide DOM query.
15469
+ *
15470
+ * @param {EventTarget | null} target
15471
+ * @returns {boolean}
15472
+ */
15473
+ function isActiveTrackedChangeContextMenuTarget(target) {
15474
+ const element = target;
15475
+ return typeof element?.closest === "function" && element.closest(".track-change-focused") != null;
15476
+ }
15477
+ /**
15376
15478
  * Normalize adaptive comments UI policy fields.
15377
15479
  *
15378
15480
  * @param {false | Record<string, unknown> | undefined} commentsConfig
@@ -15808,74 +15910,6 @@ function resolveV2ReviewTargetCommentId(target, getComment) {
15808
15910
  return commentId != null ? String(commentId) : null;
15809
15911
  }
15810
15912
  //#endregion
15811
- //#region src/helpers/v2-remote-review-hydration.js
15812
- function normalizeDocumentId(value) {
15813
- return value == null ? null : String(value);
15814
- }
15815
- function createV2RemoteReviewHydrationScheduler({ hydrate, getActiveDocumentId, debounceMs = 250, ceilingMs = 1e3, now = () => Date.now(), setTimer = (callback, delay) => setTimeout(callback, delay), clearTimer = (timer) => clearTimeout(timer) }) {
15816
- let timer = null;
15817
- let heldSinceMs = null;
15818
- let pendingDocumentId = null;
15819
- const matchesActiveDocument = (documentId) => {
15820
- return normalizeDocumentId(getActiveDocumentId()) === documentId;
15821
- };
15822
- const clear = () => {
15823
- if (timer != null) clearTimer(timer);
15824
- timer = null;
15825
- heldSinceMs = null;
15826
- pendingDocumentId = null;
15827
- };
15828
- const schedule = (documentId) => {
15829
- const normalizedDocumentId = normalizeDocumentId(documentId);
15830
- if (!matchesActiveDocument(normalizedDocumentId)) return false;
15831
- if (pendingDocumentId !== normalizedDocumentId) clear();
15832
- const scheduledAtMs = now();
15833
- pendingDocumentId = normalizedDocumentId;
15834
- heldSinceMs ??= scheduledAtMs;
15835
- if (timer != null) clearTimer(timer);
15836
- const ceilingRemainingMs = Math.max(0, ceilingMs - (scheduledAtMs - heldSinceMs));
15837
- timer = setTimer(() => {
15838
- const deliveredDocumentId = pendingDocumentId;
15839
- timer = null;
15840
- heldSinceMs = null;
15841
- pendingDocumentId = null;
15842
- if (matchesActiveDocument(deliveredDocumentId)) hydrate();
15843
- }, Math.min(debounceMs, ceilingRemainingMs));
15844
- return true;
15845
- };
15846
- return {
15847
- schedule,
15848
- clear
15849
- };
15850
- }
15851
- //#endregion
15852
- //#region src/helpers/v2-typing-review-hydration.js
15853
- /**
15854
- * Coalesce automatic review-catalog reconciliation behind a genuine typing
15855
- * quiet period. Every typing signal restarts the trailing timer; there is no
15856
- * maximum-wait escape hatch because that would deliberately run the expensive
15857
- * catalog reads in the middle of a sustained input burst.
15858
- */
15859
- function createV2TypingReviewHydrationScheduler({ hydrate, idleMs = 6500, setTimer = (callback, delay) => setTimeout(callback, delay), clearTimer = (timer) => clearTimeout(timer) }) {
15860
- let timer = null;
15861
- const clear = () => {
15862
- if (timer != null) clearTimer(timer);
15863
- timer = null;
15864
- };
15865
- const schedule = () => {
15866
- clear();
15867
- timer = setTimer(() => {
15868
- timer = null;
15869
- hydrate();
15870
- }, idleMs);
15871
- };
15872
- return {
15873
- schedule,
15874
- clear,
15875
- isPending: () => timer != null
15876
- };
15877
- }
15878
- //#endregion
15879
15913
  //#region src/helpers/v2-author-required-rejection.js
15880
15914
  var NO_AUTHOR_SIGNAL = "no-author-configured";
15881
15915
  /** Stable, non-terminal exception code surfaced to consumers. */
@@ -20312,9 +20346,9 @@ var _hoisted_1$16 = {
20312
20346
  var _hoisted_2$13 = ["innerHTML"];
20313
20347
  var _hoisted_3$10 = { class: "superdoc__document document" };
20314
20348
  var _hoisted_4$7 = { class: "floating-comments" };
20349
+ var TRACKED_CHANGE_CARRIERS_RESTAMPED_EVENT = "superdoc:v2-tracked-change-carriers-restamped";
20315
20350
  var UNAVAILABLE_COMMAND_RESULT = false;
20316
20351
  var V2_SELECTION_TOOLBAR_SYNC_RETRY_FRAMES = 3;
20317
- var V2_TYPING_REVIEW_HYDRATION_IDLE_MS = 6500;
20318
20352
  var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
20319
20353
  __name: "SuperDoc",
20320
20354
  emits: ["selection-update"],
@@ -20477,6 +20511,27 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
20477
20511
  editor: proxy.$superdoc?.activeEditor
20478
20512
  });
20479
20513
  };
20514
+ const reconcileAuthoritativeV2TrackedChangeSidebar = ({ adapter, documentId, refreshReason = "startup-authoritative" } = {}) => {
20515
+ if (!adapter || typeof adapter.listTrackedChanges !== "function") return false;
20516
+ const normalizedDocumentId = documentId == null ? null : String(documentId);
20517
+ if (!normalizedDocumentId) return false;
20518
+ commentsStore.hydrateTrackedChangesFromV2?.({
20519
+ superdoc: proxy.$superdoc,
20520
+ adapter,
20521
+ documentId: normalizedDocumentId,
20522
+ trackedChangesListMode: "background-reconcile",
20523
+ refreshReason,
20524
+ blocking: false,
20525
+ isCurrent: () => {
20526
+ const activeEditor = proxy.$superdoc?.activeEditor ?? null;
20527
+ const activeDocumentId = activeEditor?.documentId ?? activeEditor?.options?.documentId ?? null;
20528
+ if (activeDocumentId != null && String(activeDocumentId) !== normalizedDocumentId) return false;
20529
+ const activeAdapter = activeEditor?.v2TrackedChanges ?? commentsStore.getV2TrackedChangesAdapter?.(proxy.$superdoc);
20530
+ return !activeAdapter || activeAdapter === adapter;
20531
+ }
20532
+ });
20533
+ return true;
20534
+ };
20480
20535
  const scheduleReplayTrackedChangeSync = () => {
20481
20536
  pendingReplayTrackedChangeSync.value = true;
20482
20537
  nextTick(() => {
@@ -21020,7 +21075,11 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21020
21075
  pageFurniture: pageFurniture ?? null,
21021
21076
  presence: presence ?? null,
21022
21077
  lock: lock ?? null,
21023
- reviewHydration: { getDiagnostics: () => v2ReviewHydrationController.getDiagnostics() },
21078
+ reviewHydration: {
21079
+ getDiagnostics: () => v2ReviewHydrationController.getDiagnostics(),
21080
+ getSnapshot: () => v2ReviewHydrationController.getSnapshot?.() ?? null,
21081
+ subscribe: (listener) => v2ReviewHydrationController.subscribe?.(listener) ?? (() => void 0)
21082
+ },
21024
21083
  extensions: createV2ExtensionsFacet(host),
21025
21084
  fonts: fonts ?? host?.getFontRuntime?.() ?? null,
21026
21085
  /**
@@ -21076,6 +21135,11 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21076
21135
  console.warn("[SuperDoc][v2] initial render-readiness snapshot failed", err);
21077
21136
  }
21078
21137
  }
21138
+ if (commentsModuleEnabled && trackedChangesAdapter) reconcileAuthoritativeV2TrackedChangeSidebar({
21139
+ adapter: trackedChangesAdapter,
21140
+ documentId,
21141
+ refreshReason: "startup-authoritative"
21142
+ });
21079
21143
  if (areDocumentsReady.value && !proxy.$superdoc.config.collaboration) isReady.value = true;
21080
21144
  isFloatingCommentsReady.value = true;
21081
21145
  hasInitializedLocations.value = true;
@@ -21344,7 +21408,6 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21344
21408
  }
21345
21409
  },
21346
21410
  onCommittedPagePaint: (commit) => {
21347
- if (commit?.routeLane === "canonical.typing-mutation" || v2TypingReviewHydrationScheduler.isPending()) return;
21348
21411
  v2ReviewHydrationController.onCommittedPagePaint?.({
21349
21412
  ...commit,
21350
21413
  documentId: commit?.payload?.documentId ?? null
@@ -21389,7 +21452,6 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21389
21452
  const onV2RenderReadiness = (payload) => {
21390
21453
  const snapshot = payload?.snapshot ?? payload ?? null;
21391
21454
  if (!snapshot) return;
21392
- if (v2TypingReviewHydrationScheduler.isPending()) return;
21393
21455
  v2ReviewHydrationController.onRenderReadiness(snapshot);
21394
21456
  };
21395
21457
  const v2PageMetricsSnapshot = shallowRef(null);
@@ -21439,8 +21501,6 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21439
21501
  if (latestV2MountStage && (clearedDocumentId == null || latestV2MountStage.dataset?.superdocV2DocumentId === clearedDocumentId)) latestV2MountStage = null;
21440
21502
  v2ReviewHydrationController.reset("render-cleared");
21441
21503
  v2ReviewMutationReconciler.reset();
21442
- clearV2TypingReviewHydrationTimer();
21443
- v2RemoteReviewHydrationScheduler.clear();
21444
21504
  commentsStore.setV2CommentsAdapter?.(null);
21445
21505
  commentsStore.setV2TrackedChangesAdapter?.(null);
21446
21506
  commentsStore.clearEditorCommentPositions?.();
@@ -21449,26 +21509,6 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21449
21509
  v2RulerHostStyle.value = {};
21450
21510
  v2RulerReady.value = false;
21451
21511
  };
21452
- const hydrateV2CommentRowsFromHost = () => {
21453
- const commentsAdapter = proxy.$superdoc?.activeEditor?.v2Comments ?? null;
21454
- if (!commentsAdapter) return;
21455
- commentsStore.hydrateCommentsFromV2?.({
21456
- superdoc: proxy.$superdoc,
21457
- adapter: commentsAdapter,
21458
- documentId: proxy.$superdoc?.activeEditor?.documentId ?? null
21459
- });
21460
- };
21461
- const hydrateV2ReviewRowsFromHost = (options = {}) => {
21462
- hydrateV2CommentRowsFromHost();
21463
- const trackedChangesAdapter = proxy.$superdoc?.activeEditor?.v2TrackedChanges ?? null;
21464
- if (!trackedChangesAdapter) return;
21465
- commentsStore.hydrateTrackedChangesFromV2?.({
21466
- superdoc: proxy.$superdoc,
21467
- adapter: trackedChangesAdapter,
21468
- documentId: proxy.$superdoc?.activeEditor?.documentId ?? null,
21469
- ...options
21470
- });
21471
- };
21472
21512
  const v2ReviewMutationReconciler = createV2ReviewMutationReconciler({
21473
21513
  getContext: () => {
21474
21514
  const activeEditor = proxy.$superdoc?.activeEditor ?? null;
@@ -21498,31 +21538,10 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21498
21538
  reason: "review-reconcile"
21499
21539
  })
21500
21540
  });
21501
- const v2TypingReviewHydrationScheduler = createV2TypingReviewHydrationScheduler({
21502
- idleMs: V2_TYPING_REVIEW_HYDRATION_IDLE_MS,
21503
- hydrate: () => v2ReviewHydrationController.reconcileInBackground?.("typing-idle")
21504
- });
21505
- const clearV2TypingReviewHydrationTimer = () => {
21506
- v2TypingReviewHydrationScheduler.clear();
21507
- };
21508
- const scheduleV2TypingReviewHydration = () => {
21509
- v2TypingReviewHydrationScheduler.schedule();
21510
- };
21511
- const v2RemoteReviewHydrationScheduler = createV2RemoteReviewHydrationScheduler({
21512
- hydrate: () => {
21513
- if (v2TypingReviewHydrationScheduler.isPending()) return false;
21514
- return v2ReviewHydrationController.reconcileInBackground?.("remote-review-change");
21515
- },
21516
- getActiveDocumentId: () => {
21517
- const activeEditor = proxy.$superdoc?.activeEditor ?? null;
21518
- return activeEditor?.documentId ?? activeEditor?.options?.documentId ?? null;
21519
- }
21520
- });
21521
21541
  const onV2HostEvent = (document, event) => {
21522
21542
  if (!event) return;
21523
21543
  const documentId = document?.id ?? null;
21524
21544
  if (event.type === "review-mutation:started") {
21525
- clearV2TypingReviewHydrationTimer();
21526
21545
  const activeEditor = proxy.$superdoc?.activeEditor ?? null;
21527
21546
  commentsStore.supersedeV2ReviewHydration?.({
21528
21547
  commentsAdapter: activeEditor?.v2Comments ?? null,
@@ -21544,8 +21563,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21544
21563
  return;
21545
21564
  }
21546
21565
  if (event.type === "collaboration:remote-changed") {
21547
- v2ReviewHydrationController.invalidate("collaboration:remote-changed");
21548
- v2RemoteReviewHydrationScheduler.schedule(documentId);
21566
+ if (event.reviewChanged !== false) v2ReviewHydrationController.invalidate("collaboration:remote-review-changed");
21549
21567
  return;
21550
21568
  }
21551
21569
  if (event.type === "source:complete") {
@@ -21570,11 +21588,12 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21570
21588
  emitV2EditorUpdate();
21571
21589
  }
21572
21590
  if (event.type !== "mutation:committed") return;
21573
- v2ReviewHydrationController.invalidate("mutation-committed");
21591
+ if (event.reviewSidecarOnly === true) v2ReviewHydrationController.hydrateNow("review-sidecar-committed");
21574
21592
  const reviewImpact = getV2TrackedChangeMutationImpact(event);
21575
21593
  if (Array.isArray(reviewImpact?.remappedPairs) && reviewImpact.remappedPairs.length > 0) commentsStore.remapTrackedChangeIdentities?.(reviewImpact.remappedPairs, { documentId });
21576
21594
  if (reviewImpact) armV2TrackedChangeRestampGeometryRetention("tracked-change-mutation");
21577
- const readiness = (proxy.$superdoc?.activeEditor ?? null)?.documentMutationReadiness ?? null;
21595
+ const activeEditor = proxy.$superdoc?.activeEditor ?? null;
21596
+ const readiness = activeEditor?.documentMutationReadiness ?? null;
21578
21597
  const receipt = event.origin === "history" ? null : event.receipt;
21579
21598
  const canWaitForExactPaint = reviewImpact && typeof receipt?.txId === "string" && receipt.txId.length > 0 && typeof readiness?.whenPainted === "function";
21580
21599
  const reconciliation = v2ReviewMutationReconciler.enqueueAfterPaint(reviewImpact, canWaitForExactPaint ? () => readiness.whenPainted.call(readiness, receipt) : null);
@@ -21589,43 +21608,37 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21589
21608
  resumeDomains: reconciledAllResolved ? ["comments"] : ["comments", "trackedChanges"],
21590
21609
  trackedRowCount: commentsStore.getV2TrackedChangeRowCount?.(documentId) ?? null
21591
21610
  });
21611
+ if (!reconciledAllResolved) reconcileAuthoritativeV2TrackedChangeSidebar({
21612
+ adapter: activeEditor?.v2TrackedChanges ?? null,
21613
+ documentId,
21614
+ refreshReason: "mutation-authoritative"
21615
+ });
21592
21616
  };
21593
21617
  Promise.resolve(reconciliation).then(settleReviewMutation, () => settleReviewMutation(false));
21594
21618
  return;
21595
21619
  }
21596
- const isTypingMutation = isV2EditableTextMutationEvent(event);
21597
- if (!isTypingMutation) clearV2TypingReviewHydrationTimer();
21598
- if (reviewImpact?.reconcileMode === "authoritative" && reviewImpact.upsertIds.size > 0) {
21599
- hydrateV2CommentRowsFromHost();
21600
- return;
21601
- }
21602
- if (isTypingMutation) {
21603
- scheduleV2TypingReviewHydration();
21604
- return;
21605
- }
21620
+ if (reviewImpact?.reconcileMode === "authoritative" && reviewImpact.upsertIds.size > 0) return;
21606
21621
  if (reviewImpact?.removedIds.size > 0 && reviewImpact.upsertIds.size === 0) return;
21607
- hydrateV2ReviewRowsFromHost();
21608
21622
  };
21609
21623
  const onV2LinkClick = (payload) => {
21610
21624
  linkPopover.handleLinkClick(payload);
21611
21625
  };
21612
- const recollectV2GeometryIfActive = () => {
21626
+ const recollectV2GeometryIfActive = (options = void 0) => {
21613
21627
  if (!isV2Mode.value) return;
21614
21628
  if (!v2GeometryPublisher.getLastPayload()) return;
21615
21629
  if (v2GeometryRafHandle && typeof cancelAnimationFrame === "function") cancelAnimationFrame(v2GeometryRafHandle);
21616
21630
  if (typeof requestAnimationFrame !== "function") {
21617
- v2GeometryPublisher.recollect();
21631
+ v2GeometryPublisher.recollect(resolveV2GeometryPublishOptions(options));
21618
21632
  return;
21619
21633
  }
21620
21634
  v2GeometryRafHandle = requestAnimationFrame(() => {
21621
21635
  v2GeometryRafHandle = 0;
21622
- v2GeometryPublisher.recollect();
21636
+ v2GeometryPublisher.recollect(resolveV2GeometryPublishOptions(options));
21623
21637
  });
21624
21638
  };
21625
21639
  const handleV2DocumentModeChange = () => {
21626
21640
  if (!isV2Mode.value) return;
21627
21641
  try {
21628
- clearV2TypingReviewHydrationTimer();
21629
21642
  v2ReviewHydrationController.hydrateNow("document-mode-change");
21630
21643
  } catch (err) {
21631
21644
  console.warn("[SuperDoc][v2] document-mode-change rehydrate failed", err);
@@ -21644,22 +21657,6 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21644
21657
  else republishGeometry();
21645
21658
  });
21646
21659
  };
21647
- let v2BuiltInReviewSurfaceOpen = false;
21648
- let v2ExternalReviewSurfaceOpen = false;
21649
- const syncV2ReviewCatalogDemand = () => {
21650
- if (!isV2Mode.value) return;
21651
- if (!v2BuiltInReviewSurfaceOpen && !v2ExternalReviewSurfaceOpen) {
21652
- v2ReviewHydrationController.releaseCatalogDemand();
21653
- return;
21654
- }
21655
- clearV2TypingReviewHydrationTimer();
21656
- v2ReviewHydrationController.demandCatalog("review-sidebar-visible");
21657
- };
21658
- const handleV2CommentsListChange = ({ isRendered } = {}) => {
21659
- v2ExternalReviewSurfaceOpen = isRendered === true;
21660
- syncV2ReviewCatalogDemand();
21661
- };
21662
- proxy.$superdoc?.on?.("comments-list-change", handleV2CommentsListChange);
21663
21660
  const getV2EditorFailureMessage = (reason) => {
21664
21661
  switch (reason) {
21665
21662
  case "editing-mount-required": return "SuperDoc could not load the document editor because the page did not provide a mount container.";
@@ -21734,7 +21731,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21734
21731
  if (!root) return;
21735
21732
  if (!(event.target instanceof Node) || !root.contains(event.target)) return;
21736
21733
  if (layers.value?.contains(event.target)) {
21737
- commentsStore.setActiveComment(proxy.$superdoc, null);
21734
+ if (!isActiveTrackedChangeContextMenuTarget(event.target)) commentsStore.setActiveComment(proxy.$superdoc, null);
21738
21735
  commentsStore.removePendingComment(proxy.$superdoc);
21739
21736
  resetClickAnchor();
21740
21737
  }
@@ -21787,16 +21784,17 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21787
21784
  onFontsResolved: onFontsResolvedFn,
21788
21785
  onPageCountKnown: proxy.$superdoc.config.onPageCountKnown ?? null,
21789
21786
  onReviewWindowPlanned: (payload) => {
21790
- if (payload?.routeLane === "canonical.typing-mutation") {
21791
- v2TypingReviewHydrationScheduler.schedule();
21792
- return;
21793
- }
21794
- if (v2TypingReviewHydrationScheduler.isPending()) return;
21795
21787
  v2ReviewHydrationController.onReviewWindowPlanned?.({
21796
21788
  ...payload,
21797
21789
  documentId: doc.id
21798
21790
  });
21799
21791
  },
21792
+ onReviewWindowCommitted: (payload) => {
21793
+ v2ReviewHydrationController.onCommittedPagePaint?.({
21794
+ ...payload,
21795
+ documentId: doc.id
21796
+ });
21797
+ },
21800
21798
  fontAssets: proxy.$superdoc.config.fonts,
21801
21799
  proofing: resolvedProofingConfig.value,
21802
21800
  isNewFile,
@@ -22124,8 +22122,6 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22124
22122
  });
22125
22123
  watch(showCommentsSidebar, (value) => {
22126
22124
  proxy.$superdoc.broadcastSidebarToggle(value);
22127
- v2BuiltInReviewSurfaceOpen = value === true;
22128
- syncV2ReviewCatalogDemand();
22129
22125
  });
22130
22126
  useViewportFit({
22131
22127
  getSuperdoc: () => proxy.$superdoc,
@@ -22150,6 +22146,16 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22150
22146
  const handleViewportScrollOrResize = () => {
22151
22147
  recollectV2GeometryIfActive();
22152
22148
  };
22149
+ const handleV2TrackedChangeCarriersRestamped = (event) => {
22150
+ if (!isV2Mode.value) return;
22151
+ const itemIds = Array.isArray(event?.detail?.itemIds) ? event.detail.itemIds.map((id) => id == null ? "" : String(id)).filter(Boolean) : [];
22152
+ armV2TrackedChangeRestampGeometryRetention(event?.detail?.refreshReason ?? "tracked-change-restamp");
22153
+ recollectV2GeometryIfActive({
22154
+ retainMissingTrackedChangeGeometry: true,
22155
+ ...itemIds.length > 0 ? { retainedTrackedChangeIds: itemIds } : {},
22156
+ reason: "tracked-change-restamp"
22157
+ });
22158
+ };
22153
22159
  onMounted(() => {
22154
22160
  document.addEventListener("contextmenu", handleDocumentContextMenu, true);
22155
22161
  document.addEventListener("keydown", handleDocumentShortcut, true);
@@ -22157,6 +22163,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22157
22163
  claimFindShortcut(findShortcutOwner);
22158
22164
  superdocRoot.value?.addEventListener("pointerdown", handleFindOwnershipInteraction, true);
22159
22165
  superdocRoot.value?.addEventListener("focusin", handleFindOwnershipInteraction, true);
22166
+ superdocRoot.value?.addEventListener(TRACKED_CHANGE_CARRIERS_RESTAMPED_EVENT, handleV2TrackedChangeCarriersRestamped);
22160
22167
  if (typeof window !== "undefined") {
22161
22168
  window.addEventListener("scroll", handleViewportScrollOrResize, true);
22162
22169
  window.addEventListener("resize", handleViewportScrollOrResize, true);
@@ -22273,6 +22280,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22273
22280
  proxy.$superdoc?.off?.("search:open", handleOpenFindRequest);
22274
22281
  superdocRoot.value?.removeEventListener("pointerdown", handleFindOwnershipInteraction, true);
22275
22282
  superdocRoot.value?.removeEventListener("focusin", handleFindOwnershipInteraction, true);
22283
+ superdocRoot.value?.removeEventListener(TRACKED_CHANGE_CARRIERS_RESTAMPED_EVENT, handleV2TrackedChangeCarriersRestamped);
22276
22284
  releaseFindShortcut(findShortcutOwner);
22277
22285
  if (typeof window !== "undefined") {
22278
22286
  window.removeEventListener("scroll", handleViewportScrollOrResize, true);
@@ -22282,8 +22290,6 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22282
22290
  cancelAnimationFrame(v2GeometryRafHandle);
22283
22291
  v2GeometryRafHandle = 0;
22284
22292
  }
22285
- clearV2TypingReviewHydrationTimer();
22286
- v2RemoteReviewHydrationScheduler.clear();
22287
22293
  document.removeEventListener("focusin", handleRuntimeFocusIn, true);
22288
22294
  document.removeEventListener("pointerdown", handleRuntimePointerDown, true);
22289
22295
  document.removeEventListener("mousedown", handleRuntimeMouseDown, true);
@@ -22291,7 +22297,6 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22291
22297
  document.removeEventListener("mouseup", handleDocumentSelectionChange, true);
22292
22298
  document.removeEventListener("selectionchange", handleDocumentSelectionChange);
22293
22299
  proxy.$superdoc?.off?.("document-mode-change", handleV2DocumentModeChange);
22294
- proxy.$superdoc?.off?.("comments-list-change", handleV2CommentsListChange);
22295
22300
  });
22296
22301
  const selectionLayer = ref(null);
22297
22302
  const isDragging = ref(false);
@@ -22787,7 +22792,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22787
22792
  ], 38);
22788
22793
  };
22789
22794
  }
22790
- }, [["__scopeId", "data-v-25570fd2"]]);
22795
+ }, [["__scopeId", "data-v-6833a014"]]);
22791
22796
  //#endregion
22792
22797
  //#region src/core/create-app.js
22793
22798
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -43264,7 +43269,7 @@ var SuperDoc = class extends import_eventemitter3.default {
43264
43269
  this.config.colors = shuffleArray(this.config.colors);
43265
43270
  this.userColorMap = /* @__PURE__ */ new Map();
43266
43271
  this.colorIndex = 0;
43267
- this.version = "2.4.0-next.16";
43272
+ this.version = "2.4.0-next.17";
43268
43273
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
43269
43274
  this.superdocId = config.superdocId || v4();
43270
43275
  this.colors = this.config.colors ?? [];