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
package/dist/superdoc.cjs CHANGED
@@ -6,7 +6,7 @@ const require_uuid = require("./chunks/uuid-CFp0WGVU.cjs");
6
6
  const require_jszip = require("./chunks/jszip-BdUBlUeG.cjs");
7
7
  const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-BTwbGDKw.cjs");
8
8
  const require_constants = require("./chunks/constants-sbCZ2O_A.cjs");
9
- const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-CHZKlLiH.cjs");
9
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-CZBUMdjl.cjs");
10
10
  let vue = require("vue");
11
11
  vue = require_rolldown_runtime.__toESM(vue);
12
12
  require("y-websocket");
@@ -1771,6 +1771,7 @@ function useComment(params) {
1771
1771
  const importedId = params.importedId;
1772
1772
  const parentCommentId = params.parentCommentId;
1773
1773
  const trackedChangeParentId = params.trackedChangeParentId;
1774
+ const trackedChangeThreadParentId = (0, vue.ref)(params.trackedChangeThreadParentId);
1774
1775
  const fileId = params.fileId;
1775
1776
  const fileType = params.fileType;
1776
1777
  const createdAtVersionNumber = params.createdAtVersionNumber;
@@ -1951,6 +1952,7 @@ function useComment(params) {
1951
1952
  importedId,
1952
1953
  parentCommentId,
1953
1954
  trackedChangeParentId,
1955
+ trackedChangeThreadParentId: trackedChangeThreadParentId.value,
1954
1956
  fileId,
1955
1957
  fileType,
1956
1958
  mentions: mentions.value.map((u) => {
@@ -2003,6 +2005,7 @@ function useComment(params) {
2003
2005
  importedId,
2004
2006
  parentCommentId,
2005
2007
  trackedChangeParentId,
2008
+ trackedChangeThreadParentId,
2006
2009
  fileId,
2007
2010
  fileType,
2008
2011
  mentions,
@@ -2517,7 +2520,7 @@ var aggregateRectBounds = (rects) => {
2517
2520
  };
2518
2521
  var groupRectsByPage = (rects) => {
2519
2522
  const groupedRects = /* @__PURE__ */ new Map();
2520
- rects.forEach((rect) => {
2523
+ (Array.isArray(rects) ? rects : []).forEach((rect) => {
2521
2524
  const pageIndex = toFinitePageIndex(rect?.pageIndex);
2522
2525
  if (pageIndex == null) return;
2523
2526
  const pageRects = groupedRects.get(pageIndex);
@@ -2544,31 +2547,40 @@ var resolveSelectionPageIndex = (comment) => {
2544
2547
  };
2545
2548
  var buildSingleFloatingCommentInstance = ({ id, threadId, comment, positionKey, positionEntry }) => {
2546
2549
  const geometryPageIndex = toFinitePageIndex(positionEntry?.pageIndex);
2547
- const pageIndex = geometryPageIndex != null ? geometryPageIndex : resolveSelectionPageIndex(comment);
2550
+ const fallbackPageIndex = comment?.trackedChange ? null : resolveSelectionPageIndex(comment);
2548
2551
  return {
2549
2552
  id,
2550
2553
  threadId,
2551
2554
  comment,
2552
2555
  positionKey,
2553
2556
  positionEntry: positionEntry ?? null,
2554
- pageIndex,
2557
+ pageIndex: geometryPageIndex ?? fallbackPageIndex,
2555
2558
  isPrimary: true
2556
2559
  };
2557
2560
  };
2558
- var buildRepeatedHeaderFooterInstances = ({ comment, positionKey, positionEntry }) => {
2561
+ var buildRepeatedHeaderFooterInstances = ({ comment, positionKey, positionEntry, primaryInstanceId }) => {
2559
2562
  const rectGroups = groupRectsByPage(positionEntry?.rects);
2560
2563
  if (rectGroups.length < 2) return [];
2561
- const primaryPageIndex = toFinitePageIndex(positionEntry?.pageIndex) ?? rectGroups[0]?.pageIndex ?? null;
2562
- return rectGroups.map(({ pageIndex, rects }) => {
2564
+ const renderableGroups = rectGroups.map(({ pageIndex, rects }) => {
2563
2565
  const bounds = aggregateRectBounds(rects);
2564
- if (!bounds) return null;
2566
+ return bounds ? {
2567
+ pageIndex,
2568
+ rects,
2569
+ bounds
2570
+ } : null;
2571
+ }).filter(Boolean);
2572
+ if (renderableGroups.length < 2) return [];
2573
+ const geometryPageIndex = toFinitePageIndex(positionEntry?.pageIndex);
2574
+ const primaryPageIndex = renderableGroups.some(({ pageIndex }) => pageIndex === geometryPageIndex) ? geometryPageIndex : renderableGroups[0]?.pageIndex ?? null;
2575
+ return renderableGroups.map(({ pageIndex, rects, bounds }) => {
2576
+ const isPrimary = pageIndex === primaryPageIndex;
2565
2577
  return {
2566
- id: buildPageScopedInstanceId(positionKey, pageIndex),
2578
+ id: isPrimary ? primaryInstanceId : buildPageScopedInstanceId(primaryInstanceId, pageIndex),
2567
2579
  threadId: comment?.commentId ?? positionKey,
2568
2580
  comment,
2569
2581
  positionKey,
2570
2582
  pageIndex,
2571
- isPrimary: pageIndex === primaryPageIndex,
2583
+ isPrimary,
2572
2584
  positionEntry: {
2573
2585
  ...positionEntry,
2574
2586
  pageIndex,
@@ -2576,7 +2588,7 @@ var buildRepeatedHeaderFooterInstances = ({ comment, positionKey, positionEntry
2576
2588
  bounds
2577
2589
  }
2578
2590
  };
2579
- }).filter(Boolean);
2591
+ });
2580
2592
  };
2581
2593
  const buildFloatingCommentInstances = ({ comment, positionKey, positionEntry, fallbackId }) => {
2582
2594
  const instanceId = comment?.trackedChange && comment?.trackedChangeCanonicalId && positionKey && fallbackId && String(positionKey) !== String(fallbackId) ? fallbackId : positionKey ?? fallbackId;
@@ -2585,7 +2597,8 @@ const buildFloatingCommentInstances = ({ comment, positionKey, positionEntry, fa
2585
2597
  const repeatedInstances = buildRepeatedHeaderFooterInstances({
2586
2598
  comment,
2587
2599
  positionKey,
2588
- positionEntry
2600
+ positionEntry,
2601
+ primaryInstanceId: instanceId
2589
2602
  });
2590
2603
  if (repeatedInstances.length > 0) return repeatedInstances;
2591
2604
  }
@@ -2754,6 +2767,12 @@ function withInteractionSpan(stage, branch, meta, fn) {
2754
2767
  throw error;
2755
2768
  }
2756
2769
  }
2770
+ const hasLegacyTrackedChangeThreadSignal = (comment) => Boolean(comment?.trackedChangeLink) || Boolean(comment?.trackedChangeType) || Boolean(comment?.trackedChangeDisplayType) || Boolean(comment?.trackedChangeText) || Boolean(comment?.deletedText) || comment?.trackedChange === true;
2771
+ const trackedChangeThreadParentIdForComment = (comment) => {
2772
+ if (comment?.trackedChangeThreadParentId != null) return comment.trackedChangeThreadParentId;
2773
+ if (comment?.trackedChangeParentId != null && hasLegacyTrackedChangeThreadSignal(comment)) return comment.trackedChangeParentId;
2774
+ return null;
2775
+ };
2757
2776
  var Editor = class {
2758
2777
  constructor() {
2759
2778
  throw new Error("SuperDoc v2 beta: v1 editor-backed comment import paths are not available.");
@@ -3046,9 +3065,15 @@ const useCommentsStore = defineStore("comments", () => {
3046
3065
  if (!comment?.parentCommentId) return comment;
3047
3066
  return getComment(comment.parentCommentId);
3048
3067
  };
3068
+ const trackedChangeThreadParentIdForComment$1 = (comment) => {
3069
+ if (comment?.trackedChangeThreadParentId) return comment.trackedChangeThreadParentId;
3070
+ if (isV2SyntheticTrackedChangeRow(comment) && comment?.trackedChange === true) return null;
3071
+ return trackedChangeThreadParentIdForComment(comment);
3072
+ };
3049
3073
  const shouldThreadWithTrackedChange = (comment) => {
3050
- if (!comment?.trackedChangeParentId) return false;
3051
- const trackedChange = getComment(comment.trackedChangeParentId);
3074
+ const trackedChangeParentId = trackedChangeThreadParentIdForComment$1(comment);
3075
+ if (!trackedChangeParentId) return false;
3076
+ const trackedChange = getComment(trackedChangeParentId);
3052
3077
  return Boolean(trackedChange?.trackedChange);
3053
3078
  };
3054
3079
  const getCommentPositionKey = (commentOrId) => {
@@ -3145,7 +3170,7 @@ const useCommentsStore = defineStore("comments", () => {
3145
3170
  if (source == null) return true;
3146
3171
  return source === DOCUMENT_EDITOR_SELECTION_SOURCE;
3147
3172
  };
3148
- const isTrackedChangeThread = (comment) => Boolean(comment?.trackedChange) || Boolean(comment?.trackedChangeParentId);
3173
+ const isTrackedChangeThread = (comment) => Boolean(comment?.trackedChange) || Boolean(trackedChangeThreadParentIdForComment$1(comment));
3149
3174
  const syncTrackedChangePositionsWithDocument = ({ documentId, editor } = {}) => {
3150
3175
  if (!editor?.state) return 0;
3151
3176
  if (!commentsList.value?.length) return 0;
@@ -3188,7 +3213,11 @@ const useCommentsStore = defineStore("comments", () => {
3188
3213
  commentsList.value.forEach((comment) => {
3189
3214
  const normalizedPositionKey = resolveExistingPositionKey(getCommentAliasIds(comment));
3190
3215
  if (!normalizedPositionKey) return;
3191
- if ([comment?.trackedChangeParentId, comment?.parentCommentId].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => staleRootAliasIds.has(id))) stalePositionKeys.add(normalizedPositionKey);
3216
+ if ([
3217
+ trackedChangeThreadParentIdForComment$1(comment),
3218
+ comment?.threadingParentCommentId,
3219
+ comment?.parentCommentId
3220
+ ].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => staleRootAliasIds.has(id))) stalePositionKeys.add(normalizedPositionKey);
3192
3221
  });
3193
3222
  const nextPositions = { ...currentPositions };
3194
3223
  stalePositionKeys.forEach((key) => {
@@ -3198,7 +3227,11 @@ const useCommentsStore = defineStore("comments", () => {
3198
3227
  if (activeComment.value !== void 0 && activeComment.value !== null) {
3199
3228
  const activeCommentModel = getComment(activeComment.value);
3200
3229
  const activeAliases = new Set(getCommentAliasIds(activeCommentModel ?? activeComment.value));
3201
- const activeParentKeys = [activeCommentModel?.trackedChangeParentId, activeCommentModel?.parentCommentId].map((id) => normalizeCommentId(id)).filter(Boolean);
3230
+ const activeParentKeys = [
3231
+ trackedChangeThreadParentIdForComment$1(activeCommentModel),
3232
+ activeCommentModel?.threadingParentCommentId,
3233
+ activeCommentModel?.parentCommentId
3234
+ ].map((id) => normalizeCommentId(id)).filter(Boolean);
3202
3235
  if (Array.from(activeAliases).some((id) => staleRootAliasIds.has(id)) || activeParentKeys.some((id) => staleRootAliasIds.has(id))) clearActiveCommentSelection();
3203
3236
  }
3204
3237
  return stalePositionKeys.size;
@@ -3303,7 +3336,7 @@ const useCommentsStore = defineStore("comments", () => {
3303
3336
  if (!isViewingMode.value) return true;
3304
3337
  const parent = getThreadParent(comment);
3305
3338
  if (!parent && comment?.parentCommentId) return false;
3306
- return Boolean(parent?.trackedChange) || Boolean(comment?.trackedChangeParentId) ? viewingVisibility.trackChangesVisible : viewingVisibility.commentsVisible;
3339
+ return Boolean(parent?.trackedChange) || Boolean(trackedChangeThreadParentIdForComment$1(comment)) ? viewingVisibility.trackChangesVisible : viewingVisibility.commentsVisible;
3307
3340
  };
3308
3341
  const setActiveComment = (superdoc, id) => {
3309
3342
  const activeEditor = superdoc?.activeEditor;
@@ -3671,8 +3704,8 @@ const useCommentsStore = defineStore("comments", () => {
3671
3704
  const childCommentMap = /* @__PURE__ */ new Map();
3672
3705
  commentsList.value.forEach((comment) => {
3673
3706
  if (!isThreadVisible(comment)) return;
3674
- const trackedChangeParentId = shouldThreadWithTrackedChange(comment) ? comment.trackedChangeParentId : null;
3675
- const parentId = comment.parentCommentId || trackedChangeParentId;
3707
+ const trackedChangeThreadParentId = shouldThreadWithTrackedChange(comment) ? trackedChangeThreadParentIdForComment$1(comment) : null;
3708
+ const parentId = comment.parentCommentId || trackedChangeThreadParentId;
3676
3709
  if (comment.resolvedTime) resolvedComments.push(comment);
3677
3710
  else if (!parentId && !comment.resolvedTime) parentComments.push({ ...comment });
3678
3711
  else if (parentId) {
@@ -4265,7 +4298,7 @@ const useCommentsStore = defineStore("comments", () => {
4265
4298
  };
4266
4299
  const isV2TrackedChangeSidecarCommentInput = (input) => {
4267
4300
  if (!input || input.trackedChange === true) return false;
4268
- if (!input.trackedChangeParentId || input.parentCommentId) return false;
4301
+ if (!input.trackedChangeThreadParentId || input.parentCommentId) return false;
4269
4302
  return isBlankV2CommentText(input.commentText);
4270
4303
  };
4271
4304
  const activeKey = activeComment.value != null ? String(activeComment.value) : null;
@@ -4283,12 +4316,13 @@ const useCommentsStore = defineStore("comments", () => {
4283
4316
  });
4284
4317
  if (!input) continue;
4285
4318
  if (isV2TrackedChangeSidecarCommentInput(input)) {
4286
- trackedChangeSidecarParentByCommentId.set(String(input.commentId), String(input.trackedChangeParentId));
4319
+ trackedChangeSidecarParentByCommentId.set(String(input.commentId), String(input.trackedChangeThreadParentId));
4287
4320
  tracePreviewComments("hydrate:drop-v2-sidecar-comment", {
4288
4321
  commentId: input.commentId ?? null,
4289
4322
  importedId: input.importedId ?? null,
4290
4323
  parentCommentId: input.parentCommentId ?? null,
4291
4324
  trackedChangeParentId: input.trackedChangeParentId ?? null,
4325
+ trackedChangeThreadParentId: input.trackedChangeThreadParentId ?? null,
4292
4326
  trackedChangeSide: input.trackedChangeSide ?? null,
4293
4327
  commentText: input.commentText ?? null
4294
4328
  });
@@ -4301,7 +4335,7 @@ const useCommentsStore = defineStore("comments", () => {
4301
4335
  const trackedChangeThreadId = parentId ? trackedChangeSidecarParentByCommentId.get(parentId) : null;
4302
4336
  if (trackedChangeThreadId) {
4303
4337
  input.threadingParentCommentId = trackedChangeThreadId;
4304
- if (input.trackedChangeParentId == null) input.trackedChangeParentId = trackedChangeThreadId;
4338
+ if (input.trackedChangeThreadParentId == null) input.trackedChangeThreadParentId = trackedChangeThreadId;
4305
4339
  }
4306
4340
  const cid = input.commentId != null ? String(input.commentId) : null;
4307
4341
  if (!cid) continue;
@@ -4343,6 +4377,8 @@ const useCommentsStore = defineStore("comments", () => {
4343
4377
  else delete existing.parentCommentId;
4344
4378
  if (input.trackedChangeParentId !== void 0) existing.trackedChangeParentId = input.trackedChangeParentId;
4345
4379
  else delete existing.trackedChangeParentId;
4380
+ if (input.trackedChangeThreadParentId !== void 0) existing.trackedChangeThreadParentId = input.trackedChangeThreadParentId;
4381
+ else existing.trackedChangeThreadParentId = void 0;
4346
4382
  if (input.trackedChangeSide !== void 0) existing.trackedChangeSide = input.trackedChangeSide;
4347
4383
  else delete existing.trackedChangeSide;
4348
4384
  if (input.threadingParentCommentId !== void 0) existing.threadingParentCommentId = input.threadingParentCommentId;
@@ -4554,6 +4590,7 @@ const useCommentsStore = defineStore("comments", () => {
4554
4590
  isInternal: false,
4555
4591
  parentCommentId: comment.parentCommentId,
4556
4592
  trackedChangeParentId: comment.trackedChangeParentId,
4593
+ trackedChangeThreadParentId: comment.trackedChangeThreadParentId,
4557
4594
  creatorId: null,
4558
4595
  creatorName,
4559
4596
  createdTime: comment.createdTime,
@@ -4813,8 +4850,8 @@ const useCommentsStore = defineStore("comments", () => {
4813
4850
  commentsList.value = commentsList.value.filter((comment) => {
4814
4851
  if (!belongsToTrackedChangeSyncDocument(comment, activeDocumentId)) return true;
4815
4852
  const parentCommentId = comment.parentCommentId != null ? String(comment.parentCommentId) : null;
4816
- const trackedChangeParentId = comment.trackedChangeParentId != null ? String(comment.trackedChangeParentId) : null;
4817
- if (!(parentCommentId && removedIds.has(parentCommentId) || trackedChangeParentId && removedIds.has(trackedChangeParentId))) return true;
4853
+ const trackedChangeThreadParentId = trackedChangeThreadParentIdForComment$1(comment) != null ? String(trackedChangeThreadParentIdForComment$1(comment)) : null;
4854
+ if (!(parentCommentId && removedIds.has(parentCommentId) || trackedChangeThreadParentId && removedIds.has(trackedChangeThreadParentId))) return true;
4818
4855
  if (comment.resolvedTime) return true;
4819
4856
  const commentId = comment.commentId != null ? String(comment.commentId) : null;
4820
4857
  const importedId = comment.importedId != null ? String(comment.importedId) : null;
@@ -4870,7 +4907,11 @@ const useCommentsStore = defineStore("comments", () => {
4870
4907
  commentsList.value.forEach((linkedComment) => {
4871
4908
  if (!linkedComment || linkedComment === comment) return;
4872
4909
  if (linkedComment.resolvedTime) return;
4873
- if (![linkedComment.trackedChangeParentId, linkedComment.parentCommentId].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => trackedChangeIds.has(id))) return;
4910
+ if (![
4911
+ trackedChangeThreadParentIdForComment$1(linkedComment),
4912
+ linkedComment.threadingParentCommentId,
4913
+ linkedComment.parentCommentId
4914
+ ].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => trackedChangeIds.has(id))) return;
4874
4915
  if (typeof linkedComment.resolveComment === "function") {
4875
4916
  linkedComment.resolveComment(resolveArgs);
4876
4917
  resolvedCount += 1;
@@ -4925,10 +4966,12 @@ const useCommentsStore = defineStore("comments", () => {
4925
4966
  commentsList.value.forEach((linkedComment) => {
4926
4967
  if (!linkedComment || linkedComment === comment) return;
4927
4968
  const trackedChangeParentId = normalizeCommentId(linkedComment.trackedChangeParentId);
4969
+ const trackedChangeThreadParentId = normalizeCommentId(linkedComment.trackedChangeThreadParentId);
4928
4970
  const threadingParentCommentId = normalizeCommentId(linkedComment.threadingParentCommentId);
4929
4971
  const parentCommentId = normalizeCommentId(linkedComment.parentCommentId);
4930
- if (!(trackedChangeParentId && trackedChangeIds.has(trackedChangeParentId) || threadingParentCommentId && trackedChangeIds.has(threadingParentCommentId) || parentCommentId && trackedChangeIds.has(parentCommentId))) return;
4972
+ if (!(trackedChangeParentId && trackedChangeIds.has(trackedChangeParentId) || trackedChangeThreadParentId && trackedChangeIds.has(trackedChangeThreadParentId) || threadingParentCommentId && trackedChangeIds.has(threadingParentCommentId) || parentCommentId && trackedChangeIds.has(parentCommentId))) return;
4931
4973
  delete linkedComment.trackedChangeParentId;
4974
+ linkedComment.trackedChangeThreadParentId = void 0;
4932
4975
  delete linkedComment.trackedChangeSide;
4933
4976
  delete linkedComment.threadingParentCommentId;
4934
4977
  if (parentCommentId && trackedChangeIds.has(parentCommentId)) delete linkedComment.parentCommentId;
@@ -5779,6 +5822,7 @@ const useCommentsStore = defineStore("comments", () => {
5779
5822
  const getFloatingComments = (0, vue.computed)(() => {
5780
5823
  return getGroupedComments.value?.parentComments.filter((c) => !c.resolvedTime).filter((c) => {
5781
5824
  if (!isEditorBackedComment(c)) return true;
5825
+ if (isTrackedChangeThread(c)) return true;
5782
5826
  return Boolean(resolveCommentPositionEntry(c).entry);
5783
5827
  }).filter((c) => !isInlineTrackedChangeInsideTrackedTable(c));
5784
5828
  });
@@ -6557,6 +6601,7 @@ var _sfc_main$34 = {
6557
6601
  return Boolean(currentName && commentName && currentName === commentName);
6558
6602
  };
6559
6603
  const isOwnComment = (0, vue.computed)(() => isCommentOwnedByCurrentUser(props.comment));
6604
+ const trackedChangeThreadParentId = (0, vue.computed)(() => trackedChangeThreadParentIdForComment(props.comment));
6560
6605
  const { uiFontFamily } = useUiFontFamily();
6561
6606
  const OVERFLOW_OPTIONS = Object.freeze({
6562
6607
  edit: {
@@ -6581,7 +6626,7 @@ var _sfc_main$34 = {
6581
6626
  if (!generallyAllowed.value) return false;
6582
6627
  if (!props.comment.trackedChange && props.config.allowResolve === false) return false;
6583
6628
  if (props.comment.parentCommentId) return false;
6584
- if (props.comment.trackedChangeParentId) return false;
6629
+ if (trackedChangeThreadParentId.value) return false;
6585
6630
  const context = {
6586
6631
  comment: props.comment,
6587
6632
  currentUser: proxy.$superdoc.config.user,
@@ -6610,7 +6655,7 @@ var _sfc_main$34 = {
6610
6655
  if (commentsStore.pendingComment) return false;
6611
6656
  if (props.isPendingInput) return false;
6612
6657
  if (props.comment.parentCommentId) return false;
6613
- if (props.comment.trackedChangeParentId) return false;
6658
+ if (trackedChangeThreadParentId.value) return false;
6614
6659
  if (props.comment.trackedChange) return false;
6615
6660
  const context = {
6616
6661
  comment: props.comment,
@@ -6732,7 +6777,7 @@ var _sfc_main$34 = {
6732
6777
  };
6733
6778
  }
6734
6779
  };
6735
- var CommentHeader_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$34, [["__scopeId", "data-v-359c13bb"]]);
6780
+ var CommentHeader_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$34, [["__scopeId", "data-v-ca6050aa"]]);
6736
6781
  var _hoisted_1$26 = { class: "input-section" };
6737
6782
  var TEXTAREA_MIN_HEIGHT = 28;
6738
6783
  var TEXTAREA_MAX_HEIGHT = 132;
@@ -6833,8 +6878,8 @@ const collectTrackedChangeThread = (parentComment, allComments) => {
6833
6878
  allComments.forEach((comment) => {
6834
6879
  if (comment.commentId === trackedChangeId) return;
6835
6880
  const isDirectChild = [comment.parentCommentId, comment.threadingParentCommentId].filter((id) => id != null).map((id) => String(id)).includes(trackedChangeId);
6836
- const isTrackedChangeAnchoredRoot = comment.trackedChangeParentId === trackedChangeId && !comment.parentCommentId;
6837
- if (isDirectChild || isTrackedChangeAnchoredRoot) {
6881
+ const isTrackedChangeThreadRoot = String(trackedChangeThreadParentIdForComment(comment) ?? "") === trackedChangeId && !comment.parentCommentId;
6882
+ if (isDirectChild || isTrackedChangeThreadRoot) {
6838
6883
  threadIds.add(comment.commentId);
6839
6884
  queue.push(comment.commentId);
6840
6885
  }
@@ -6937,12 +6982,18 @@ var _hoisted_44 = {
6937
6982
  class: "comment-separator"
6938
6983
  };
6939
6984
  var _hoisted_45 = {
6985
+ key: 2,
6986
+ class: "tracked-change-decision-alert",
6987
+ role: "alert"
6988
+ };
6989
+ var _hoisted_46 = { class: "tracked-change-decision-alert__message" };
6990
+ var _hoisted_47 = {
6940
6991
  key: 1,
6941
6992
  class: "reply-expanded"
6942
6993
  };
6943
- var _hoisted_46 = { class: "reply-input-wrapper" };
6944
- var _hoisted_47 = { class: "reply-actions" };
6945
- var _hoisted_48 = ["disabled", "data-disabled-reason"];
6994
+ var _hoisted_48 = { class: "reply-input-wrapper" };
6995
+ var _hoisted_49 = { class: "reply-actions" };
6996
+ var _hoisted_50 = ["disabled", "data-disabled-reason"];
6946
6997
  var CLICK_OUTSIDE_HIT_TOLERANCE_PX = 3;
6947
6998
  var TRACKED_CHANGE_PREVIEW_MAX_PX = 90;
6948
6999
  var _sfc_main$32 = {
@@ -6994,6 +7045,7 @@ var _sfc_main$32 = {
6994
7045
  const isInternal = (0, vue.ref)(true);
6995
7046
  const commentInput = (0, vue.ref)(null);
6996
7047
  const editCommentInputs = (0, vue.ref)(/* @__PURE__ */ new Map());
7048
+ const trackedChangeDecisionFailure = (0, vue.ref)(null);
6997
7049
  const CLICK_OUTSIDE_HIT_SAMPLE_OFFSETS = [
6998
7050
  [0, 0],
6999
7051
  [-CLICK_OUTSIDE_HIT_TOLERANCE_PX, 0],
@@ -7443,6 +7495,35 @@ var _sfc_main$32 = {
7443
7495
  if (!isV2WriteDisabled.value) return null;
7444
7496
  return v2WriteCapability.value?.reason ?? "v2-write-unavailable";
7445
7497
  });
7498
+ const reportTrackedChangeDecisionFailure = (decision, outcome) => {
7499
+ trackedChangeDecisionFailure.value = {
7500
+ decision,
7501
+ reason: outcome?.reason ?? null
7502
+ };
7503
+ (0, vue.nextTick)(() => emit("resize"));
7504
+ };
7505
+ const clearTrackedChangeDecisionFailure = () => {
7506
+ if (!trackedChangeDecisionFailure.value) return;
7507
+ trackedChangeDecisionFailure.value = null;
7508
+ (0, vue.nextTick)(() => emit("resize"));
7509
+ };
7510
+ const trackedChangeDecisionFailureMessage = (0, vue.computed)(() => {
7511
+ const failure = trackedChangeDecisionFailure.value;
7512
+ if (!failure) return null;
7513
+ const action = failure.decision === "reject" ? "reject" : "accept";
7514
+ if (failure.reason === "stale-catalog") return `Couldn't ${action} this change because the review list is stale.`;
7515
+ return `Couldn't ${action} this change.`;
7516
+ });
7517
+ const retryTrackedChangeDecision = () => {
7518
+ const failure = trackedChangeDecisionFailure.value;
7519
+ if (!failure) return;
7520
+ trackedChangeDecisionFailure.value = null;
7521
+ if (failure.decision === "reject") {
7522
+ handleReject();
7523
+ return;
7524
+ }
7525
+ handleResolve();
7526
+ };
7446
7527
  const handleReject = async () => {
7447
7528
  if (commentsAreReadOnly$1()) return readOnlyMutationOutcome$1();
7448
7529
  const customHandler = proxy.$superdoc.config.onTrackedChangeBubbleReject;
@@ -7453,7 +7534,11 @@ var _sfc_main$32 = {
7453
7534
  comment: props.comment,
7454
7535
  decision: "reject"
7455
7536
  });
7456
- if (!outcome?.ok || outcome.success === false) return;
7537
+ if (!outcome?.ok || outcome.success === false) {
7538
+ reportTrackedChangeDecisionFailure("reject", outcome);
7539
+ return;
7540
+ }
7541
+ clearTrackedChangeDecisionFailure();
7457
7542
  if (typeof customHandler === "function") customHandler(props.comment, proxy.$superdoc.activeEditor);
7458
7543
  (0, vue.nextTick)(() => {
7459
7544
  commentsStore.lastUpdate = /* @__PURE__ */ new Date();
@@ -7509,7 +7594,11 @@ var _sfc_main$32 = {
7509
7594
  comment: props.comment,
7510
7595
  decision: "accept"
7511
7596
  });
7512
- if (!outcome?.ok || outcome.success === false) return;
7597
+ if (!outcome?.ok || outcome.success === false) {
7598
+ reportTrackedChangeDecisionFailure("accept", outcome);
7599
+ return;
7600
+ }
7601
+ clearTrackedChangeDecisionFailure();
7513
7602
  if (typeof customHandler === "function") customHandler(props.comment, proxy.$superdoc.activeEditor);
7514
7603
  (0, vue.nextTick)(() => {
7515
7604
  commentsStore.lastUpdate = /* @__PURE__ */ new Date();
@@ -7861,11 +7950,16 @@ var _sfc_main$32 = {
7861
7950
  showSeparator.value(index) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_44)) : (0, vue.createCommentVNode)("", true)
7862
7951
  ]);
7863
7952
  }), 128)),
7864
- showInputSection.value && !(0, vue.unref)(getConfig).readOnly ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [!isReplying.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
7953
+ trackedChangeDecisionFailure.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_45, [(0, vue.createElementVNode)("span", _hoisted_46, (0, vue.toDisplayString)(trackedChangeDecisionFailureMessage.value), 1), (0, vue.createElementVNode)("button", {
7954
+ type: "button",
7955
+ class: "sd-button tracked-change-decision-alert__retry",
7956
+ onClick: (0, vue.withModifiers)(retryTrackedChangeDecision, ["stop", "prevent"])
7957
+ }, " Retry ")])) : (0, vue.createCommentVNode)("", true),
7958
+ showInputSection.value && !(0, vue.unref)(getConfig).readOnly ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 3 }, [!isReplying.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
7865
7959
  key: 0,
7866
7960
  class: "reply-pill",
7867
7961
  onClick: (0, vue.withModifiers)(startReply, ["stop", "prevent"])
7868
- }, "Reply or add others with @")) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_45, [(0, vue.createElementVNode)("div", _hoisted_46, [(0, vue.createVNode)(CommentInput_default, {
7962
+ }, "Reply or add others with @")) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_47, [(0, vue.createElementVNode)("div", _hoisted_48, [(0, vue.createVNode)(CommentInput_default, {
7869
7963
  ref_key: "commentInput",
7870
7964
  ref: commentInput,
7871
7965
  users: usersFiltered.value,
@@ -7876,7 +7970,7 @@ var _sfc_main$32 = {
7876
7970
  "users",
7877
7971
  "config",
7878
7972
  "comment"
7879
- ])]), (0, vue.createElementVNode)("div", _hoisted_47, [(0, vue.createElementVNode)("button", {
7973
+ ])]), (0, vue.createElementVNode)("div", _hoisted_49, [(0, vue.createElementVNode)("button", {
7880
7974
  class: "sd-button reply-btn-cancel",
7881
7975
  onClick: (0, vue.withModifiers)(handleCancel, ["stop", "prevent"])
7882
7976
  }, "Cancel"), (0, vue.createElementVNode)("button", {
@@ -7884,12 +7978,12 @@ var _sfc_main$32 = {
7884
7978
  onClick: (0, vue.withModifiers)(handleAddComment, ["stop", "prevent"]),
7885
7979
  disabled: !hasTextContent.value || isV2WriteDisabled.value,
7886
7980
  "data-disabled-reason": isV2WriteDisabled.value ? v2WriteCapability.value?.reason ?? null : null
7887
- }, " Reply ", 10, _hoisted_48)])]))], 64)) : (0, vue.createCommentVNode)("", true)
7981
+ }, " Reply ", 10, _hoisted_50)])]))], 64)) : (0, vue.createCommentVNode)("", true)
7888
7982
  ], 64))], 14, _hoisted_1$25)), [[_directive_click_outside, handleClickOutside]]);
7889
7983
  };
7890
7984
  }
7891
7985
  };
7892
- var CommentDialog_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$32, [["__scopeId", "data-v-67a03ee2"]]);
7986
+ var CommentDialog_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$32, [["__scopeId", "data-v-35236c9c"]]);
7893
7987
  var _hoisted_1$24 = { class: "comments-list" };
7894
7988
  var _hoisted_2$19 = { key: 0 };
7895
7989
  var _hoisted_3$15 = [
@@ -8277,6 +8371,7 @@ var _sfc_main$30 = {
8277
8371
  setup(__props) {
8278
8372
  const ESTIMATED_HEIGHT = 110;
8279
8373
  const OBSERVER_MARGIN = 600;
8374
+ const FALLBACK_ANCHOR_STEP = .001;
8280
8375
  const resolveCollisions = (positions, activeIndex, gap) => {
8281
8376
  if (activeIndex >= 0) {
8282
8377
  positions[activeIndex].top = positions[activeIndex].anchorTop;
@@ -8408,18 +8503,31 @@ var _sfc_main$30 = {
8408
8503
  const hasPending = pendingComment.value && pendingComment.value.fileId === props.currentDocument.id;
8409
8504
  if (!instances.length && !hasPending) return [];
8410
8505
  const positions = [];
8506
+ let lastAnchoredTop = 0;
8507
+ let fallbackAnchorCount = 0;
8411
8508
  for (const instance of instances) {
8412
8509
  const key = instance?.id;
8413
8510
  const anchorTop = getAnchorTop(instance);
8414
8511
  const threadId = getThreadId(instance?.comment);
8415
- if (!key || !threadId || typeof anchorTop !== "number" || isNaN(anchorTop)) continue;
8416
- const top = normalizeFloatingAnchorTop(anchorTop, instance.comment);
8512
+ if (!key || !threadId) continue;
8513
+ const hasAnchorGeometry = typeof anchorTop === "number" && !isNaN(anchorTop);
8514
+ if (!hasAnchorGeometry && !isPersistentReviewSidebarItem(instance?.comment)) continue;
8515
+ let top;
8516
+ if (hasAnchorGeometry) {
8517
+ top = normalizeFloatingAnchorTop(anchorTop, instance.comment);
8518
+ lastAnchoredTop = top;
8519
+ fallbackAnchorCount = 0;
8520
+ } else {
8521
+ fallbackAnchorCount += 1;
8522
+ top = lastAnchoredTop + fallbackAnchorCount * FALLBACK_ANCHOR_STEP;
8523
+ }
8417
8524
  positions.push({
8418
8525
  id: key,
8419
8526
  threadId,
8420
8527
  pageIndex: instance?.pageIndex ?? null,
8421
8528
  anchorTop: top,
8422
- anchorBottom: getAnchorBottom(instance, top),
8529
+ anchorBottom: hasAnchorGeometry ? getAnchorBottom(instance, top) : top,
8530
+ hasAnchorGeometry,
8423
8531
  top,
8424
8532
  height: measuredHeights.value[key] || ESTIMATED_HEIGHT,
8425
8533
  commentRef: instance.comment,
@@ -8432,6 +8540,7 @@ var _sfc_main$30 = {
8432
8540
  id: "pending",
8433
8541
  anchorTop: pendingTop,
8434
8542
  anchorBottom: pendingTop,
8543
+ hasAnchorGeometry: true,
8435
8544
  top: pendingTop,
8436
8545
  height: measuredHeights.value["pending"] || ESTIMATED_HEIGHT,
8437
8546
  commentRef: pendingComment.value
@@ -8442,6 +8551,7 @@ var _sfc_main$30 = {
8442
8551
  resolveCollisions(positions, activeKey ? positions.findIndex((p) => p.id === activeKey) : -1, 15);
8443
8552
  const viewportRange = getFloatingViewportRange();
8444
8553
  if (viewportRange) for (const position of positions) {
8554
+ if (!position.hasAnchorGeometry) continue;
8445
8555
  const persistentReviewTop = resolvePersistentReviewCardTop({
8446
8556
  comment: position.commentRef,
8447
8557
  anchorTop: position.anchorTop,
@@ -8571,6 +8681,7 @@ var _sfc_main$30 = {
8571
8681
  let continuityAlignmentScheduled = false;
8572
8682
  let continuityAlignmentGeneration = 0;
8573
8683
  let continuityTransitionFrame = null;
8684
+ let activeLayoutContinuityFrame = null;
8574
8685
  const clearDeferredRemeasureTimers = () => {
8575
8686
  remeasureTimers.forEach(clearTimeout);
8576
8687
  remeasureTimers = [];
@@ -8742,14 +8853,27 @@ var _sfc_main$30 = {
8742
8853
  });
8743
8854
  let prevPositionIds = /* @__PURE__ */ new Set();
8744
8855
  let prevActiveAnchorTop = null;
8856
+ let prevActiveLayoutTop = null;
8745
8857
  (0, vue.watch)(allPositions, (positions) => {
8746
8858
  const activePosition = activeCommentInstanceId.value ? positions.find((position) => position.id === activeCommentInstanceId.value) : null;
8747
8859
  const activeAnchorTop = typeof activePosition?.anchorTop === "number" && Number.isFinite(activePosition.anchorTop) ? activePosition.anchorTop : null;
8748
- if (activeAnchorTop != null && prevActiveAnchorTop != null && Math.abs(activeAnchorTop - prevActiveAnchorTop) > 1 && sidebarOffsetY.value !== 0 && !Number.isFinite(instantSidebarAlignmentTargetY.value)) {
8860
+ const activeAnchorMoved = activeAnchorTop != null && prevActiveAnchorTop != null && Math.abs(activeAnchorTop - prevActiveAnchorTop) > 1;
8861
+ const activeLayoutTop = typeof activePosition?.top === "number" && Number.isFinite(activePosition.top) ? activePosition.top : null;
8862
+ const activeLayoutMoved = activeLayoutTop != null && prevActiveLayoutTop != null && Math.abs(activeLayoutTop - prevActiveLayoutTop) > 1;
8863
+ if (activeAnchorMoved && sidebarOffsetY.value !== 0 && !Number.isFinite(instantSidebarAlignmentTargetY.value)) {
8749
8864
  sidebarOffsetY.value = 0;
8750
8865
  setInstantLayoutTransitionsDisabled(false);
8866
+ } else if (activeLayoutMoved && sidebarOffsetY.value !== 0 && !Number.isFinite(instantSidebarAlignmentTargetY.value) && !sidebarContinuityAnchor) {
8867
+ setInstantLayoutTransitionsDisabled(true);
8868
+ sidebarOffsetY.value += prevActiveLayoutTop - activeLayoutTop;
8869
+ if (activeLayoutContinuityFrame != null) cancelAnimationFrame(activeLayoutContinuityFrame);
8870
+ activeLayoutContinuityFrame = requestAnimationFrame(() => {
8871
+ activeLayoutContinuityFrame = null;
8872
+ if (!sidebarContinuityAnchor && !Number.isFinite(instantSidebarAlignmentTargetY.value)) setInstantLayoutTransitionsDisabled(false);
8873
+ });
8751
8874
  }
8752
8875
  prevActiveAnchorTop = activeAnchorTop;
8876
+ prevActiveLayoutTop = activeLayoutTop;
8753
8877
  const positionOrder = positions.map((position) => position.id);
8754
8878
  const currentIds = new Set(positionOrder);
8755
8879
  if (sidebarContinuityAnchor && !currentIds.has(sidebarContinuityAnchor.key)) {
@@ -8814,6 +8938,10 @@ var _sfc_main$30 = {
8814
8938
  clearDeferredRemeasureTimers();
8815
8939
  if (scrollTimer) clearTimeout(scrollTimer);
8816
8940
  clearSidebarContinuityAnchor();
8941
+ if (activeLayoutContinuityFrame != null) {
8942
+ cancelAnimationFrame(activeLayoutContinuityFrame);
8943
+ activeLayoutContinuityFrame = null;
8944
+ }
8817
8945
  if (observer) {
8818
8946
  observer.disconnect();
8819
8947
  observer = null;
@@ -8875,7 +9003,7 @@ var _sfc_main$30 = {
8875
9003
  };
8876
9004
  }
8877
9005
  };
8878
- var FloatingComments_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$30, [["__scopeId", "data-v-7bf85652"]]);
9006
+ var FloatingComments_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$30, [["__scopeId", "data-v-3672b976"]]);
8879
9007
  var _hoisted_1$22 = {
8880
9008
  class: "superdoc__pdf-comments-layer pdf-comments-layer",
8881
9009
  "aria-hidden": "false"
@@ -9621,6 +9749,17 @@ const DRAWING_SUPPORT_TAXONOMY = {
9621
9749
  }
9622
9750
  };
9623
9751
  const DRAWING_FAMILIES = Object.keys(DRAWING_SUPPORT_TAXONOMY);
9752
+ const PAGE_CHECKPOINT_DEPENDENCY_CLASSES = Object.freeze([
9753
+ "multiple-sections",
9754
+ "furniture-page-tokens",
9755
+ "non-balanceable-multi-column-sections",
9756
+ "body-anchored-objects",
9757
+ "footnotes",
9758
+ "page-references",
9759
+ "keep-constraints",
9760
+ "tables",
9761
+ "furniture-anchored-objects"
9762
+ ]);
9624
9763
  var _hoisted_1$20 = { class: "superdoc-html-viewer" };
9625
9764
  var _hoisted_2$17 = { class: "superdoc-html-viewer__document" };
9626
9765
  var _hoisted_3$14 = ["innerHTML"];
@@ -9679,6 +9818,38 @@ var _sfc_main$26 = {
9679
9818
  }
9680
9819
  };
9681
9820
  var HtmlViewer_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$26, [["__scopeId", "data-v-da3494ba"]]);
9821
+ const collectRemovedCommentIds = (comments, targetIds, isInScope = () => true) => {
9822
+ const targets = new Set(targetIds.map(String));
9823
+ const removedIds = /* @__PURE__ */ new Set();
9824
+ comments.forEach((comment) => {
9825
+ if (!isInScope(comment)) return;
9826
+ const commentId = comment.commentId != null ? String(comment.commentId) : null;
9827
+ const importedId = comment.importedId != null ? String(comment.importedId) : null;
9828
+ if (!(commentId && targets.has(commentId)) && !(importedId && targets.has(importedId))) return;
9829
+ if (commentId) removedIds.add(commentId);
9830
+ if (importedId) removedIds.add(importedId);
9831
+ });
9832
+ let expanded = true;
9833
+ while (expanded) {
9834
+ expanded = false;
9835
+ comments.forEach((comment) => {
9836
+ if (!isInScope(comment)) return;
9837
+ const commentId = comment.commentId != null ? String(comment.commentId) : null;
9838
+ const importedId = comment.importedId != null ? String(comment.importedId) : null;
9839
+ const parentCommentId = comment.parentCommentId != null ? String(comment.parentCommentId) : null;
9840
+ const trackedChangeThreadParentIdValue = trackedChangeThreadParentIdForComment(comment);
9841
+ const trackedChangeThreadParentId = trackedChangeThreadParentIdValue != null ? String(trackedChangeThreadParentIdValue) : null;
9842
+ const isRemovedComment = commentId && removedIds.has(commentId) || importedId && removedIds.has(importedId);
9843
+ const isDescendant = parentCommentId && removedIds.has(parentCommentId) || trackedChangeThreadParentId && removedIds.has(trackedChangeThreadParentId);
9844
+ if (!isRemovedComment && !isDescendant) return;
9845
+ const sizeBefore = removedIds.size;
9846
+ if (commentId) removedIds.add(commentId);
9847
+ if (importedId) removedIds.add(importedId);
9848
+ if (removedIds.size > sizeBefore) expanded = true;
9849
+ });
9850
+ }
9851
+ return removedIds;
9852
+ };
9682
9853
  var isHighContrastMode = (0, vue.ref)(false);
9683
9854
  function useHighContrastMode() {
9684
9855
  const setHighContrastMode = (value) => {
@@ -10067,6 +10238,45 @@ function resolveV2ReviewTargetCommentId(target, getComment) {
10067
10238
  const commentId = comment?.commentId ?? comment?.importedId ?? target.entityId;
10068
10239
  return commentId != null ? String(commentId) : null;
10069
10240
  }
10241
+ function normalizeDocumentId(value) {
10242
+ return value == null ? null : String(value);
10243
+ }
10244
+ 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) }) {
10245
+ let timer = null;
10246
+ let heldSinceMs = null;
10247
+ let pendingDocumentId = null;
10248
+ const matchesActiveDocument = (documentId) => {
10249
+ return normalizeDocumentId(getActiveDocumentId()) === documentId;
10250
+ };
10251
+ const clear = () => {
10252
+ if (timer != null) clearTimer(timer);
10253
+ timer = null;
10254
+ heldSinceMs = null;
10255
+ pendingDocumentId = null;
10256
+ };
10257
+ const schedule = (documentId) => {
10258
+ const normalizedDocumentId = normalizeDocumentId(documentId);
10259
+ if (!matchesActiveDocument(normalizedDocumentId)) return false;
10260
+ if (pendingDocumentId !== normalizedDocumentId) clear();
10261
+ const scheduledAtMs = now$2();
10262
+ pendingDocumentId = normalizedDocumentId;
10263
+ heldSinceMs ??= scheduledAtMs;
10264
+ if (timer != null) clearTimer(timer);
10265
+ const ceilingRemainingMs = Math.max(0, ceilingMs - (scheduledAtMs - heldSinceMs));
10266
+ timer = setTimer(() => {
10267
+ const deliveredDocumentId = pendingDocumentId;
10268
+ timer = null;
10269
+ heldSinceMs = null;
10270
+ pendingDocumentId = null;
10271
+ if (matchesActiveDocument(deliveredDocumentId)) hydrate();
10272
+ }, Math.min(debounceMs, ceilingRemainingMs));
10273
+ return true;
10274
+ };
10275
+ return {
10276
+ schedule,
10277
+ clear
10278
+ };
10279
+ }
10070
10280
  var NO_AUTHOR_SIGNAL = "no-author-configured";
10071
10281
  const V2_AUTHOR_REQUIRED_CODE = "author-required";
10072
10282
  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.";
@@ -11406,8 +11616,11 @@ function scrollToElement(targetElement, options = {
11406
11616
  const container = getScrollableParent(targetElement);
11407
11617
  const containerRect = container.getBoundingClientRect();
11408
11618
  const offsetTop = targetElement.getBoundingClientRect().top - containerRect.top + container.scrollTop;
11619
+ const scrollPaddingTopValue = window.getComputedStyle(container).scrollPaddingTop?.trim();
11620
+ const resolvedScrollPaddingTop = scrollPaddingTopValue?.endsWith("px") ? Number(scrollPaddingTopValue.slice(0, -2)) : 0;
11621
+ const scrollPaddingTop = Number.isFinite(resolvedScrollPaddingTop) && resolvedScrollPaddingTop >= 0 ? resolvedScrollPaddingTop : 0;
11409
11622
  container.scrollTo({
11410
- top: options.block === "start" ? offsetTop : offsetTop - container.clientHeight + targetElement.offsetHeight,
11623
+ top: options.block === "start" ? offsetTop - scrollPaddingTop : offsetTop - container.clientHeight + targetElement.offsetHeight,
11411
11624
  behavior: options.behavior
11412
11625
  });
11413
11626
  }
@@ -14615,6 +14828,8 @@ var _sfc_main$20 = {
14615
14828
  if (latestV2MountStage && (clearedDocumentId == null || latestV2MountStage.dataset?.superdocV2DocumentId === clearedDocumentId)) latestV2MountStage = null;
14616
14829
  v2ReviewHydrationController.reset("render-cleared");
14617
14830
  v2ReviewMutationReconciler.reset();
14831
+ clearV2TypingReviewHydrationTimer();
14832
+ v2RemoteReviewHydrationScheduler.clear();
14618
14833
  commentsStore.setV2CommentsAdapter?.(null);
14619
14834
  commentsStore.setV2TrackedChangesAdapter?.(null);
14620
14835
  commentsStore.clearEditorCommentPositions?.();
@@ -14667,6 +14882,12 @@ var _sfc_main$20 = {
14667
14882
  });
14668
14883
  let v2LastTypingMutationAtMs = 0;
14669
14884
  let v2TypingReviewHydrationHeldSinceMs = 0;
14885
+ const clearV2TypingReviewHydrationTimer = () => {
14886
+ if (v2TypingReviewHydrationTimer && typeof clearTimeout === "function") clearTimeout(v2TypingReviewHydrationTimer);
14887
+ v2TypingReviewHydrationTimer = 0;
14888
+ v2LastTypingMutationAtMs = 0;
14889
+ v2TypingReviewHydrationHeldSinceMs = 0;
14890
+ };
14670
14891
  const scheduleV2TypingReviewHydration = () => {
14671
14892
  v2LastTypingMutationAtMs = Date.now();
14672
14893
  if (!v2TypingReviewHydrationHeldSinceMs) v2TypingReviewHydrationHeldSinceMs = v2LastTypingMutationAtMs;
@@ -14687,6 +14908,13 @@ var _sfc_main$20 = {
14687
14908
  const ceilingRemainingMs = Math.max(0, V2_TYPING_REVIEW_HYDRATION_CEILING_MS - (Date.now() - v2TypingReviewHydrationHeldSinceMs));
14688
14909
  v2TypingReviewHydrationTimer = setTimeout(attempt, Math.min(V2_TYPING_REVIEW_HYDRATION_IDLE_MS, ceilingRemainingMs));
14689
14910
  };
14911
+ const v2RemoteReviewHydrationScheduler = createV2RemoteReviewHydrationScheduler({
14912
+ hydrate: () => hydrateV2ReviewRowsFromHost(),
14913
+ getActiveDocumentId: () => {
14914
+ const activeEditor = proxy.$superdoc?.activeEditor ?? null;
14915
+ return activeEditor?.documentId ?? activeEditor?.options?.documentId ?? null;
14916
+ }
14917
+ });
14690
14918
  const onV2HostEvent = (document$1, event) => {
14691
14919
  if (!event) return;
14692
14920
  const documentId = document$1?.id ?? null;
@@ -14694,6 +14922,10 @@ var _sfc_main$20 = {
14694
14922
  syncSidebarActiveCommentFromV2ReviewTarget(event.next);
14695
14923
  return;
14696
14924
  }
14925
+ if (event.type === "collaboration:remote-changed") {
14926
+ v2RemoteReviewHydrationScheduler.schedule(documentId);
14927
+ return;
14928
+ }
14697
14929
  if (event.type === "source:complete") {
14698
14930
  proxy.$superdoc.broadcastSourceComplete();
14699
14931
  return;
@@ -14927,6 +15159,7 @@ var _sfc_main$20 = {
14927
15159
  "isInternal",
14928
15160
  "parentCommentId",
14929
15161
  "trackedChangeParentId",
15162
+ "trackedChangeThreadParentId",
14930
15163
  "threadingParentCommentId",
14931
15164
  "trackedChange",
14932
15165
  "trackedChangeType",
@@ -15091,34 +15324,8 @@ var _sfc_main$20 = {
15091
15324
  if (!activeDocumentId || typeof belongsToDocument !== "function") return true;
15092
15325
  return belongsToDocument(comment, activeDocumentId);
15093
15326
  };
15094
- const removedCommentIds = /* @__PURE__ */ new Set();
15095
- commentsList.value.forEach((comment) => {
15096
- if (!isInActiveDocument(comment)) return;
15097
- const commentId = comment.commentId != null ? String(comment.commentId) : null;
15098
- const importedId = comment.importedId != null ? String(comment.importedId) : null;
15099
- if (!(commentId && targetIds.includes(commentId) || importedId && targetIds.includes(importedId))) return;
15100
- if (commentId) removedCommentIds.add(commentId);
15101
- if (importedId) removedCommentIds.add(importedId);
15102
- });
15327
+ const removedCommentIds = collectRemovedCommentIds(commentsList.value, targetIds, isInActiveDocument);
15103
15328
  if (removedCommentIds.size) {
15104
- let expanded = true;
15105
- while (expanded) {
15106
- expanded = false;
15107
- commentsList.value.forEach((comment) => {
15108
- if (!isInActiveDocument(comment)) return;
15109
- const commentId = comment.commentId != null ? String(comment.commentId) : null;
15110
- const importedId = comment.importedId != null ? String(comment.importedId) : null;
15111
- const parentCommentId = comment.parentCommentId != null ? String(comment.parentCommentId) : null;
15112
- const trackedChangeParentId = comment.trackedChangeParentId != null ? String(comment.trackedChangeParentId) : null;
15113
- const isRemovedComment = commentId && removedCommentIds.has(commentId) || importedId && removedCommentIds.has(importedId);
15114
- const isDescendantOfRemovedComment = parentCommentId && removedCommentIds.has(parentCommentId) || trackedChangeParentId && removedCommentIds.has(trackedChangeParentId);
15115
- if (!isRemovedComment && !isDescendantOfRemovedComment) return;
15116
- const sizeBefore = removedCommentIds.size;
15117
- if (commentId) removedCommentIds.add(commentId);
15118
- if (importedId) removedCommentIds.add(importedId);
15119
- if (removedCommentIds.size > sizeBefore) expanded = true;
15120
- });
15121
- }
15122
15329
  const previousComments = [...commentsList.value];
15123
15330
  commentsList.value = commentsList.value.filter((comment) => {
15124
15331
  if (!isInActiveDocument(comment)) return true;
@@ -15376,11 +15583,8 @@ var _sfc_main$20 = {
15376
15583
  cancelAnimationFrame(v2GeometryRafHandle);
15377
15584
  v2GeometryRafHandle = 0;
15378
15585
  }
15379
- if (v2TypingReviewHydrationTimer && typeof clearTimeout === "function") {
15380
- clearTimeout(v2TypingReviewHydrationTimer);
15381
- v2TypingReviewHydrationTimer = 0;
15382
- }
15383
- v2TypingReviewHydrationHeldSinceMs = 0;
15586
+ clearV2TypingReviewHydrationTimer();
15587
+ v2RemoteReviewHydrationScheduler.clear();
15384
15588
  document.removeEventListener("focusin", handleRuntimeFocusIn, true);
15385
15589
  document.removeEventListener("pointerdown", handleRuntimePointerDown, true);
15386
15590
  document.removeEventListener("mousedown", handleRuntimeMouseDown, true);
@@ -15874,7 +16078,7 @@ var _sfc_main$20 = {
15874
16078
  };
15875
16079
  }
15876
16080
  };
15877
- var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-8d8777e2"]]);
16081
+ var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-c4ab995e"]]);
15878
16082
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
15879
16083
  var PINIA_DEVTOOLS_PLUGIN_ID = "dev.esm.pinia";
15880
16084
  var piniaDevtoolsSuppressionState = {
@@ -34443,7 +34647,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
34443
34647
  this.config.colors = shuffleArray(this.config.colors);
34444
34648
  this.userColorMap = /* @__PURE__ */ new Map();
34445
34649
  this.colorIndex = 0;
34446
- this.version = "2.0.0-next.26";
34650
+ this.version = "2.0.0-next.28";
34447
34651
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
34448
34652
  this.superdocId = config.superdocId || require_uuid.v4_default();
34449
34653
  this.colors = this.config.colors ?? [];