superdoc 2.0.0-next.26 → 2.0.0-next.28

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 (39) hide show
  1. package/dist/chunks/{create-super-doc-ui-CBs8xQUw.es.js → create-super-doc-ui-BlnUCtrx.es.js} +634 -115
  2. package/dist/chunks/{create-super-doc-ui-CHZKlLiH.cjs → create-super-doc-ui-CZBUMdjl.cjs} +634 -115
  3. package/dist/collaboration-upgrade-engine.cjs +1 -1
  4. package/dist/collaboration-upgrade-engine.es.js +1 -1
  5. package/dist/document-api/src/comments/comments.types.d.ts +9 -0
  6. package/dist/document-api/src/content-controls/content-controls.types.d.ts +13 -1
  7. package/dist/document-api/src/contract/operation-definitions.d.ts +2 -2
  8. package/dist/document-api/src/track-changes/track-changes.d.ts +6 -2
  9. package/dist/document-api/src/types/clipboard.d.ts +5 -1
  10. package/dist/document-api/src/types/table-operations.types.d.ts +6 -4
  11. package/dist/document-api/src/types/track-changes.types.d.ts +15 -0
  12. package/dist/layout-engine/contracts/src/incremental-dependency.d.ts +10 -0
  13. package/dist/layout-engine/contracts/src/index.d.ts +39 -0
  14. package/dist/layout-engine/layout-bridge/src/incrementalLayout.d.ts +23 -1
  15. package/dist/layout-engine/layout-engine/src/index.d.ts +17 -0
  16. package/dist/layout-engine/layout-engine/src/paginator.d.ts +16 -0
  17. package/dist/layout-engine/layout-engine/src/paragraph-layout-eligibility.d.ts +1 -4
  18. package/dist/layout-engine/style-engine/src/normalize/types.d.ts +1 -0
  19. package/dist/public/ui-react.cjs +1 -1
  20. package/dist/public/ui-react.es.js +1 -1
  21. package/dist/public/ui.cjs +1 -1
  22. package/dist/public/ui.es.js +1 -1
  23. package/dist/style.css +119 -100
  24. package/dist/style.layered.css +119 -100
  25. package/dist/superdoc/src/components/CommentsLayer/collect-removed-comment-ids.d.ts +1 -0
  26. package/dist/superdoc/src/components/CommentsLayer/collect-tracked-change-thread.d.ts +1 -1
  27. package/dist/superdoc/src/components/CommentsLayer/tracked-change-threading.d.ts +2 -0
  28. package/dist/superdoc/src/core/types/index.d.ts +7 -0
  29. package/dist/superdoc/src/helpers/v2-remote-review-hydration.d.ts +12 -0
  30. package/dist/superdoc/src/public/ui/reasons.d.ts +8 -0
  31. package/dist/superdoc/src/stores/comments-store.d.ts +9 -9
  32. package/dist/superdoc/src/stores/helpers/floating-comment-instances.d.ts +2 -10
  33. package/dist/superdoc/src/stores/superdoc-store.d.ts +27 -27
  34. package/dist/superdoc.cjs +286 -82
  35. package/dist/superdoc.es.js +286 -82
  36. package/dist-cdn/style.layered.css +1 -1
  37. package/dist-cdn/superdoc.min.css +1 -1
  38. package/dist-cdn/superdoc.min.js +37 -37
  39. package/package.json +3 -2
@@ -5,7 +5,7 @@ import { t as v4_default } from "./chunks/uuid-B2Sqk-3p.es.js";
5
5
  import { a as init_dist, i as global, n as init_dist$1, r as process$1, t as require_jszip_min } from "./chunks/jszip-DzmwAHr3.es.js";
6
6
  import { t as __plugin_vue_export_helper_default } from "./chunks/_plugin-vue_export-helper-CInC0bKI.es.js";
7
7
  import { n as PDF_TO_CSS_UNITS } from "./chunks/constants-CY3R3_kF.es.js";
8
- import { a as createV2ReviewMutationReconciler, i as isV2EditableTextMutationEvent, o as getV2TrackedChangeMutationImpact, t as createSuperDocUI } from "./chunks/create-super-doc-ui-CBs8xQUw.es.js";
8
+ import { a as createV2ReviewMutationReconciler, i as isV2EditableTextMutationEvent, o as getV2TrackedChangeMutationImpact, t as createSuperDocUI } from "./chunks/create-super-doc-ui-BlnUCtrx.es.js";
9
9
  import * as Vue from "vue";
10
10
  import { Fragment, Teleport, Transition, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineAsyncComponent, defineComponent, getCurrentInstance, h, inject, markRaw, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onActivated, onBeforeUnmount, onDeactivated, onMounted, openBlock, reactive, ref, renderList, renderSlot, resolveDirective, resolveDynamicComponent, shallowRef, toDisplayString, toRaw, toRef, unref, useAttrs, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
11
11
  import "y-websocket";
@@ -1768,6 +1768,7 @@ function useComment(params) {
1768
1768
  const importedId = params.importedId;
1769
1769
  const parentCommentId = params.parentCommentId;
1770
1770
  const trackedChangeParentId = params.trackedChangeParentId;
1771
+ const trackedChangeThreadParentId = ref(params.trackedChangeThreadParentId);
1771
1772
  const fileId = params.fileId;
1772
1773
  const fileType = params.fileType;
1773
1774
  const createdAtVersionNumber = params.createdAtVersionNumber;
@@ -1948,6 +1949,7 @@ function useComment(params) {
1948
1949
  importedId,
1949
1950
  parentCommentId,
1950
1951
  trackedChangeParentId,
1952
+ trackedChangeThreadParentId: trackedChangeThreadParentId.value,
1951
1953
  fileId,
1952
1954
  fileType,
1953
1955
  mentions: mentions.value.map((u) => {
@@ -2000,6 +2002,7 @@ function useComment(params) {
2000
2002
  importedId,
2001
2003
  parentCommentId,
2002
2004
  trackedChangeParentId,
2005
+ trackedChangeThreadParentId,
2003
2006
  fileId,
2004
2007
  fileType,
2005
2008
  mentions,
@@ -2514,7 +2517,7 @@ var aggregateRectBounds = (rects) => {
2514
2517
  };
2515
2518
  var groupRectsByPage = (rects) => {
2516
2519
  const groupedRects = /* @__PURE__ */ new Map();
2517
- rects.forEach((rect) => {
2520
+ (Array.isArray(rects) ? rects : []).forEach((rect) => {
2518
2521
  const pageIndex = toFinitePageIndex(rect?.pageIndex);
2519
2522
  if (pageIndex == null) return;
2520
2523
  const pageRects = groupedRects.get(pageIndex);
@@ -2541,31 +2544,40 @@ var resolveSelectionPageIndex = (comment) => {
2541
2544
  };
2542
2545
  var buildSingleFloatingCommentInstance = ({ id, threadId, comment, positionKey, positionEntry }) => {
2543
2546
  const geometryPageIndex = toFinitePageIndex(positionEntry?.pageIndex);
2544
- const pageIndex = geometryPageIndex != null ? geometryPageIndex : resolveSelectionPageIndex(comment);
2547
+ const fallbackPageIndex = comment?.trackedChange ? null : resolveSelectionPageIndex(comment);
2545
2548
  return {
2546
2549
  id,
2547
2550
  threadId,
2548
2551
  comment,
2549
2552
  positionKey,
2550
2553
  positionEntry: positionEntry ?? null,
2551
- pageIndex,
2554
+ pageIndex: geometryPageIndex ?? fallbackPageIndex,
2552
2555
  isPrimary: true
2553
2556
  };
2554
2557
  };
2555
- var buildRepeatedHeaderFooterInstances = ({ comment, positionKey, positionEntry }) => {
2558
+ var buildRepeatedHeaderFooterInstances = ({ comment, positionKey, positionEntry, primaryInstanceId }) => {
2556
2559
  const rectGroups = groupRectsByPage(positionEntry?.rects);
2557
2560
  if (rectGroups.length < 2) return [];
2558
- const primaryPageIndex = toFinitePageIndex(positionEntry?.pageIndex) ?? rectGroups[0]?.pageIndex ?? null;
2559
- return rectGroups.map(({ pageIndex, rects }) => {
2561
+ const renderableGroups = rectGroups.map(({ pageIndex, rects }) => {
2560
2562
  const bounds = aggregateRectBounds(rects);
2561
- if (!bounds) return null;
2563
+ return bounds ? {
2564
+ pageIndex,
2565
+ rects,
2566
+ bounds
2567
+ } : null;
2568
+ }).filter(Boolean);
2569
+ if (renderableGroups.length < 2) return [];
2570
+ const geometryPageIndex = toFinitePageIndex(positionEntry?.pageIndex);
2571
+ const primaryPageIndex = renderableGroups.some(({ pageIndex }) => pageIndex === geometryPageIndex) ? geometryPageIndex : renderableGroups[0]?.pageIndex ?? null;
2572
+ return renderableGroups.map(({ pageIndex, rects, bounds }) => {
2573
+ const isPrimary = pageIndex === primaryPageIndex;
2562
2574
  return {
2563
- id: buildPageScopedInstanceId(positionKey, pageIndex),
2575
+ id: isPrimary ? primaryInstanceId : buildPageScopedInstanceId(primaryInstanceId, pageIndex),
2564
2576
  threadId: comment?.commentId ?? positionKey,
2565
2577
  comment,
2566
2578
  positionKey,
2567
2579
  pageIndex,
2568
- isPrimary: pageIndex === primaryPageIndex,
2580
+ isPrimary,
2569
2581
  positionEntry: {
2570
2582
  ...positionEntry,
2571
2583
  pageIndex,
@@ -2573,7 +2585,7 @@ var buildRepeatedHeaderFooterInstances = ({ comment, positionKey, positionEntry
2573
2585
  bounds
2574
2586
  }
2575
2587
  };
2576
- }).filter(Boolean);
2588
+ });
2577
2589
  };
2578
2590
  const buildFloatingCommentInstances = ({ comment, positionKey, positionEntry, fallbackId }) => {
2579
2591
  const instanceId = comment?.trackedChange && comment?.trackedChangeCanonicalId && positionKey && fallbackId && String(positionKey) !== String(fallbackId) ? fallbackId : positionKey ?? fallbackId;
@@ -2582,7 +2594,8 @@ const buildFloatingCommentInstances = ({ comment, positionKey, positionEntry, fa
2582
2594
  const repeatedInstances = buildRepeatedHeaderFooterInstances({
2583
2595
  comment,
2584
2596
  positionKey,
2585
- positionEntry
2597
+ positionEntry,
2598
+ primaryInstanceId: instanceId
2586
2599
  });
2587
2600
  if (repeatedInstances.length > 0) return repeatedInstances;
2588
2601
  }
@@ -2750,6 +2763,12 @@ function withInteractionSpan(stage, branch, meta, fn) {
2750
2763
  throw error;
2751
2764
  }
2752
2765
  }
2766
+ const hasLegacyTrackedChangeThreadSignal = (comment) => Boolean(comment?.trackedChangeLink) || Boolean(comment?.trackedChangeType) || Boolean(comment?.trackedChangeDisplayType) || Boolean(comment?.trackedChangeText) || Boolean(comment?.deletedText) || comment?.trackedChange === true;
2767
+ const trackedChangeThreadParentIdForComment = (comment) => {
2768
+ if (comment?.trackedChangeThreadParentId != null) return comment.trackedChangeThreadParentId;
2769
+ if (comment?.trackedChangeParentId != null && hasLegacyTrackedChangeThreadSignal(comment)) return comment.trackedChangeParentId;
2770
+ return null;
2771
+ };
2753
2772
  var Editor = class {
2754
2773
  constructor() {
2755
2774
  throw new Error("SuperDoc v2 beta: v1 editor-backed comment import paths are not available.");
@@ -3042,9 +3061,15 @@ const useCommentsStore = defineStore("comments", () => {
3042
3061
  if (!comment?.parentCommentId) return comment;
3043
3062
  return getComment(comment.parentCommentId);
3044
3063
  };
3064
+ const trackedChangeThreadParentIdForComment$1 = (comment) => {
3065
+ if (comment?.trackedChangeThreadParentId) return comment.trackedChangeThreadParentId;
3066
+ if (isV2SyntheticTrackedChangeRow(comment) && comment?.trackedChange === true) return null;
3067
+ return trackedChangeThreadParentIdForComment(comment);
3068
+ };
3045
3069
  const shouldThreadWithTrackedChange = (comment) => {
3046
- if (!comment?.trackedChangeParentId) return false;
3047
- const trackedChange = getComment(comment.trackedChangeParentId);
3070
+ const trackedChangeParentId = trackedChangeThreadParentIdForComment$1(comment);
3071
+ if (!trackedChangeParentId) return false;
3072
+ const trackedChange = getComment(trackedChangeParentId);
3048
3073
  return Boolean(trackedChange?.trackedChange);
3049
3074
  };
3050
3075
  const getCommentPositionKey = (commentOrId) => {
@@ -3141,7 +3166,7 @@ const useCommentsStore = defineStore("comments", () => {
3141
3166
  if (source == null) return true;
3142
3167
  return source === DOCUMENT_EDITOR_SELECTION_SOURCE;
3143
3168
  };
3144
- const isTrackedChangeThread = (comment) => Boolean(comment?.trackedChange) || Boolean(comment?.trackedChangeParentId);
3169
+ const isTrackedChangeThread = (comment) => Boolean(comment?.trackedChange) || Boolean(trackedChangeThreadParentIdForComment$1(comment));
3145
3170
  const syncTrackedChangePositionsWithDocument = ({ documentId, editor } = {}) => {
3146
3171
  if (!editor?.state) return 0;
3147
3172
  if (!commentsList.value?.length) return 0;
@@ -3184,7 +3209,11 @@ const useCommentsStore = defineStore("comments", () => {
3184
3209
  commentsList.value.forEach((comment) => {
3185
3210
  const normalizedPositionKey = resolveExistingPositionKey(getCommentAliasIds(comment));
3186
3211
  if (!normalizedPositionKey) return;
3187
- if ([comment?.trackedChangeParentId, comment?.parentCommentId].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => staleRootAliasIds.has(id))) stalePositionKeys.add(normalizedPositionKey);
3212
+ if ([
3213
+ trackedChangeThreadParentIdForComment$1(comment),
3214
+ comment?.threadingParentCommentId,
3215
+ comment?.parentCommentId
3216
+ ].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => staleRootAliasIds.has(id))) stalePositionKeys.add(normalizedPositionKey);
3188
3217
  });
3189
3218
  const nextPositions = { ...currentPositions };
3190
3219
  stalePositionKeys.forEach((key) => {
@@ -3194,7 +3223,11 @@ const useCommentsStore = defineStore("comments", () => {
3194
3223
  if (activeComment.value !== void 0 && activeComment.value !== null) {
3195
3224
  const activeCommentModel = getComment(activeComment.value);
3196
3225
  const activeAliases = new Set(getCommentAliasIds(activeCommentModel ?? activeComment.value));
3197
- const activeParentKeys = [activeCommentModel?.trackedChangeParentId, activeCommentModel?.parentCommentId].map((id) => normalizeCommentId(id)).filter(Boolean);
3226
+ const activeParentKeys = [
3227
+ trackedChangeThreadParentIdForComment$1(activeCommentModel),
3228
+ activeCommentModel?.threadingParentCommentId,
3229
+ activeCommentModel?.parentCommentId
3230
+ ].map((id) => normalizeCommentId(id)).filter(Boolean);
3198
3231
  if (Array.from(activeAliases).some((id) => staleRootAliasIds.has(id)) || activeParentKeys.some((id) => staleRootAliasIds.has(id))) clearActiveCommentSelection();
3199
3232
  }
3200
3233
  return stalePositionKeys.size;
@@ -3299,7 +3332,7 @@ const useCommentsStore = defineStore("comments", () => {
3299
3332
  if (!isViewingMode.value) return true;
3300
3333
  const parent = getThreadParent(comment);
3301
3334
  if (!parent && comment?.parentCommentId) return false;
3302
- return Boolean(parent?.trackedChange) || Boolean(comment?.trackedChangeParentId) ? viewingVisibility.trackChangesVisible : viewingVisibility.commentsVisible;
3335
+ return Boolean(parent?.trackedChange) || Boolean(trackedChangeThreadParentIdForComment$1(comment)) ? viewingVisibility.trackChangesVisible : viewingVisibility.commentsVisible;
3303
3336
  };
3304
3337
  const setActiveComment = (superdoc, id) => {
3305
3338
  const activeEditor = superdoc?.activeEditor;
@@ -3667,8 +3700,8 @@ const useCommentsStore = defineStore("comments", () => {
3667
3700
  const childCommentMap = /* @__PURE__ */ new Map();
3668
3701
  commentsList.value.forEach((comment) => {
3669
3702
  if (!isThreadVisible(comment)) return;
3670
- const trackedChangeParentId = shouldThreadWithTrackedChange(comment) ? comment.trackedChangeParentId : null;
3671
- const parentId = comment.parentCommentId || trackedChangeParentId;
3703
+ const trackedChangeThreadParentId = shouldThreadWithTrackedChange(comment) ? trackedChangeThreadParentIdForComment$1(comment) : null;
3704
+ const parentId = comment.parentCommentId || trackedChangeThreadParentId;
3672
3705
  if (comment.resolvedTime) resolvedComments.push(comment);
3673
3706
  else if (!parentId && !comment.resolvedTime) parentComments.push({ ...comment });
3674
3707
  else if (parentId) {
@@ -4261,7 +4294,7 @@ const useCommentsStore = defineStore("comments", () => {
4261
4294
  };
4262
4295
  const isV2TrackedChangeSidecarCommentInput = (input) => {
4263
4296
  if (!input || input.trackedChange === true) return false;
4264
- if (!input.trackedChangeParentId || input.parentCommentId) return false;
4297
+ if (!input.trackedChangeThreadParentId || input.parentCommentId) return false;
4265
4298
  return isBlankV2CommentText(input.commentText);
4266
4299
  };
4267
4300
  const activeKey = activeComment.value != null ? String(activeComment.value) : null;
@@ -4279,12 +4312,13 @@ const useCommentsStore = defineStore("comments", () => {
4279
4312
  });
4280
4313
  if (!input) continue;
4281
4314
  if (isV2TrackedChangeSidecarCommentInput(input)) {
4282
- trackedChangeSidecarParentByCommentId.set(String(input.commentId), String(input.trackedChangeParentId));
4315
+ trackedChangeSidecarParentByCommentId.set(String(input.commentId), String(input.trackedChangeThreadParentId));
4283
4316
  tracePreviewComments("hydrate:drop-v2-sidecar-comment", {
4284
4317
  commentId: input.commentId ?? null,
4285
4318
  importedId: input.importedId ?? null,
4286
4319
  parentCommentId: input.parentCommentId ?? null,
4287
4320
  trackedChangeParentId: input.trackedChangeParentId ?? null,
4321
+ trackedChangeThreadParentId: input.trackedChangeThreadParentId ?? null,
4288
4322
  trackedChangeSide: input.trackedChangeSide ?? null,
4289
4323
  commentText: input.commentText ?? null
4290
4324
  });
@@ -4297,7 +4331,7 @@ const useCommentsStore = defineStore("comments", () => {
4297
4331
  const trackedChangeThreadId = parentId ? trackedChangeSidecarParentByCommentId.get(parentId) : null;
4298
4332
  if (trackedChangeThreadId) {
4299
4333
  input.threadingParentCommentId = trackedChangeThreadId;
4300
- if (input.trackedChangeParentId == null) input.trackedChangeParentId = trackedChangeThreadId;
4334
+ if (input.trackedChangeThreadParentId == null) input.trackedChangeThreadParentId = trackedChangeThreadId;
4301
4335
  }
4302
4336
  const cid = input.commentId != null ? String(input.commentId) : null;
4303
4337
  if (!cid) continue;
@@ -4339,6 +4373,8 @@ const useCommentsStore = defineStore("comments", () => {
4339
4373
  else delete existing.parentCommentId;
4340
4374
  if (input.trackedChangeParentId !== void 0) existing.trackedChangeParentId = input.trackedChangeParentId;
4341
4375
  else delete existing.trackedChangeParentId;
4376
+ if (input.trackedChangeThreadParentId !== void 0) existing.trackedChangeThreadParentId = input.trackedChangeThreadParentId;
4377
+ else existing.trackedChangeThreadParentId = void 0;
4342
4378
  if (input.trackedChangeSide !== void 0) existing.trackedChangeSide = input.trackedChangeSide;
4343
4379
  else delete existing.trackedChangeSide;
4344
4380
  if (input.threadingParentCommentId !== void 0) existing.threadingParentCommentId = input.threadingParentCommentId;
@@ -4550,6 +4586,7 @@ const useCommentsStore = defineStore("comments", () => {
4550
4586
  isInternal: false,
4551
4587
  parentCommentId: comment.parentCommentId,
4552
4588
  trackedChangeParentId: comment.trackedChangeParentId,
4589
+ trackedChangeThreadParentId: comment.trackedChangeThreadParentId,
4553
4590
  creatorId: null,
4554
4591
  creatorName,
4555
4592
  createdTime: comment.createdTime,
@@ -4809,8 +4846,8 @@ const useCommentsStore = defineStore("comments", () => {
4809
4846
  commentsList.value = commentsList.value.filter((comment) => {
4810
4847
  if (!belongsToTrackedChangeSyncDocument(comment, activeDocumentId)) return true;
4811
4848
  const parentCommentId = comment.parentCommentId != null ? String(comment.parentCommentId) : null;
4812
- const trackedChangeParentId = comment.trackedChangeParentId != null ? String(comment.trackedChangeParentId) : null;
4813
- if (!(parentCommentId && removedIds.has(parentCommentId) || trackedChangeParentId && removedIds.has(trackedChangeParentId))) return true;
4849
+ const trackedChangeThreadParentId = trackedChangeThreadParentIdForComment$1(comment) != null ? String(trackedChangeThreadParentIdForComment$1(comment)) : null;
4850
+ if (!(parentCommentId && removedIds.has(parentCommentId) || trackedChangeThreadParentId && removedIds.has(trackedChangeThreadParentId))) return true;
4814
4851
  if (comment.resolvedTime) return true;
4815
4852
  const commentId = comment.commentId != null ? String(comment.commentId) : null;
4816
4853
  const importedId = comment.importedId != null ? String(comment.importedId) : null;
@@ -4866,7 +4903,11 @@ const useCommentsStore = defineStore("comments", () => {
4866
4903
  commentsList.value.forEach((linkedComment) => {
4867
4904
  if (!linkedComment || linkedComment === comment) return;
4868
4905
  if (linkedComment.resolvedTime) return;
4869
- if (![linkedComment.trackedChangeParentId, linkedComment.parentCommentId].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => trackedChangeIds.has(id))) return;
4906
+ if (![
4907
+ trackedChangeThreadParentIdForComment$1(linkedComment),
4908
+ linkedComment.threadingParentCommentId,
4909
+ linkedComment.parentCommentId
4910
+ ].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => trackedChangeIds.has(id))) return;
4870
4911
  if (typeof linkedComment.resolveComment === "function") {
4871
4912
  linkedComment.resolveComment(resolveArgs);
4872
4913
  resolvedCount += 1;
@@ -4921,10 +4962,12 @@ const useCommentsStore = defineStore("comments", () => {
4921
4962
  commentsList.value.forEach((linkedComment) => {
4922
4963
  if (!linkedComment || linkedComment === comment) return;
4923
4964
  const trackedChangeParentId = normalizeCommentId(linkedComment.trackedChangeParentId);
4965
+ const trackedChangeThreadParentId = normalizeCommentId(linkedComment.trackedChangeThreadParentId);
4924
4966
  const threadingParentCommentId = normalizeCommentId(linkedComment.threadingParentCommentId);
4925
4967
  const parentCommentId = normalizeCommentId(linkedComment.parentCommentId);
4926
- if (!(trackedChangeParentId && trackedChangeIds.has(trackedChangeParentId) || threadingParentCommentId && trackedChangeIds.has(threadingParentCommentId) || parentCommentId && trackedChangeIds.has(parentCommentId))) return;
4968
+ if (!(trackedChangeParentId && trackedChangeIds.has(trackedChangeParentId) || trackedChangeThreadParentId && trackedChangeIds.has(trackedChangeThreadParentId) || threadingParentCommentId && trackedChangeIds.has(threadingParentCommentId) || parentCommentId && trackedChangeIds.has(parentCommentId))) return;
4927
4969
  delete linkedComment.trackedChangeParentId;
4970
+ linkedComment.trackedChangeThreadParentId = void 0;
4928
4971
  delete linkedComment.trackedChangeSide;
4929
4972
  delete linkedComment.threadingParentCommentId;
4930
4973
  if (parentCommentId && trackedChangeIds.has(parentCommentId)) delete linkedComment.parentCommentId;
@@ -5775,6 +5818,7 @@ const useCommentsStore = defineStore("comments", () => {
5775
5818
  const getFloatingComments = computed(() => {
5776
5819
  return getGroupedComments.value?.parentComments.filter((c) => !c.resolvedTime).filter((c) => {
5777
5820
  if (!isEditorBackedComment(c)) return true;
5821
+ if (isTrackedChangeThread(c)) return true;
5778
5822
  return Boolean(resolveCommentPositionEntry(c).entry);
5779
5823
  }).filter((c) => !isInlineTrackedChangeInsideTrackedTable(c));
5780
5824
  });
@@ -6550,6 +6594,7 @@ var CommentHeader_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
6550
6594
  return Boolean(currentName && commentName && currentName === commentName);
6551
6595
  };
6552
6596
  const isOwnComment = computed(() => isCommentOwnedByCurrentUser(props.comment));
6597
+ const trackedChangeThreadParentId = computed(() => trackedChangeThreadParentIdForComment(props.comment));
6553
6598
  const { uiFontFamily } = useUiFontFamily();
6554
6599
  const OVERFLOW_OPTIONS = Object.freeze({
6555
6600
  edit: {
@@ -6574,7 +6619,7 @@ var CommentHeader_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
6574
6619
  if (!generallyAllowed.value) return false;
6575
6620
  if (!props.comment.trackedChange && props.config.allowResolve === false) return false;
6576
6621
  if (props.comment.parentCommentId) return false;
6577
- if (props.comment.trackedChangeParentId) return false;
6622
+ if (trackedChangeThreadParentId.value) return false;
6578
6623
  const context = {
6579
6624
  comment: props.comment,
6580
6625
  currentUser: proxy.$superdoc.config.user,
@@ -6603,7 +6648,7 @@ var CommentHeader_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
6603
6648
  if (commentsStore.pendingComment) return false;
6604
6649
  if (props.isPendingInput) return false;
6605
6650
  if (props.comment.parentCommentId) return false;
6606
- if (props.comment.trackedChangeParentId) return false;
6651
+ if (trackedChangeThreadParentId.value) return false;
6607
6652
  if (props.comment.trackedChange) return false;
6608
6653
  const context = {
6609
6654
  comment: props.comment,
@@ -6724,7 +6769,7 @@ var CommentHeader_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
6724
6769
  ], 2)]);
6725
6770
  };
6726
6771
  }
6727
- }, [["__scopeId", "data-v-359c13bb"]]);
6772
+ }, [["__scopeId", "data-v-ca6050aa"]]);
6728
6773
  var _hoisted_1$26 = { class: "input-section" };
6729
6774
  var TEXTAREA_MIN_HEIGHT = 28;
6730
6775
  var TEXTAREA_MAX_HEIGHT = 132;
@@ -6824,8 +6869,8 @@ const collectTrackedChangeThread = (parentComment, allComments) => {
6824
6869
  allComments.forEach((comment) => {
6825
6870
  if (comment.commentId === trackedChangeId) return;
6826
6871
  const isDirectChild = [comment.parentCommentId, comment.threadingParentCommentId].filter((id) => id != null).map((id) => String(id)).includes(trackedChangeId);
6827
- const isTrackedChangeAnchoredRoot = comment.trackedChangeParentId === trackedChangeId && !comment.parentCommentId;
6828
- if (isDirectChild || isTrackedChangeAnchoredRoot) {
6872
+ const isTrackedChangeThreadRoot = String(trackedChangeThreadParentIdForComment(comment) ?? "") === trackedChangeId && !comment.parentCommentId;
6873
+ if (isDirectChild || isTrackedChangeThreadRoot) {
6829
6874
  threadIds.add(comment.commentId);
6830
6875
  queue.push(comment.commentId);
6831
6876
  }
@@ -6928,12 +6973,18 @@ var _hoisted_44 = {
6928
6973
  class: "comment-separator"
6929
6974
  };
6930
6975
  var _hoisted_45 = {
6976
+ key: 2,
6977
+ class: "tracked-change-decision-alert",
6978
+ role: "alert"
6979
+ };
6980
+ var _hoisted_46 = { class: "tracked-change-decision-alert__message" };
6981
+ var _hoisted_47 = {
6931
6982
  key: 1,
6932
6983
  class: "reply-expanded"
6933
6984
  };
6934
- var _hoisted_46 = { class: "reply-input-wrapper" };
6935
- var _hoisted_47 = { class: "reply-actions" };
6936
- var _hoisted_48 = ["disabled", "data-disabled-reason"];
6985
+ var _hoisted_48 = { class: "reply-input-wrapper" };
6986
+ var _hoisted_49 = { class: "reply-actions" };
6987
+ var _hoisted_50 = ["disabled", "data-disabled-reason"];
6937
6988
  var CLICK_OUTSIDE_HIT_TOLERANCE_PX = 3;
6938
6989
  var TRACKED_CHANGE_PREVIEW_MAX_PX = 90;
6939
6990
  var CommentDialog_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
@@ -6985,6 +7036,7 @@ var CommentDialog_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
6985
7036
  const isInternal = ref(true);
6986
7037
  const commentInput = ref(null);
6987
7038
  const editCommentInputs = ref(/* @__PURE__ */ new Map());
7039
+ const trackedChangeDecisionFailure = ref(null);
6988
7040
  const CLICK_OUTSIDE_HIT_SAMPLE_OFFSETS = [
6989
7041
  [0, 0],
6990
7042
  [-CLICK_OUTSIDE_HIT_TOLERANCE_PX, 0],
@@ -7434,6 +7486,35 @@ var CommentDialog_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
7434
7486
  if (!isV2WriteDisabled.value) return null;
7435
7487
  return v2WriteCapability.value?.reason ?? "v2-write-unavailable";
7436
7488
  });
7489
+ const reportTrackedChangeDecisionFailure = (decision, outcome) => {
7490
+ trackedChangeDecisionFailure.value = {
7491
+ decision,
7492
+ reason: outcome?.reason ?? null
7493
+ };
7494
+ nextTick(() => emit("resize"));
7495
+ };
7496
+ const clearTrackedChangeDecisionFailure = () => {
7497
+ if (!trackedChangeDecisionFailure.value) return;
7498
+ trackedChangeDecisionFailure.value = null;
7499
+ nextTick(() => emit("resize"));
7500
+ };
7501
+ const trackedChangeDecisionFailureMessage = computed(() => {
7502
+ const failure = trackedChangeDecisionFailure.value;
7503
+ if (!failure) return null;
7504
+ const action = failure.decision === "reject" ? "reject" : "accept";
7505
+ if (failure.reason === "stale-catalog") return `Couldn't ${action} this change because the review list is stale.`;
7506
+ return `Couldn't ${action} this change.`;
7507
+ });
7508
+ const retryTrackedChangeDecision = () => {
7509
+ const failure = trackedChangeDecisionFailure.value;
7510
+ if (!failure) return;
7511
+ trackedChangeDecisionFailure.value = null;
7512
+ if (failure.decision === "reject") {
7513
+ handleReject();
7514
+ return;
7515
+ }
7516
+ handleResolve();
7517
+ };
7437
7518
  const handleReject = async () => {
7438
7519
  if (commentsAreReadOnly$1()) return readOnlyMutationOutcome$1();
7439
7520
  const customHandler = proxy.$superdoc.config.onTrackedChangeBubbleReject;
@@ -7444,7 +7525,11 @@ var CommentDialog_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
7444
7525
  comment: props.comment,
7445
7526
  decision: "reject"
7446
7527
  });
7447
- if (!outcome?.ok || outcome.success === false) return;
7528
+ if (!outcome?.ok || outcome.success === false) {
7529
+ reportTrackedChangeDecisionFailure("reject", outcome);
7530
+ return;
7531
+ }
7532
+ clearTrackedChangeDecisionFailure();
7448
7533
  if (typeof customHandler === "function") customHandler(props.comment, proxy.$superdoc.activeEditor);
7449
7534
  nextTick(() => {
7450
7535
  commentsStore.lastUpdate = /* @__PURE__ */ new Date();
@@ -7500,7 +7585,11 @@ var CommentDialog_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
7500
7585
  comment: props.comment,
7501
7586
  decision: "accept"
7502
7587
  });
7503
- if (!outcome?.ok || outcome.success === false) return;
7588
+ if (!outcome?.ok || outcome.success === false) {
7589
+ reportTrackedChangeDecisionFailure("accept", outcome);
7590
+ return;
7591
+ }
7592
+ clearTrackedChangeDecisionFailure();
7504
7593
  if (typeof customHandler === "function") customHandler(props.comment, proxy.$superdoc.activeEditor);
7505
7594
  nextTick(() => {
7506
7595
  commentsStore.lastUpdate = /* @__PURE__ */ new Date();
@@ -7852,11 +7941,16 @@ var CommentDialog_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
7852
7941
  showSeparator.value(index) ? (openBlock(), createElementBlock("div", _hoisted_44)) : createCommentVNode("", true)
7853
7942
  ]);
7854
7943
  }), 128)),
7855
- showInputSection.value && !unref(getConfig).readOnly ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [!isReplying.value ? (openBlock(), createElementBlock("div", {
7944
+ trackedChangeDecisionFailure.value ? (openBlock(), createElementBlock("div", _hoisted_45, [createElementVNode("span", _hoisted_46, toDisplayString(trackedChangeDecisionFailureMessage.value), 1), createElementVNode("button", {
7945
+ type: "button",
7946
+ class: "sd-button tracked-change-decision-alert__retry",
7947
+ onClick: withModifiers(retryTrackedChangeDecision, ["stop", "prevent"])
7948
+ }, " Retry ")])) : createCommentVNode("", true),
7949
+ showInputSection.value && !unref(getConfig).readOnly ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [!isReplying.value ? (openBlock(), createElementBlock("div", {
7856
7950
  key: 0,
7857
7951
  class: "reply-pill",
7858
7952
  onClick: withModifiers(startReply, ["stop", "prevent"])
7859
- }, "Reply or add others with @")) : (openBlock(), createElementBlock("div", _hoisted_45, [createElementVNode("div", _hoisted_46, [createVNode(CommentInput_default, {
7953
+ }, "Reply or add others with @")) : (openBlock(), createElementBlock("div", _hoisted_47, [createElementVNode("div", _hoisted_48, [createVNode(CommentInput_default, {
7860
7954
  ref_key: "commentInput",
7861
7955
  ref: commentInput,
7862
7956
  users: usersFiltered.value,
@@ -7867,7 +7961,7 @@ var CommentDialog_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
7867
7961
  "users",
7868
7962
  "config",
7869
7963
  "comment"
7870
- ])]), createElementVNode("div", _hoisted_47, [createElementVNode("button", {
7964
+ ])]), createElementVNode("div", _hoisted_49, [createElementVNode("button", {
7871
7965
  class: "sd-button reply-btn-cancel",
7872
7966
  onClick: withModifiers(handleCancel, ["stop", "prevent"])
7873
7967
  }, "Cancel"), createElementVNode("button", {
@@ -7875,11 +7969,11 @@ var CommentDialog_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
7875
7969
  onClick: withModifiers(handleAddComment, ["stop", "prevent"]),
7876
7970
  disabled: !hasTextContent.value || isV2WriteDisabled.value,
7877
7971
  "data-disabled-reason": isV2WriteDisabled.value ? v2WriteCapability.value?.reason ?? null : null
7878
- }, " Reply ", 10, _hoisted_48)])]))], 64)) : createCommentVNode("", true)
7972
+ }, " Reply ", 10, _hoisted_50)])]))], 64)) : createCommentVNode("", true)
7879
7973
  ], 64))], 14, _hoisted_1$25)), [[_directive_click_outside, handleClickOutside]]);
7880
7974
  };
7881
7975
  }
7882
- }, [["__scopeId", "data-v-67a03ee2"]]);
7976
+ }, [["__scopeId", "data-v-35236c9c"]]);
7883
7977
  var _hoisted_1$24 = { class: "comments-list" };
7884
7978
  var _hoisted_2$19 = { key: 0 };
7885
7979
  var _hoisted_3$15 = [
@@ -8266,6 +8360,7 @@ var FloatingComments_default = /* @__PURE__ */ __plugin_vue_export_helper_defaul
8266
8360
  setup(__props) {
8267
8361
  const ESTIMATED_HEIGHT = 110;
8268
8362
  const OBSERVER_MARGIN = 600;
8363
+ const FALLBACK_ANCHOR_STEP = .001;
8269
8364
  const resolveCollisions = (positions, activeIndex, gap) => {
8270
8365
  if (activeIndex >= 0) {
8271
8366
  positions[activeIndex].top = positions[activeIndex].anchorTop;
@@ -8397,18 +8492,31 @@ var FloatingComments_default = /* @__PURE__ */ __plugin_vue_export_helper_defaul
8397
8492
  const hasPending = pendingComment.value && pendingComment.value.fileId === props.currentDocument.id;
8398
8493
  if (!instances.length && !hasPending) return [];
8399
8494
  const positions = [];
8495
+ let lastAnchoredTop = 0;
8496
+ let fallbackAnchorCount = 0;
8400
8497
  for (const instance of instances) {
8401
8498
  const key = instance?.id;
8402
8499
  const anchorTop = getAnchorTop(instance);
8403
8500
  const threadId = getThreadId(instance?.comment);
8404
- if (!key || !threadId || typeof anchorTop !== "number" || isNaN(anchorTop)) continue;
8405
- const top = normalizeFloatingAnchorTop(anchorTop, instance.comment);
8501
+ if (!key || !threadId) continue;
8502
+ const hasAnchorGeometry = typeof anchorTop === "number" && !isNaN(anchorTop);
8503
+ if (!hasAnchorGeometry && !isPersistentReviewSidebarItem(instance?.comment)) continue;
8504
+ let top;
8505
+ if (hasAnchorGeometry) {
8506
+ top = normalizeFloatingAnchorTop(anchorTop, instance.comment);
8507
+ lastAnchoredTop = top;
8508
+ fallbackAnchorCount = 0;
8509
+ } else {
8510
+ fallbackAnchorCount += 1;
8511
+ top = lastAnchoredTop + fallbackAnchorCount * FALLBACK_ANCHOR_STEP;
8512
+ }
8406
8513
  positions.push({
8407
8514
  id: key,
8408
8515
  threadId,
8409
8516
  pageIndex: instance?.pageIndex ?? null,
8410
8517
  anchorTop: top,
8411
- anchorBottom: getAnchorBottom(instance, top),
8518
+ anchorBottom: hasAnchorGeometry ? getAnchorBottom(instance, top) : top,
8519
+ hasAnchorGeometry,
8412
8520
  top,
8413
8521
  height: measuredHeights.value[key] || ESTIMATED_HEIGHT,
8414
8522
  commentRef: instance.comment,
@@ -8421,6 +8529,7 @@ var FloatingComments_default = /* @__PURE__ */ __plugin_vue_export_helper_defaul
8421
8529
  id: "pending",
8422
8530
  anchorTop: pendingTop,
8423
8531
  anchorBottom: pendingTop,
8532
+ hasAnchorGeometry: true,
8424
8533
  top: pendingTop,
8425
8534
  height: measuredHeights.value["pending"] || ESTIMATED_HEIGHT,
8426
8535
  commentRef: pendingComment.value
@@ -8431,6 +8540,7 @@ var FloatingComments_default = /* @__PURE__ */ __plugin_vue_export_helper_defaul
8431
8540
  resolveCollisions(positions, activeKey ? positions.findIndex((p) => p.id === activeKey) : -1, 15);
8432
8541
  const viewportRange = getFloatingViewportRange();
8433
8542
  if (viewportRange) for (const position of positions) {
8543
+ if (!position.hasAnchorGeometry) continue;
8434
8544
  const persistentReviewTop = resolvePersistentReviewCardTop({
8435
8545
  comment: position.commentRef,
8436
8546
  anchorTop: position.anchorTop,
@@ -8560,6 +8670,7 @@ var FloatingComments_default = /* @__PURE__ */ __plugin_vue_export_helper_defaul
8560
8670
  let continuityAlignmentScheduled = false;
8561
8671
  let continuityAlignmentGeneration = 0;
8562
8672
  let continuityTransitionFrame = null;
8673
+ let activeLayoutContinuityFrame = null;
8563
8674
  const clearDeferredRemeasureTimers = () => {
8564
8675
  remeasureTimers.forEach(clearTimeout);
8565
8676
  remeasureTimers = [];
@@ -8731,14 +8842,27 @@ var FloatingComments_default = /* @__PURE__ */ __plugin_vue_export_helper_defaul
8731
8842
  });
8732
8843
  let prevPositionIds = /* @__PURE__ */ new Set();
8733
8844
  let prevActiveAnchorTop = null;
8845
+ let prevActiveLayoutTop = null;
8734
8846
  watch(allPositions, (positions) => {
8735
8847
  const activePosition = activeCommentInstanceId.value ? positions.find((position) => position.id === activeCommentInstanceId.value) : null;
8736
8848
  const activeAnchorTop = typeof activePosition?.anchorTop === "number" && Number.isFinite(activePosition.anchorTop) ? activePosition.anchorTop : null;
8737
- if (activeAnchorTop != null && prevActiveAnchorTop != null && Math.abs(activeAnchorTop - prevActiveAnchorTop) > 1 && sidebarOffsetY.value !== 0 && !Number.isFinite(instantSidebarAlignmentTargetY.value)) {
8849
+ const activeAnchorMoved = activeAnchorTop != null && prevActiveAnchorTop != null && Math.abs(activeAnchorTop - prevActiveAnchorTop) > 1;
8850
+ const activeLayoutTop = typeof activePosition?.top === "number" && Number.isFinite(activePosition.top) ? activePosition.top : null;
8851
+ const activeLayoutMoved = activeLayoutTop != null && prevActiveLayoutTop != null && Math.abs(activeLayoutTop - prevActiveLayoutTop) > 1;
8852
+ if (activeAnchorMoved && sidebarOffsetY.value !== 0 && !Number.isFinite(instantSidebarAlignmentTargetY.value)) {
8738
8853
  sidebarOffsetY.value = 0;
8739
8854
  setInstantLayoutTransitionsDisabled(false);
8855
+ } else if (activeLayoutMoved && sidebarOffsetY.value !== 0 && !Number.isFinite(instantSidebarAlignmentTargetY.value) && !sidebarContinuityAnchor) {
8856
+ setInstantLayoutTransitionsDisabled(true);
8857
+ sidebarOffsetY.value += prevActiveLayoutTop - activeLayoutTop;
8858
+ if (activeLayoutContinuityFrame != null) cancelAnimationFrame(activeLayoutContinuityFrame);
8859
+ activeLayoutContinuityFrame = requestAnimationFrame(() => {
8860
+ activeLayoutContinuityFrame = null;
8861
+ if (!sidebarContinuityAnchor && !Number.isFinite(instantSidebarAlignmentTargetY.value)) setInstantLayoutTransitionsDisabled(false);
8862
+ });
8740
8863
  }
8741
8864
  prevActiveAnchorTop = activeAnchorTop;
8865
+ prevActiveLayoutTop = activeLayoutTop;
8742
8866
  const positionOrder = positions.map((position) => position.id);
8743
8867
  const currentIds = new Set(positionOrder);
8744
8868
  if (sidebarContinuityAnchor && !currentIds.has(sidebarContinuityAnchor.key)) {
@@ -8803,6 +8927,10 @@ var FloatingComments_default = /* @__PURE__ */ __plugin_vue_export_helper_defaul
8803
8927
  clearDeferredRemeasureTimers();
8804
8928
  if (scrollTimer) clearTimeout(scrollTimer);
8805
8929
  clearSidebarContinuityAnchor();
8930
+ if (activeLayoutContinuityFrame != null) {
8931
+ cancelAnimationFrame(activeLayoutContinuityFrame);
8932
+ activeLayoutContinuityFrame = null;
8933
+ }
8806
8934
  if (observer) {
8807
8935
  observer.disconnect();
8808
8936
  observer = null;
@@ -8863,7 +8991,7 @@ var FloatingComments_default = /* @__PURE__ */ __plugin_vue_export_helper_defaul
8863
8991
  }), 128))], 4)], 4);
8864
8992
  };
8865
8993
  }
8866
- }, [["__scopeId", "data-v-7bf85652"]]);
8994
+ }, [["__scopeId", "data-v-3672b976"]]);
8867
8995
  var _hoisted_1$22 = {
8868
8996
  class: "superdoc__pdf-comments-layer pdf-comments-layer",
8869
8997
  "aria-hidden": "false"
@@ -9387,6 +9515,17 @@ const DRAWING_DIAGNOSTIC_CODES = {
9387
9515
  };
9388
9516
  DRAWING_DIAGNOSTIC_CODES.missingRelationship, DRAWING_DIAGNOSTIC_CODES.unsupportedRelationshipType, DRAWING_DIAGNOSTIC_CODES.unsupportedRelationshipType, DRAWING_DIAGNOSTIC_CODES.imageTooLarge, DRAWING_DIAGNOSTIC_CODES.missingMediaPart, DRAWING_DIAGNOSTIC_CODES.unsupportedObject, DRAWING_DIAGNOSTIC_CODES.vmlUnsupported;
9389
9517
  DRAWING_DIAGNOSTIC_CODES.externalImageDeferred, DRAWING_DIAGNOSTIC_CODES.missingRelationship, DRAWING_DIAGNOSTIC_CODES.missingMediaPart, DRAWING_DIAGNOSTIC_CODES.unsupportedRelationshipType, DRAWING_DIAGNOSTIC_CODES.unsupportedMime, DRAWING_DIAGNOSTIC_CODES.imageTooLarge, DRAWING_DIAGNOSTIC_CODES.unsafeSvg, DRAWING_DIAGNOSTIC_CODES.unsupportedFormat, DRAWING_DIAGNOSTIC_CODES.embeddedObjectNotSupported, DRAWING_DIAGNOSTIC_CODES.unsupportedObject, DRAWING_DIAGNOSTIC_CODES.vmlUnsupported, DRAWING_DIAGNOSTIC_CODES.vmlImageUnsupported, DRAWING_DIAGNOSTIC_CODES.unsupportedGeometryCommand, DRAWING_DIAGNOSTIC_CODES.anchorUnsupported, DRAWING_DIAGNOSTIC_CODES.wrapUnsupported, DRAWING_DIAGNOSTIC_CODES.altContentNoSupportedChoice, DRAWING_DIAGNOSTIC_CODES.groupChildUnsupported;
9518
+ Object.freeze([
9519
+ "multiple-sections",
9520
+ "furniture-page-tokens",
9521
+ "non-balanceable-multi-column-sections",
9522
+ "body-anchored-objects",
9523
+ "footnotes",
9524
+ "page-references",
9525
+ "keep-constraints",
9526
+ "tables",
9527
+ "furniture-anchored-objects"
9528
+ ]);
9390
9529
  var _hoisted_1$20 = { class: "superdoc-html-viewer" };
9391
9530
  var _hoisted_2$17 = { class: "superdoc-html-viewer__document" };
9392
9531
  var _hoisted_3$14 = ["innerHTML"];
@@ -9444,6 +9583,38 @@ var HtmlViewer_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
9444
9583
  };
9445
9584
  }
9446
9585
  }, [["__scopeId", "data-v-da3494ba"]]);
9586
+ const collectRemovedCommentIds = (comments, targetIds, isInScope = () => true) => {
9587
+ const targets = new Set(targetIds.map(String));
9588
+ const removedIds = /* @__PURE__ */ new Set();
9589
+ comments.forEach((comment) => {
9590
+ if (!isInScope(comment)) return;
9591
+ const commentId = comment.commentId != null ? String(comment.commentId) : null;
9592
+ const importedId = comment.importedId != null ? String(comment.importedId) : null;
9593
+ if (!(commentId && targets.has(commentId)) && !(importedId && targets.has(importedId))) return;
9594
+ if (commentId) removedIds.add(commentId);
9595
+ if (importedId) removedIds.add(importedId);
9596
+ });
9597
+ let expanded = true;
9598
+ while (expanded) {
9599
+ expanded = false;
9600
+ comments.forEach((comment) => {
9601
+ if (!isInScope(comment)) return;
9602
+ const commentId = comment.commentId != null ? String(comment.commentId) : null;
9603
+ const importedId = comment.importedId != null ? String(comment.importedId) : null;
9604
+ const parentCommentId = comment.parentCommentId != null ? String(comment.parentCommentId) : null;
9605
+ const trackedChangeThreadParentIdValue = trackedChangeThreadParentIdForComment(comment);
9606
+ const trackedChangeThreadParentId = trackedChangeThreadParentIdValue != null ? String(trackedChangeThreadParentIdValue) : null;
9607
+ const isRemovedComment = commentId && removedIds.has(commentId) || importedId && removedIds.has(importedId);
9608
+ const isDescendant = parentCommentId && removedIds.has(parentCommentId) || trackedChangeThreadParentId && removedIds.has(trackedChangeThreadParentId);
9609
+ if (!isRemovedComment && !isDescendant) return;
9610
+ const sizeBefore = removedIds.size;
9611
+ if (commentId) removedIds.add(commentId);
9612
+ if (importedId) removedIds.add(importedId);
9613
+ if (removedIds.size > sizeBefore) expanded = true;
9614
+ });
9615
+ }
9616
+ return removedIds;
9617
+ };
9447
9618
  var isHighContrastMode = ref(false);
9448
9619
  function useHighContrastMode() {
9449
9620
  const setHighContrastMode = (value) => {
@@ -9826,6 +9997,45 @@ function resolveV2ReviewTargetCommentId(target, getComment) {
9826
9997
  const commentId = comment?.commentId ?? comment?.importedId ?? target.entityId;
9827
9998
  return commentId != null ? String(commentId) : null;
9828
9999
  }
10000
+ function normalizeDocumentId(value) {
10001
+ return value == null ? null : String(value);
10002
+ }
10003
+ function createV2RemoteReviewHydrationScheduler({ hydrate, getActiveDocumentId, debounceMs = 250, ceilingMs = 1e3, now: now$2 = () => Date.now(), setTimer = (callback, delay) => setTimeout(callback, delay), clearTimer = (timer$1) => clearTimeout(timer$1) }) {
10004
+ let timer = null;
10005
+ let heldSinceMs = null;
10006
+ let pendingDocumentId = null;
10007
+ const matchesActiveDocument = (documentId) => {
10008
+ return normalizeDocumentId(getActiveDocumentId()) === documentId;
10009
+ };
10010
+ const clear = () => {
10011
+ if (timer != null) clearTimer(timer);
10012
+ timer = null;
10013
+ heldSinceMs = null;
10014
+ pendingDocumentId = null;
10015
+ };
10016
+ const schedule = (documentId) => {
10017
+ const normalizedDocumentId = normalizeDocumentId(documentId);
10018
+ if (!matchesActiveDocument(normalizedDocumentId)) return false;
10019
+ if (pendingDocumentId !== normalizedDocumentId) clear();
10020
+ const scheduledAtMs = now$2();
10021
+ pendingDocumentId = normalizedDocumentId;
10022
+ heldSinceMs ??= scheduledAtMs;
10023
+ if (timer != null) clearTimer(timer);
10024
+ const ceilingRemainingMs = Math.max(0, ceilingMs - (scheduledAtMs - heldSinceMs));
10025
+ timer = setTimer(() => {
10026
+ const deliveredDocumentId = pendingDocumentId;
10027
+ timer = null;
10028
+ heldSinceMs = null;
10029
+ pendingDocumentId = null;
10030
+ if (matchesActiveDocument(deliveredDocumentId)) hydrate();
10031
+ }, Math.min(debounceMs, ceilingRemainingMs));
10032
+ return true;
10033
+ };
10034
+ return {
10035
+ schedule,
10036
+ clear
10037
+ };
10038
+ }
9829
10039
  var NO_AUTHOR_SIGNAL = "no-author-configured";
9830
10040
  const V2_AUTHOR_REQUIRED_CODE = "author-required";
9831
10041
  const V2_AUTHOR_REQUIRED_MESSAGE = "This edit needs an author identity. Set `user.name` in your SuperDoc configuration and reopen the document to make tracked or revision-overlapping edits.";
@@ -11152,8 +11362,11 @@ function scrollToElement(targetElement, options = {
11152
11362
  const container = getScrollableParent(targetElement);
11153
11363
  const containerRect = container.getBoundingClientRect();
11154
11364
  const offsetTop = targetElement.getBoundingClientRect().top - containerRect.top + container.scrollTop;
11365
+ const scrollPaddingTopValue = window.getComputedStyle(container).scrollPaddingTop?.trim();
11366
+ const resolvedScrollPaddingTop = scrollPaddingTopValue?.endsWith("px") ? Number(scrollPaddingTopValue.slice(0, -2)) : 0;
11367
+ const scrollPaddingTop = Number.isFinite(resolvedScrollPaddingTop) && resolvedScrollPaddingTop >= 0 ? resolvedScrollPaddingTop : 0;
11155
11368
  container.scrollTo({
11156
- top: options.block === "start" ? offsetTop : offsetTop - container.clientHeight + targetElement.offsetHeight,
11369
+ top: options.block === "start" ? offsetTop - scrollPaddingTop : offsetTop - container.clientHeight + targetElement.offsetHeight,
11157
11370
  behavior: options.behavior
11158
11371
  });
11159
11372
  }
@@ -14357,6 +14570,8 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
14357
14570
  if (latestV2MountStage && (clearedDocumentId == null || latestV2MountStage.dataset?.superdocV2DocumentId === clearedDocumentId)) latestV2MountStage = null;
14358
14571
  v2ReviewHydrationController.reset("render-cleared");
14359
14572
  v2ReviewMutationReconciler.reset();
14573
+ clearV2TypingReviewHydrationTimer();
14574
+ v2RemoteReviewHydrationScheduler.clear();
14360
14575
  commentsStore.setV2CommentsAdapter?.(null);
14361
14576
  commentsStore.setV2TrackedChangesAdapter?.(null);
14362
14577
  commentsStore.clearEditorCommentPositions?.();
@@ -14409,6 +14624,12 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
14409
14624
  });
14410
14625
  let v2LastTypingMutationAtMs = 0;
14411
14626
  let v2TypingReviewHydrationHeldSinceMs = 0;
14627
+ const clearV2TypingReviewHydrationTimer = () => {
14628
+ if (v2TypingReviewHydrationTimer && typeof clearTimeout === "function") clearTimeout(v2TypingReviewHydrationTimer);
14629
+ v2TypingReviewHydrationTimer = 0;
14630
+ v2LastTypingMutationAtMs = 0;
14631
+ v2TypingReviewHydrationHeldSinceMs = 0;
14632
+ };
14412
14633
  const scheduleV2TypingReviewHydration = () => {
14413
14634
  v2LastTypingMutationAtMs = Date.now();
14414
14635
  if (!v2TypingReviewHydrationHeldSinceMs) v2TypingReviewHydrationHeldSinceMs = v2LastTypingMutationAtMs;
@@ -14429,6 +14650,13 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
14429
14650
  const ceilingRemainingMs = Math.max(0, V2_TYPING_REVIEW_HYDRATION_CEILING_MS - (Date.now() - v2TypingReviewHydrationHeldSinceMs));
14430
14651
  v2TypingReviewHydrationTimer = setTimeout(attempt, Math.min(V2_TYPING_REVIEW_HYDRATION_IDLE_MS, ceilingRemainingMs));
14431
14652
  };
14653
+ const v2RemoteReviewHydrationScheduler = createV2RemoteReviewHydrationScheduler({
14654
+ hydrate: () => hydrateV2ReviewRowsFromHost(),
14655
+ getActiveDocumentId: () => {
14656
+ const activeEditor = proxy.$superdoc?.activeEditor ?? null;
14657
+ return activeEditor?.documentId ?? activeEditor?.options?.documentId ?? null;
14658
+ }
14659
+ });
14432
14660
  const onV2HostEvent = (document$1, event) => {
14433
14661
  if (!event) return;
14434
14662
  const documentId = document$1?.id ?? null;
@@ -14436,6 +14664,10 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
14436
14664
  syncSidebarActiveCommentFromV2ReviewTarget(event.next);
14437
14665
  return;
14438
14666
  }
14667
+ if (event.type === "collaboration:remote-changed") {
14668
+ v2RemoteReviewHydrationScheduler.schedule(documentId);
14669
+ return;
14670
+ }
14439
14671
  if (event.type === "source:complete") {
14440
14672
  proxy.$superdoc.broadcastSourceComplete();
14441
14673
  return;
@@ -14669,6 +14901,7 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
14669
14901
  "isInternal",
14670
14902
  "parentCommentId",
14671
14903
  "trackedChangeParentId",
14904
+ "trackedChangeThreadParentId",
14672
14905
  "threadingParentCommentId",
14673
14906
  "trackedChange",
14674
14907
  "trackedChangeType",
@@ -14833,34 +15066,8 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
14833
15066
  if (!activeDocumentId || typeof belongsToDocument !== "function") return true;
14834
15067
  return belongsToDocument(comment, activeDocumentId);
14835
15068
  };
14836
- const removedCommentIds = /* @__PURE__ */ new Set();
14837
- commentsList.value.forEach((comment) => {
14838
- if (!isInActiveDocument(comment)) return;
14839
- const commentId = comment.commentId != null ? String(comment.commentId) : null;
14840
- const importedId = comment.importedId != null ? String(comment.importedId) : null;
14841
- if (!(commentId && targetIds.includes(commentId) || importedId && targetIds.includes(importedId))) return;
14842
- if (commentId) removedCommentIds.add(commentId);
14843
- if (importedId) removedCommentIds.add(importedId);
14844
- });
15069
+ const removedCommentIds = collectRemovedCommentIds(commentsList.value, targetIds, isInActiveDocument);
14845
15070
  if (removedCommentIds.size) {
14846
- let expanded = true;
14847
- while (expanded) {
14848
- expanded = false;
14849
- commentsList.value.forEach((comment) => {
14850
- if (!isInActiveDocument(comment)) return;
14851
- const commentId = comment.commentId != null ? String(comment.commentId) : null;
14852
- const importedId = comment.importedId != null ? String(comment.importedId) : null;
14853
- const parentCommentId = comment.parentCommentId != null ? String(comment.parentCommentId) : null;
14854
- const trackedChangeParentId = comment.trackedChangeParentId != null ? String(comment.trackedChangeParentId) : null;
14855
- const isRemovedComment = commentId && removedCommentIds.has(commentId) || importedId && removedCommentIds.has(importedId);
14856
- const isDescendantOfRemovedComment = parentCommentId && removedCommentIds.has(parentCommentId) || trackedChangeParentId && removedCommentIds.has(trackedChangeParentId);
14857
- if (!isRemovedComment && !isDescendantOfRemovedComment) return;
14858
- const sizeBefore = removedCommentIds.size;
14859
- if (commentId) removedCommentIds.add(commentId);
14860
- if (importedId) removedCommentIds.add(importedId);
14861
- if (removedCommentIds.size > sizeBefore) expanded = true;
14862
- });
14863
- }
14864
15071
  const previousComments = [...commentsList.value];
14865
15072
  commentsList.value = commentsList.value.filter((comment) => {
14866
15073
  if (!isInActiveDocument(comment)) return true;
@@ -15118,11 +15325,8 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
15118
15325
  cancelAnimationFrame(v2GeometryRafHandle);
15119
15326
  v2GeometryRafHandle = 0;
15120
15327
  }
15121
- if (v2TypingReviewHydrationTimer && typeof clearTimeout === "function") {
15122
- clearTimeout(v2TypingReviewHydrationTimer);
15123
- v2TypingReviewHydrationTimer = 0;
15124
- }
15125
- v2TypingReviewHydrationHeldSinceMs = 0;
15328
+ clearV2TypingReviewHydrationTimer();
15329
+ v2RemoteReviewHydrationScheduler.clear();
15126
15330
  document.removeEventListener("focusin", handleRuntimeFocusIn, true);
15127
15331
  document.removeEventListener("pointerdown", handleRuntimePointerDown, true);
15128
15332
  document.removeEventListener("mousedown", handleRuntimeMouseDown, true);
@@ -15615,7 +15819,7 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
15615
15819
  ], 38);
15616
15820
  };
15617
15821
  }
15618
- }, [["__scopeId", "data-v-8d8777e2"]]);
15822
+ }, [["__scopeId", "data-v-c4ab995e"]]);
15619
15823
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
15620
15824
  var PINIA_DEVTOOLS_PLUGIN_ID = "dev.esm.pinia";
15621
15825
  var piniaDevtoolsSuppressionState = {
@@ -34161,7 +34365,7 @@ var SuperDoc = class extends import_eventemitter3.default {
34161
34365
  this.config.colors = shuffleArray(this.config.colors);
34162
34366
  this.userColorMap = /* @__PURE__ */ new Map();
34163
34367
  this.colorIndex = 0;
34164
- this.version = "2.0.0-next.26";
34368
+ this.version = "2.0.0-next.28";
34165
34369
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
34166
34370
  this.superdocId = config.superdocId || v4_default();
34167
34371
  this.colors = this.config.colors ?? [];