superdoc 2.27.0 → 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 (149) hide show
  1. package/dist/chunks/{create-super-doc-ui-DpVh2nQH.cjs → create-super-doc-ui-B4c55pFy.cjs} +575 -86
  2. package/dist/chunks/{create-super-doc-ui-cHUUipYM.es.js → create-super-doc-ui-C4Ka5Ph3.es.js} +570 -87
  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 +46 -46
  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 +5 -4
  14. package/dist/document-api/src/replace/replace.d.ts +4 -1
  15. package/dist/document-api/src/styles/apply.d.ts +26 -2
  16. package/dist/document-api/src/styles/index.d.ts +3 -3
  17. package/dist/document-api/src/styles/schema.d.ts +3 -1
  18. package/dist/document-api/src/styles/validation.d.ts +10 -9
  19. package/dist/document-api/src/types/mutation-plan.types.d.ts +13 -4
  20. package/dist/document-api/src/types/temporary-mutation.d.ts +5 -1
  21. package/dist/document-api/src/types/track-changes.types.d.ts +10 -2
  22. package/dist/layout-engine/contracts/src/index.d.ts +3 -1
  23. package/dist/layout-engine/contracts/src/resolved-layout.d.ts +1 -0
  24. package/dist/layout-engine/contracts/src/run-helpers.d.ts +7 -0
  25. package/dist/layout-engine/painters/dom/src/page-content.d.ts +1 -0
  26. package/dist/layout-engine/painters/dom/src/review-markers.d.ts +3 -0
  27. package/dist/layout-engine/painters/dom/src/table/renderTableCell.d.ts +1 -0
  28. package/dist/public/ui-react.cjs +1 -1
  29. package/dist/public/ui-react.es.js +1 -1
  30. package/dist/public/ui-vue.cjs +1 -1
  31. package/dist/public/ui-vue.es.js +1 -1
  32. package/dist/public/ui.cjs +1 -1
  33. package/dist/public/ui.es.js +1 -1
  34. package/dist/shared/common/list-marker-utils.d.ts +3 -0
  35. package/dist/style.css +1 -1
  36. package/dist/style.layered.css +1 -1
  37. package/dist/superdoc/src/core/SuperDoc.d.ts +2 -6
  38. package/dist/superdoc/src/core/collaboration/resolve-v2-collaboration-target.d.ts +2 -0
  39. package/dist/superdoc/src/core/config/normalize-ui-config.d.ts +1 -0
  40. package/dist/superdoc/src/core/editor-runtime/types.d.ts +1 -0
  41. package/dist/superdoc/src/core/editor-runtime/v2/v2-editor-runtime-adapter.d.ts +2 -2
  42. package/dist/superdoc/src/core/extensions/types.d.ts +14 -3
  43. package/dist/superdoc/src/core/helpers/resolve-docx-export.d.ts +6 -0
  44. package/dist/superdoc/src/core/types/index.d.ts +35 -1
  45. package/dist/superdoc/src/core/v2-integration/v2-integration.d.ts +0 -8
  46. package/dist/superdoc/src/internal/toolbar/built-in/LinkedStyle.vue.d.ts +3 -1
  47. package/dist/superdoc/src/internal/toolbar/built-in/color-dropdown-helpers.d.ts +0 -1
  48. package/dist/superdoc/src/internal/toolbar/built-in/constants.d.ts +0 -2
  49. package/dist/superdoc/src/internal/toolbar/built-in/toolbarTexts.d.ts +1 -0
  50. package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +1 -0
  51. package/dist/superdoc/src/public/export-types.d.ts +3 -0
  52. package/dist/superdoc/src/public/ui/entity-at.d.ts +1 -0
  53. package/dist/superdoc/src/public/ui/format-painter-helpers.d.ts +0 -13
  54. package/dist/superdoc/src/public/ui/style-match-patch.d.ts +7 -0
  55. package/dist/superdoc/src/public/ui/types.d.ts +20 -2
  56. package/dist/superdoc/src/public/ui.d.cts +18 -0
  57. package/dist/superdoc/src/public/ui.d.ts +1 -1
  58. package/dist/superdoc/src/stores/comments-store.d.ts +3 -57
  59. package/dist/superdoc/src/stores/superdoc-store.d.ts +9 -171
  60. package/dist/superdoc.cjs +476 -216
  61. package/dist/superdoc.es.js +473 -215
  62. package/dist/word-layout/src/types.d.ts +1 -0
  63. package/dist-cdn/style.layered.css +1 -1
  64. package/dist-cdn/superdoc.min.css +1 -1
  65. package/dist-cdn/superdoc.min.js +42 -42
  66. package/package.json +2 -2
  67. package/dist/footnote-table-order.docx +0 -0
  68. package/dist/images/altText_add.svg +0 -3
  69. package/dist/images/altText_disclaimer.svg +0 -3
  70. package/dist/images/altText_done.svg +0 -3
  71. package/dist/images/altText_spinner.svg +0 -30
  72. package/dist/images/altText_warning.svg +0 -3
  73. package/dist/images/annotation-check.svg +0 -11
  74. package/dist/images/annotation-comment.svg +0 -16
  75. package/dist/images/annotation-help.svg +0 -26
  76. package/dist/images/annotation-insert.svg +0 -10
  77. package/dist/images/annotation-key.svg +0 -11
  78. package/dist/images/annotation-newparagraph.svg +0 -11
  79. package/dist/images/annotation-noicon.svg +0 -7
  80. package/dist/images/annotation-note.svg +0 -42
  81. package/dist/images/annotation-paperclip.svg +0 -6
  82. package/dist/images/annotation-paragraph.svg +0 -16
  83. package/dist/images/annotation-pushpin.svg +0 -7
  84. package/dist/images/checkmark.svg +0 -5
  85. package/dist/images/comment-actionsButton.svg +0 -3
  86. package/dist/images/comment-closeButton.svg +0 -3
  87. package/dist/images/comment-editButton.svg +0 -8
  88. package/dist/images/comment-popup-editButton.svg +0 -5
  89. package/dist/images/cursor-editorFreeHighlight.svg +0 -6
  90. package/dist/images/cursor-editorFreeText.svg +0 -3
  91. package/dist/images/cursor-editorInk.svg +0 -4
  92. package/dist/images/cursor-editorTextHighlight.svg +0 -8
  93. package/dist/images/editor-toolbar-delete.svg +0 -5
  94. package/dist/images/editor-toolbar-edit.svg +0 -3
  95. package/dist/images/findbarButton-next.svg +0 -3
  96. package/dist/images/findbarButton-previous.svg +0 -3
  97. package/dist/images/gv-toolbarButton-download.svg +0 -3
  98. package/dist/images/loading-icon.gif +0 -0
  99. package/dist/images/loading.svg +0 -1
  100. package/dist/images/messageBar_closingButton.svg +0 -3
  101. package/dist/images/messageBar_info.svg +0 -3
  102. package/dist/images/messageBar_warning.svg +0 -3
  103. package/dist/images/pages_closeButton.svg +0 -3
  104. package/dist/images/pages_selected.svg +0 -7
  105. package/dist/images/pages_viewArrow.svg +0 -3
  106. package/dist/images/pages_viewButton.svg +0 -3
  107. package/dist/images/secondaryToolbarButton-documentProperties.svg +0 -3
  108. package/dist/images/secondaryToolbarButton-firstPage.svg +0 -3
  109. package/dist/images/secondaryToolbarButton-handTool.svg +0 -3
  110. package/dist/images/secondaryToolbarButton-lastPage.svg +0 -3
  111. package/dist/images/secondaryToolbarButton-rotateCcw.svg +0 -3
  112. package/dist/images/secondaryToolbarButton-rotateCw.svg +0 -3
  113. package/dist/images/secondaryToolbarButton-scrollHorizontal.svg +0 -3
  114. package/dist/images/secondaryToolbarButton-scrollPage.svg +0 -3
  115. package/dist/images/secondaryToolbarButton-scrollVertical.svg +0 -3
  116. package/dist/images/secondaryToolbarButton-scrollWrapped.svg +0 -3
  117. package/dist/images/secondaryToolbarButton-selectTool.svg +0 -3
  118. package/dist/images/secondaryToolbarButton-spreadEven.svg +0 -3
  119. package/dist/images/secondaryToolbarButton-spreadNone.svg +0 -3
  120. package/dist/images/secondaryToolbarButton-spreadOdd.svg +0 -3
  121. package/dist/images/toolbarButton-bookmark.svg +0 -3
  122. package/dist/images/toolbarButton-currentOutlineItem.svg +0 -3
  123. package/dist/images/toolbarButton-download.svg +0 -4
  124. package/dist/images/toolbarButton-editorFreeText.svg +0 -5
  125. package/dist/images/toolbarButton-editorHighlight.svg +0 -6
  126. package/dist/images/toolbarButton-editorInk.svg +0 -4
  127. package/dist/images/toolbarButton-editorSignature.svg +0 -6
  128. package/dist/images/toolbarButton-editorStamp.svg +0 -8
  129. package/dist/images/toolbarButton-menuArrow.svg +0 -3
  130. package/dist/images/toolbarButton-openFile.svg +0 -3
  131. package/dist/images/toolbarButton-pageDown.svg +0 -3
  132. package/dist/images/toolbarButton-pageUp.svg +0 -3
  133. package/dist/images/toolbarButton-presentationMode.svg +0 -3
  134. package/dist/images/toolbarButton-print.svg +0 -3
  135. package/dist/images/toolbarButton-search.svg +0 -3
  136. package/dist/images/toolbarButton-secondaryToolbarToggle.svg +0 -3
  137. package/dist/images/toolbarButton-viewAttachments.svg +0 -3
  138. package/dist/images/toolbarButton-viewLayers.svg +0 -3
  139. package/dist/images/toolbarButton-viewOutline.svg +0 -3
  140. package/dist/images/toolbarButton-viewThumbnail.svg +0 -3
  141. package/dist/images/toolbarButton-viewsManagerToggle.svg +0 -3
  142. package/dist/images/toolbarButton-zoomIn.svg +0 -3
  143. package/dist/images/toolbarButton-zoomOut.svg +0 -3
  144. package/dist/images/treeitem-collapsed.svg +0 -1
  145. package/dist/images/treeitem-expanded.svg +0 -1
  146. package/dist/superdoc/src/helpers/floor.d.ts +0 -1
  147. package/dist/superdoc/src/index.d.cts +0 -18
  148. package/dist/superdoc/src/index.d.ts +0 -14
  149. 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-cHUUipYM.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.27.0";
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;
@@ -12253,11 +12297,11 @@ function useUiFontFamily() {
12253
12297
  //#region src/components/CommentsLayer/CommentsDropdown.vue
12254
12298
  var _hoisted_1$31 = { class: "comments-dropdown" };
12255
12299
  var _hoisted_2$24 = ["onClick"];
12256
- var _hoisted_3$20 = {
12300
+ var _hoisted_3$21 = {
12257
12301
  key: 0,
12258
12302
  class: "comments-dropdown__option-icon"
12259
12303
  };
12260
- var _hoisted_4$14 = ["innerHTML"];
12304
+ var _hoisted_4$15 = ["innerHTML"];
12261
12305
  var _hoisted_5$11 = { class: "comments-dropdown__option-label" };
12262
12306
  var CommentsDropdown_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12263
12307
  __name: "CommentsDropdown",
@@ -12398,10 +12442,10 @@ var CommentsDropdown_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12398
12442
  key: option.key,
12399
12443
  class: normalizeClass(["comments-dropdown__option", { "sd-disabled": option.disabled }]),
12400
12444
  onClick: ($event) => onOptionClick(option)
12401
- }, [hasIcon(option) ? (openBlock(), createElementBlock("span", _hoisted_3$20, [option.iconString ? (openBlock(), createElementBlock("span", {
12445
+ }, [hasIcon(option) ? (openBlock(), createElementBlock("span", _hoisted_3$21, [option.iconString ? (openBlock(), createElementBlock("span", {
12402
12446
  key: 0,
12403
12447
  innerHTML: option.iconString
12404
- }, null, 8, _hoisted_4$14)) : (openBlock(), createBlock(unref(OptionIcon), {
12448
+ }, null, 8, _hoisted_4$15)) : (openBlock(), createBlock(unref(OptionIcon), {
12405
12449
  key: 1,
12406
12450
  option
12407
12451
  }, null, 8, ["option"]))])) : createCommentVNode("", true), createElementVNode("span", _hoisted_5$11, toDisplayString(option.label), 1)], 10, _hoisted_2$24);
@@ -12413,8 +12457,8 @@ var CommentsDropdown_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12413
12457
  //#region src/components/CommentsLayer/InternalDropdown.vue
12414
12458
  var _hoisted_1$30 = { class: "sd-comment-option" };
12415
12459
  var _hoisted_2$23 = ["innerHTML"];
12416
- var _hoisted_3$19 = { class: "sd-option-state" };
12417
- var _hoisted_4$13 = ["innerHTML"];
12460
+ var _hoisted_3$20 = { class: "sd-option-state" };
12461
+ var _hoisted_4$14 = ["innerHTML"];
12418
12462
  var InternalDropdown_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12419
12463
  __name: "InternalDropdown",
12420
12464
  props: {
@@ -12487,11 +12531,11 @@ var InternalDropdown_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12487
12531
  class: "sd-active-icon",
12488
12532
  innerHTML: activeIcon.value
12489
12533
  }, null, 8, _hoisted_2$23),
12490
- createElementVNode("div", _hoisted_3$19, toDisplayString(getState.value), 1),
12534
+ createElementVNode("div", _hoisted_3$20, toDisplayString(getState.value), 1),
12491
12535
  createElementVNode("div", {
12492
12536
  class: "sd-dropdown-caret",
12493
12537
  innerHTML: unref(superdocIcons).caretDown
12494
- }, null, 8, _hoisted_4$13)
12538
+ }, null, 8, _hoisted_4$14)
12495
12539
  ])]),
12496
12540
  _: 1
12497
12541
  }, 8, ["disabled", "content-style"])], 4);
@@ -12649,7 +12693,7 @@ var isAllowed = (permission, role, isInternal, context = {}) => {
12649
12693
  //#region src/components/general/Avatar.vue
12650
12694
  var _hoisted_1$29 = { class: "user-container" };
12651
12695
  var _hoisted_2$22 = ["src"];
12652
- var _hoisted_3$18 = {
12696
+ var _hoisted_3$19 = {
12653
12697
  key: 1,
12654
12698
  class: "user-bg"
12655
12699
  };
@@ -12674,7 +12718,7 @@ var Avatar_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12674
12718
  key: 0,
12675
12719
  class: "user-bg",
12676
12720
  src: __props.user.image.startsWith("http") ? __props.user.image : `data:image/png;base64,${__props.user.image}`
12677
- }, null, 8, _hoisted_2$22)) : (openBlock(), createElementBlock("span", _hoisted_3$18, toDisplayString(getInitials(__props.user.name, __props.user.email)), 1))]);
12721
+ }, null, 8, _hoisted_2$22)) : (openBlock(), createElementBlock("span", _hoisted_3$19, toDisplayString(getInitials(__props.user.name, __props.user.email)), 1))]);
12678
12722
  };
12679
12723
  }
12680
12724
  }, [["__scopeId", "data-v-c95b2073"]]);
@@ -12682,8 +12726,8 @@ var Avatar_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12682
12726
  //#region src/components/CommentsLayer/CommentHeader.vue
12683
12727
  var _hoisted_1$28 = { class: "card-section comment-header" };
12684
12728
  var _hoisted_2$21 = { class: "comment-header-left" };
12685
- var _hoisted_3$17 = { class: "user-info" };
12686
- var _hoisted_4$12 = { class: "user-name" };
12729
+ var _hoisted_3$18 = { class: "user-info" };
12730
+ var _hoisted_4$13 = { class: "user-name" };
12687
12731
  var _hoisted_5$10 = {
12688
12732
  key: 0,
12689
12733
  class: "imported-tag"
@@ -12943,7 +12987,7 @@ var CommentHeader_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12943
12987
  return openBlock(), createElementBlock("div", _hoisted_1$28, [createElementVNode("div", _hoisted_2$21, [createVNode(Avatar_default, {
12944
12988
  user: getCurrentUser.value,
12945
12989
  class: "avatar"
12946
- }, null, 8, ["user"]), createElementVNode("div", _hoisted_3$17, [createElementVNode("div", _hoisted_4$12, [createTextVNode(toDisplayString(getCurrentUser.value.name), 1), isImported.value ? (openBlock(), createElementBlock("span", _hoisted_5$10, "IMPORTED")) : createCommentVNode("", true)]), props.comment.createdTime ? (openBlock(), createElementBlock("div", _hoisted_6$8, toDisplayString(unref(formatDate)(props.comment.createdTime)), 1)) : createCommentVNode("", true)])]), createElementVNode("div", { class: normalizeClass(["overflow-menu", { "is-visible": props.isActive }]) }, [
12990
+ }, null, 8, ["user"]), createElementVNode("div", _hoisted_3$18, [createElementVNode("div", _hoisted_4$13, [createTextVNode(toDisplayString(getCurrentUser.value.name), 1), isImported.value ? (openBlock(), createElementBlock("span", _hoisted_5$10, "IMPORTED")) : createCommentVNode("", true)]), props.comment.createdTime ? (openBlock(), createElementBlock("div", _hoisted_6$8, toDisplayString(unref(formatDate)(props.comment.createdTime)), 1)) : createCommentVNode("", true)])]), createElementVNode("div", { class: normalizeClass(["overflow-menu", { "is-visible": props.isActive }]) }, [
12947
12991
  allowResolve.value ? (openBlock(), createElementBlock("div", {
12948
12992
  key: 0,
12949
12993
  class: normalizeClass(["overflow-menu__icon", { "sd-is-disabled": Boolean(__props.resolveDisabledReason) }]),
@@ -12993,12 +13037,12 @@ var CommentHeader_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
12993
13037
  //#region src/components/CommentsLayer/CommentInput.vue
12994
13038
  var _hoisted_1$27 = { class: "input-section" };
12995
13039
  var _hoisted_2$20 = { class: "comment-composer" };
12996
- var _hoisted_3$16 = [
13040
+ var _hoisted_3$17 = [
12997
13041
  "aria-expanded",
12998
13042
  "aria-controls",
12999
13043
  "aria-activedescendant"
13000
13044
  ];
13001
- var _hoisted_4$11 = [
13045
+ var _hoisted_4$12 = [
13002
13046
  "id",
13003
13047
  "aria-selected",
13004
13048
  "data-sd-comment-mention-option",
@@ -13188,7 +13232,7 @@ var CommentInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13188
13232
  onKeydown,
13189
13233
  onFocus: _cache[1] || (_cache[1] = ($event) => handleFocusChange(true)),
13190
13234
  onBlur: _cache[2] || (_cache[2] = ($event) => handleFocusChange(false))
13191
- }, null, 40, _hoisted_3$16), [[vModelText, commentDraft.value]]), mentionListOpen.value ? (openBlock(), createElementBlock("div", {
13235
+ }, null, 40, _hoisted_3$17), [[vModelText, commentDraft.value]]), mentionListOpen.value ? (openBlock(), createElementBlock("div", {
13192
13236
  key: 0,
13193
13237
  id: mentionListId,
13194
13238
  class: "comment-mention-list",
@@ -13204,7 +13248,7 @@ var CommentInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
13204
13248
  "aria-selected": index === highlightedMentionIndex.value,
13205
13249
  "data-sd-comment-mention-option": userKey(user),
13206
13250
  onMousedown: withModifiers(($event) => selectMention(user), ["prevent"])
13207
- }, [createElementVNode("span", _hoisted_5$9, toDisplayString(displayName(user)), 1), user.email ? (openBlock(), createElementBlock("span", _hoisted_6$7, toDisplayString(user.email), 1)) : createCommentVNode("", true)], 42, _hoisted_4$11);
13251
+ }, [createElementVNode("span", _hoisted_5$9, toDisplayString(displayName(user)), 1), user.email ? (openBlock(), createElementBlock("span", _hoisted_6$7, toDisplayString(user.email), 1)) : createCommentVNode("", true)], 42, _hoisted_4$12);
13208
13252
  }), 128))])) : createCommentVNode("", true)])], 2)]);
13209
13253
  };
13210
13254
  }
@@ -13330,98 +13374,108 @@ var _hoisted_2$19 = {
13330
13374
  key: 0,
13331
13375
  class: "existing-internal-input"
13332
13376
  };
13333
- var _hoisted_3$15 = { class: "new-comment-input-wrapper" };
13334
- var _hoisted_4$10 = { class: "reply-actions" };
13335
- var _hoisted_5$8 = ["disabled"];
13336
- var _hoisted_6$6 = {
13377
+ var _hoisted_3$16 = { class: "new-comment-input-wrapper" };
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;
@@ -14410,7 +14487,7 @@ var CommentDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14410
14487
  comment: props.comment,
14411
14488
  "is-pending-input": true
14412
14489
  }, null, 8, ["config", "comment"]),
14413
- createElementVNode("div", _hoisted_3$15, [createVNode(CommentInput_default, {
14490
+ createElementVNode("div", _hoisted_3$16, [createVNode(CommentInput_default, {
14414
14491
  ref_key: "commentInput",
14415
14492
  ref: commentInput,
14416
14493
  users: usersFiltered.value,
@@ -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$10, [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 = [
@@ -14747,7 +14826,7 @@ var ReviewDirectoryListItem_default = /*#__PURE__*/ _plugin_vue_export_helper_de
14747
14826
  //#region src/components/CommentsLayer/commentsList/commentsList.vue
14748
14827
  var _hoisted_1$24 = ["aria-busy"];
14749
14828
  var _hoisted_2$18 = { key: 0 };
14750
- var _hoisted_3$14 = { key: 1 };
14829
+ var _hoisted_3$15 = { key: 1 };
14751
14830
  var REPEATED_HEADER_FOOTER_STORY_TYPE = "headerFooterPart";
14752
14831
  var commentsList_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14753
14832
  __name: "commentsList",
@@ -14891,7 +14970,7 @@ var commentsList_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
14891
14970
  "total",
14892
14971
  "tab-index"
14893
14972
  ]);
14894
- }), 128))])) : createCommentVNode("", true), shouldShowResolvedComments.value ? (openBlock(), createElementBlock("div", _hoisted_3$14, [_cache[2] || (_cache[2] = createElementVNode("div", { class: "comment-title" }, "Resolved", -1)), (openBlock(true), createElementBlock(Fragment, null, renderList(resolvedCommentDisplayItems.value, (item, index) => {
14973
+ }), 128))])) : createCommentVNode("", true), shouldShowResolvedComments.value ? (openBlock(), createElementBlock("div", _hoisted_3$15, [_cache[2] || (_cache[2] = createElementVNode("div", { class: "comment-title" }, "Resolved", -1)), (openBlock(true), createElementBlock(Fragment, null, renderList(resolvedCommentDisplayItems.value, (item, index) => {
14895
14974
  return openBlock(), createBlock(ReviewDirectoryListItem_default, {
14896
14975
  key: item.id,
14897
14976
  item,
@@ -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;
@@ -19011,11 +19164,11 @@ var _hoisted_2$16 = {
19011
19164
  key: 1,
19012
19165
  class: "link-title"
19013
19166
  };
19014
- var _hoisted_3$13 = {
19167
+ var _hoisted_3$14 = {
19015
19168
  key: 2,
19016
19169
  class: "link-title"
19017
19170
  };
19018
- var _hoisted_4$9 = {
19171
+ var _hoisted_4$10 = {
19019
19172
  key: 3,
19020
19173
  class: "link-title"
19021
19174
  };
@@ -19258,7 +19411,7 @@ var LinkInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
19258
19411
  };
19259
19412
  return (_ctx, _cache) => {
19260
19413
  return openBlock(), createElementBlock("div", { class: normalizeClass(["link-input-ctn", { "high-contrast": unref(isHighContrastMode) }]) }, [
19261
- isAnchor.value ? (openBlock(), createElementBlock("div", _hoisted_1$20, "Page anchor")) : isViewingMode.value ? (openBlock(), createElementBlock("div", _hoisted_2$16, "Link details")) : isEditing.value ? (openBlock(), createElementBlock("div", _hoisted_3$13, "Edit link")) : (openBlock(), createElementBlock("div", _hoisted_4$9, "Add link")),
19414
+ isAnchor.value ? (openBlock(), createElementBlock("div", _hoisted_1$20, "Page anchor")) : isViewingMode.value ? (openBlock(), createElementBlock("div", _hoisted_2$16, "Link details")) : isEditing.value ? (openBlock(), createElementBlock("div", _hoisted_3$14, "Edit link")) : (openBlock(), createElementBlock("div", _hoisted_4$10, "Add link")),
19262
19415
  __props.showInput && !isAnchor.value ? (openBlock(), createElementBlock("div", _hoisted_5$7, [
19263
19416
  createElementVNode("div", _hoisted_6$5, [_cache[5] || (_cache[5] = createElementVNode("div", { class: "input-icon text-input-icon" }, "T", -1)), withDirectives(createElementVNode("input", {
19264
19417
  type: "text",
@@ -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);
@@ -21355,7 +21530,7 @@ var FOCUSABLE_SELECTOR = [
21355
21530
  //#region src/components/surfaces/SurfaceDialog.vue
21356
21531
  var _hoisted_1$19 = ["aria-labelledby", "aria-label"];
21357
21532
  var _hoisted_2$15 = ["id"];
21358
- var _hoisted_3$12 = { class: "sd-surface-dialog__content" };
21533
+ var _hoisted_3$13 = { class: "sd-surface-dialog__content" };
21359
21534
  var SurfaceDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21360
21535
  __name: "SurfaceDialog",
21361
21536
  props: {
@@ -21487,7 +21662,7 @@ var SurfaceDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21487
21662
  key: 0,
21488
21663
  id: titleId.value,
21489
21664
  class: "sd-surface-dialog__title"
21490
- }, toDisplayString(__props.surface.request.title), 9, _hoisted_2$15)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$12, [__props.surface.render ? (openBlock(), createBlock(SurfaceExternalMount_default, {
21665
+ }, toDisplayString(__props.surface.request.title), 9, _hoisted_2$15)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$13, [__props.surface.render ? (openBlock(), createBlock(SurfaceExternalMount_default, {
21491
21666
  key: 0,
21492
21667
  "surface-id": __props.surface.id,
21493
21668
  mode: "dialog",
@@ -21509,7 +21684,7 @@ var SurfaceDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21509
21684
  //#region src/components/surfaces/SurfaceFloating.vue
21510
21685
  var _hoisted_1$18 = ["aria-labelledby", "aria-label"];
21511
21686
  var _hoisted_2$14 = ["id"];
21512
- var _hoisted_3$11 = { class: "sd-surface-floating__content" };
21687
+ var _hoisted_3$12 = { class: "sd-surface-floating__content" };
21513
21688
  var SurfaceFloating_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21514
21689
  __name: "SurfaceFloating",
21515
21690
  props: { surface: {
@@ -21641,7 +21816,7 @@ var SurfaceFloating_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21641
21816
  key: 0,
21642
21817
  id: titleId.value,
21643
21818
  class: "sd-surface-floating__title"
21644
- }, toDisplayString(__props.surface.request.title), 9, _hoisted_2$14)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$11, [__props.surface.render ? (openBlock(), createBlock(SurfaceExternalMount_default, {
21819
+ }, toDisplayString(__props.surface.request.title), 9, _hoisted_2$14)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$12, [__props.surface.render ? (openBlock(), createBlock(SurfaceExternalMount_default, {
21645
21820
  key: 0,
21646
21821
  "surface-id": __props.surface.id,
21647
21822
  mode: "floating",
@@ -21885,8 +22060,8 @@ var SurfaceHost_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
21885
22060
  //#region src/SuperDoc.vue
21886
22061
  var _hoisted_1$17 = ["data-superdoc-ui-owner"];
21887
22062
  var _hoisted_2$13 = ["innerHTML"];
21888
- var _hoisted_3$10 = { class: "superdoc__document document" };
21889
- var _hoisted_4$8 = { class: "floating-comments" };
22063
+ var _hoisted_3$11 = { class: "superdoc__document document" };
22064
+ var _hoisted_4$9 = { class: "floating-comments" };
21890
22065
  var TRACKED_CHANGE_CARRIERS_RESTAMPED_EVENT = "superdoc:v2-tracked-change-carriers-restamped";
21891
22066
  var UNAVAILABLE_COMMAND_RESULT = false;
21892
22067
  var V2_SELECTION_TOOLBAR_SYNC_RETRY_FRAMES = 3;
@@ -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)
@@ -24365,7 +24548,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
24365
24548
  }, [createElementVNode("div", {
24366
24549
  class: "superdoc__tools-icon",
24367
24550
  innerHTML: unref(superdocIcons).comment
24368
- }, null, 8, _hoisted_2$13)], 32)], 4)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$10, [
24551
+ }, null, 8, _hoisted_2$13)], 32)], 4)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$11, [
24369
24552
  isCommentsEnabled.value ? (openBlock(), createElementBlock("div", {
24370
24553
  key: 0,
24371
24554
  class: "superdoc__selection-layer selection-layer",
@@ -24493,7 +24676,7 @@ var SuperDoc_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
24493
24676
  ref_key: "rightSidebarRef",
24494
24677
  ref: rightSidebarRef,
24495
24678
  class: "superdoc__right-sidebar right-sidebar"
24496
- }, [createElementVNode("div", _hoisted_4$8, [unref(hasInitializedLocations) && (floatingComments.value.length > 0 || unref(pendingComment)) ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(unref(documentsWithConverations), (doc) => {
24679
+ }, [createElementVNode("div", _hoisted_4$9, [unref(hasInitializedLocations) && (floatingComments.value.length > 0 || unref(pendingComment)) ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(unref(documentsWithConverations), (doc) => {
24497
24680
  return openBlock(), createBlock(FloatingComments_default, {
24498
24681
  parent: layers.value,
24499
24682
  "current-document": doc
@@ -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),
@@ -38997,8 +39186,8 @@ var _hoisted_1$15 = [
38997
39186
  "aria-disabled"
38998
39187
  ];
38999
39188
  var _hoisted_2$11 = ["data-item"];
39000
- var _hoisted_3$9 = ["data-item"];
39001
- var _hoisted_4$7 = {
39189
+ var _hoisted_3$10 = ["data-item"];
39190
+ var _hoisted_4$8 = {
39002
39191
  key: 1,
39003
39192
  class: "sd-button-label"
39004
39193
  };
@@ -39219,7 +39408,7 @@ var ToolbarButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
39219
39408
  "color",
39220
39409
  "icon",
39221
39410
  "name"
39222
- ])) : createCommentVNode("", true), unref(label) && !unref(hideLabel) && !unref(inlineTextInputVisible) ? (openBlock(), createElementBlock("div", _hoisted_4$7, toDisplayString(unref(label)), 1)) : createCommentVNode("", true)], 8, _hoisted_3$9)) : createCommentVNode("", true),
39411
+ ])) : createCommentVNode("", true), unref(label) && !unref(hideLabel) && !unref(inlineTextInputVisible) ? (openBlock(), createElementBlock("div", _hoisted_4$8, toDisplayString(unref(label)), 1)) : createCommentVNode("", true)], 8, _hoisted_3$10)) : createCommentVNode("", true),
39223
39412
  isSplit.value ? (openBlock(), createElementBlock("div", {
39224
39413
  key: 1,
39225
39414
  class: "sd-toolbar-button__caret",
@@ -39321,8 +39510,8 @@ var ToolbarSeparator_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
39321
39510
  //#region src/internal/toolbar/built-in/ToolbarDropdown.vue
39322
39511
  var _hoisted_1$13 = { class: "toolbar-dropdown" };
39323
39512
  var _hoisted_2$10 = ["data-superdoc-ui-owner"];
39324
- var _hoisted_3$8 = ["onClick"];
39325
- var _hoisted_4$6 = {
39513
+ var _hoisted_3$9 = ["onClick"];
39514
+ var _hoisted_4$7 = {
39326
39515
  key: 0,
39327
39516
  class: "toolbar-dropdown-option__icon"
39328
39517
  };
@@ -39711,7 +39900,7 @@ var ToolbarDropdown_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
39711
39900
  }), [isRenderOption(option) ? (openBlock(), createBlock(unref(RenderOption), {
39712
39901
  key: 0,
39713
39902
  option
39714
- }, null, 8, ["option"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [hasIcon(option) ? (openBlock(), createElementBlock("span", _hoisted_4$6, [createVNode(unref(OptionIcon), { option }, null, 8, ["option"])])) : createCommentVNode("", true), createElementVNode("span", _hoisted_5$5, toDisplayString(option.label), 1)], 64))], 16, _hoisted_3$8);
39903
+ }, null, 8, ["option"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [hasIcon(option) ? (openBlock(), createElementBlock("span", _hoisted_4$7, [createVNode(unref(OptionIcon), { option }, null, 8, ["option"])])) : createCommentVNode("", true), createElementVNode("span", _hoisted_5$5, toDisplayString(option.label), 1)], 64))], 16, _hoisted_3$9);
39715
39904
  }), 128))], 16, _hoisted_2$10)) : createCommentVNode("", true)]),
39716
39905
  _: 3
39717
39906
  })], 8, ["to"]))]);
@@ -39950,12 +40139,12 @@ var _hoisted_2$9 = [
39950
40139
  "aria-activedescendant",
39951
40140
  "data-item"
39952
40141
  ];
39953
- var _hoisted_3$7 = [
40142
+ var _hoisted_3$8 = [
39954
40143
  "data-item",
39955
40144
  "aria-label",
39956
40145
  "disabled"
39957
40146
  ];
39958
- var _hoisted_4$5 = ["innerHTML"];
40147
+ var _hoisted_4$6 = ["innerHTML"];
39959
40148
  var _hoisted_5$4 = [
39960
40149
  "data-superdoc-ui-owner",
39961
40150
  "id",
@@ -40423,7 +40612,7 @@ var ToolbarComboBox_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
40423
40612
  }, [createElementVNode("span", {
40424
40613
  class: "sd-dropdown-caret",
40425
40614
  innerHTML: caretIcon.value
40426
- }, null, 8, _hoisted_4$5)], 40, _hoisted_3$7),
40615
+ }, null, 8, _hoisted_4$6)], 40, _hoisted_3$8),
40427
40616
  (openBlock(), createBlock(Teleport, { to: "body" }, [isOpen.value ? (openBlock(), createElementBlock("div", {
40428
40617
  key: 0,
40429
40618
  ref_key: "popupRef",
@@ -40768,8 +40957,8 @@ var _hoisted_1$11 = [
40768
40957
  "data-item-id"
40769
40958
  ];
40770
40959
  var _hoisted_2$8 = { key: 0 };
40771
- var _hoisted_3$6 = { key: 0 };
40772
- var _hoisted_4$4 = { key: 0 };
40960
+ var _hoisted_3$7 = { key: 0 };
40961
+ var _hoisted_4$5 = { key: 0 };
40773
40962
  var _hoisted_5$3 = { key: 0 };
40774
40963
  var _hoisted_6$2 = { key: 0 };
40775
40964
  var ButtonGroup_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
@@ -41173,7 +41362,7 @@ var ButtonGroup_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
41173
41362
  onTabOut: _cache[1] || (_cache[1] = ($event) => handleFontSizeTabOut($event)),
41174
41363
  onEditorHandoff: handleEditorHandoff
41175
41364
  }, null, 8, ["item", "ui-font-family"])]),
41176
- default: withCtx(() => [createElementVNode("div", null, [createTextVNode(toDisplayString(item.tooltip) + " ", 1), item.disabled.value ? (openBlock(), createElementBlock("span", _hoisted_3$6, "(disabled)")) : createCommentVNode("", true)])]),
41365
+ default: withCtx(() => [createElementVNode("div", null, [createTextVNode(toDisplayString(item.tooltip) + " ", 1), item.disabled.value ? (openBlock(), createElementBlock("span", _hoisted_3$7, "(disabled)")) : createCommentVNode("", true)])]),
41177
41366
  _: 2
41178
41367
  }, 1032, ["disabled", "content-style"])) : isDropdown(item) && item.nestedOptions?.value?.length ? (openBlock(), createBlock(ToolbarDropdown_default, {
41179
41368
  key: 3,
@@ -41210,7 +41399,7 @@ var ButtonGroup_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
41210
41399
  "onTextSubmit",
41211
41400
  "onMainClick"
41212
41401
  ])]),
41213
- default: withCtx(() => [createElementVNode("div", null, [createTextVNode(toDisplayString(item.tooltip) + " ", 1), item.disabled.value ? (openBlock(), createElementBlock("span", _hoisted_4$4, "(disabled)")) : createCommentVNode("", true)])]),
41402
+ default: withCtx(() => [createElementVNode("div", null, [createTextVNode(toDisplayString(item.tooltip) + " ", 1), item.disabled.value ? (openBlock(), createElementBlock("span", _hoisted_4$5, "(disabled)")) : createCommentVNode("", true)])]),
41214
41403
  _: 2
41215
41404
  }, 1032, ["disabled", "content-style"])]),
41216
41405
  _: 2
@@ -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"];
@@ -41577,7 +41763,13 @@ var Toolbar_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
41577
41763
  proxy.$toolbar.pendingSelectionCapture = pendingSelectionCapture;
41578
41764
  };
41579
41765
  const handleCommand = ({ item, argument, option }) => {
41580
- restoreSelection();
41766
+ const commandId = resolveToolbarCommandId(item?.name?.value);
41767
+ if (!(item?.type === "button" && !item.isCustomToolbarItem && [
41768
+ "bold",
41769
+ "italic",
41770
+ "underline",
41771
+ "strikethrough"
41772
+ ].includes(commandId) && proxy.$toolbar.snapshot?.commands?.[commandId]?.source === "builtin")) restoreSelection();
41581
41773
  proxy.$toolbar.emitCommand({
41582
41774
  item,
41583
41775
  argument,
@@ -41655,7 +41847,7 @@ var Toolbar_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
41655
41847
  ], 40, _hoisted_1$10);
41656
41848
  };
41657
41849
  }
41658
- }, [["__scopeId", "data-v-19ce2dae"]]);
41850
+ }, [["__scopeId", "data-v-9554df11"]]);
41659
41851
  //#endregion
41660
41852
  //#region src/internal/toolbar/built-in/font-options.js
41661
41853
  /**
@@ -42082,8 +42274,8 @@ var numberedStyleButtons = [
42082
42274
  //#region src/internal/toolbar/built-in/DocumentMode.vue
42083
42275
  var _hoisted_1$7 = ["onClick", "onKeydown"];
42084
42276
  var _hoisted_2$7 = { class: "document-mode-column icon-column" };
42085
- var _hoisted_3$5 = ["innerHTML"];
42086
- var _hoisted_4$3 = { class: "document-mode-column text-column" };
42277
+ var _hoisted_3$6 = ["innerHTML"];
42278
+ var _hoisted_4$4 = { class: "document-mode-column text-column" };
42087
42279
  var _hoisted_5$2 = { class: "document-mode-type" };
42088
42280
  var _hoisted_6$1 = { class: "document-mode-description" };
42089
42281
  var DocumentMode_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
@@ -42146,7 +42338,7 @@ var DocumentMode_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
42146
42338
  }, [createElementVNode("div", _hoisted_2$7, [createElementVNode("div", {
42147
42339
  class: "icon-column__icon",
42148
42340
  innerHTML: option.icon
42149
- }, null, 8, _hoisted_3$5)]), createElementVNode("div", _hoisted_4$3, [createElementVNode("div", _hoisted_5$2, toDisplayString(option.label), 1), createElementVNode("div", _hoisted_6$1, toDisplayString(option.description), 1)])], 42, _hoisted_1$7);
42341
+ }, null, 8, _hoisted_3$6)]), createElementVNode("div", _hoisted_4$4, [createElementVNode("div", _hoisted_5$2, toDisplayString(option.label), 1), createElementVNode("div", _hoisted_6$1, toDisplayString(option.description), 1)])], 42, _hoisted_1$7);
42150
42342
  }), 256))], 2);
42151
42343
  };
42152
42344
  }
@@ -42162,6 +42354,12 @@ var _hoisted_2$6 = [
42162
42354
  "onKeydown",
42163
42355
  "aria-label"
42164
42356
  ];
42357
+ var _hoisted_3$5 = [
42358
+ "title",
42359
+ "aria-label",
42360
+ "onClick"
42361
+ ];
42362
+ var _hoisted_4$3 = ["innerHTML"];
42165
42363
  var LinkedStyle_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
42166
42364
  __name: "LinkedStyle",
42167
42365
  props: {
@@ -42172,9 +42370,13 @@ var LinkedStyle_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
42172
42370
  selectedOption: {
42173
42371
  type: String,
42174
42372
  default: null
42373
+ },
42374
+ updateLabel: {
42375
+ type: String,
42376
+ default: "Update to match selection"
42175
42377
  }
42176
42378
  },
42177
- emits: ["select"],
42379
+ emits: ["select", "update"],
42178
42380
  setup(__props, { emit: __emit }) {
42179
42381
  const emit = __emit;
42180
42382
  const styleRefs = ref([]);
@@ -42182,6 +42384,9 @@ var LinkedStyle_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
42182
42384
  const select = (style) => {
42183
42385
  emit("select", style);
42184
42386
  };
42387
+ const update = (style) => {
42388
+ emit("update", style);
42389
+ };
42185
42390
  const moveToNextStyle = (index) => {
42186
42391
  if (index === styleRefs.value.length - 1) return;
42187
42392
  const nextItem = styleRefs.value[index + 1];
@@ -42241,11 +42446,22 @@ var LinkedStyle_default = /*#__PURE__*/ _plugin_vue_export_helper_default({
42241
42446
  class: "style-name",
42242
42447
  "data-item": "btn-linkedStyles-option",
42243
42448
  style: normalizeStyle(previewStyle(style))
42244
- }, toDisplayString(styleLabel(style)), 5)], 42, _hoisted_2$6);
42449
+ }, toDisplayString(styleLabel(style)), 5), createElementVNode("button", {
42450
+ type: "button",
42451
+ class: "style-update",
42452
+ "data-item": "btn-linkedStyles-update",
42453
+ title: props.updateLabel,
42454
+ "aria-label": `${props.updateLabel}: ${styleLabel(style)}`,
42455
+ onClick: withModifiers(($event) => update(style), ["stop"]),
42456
+ onKeydown: _cache[0] || (_cache[0] = withModifiers(() => {}, ["stop"]))
42457
+ }, [createElementVNode("span", {
42458
+ class: "style-update-icon",
42459
+ innerHTML: unref(toolbarIcons).paintbrush
42460
+ }, null, 8, _hoisted_4$3)], 40, _hoisted_3$5)], 42, _hoisted_2$6);
42245
42461
  }), 128))]);
42246
42462
  };
42247
42463
  }
42248
- }, [["__scopeId", "data-v-74c8924b"]]);
42464
+ }, [["__scopeId", "data-v-b5a32523"]]);
42249
42465
  //#endregion
42250
42466
  //#region src/internal/toolbar/built-in/AIWriter.vue
42251
42467
  var _hoisted_1$5 = ["placeholder"];
@@ -44446,10 +44662,18 @@ var makeDefaultItems = ({ superToolbar, toolbarIcons, toolbarTexts, toolbarFonts
44446
44662
  argument: styleId
44447
44663
  });
44448
44664
  };
44665
+ const handleUpdate = (style) => {
44666
+ closeDropdown(linkedStyles);
44667
+ const styleId = typeof style === "string" ? style : style?.id ?? null;
44668
+ if (!styleId) return;
44669
+ superToolbar.updateLinkedStyleToMatchSelection?.(styleId);
44670
+ };
44449
44671
  const activeStyleId = superToolbar.getActiveLinkedStyleId?.() ?? null;
44450
44672
  return h("div", {}, [h(LinkedStyle_default, {
44451
44673
  styles: superToolbar.getLinkedStyleOptions?.() ?? [],
44452
44674
  onSelect: handleSelect,
44675
+ onUpdate: handleUpdate,
44676
+ updateLabel: toolbarTexts.updateLinkedStyle,
44453
44677
  selectedOption: activeStyleId
44454
44678
  })]);
44455
44679
  }
@@ -44708,7 +44932,8 @@ var toolbarTexts = {
44708
44932
  documentEditingModeDescription: "Edit document directly",
44709
44933
  documentSuggestingModeDescription: "Edits become suggestions",
44710
44934
  documentViewingModeDescription: "View clean version of document only",
44711
- linkedStyles: "Linked styles"
44935
+ linkedStyles: "Linked styles",
44936
+ updateLinkedStyle: "Update to match selection"
44712
44937
  };
44713
44938
  //#endregion
44714
44939
  //#region src/internal/toolbar/built-in/general.js
@@ -45200,12 +45425,16 @@ var BuiltInToolbar = class extends import_eventemitter3.default {
45200
45425
  return this._linkedStyleOptions.value;
45201
45426
  }
45202
45427
  #refreshLinkedStyleOptions() {
45203
- this.ui?.styles?.getCatalog?.({ includePreview: true });
45428
+ const allStyles = this.ui?.styles?.getCatalog?.({ includePreview: true });
45204
45429
  const options = (this.ui?.styles?.getCatalog?.({
45205
45430
  view: "quickGallery",
45206
45431
  includePreview: true
45207
45432
  }))?.items ?? this.ui?.styles?.getQuickGallery?.() ?? [];
45208
- if (options !== this._linkedStyleOptions.value) this._linkedStyleOptions.value = options;
45433
+ const activeStyleId = this.ui?.styles?.getActiveParagraphStyle?.()?.styleId;
45434
+ const activeStyle = activeStyleId && !options.some((style) => style.id === activeStyleId) ? allStyles?.styles?.find((style) => style.id === activeStyleId && (style.type === "paragraph" || style.type === "linked")) : null;
45435
+ const nextOptions = activeStyle ? [activeStyle, ...options] : options;
45436
+ const previousOptions = this._linkedStyleOptions.value;
45437
+ if (nextOptions.length !== previousOptions.length || nextOptions.some((style, index) => style !== previousOptions[index])) this._linkedStyleOptions.value = nextOptions;
45209
45438
  }
45210
45439
  /**
45211
45440
  * The stable style id active across the current selection's paragraph(s), or
@@ -45215,6 +45444,17 @@ var BuiltInToolbar = class extends import_eventemitter3.default {
45215
45444
  getActiveLinkedStyleId() {
45216
45445
  return this.ui?.styles?.getActiveParagraphStyle?.()?.styleId ?? null;
45217
45446
  }
45447
+ async updateLinkedStyleToMatchSelection(styleId) {
45448
+ if (!styleId || typeof this.ui?.styles?.updateToMatchSelection !== "function") return null;
45449
+ try {
45450
+ return await this.ui.styles.updateToMatchSelection({ styleId });
45451
+ } catch (error) {
45452
+ this.#emitCommandException(error, "linkedStyles");
45453
+ return null;
45454
+ } finally {
45455
+ this.updateToolbarState();
45456
+ }
45457
+ }
45218
45458
  /**
45219
45459
  * Compatibility hook: `SuperDoc` calls this when the active editor changes.
45220
45460
  * The shared controller already tracks selection/transaction state, so this
@@ -46154,7 +46394,7 @@ var SuperDoc = class extends import_eventemitter3.default {
46154
46394
  }
46155
46395
  this.userColorMap = /* @__PURE__ */ new Map();
46156
46396
  this.colorIndex = 0;
46157
- this.version = "2.27.0";
46397
+ this.version = "2.28.0-next.10";
46158
46398
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
46159
46399
  this.superdocId = config.superdocId || v4();
46160
46400
  this.colors = this.config.colors ?? [];
@@ -46870,7 +47110,8 @@ var SuperDoc = class extends import_eventemitter3.default {
46870
47110
  ...syncTimeoutOption,
46871
47111
  ...target.serverUrl ? { serverUrl: target.serverUrl } : {},
46872
47112
  ...target.params ? { params: target.params } : {},
46873
- ...target.token ? { token: target.token } : {}
47113
+ ...target.token ? { token: target.token } : {},
47114
+ ...target.retry !== void 0 ? { retry: target.retry } : {}
46874
47115
  };
46875
47116
  return {
46876
47117
  providerType: "y-websocket",
@@ -48107,12 +48348,13 @@ var SuperDoc = class extends import_eventemitter3.default {
48107
48348
  * Export the superdoc to a file
48108
48349
  * @param params - Export configuration
48109
48350
  */
48110
- 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 } = {}) {
48111
48352
  if (!Array.isArray(exportType) || exportType.length !== 1 || exportType[0] !== "docx") throw new TypeError("SuperDoc.export() only supports exportType: [\"docx\"].");
48112
48353
  const baseFileName = exportedName ? cleanName(exportedName) : cleanName(this.config.title);
48113
48354
  const docxFiles = await this.exportEditorsToDOCX({
48114
48355
  commentsType,
48115
48356
  isFinalDoc,
48357
+ policies,
48116
48358
  fieldsHighlightColor
48117
48359
  });
48118
48360
  const blobsToZip = [...additionalFiles];
@@ -48198,7 +48440,12 @@ var SuperDoc = class extends import_eventemitter3.default {
48198
48440
  * Export editors to DOCX format.
48199
48441
  * @param [options]
48200
48442
  */
48201
- 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
+ });
48202
48449
  const uiStoreHydrated = this.config?.modules?.comments !== false;
48203
48450
  let legacyComments;
48204
48451
  let legacyCommentsComputed = false;
@@ -48218,7 +48465,13 @@ var SuperDoc = class extends import_eventemitter3.default {
48218
48465
  };
48219
48466
  this.on("exception", rememberBridgedExportError);
48220
48467
  try {
48221
- 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) => {
48222
48475
  if (!doc || doc.type !== "application/vnd.openxmlformats-officedocument.wordprocessingml.document") return null;
48223
48476
  const editor = typeof doc.getEditor === "function" ? doc.getEditor() : null;
48224
48477
  const fallbackDocx = () => {
@@ -48235,6 +48488,7 @@ var SuperDoc = class extends import_eventemitter3.default {
48235
48488
  const exported = await editor.exportDocx(isV2Editor ? {
48236
48489
  isFinalDoc,
48237
48490
  commentsType,
48491
+ policies,
48238
48492
  fieldsHighlightColor
48239
48493
  } : {
48240
48494
  isFinalDoc,
@@ -48563,4 +48817,8 @@ function defineSuperDocExtension(extension) {
48563
48817
  return extension;
48564
48818
  }
48565
48819
  //#endregion
48566
- 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 };