superdoc 2.28.0-next.1 → 2.28.0-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/dist/chunks/{create-super-doc-ui-D1eOhAjv.cjs → create-super-doc-ui-B4c55pFy.cjs} +420 -84
  2. package/dist/chunks/{create-super-doc-ui-B29zw5qD.es.js → create-super-doc-ui-C4Ka5Ph3.es.js} +415 -85
  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/content-controls/content-controls.types.d.ts +11 -0
  6. package/dist/document-api/src/contract/command-catalog.d.ts +1 -1
  7. package/dist/document-api/src/contract/operation-definitions.d.ts +44 -44
  8. package/dist/document-api/src/contract/operation-registry.d.ts +4 -0
  9. package/dist/document-api/src/export/export.d.ts +3 -1
  10. package/dist/document-api/src/export/export.types.d.ts +8 -0
  11. package/dist/document-api/src/get-node/get-node.d.ts +10 -4
  12. package/dist/document-api/src/hyperlinks/hyperlinks.types.d.ts +2 -0
  13. package/dist/document-api/src/index.d.ts +2 -1
  14. package/dist/document-api/src/replace/replace.d.ts +4 -1
  15. package/dist/document-api/src/types/mutation-plan.types.d.ts +2 -0
  16. package/dist/document-api/src/types/track-changes.types.d.ts +10 -2
  17. package/dist/layout-engine/contracts/src/index.d.ts +2 -0
  18. package/dist/layout-engine/contracts/src/resolved-layout.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-vue.cjs +1 -1
  22. package/dist/public/ui-vue.es.js +1 -1
  23. package/dist/public/ui.cjs +1 -1
  24. package/dist/public/ui.es.js +1 -1
  25. package/dist/shared/common/list-marker-utils.d.ts +3 -0
  26. package/dist/style.css +1 -1
  27. package/dist/style.layered.css +1 -1
  28. package/dist/superdoc/src/core/SuperDoc.d.ts +2 -6
  29. package/dist/superdoc/src/core/collaboration/resolve-v2-collaboration-target.d.ts +2 -0
  30. package/dist/superdoc/src/core/config/normalize-ui-config.d.ts +1 -0
  31. package/dist/superdoc/src/core/editor-runtime/types.d.ts +1 -0
  32. package/dist/superdoc/src/core/editor-runtime/v2/v2-editor-runtime-adapter.d.ts +2 -2
  33. package/dist/superdoc/src/core/extensions/types.d.ts +14 -3
  34. package/dist/superdoc/src/core/helpers/resolve-docx-export.d.ts +6 -0
  35. package/dist/superdoc/src/core/types/index.d.ts +35 -1
  36. package/dist/superdoc/src/core/v2-integration/v2-integration.d.ts +0 -8
  37. package/dist/superdoc/src/internal/toolbar/built-in/color-dropdown-helpers.d.ts +0 -1
  38. package/dist/superdoc/src/internal/toolbar/built-in/constants.d.ts +0 -2
  39. package/dist/superdoc/src/public/export-types.d.ts +3 -0
  40. package/dist/superdoc/src/public/ui/entity-at.d.ts +1 -0
  41. package/dist/superdoc/src/public/ui/format-painter-helpers.d.ts +0 -13
  42. package/dist/superdoc/src/public/ui/types.d.ts +16 -2
  43. package/dist/superdoc/src/public/ui.d.cts +14 -0
  44. package/dist/superdoc/src/public/ui.d.ts +1 -1
  45. package/dist/superdoc/src/stores/comments-store.d.ts +3 -57
  46. package/dist/superdoc/src/stores/superdoc-store.d.ts +9 -171
  47. package/dist/superdoc.cjs +363 -159
  48. package/dist/superdoc.es.js +363 -159
  49. package/dist/word-layout/src/types.d.ts +1 -0
  50. package/dist-cdn/style.layered.css +1 -1
  51. package/dist-cdn/superdoc.min.css +1 -1
  52. package/dist-cdn/superdoc.min.js +42 -42
  53. package/package.json +2 -2
  54. package/dist/footnote-table-order.docx +0 -0
  55. package/dist/images/altText_add.svg +0 -3
  56. package/dist/images/altText_disclaimer.svg +0 -3
  57. package/dist/images/altText_done.svg +0 -3
  58. package/dist/images/altText_spinner.svg +0 -30
  59. package/dist/images/altText_warning.svg +0 -3
  60. package/dist/images/annotation-check.svg +0 -11
  61. package/dist/images/annotation-comment.svg +0 -16
  62. package/dist/images/annotation-help.svg +0 -26
  63. package/dist/images/annotation-insert.svg +0 -10
  64. package/dist/images/annotation-key.svg +0 -11
  65. package/dist/images/annotation-newparagraph.svg +0 -11
  66. package/dist/images/annotation-noicon.svg +0 -7
  67. package/dist/images/annotation-note.svg +0 -42
  68. package/dist/images/annotation-paperclip.svg +0 -6
  69. package/dist/images/annotation-paragraph.svg +0 -16
  70. package/dist/images/annotation-pushpin.svg +0 -7
  71. package/dist/images/checkmark.svg +0 -5
  72. package/dist/images/comment-actionsButton.svg +0 -3
  73. package/dist/images/comment-closeButton.svg +0 -3
  74. package/dist/images/comment-editButton.svg +0 -8
  75. package/dist/images/comment-popup-editButton.svg +0 -5
  76. package/dist/images/cursor-editorFreeHighlight.svg +0 -6
  77. package/dist/images/cursor-editorFreeText.svg +0 -3
  78. package/dist/images/cursor-editorInk.svg +0 -4
  79. package/dist/images/cursor-editorTextHighlight.svg +0 -8
  80. package/dist/images/editor-toolbar-delete.svg +0 -5
  81. package/dist/images/editor-toolbar-edit.svg +0 -3
  82. package/dist/images/findbarButton-next.svg +0 -3
  83. package/dist/images/findbarButton-previous.svg +0 -3
  84. package/dist/images/gv-toolbarButton-download.svg +0 -3
  85. package/dist/images/loading-icon.gif +0 -0
  86. package/dist/images/loading.svg +0 -1
  87. package/dist/images/messageBar_closingButton.svg +0 -3
  88. package/dist/images/messageBar_info.svg +0 -3
  89. package/dist/images/messageBar_warning.svg +0 -3
  90. package/dist/images/pages_closeButton.svg +0 -3
  91. package/dist/images/pages_selected.svg +0 -7
  92. package/dist/images/pages_viewArrow.svg +0 -3
  93. package/dist/images/pages_viewButton.svg +0 -3
  94. package/dist/images/secondaryToolbarButton-documentProperties.svg +0 -3
  95. package/dist/images/secondaryToolbarButton-firstPage.svg +0 -3
  96. package/dist/images/secondaryToolbarButton-handTool.svg +0 -3
  97. package/dist/images/secondaryToolbarButton-lastPage.svg +0 -3
  98. package/dist/images/secondaryToolbarButton-rotateCcw.svg +0 -3
  99. package/dist/images/secondaryToolbarButton-rotateCw.svg +0 -3
  100. package/dist/images/secondaryToolbarButton-scrollHorizontal.svg +0 -3
  101. package/dist/images/secondaryToolbarButton-scrollPage.svg +0 -3
  102. package/dist/images/secondaryToolbarButton-scrollVertical.svg +0 -3
  103. package/dist/images/secondaryToolbarButton-scrollWrapped.svg +0 -3
  104. package/dist/images/secondaryToolbarButton-selectTool.svg +0 -3
  105. package/dist/images/secondaryToolbarButton-spreadEven.svg +0 -3
  106. package/dist/images/secondaryToolbarButton-spreadNone.svg +0 -3
  107. package/dist/images/secondaryToolbarButton-spreadOdd.svg +0 -3
  108. package/dist/images/toolbarButton-bookmark.svg +0 -3
  109. package/dist/images/toolbarButton-currentOutlineItem.svg +0 -3
  110. package/dist/images/toolbarButton-download.svg +0 -4
  111. package/dist/images/toolbarButton-editorFreeText.svg +0 -5
  112. package/dist/images/toolbarButton-editorHighlight.svg +0 -6
  113. package/dist/images/toolbarButton-editorInk.svg +0 -4
  114. package/dist/images/toolbarButton-editorSignature.svg +0 -6
  115. package/dist/images/toolbarButton-editorStamp.svg +0 -8
  116. package/dist/images/toolbarButton-menuArrow.svg +0 -3
  117. package/dist/images/toolbarButton-openFile.svg +0 -3
  118. package/dist/images/toolbarButton-pageDown.svg +0 -3
  119. package/dist/images/toolbarButton-pageUp.svg +0 -3
  120. package/dist/images/toolbarButton-presentationMode.svg +0 -3
  121. package/dist/images/toolbarButton-print.svg +0 -3
  122. package/dist/images/toolbarButton-search.svg +0 -3
  123. package/dist/images/toolbarButton-secondaryToolbarToggle.svg +0 -3
  124. package/dist/images/toolbarButton-viewAttachments.svg +0 -3
  125. package/dist/images/toolbarButton-viewLayers.svg +0 -3
  126. package/dist/images/toolbarButton-viewOutline.svg +0 -3
  127. package/dist/images/toolbarButton-viewThumbnail.svg +0 -3
  128. package/dist/images/toolbarButton-viewsManagerToggle.svg +0 -3
  129. package/dist/images/toolbarButton-zoomIn.svg +0 -3
  130. package/dist/images/toolbarButton-zoomOut.svg +0 -3
  131. package/dist/images/treeitem-collapsed.svg +0 -1
  132. package/dist/images/treeitem-expanded.svg +0 -1
  133. package/dist/superdoc/src/helpers/floor.d.ts +0 -1
  134. package/dist/superdoc/src/index.d.cts +0 -18
  135. package/dist/superdoc/src/index.d.ts +0 -14
  136. package/dist-cdn/footnote-table-order.docx +0 -0
@@ -1,6 +1,6 @@
1
1
  import { i as __toESM$2 } from "./chunks/rolldown-runtime-0pSA04fp.es.js";
2
2
  import { t as blank_default } from "./chunks/blank-docx-DzQccOlW.es.js";
3
- import { _ as getWorkflowRecording, a as registerFirstPartyCommandMutation, c as getV2TrackedChangeMutationImpact, d as resolveImageSrc, g as createInteractionHistory, h as closeInteractionHistory, i as readFirstPartyPageNumbers, l as isPlainObject$1, m as DOM_CLASS_NAMES, n as executeFirstPartyCommandAsync, p as isSyntheticTrackedChangeCommentLaneItem, r as executeFirstPartyShortcutAsync, s as applyV2CommentInvalidationFromMutation, t as createSuperDocUI, u as createImageFilePicker, v as isWorkflowRecordingEnabled, y as recordInteraction } from "./chunks/create-super-doc-ui-B29zw5qD.es.js";
3
+ import { _ as createInteractionHistory, a as registerFirstPartyCommandMutation, b as recordInteraction, c as applyV2CommentInvalidationFromMutation, d as createImageFilePicker, f as resolveImageSrc, g as closeInteractionHistory, h as DOM_CLASS_NAMES, i as readFirstPartyPageNumbers, l as getV2TrackedChangeMutationImpact, m as isSyntheticTrackedChangeCommentLaneItem, n as executeFirstPartyCommandAsync, o as isRecord, r as executeFirstPartyShortcutAsync, t as createSuperDocUI, u as isPlainObject$1, v as getWorkflowRecording, y as isWorkflowRecordingEnabled } from "./chunks/create-super-doc-ui-C4Ka5Ph3.es.js";
4
4
  import { t as import_eventemitter3 } from "./chunks/eventemitter3-DEIiXiH2.es.js";
5
5
  import { t as v4 } from "./chunks/uuid-H0Xcmmhy.es.js";
6
6
  import { $ as vModelText, A as onActivated, B as renderSlot, C as isRef$1, D as normalizeClass, E as nextTick, F as openBlock, G as toRaw$2, H as resolveDynamicComponent, I as provide$1, J as unref, K as toRef, L as reactive, M as onDeactivated, N as onMounted, O as normalizeProps, P as onScopeDispose$1, Q as vModelSelect, R as ref, S as isReactive$1, T as mergeProps, U as shallowRef$1, V as resolveDirective, W as toDisplayString, X as useSlots, Y as useAttrs, Z as vModelCheckbox, _ as getCurrentInstance, a as computed$1, b as hasInjectionContext, c as createCommentVNode, d as createStaticVNode, et as watch$1, f as createTextVNode, g as effectScope, h as defineComponent, i as Transition, it as withModifiers, j as onBeforeUnmount, k as normalizeStyle, l as createElementBlock, m as defineAsyncComponent, n as Fragment, nt as withDirectives, o as createApp, p as createVNode, q as toRefs, r as Teleport, rt as withKeys, s as createBlock, t as _plugin_vue_export_helper_default, tt as withCtx, u as createElementVNode, v as getCurrentScope, w as markRaw, x as inject$1, y as h, z as renderList } from "./chunks/_plugin-vue_export-helper-7ZiLY07t.es.js";
@@ -258,7 +258,7 @@ var v_click_outside_default = {
258
258
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
259
259
  function getSuperdocVersion() {
260
260
  try {
261
- return "2.28.0-next.1";
261
+ return "2.28.0-next.10";
262
262
  } catch {
263
263
  return "unknown";
264
264
  }
@@ -5462,7 +5462,8 @@ function resolveWebsocketFamily(family, candidate) {
5462
5462
  roomMode,
5463
5463
  serverUrl,
5464
5464
  ...params ? { params } : {},
5465
- ...token ? { token } : {}
5465
+ ...token ? { token } : {},
5466
+ ...family === "hocuspocus" && candidate.retry !== void 0 ? { retry: candidate.retry } : {}
5466
5467
  }
5467
5468
  };
5468
5469
  }
@@ -7185,16 +7186,6 @@ function createDefaultV2Integration() {
7185
7186
  return createStubV2Integration();
7186
7187
  }
7187
7188
  }
7188
- /**
7189
- * Backwards-compatible alias. The v2 branch no longer reads any customer
7190
- * config; the parameter is ignored and retained only so existing call sites do
7191
- * not need to change in lockstep with this internalization.
7192
- *
7193
- * @returns {SuperDocV2Integration}
7194
- */
7195
- function resolveV2Integration() {
7196
- return createDefaultV2Integration();
7197
- }
7198
7189
  //#endregion
7199
7190
  //#region src/helpers/interaction-trace.js
7200
7191
  function safeTraceCollector() {
@@ -7753,6 +7744,7 @@ var useCommentsStore = defineStore("comments", () => {
7753
7744
  const instantSidebarAlignmentInstanceId = ref(null);
7754
7745
  const pendingComment = ref(null);
7755
7746
  const pendingV2CommentTarget = shallowRef$1(null);
7747
+ let pendingCommentRequest = 0;
7756
7748
  const isViewingMode = computed$1(() => viewingVisibility.documentMode === "viewing");
7757
7749
  const shouldRenderReviewInViewing = computed$1(() => {
7758
7750
  if (!isViewingMode.value) return true;
@@ -7760,6 +7752,7 @@ var useCommentsStore = defineStore("comments", () => {
7760
7752
  });
7761
7753
  const v2CommentsAdapter = shallowRef$1(null);
7762
7754
  const setV2CommentsAdapter = (adapter) => {
7755
+ if (v2CommentsAdapter.value !== (adapter ?? null)) pendingCommentRequest += 1;
7763
7756
  v2CommentsAdapter.value = adapter ?? null;
7764
7757
  };
7765
7758
  const getV2CommentsAdapter = (superdoc) => {
@@ -8618,26 +8611,41 @@ var useCommentsStore = defineStore("comments", () => {
8618
8611
  }
8619
8612
  if (typeof currentSelection !== "function") return null;
8620
8613
  try {
8621
- return currentSelection();
8614
+ const snapshot = currentSelection();
8615
+ return typeof snapshot?.then === "function" ? Promise.resolve(snapshot).catch(() => null) : snapshot;
8622
8616
  } catch {
8623
8617
  return null;
8624
8618
  }
8625
8619
  };
8626
8620
  const showAddComment = (superdoc, targetClientY = null) => {
8621
+ const request = ++pendingCommentRequest;
8622
+ const editor = superdoc?.activeEditor;
8627
8623
  const v2Adapter = getV2CommentsAdapter(superdoc);
8628
- const pendingSelection = getPendingSelectionSnapshot(superdoc, superdocStore.activeSelection);
8629
- const event = {
8630
- type: COMMENT_EVENTS.PENDING,
8631
- pendingSelection
8624
+ const ownsRequest = () => pendingCommentRequest === request;
8625
+ const emitPending = (snapshot) => {
8626
+ if (!ownsRequest()) return;
8627
+ superdoc.emit("comments-update", {
8628
+ type: COMMENT_EVENTS.PENDING,
8629
+ pendingSelection: superdoc?.activeEditor === editor ? snapshot : null
8630
+ });
8632
8631
  };
8633
- superdoc.emit("comments-update", event);
8634
8632
  if (v2Adapter) {
8635
8633
  const cap = v2Adapter.getCapabilityState?.();
8636
8634
  if (cap && cap.canWrite === false) return {
8637
8635
  ok: false,
8638
8636
  reason: cap.reason
8639
8637
  };
8640
- return Promise.resolve(v2Adapter.captureCurrentSelection?.()).then((capture) => {
8638
+ return Promise.resolve(v2Adapter.captureCurrentSelection?.({ beforeReady: (snapshot) => {
8639
+ if (superdoc?.activeEditor === editor && getV2CommentsAdapter(superdoc) === v2Adapter) emitPending(snapshot);
8640
+ } })).then((capture) => {
8641
+ if (!ownsRequest()) return {
8642
+ ok: false,
8643
+ reason: "pending-comment-superseded"
8644
+ };
8645
+ if (superdoc?.activeEditor !== editor || getV2CommentsAdapter(superdoc) !== v2Adapter) return {
8646
+ ok: false,
8647
+ reason: "document-replaced"
8648
+ };
8641
8649
  if (!capture?.ok) return {
8642
8650
  ok: false,
8643
8651
  reason: capture?.reason ?? "editing-range-required",
@@ -8666,25 +8674,52 @@ var useCommentsStore = defineStore("comments", () => {
8666
8674
  detail: err?.message ?? String(err)
8667
8675
  }));
8668
8676
  }
8669
- const selection = { ...superdocStore.activeSelection };
8670
- selection.selectionBounds = { ...selection.selectionBounds };
8671
- if (superdocStore.selectionPosition?.source && superdocStore.selectionPosition.source !== "pdf") superdocStore.selectionPosition.source = null;
8672
- pendingComment.value = getPendingComment({
8673
- selection,
8674
- documentId: selection.documentId,
8675
- parentCommentId: null
8676
- });
8677
- if (!superdoc.config.isInternal) pendingComment.value.isInternal = false;
8678
- if (superdoc.activeEditor?.commands) superdoc.activeEditor.commands.insertComment({
8679
- ...pendingComment.value.getValues(),
8680
- commentId: "pending",
8681
- skipEmit: true
8682
- });
8683
- if (pendingComment.value.selection.source === "document-editor" && superdocStore.selectionPosition) superdocStore.selectionPosition.source = DOCUMENT_EDITOR_SELECTION_SOURCE;
8684
- requestInstantSidebarAlignment(targetClientY, "pending");
8685
- setActiveFloatingCommentInstance(null);
8686
- activeComment.value = pendingComment.value.commentId;
8687
- return { ok: true };
8677
+ const pendingSelection = getPendingSelectionSnapshot(superdoc, superdocStore.activeSelection);
8678
+ const asyncSnapshot = typeof pendingSelection?.then === "function";
8679
+ if (!asyncSnapshot) emitPending(pendingSelection);
8680
+ const showLegacyPending = (selection) => {
8681
+ selection.selectionBounds = { ...selection.selectionBounds };
8682
+ if (superdocStore.selectionPosition?.source && superdocStore.selectionPosition.source !== "pdf") superdocStore.selectionPosition.source = null;
8683
+ pendingComment.value = getPendingComment({
8684
+ selection,
8685
+ documentId: selection.documentId,
8686
+ parentCommentId: null
8687
+ });
8688
+ if (!superdoc.config.isInternal) pendingComment.value.isInternal = false;
8689
+ if (superdoc.activeEditor?.commands) superdoc.activeEditor.commands.insertComment({
8690
+ ...pendingComment.value.getValues(),
8691
+ commentId: "pending",
8692
+ skipEmit: true
8693
+ });
8694
+ if (pendingComment.value.selection.source === "document-editor" && superdocStore.selectionPosition) superdocStore.selectionPosition.source = DOCUMENT_EDITOR_SELECTION_SOURCE;
8695
+ requestInstantSidebarAlignment(targetClientY, "pending");
8696
+ setActiveFloatingCommentInstance(null);
8697
+ activeComment.value = pendingComment.value.commentId;
8698
+ return { ok: true };
8699
+ };
8700
+ if (asyncSnapshot) {
8701
+ const selection = { ...superdocStore.activeSelection };
8702
+ selection.selectionBounds = { ...selection.selectionBounds };
8703
+ return pendingSelection.then((snapshot) => {
8704
+ if (!ownsRequest()) return {
8705
+ ok: false,
8706
+ reason: "pending-comment-superseded"
8707
+ };
8708
+ emitPending(snapshot);
8709
+ if (!ownsRequest()) return {
8710
+ ok: false,
8711
+ reason: "pending-comment-superseded"
8712
+ };
8713
+ return superdoc?.activeEditor === editor ? showLegacyPending(selection) : {
8714
+ ok: false,
8715
+ reason: "document-replaced"
8716
+ };
8717
+ });
8718
+ }
8719
+ return ownsRequest() ? showLegacyPending({ ...superdocStore.activeSelection }) : {
8720
+ ok: false,
8721
+ reason: "pending-comment-superseded"
8722
+ };
8688
8723
  };
8689
8724
  /**
8690
8725
  * Get the numeric position value for sorting a comment by document order.
@@ -8839,7 +8874,7 @@ var useCommentsStore = defineStore("comments", () => {
8839
8874
  *
8840
8875
  * @returns {void}
8841
8876
  */
8842
- const removePendingComment = (superdoc) => {
8877
+ const resetPendingCommentState = (superdoc, clearViewingSelection = true) => {
8843
8878
  const hadPending = !!pendingComment.value;
8844
8879
  currentCommentText.value = "";
8845
8880
  currentCommentMentions.value = [];
@@ -8848,13 +8883,17 @@ var useCommentsStore = defineStore("comments", () => {
8848
8883
  superdocStore.selectionPosition = null;
8849
8884
  if (hadPending) clearActiveCommentSelection();
8850
8885
  if (isV2EditorActive(superdoc)) {
8851
- if (hadPending && isViewingMode.value) try {
8886
+ if (hadPending && clearViewingSelection && isViewingMode.value) try {
8852
8887
  superdoc?.activeEditor?.host?.getHandles?.()?.selection?.clear?.();
8853
8888
  } catch {}
8854
8889
  return;
8855
8890
  }
8856
8891
  superdoc?.activeEditor?.commands?.removeComment({ commentId: "pending" });
8857
8892
  };
8893
+ const removePendingComment = (superdoc) => {
8894
+ pendingCommentRequest += 1;
8895
+ resetPendingCommentState(superdoc);
8896
+ };
8858
8897
  const getV2CreatedComment = ({ outcome, reconciled, documentId }) => {
8859
8898
  const createdId = normalizeCommentId(outcome?.createdCommentId);
8860
8899
  if (!createdId) return reconciled?.added ?? null;
@@ -8872,6 +8911,7 @@ var useCommentsStore = defineStore("comments", () => {
8872
8911
  const v2Adapter = !skipEditorUpdate && !isHydration ? getV2CommentsAdapter(superdoc) : null;
8873
8912
  if (v2Adapter && !comment.trackedChange) {
8874
8913
  const submittedPendingComment = pendingComment.value;
8914
+ const submittedPendingRequest = pendingCommentRequest;
8875
8915
  const text = normalizeV2CommentDraftText(submittedPendingComment ? currentCommentText.value : comment.commentText);
8876
8916
  const mentions = pendingComment.value ? currentCommentMentions.value : comment.mentions ?? [];
8877
8917
  const target = pendingComment.value ? pendingV2CommentTarget.value : null;
@@ -8920,9 +8960,11 @@ var useCommentsStore = defineStore("comments", () => {
8920
8960
  documentId: v2Adapter.documentId
8921
8961
  });
8922
8962
  const hadPendingComment = submittedPendingComment != null && pendingComment.value?.commentId === submittedPendingComment.commentId;
8923
- if (hadPendingComment) removePendingComment(superdoc);
8963
+ const ownsSubmittedRequest = pendingCommentRequest === submittedPendingRequest;
8964
+ if (hadPendingComment) if (ownsSubmittedRequest) removePendingComment(superdoc);
8965
+ else resetPendingCommentState(superdoc, false);
8924
8966
  const createdId = created?.commentId ?? null;
8925
- if (hadPendingComment && createdId) {
8967
+ if (hadPendingComment && ownsSubmittedRequest && createdId) {
8926
8968
  setActiveComment(superdoc, createdId);
8927
8969
  setActiveFloatingCommentInstance(createdId);
8928
8970
  }
@@ -9019,6 +9061,8 @@ var useCommentsStore = defineStore("comments", () => {
9019
9061
  rejected: true,
9020
9062
  comment: comment.getValues(),
9021
9063
  reason: outcome?.reason ?? "v2-delete-failed",
9064
+ ...outcome?.code !== void 0 ? { code: outcome.code } : {},
9065
+ ...outcome?.detail !== void 0 ? { detail: outcome.detail } : {},
9022
9066
  ...outcome?.committed ? { committed: true } : {}
9023
9067
  });
9024
9068
  return outcome;
@@ -13331,97 +13375,107 @@ var _hoisted_2$19 = {
13331
13375
  class: "existing-internal-input"
13332
13376
  };
13333
13377
  var _hoisted_3$16 = { class: "new-comment-input-wrapper" };
13334
- var _hoisted_4$11 = { class: "reply-actions" };
13335
- var _hoisted_5$8 = ["disabled"];
13336
- var _hoisted_6$6 = {
13378
+ var _hoisted_4$11 = {
13379
+ key: 1,
13380
+ class: "tracked-change-decision-alert",
13381
+ role: "alert"
13382
+ };
13383
+ var _hoisted_5$8 = { class: "reply-actions" };
13384
+ var _hoisted_6$6 = ["disabled"];
13385
+ var _hoisted_7$4 = {
13337
13386
  key: 0,
13338
13387
  class: "resolved-badge"
13339
13388
  };
13340
- var _hoisted_7$4 = ["innerHTML"];
13341
- var _hoisted_8$4 = {
13389
+ var _hoisted_8$4 = ["innerHTML"];
13390
+ var _hoisted_9$3 = {
13342
13391
  key: 1,
13343
13392
  class: "existing-internal-input"
13344
13393
  };
13345
- var _hoisted_9$3 = {
13394
+ var _hoisted_10$3 = {
13395
+ key: 2,
13396
+ class: "tracked-change-decision-alert",
13397
+ role: "alert"
13398
+ };
13399
+ var _hoisted_11$3 = {
13346
13400
  key: 0,
13347
13401
  class: "card-section comment-body"
13348
13402
  };
13349
- var _hoisted_10$3 = ["data-track-change-semantic-color-key"];
13350
- var _hoisted_11$3 = { key: 0 };
13351
- var _hoisted_12$2 = { class: "change-type tracked-change-label" };
13352
- var _hoisted_13$2 = {
13403
+ var _hoisted_12$2 = ["data-track-change-semantic-color-key"];
13404
+ var _hoisted_13$2 = { key: 0 };
13405
+ var _hoisted_14$2 = { class: "change-type tracked-change-label" };
13406
+ var _hoisted_15$2 = {
13353
13407
  key: 0,
13354
13408
  class: "tracked-change-detail-lines"
13355
13409
  };
13356
- var _hoisted_14$2 = {
13410
+ var _hoisted_16$2 = {
13357
13411
  key: 0,
13358
13412
  class: "tracked-change-text"
13359
13413
  };
13360
- var _hoisted_15$2 = {
13414
+ var _hoisted_17$2 = {
13361
13415
  key: 1,
13362
13416
  class: "change-type"
13363
13417
  };
13364
- var _hoisted_16$2 = { class: "change-type" };
13365
- var _hoisted_17$2 = { key: 1 };
13366
- var _hoisted_18$2 = { class: "tracked-change-text is-inserted" };
13367
- var _hoisted_19$1 = { key: 2 };
13418
+ var _hoisted_18$2 = { class: "change-type" };
13419
+ var _hoisted_19$1 = { key: 1 };
13368
13420
  var _hoisted_20$1 = { class: "tracked-change-text is-inserted" };
13369
- var _hoisted_21$1 = { key: 3 };
13370
- var _hoisted_22$1 = { key: 4 };
13371
- var _hoisted_23$1 = { key: 5 };
13372
- var _hoisted_24 = { key: 6 };
13373
- var _hoisted_25 = { class: "tracked-change-text" };
13374
- var _hoisted_26 = { key: 7 };
13375
- var _hoisted_27 = { class: "tracked-change-text is-deleted" };
13376
- var _hoisted_28 = { class: "tracked-change-text is-inserted" };
13377
- var _hoisted_29 = { key: 8 };
13378
- var _hoisted_30 = { key: 9 };
13379
- var _hoisted_31 = { key: 10 };
13380
- var _hoisted_32 = { class: "tracked-change-text is-deleted" };
13381
- var _hoisted_33 = { key: 11 };
13382
- var _hoisted_34 = { class: "tracked-change-text is-inserted" };
13383
- var _hoisted_35 = ["data-track-change-image-preview-role"];
13384
- var _hoisted_36 = ["src", "alt"];
13385
- var _hoisted_37 = {
13421
+ var _hoisted_21$1 = { key: 2 };
13422
+ var _hoisted_22$1 = { class: "tracked-change-text is-inserted" };
13423
+ var _hoisted_23$1 = { key: 3 };
13424
+ var _hoisted_24 = { key: 4 };
13425
+ var _hoisted_25 = { key: 5 };
13426
+ var _hoisted_26 = { key: 6 };
13427
+ var _hoisted_27 = { class: "tracked-change-text" };
13428
+ var _hoisted_28 = { key: 7 };
13429
+ var _hoisted_29 = { class: "tracked-change-text is-deleted" };
13430
+ var _hoisted_30 = { class: "tracked-change-text is-inserted" };
13431
+ var _hoisted_31 = { key: 8 };
13432
+ var _hoisted_32 = { key: 9 };
13433
+ var _hoisted_33 = { key: 10 };
13434
+ var _hoisted_34 = { class: "tracked-change-text is-deleted" };
13435
+ var _hoisted_35 = { key: 11 };
13436
+ var _hoisted_36 = { class: "tracked-change-text is-inserted" };
13437
+ var _hoisted_37 = ["data-track-change-image-preview-role"];
13438
+ var _hoisted_38 = ["src", "alt"];
13439
+ var _hoisted_39 = {
13386
13440
  key: 1,
13387
13441
  class: "card-section comment-body"
13388
13442
  };
13389
- var _hoisted_38 = ["innerHTML"];
13390
- var _hoisted_39 = {
13443
+ var _hoisted_40 = ["innerHTML"];
13444
+ var _hoisted_41 = {
13391
13445
  key: 1,
13392
13446
  class: "comment"
13393
13447
  };
13394
- var _hoisted_40 = {
13448
+ var _hoisted_42 = {
13395
13449
  key: 2,
13396
13450
  class: "reply-expanded"
13397
13451
  };
13398
- var _hoisted_41 = { class: "reply-input-wrapper" };
13399
- var _hoisted_42 = { class: "reply-actions" };
13400
- var _hoisted_43 = ["onClick"];
13401
- var _hoisted_44 = [
13452
+ var _hoisted_43 = { class: "reply-input-wrapper" };
13453
+ var _hoisted_44 = { class: "reply-actions" };
13454
+ var _hoisted_45 = ["onClick"];
13455
+ var _hoisted_46 = [
13402
13456
  "onClick",
13403
13457
  "disabled",
13404
13458
  "data-disabled-reason"
13405
13459
  ];
13406
- var _hoisted_45 = { class: "collapsed-avatars" };
13407
- var _hoisted_46 = {
13460
+ var _hoisted_47 = { class: "collapsed-avatars" };
13461
+ var _hoisted_48 = {
13408
13462
  key: 3,
13409
13463
  class: "comment-separator"
13410
13464
  };
13411
- var _hoisted_47 = {
13412
- key: 2,
13465
+ var _hoisted_49 = {
13466
+ key: 3,
13413
13467
  class: "tracked-change-decision-alert",
13414
13468
  role: "alert"
13415
13469
  };
13416
- var _hoisted_48 = { class: "tracked-change-decision-alert__message" };
13417
- var _hoisted_49 = ["disabled", "data-disabled-reason"];
13418
- var _hoisted_50 = {
13470
+ var _hoisted_50 = { class: "tracked-change-decision-alert__message" };
13471
+ var _hoisted_51 = ["disabled", "data-disabled-reason"];
13472
+ var _hoisted_52 = {
13419
13473
  key: 1,
13420
13474
  class: "reply-expanded"
13421
13475
  };
13422
- var _hoisted_51 = { class: "reply-input-wrapper" };
13423
- var _hoisted_52 = { class: "reply-actions" };
13424
- var _hoisted_53 = ["disabled", "data-disabled-reason"];
13476
+ var _hoisted_53 = { class: "reply-input-wrapper" };
13477
+ var _hoisted_54 = { class: "reply-actions" };
13478
+ var _hoisted_55 = ["disabled", "data-disabled-reason"];
13425
13479
  var commentEditSessions = /* @__PURE__ */ new WeakMap();
13426
13480
  var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13427
13481
  __name: "CommentDialog",
@@ -13501,6 +13555,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13501
13555
  };
13502
13556
  };
13503
13557
  const CLICK_OUTSIDE_IGNORED_SELECTORS = [
13558
+ ".superdoc__tools [data-id=\"is-tool\"]",
13504
13559
  ".comments-dropdown__option-label",
13505
13560
  ".comments-dropdown__menu",
13506
13561
  ".comments-dropdown__option",
@@ -13674,12 +13729,17 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13674
13729
  const isReplying = ref(false);
13675
13730
  const isSubmittingReply = ref(false);
13676
13731
  const isSubmittingNewComment = ref(false);
13732
+ const commentSaveFailure = ref("");
13733
+ const commentSaveFailureMessage = (outcome, hasDraft = true) => {
13734
+ return `Your comment could not be saved${outcome?.detail === "document-mode-read-only" ? " because the document or connection is read-only" : outcome?.code === "PERMISSION_DENIED" ? " because you do not have permission" : ""}.${hasDraft ? " Your draft is still here. Try again or cancel." : " Try again."}`;
13735
+ };
13677
13736
  const startReply = () => {
13678
13737
  if (commentsAreReadOnly()) return readOnlyMutationOutcome();
13679
13738
  if (isV2WriteDisabled.value) return {
13680
13739
  ok: false,
13681
13740
  reason: v2WriteCapability.value?.reason ?? "v2-write-unavailable"
13682
13741
  };
13742
+ commentSaveFailure.value = "";
13683
13743
  isReplying.value = true;
13684
13744
  nextTick(() => {
13685
13745
  commentInput.value?.focus?.();
@@ -13929,6 +13989,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13929
13989
  reason: "reply-submit-in-flight"
13930
13990
  };
13931
13991
  isSubmittingReply.value = true;
13992
+ commentSaveFailure.value = "";
13932
13993
  try {
13933
13994
  const parentCommentId = getV2ExistingReplyParentId(props.comment);
13934
13995
  const trackedChangeTarget = getV2TrackedChangeCommentTarget(props.comment);
@@ -13940,6 +14001,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13940
14001
  ...trackedChangeTarget ? { trackedChangeTarget } : {}
13941
14002
  });
13942
14003
  if (!outcome?.ok) {
14004
+ commentSaveFailure.value = commentSaveFailureMessage(outcome);
13943
14005
  nextTick(() => emit("resize"));
13944
14006
  return outcome;
13945
14007
  }
@@ -13958,6 +14020,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13958
14020
  reason: "comment-submit-in-flight"
13959
14021
  };
13960
14022
  isSubmittingNewComment.value = true;
14023
+ commentSaveFailure.value = "";
13961
14024
  }
13962
14025
  const options = {
13963
14026
  documentId: props.comment.fileId,
@@ -13973,7 +14036,10 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13973
14036
  Promise.resolve().then(() => addComment({
13974
14037
  superdoc: proxy.$superdoc,
13975
14038
  comment
13976
- })).catch((err) => {
14039
+ })).then((outcome) => {
14040
+ if (isPendingNewComment.value && outcome?.ok === false) commentSaveFailure.value = commentSaveFailureMessage(outcome);
14041
+ }).catch((err) => {
14042
+ commentSaveFailure.value = commentSaveFailureMessage();
13977
14043
  console.error("[SuperDoc] addComment failed", err);
13978
14044
  }).finally(() => {
13979
14045
  isSubmittingNewComment.value = false;
@@ -14011,15 +14077,8 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14011
14077
  const v2WriteCapability = computed$1(() => {
14012
14078
  v2CapabilityRevision.value;
14013
14079
  if (!v2CommentsAdapter.value) return null;
14014
- const documentMode = commentsStore.viewingVisibility.documentMode;
14015
14080
  const command = isPendingNewComment.value ? "comments.createFromSelection" : null;
14016
- const capability = v2CommentsAdapter.value.getCapabilityState?.(command) ?? null;
14017
- if (documentMode === "viewing" && !isPendingNewComment.value) return {
14018
- ...capability ?? {},
14019
- canWrite: false,
14020
- reason: "review-surface-read-only"
14021
- };
14022
- return capability;
14081
+ return v2CommentsAdapter.value.getCapabilityState?.(command) ?? null;
14023
14082
  });
14024
14083
  const isV2WriteDisabled = computed$1(() => {
14025
14084
  if (!isV2Mode.value) return false;
@@ -14205,10 +14264,15 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14205
14264
  });
14206
14265
  v1TrackedChangeDecisionApplied = Boolean(outcome?.ok) && outcome.success !== false;
14207
14266
  } else if (isV2Mode.value && v2CommentsAdapter.value) {
14208
- if (!(await commentsStore.resolveCommentV2({
14267
+ const outcome = await commentsStore.resolveCommentV2({
14209
14268
  superdoc: proxy.$superdoc,
14210
14269
  commentId: props.comment.commentId
14211
- }))?.ok) return;
14270
+ });
14271
+ if (!outcome?.ok) {
14272
+ commentSaveFailure.value = commentSaveFailureMessage(outcome, false);
14273
+ return outcome;
14274
+ }
14275
+ commentSaveFailure.value = "";
14212
14276
  } else props.comment.resolveComment({
14213
14277
  id: superdocStore.user.id,
14214
14278
  email: superdocStore.user.email,
@@ -14237,17 +14301,22 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14237
14301
  reason: "resolve-disabled"
14238
14302
  };
14239
14303
  if (!isV2Mode.value || !v2CommentsAdapter.value) return;
14240
- if (!(await commentsStore.reopenCommentV2({
14304
+ const outcome = await commentsStore.reopenCommentV2({
14241
14305
  superdoc: proxy.$superdoc,
14242
14306
  commentId: props.comment.commentId
14243
- }))?.ok) return;
14307
+ });
14308
+ if (!outcome?.ok) {
14309
+ commentSaveFailure.value = commentSaveFailureMessage(outcome, false);
14310
+ return outcome;
14311
+ }
14312
+ commentSaveFailure.value = "";
14244
14313
  nextTick(() => {
14245
14314
  commentsStore.lastUpdate = /* @__PURE__ */ new Date();
14246
14315
  commentsStore.setActiveComment(proxy.$superdoc, activeComment.value);
14247
14316
  proxy.$superdoc.focus?.();
14248
14317
  });
14249
14318
  };
14250
- const handleOverflowSelect = (value, comment) => {
14319
+ const handleOverflowSelect = async (value, comment) => {
14251
14320
  if (commentsAreReadOnly()) return readOnlyMutationOutcome();
14252
14321
  switch (value) {
14253
14322
  case "edit":
@@ -14266,10 +14335,13 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14266
14335
  });
14267
14336
  break;
14268
14337
  case "delete":
14269
- deleteComment({
14270
- superdoc: proxy.$superdoc,
14271
- commentId: comment.commentId
14272
- });
14338
+ {
14339
+ const outcome = await deleteComment({
14340
+ superdoc: proxy.$superdoc,
14341
+ commentId: comment.commentId
14342
+ });
14343
+ commentSaveFailure.value = outcome?.ok ? "" : commentSaveFailureMessage(outcome, false);
14344
+ }
14273
14345
  break;
14274
14346
  }
14275
14347
  };
@@ -14290,8 +14362,12 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14290
14362
  commentId: comment.commentId,
14291
14363
  text: draft
14292
14364
  });
14293
- if (!outcome?.ok) return outcome;
14294
14365
  if (session?.owner !== editSessionOwner || commentEditSessions.get(commentsStore) !== session || session.submission !== submission || proxy.$superdoc.activeEditor !== editor || editor.v2Comments !== adapter || adapter.documentId !== documentId || editor.doc !== document || props.comment !== thread || editingCommentId.value !== comment.commentId || currentCommentText.value !== draft) return outcome;
14366
+ if (!outcome?.ok) {
14367
+ commentSaveFailure.value = commentSaveFailureMessage(outcome);
14368
+ return outcome;
14369
+ }
14370
+ commentSaveFailure.value = "";
14295
14371
  retireOwnEditSession();
14296
14372
  editingCommentId.value = null;
14297
14373
  removePendingComment(proxy.$superdoc);
@@ -14323,6 +14399,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14323
14399
  return typeof timestamp === "string" ? new Date(timestamp).getTime() : timestamp;
14324
14400
  };
14325
14401
  const handleCancel = (comment) => {
14402
+ commentSaveFailure.value = "";
14326
14403
  retireOwnEditSession();
14327
14404
  editingCommentId.value = null;
14328
14405
  isReplying.value = false;
@@ -14422,26 +14499,28 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14422
14499
  "config",
14423
14500
  "comment"
14424
14501
  ])]),
14425
- createElementVNode("div", _hoisted_4$11, [createElementVNode("button", {
14502
+ commentSaveFailure.value ? (openBlock(), createElementBlock("p", _hoisted_4$11, toDisplayString(commentSaveFailure.value), 1)) : createCommentVNode("", true),
14503
+ createElementVNode("div", _hoisted_5$8, [createElementVNode("button", {
14426
14504
  class: "sd-button reply-btn-cancel",
14427
14505
  onClick: withModifiers(handleCancel, ["stop", "prevent"])
14428
14506
  }, "Cancel"), createElementVNode("button", {
14429
14507
  class: normalizeClass(["sd-button primary reply-btn-primary", { "sd-is-disabled": !hasTextContent.value || isSubmittingNewComment.value }]),
14430
14508
  onClick: withModifiers(handleAddComment, ["stop", "prevent"]),
14431
14509
  disabled: !hasTextContent.value || isSubmittingNewComment.value
14432
- }, " Comment ", 10, _hoisted_5$8)])
14510
+ }, " Comment ", 10, _hoisted_6$6)])
14433
14511
  ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
14434
- resolvedBadgeLabel.value ? (openBlock(), createElementBlock("div", _hoisted_6$6, [createElementVNode("span", {
14512
+ resolvedBadgeLabel.value ? (openBlock(), createElementBlock("div", _hoisted_7$4, [createElementVNode("span", {
14435
14513
  class: "resolved-badge__icon",
14436
14514
  innerHTML: unref(superdocIcons).markDone
14437
- }, null, 8, _hoisted_7$4), createTextVNode(" " + toDisplayString(resolvedBadgeLabel.value), 1)])) : createCommentVNode("", true),
14438
- shouldShowInternalExternal.value ? (openBlock(), createElementBlock("div", _hoisted_8$4, [createVNode(InternalDropdown_default, {
14515
+ }, null, 8, _hoisted_8$4), createTextVNode(" " + toDisplayString(resolvedBadgeLabel.value), 1)])) : createCommentVNode("", true),
14516
+ shouldShowInternalExternal.value ? (openBlock(), createElementBlock("div", _hoisted_9$3, [createVNode(InternalDropdown_default, {
14439
14517
  onClick: _cache[1] || (_cache[1] = withModifiers(() => {}, ["stop", "prevent"])),
14440
14518
  class: "sd-internal-dropdown",
14441
14519
  "is-disabled": isInternalDropdownDisabled.value,
14442
14520
  state: __props.comment.isInternal ? "internal" : "external",
14443
14521
  onSelect: handleInternalExternalSelect
14444
14522
  }, null, 8, ["is-disabled", "state"])])) : createCommentVNode("", true),
14523
+ commentSaveFailure.value ? (openBlock(), createElementBlock("p", _hoisted_10$3, toDisplayString(commentSaveFailure.value), 1)) : createCommentVNode("", true),
14445
14524
  (openBlock(true), createElementBlock(Fragment, null, renderList(visibleComments.value, (comment, index) => {
14446
14525
  return openBlock(), createElementBlock("div", {
14447
14526
  key: comment.commentId,
@@ -14473,27 +14552,27 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14473
14552
  "write-disabled-reason",
14474
14553
  "onOverflowSelect"
14475
14554
  ]),
14476
- comment.trackedChange ? (openBlock(), createElementBlock("div", _hoisted_9$3, [
14555
+ comment.trackedChange ? (openBlock(), createElementBlock("div", _hoisted_11$3, [
14477
14556
  createElementVNode("div", {
14478
14557
  class: normalizeClass(["tracked-change", index === 0 ? bodyOverflowClass.value : void 0]),
14479
14558
  "data-track-change-semantic-color-key": comment.semanticColorKey ?? void 0,
14480
14559
  ref_for: true,
14481
14560
  ref: index === 0 ? setParentBodyRef : void 0
14482
- }, [comment.trackedChangeLabel ? (openBlock(), createElementBlock("div", _hoisted_11$3, [createElementVNode("span", _hoisted_12$2, toDisplayString(comment.trackedChangeLabel), 1), comment.trackedChangeDetailLines && comment.trackedChangeDetailLines.length ? (openBlock(), createElementBlock("div", _hoisted_13$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(comment.trackedChangeDetailLines, (line, lineIndex) => {
14561
+ }, [comment.trackedChangeLabel ? (openBlock(), createElementBlock("div", _hoisted_13$2, [createElementVNode("span", _hoisted_14$2, toDisplayString(comment.trackedChangeLabel), 1), comment.trackedChangeDetailLines && comment.trackedChangeDetailLines.length ? (openBlock(), createElementBlock("div", _hoisted_15$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(comment.trackedChangeDetailLines, (line, lineIndex) => {
14483
14562
  return openBlock(), createElementBlock("div", {
14484
14563
  key: lineIndex,
14485
14564
  class: "tracked-change-detail-line"
14486
14565
  }, [
14487
- line.excerpt ? (openBlock(), createElementBlock("span", _hoisted_14$2, "\"" + toDisplayString(line.excerpt) + "\"", 1)) : createCommentVNode("", true),
14488
- line.excerpt ? (openBlock(), createElementBlock("span", _hoisted_15$2, " — ")) : createCommentVNode("", true),
14489
- createElementVNode("span", _hoisted_16$2, toDisplayString(line.label), 1)
14566
+ line.excerpt ? (openBlock(), createElementBlock("span", _hoisted_16$2, "\"" + toDisplayString(line.excerpt) + "\"", 1)) : createCommentVNode("", true),
14567
+ line.excerpt ? (openBlock(), createElementBlock("span", _hoisted_17$2, " — ")) : createCommentVNode("", true),
14568
+ createElementVNode("span", _hoisted_18$2, toDisplayString(line.label), 1)
14490
14569
  ]);
14491
- }), 128))])) : createCommentVNode("", true)])) : comment.trackedChangeDisplayType === "hyperlinkAdded" ? (openBlock(), createElementBlock("div", _hoisted_17$2, [_cache[2] || (_cache[2] = createElementVNode("span", { class: "change-type" }, "Added hyperlink ", -1)), createElementVNode("span", _hoisted_18$2, "\"" + toDisplayString(comment.trackedChangeText) + "\"", 1)])) : comment.trackedChangeDisplayType === "hyperlinkModified" ? (openBlock(), createElementBlock("div", _hoisted_19$1, [_cache[3] || (_cache[3] = createElementVNode("span", { class: "change-type" }, "Changed hyperlink to ", -1)), createElementVNode("span", _hoisted_20$1, "\"" + toDisplayString(comment.trackedChangeText) + "\"", 1)])) : comment.trackedChangeDisplayType === "paragraphSplit" ? (openBlock(), createElementBlock("div", _hoisted_21$1, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "change-type" }, "Added new line", -1)])])) : comment.trackedChangeDisplayType === "tableInsert" ? (openBlock(), createElementBlock("div", _hoisted_22$1, [..._cache[5] || (_cache[5] = [createElementVNode("span", { class: "change-type" }, "Added table", -1)])])) : comment.trackedChangeDisplayType === "tableDelete" ? (openBlock(), createElementBlock("div", _hoisted_23$1, [..._cache[6] || (_cache[6] = [createElementVNode("span", { class: "change-type" }, "Deleted table", -1)])])) : comment.trackedChangeType === "trackFormat" ? (openBlock(), createElementBlock("div", _hoisted_24, [_cache[7] || (_cache[7] = createElementVNode("span", { class: "change-type" }, "Format: ", -1)), createElementVNode("span", _hoisted_25, toDisplayString(comment.trackedChangeText), 1)])) : comment.trackedChangeType === "both" ? (openBlock(), createElementBlock("div", _hoisted_26, [
14570
+ }), 128))])) : createCommentVNode("", true)])) : comment.trackedChangeDisplayType === "hyperlinkAdded" ? (openBlock(), createElementBlock("div", _hoisted_19$1, [_cache[2] || (_cache[2] = createElementVNode("span", { class: "change-type" }, "Added hyperlink ", -1)), createElementVNode("span", _hoisted_20$1, "\"" + toDisplayString(comment.trackedChangeText) + "\"", 1)])) : comment.trackedChangeDisplayType === "hyperlinkModified" ? (openBlock(), createElementBlock("div", _hoisted_21$1, [_cache[3] || (_cache[3] = createElementVNode("span", { class: "change-type" }, "Changed hyperlink to ", -1)), createElementVNode("span", _hoisted_22$1, "\"" + toDisplayString(comment.trackedChangeText) + "\"", 1)])) : comment.trackedChangeDisplayType === "paragraphSplit" ? (openBlock(), createElementBlock("div", _hoisted_23$1, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "change-type" }, "Added new line", -1)])])) : comment.trackedChangeDisplayType === "tableInsert" ? (openBlock(), createElementBlock("div", _hoisted_24, [..._cache[5] || (_cache[5] = [createElementVNode("span", { class: "change-type" }, "Added table", -1)])])) : comment.trackedChangeDisplayType === "tableDelete" ? (openBlock(), createElementBlock("div", _hoisted_25, [..._cache[6] || (_cache[6] = [createElementVNode("span", { class: "change-type" }, "Deleted table", -1)])])) : comment.trackedChangeType === "trackFormat" ? (openBlock(), createElementBlock("div", _hoisted_26, [_cache[7] || (_cache[7] = createElementVNode("span", { class: "change-type" }, "Format: ", -1)), createElementVNode("span", _hoisted_27, toDisplayString(comment.trackedChangeText), 1)])) : comment.trackedChangeType === "both" ? (openBlock(), createElementBlock("div", _hoisted_28, [
14492
14571
  _cache[8] || (_cache[8] = createElementVNode("span", { class: "change-type" }, "Replaced ", -1)),
14493
- createElementVNode("span", _hoisted_27, "\"" + toDisplayString(comment.deletedText) + "\"", 1),
14572
+ createElementVNode("span", _hoisted_29, "\"" + toDisplayString(comment.deletedText) + "\"", 1),
14494
14573
  _cache[9] || (_cache[9] = createElementVNode("span", { class: "change-type" }, " with ", -1)),
14495
- createElementVNode("span", _hoisted_28, "\"" + toDisplayString(comment.trackedChangeText) + "\"", 1)
14496
- ])) : comment.deletedText && comment.deletedText === "\n" ? (openBlock(), createElementBlock("div", _hoisted_29, [..._cache[10] || (_cache[10] = [createElementVNode("span", { class: "change-type" }, "Deleted line break", -1)])])) : comment.trackedChangeText && comment.trackedChangeText === "\n" ? (openBlock(), createElementBlock("div", _hoisted_30, [..._cache[11] || (_cache[11] = [createElementVNode("span", { class: "change-type" }, "Added line break", -1)])])) : comment.deletedText ? (openBlock(), createElementBlock("div", _hoisted_31, [_cache[12] || (_cache[12] = createElementVNode("span", { class: "change-type" }, "Deleted ", -1)), createElementVNode("span", _hoisted_32, "\"" + toDisplayString(comment.deletedText) + "\"", 1)])) : comment.trackedChangeText ? (openBlock(), createElementBlock("div", _hoisted_33, [_cache[13] || (_cache[13] = createElementVNode("span", { class: "change-type" }, "Added ", -1)), createElementVNode("span", _hoisted_34, "\"" + toDisplayString(comment.trackedChangeText) + "\"", 1)])) : createCommentVNode("", true), comment.trackedChangeImagePreview?.src ? (openBlock(), createElementBlock("div", {
14574
+ createElementVNode("span", _hoisted_30, "\"" + toDisplayString(comment.trackedChangeText) + "\"", 1)
14575
+ ])) : comment.deletedText && comment.deletedText === "\n" ? (openBlock(), createElementBlock("div", _hoisted_31, [..._cache[10] || (_cache[10] = [createElementVNode("span", { class: "change-type" }, "Deleted line break", -1)])])) : comment.trackedChangeText && comment.trackedChangeText === "\n" ? (openBlock(), createElementBlock("div", _hoisted_32, [..._cache[11] || (_cache[11] = [createElementVNode("span", { class: "change-type" }, "Added line break", -1)])])) : comment.deletedText ? (openBlock(), createElementBlock("div", _hoisted_33, [_cache[12] || (_cache[12] = createElementVNode("span", { class: "change-type" }, "Deleted ", -1)), createElementVNode("span", _hoisted_34, "\"" + toDisplayString(comment.deletedText) + "\"", 1)])) : comment.trackedChangeText ? (openBlock(), createElementBlock("div", _hoisted_35, [_cache[13] || (_cache[13] = createElementVNode("span", { class: "change-type" }, "Added ", -1)), createElementVNode("span", _hoisted_36, "\"" + toDisplayString(comment.trackedChangeText) + "\"", 1)])) : createCommentVNode("", true), comment.trackedChangeImagePreview?.src ? (openBlock(), createElementBlock("div", {
14497
14576
  key: 12,
14498
14577
  class: "tracked-change-image-preview",
14499
14578
  "data-track-change-image-preview-role": comment.trackedChangeImagePreview.role ?? void 0
@@ -14504,7 +14583,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14504
14583
  style: normalizeStyle(trackedChangeImagePreviewStyle(comment.trackedChangeImagePreview)),
14505
14584
  loading: "lazy",
14506
14585
  decoding: "async"
14507
- }, null, 12, _hoisted_36)], 8, _hoisted_35)) : createCommentVNode("", true)], 10, _hoisted_10$3),
14586
+ }, null, 12, _hoisted_38)], 8, _hoisted_37)) : createCommentVNode("", true)], 10, _hoisted_12$2),
14508
14587
  shouldTruncate.value && isTextOverflowing.value && index === 0 ? (openBlock(), createElementBlock("div", {
14509
14588
  key: 0,
14510
14589
  class: "show-more-toggle",
@@ -14516,29 +14595,29 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14516
14595
  onClick: withModifiers(toggleTruncation, ["stop", "prevent"])
14517
14596
  }, " Show less ")) : createCommentVNode("", true)
14518
14597
  ])) : createCommentVNode("", true),
14519
- !comment.trackedChange ? (openBlock(), createElementBlock("div", _hoisted_37, [
14598
+ !comment.trackedChange ? (openBlock(), createElementBlock("div", _hoisted_39, [
14520
14599
  !unref(isDebugging) && !isEditingThisComment.value(comment) ? (openBlock(), createElementBlock("div", {
14521
14600
  key: 0,
14522
14601
  class: normalizeClass(["comment", index === 0 ? bodyOverflowClass.value : void 0]),
14523
14602
  ref_for: true,
14524
14603
  ref: index === 0 ? setParentBodyRef : void 0,
14525
14604
  innerHTML: renderedCommentTexts.value.get(comment.commentId)
14526
- }, null, 10, _hoisted_38)) : unref(isDebugging) && !isEditingThisComment.value(comment) ? (openBlock(), createElementBlock("div", _hoisted_39, toDisplayString(unref(editorCommentPositions)[comment.importedId !== void 0 ? comment.importedId : comment.commentId]?.bounds), 1)) : (openBlock(), createElementBlock("div", _hoisted_40, [createElementVNode("div", _hoisted_41, [createVNode(CommentInput_default, {
14605
+ }, null, 10, _hoisted_40)) : unref(isDebugging) && !isEditingThisComment.value(comment) ? (openBlock(), createElementBlock("div", _hoisted_41, toDisplayString(unref(editorCommentPositions)[comment.importedId !== void 0 ? comment.importedId : comment.commentId]?.bounds), 1)) : (openBlock(), createElementBlock("div", _hoisted_42, [createElementVNode("div", _hoisted_43, [createVNode(CommentInput_default, {
14527
14606
  ref_for: true,
14528
14607
  ref: setEditCommentInputRef(comment.commentId),
14529
14608
  users: [],
14530
14609
  config: unref(getConfig),
14531
14610
  "include-header": false,
14532
14611
  comment
14533
- }, null, 8, ["config", "comment"])]), createElementVNode("div", _hoisted_42, [createElementVNode("button", {
14612
+ }, null, 8, ["config", "comment"])]), createElementVNode("div", _hoisted_44, [createElementVNode("button", {
14534
14613
  class: "sd-button reply-btn-cancel",
14535
14614
  onClick: withModifiers(($event) => handleCancel(comment), ["stop", "prevent"])
14536
- }, "Cancel", 8, _hoisted_43), createElementVNode("button", {
14615
+ }, "Cancel", 8, _hoisted_45), createElementVNode("button", {
14537
14616
  class: normalizeClass(["sd-button primary reply-btn-primary", { "sd-is-disabled": !hasTextContent.value || isV2WriteDisabled.value }]),
14538
14617
  onClick: withModifiers(($event) => handleCommentUpdate(comment), ["stop", "prevent"]),
14539
14618
  disabled: !hasTextContent.value || isV2WriteDisabled.value,
14540
14619
  "data-disabled-reason": isV2WriteDisabled.value ? v2WriteCapability.value?.reason ?? null : null
14541
- }, " Update ", 10, _hoisted_44)])])),
14620
+ }, " Update ", 10, _hoisted_46)])])),
14542
14621
  shouldTruncate.value && isTextOverflowing.value && index === 0 && !isEditingThisComment.value(comment) ? (openBlock(), createElementBlock("div", {
14543
14622
  key: 3,
14544
14623
  class: "show-more-toggle",
@@ -14553,29 +14632,29 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14553
14632
  shouldCollapseThread.value && index === 0 ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [_cache[14] || (_cache[14] = createElementVNode("div", { class: "comment-separator" }, null, -1)), createElementVNode("div", {
14554
14633
  class: "collapsed-replies",
14555
14634
  onClick: withModifiers(expandThread, ["stop", "prevent"])
14556
- }, [createElementVNode("div", _hoisted_45, [(openBlock(true), createElementBlock(Fragment, null, renderList(collapsedReplyAuthors.value, (author) => {
14635
+ }, [createElementVNode("div", _hoisted_47, [(openBlock(true), createElementBlock(Fragment, null, renderList(collapsedReplyAuthors.value, (author) => {
14557
14636
  return openBlock(), createBlock(Avatar_default, {
14558
14637
  key: author.email || author.name,
14559
14638
  user: author,
14560
14639
  class: "mini-avatar"
14561
14640
  }, null, 8, ["user"]);
14562
14641
  }), 128))]), createElementVNode("span", null, toDisplayString(collapsedReplyCount.value) + " more " + toDisplayString(collapsedReplyCount.value === 1 ? "reply" : "replies"), 1)])], 64)) : createCommentVNode("", true),
14563
- showSeparator.value(index) ? (openBlock(), createElementBlock("div", _hoisted_46)) : createCommentVNode("", true)
14642
+ showSeparator.value(index) ? (openBlock(), createElementBlock("div", _hoisted_48)) : createCommentVNode("", true)
14564
14643
  ]);
14565
14644
  }), 128)),
14566
- trackedChangeDecisionFailure.value ? (openBlock(), createElementBlock("div", _hoisted_47, [createElementVNode("span", _hoisted_48, toDisplayString(trackedChangeDecisionFailureMessage.value), 1), createElementVNode("button", {
14645
+ trackedChangeDecisionFailure.value ? (openBlock(), createElementBlock("div", _hoisted_49, [createElementVNode("span", _hoisted_50, toDisplayString(trackedChangeDecisionFailureMessage.value), 1), createElementVNode("button", {
14567
14646
  type: "button",
14568
14647
  class: "sd-button tracked-change-decision-alert__retry",
14569
14648
  onClick: withModifiers(retryTrackedChangeDecision, ["stop", "prevent"])
14570
14649
  }, " Retry ")])) : createCommentVNode("", true),
14571
- showInputSection.value && !unref(getConfig).readOnly ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [!isReplying.value ? (openBlock(), createElementBlock("button", {
14650
+ showInputSection.value && !unref(getConfig).readOnly ? (openBlock(), createElementBlock(Fragment, { key: 4 }, [!isReplying.value ? (openBlock(), createElementBlock("button", {
14572
14651
  key: 0,
14573
14652
  type: "button",
14574
14653
  class: normalizeClass(["reply-pill", { "sd-is-disabled": isV2WriteDisabled.value }]),
14575
14654
  onClick: withModifiers(startReply, ["stop", "prevent"]),
14576
14655
  disabled: isV2WriteDisabled.value,
14577
14656
  "data-disabled-reason": isV2WriteDisabled.value ? v2WriteCapability.value?.reason ?? null : null
14578
- }, " Reply or add others with @ ", 10, _hoisted_49)) : (openBlock(), createElementBlock("div", _hoisted_50, [createElementVNode("div", _hoisted_51, [createVNode(CommentInput_default, {
14657
+ }, " Reply or add others with @ ", 10, _hoisted_51)) : (openBlock(), createElementBlock("div", _hoisted_52, [createElementVNode("div", _hoisted_53, [createVNode(CommentInput_default, {
14579
14658
  ref_key: "commentInput",
14580
14659
  ref: commentInput,
14581
14660
  users: usersFiltered.value,
@@ -14586,7 +14665,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14586
14665
  "users",
14587
14666
  "config",
14588
14667
  "comment"
14589
- ])]), createElementVNode("div", _hoisted_52, [createElementVNode("button", {
14668
+ ])]), createElementVNode("div", _hoisted_54, [createElementVNode("button", {
14590
14669
  class: "sd-button reply-btn-cancel",
14591
14670
  onClick: withModifiers(handleCancel, ["stop", "prevent"])
14592
14671
  }, "Cancel"), createElementVNode("button", {
@@ -14594,11 +14673,11 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14594
14673
  onClick: withModifiers(handleAddComment, ["stop", "prevent"]),
14595
14674
  disabled: !hasTextContent.value || isV2WriteDisabled.value || isSubmittingReply.value,
14596
14675
  "data-disabled-reason": v2ReplyDisabledReason.value
14597
- }, " Reply ", 10, _hoisted_53)])]))], 64)) : createCommentVNode("", true)
14676
+ }, " Reply ", 10, _hoisted_55)])]))], 64)) : createCommentVNode("", true)
14598
14677
  ], 64))], 14, _hoisted_1$26)), [[_directive_click_outside, handleClickOutside]]);
14599
14678
  };
14600
14679
  }
14601
- }, [["__scopeId", "data-v-f5016db4"]]);
14680
+ }, [["__scopeId", "data-v-f8b79c74"]]);
14602
14681
  //#endregion
14603
14682
  //#region src/components/CommentsLayer/commentsList/ReviewDirectoryListItem.vue
14604
14683
  var _hoisted_1$25 = [
@@ -15321,6 +15400,80 @@ var composeAuthorColorResolver = (config) => {
15321
15400
  };
15322
15401
  };
15323
15402
  //#endregion
15403
+ //#region ../document-api/src/errors.ts
15404
+ /**
15405
+ * Structured validation error thrown by document-api execute* functions.
15406
+ *
15407
+ * Consumers should prefer checking `error.code` over `instanceof` for resilience
15408
+ * across package boundaries and bundling scenarios.
15409
+ */
15410
+ var DocumentApiValidationError = class DocumentApiValidationError extends Error {
15411
+ constructor(code, message, details) {
15412
+ super(message);
15413
+ this.name = "DocumentApiValidationError";
15414
+ this.code = code;
15415
+ this.details = details;
15416
+ Object.setPrototypeOf(this, DocumentApiValidationError.prototype);
15417
+ }
15418
+ };
15419
+ //#endregion
15420
+ //#region ../document-api/src/export/export.types.ts
15421
+ /** Canonical tracked-change export modes accepted by every public export surface. */
15422
+ var SD_EXPORT_MODES = [
15423
+ "review-preserving",
15424
+ "final",
15425
+ "original"
15426
+ ];
15427
+ /** Default mode for modeful DOCX export. */
15428
+ var DEFAULT_SD_EXPORT_MODE = "review-preserving";
15429
+ var SD_COMMENT_EXPORT_POLICIES = [
15430
+ "preserve",
15431
+ "resolve",
15432
+ "remove"
15433
+ ];
15434
+ var SD_CONTENT_CONTROL_EXPORT_POLICIES = ["preserve", "flatten"];
15435
+ //#endregion
15436
+ //#region ../document-api/src/export/export.ts
15437
+ /**
15438
+ * Export namespace: engine-agnostic public API and adapter contract.
15439
+ *
15440
+ * Validates the requested mode at the public boundary so an invalid mode fails
15441
+ * closed with `INVALID_INPUT` before any document work happens, then delegates
15442
+ * byte production and degradation reporting to the engine adapter.
15443
+ */
15444
+ function resolveMode$1(input) {
15445
+ if (input != null && !isRecord(input)) throw new DocumentApiValidationError("INVALID_INPUT", "export.toDocx input must be an object.");
15446
+ const raw = input?.mode;
15447
+ if (raw === void 0) return DEFAULT_SD_EXPORT_MODE;
15448
+ if (typeof raw !== "string" || !SD_EXPORT_MODES.includes(raw)) throw new DocumentApiValidationError("INVALID_INPUT", `export.toDocx mode must be one of: ${SD_EXPORT_MODES.join(", ")}.`, {
15449
+ mode: raw,
15450
+ allowedModes: [...SD_EXPORT_MODES]
15451
+ });
15452
+ return raw;
15453
+ }
15454
+ function resolveDocxExportPolicies(input = {}) {
15455
+ if (!isRecord(input)) throw new DocumentApiValidationError("INVALID_INPUT", "DOCX export input must be an object.");
15456
+ const mode = resolveMode$1(input);
15457
+ const policies = input.policies;
15458
+ if (policies !== void 0 && !isRecord(policies)) throw new DocumentApiValidationError("INVALID_INPUT", "DOCX export policies must be an object.");
15459
+ const allowed = {
15460
+ trackedChanges: SD_EXPORT_MODES,
15461
+ comments: SD_COMMENT_EXPORT_POLICIES,
15462
+ contentControls: SD_CONTENT_CONTROL_EXPORT_POLICIES
15463
+ };
15464
+ for (const [key, value] of Object.entries(policies ?? {})) if (!Object.prototype.hasOwnProperty.call(allowed, key) || value !== void 0 && !allowed[key].includes(value)) throw new DocumentApiValidationError("INVALID_INPUT", `Unsupported DOCX export policy: ${key}.`, {
15465
+ policy: key,
15466
+ value
15467
+ });
15468
+ const requested = policies;
15469
+ if (input.mode !== void 0 && requested?.trackedChanges !== void 0 && mode !== requested.trackedChanges) throw new DocumentApiValidationError("INVALID_INPUT", "mode conflicts with policies.trackedChanges.");
15470
+ return {
15471
+ trackedChanges: requested?.trackedChanges ?? mode,
15472
+ comments: requested?.comments ?? "preserve",
15473
+ contentControls: requested?.contentControls ?? "preserve"
15474
+ };
15475
+ }
15476
+ //#endregion
15324
15477
  //#region ../document-api/src/permission-ranges/permission-ranges.ts
15325
15478
  function editorKey(editor) {
15326
15479
  return editor.id?.trim() ? editor.id : editor.email?.trim() || void 0;
@@ -20058,6 +20211,28 @@ function useLinkPopover({ getSurfaceManager, getActiveEditor, getUi, getActivati
20058
20211
  };
20059
20212
  }
20060
20213
  //#endregion
20214
+ //#region src/core/helpers/resolve-docx-export.ts
20215
+ function resolveV2DocxExportOptions(options = {}) {
20216
+ const policies = resolveDocxExportPolicies({ policies: options.policies });
20217
+ if (options.isFinalDoc !== void 0) {
20218
+ if (typeof options.isFinalDoc !== "boolean") throw new DocumentApiValidationError("INVALID_INPUT", "isFinalDoc must be a boolean.");
20219
+ const legacy = options.isFinalDoc ? "final" : "review-preserving";
20220
+ if (options.policies?.trackedChanges !== void 0 && policies.trackedChanges !== legacy) throw new DocumentApiValidationError("INVALID_INPUT", "isFinalDoc conflicts with policies.trackedChanges.");
20221
+ policies.trackedChanges = legacy;
20222
+ }
20223
+ if (options.commentsType !== void 0) {
20224
+ if (options.commentsType !== "external" && options.commentsType !== "clean") throw new DocumentApiValidationError("INVALID_INPUT", "commentsType must be external or clean.");
20225
+ const legacy = options.commentsType === "clean" ? "remove" : "preserve";
20226
+ if (options.policies?.comments !== void 0 && policies.comments !== legacy) throw new DocumentApiValidationError("INVALID_INPUT", "commentsType conflicts with policies.comments.");
20227
+ policies.comments = legacy;
20228
+ }
20229
+ return {
20230
+ mode: policies.trackedChanges,
20231
+ commentExportMode: policies.comments === "remove" ? "strip" : policies.comments,
20232
+ contentControlExportMode: policies.contentControls
20233
+ };
20234
+ }
20235
+ //#endregion
20061
20236
  //#region src/core/editor-runtime/v2/v2-editor-runtime-adapter.ts
20062
20237
  var DEFAULT_V2_LEGACY_PROJECTION = Object.freeze({
20063
20238
  editorVersion: 2,
@@ -20697,7 +20872,7 @@ function createV2EditorRuntimeAdapter(options) {
20697
20872
  save: () => host.save(),
20698
20873
  exportDocx: (options) => host.save({
20699
20874
  format: "docx",
20700
- commentExportMode: options?.commentsType === "clean" ? "strip" : "preserve"
20875
+ ...resolveV2DocxExportOptions(options)
20701
20876
  }),
20702
20877
  async setZoom(percent) {
20703
20878
  const result = host.setZoom(percent);
@@ -21944,7 +22119,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21944
22119
  const { proxy } = getCurrentInstance();
21945
22120
  commentsStore.proxy = proxy;
21946
22121
  const documentOpenTelemetry = createDocumentOpenTelemetry(proxy.$superdoc.config);
21947
- const resolvedEditorIntegration = resolveV2Integration(proxy.$superdoc.config);
22122
+ const resolvedEditorIntegration = createDefaultV2Integration();
21948
22123
  const V2DocumentEditor = markRaw(resolvedEditorIntegration.EditorComponent);
21949
22124
  const V2Ruler = resolvedEditorIntegration.RulerComponent ? markRaw(resolvedEditorIntegration.RulerComponent) : null;
21950
22125
  const floatingComments = computed$1(() => {
@@ -22090,6 +22265,10 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22090
22265
  return layers.value.getBoundingClientRect().top + top * zoom;
22091
22266
  };
22092
22267
  const handleCommentToolClick = async () => {
22268
+ if (isV2Mode.value) {
22269
+ cancelScheduledV2DomSelectionSync();
22270
+ if (applyCurrentV2DomSelection()?.ok === false) return;
22271
+ }
22093
22272
  if ((await showAddComment(proxy.$superdoc, getPendingCommentTargetClientY()))?.ok === false) return;
22094
22273
  if (!isV2Mode.value) return;
22095
22274
  const pendingPosition = buildV2PendingPositionEntry();
@@ -22362,10 +22541,9 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22362
22541
  return host.save(saveOptions);
22363
22542
  });
22364
22543
  const exportV2Docx = async (options = {}) => {
22365
- const commentExportMode = options?.commentsType === "clean" ? "strip" : "preserve";
22366
22544
  const bytes = await saveV2Bytes({
22367
22545
  format: "docx",
22368
- commentExportMode
22546
+ ...resolveV2DocxExportOptions(options)
22369
22547
  });
22370
22548
  return new Blob([bytes], { type: DOCX });
22371
22549
  };
@@ -22640,6 +22818,9 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22640
22818
  subscribe: (listener) => v2ReviewWindowController.subscribe?.(listener) ?? (() => void 0)
22641
22819
  },
22642
22820
  extensions: createV2ExtensionsFacet(host),
22821
+ get visuals() {
22822
+ return typeof host?.getHostVisuals === "function" ? host.getHostVisuals() : null;
22823
+ },
22643
22824
  fonts: fonts ?? host?.getFontRuntime?.() ?? null,
22644
22825
  /**
22645
22826
  * The v2 active-editor facade explicitly does NOT carry v1 commands /
@@ -22805,7 +22986,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
22805
22986
  const result = handles?.selection?.applyDomSelection?.(selection);
22806
22987
  if (!result?.ok || result.mode !== "range") {
22807
22988
  clearV2SelectionToolbarState();
22808
- return;
22989
+ return { ok: false };
22809
22990
  }
22810
22991
  v2DomMirroredRange.value = true;
22811
22992
  v2HasRangeSelection.value = true;
@@ -23267,7 +23448,8 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
23267
23448
  return;
23268
23449
  }
23269
23450
  const collaborationException = createCollaborationException(reason, documentId);
23270
- const message = collaborationException?.error.message ?? getV2EditorFailureMessage(reason);
23451
+ const baseMessage = collaborationException?.error.message ?? getV2EditorFailureMessage(reason);
23452
+ const message = reason === "collaboration-config-invalid" && detail ? `${baseMessage} ${detail}` : baseMessage;
23271
23453
  const workerFailure = payload?.workerFailure && typeof payload.workerFailure === "object" ? payload.workerFailure : null;
23272
23454
  setV2EditorFailure(documentId, {
23273
23455
  reason,
@@ -23283,7 +23465,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
23283
23465
  };
23284
23466
  if (reason === "collaboration-v1-config-unsupported" || reason === "collaboration-room-format-unsupported" || reason === "collaboration-room-format-conflict" || reason === "collaboration-room-corrupt" || reason === "collaboration-v2-room-missing" || reason === "collaboration-v2-room-already-exists" || reason === "collaboration-v2-room-initializing" || reason === "collaboration-v2-room-bootstrap-stalled" || reason === "collaboration-open-intent-invalid" || reason === "collaboration-config-invalid") console.warn(`[SuperDoc] ${message}`, logContext);
23285
23467
  else console.error(`[SuperDoc] ${message}`, logContext);
23286
- proxy.$superdoc.emit("exception", collaborationException ?? {
23468
+ proxy.$superdoc.emit("exception", collaborationException && reason !== "collaboration-config-invalid" ? collaborationException : {
23287
23469
  error: new Error(message),
23288
23470
  code: reason,
23289
23471
  ...documentId ? { documentId } : {},
@@ -23457,6 +23639,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
23457
23639
  emitCommentPositionsInViewing: isViewingMode() && shouldRenderCommentsInViewing.value,
23458
23640
  enableCommentsInViewing: isViewingCommentsVisible.value,
23459
23641
  contentControlsChrome: proxy.$superdoc.uiConfig.contentControls.options.chrome,
23642
+ commentHighlights: proxy.$superdoc.uiConfig.comments.highlights,
23460
23643
  resolveTrackedChangeColor: composeAuthorColorResolver(proxy.$superdoc.config.modules?.trackChanges?.authorColors)
23461
23644
  } : void 0,
23462
23645
  permissionResolver: createTrackedChangePermissionResolver(proxy.$superdoc)
@@ -24511,7 +24694,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
24511
24694
  ], 46, _hoisted_1$17);
24512
24695
  };
24513
24696
  }
24514
- }, [["__scopeId", "data-v-143de6c8"]]);
24697
+ }, [["__scopeId", "data-v-f2db957f"]]);
24515
24698
  //#endregion
24516
24699
  //#region src/core/create-app.js
24517
24700
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -37973,6 +38156,11 @@ var COMMENT_POLICY_FIELDS = Object.freeze([
37973
38156
  "allowResolve",
37974
38157
  "permissionResolver"
37975
38158
  ]);
38159
+ function withoutSwitches(options) {
38160
+ if (!("panel" in options) && !("highlights" in options)) return options;
38161
+ const { panel: _panel, highlights: _highlights, ...rest } = options;
38162
+ return rest;
38163
+ }
37976
38164
  /**
37977
38165
  * Drop policy fields from a presentation options bag.
37978
38166
  */
@@ -38317,8 +38505,9 @@ function normalizeUiConfig(config = {}) {
38317
38505
  }
38318
38506
  },
38319
38507
  comments: {
38320
- enabled: explicit("comments") ?? (!allDisabled && config.modules?.comments !== false),
38321
- options: allDisabled ? {} : normalizeCommentsUiConfig(withoutCommentPolicy(options("comments"))) || {}
38508
+ enabled: (explicit("comments") ?? (!allDisabled && config.modules?.comments !== false)) && options("comments").panel !== false,
38509
+ highlights: options("comments").highlights !== false,
38510
+ options: allDisabled ? {} : normalizeCommentsUiConfig(withoutCommentPolicy(withoutSwitches(options("comments")))) || {}
38322
38511
  },
38323
38512
  contextMenu: {
38324
38513
  enabled: explicit("contextMenu") ?? (!allDisabled && config.disableContextMenu !== true),
@@ -41442,9 +41631,6 @@ var TABLE_ACTION_COMMAND_MAP = {
41442
41631
  fixTables: "table-fix"
41443
41632
  };
41444
41633
  var TABLE_ACTION_COMMAND_IDS = Object.values(TABLE_ACTION_COMMAND_MAP);
41445
- [.../* @__PURE__ */ new Set([...Object.values(HEADLESS_ITEM_MAP), ...TABLE_ACTION_COMMAND_IDS])];
41446
- var NON_HEADLESS_EXECUTE_ITEM_NAMES = /* @__PURE__ */ new Set(["link"]);
41447
- new Set(Object.keys(HEADLESS_ITEM_MAP).filter((itemName) => !NON_HEADLESS_EXECUTE_ITEM_NAMES.has(itemName)));
41448
41634
  //#endregion
41449
41635
  //#region src/internal/toolbar/built-in/Toolbar.vue
41450
41636
  var _hoisted_1$10 = ["data-superdoc-ui-owner"];
@@ -46208,7 +46394,7 @@ var SuperDoc = class extends import_eventemitter3.default {
46208
46394
  }
46209
46395
  this.userColorMap = /* @__PURE__ */ new Map();
46210
46396
  this.colorIndex = 0;
46211
- this.version = "2.28.0-next.1";
46397
+ this.version = "2.28.0-next.10";
46212
46398
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
46213
46399
  this.superdocId = config.superdocId || v4();
46214
46400
  this.colors = this.config.colors ?? [];
@@ -46924,7 +47110,8 @@ var SuperDoc = class extends import_eventemitter3.default {
46924
47110
  ...syncTimeoutOption,
46925
47111
  ...target.serverUrl ? { serverUrl: target.serverUrl } : {},
46926
47112
  ...target.params ? { params: target.params } : {},
46927
- ...target.token ? { token: target.token } : {}
47113
+ ...target.token ? { token: target.token } : {},
47114
+ ...target.retry !== void 0 ? { retry: target.retry } : {}
46928
47115
  };
46929
47116
  return {
46930
47117
  providerType: "y-websocket",
@@ -48161,12 +48348,13 @@ var SuperDoc = class extends import_eventemitter3.default {
48161
48348
  * Export the superdoc to a file
48162
48349
  * @param params - Export configuration
48163
48350
  */
48164
- async export({ exportType = ["docx"], commentsType = "external", exportedName, additionalFiles = [], additionalFileNames = [], isFinalDoc = false, triggerDownload = true, fieldsHighlightColor = null } = {}) {
48351
+ async export({ exportType = ["docx"], commentsType, exportedName, additionalFiles = [], additionalFileNames = [], isFinalDoc, policies, triggerDownload = true, fieldsHighlightColor = null } = {}) {
48165
48352
  if (!Array.isArray(exportType) || exportType.length !== 1 || exportType[0] !== "docx") throw new TypeError("SuperDoc.export() only supports exportType: [\"docx\"].");
48166
48353
  const baseFileName = exportedName ? cleanName(exportedName) : cleanName(this.config.title);
48167
48354
  const docxFiles = await this.exportEditorsToDOCX({
48168
48355
  commentsType,
48169
48356
  isFinalDoc,
48357
+ policies,
48170
48358
  fieldsHighlightColor
48171
48359
  });
48172
48360
  const blobsToZip = [...additionalFiles];
@@ -48252,7 +48440,12 @@ var SuperDoc = class extends import_eventemitter3.default {
48252
48440
  * Export editors to DOCX format.
48253
48441
  * @param [options]
48254
48442
  */
48255
- async exportEditorsToDOCX({ commentsType, isFinalDoc, fieldsHighlightColor } = {}) {
48443
+ async exportEditorsToDOCX({ commentsType, isFinalDoc, policies, fieldsHighlightColor } = {}) {
48444
+ if (policies !== void 0) resolveV2DocxExportOptions({
48445
+ policies,
48446
+ commentsType,
48447
+ isFinalDoc
48448
+ });
48256
48449
  const uiStoreHydrated = this.config?.modules?.comments !== false;
48257
48450
  let legacyComments;
48258
48451
  let legacyCommentsComputed = false;
@@ -48272,7 +48465,13 @@ var SuperDoc = class extends import_eventemitter3.default {
48272
48465
  };
48273
48466
  this.on("exception", rememberBridgedExportError);
48274
48467
  try {
48275
- const docxPromises = this.#requireSuperdocStore("exportEditorsToDOCX").documents.map(async (doc) => {
48468
+ const documents = this.#requireSuperdocStore("exportEditorsToDOCX").documents;
48469
+ if (policies !== void 0 && documents.some((doc) => {
48470
+ if (doc.type !== "application/vnd.openxmlformats-officedocument.wordprocessingml.document") return false;
48471
+ const editor = doc.getEditor?.();
48472
+ return editor?.editorVersion !== 2 || typeof editor.exportDocx !== "function";
48473
+ })) throw new Error("Independent DOCX export policies require a mounted V2 exporter for every document.");
48474
+ const docxPromises = documents.map(async (doc) => {
48276
48475
  if (!doc || doc.type !== "application/vnd.openxmlformats-officedocument.wordprocessingml.document") return null;
48277
48476
  const editor = typeof doc.getEditor === "function" ? doc.getEditor() : null;
48278
48477
  const fallbackDocx = () => {
@@ -48289,6 +48488,7 @@ var SuperDoc = class extends import_eventemitter3.default {
48289
48488
  const exported = await editor.exportDocx(isV2Editor ? {
48290
48489
  isFinalDoc,
48291
48490
  commentsType,
48491
+ policies,
48292
48492
  fieldsHighlightColor
48293
48493
  } : {
48294
48494
  isFinalDoc,
@@ -48617,4 +48817,8 @@ function defineSuperDocExtension(extension) {
48617
48817
  return extension;
48618
48818
  }
48619
48819
  //#endregion
48620
- export { blank_default as BlankDOCX, DOCX, DocumentLoadError, HTML, PDF, SuperDoc, buildTheme, compareVersions, createTheme, defineSuperDocExtension, getFileObject, listPermissionRangeEditors, resolvePermissionRangeEditor };
48820
+ //#region src/public/index.ts
48821
+ /** URL to the blank DOCX template. */
48822
+ var BlankDOCX = blank_default;
48823
+ //#endregion
48824
+ export { BlankDOCX, DOCX, DocumentLoadError, HTML, PDF, SuperDoc, buildTheme, compareVersions, createTheme, defineSuperDocExtension, getFileObject, listPermissionRangeEditors, resolvePermissionRangeEditor };