superdoc 2.29.0-next.9 → 2.30.0-next.13

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 (177) hide show
  1. package/README.md +127 -25
  2. package/dist/chunks/{FindReplaceSurface-BKVHzhQ4.es.js → FindReplaceSurface-BEnRLpD9.es.js} +1 -1
  3. package/dist/chunks/{FindReplaceSurface-BNDrJ6VS.cjs → FindReplaceSurface-DWXgWgg7.cjs} +1 -1
  4. package/dist/chunks/{PasswordPromptSurface-6mF6Azda.es.js → PasswordPromptSurface-DjV1JgjD.es.js} +1 -1
  5. package/dist/chunks/{PasswordPromptSurface-BNkaztaP.cjs → PasswordPromptSurface-VFPnQOML.cjs} +1 -1
  6. package/dist/chunks/{PdfViewer-aOWhUVI7.es.js → PdfViewer-C2r-K8zC.es.js} +4 -10
  7. package/dist/chunks/{PdfViewer-DmSkZehl.cjs → PdfViewer-DYTbPVUr.cjs} +4 -10
  8. package/dist/chunks/{_plugin-vue_export-helper-6MBoygIY.cjs → _plugin-vue_export-helper-BzM2_tVU.cjs} +40 -7
  9. package/dist/chunks/{_plugin-vue_export-helper-CsJQtMvr.es.js → _plugin-vue_export-helper-CmkaJDnr.es.js} +23 -8
  10. package/dist/chunks/{create-super-doc-ui-Bm5kmx0W.es.js → create-super-doc-ui--o8TcYYv.es.js} +3322 -2729
  11. package/dist/chunks/{create-super-doc-ui-DN70aatf.cjs → create-super-doc-ui-CvK1JdZv.cjs} +3447 -2854
  12. package/dist/collaboration-upgrade-engine.cjs +1 -1
  13. package/dist/collaboration-upgrade-engine.es.js +1 -1
  14. package/dist/document-api/src/changes/changes.d.ts +26 -0
  15. package/dist/document-api/src/changes/changes.types.d.ts +156 -0
  16. package/dist/document-api/src/comments/comment-create-attribution.d.ts +4 -0
  17. package/dist/document-api/src/comments/comments.types.d.ts +4 -0
  18. package/dist/document-api/src/contract/command-catalog.d.ts +1 -1
  19. package/dist/document-api/src/contract/operation-definitions.d.ts +76 -8
  20. package/dist/document-api/src/contract/operation-registry.d.ts +2 -2
  21. package/dist/document-api/src/contract/schemas.d.ts +7 -1
  22. package/dist/document-api/src/create/create.d.ts +0 -4
  23. package/dist/document-api/src/diff/diff.types.d.ts +6 -6
  24. package/dist/document-api/src/header-footers/header-footers.d.ts +1 -3
  25. package/dist/document-api/src/index.d.ts +13 -1
  26. package/dist/document-api/src/inline-semantics/token-sets.d.ts +0 -2
  27. package/dist/document-api/src/insert/insert.d.ts +0 -1
  28. package/dist/document-api/src/paragraphs/paragraphs.d.ts +8 -3
  29. package/dist/document-api/src/paragraphs/paragraphs.types.d.ts +49 -5
  30. package/dist/document-api/src/tables/data/table-preset-appearance.generated.d.ts +2 -0
  31. package/dist/document-api/src/tables/table-style-presets.d.ts +73 -0
  32. package/dist/document-api/src/tables/tables.d.ts +4 -1
  33. package/dist/document-api/src/types/sd-props.d.ts +7 -0
  34. package/dist/document-api/src/types/table-operations.types.d.ts +12 -15
  35. package/dist/layout-engine/contracts/src/index.d.ts +4 -1
  36. package/dist/layout-engine/contracts/src/table-cell-vector-overlay.d.ts +2 -0
  37. package/dist/layout-engine/dom-contract/src/data-attrs.d.ts +4 -0
  38. package/dist/layout-engine/layout-bridge/src/coupled-footnote-pagination.d.ts +1 -0
  39. package/dist/layout-engine/layout-bridge/src/footnote-page-certificate.d.ts +1 -0
  40. package/dist/layout-engine/layout-bridge/src/footnote-page-planner.d.ts +5 -0
  41. package/dist/layout-engine/layout-bridge/src/incrementalLayout.d.ts +1 -0
  42. package/dist/layout-engine/layout-engine/src/footnote-page-flow.d.ts +3 -0
  43. package/dist/layout-engine/layout-engine/src/index.d.ts +7 -0
  44. package/dist/layout-engine/layout-engine/src/layout-paragraph.d.ts +5 -0
  45. package/dist/layout-engine/layout-engine/src/layout-table.d.ts +3 -1
  46. package/dist/layout-engine/layout-engine/src/layout-utils.d.ts +0 -4
  47. package/dist/layout-engine/layout-engine/src/paginator.d.ts +4 -0
  48. package/dist/layout-engine/painters/dom/src/index.d.ts +2 -0
  49. package/dist/layout-engine/painters/dom/src/paragraph/list-marker.d.ts +1 -1
  50. package/dist/layout-engine/painters/dom/src/paragraph/renderParagraphContent.d.ts +1 -1
  51. package/dist/layout-engine/painters/dom/src/styles.d.ts +0 -10
  52. package/dist/layout-engine/painters/dom/src/svg-utils.d.ts +1 -13
  53. package/dist/public/ui-react.cjs +1 -1
  54. package/dist/public/ui-react.es.js +1 -1
  55. package/dist/public/ui-vue.cjs +1 -1
  56. package/dist/public/ui-vue.es.js +1 -1
  57. package/dist/public/ui.cjs +1 -1
  58. package/dist/public/ui.es.js +1 -1
  59. package/dist/shared/common/Telemetry.d.ts +50 -0
  60. package/dist/shared/common/event-types.d.ts +13 -0
  61. package/dist/shared/font-system/src/bundled-face-names.d.ts +1 -0
  62. package/dist/shared/font-system/src/resolver.d.ts +1 -0
  63. package/dist/style.css +1 -1
  64. package/dist/style.layered.css +1 -1
  65. package/dist/superdoc/src/components/CommentsLayer/CommentDialog.vue.d.ts +17 -33
  66. package/dist/superdoc/src/components/CommentsLayer/collect-removed-comment-ids.d.ts +11 -1
  67. package/dist/superdoc/src/components/CommentsLayer/collect-tracked-change-thread.d.ts +25 -6
  68. package/dist/superdoc/src/components/CommentsLayer/comment-params.d.ts +84 -0
  69. package/dist/superdoc/src/components/CommentsLayer/comment-urls.d.ts +1 -1
  70. package/dist/superdoc/src/components/CommentsLayer/commentsList/super-comments-list.d.ts +23 -20
  71. package/dist/superdoc/src/components/CommentsLayer/helpers.d.ts +1 -4
  72. package/dist/superdoc/src/components/CommentsLayer/tracked-change-threading.d.ts +16 -1
  73. package/dist/superdoc/src/components/CommentsLayer/use-comment.d.ts +15 -95
  74. package/dist/superdoc/src/components/Whiteboard/WhiteboardLayer.vue.d.ts +4 -5
  75. package/dist/superdoc/src/components/Whiteboard/WhiteboardPage.vue.d.ts +3 -4
  76. package/dist/superdoc/src/components/Whiteboard/use-whiteboard.d.ts +30 -9
  77. package/dist/superdoc/src/components/Whiteboard/whiteboard-types.d.ts +2 -0
  78. package/dist/superdoc/src/components/surfaces/watermark-surface-runtime.d.ts +7 -7
  79. package/dist/superdoc/src/composables/use-comment-sidebar.d.ts +6 -0
  80. package/dist/superdoc/src/composables/use-comment-small-screen.d.ts +11 -7
  81. package/dist/superdoc/src/composables/use-compact-comment-popover.d.ts +44 -18
  82. package/dist/superdoc/src/composables/use-document.d.ts +51 -99
  83. package/dist/superdoc/src/composables/use-find-replace.d.ts +13 -3
  84. package/dist/superdoc/src/composables/use-password-prompt.d.ts +1 -1
  85. package/dist/superdoc/src/composables/use-viewport-fit.d.ts +62 -26
  86. package/dist/superdoc/src/core/SuperDoc.d.ts +15 -6
  87. package/dist/superdoc/src/core/collaboration/cdn-collaboration-comment-map.d.ts +1 -0
  88. package/dist/superdoc/src/core/collaboration/collaboration-comment-map.d.ts +2 -0
  89. package/dist/superdoc/src/core/collaboration/helpers.d.ts +1 -1
  90. package/dist/superdoc/src/core/config/normalize-interaction-config.d.ts +10 -1
  91. package/dist/superdoc/src/core/document-open-telemetry.d.ts +1 -1
  92. package/dist/superdoc/src/core/editor-runtime/types.d.ts +4 -0
  93. package/dist/superdoc/src/core/editor-runtime/v2/v2-editor-runtime-adapter.d.ts +1 -0
  94. package/dist/superdoc/src/core/pdf/pdf-adapter.d.ts +6 -2
  95. package/dist/superdoc/src/core/types/index.d.ts +147 -43
  96. package/dist/superdoc/src/core/v2-integration/browser-peer-runtime.d.ts +5 -3
  97. package/dist/superdoc/src/core/v2-integration/cdn-engine-loader.d.ts +3 -13
  98. package/dist/superdoc/src/core/v2-integration/internal-vue-runtime.d.ts +64 -59
  99. package/dist/superdoc/src/helpers/deprecation.d.ts +12 -3
  100. package/dist/superdoc/src/helpers/object-guards.d.ts +2 -0
  101. package/dist/superdoc/src/helpers/v2-author-required-rejection.d.ts +8 -11
  102. package/dist/superdoc/src/helpers/v2-bulk-decision-event.d.ts +9 -7
  103. package/dist/superdoc/src/helpers/v2-keyboard-edit-rejection.d.ts +8 -7
  104. package/dist/superdoc/src/helpers/v2-mutation-exception.d.ts +12 -8
  105. package/dist/superdoc/src/helpers/v2-review-geometry-delivery.d.ts +22 -0
  106. package/dist/superdoc/src/helpers/v2-review-target.d.ts +11 -1
  107. package/dist/superdoc/src/helpers/v2-selection-sync.d.ts +40 -14
  108. package/dist/superdoc/src/helpers/v2-typing-mutation-event.d.ts +14 -5
  109. package/dist/superdoc/src/icons.d.ts +11 -19
  110. package/dist/superdoc/src/internal/diagnostics/translate-diagnostic.d.ts +6 -4
  111. package/dist/superdoc/src/internal/toolbar/built-in/PageNumberMenu.vue.d.ts +25 -15
  112. package/dist/superdoc/src/internal/toolbar/built-in/ToolbarButton.vue.d.ts +1 -0
  113. package/dist/superdoc/src/internal/toolbar/built-in/constants.d.ts +3 -1
  114. package/dist/superdoc/src/internal/toolbar/built-in/font-options.d.ts +15 -1
  115. package/dist/superdoc/src/internal/toolbar/built-in/font-typeahead.d.ts +37 -7
  116. package/dist/superdoc/src/internal/toolbar/built-in/general.d.ts +12 -1
  117. package/dist/superdoc/src/internal/toolbar/built-in/helpers.d.ts +9 -4
  118. package/dist/superdoc/src/internal/toolbar/built-in/list-style-buttons.d.ts +2 -2
  119. package/dist/superdoc/src/internal/toolbar/built-in/page-number-feedback.d.ts +4 -5
  120. package/dist/superdoc/src/internal/toolbar/built-in/scroll-helpers.d.ts +3 -4
  121. package/dist/superdoc/src/internal/toolbar/built-in/toolbarIcons.d.ts +78 -145
  122. package/dist/superdoc/src/internal/toolbar/built-in/url-safety.d.ts +11 -3
  123. package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +4 -3
  124. package/dist/superdoc/src/internal/toolbar/image-upload.d.ts +29 -39
  125. package/dist/superdoc/src/public/content-control-ref.d.ts +12 -0
  126. package/dist/superdoc/src/public/index.d.cts +20 -0
  127. package/dist/superdoc/src/public/index.d.ts +4 -1
  128. package/dist/superdoc/src/public/ui/async-read-cache.d.ts +32 -0
  129. package/dist/superdoc/src/public/ui/block-commands.d.ts +39 -0
  130. package/dist/superdoc/src/public/ui/command-results.d.ts +39 -0
  131. package/dist/superdoc/src/public/ui/commands.d.ts +5 -1
  132. package/dist/superdoc/src/public/ui/create-super-doc-ui.d.ts +1 -17
  133. package/dist/superdoc/src/public/ui/document-change-records.d.ts +7 -0
  134. package/dist/superdoc/src/public/ui/entity-rows.d.ts +14 -0
  135. package/dist/superdoc/src/public/ui/font-options.d.ts +7 -0
  136. package/dist/superdoc/src/public/ui/format-painter-helpers.d.ts +2 -8
  137. package/dist/superdoc/src/public/ui/format-painter-paragraph.d.ts +7 -0
  138. package/dist/superdoc/src/public/ui/format-painter-state.d.ts +29 -0
  139. package/dist/superdoc/src/public/ui/heavy-read-policy.d.ts +11 -0
  140. package/dist/superdoc/src/public/ui/host-events.d.ts +3 -0
  141. package/dist/superdoc/src/public/ui/inline-values.d.ts +80 -0
  142. package/dist/superdoc/src/public/ui/loose-record.d.ts +4 -0
  143. package/dist/superdoc/src/public/ui/reasons.d.ts +1 -0
  144. package/dist/superdoc/src/public/ui/selection-targets.d.ts +53 -0
  145. package/dist/superdoc/src/public/ui/shared-tracked-changes-catalog.d.ts +16 -0
  146. package/dist/superdoc/src/public/ui/tracked-change-ids.d.ts +51 -0
  147. package/dist/superdoc/src/public/ui/types.d.ts +25 -2
  148. package/dist/superdoc/src/public/ui/ui-bench-timing.d.ts +9 -0
  149. package/dist/superdoc/src/public/ui.d.cts +18 -0
  150. package/dist/superdoc/src/public/ui.d.ts +1 -1
  151. package/dist/superdoc/src/stores/comments-store.d.ts +23028 -552
  152. package/dist/superdoc/src/stores/helpers/comment-document-scope.d.ts +22 -0
  153. package/dist/superdoc/src/stores/helpers/comment-grouping.d.ts +1 -1
  154. package/dist/superdoc/src/stores/helpers/comment-identity.d.ts +10 -10
  155. package/dist/superdoc/src/stores/helpers/pending-selection-snapshot.d.ts +17 -0
  156. package/dist/superdoc/src/stores/helpers/review-presentation.d.ts +91 -0
  157. package/dist/superdoc/src/stores/helpers/tracked-change-compaction.d.ts +16 -0
  158. package/dist/superdoc/src/stores/helpers/tracked-change-decision.d.ts +45 -0
  159. package/dist/superdoc/src/stores/helpers/tracked-change-identity.d.ts +4 -2
  160. package/dist/superdoc/src/stores/helpers/tracked-change-row-values.d.ts +1 -8
  161. package/dist/superdoc/src/stores/helpers/tracked-change-thread-index.d.ts +1 -1
  162. package/dist/superdoc/src/stores/helpers/v2-review-adapters.d.ts +147 -0
  163. package/dist/superdoc/src/stores/superdoc-store.d.ts +12 -2895
  164. package/dist/superdoc.cjs +1330 -972
  165. package/dist/superdoc.es.js +1242 -884
  166. package/dist/word-layout/src/marker-utils.d.ts +0 -5
  167. package/dist/word-layout/src/unit-conversions.d.ts +0 -1
  168. package/dist-cdn/style.layered.css +1 -1
  169. package/dist-cdn/superdoc.min.css +1 -1
  170. package/dist-cdn/superdoc.min.js +38 -42
  171. package/package.json +13 -3
  172. package/dist/document-api/src/diff/index.d.ts +0 -3
  173. package/dist/document-api/src/write/locator.d.ts +0 -24
  174. package/dist/layout-engine/painters/dom/src/features/feature-registry.d.ts +0 -41
  175. package/dist/superdoc/src/internal/toolbar/built-in/format-negation.d.ts +0 -5
  176. package/dist/superdoc/src/main.d.ts +0 -1
  177. package/dist/word-layout/src/tab-layout.d.ts +0 -193
package/dist/superdoc.cjs CHANGED
@@ -1,21 +1,21 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("./chunks/rolldown-runtime-74VwNCz7.cjs");
3
+ const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-BzM2_tVU.cjs");
3
4
  const require_blank_docx = require("./chunks/blank-docx-BuFAbRjs.cjs");
4
- const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-DN70aatf.cjs");
5
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-CvK1JdZv.cjs");
5
6
  const require_eventemitter3 = require("./chunks/eventemitter3-C_TAnXOl.cjs");
6
7
  const require_uuid = require("./chunks/uuid-BhG0ngwk.cjs");
7
- const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-6MBoygIY.cjs");
8
8
  const require_jszip = require("./chunks/jszip-D8mAFF-r.cjs");
9
9
  const require_is_finite_number = require("./chunks/is-finite-number-BEXgTRgc.cjs");
10
10
  const require_constants = require("./chunks/constants-BeeNZoQp.cjs");
11
11
  let superdoc_entry_vue = require("vue");
12
12
  superdoc_entry_vue = require_rolldown_runtime.__toESM(superdoc_entry_vue, 1);
13
13
  let yjs = require("yjs");
14
- //#region src/core/v2-integration/browser-peer-runtime.js
14
+ //#region src/core/v2-integration/browser-peer-runtime.ts
15
15
  var SUPERDOC_V2_BROWSER_RUNTIME_GLOBAL_KEY = "__SUPERDOC_V2_BROWSER_RUNTIME__";
16
16
  function readInstalledRuntime(globalObject = globalThis) {
17
- const installed = globalObject[SUPERDOC_V2_BROWSER_RUNTIME_GLOBAL_KEY];
18
- return installed && typeof installed === "object" ? installed : null;
17
+ const installed = Reflect.get(globalObject, SUPERDOC_V2_BROWSER_RUNTIME_GLOBAL_KEY);
18
+ return require__plugin_vue_export_helper.isPlainObject(installed) ? installed : null;
19
19
  }
20
20
  function installSuperDocV2BrowserRuntime(runtime = {}, globalObject = globalThis) {
21
21
  const installed = readInstalledRuntime(globalObject) ?? {};
@@ -24,7 +24,7 @@ function installSuperDocV2BrowserRuntime(runtime = {}, globalObject = globalThis
24
24
  ...runtime,
25
25
  vue: runtime.vue ?? installed.vue ?? superdoc_entry_vue
26
26
  };
27
- globalObject[SUPERDOC_V2_BROWSER_RUNTIME_GLOBAL_KEY] = nextRuntime;
27
+ Reflect.set(globalObject, SUPERDOC_V2_BROWSER_RUNTIME_GLOBAL_KEY, nextRuntime);
28
28
  return nextRuntime;
29
29
  }
30
30
  installSuperDocV2BrowserRuntime();
@@ -259,7 +259,7 @@ var v_click_outside_default = {
259
259
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
260
260
  function getSuperdocVersion() {
261
261
  try {
262
- return "2.29.0-next.9";
262
+ return "2.30.0-next.13";
263
263
  } catch {
264
264
  return "unknown";
265
265
  }
@@ -5839,22 +5839,27 @@ function useCheckboxField(field) {
5839
5839
  }) : itemoptions) };
5840
5840
  }
5841
5841
  //#endregion
5842
+ //#region src/core/collaboration/collaboration-comment-map.ts
5843
+ function createCollaborationCommentMap(entries) {
5844
+ return new yjs.Map(entries);
5845
+ }
5846
+ //#endregion
5842
5847
  //#region src/core/collaboration/collaboration-comments.ts
5843
5848
  var readComment = (event) => {
5844
5849
  const { comment } = event;
5845
- if (!require_create_super_doc_ui.isPlainObject(comment)) throw new TypeError("Collaboration comment events require a comment object");
5850
+ if (!require__plugin_vue_export_helper.isPlainObject(comment)) throw new TypeError("Collaboration comment events require a comment object");
5846
5851
  return comment;
5847
5852
  };
5848
5853
  var addYComment = (yArray, ydoc, event, user) => {
5849
5854
  const comment = readComment(event);
5850
- const yComment = new yjs.Map(Object.entries(comment));
5855
+ const yComment = createCollaborationCommentMap(Object.entries(comment));
5851
5856
  ydoc.transact(() => {
5852
5857
  yArray.push([yComment]);
5853
5858
  }, { user });
5854
5859
  };
5855
5860
  var updateYComment = (yArray, ydoc, event, user) => {
5856
5861
  const comment = readComment(event);
5857
- const yComment = new yjs.Map(Object.entries(comment));
5862
+ const yComment = createCollaborationCommentMap(Object.entries(comment));
5858
5863
  const commentIndex = getCommentIndex(yArray, comment);
5859
5864
  if (commentIndex === -1) return;
5860
5865
  ydoc.transact(() => {
@@ -5870,12 +5875,12 @@ var deleteYComment = (yArray, ydoc, event, user) => {
5870
5875
  }, { user });
5871
5876
  };
5872
5877
  var getCommentIndex = (yArray, comment) => {
5873
- return yArray.toJSON().findIndex((c) => require_create_super_doc_ui.isPlainObject(c) && c.commentId === comment.commentId);
5878
+ return yArray.toJSON().findIndex((c) => require__plugin_vue_export_helper.isPlainObject(c) && c.commentId === comment.commentId);
5874
5879
  };
5875
5880
  //#endregion
5876
5881
  //#region src/core/collaboration/helpers.ts
5877
5882
  var isPropertyBag = (value) => typeof value === "object" && value !== null || typeof value === "function";
5878
- var readCommentsStore = (superdoc) => superdoc["commentsStore"];
5883
+ var readCommentsStore$1 = (superdoc) => superdoc["commentsStore"];
5879
5884
  var isV2ReviewRuntimeActive = (superdoc) => superdoc.activeEditor?.editorVersion === 2 || superdoc.editorVersion === 2;
5880
5885
  var commentKey = (comment) => {
5881
5886
  const key = comment.commentId ?? comment.importedId;
@@ -5894,7 +5899,7 @@ var preserveLocalV2TrackedChangeRows = (superdoc, commentsStore, incomingComment
5894
5899
  };
5895
5900
  var loadCommentsFromYdoc = (superdoc) => {
5896
5901
  if (!superdoc?.ydoc) return false;
5897
- const commentsStore = readCommentsStore(superdoc);
5902
+ const commentsStore = readCommentsStore$1(superdoc);
5898
5903
  if (!commentsStore) return false;
5899
5904
  const comments = superdoc.ydoc.getArray("comments").toJSON();
5900
5905
  const seenCommentIdByKey = /* @__PURE__ */ new Map();
@@ -5940,7 +5945,7 @@ var initCollaborationComments = (superdoc) => {
5940
5945
  const updateCommentsStore = () => loadCommentsFromYdoc(superdoc);
5941
5946
  const onSuperDocYdocSynced = () => {
5942
5947
  if (!updateCommentsStore()) setTimeout(updateCommentsStore, 0);
5943
- const commentsStore = readCommentsStore(superdoc);
5948
+ const commentsStore = readCommentsStore$1(superdoc);
5944
5949
  if (commentsStore) commentsStore.hasSyncedCollaborationComments = true;
5945
5950
  const currentProvider = superdoc.provider;
5946
5951
  if (!currentProvider) throw new TypeError("initCollaborationComments requires superdoc.provider");
@@ -5952,7 +5957,7 @@ var initCollaborationComments = (superdoc) => {
5952
5957
  provider.on("synced", onSuperDocYdocSynced);
5953
5958
  if (!updateCommentsStore()) setTimeout(updateCommentsStore, 0);
5954
5959
  commentsArray.observe((event) => {
5955
- if (!readCommentsStore(superdoc)) return;
5960
+ if (!readCommentsStore$1(superdoc)) return;
5956
5961
  const currentUser = superdoc.config.user;
5957
5962
  const origin = event?.transaction?.origin;
5958
5963
  const originUser = isPropertyBag(origin) ? origin.user : null;
@@ -6751,6 +6756,136 @@ var useSuperdocStore = defineStore("superdoc", () => {
6751
6756
  };
6752
6757
  });
6753
6758
  //#endregion
6759
+ //#region ../document-api/src/errors.ts
6760
+ /**
6761
+ * Structured validation error thrown by document-api execute* functions.
6762
+ *
6763
+ * Consumers should prefer checking `error.code` over `instanceof` for resilience
6764
+ * across package boundaries and bundling scenarios.
6765
+ */
6766
+ var DocumentApiValidationError = class DocumentApiValidationError extends Error {
6767
+ constructor(code, message, details) {
6768
+ super(message);
6769
+ this.name = "DocumentApiValidationError";
6770
+ this.code = code;
6771
+ this.details = details;
6772
+ Object.setPrototypeOf(this, DocumentApiValidationError.prototype);
6773
+ }
6774
+ };
6775
+ //#endregion
6776
+ //#region ../document-api/src/export/export.types.ts
6777
+ /** Canonical tracked-change export modes accepted by every public export surface. */
6778
+ var SD_EXPORT_MODES = [
6779
+ "review-preserving",
6780
+ "final",
6781
+ "original"
6782
+ ];
6783
+ /** Default mode for modeful DOCX export. */
6784
+ var DEFAULT_SD_EXPORT_MODE = "review-preserving";
6785
+ var SD_COMMENT_EXPORT_POLICIES = [
6786
+ "preserve",
6787
+ "resolve",
6788
+ "remove"
6789
+ ];
6790
+ var SD_CONTENT_CONTROL_EXPORT_POLICIES = ["preserve", "flatten"];
6791
+ //#endregion
6792
+ //#region ../document-api/src/export/export.ts
6793
+ /**
6794
+ * Export namespace: engine-agnostic public API and adapter contract.
6795
+ *
6796
+ * Validates the requested mode at the public boundary so an invalid mode fails
6797
+ * closed with `INVALID_INPUT` before any document work happens, then delegates
6798
+ * byte production and degradation reporting to the engine adapter.
6799
+ */
6800
+ function resolveMode$1(input) {
6801
+ if (input != null && !require_create_super_doc_ui.isRecord(input)) throw new DocumentApiValidationError("INVALID_INPUT", "export.toDocx input must be an object.");
6802
+ const raw = input?.mode;
6803
+ if (raw === void 0) return DEFAULT_SD_EXPORT_MODE;
6804
+ 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(", ")}.`, {
6805
+ mode: raw,
6806
+ allowedModes: [...SD_EXPORT_MODES]
6807
+ });
6808
+ return raw;
6809
+ }
6810
+ function resolveDocxExportPolicies(input = {}) {
6811
+ if (!require_create_super_doc_ui.isRecord(input)) throw new DocumentApiValidationError("INVALID_INPUT", "DOCX export input must be an object.");
6812
+ const mode = resolveMode$1(input);
6813
+ const policies = input.policies;
6814
+ if (policies !== void 0 && !require_create_super_doc_ui.isRecord(policies)) throw new DocumentApiValidationError("INVALID_INPUT", "DOCX export policies must be an object.");
6815
+ const allowed = {
6816
+ trackedChanges: SD_EXPORT_MODES,
6817
+ comments: SD_COMMENT_EXPORT_POLICIES,
6818
+ contentControls: SD_CONTENT_CONTROL_EXPORT_POLICIES
6819
+ };
6820
+ 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}.`, {
6821
+ policy: key,
6822
+ value
6823
+ });
6824
+ const requested = policies;
6825
+ if (input.mode !== void 0 && requested?.trackedChanges !== void 0 && mode !== requested.trackedChanges) throw new DocumentApiValidationError("INVALID_INPUT", "mode conflicts with policies.trackedChanges.");
6826
+ return {
6827
+ trackedChanges: requested?.trackedChanges ?? mode,
6828
+ comments: requested?.comments ?? "preserve",
6829
+ contentControls: requested?.contentControls ?? "preserve"
6830
+ };
6831
+ }
6832
+ new TextEncoder();
6833
+ function normalizeCommentIdentity(value) {
6834
+ if (value === null) return null;
6835
+ if (typeof value !== "object" || Array.isArray(value) || !("providerId" in value) || !("userId" in value) || !xmlIdentityString(value.providerId) || !xmlIdentityString(value.userId)) throw new TypeError("commentIdentity requires XML-safe non-empty providerId and userId strings.");
6836
+ return {
6837
+ providerId: value.providerId,
6838
+ userId: value.userId
6839
+ };
6840
+ }
6841
+ function xmlIdentityString(value) {
6842
+ return typeof value === "string" && value.trim().length > 0 && !/[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/u.test(value);
6843
+ }
6844
+ //#endregion
6845
+ //#region ../document-api/src/permission-ranges/permission-ranges.ts
6846
+ function editorKey(editor) {
6847
+ return editor.id?.trim() ? editor.id : editor.email?.trim() || void 0;
6848
+ }
6849
+ function editorMatches(editor, id) {
6850
+ return Boolean(id.trim()) && (editor.id === id || Boolean(editor.email?.trim() && editor.email.trim().toLowerCase() === id.toLowerCase()));
6851
+ }
6852
+ /**
6853
+ * Resolve a host ID or imported Word email against an explicitly supplied roster.
6854
+ * Word receives the email when available; opaque IDs remain host-specific.
6855
+ * Duplicate IDs/emails are ambiguous. This does not authenticate a user.
6856
+ */
6857
+ function resolvePermissionRangeEditor(editors, id) {
6858
+ const matches = editors.filter((editor) => editorMatches(editor, id));
6859
+ if (matches.length === 0) return {
6860
+ status: "unknown",
6861
+ id
6862
+ };
6863
+ if (matches.length !== 1) return {
6864
+ status: "ambiguous",
6865
+ id
6866
+ };
6867
+ const editor = matches[0];
6868
+ const wordId = editor.email?.trim() || editor.id;
6869
+ if (editors.filter((candidate) => editorMatches(candidate, wordId)).length !== 1) return {
6870
+ status: "ambiguous",
6871
+ id
6872
+ };
6873
+ return {
6874
+ status: "resolved",
6875
+ id,
6876
+ editor: { ...editor },
6877
+ principal: {
6878
+ kind: "editor",
6879
+ id: wordId
6880
+ }
6881
+ };
6882
+ }
6883
+ /** Enumerate the host roster for an editor picker, including ambiguous entries. */
6884
+ function listPermissionRangeEditors(editors) {
6885
+ const ids = new Set(editors.map(editorKey).filter((id) => id !== void 0));
6886
+ return Array.from(ids, (id) => resolvePermissionRangeEditor(editors, id));
6887
+ }
6888
+ //#endregion
6754
6889
  //#region src/stores/helpers/floating-comment-instances.ts
6755
6890
  var HEADER_FOOTER_TRACKED_CHANGE_STORY_TYPE = "headerFooterPart";
6756
6891
  var toFinitePageIndex = (value) => {
@@ -6810,7 +6945,7 @@ var groupRectsByPage = (rects) => {
6810
6945
  }));
6811
6946
  };
6812
6947
  var readStoryType = (story) => {
6813
- return require_create_super_doc_ui.isPlainObject(story) ? story.storyType : void 0;
6948
+ return require__plugin_vue_export_helper.isPlainObject(story) ? story.storyType : void 0;
6814
6949
  };
6815
6950
  var isRepeatedHeaderFooterTrackedChange = (comment, positionEntry) => {
6816
6951
  if (!comment?.trackedChange) return false;
@@ -6891,23 +7026,76 @@ var buildFloatingCommentInstances = ({ comment, positionKey, positionEntry, fall
6891
7026
  })];
6892
7027
  };
6893
7028
  //#endregion
6894
- //#region src/components/CommentsLayer/tracked-change-threading.js
7029
+ //#region src/stores/helpers/comment-document-scope.ts
7030
+ var getCommentDocumentId = (comment) => {
7031
+ if (!comment) return null;
7032
+ if (comment.fileId != null) return String(comment.fileId);
7033
+ if (comment.documentId != null) return String(comment.documentId);
7034
+ if (comment.selection?.documentId != null) return String(comment.selection.documentId);
7035
+ return null;
7036
+ };
7037
+ var createCommentDocumentScope = (readOpenDocuments) => {
7038
+ const getOpenDocuments = () => {
7039
+ const source = readOpenDocuments();
7040
+ const docs = Array.isArray(source) ? source : source?.value;
7041
+ return Array.isArray(docs) ? docs : [];
7042
+ };
7043
+ const getSingleOpenDocumentId = () => {
7044
+ const docs = getOpenDocuments();
7045
+ if (docs.length !== 1) return null;
7046
+ return docs[0]?.id != null ? String(docs[0].id) : null;
7047
+ };
7048
+ const belongsToDocument = (comment, activeDocumentId, options = {}) => {
7049
+ const { allowSingleDocumentMismatch = false } = options;
7050
+ if (!activeDocumentId) return false;
7051
+ const commentDocumentId = getCommentDocumentId(comment);
7052
+ if (commentDocumentId) {
7053
+ if (commentDocumentId === activeDocumentId) return true;
7054
+ const singleOpenDocumentId = getSingleOpenDocumentId();
7055
+ return allowSingleDocumentMismatch && singleOpenDocumentId === activeDocumentId;
7056
+ }
7057
+ return getSingleOpenDocumentId() === activeDocumentId;
7058
+ };
7059
+ const belongsToTrackedChangeSyncDocument = (comment, activeDocumentId) => belongsToDocument(comment, activeDocumentId, { allowSingleDocumentMismatch: true });
7060
+ return {
7061
+ belongsToDocument,
7062
+ belongsToTrackedChangeSyncDocument
7063
+ };
7064
+ };
7065
+ //#endregion
7066
+ //#region src/stores/helpers/pending-selection-snapshot.ts
7067
+ var isThenable = (value) => (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
7068
+ var getPendingSelectionSnapshot = (superdoc, activeSelection) => {
7069
+ if (activeSelection?.source !== "document-editor") return null;
7070
+ const selectionDocumentId = activeSelection?.documentId ?? null;
7071
+ const editorDocumentId = superdoc?.activeEditor?.options?.documentId ?? null;
7072
+ if (!selectionDocumentId || !editorDocumentId || selectionDocumentId !== editorDocumentId) return null;
7073
+ let currentSelection;
7074
+ try {
7075
+ currentSelection = superdoc?.activeEditor?.doc?.selection?.current;
7076
+ } catch {
7077
+ return null;
7078
+ }
7079
+ if (typeof currentSelection !== "function") return null;
7080
+ try {
7081
+ const snapshot = currentSelection();
7082
+ return isThenable(snapshot) ? Promise.resolve(snapshot).catch(() => null) : snapshot;
7083
+ } catch {
7084
+ return null;
7085
+ }
7086
+ };
7087
+ //#endregion
7088
+ //#region src/components/CommentsLayer/tracked-change-threading.ts
6895
7089
  /**
6896
7090
  * Legacy comment payloads predate explicit tracked-change thread provenance.
6897
7091
  * These fields distinguish a true legacy review child from a v2 comment whose
6898
7092
  * anchor merely overlaps tracked content.
6899
- *
6900
- * @param {Record<string, any> | null | undefined} comment
6901
- * @returns {boolean}
6902
7093
  */
6903
7094
  var hasLegacyTrackedChangeThreadSignal = (comment) => Boolean(comment?.trackedChangeLink) || Boolean(comment?.trackedChangeType) || Boolean(comment?.trackedChangeDisplayType) || Boolean(comment?.trackedChangeText) || Boolean(comment?.deletedText) || comment?.trackedChange === true;
6904
7095
  /**
6905
7096
  * Resolve explicit thread provenance first, then the guarded legacy fallback.
6906
7097
  * Spatial-only v2 comments carry neither the explicit field nor a legacy
6907
7098
  * review signal and therefore remain standalone.
6908
- *
6909
- * @param {Record<string, any> | null | undefined} comment
6910
- * @returns {string | number | null}
6911
7099
  */
6912
7100
  var trackedChangeThreadParentIdForComment$1 = (comment) => {
6913
7101
  if (comment?.trackedChangeThreadParentId != null) return comment.trackedChangeThreadParentId;
@@ -7059,6 +7247,7 @@ var groupCommittedComments = (comments, presentations, isVisible) => {
7059
7247
  });
7060
7248
  const grouped = groupComments(comments.filter((row) => !presentations[String(row.fileId)]), isVisible);
7061
7249
  for (const [documentId, presentation] of Object.entries(presentations)) {
7250
+ if (!presentation) continue;
7062
7251
  grouped.parentComments.push(...visibleRowsInOrder(documentId, presentation.groupOrder.open));
7063
7252
  grouped.resolvedComments.push(...visibleRowsInOrder(documentId, presentation.groupOrder.resolved));
7064
7253
  }
@@ -7096,7 +7285,7 @@ async function loadDefaultV2IntegrationOrFallback() {
7096
7285
  }
7097
7286
  var V2_BODY_TRACKED_CHANGE_ANCHOR_PREFIX = "tc::body::";
7098
7287
  function isV2SyntheticTrackedChangeRow(row) {
7099
- if (!require_create_super_doc_ui.isPlainObject(row) || row.trackedChange !== true) return false;
7288
+ if (!require__plugin_vue_export_helper.isPlainObject(row) || row.trackedChange !== true) return false;
7100
7289
  const anchorKey = row.trackedChangeAnchorKey;
7101
7290
  return typeof anchorKey === "string" && anchorKey.startsWith(V2_BODY_TRACKED_CHANGE_ANCHOR_PREFIX);
7102
7291
  }
@@ -7160,7 +7349,7 @@ function createStubV2Integration() {
7160
7349
  }
7161
7350
  function adoptEngineIntegration(engineIntegration) {
7162
7351
  const stub = createStubV2Integration();
7163
- if (!require_create_super_doc_ui.isPlainObject(engineIntegration) || !engineIntegration.EditorComponent) return stub;
7352
+ if (!require__plugin_vue_export_helper.isPlainObject(engineIntegration) || !engineIntegration.EditorComponent) return stub;
7164
7353
  const engine = engineIntegration;
7165
7354
  return {
7166
7355
  version: typeof engine.version === "number" ? engine.version : stub.version,
@@ -7186,7 +7375,6 @@ function createDefaultV2Integration() {
7186
7375
  //#region src/helpers/interaction-trace.ts
7187
7376
  var isStartSpan = (value) => typeof value === "function";
7188
7377
  var isEndSpan = (value) => typeof value === "function";
7189
- var isThenable$3 = (value) => (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
7190
7378
  function safeTraceCollector() {
7191
7379
  try {
7192
7380
  const collector = Reflect.get(globalThis, "__superdocInteractionTrace");
@@ -7217,7 +7405,7 @@ function withInteractionSpan(stage, branch, meta, fn) {
7217
7405
  if (!span) return fn();
7218
7406
  try {
7219
7407
  const result = fn();
7220
- if (isThenable$3(result)) return result.then((value) => {
7408
+ if (require__plugin_vue_export_helper.isThenable(result)) return result.then((value) => {
7221
7409
  endInteractionSpan(span);
7222
7410
  return value;
7223
7411
  }, (error) => {
@@ -7232,6 +7420,81 @@ function withInteractionSpan(stage, branch, meta, fn) {
7232
7420
  }
7233
7421
  }
7234
7422
  //#endregion
7423
+ //#region src/stores/helpers/tracked-change-decision.ts
7424
+ var normalizeTrackedChangeDecisionType = (value) => {
7425
+ const lower = typeof value === "string" ? value.toLowerCase() : "";
7426
+ if (!lower) return null;
7427
+ if (lower === "insert" || lower === "insertion" || lower === "trackinsert" || lower === "tableinsert" || lower === "paragraphsplit") return "insertion";
7428
+ if (lower === "delete" || lower === "deletion" || lower === "trackdelete" || lower === "tabledelete") return "deletion";
7429
+ return lower;
7430
+ };
7431
+ var trackedChangeDecisionKeepsCommentAnchor = ({ comment, decision } = {}) => {
7432
+ const normalizedDecision = decision === "accept" || decision === "reject" ? decision : null;
7433
+ if (!normalizedDecision) return false;
7434
+ const type = normalizeTrackedChangeDecisionType(comment?.trackedChangeDisplayType) ?? normalizeTrackedChangeDecisionType(comment?.trackedChangeType);
7435
+ return normalizedDecision === "accept" && type === "insertion" || normalizedDecision === "reject" && type === "deletion";
7436
+ };
7437
+ var collectTrackedChangeDecisionIdsWithAliases = (comment, aliasIds) => {
7438
+ const trackedChangeIds = new Set(aliasIds);
7439
+ if (comment?.trackedChangeCanonicalId != null) trackedChangeIds.add(String(comment.trackedChangeCanonicalId));
7440
+ const anchorKey = comment?.trackedChangeAnchorKey != null ? String(comment.trackedChangeAnchorKey) : null;
7441
+ if (anchorKey) {
7442
+ trackedChangeIds.add(anchorKey);
7443
+ if (anchorKey.startsWith("tc::")) {
7444
+ const rawId = anchorKey.slice(anchorKey.lastIndexOf("::") + 2);
7445
+ if (rawId) trackedChangeIds.add(rawId);
7446
+ }
7447
+ }
7448
+ return trackedChangeIds;
7449
+ };
7450
+ var collectTrackedChangeEntityIdsFromReceipt = (receipt) => {
7451
+ const record = receipt && typeof receipt === "object" ? receipt : null;
7452
+ if (!record?.success) return /* @__PURE__ */ new Set();
7453
+ const ids = /* @__PURE__ */ new Set();
7454
+ const collect = (entry) => {
7455
+ const ref = entry && typeof entry === "object" ? entry : null;
7456
+ if (ref?.kind !== "entity" || ref.entityType !== "trackedChange") return;
7457
+ if (ref.entityId != null && String(ref.entityId).length > 0) ids.add(String(ref.entityId));
7458
+ };
7459
+ if (Array.isArray(record.removed)) record.removed.forEach(collect);
7460
+ if (Array.isArray(record.invalidatedRefs)) record.invalidatedRefs.forEach(collect);
7461
+ return ids;
7462
+ };
7463
+ var collectReliableDecidedTrackedChangeIds = (outcome) => {
7464
+ const ids = /* @__PURE__ */ new Set();
7465
+ if (outcome?.decidedId != null && String(outcome.decidedId).length > 0) ids.add(String(outcome.decidedId));
7466
+ if (Array.isArray(outcome?.decidedIds)) outcome.decidedIds.forEach((id) => {
7467
+ if (id != null && String(id).length > 0) ids.add(String(id));
7468
+ });
7469
+ collectTrackedChangeEntityIdsFromReceipt(outcome?.receipt).forEach((id) => ids.add(id));
7470
+ return ids;
7471
+ };
7472
+ var clearV2ActiveTrackedChangeTarget = (adapter, decidedId) => {
7473
+ if (!decidedId || typeof adapter?.clearActiveTrackedChangeTargetIfMatches !== "function") return;
7474
+ try {
7475
+ adapter.clearActiveTrackedChangeTargetIfMatches(decidedId);
7476
+ } catch {}
7477
+ };
7478
+ var waitForTrackedDecisionCanonicalPaint = async ({ superdoc, receipt } = {}) => {
7479
+ const readiness = superdoc?.activeEditor?.documentMutationReadiness;
7480
+ if (receipt?.success !== true || typeof receipt?.txId !== "string" || !receipt.txId || typeof readiness?.whenPainted !== "function") return;
7481
+ try {
7482
+ await readiness.whenPainted(receipt);
7483
+ const requestFrame = globalThis.requestAnimationFrame;
7484
+ if (typeof requestFrame === "function") await new Promise((resolve) => {
7485
+ let settled = false;
7486
+ const finish = () => {
7487
+ if (settled) return;
7488
+ settled = true;
7489
+ clearTimeout(fallback);
7490
+ resolve();
7491
+ };
7492
+ const fallback = setTimeout(finish, 250);
7493
+ requestFrame(() => requestFrame(() => setTimeout(finish, 0)));
7494
+ });
7495
+ } catch {}
7496
+ };
7497
+ //#endregion
7235
7498
  //#region src/stores/helpers/comment-draft-text.ts
7236
7499
  var COMMENT_DRAFT_BR_TAG = /<br(?:\s[^>]*)?\s*\/?>/gi;
7237
7500
  var COMMENT_DRAFT_BLOCK_BOUNDARY = /(?:<\/(?:p|div|li|blockquote|pre|h[1-6])\s*>\s*)+(?:<(?:p|div|li|blockquote|pre|h[1-6])(?:\s[^>]*)?\s*\/?>)+/gi;
@@ -7276,12 +7539,12 @@ var BODY_TRACKED_CHANGE_STORY = {
7276
7539
  };
7277
7540
  var normalizeCommentId = (id) => id === void 0 || id === null ? null : String(id);
7278
7541
  var isNonEmptyString$2 = (value) => Boolean(value);
7279
- var trackedChangeFields = (comment) => require_create_super_doc_ui.isPlainObject(comment) && comment.trackedChange ? comment : null;
7542
+ var trackedChangeFields = (comment) => require__plugin_vue_export_helper.isPlainObject(comment) && comment.trackedChange ? comment : null;
7280
7543
  var makeTrackedChangeAnchorKey = ({ storyKey, rawId }) => `tc::${storyKey}::${rawId}`;
7281
7544
  var isBodyTrackedChangeComment = (comment) => {
7282
7545
  const fields = trackedChangeFields(comment);
7283
7546
  if (!fields) return false;
7284
- const storyType = require_create_super_doc_ui.isPlainObject(fields.trackedChangeStory) ? fields.trackedChangeStory.storyType : void 0;
7547
+ const storyType = require__plugin_vue_export_helper.isPlainObject(fields.trackedChangeStory) ? fields.trackedChangeStory.storyType : void 0;
7285
7548
  if (storyType == null || storyType === "body") return true;
7286
7549
  const anchorKey = fields.trackedChangeAnchorKey;
7287
7550
  return typeof anchorKey === "string" && anchorKey.startsWith("tc::body::");
@@ -7324,7 +7587,7 @@ var getTrackedChangeStoryKey = (comment) => {
7324
7587
  const anchorParts = parseTrackedChangeAnchorKey(fields.trackedChangeAnchorKey);
7325
7588
  if (anchorParts) return anchorParts.storyKey;
7326
7589
  const story = fields.trackedChangeStory;
7327
- if (!require_create_super_doc_ui.isPlainObject(story)) return null;
7590
+ if (!require__plugin_vue_export_helper.isPlainObject(story)) return null;
7328
7591
  switch (story.storyType) {
7329
7592
  case "body": return "body";
7330
7593
  case "headerFooterPart": return storyIdKey("hf", story.refId);
@@ -7345,7 +7608,7 @@ var trackedChangeStoryKeysAreCompatible = (leftStoryKey, rightStoryKey) => {
7345
7608
  return !left || !right || left === right;
7346
7609
  };
7347
7610
  var positionEntryMatchesTrackedChangeStory = (entry, comment) => {
7348
- return trackedChangeStoryKeysAreCompatible(normalizeTrackedChangeStoryKey(getTrackedChangeStoryKey(comment)), normalizeTrackedChangeStoryKey(normalizeCommentId(require_create_super_doc_ui.isPlainObject(entry) ? entry.storyKey : null)));
7611
+ return trackedChangeStoryKeysAreCompatible(normalizeTrackedChangeStoryKey(getTrackedChangeStoryKey(comment)), normalizeTrackedChangeStoryKey(normalizeCommentId(require__plugin_vue_export_helper.isPlainObject(entry) ? entry.storyKey : null)));
7349
7612
  };
7350
7613
  var buildTrackedChangeImportedPositionId = (id) => {
7351
7614
  const normalizedId = normalizeCommentId(id);
@@ -7542,7 +7805,7 @@ var createCommentIdentity = ({ getComments, getReviewDirectory, getPositions })
7542
7805
  };
7543
7806
  //#endregion
7544
7807
  //#region src/stores/helpers/tracked-change-row-values.ts
7545
- var isObjectOrArray = (value) => require_create_super_doc_ui.isPlainObject(value) || Array.isArray(value);
7808
+ var isObjectOrArray = (value) => require__plugin_vue_export_helper.isPlainObject(value) || Array.isArray(value);
7546
7809
  var stringOrEmpty = (value) => typeof value === "string" ? value : "";
7547
7810
  var shallowEqual = (a, b) => {
7548
7811
  if (Object.is(a, b)) return true;
@@ -7604,9 +7867,131 @@ var cloneV2TrackedChangeStory = (story) => {
7604
7867
  };
7605
7868
  };
7606
7869
  //#endregion
7607
- //#region src/stores/comments-store.js
7870
+ //#region src/stores/helpers/tracked-change-compaction.ts
7871
+ var isPresentId = (id) => Boolean(id);
7872
+ var getBodyTrackedChangeIdentityIds = (comment) => {
7873
+ return [normalizeCommentId(comment.commentId), ...!normalizeCommentId(comment.trackedChangeCanonicalId) ? [
7874
+ comment.importedId,
7875
+ comment.trackedChangeAnchorKey,
7876
+ ...normalizeTrackedChangePositionAliases(comment.trackedChangePositionAliases)
7877
+ ] : []].map((id) => normalizeCommentId(id)).filter(isPresentId);
7878
+ };
7879
+ var groupBodyTrackedChangeCommentsByIdentity = (comments) => {
7880
+ const parents = comments.map((_, index) => index);
7881
+ const findRoot = (index) => {
7882
+ let root = index;
7883
+ while (parents[root] !== root) root = parents[root];
7884
+ while (parents[index] !== index) {
7885
+ const next = parents[index];
7886
+ parents[index] = root;
7887
+ index = next;
7888
+ }
7889
+ return root;
7890
+ };
7891
+ const join = (left, right) => {
7892
+ const leftRoot = findRoot(left);
7893
+ const rightRoot = findRoot(right);
7894
+ if (leftRoot === rightRoot) return;
7895
+ parents[Math.max(leftRoot, rightRoot)] = Math.min(leftRoot, rightRoot);
7896
+ };
7897
+ const identityOwner = /* @__PURE__ */ new Map();
7898
+ comments.forEach((comment, index) => {
7899
+ getBodyTrackedChangeIdentityIds(comment).forEach((identityId) => {
7900
+ const owner = identityOwner.get(identityId);
7901
+ if (owner === void 0) identityOwner.set(identityId, index);
7902
+ else join(index, owner);
7903
+ });
7904
+ });
7905
+ const groups = /* @__PURE__ */ new Map();
7906
+ comments.forEach((comment, index) => {
7907
+ const root = findRoot(index);
7908
+ const group = groups.get(root) ?? [];
7909
+ group.push(comment);
7910
+ groups.set(root, group);
7911
+ });
7912
+ return groups;
7913
+ };
7914
+ var mergeDuplicateBodyTrackedChangeComments = (groups) => {
7915
+ const duplicates = /* @__PURE__ */ new Map();
7916
+ groups.forEach(([survivor, ...duplicateRows]) => {
7917
+ if (!survivor || duplicateRows.length === 0) return;
7918
+ const resolvedDuplicate = duplicateRows.find((comment) => comment.resolvedTime != null);
7919
+ if (survivor.resolvedTime == null && resolvedDuplicate) {
7920
+ survivor.resolvedTime = resolvedDuplicate.resolvedTime;
7921
+ survivor.resolvedById = resolvedDuplicate.resolvedById;
7922
+ survivor.resolvedByEmail = resolvedDuplicate.resolvedByEmail;
7923
+ survivor.resolvedByName = resolvedDuplicate.resolvedByName;
7924
+ survivor.trackedChangeDecision = resolvedDuplicate.trackedChangeDecision;
7925
+ }
7926
+ survivor.trackedChangePositionAliases = normalizeTrackedChangePositionAliases([...normalizeTrackedChangePositionAliases(survivor.trackedChangePositionAliases), ...duplicateRows.flatMap((comment) => [
7927
+ comment.commentId,
7928
+ comment.importedId,
7929
+ comment.trackedChangeCanonicalId,
7930
+ ...normalizeTrackedChangePositionAliases(comment.trackedChangePositionAliases)
7931
+ ])]);
7932
+ duplicateRows.forEach((comment) => duplicates.set(comment, survivor));
7933
+ });
7934
+ return duplicates;
7935
+ };
7936
+ var createDroppedCommentIdMap = (duplicates) => {
7937
+ const droppedCommentIds = /* @__PURE__ */ new Map();
7938
+ duplicates.forEach((survivor, duplicate) => {
7939
+ const fromId = normalizeCommentId(duplicate.commentId);
7940
+ const toId = normalizeCommentId(survivor.commentId);
7941
+ if (fromId && toId) droppedCommentIds.set(fromId, toId);
7942
+ });
7943
+ return droppedCommentIds;
7944
+ };
7945
+ //#endregion
7946
+ //#region src/stores/helpers/v2-review-adapters.ts
7947
+ var COMMENTS_ADAPTER_METHODS = [
7948
+ "setActiveComment",
7949
+ "commitPendingComment",
7950
+ "reply",
7951
+ "edit",
7952
+ "resolve",
7953
+ "reopen",
7954
+ "delete",
7955
+ "mapV2CommentToUseCommentInput"
7956
+ ];
7957
+ var COMMENTS_ADAPTER_OPTIONAL_METHODS = [
7958
+ "getCapabilityState",
7959
+ "captureCurrentSelection",
7960
+ "isPendingCommentCreation",
7961
+ "seedReviewCatalog",
7962
+ "selectVisibleReviewComments"
7963
+ ];
7964
+ var TRACKED_CHANGES_ADAPTER_METHODS = [
7965
+ "accept",
7966
+ "reject",
7967
+ "mapV2TrackedChangeToCommentParams"
7968
+ ];
7969
+ var TRACKED_CHANGES_ADAPTER_OPTIONAL_METHODS = ["clearActiveTrackedChangeTargetIfMatches"];
7970
+ var isAdapterDocumentId = (value) => value === void 0 || value === null || typeof value === "string" || typeof value === "number";
7971
+ var hasAdapterShape = (value, required, optional) => require__plugin_vue_export_helper.isPlainObject(value) && isAdapterDocumentId(value.documentId) && required.every((member) => typeof value[member] === "function") && optional.every((member) => value[member] === void 0 || typeof value[member] === "function");
7972
+ function isV2CommentsAdapter(value) {
7973
+ return hasAdapterShape(value, COMMENTS_ADAPTER_METHODS, COMMENTS_ADAPTER_OPTIONAL_METHODS);
7974
+ }
7975
+ function isV2TrackedChangesAdapter(value) {
7976
+ return hasAdapterShape(value, TRACKED_CHANGES_ADAPTER_METHODS, TRACKED_CHANGES_ADAPTER_OPTIONAL_METHODS);
7977
+ }
7978
+ //#endregion
7979
+ //#region src/stores/comments-store.ts
7980
+ var requireHost = (superdoc, action) => {
7981
+ if (!superdoc) throw new TypeError(`${action} requires superdoc`);
7982
+ return superdoc;
7983
+ };
7984
+ var PARENT_LINK_FIELDS = [
7985
+ "trackedChangeThreadParentId",
7986
+ "trackedChangeParentId",
7987
+ "threadingParentCommentId",
7988
+ "parentCommentId"
7989
+ ];
7990
+ var isPresent = (value) => Boolean(value);
7991
+ var errorDetail = (error) => (error == null ? void 0 : Reflect.get(Object(error), "message")) ?? String(error);
7608
7992
  var useCommentsStore = defineStore("comments", () => {
7609
7993
  const superdocStore = useSuperdocStore();
7994
+ const findDocument = (documentId) => typeof documentId === "string" ? superdocStore.getDocument(documentId) : void 0;
7610
7995
  const commentsConfig = require__plugin_vue_export_helper.reactive({
7611
7996
  name: "comments",
7612
7997
  readOnly: false,
@@ -7636,6 +8021,7 @@ var useCommentsStore = defineStore("comments", () => {
7636
8021
  });
7637
8022
  const debounceTimers = {};
7638
8023
  const trackedChangeResolutionSnapshots = /* @__PURE__ */ new WeakMap();
8024
+ let cachedTrackedChangeBatchIdentityIndex = null;
7639
8025
  const isBenchmarkCommentsDebugEnabled = () => {
7640
8026
  if (typeof window === "undefined") return false;
7641
8027
  return "__labsSuperDocV2BenchmarkDebug" in window;
@@ -7673,7 +8059,7 @@ var useCommentsStore = defineStore("comments", () => {
7673
8059
  });
7674
8060
  const getTrackedChangeThread = (parentComment) => {
7675
8061
  const id = parentComment?.commentId ?? null;
7676
- return (id != null ? trackedChangeThreadIndex.value.get(id) : null) ?? [parentComment].filter(Boolean);
8062
+ return (id != null ? trackedChangeThreadIndex.value.get(id) : null) ?? (parentComment ? [parentComment] : []);
7677
8063
  };
7678
8064
  let priorTrackedChangeDecisionLinkIndex = /* @__PURE__ */ new Map();
7679
8065
  const trackedChangeDecisionLinkIndex = require__plugin_vue_export_helper.computed(() => {
@@ -7705,29 +8091,28 @@ var useCommentsStore = defineStore("comments", () => {
7705
8091
  });
7706
8092
  const v2CommentsAdapter = require__plugin_vue_export_helper.shallowRef(null);
7707
8093
  const setV2CommentsAdapter = (adapter) => {
7708
- if (v2CommentsAdapter.value !== (adapter ?? null)) pendingCommentRequest += 1;
7709
- v2CommentsAdapter.value = adapter ?? null;
8094
+ const next = isV2CommentsAdapter(adapter) ? adapter : null;
8095
+ if (v2CommentsAdapter.value !== next) pendingCommentRequest += 1;
8096
+ v2CommentsAdapter.value = next;
7710
8097
  };
7711
8098
  const getV2CommentsAdapter = (superdoc) => {
7712
- const fromFacade = superdoc?.activeEditor?.v2Comments ?? null;
7713
- if (fromFacade) return fromFacade;
8099
+ const fromFacade = superdoc?.activeEditor?.v2Comments;
8100
+ if (isV2CommentsAdapter(fromFacade)) return fromFacade;
7714
8101
  return v2CommentsAdapter.value;
7715
8102
  };
7716
8103
  const isV2EditorActive = (superdoc) => superdoc?.activeEditor?.editorVersion === 2 || v2CommentsAdapter.value !== null;
7717
8104
  const v2TrackedChangesAdapter = require__plugin_vue_export_helper.shallowRef(null);
7718
8105
  const setV2TrackedChangesAdapter = (adapter) => {
7719
- v2TrackedChangesAdapter.value = adapter ?? null;
8106
+ cachedTrackedChangeBatchIdentityIndex = null;
8107
+ v2TrackedChangesAdapter.value = isV2TrackedChangesAdapter(adapter) ? adapter : null;
7720
8108
  };
7721
8109
  const getV2TrackedChangesAdapter = (superdoc) => {
7722
- const fromFacade = superdoc?.activeEditor?.v2TrackedChanges ?? null;
7723
- if (fromFacade) return fromFacade;
8110
+ const fromFacade = superdoc?.activeEditor?.v2TrackedChanges;
8111
+ if (isV2TrackedChangesAdapter(fromFacade)) return fromFacade;
7724
8112
  return v2TrackedChangesAdapter.value;
7725
8113
  };
7726
8114
  /**
7727
8115
  * Initialize the store
7728
- *
7729
- * @param {Object} config The comments module config from SuperDoc
7730
- * @returns {void}
7731
8116
  */
7732
8117
  const init = (config = {}) => {
7733
8118
  const updatedConfig = {
@@ -7759,12 +8144,17 @@ var useCommentsStore = defineStore("comments", () => {
7759
8144
  comment.trackedChangeDecision = null;
7760
8145
  };
7761
8146
  const getCommentEventPayload = (comment) => typeof comment?.getValues === "function" ? comment.getValues() : { ...comment };
8147
+ const getDeletedCommentChanges = (sources, fileId) => {
8148
+ const commentId = [...sources.map((source) => source?.commentId), ...sources.map((source) => source?.importedId)].map(normalizeCommentId).find(Boolean);
8149
+ return commentId ? [{
8150
+ key: "deleted",
8151
+ commentId,
8152
+ fileId
8153
+ }] : [];
8154
+ };
7762
8155
  /**
7763
8156
  * Check if a comment originated from the document editor (or has no explicit source).
7764
8157
  * Comments without a source are assumed to be editor-backed for backward compatibility.
7765
- *
7766
- * @param {Object} comment - The comment to check
7767
- * @returns {boolean} True if the comment is editor-backed
7768
8158
  */
7769
8159
  const isEditorBackedComment = (comment) => {
7770
8160
  const source = comment?.selection?.source;
@@ -7798,9 +8188,6 @@ var useCommentsStore = defineStore("comments", () => {
7798
8188
  }, { deep: false });
7799
8189
  /**
7800
8190
  * Get the editor position data for a comment.
7801
- *
7802
- * @param {Object | string} commentOrId The comment object or comment ID
7803
- * @returns {Object | null} The position data from editorCommentPositions
7804
8191
  */
7805
8192
  const getCommentPosition = (commentOrId) => {
7806
8193
  return resolveCommentPositionEntry(commentOrId).entry ?? null;
@@ -7813,10 +8200,6 @@ var useCommentsStore = defineStore("comments", () => {
7813
8200
  };
7814
8201
  /**
7815
8202
  * Set the active comment or clear all active comments
7816
- *
7817
- * @param {Object | undefined | null} superdoc The SuperDoc instance holding the active editor
7818
- * @param {string | undefined | null} id The comment ID
7819
- * @returns {void}
7820
8203
  */
7821
8204
  const setActiveComment = (superdoc, id) => {
7822
8205
  const activeEditor = superdoc?.activeEditor;
@@ -7827,7 +8210,7 @@ var useCommentsStore = defineStore("comments", () => {
7827
8210
  v2Adapter.setActiveComment(null);
7828
8211
  return;
7829
8212
  }
7830
- activeEditor?.commands?.setActiveComment({ commentId: null });
8213
+ activeEditor?.commands?.setActiveComment?.({ commentId: null });
7831
8214
  return;
7832
8215
  }
7833
8216
  const comment = getComment(id);
@@ -7838,18 +8221,13 @@ var useCommentsStore = defineStore("comments", () => {
7838
8221
  v2Adapter.setActiveComment(comment.commentId);
7839
8222
  return;
7840
8223
  }
7841
- activeEditor?.commands?.setActiveComment({ commentId: activeComment.value });
8224
+ activeEditor?.commands?.setActiveComment?.({ commentId: activeComment.value });
7842
8225
  };
7843
8226
  /**
7844
8227
  * Called when a tracked change is updated. Creates a new comment if necessary,
7845
8228
  * or updates an existing tracked-change comment.
7846
- *
7847
- * @param {Object} param0
7848
- * @param {Object} param0.superdoc The SuperDoc instance
7849
- * @param {Object} param0.params The tracked change params
7850
- * @returns {void}
7851
8229
  */
7852
- const handleTrackedChangeUpdate = ({ superdoc, params, broadcastChanges = true, trackedChangeIdentityIndex = null }) => {
8230
+ const handleTrackedChangeUpdate = ({ superdoc, params, broadcastChanges = true, trackedChangeIdentityIndex = null, preserveDraft = false }) => {
7853
8231
  const span = startInteractionSpan("store.trackedChanges.handleUpdate", "store-reconciliation", {
7854
8232
  event: params?.event ?? null,
7855
8233
  changeId: params?.changeId ?? null,
@@ -7874,9 +8252,11 @@ var useCommentsStore = defineStore("comments", () => {
7874
8252
  const normalizedTrackedChangeLabel = typeof trackedChangeLabel === "string" && trackedChangeLabel.length > 0 ? trackedChangeLabel : null;
7875
8253
  const normalizedTrackedChangeDetailLines = normalizeTrackedChangeDetailLines(trackedChangeDetailLines);
7876
8254
  const normalizedTrackedChangeImagePreview = normalizeTrackedChangeImagePreview(trackedChangeImagePreview);
8255
+ const hasDraft = preserveDraft && (pendingComment.value !== null || currentCommentText.value !== "" || currentCommentMentions.value.length > 0);
7877
8256
  const comment = getPendingComment({
7878
8257
  documentId,
7879
- commentId: changeId,
8258
+ ...hasDraft ? { commentText: "" } : {},
8259
+ commentId: normalizedChangeId ?? void 0,
7880
8260
  trackedChange: true,
7881
8261
  trackedChangeText,
7882
8262
  trackedChangeType,
@@ -7928,7 +8308,7 @@ var useCommentsStore = defineStore("comments", () => {
7928
8308
  commentCanonicalId,
7929
8309
  commentAnchorKey,
7930
8310
  ...commentAliasIds
7931
- ].filter(Boolean).some((id) => incomingAliasIds.has(id))) return true;
8311
+ ].some((id) => id != null && incomingAliasIds.has(id))) return true;
7932
8312
  const hasSyntheticSideIdentity = normalizedTrackedChangeCanonicalId && normalizedTrackedChangeCanonicalId !== normalizedChangeId || commentCanonicalId && commentCanonicalId !== commentId;
7933
8313
  if (hasCompatibleStory && commentId === normalizedChangeId) return true;
7934
8314
  if (hasCompatibleStory && !hasSyntheticSideIdentity && (importedId === normalizedChangeId || normalizedImportedId !== void 0 && normalizedImportedId != null && importedId === normalizedImportedId)) return true;
@@ -7952,7 +8332,7 @@ var useCommentsStore = defineStore("comments", () => {
7952
8332
  };
7953
8333
  const emitTrackedChangeEvent = (event) => {
7954
8334
  if (!broadcastChanges) return;
7955
- syncCommentsToClients(superdoc, event);
8335
+ syncCommentsToClients(requireHost(superdoc, "handleTrackedChangeUpdate"), event);
7956
8336
  debounceEmit(changeId, event, superdoc);
7957
8337
  };
7958
8338
  const setIfChanged = (target, key, value) => {
@@ -7995,8 +8375,9 @@ var useCommentsStore = defineStore("comments", () => {
7995
8375
  target?.trackedChangeCanonicalId,
7996
8376
  target?.trackedChangeAnchorKey,
7997
8377
  ...getCommentAliasIds(target)
7998
- ].map((id) => normalizeCommentId(id)).filter(Boolean));
7999
- fields.trackedChangePositionAliases = normalizedTrackedChangePositionAliases.some((alias) => targetIdentityIds.has(alias)) ? normalizeTrackedChangePositionAliases([...Array.isArray(target?.trackedChangePositionAliases) ? target.trackedChangePositionAliases : [], ...normalizedTrackedChangePositionAliases]) : normalizedTrackedChangePositionAliases;
8378
+ ].map((id) => normalizeCommentId(id)).filter(isPresent));
8379
+ const incomingAliases = normalizedTrackedChangePositionAliases ?? [];
8380
+ fields.trackedChangePositionAliases = incomingAliases.some((alias) => targetIdentityIds.has(alias)) ? normalizeTrackedChangePositionAliases([...Array.isArray(target?.trackedChangePositionAliases) ? target.trackedChangePositionAliases : [], ...incomingAliases]) : incomingAliases;
8000
8381
  }
8001
8382
  let didChange = false;
8002
8383
  for (const [key, value] of Object.entries(fields)) didChange = setIfChanged(target, key, value) || didChange;
@@ -8005,7 +8386,7 @@ var useCommentsStore = defineStore("comments", () => {
8005
8386
  didChange = true;
8006
8387
  }
8007
8388
  if (hasCustomAttributes && target && !trackedChangeCustomAttributesEqual(target.customAttributes, normalizedCustomAttributes)) {
8008
- target.customAttributes = normalizedCustomAttributes;
8389
+ target.customAttributes = normalizedCustomAttributes ?? null;
8009
8390
  didChange = true;
8010
8391
  }
8011
8392
  return applyStoryMetadata(target) || didChange;
@@ -8027,9 +8408,10 @@ var useCommentsStore = defineStore("comments", () => {
8027
8408
  return;
8028
8409
  }
8029
8410
  addHydratedComment({
8030
- superdoc,
8411
+ superdoc: requireHost(superdoc, "handleTrackedChangeUpdate"),
8031
8412
  comment,
8032
- broadcastChanges
8413
+ broadcastChanges,
8414
+ preserveDraft: hasDraft
8033
8415
  });
8034
8416
  trackedChangeIdentityIndex?.add(comment);
8035
8417
  } else if (event === "update") {
@@ -8047,11 +8429,12 @@ var useCommentsStore = defineStore("comments", () => {
8047
8429
  id: params.resolvedById ?? superdoc?.user?.id ?? null,
8048
8430
  email: params.resolvedByEmail ?? superdoc?.user?.email ?? null,
8049
8431
  name: params.resolvedByName ?? superdoc?.user?.name ?? null,
8050
- decision: params.decision ?? null,
8432
+ decision: params.decision ?? void 0,
8051
8433
  superdoc
8052
8434
  };
8053
8435
  if (existingTrackedChange && !existingTrackedChange.resolvedTime) existingTrackedChange.resolveComment({
8054
8436
  ...resolveArgs,
8437
+ superdoc: requireHost(superdoc, "handleTrackedChangeUpdate"),
8055
8438
  reconciliationToken: COMMENT_RECONCILIATION_TOKEN
8056
8439
  });
8057
8440
  }
@@ -8076,31 +8459,13 @@ var useCommentsStore = defineStore("comments", () => {
8076
8459
  instantSidebarAlignmentInstanceId.value = null;
8077
8460
  };
8078
8461
  const debounceEmit = (commentId, event, superdoc, delay = 1e3) => {
8079
- if (debounceTimers[commentId]) clearTimeout(debounceTimers[commentId]);
8080
- debounceTimers[commentId] = setTimeout(() => {
8462
+ const timerKey = String(commentId);
8463
+ if (debounceTimers[timerKey]) clearTimeout(debounceTimers[timerKey]);
8464
+ debounceTimers[timerKey] = setTimeout(() => {
8081
8465
  if (superdoc) superdoc.emit("comments-update", event);
8082
- delete debounceTimers[commentId];
8466
+ delete debounceTimers[timerKey];
8083
8467
  }, delay);
8084
8468
  };
8085
- const getPendingSelectionSnapshot = (superdoc, activeSelection) => {
8086
- if (activeSelection?.source !== "document-editor") return null;
8087
- const selectionDocumentId = activeSelection?.documentId ?? null;
8088
- const editorDocumentId = superdoc?.activeEditor?.options?.documentId ?? null;
8089
- if (!selectionDocumentId || !editorDocumentId || selectionDocumentId !== editorDocumentId) return null;
8090
- let currentSelection;
8091
- try {
8092
- currentSelection = superdoc?.activeEditor?.doc?.selection?.current;
8093
- } catch {
8094
- return null;
8095
- }
8096
- if (typeof currentSelection !== "function") return null;
8097
- try {
8098
- const snapshot = currentSelection();
8099
- return typeof snapshot?.then === "function" ? Promise.resolve(snapshot).catch(() => null) : snapshot;
8100
- } catch {
8101
- return null;
8102
- }
8103
- };
8104
8469
  const showAddComment = (superdoc, targetClientY = null) => {
8105
8470
  const request = ++pendingCommentRequest;
8106
8471
  const editor = superdoc?.activeEditor;
@@ -8110,7 +8475,7 @@ var useCommentsStore = defineStore("comments", () => {
8110
8475
  if (!ownsRequest()) return;
8111
8476
  superdoc.emit("comments-update", {
8112
8477
  type: COMMENT_EVENTS.PENDING,
8113
- pendingSelection: superdoc?.activeEditor === editor ? snapshot : null
8478
+ pendingSelection: superdoc?.activeEditor === editor && require__plugin_vue_export_helper.isPlainObject(snapshot) ? snapshot : null
8114
8479
  });
8115
8480
  };
8116
8481
  if (v2Adapter) {
@@ -8155,12 +8520,11 @@ var useCommentsStore = defineStore("comments", () => {
8155
8520
  }).catch((err) => ({
8156
8521
  ok: false,
8157
8522
  reason: "selection-capture-failed",
8158
- detail: err?.message ?? String(err)
8523
+ detail: errorDetail(err)
8159
8524
  }));
8160
8525
  }
8161
8526
  const pendingSelection = getPendingSelectionSnapshot(superdoc, superdocStore.activeSelection);
8162
- const asyncSnapshot = typeof pendingSelection?.then === "function";
8163
- if (!asyncSnapshot) emitPending(pendingSelection);
8527
+ if (!require__plugin_vue_export_helper.isThenable(pendingSelection)) emitPending(pendingSelection);
8164
8528
  const showLegacyPending = (selection) => {
8165
8529
  selection.selectionBounds = { ...selection.selectionBounds };
8166
8530
  if (superdocStore.selectionPosition?.source && superdocStore.selectionPosition.source !== "pdf") superdocStore.selectionPosition.source = null;
@@ -8170,7 +8534,7 @@ var useCommentsStore = defineStore("comments", () => {
8170
8534
  parentCommentId: null
8171
8535
  });
8172
8536
  if (!superdoc.config.isInternal) pendingComment.value.isInternal = false;
8173
- if (superdoc.activeEditor?.commands) superdoc.activeEditor.commands.insertComment({
8537
+ if (superdoc.activeEditor?.commands) superdoc.activeEditor.commands.insertComment?.({
8174
8538
  ...pendingComment.value.getValues(),
8175
8539
  commentId: "pending",
8176
8540
  skipEmit: true
@@ -8181,10 +8545,10 @@ var useCommentsStore = defineStore("comments", () => {
8181
8545
  activeComment.value = pendingComment.value.commentId;
8182
8546
  return { ok: true };
8183
8547
  };
8184
- if (asyncSnapshot) {
8548
+ if (require__plugin_vue_export_helper.isThenable(pendingSelection)) {
8185
8549
  const selection = { ...superdocStore.activeSelection };
8186
8550
  selection.selectionBounds = { ...selection.selectionBounds };
8187
- return pendingSelection.then((snapshot) => {
8551
+ return Promise.resolve(pendingSelection).then((snapshot) => {
8188
8552
  if (!ownsRequest()) return {
8189
8553
  ok: false,
8190
8554
  reason: "pending-comment-superseded"
@@ -8216,12 +8580,6 @@ var useCommentsStore = defineStore("comments", () => {
8216
8580
  });
8217
8581
  /**
8218
8582
  * Get a new pending comment
8219
- *
8220
- * @param {Object} param0
8221
- * @param {Object} [param0.selection] The selection object
8222
- * @param {string | null} [param0.documentId] The document ID
8223
- * @param {string | null} [param0.parentCommentId] The parent comment
8224
- * @returns {ReturnType<typeof useComment>} The new comment object
8225
8583
  */
8226
8584
  const getPendingComment = ({ selection, documentId, parentCommentId, ...options }) => {
8227
8585
  return _getNewcomment({
@@ -8233,17 +8591,11 @@ var useCommentsStore = defineStore("comments", () => {
8233
8591
  };
8234
8592
  /**
8235
8593
  * Get the new comment object
8236
- *
8237
- * @param {Object} param0
8238
- * @param {Object} param0.selection The selection object
8239
- * @param {String} param0.documentId The document ID
8240
- * @param {String} param0.parentCommentId The parent comment ID
8241
- * @returns {Object} The new comment object
8242
8594
  */
8243
8595
  const _getNewcomment = ({ selection, documentId, parentCommentId, ...options }) => {
8244
8596
  let activeDocument;
8245
- if (documentId) activeDocument = superdocStore.getDocument(documentId);
8246
- else if (selection) activeDocument = superdocStore.getDocument(selection.documentId);
8597
+ if (documentId) activeDocument = findDocument(documentId);
8598
+ else if (selection) activeDocument = findDocument(selection.documentId);
8247
8599
  if (!activeDocument) activeDocument = superdocStore.documents[0];
8248
8600
  return useComment({
8249
8601
  fileId: activeDocument.id,
@@ -8260,8 +8612,6 @@ var useCommentsStore = defineStore("comments", () => {
8260
8612
  };
8261
8613
  /**
8262
8614
  * Remove the pending comment
8263
- *
8264
- * @returns {void}
8265
8615
  */
8266
8616
  const resetPendingCommentState = (superdoc, clearViewingSelection = true) => {
8267
8617
  const hadPending = !!pendingComment.value;
@@ -8277,7 +8627,7 @@ var useCommentsStore = defineStore("comments", () => {
8277
8627
  } catch {}
8278
8628
  return;
8279
8629
  }
8280
- superdoc?.activeEditor?.commands?.removeComment({ commentId: "pending" });
8630
+ superdoc?.activeEditor?.commands?.removeComment?.({ commentId: "pending" });
8281
8631
  };
8282
8632
  const removePendingComment = (superdoc) => {
8283
8633
  pendingCommentRequest += 1;
@@ -8290,16 +8640,8 @@ var useCommentsStore = defineStore("comments", () => {
8290
8640
  };
8291
8641
  /**
8292
8642
  * Add a new comment to the document
8293
- *
8294
- * @param {Object} param0
8295
- * @param {Object} param0.superdoc The SuperDoc instance
8296
- * @param {ReturnType<typeof useComment>} param0.comment The comment to add
8297
- * @param {boolean} [param0.skipEditorUpdate] Skip writing the comment into the editor
8298
- * @param {boolean} [param0.broadcastChanges] Emit and sync the change
8299
- * @param {boolean} [param0.isHydration] The comment comes from import or collaboration
8300
- * @returns {{ ok: boolean, reason?: string, detail?: string, code?: string } | Promise<{ ok: boolean, reason?: string, detail?: string, code?: string }>} The mutation outcome
8301
8643
  */
8302
- const addCommentInternal = ({ superdoc, comment, skipEditorUpdate = false, broadcastChanges = true, isHydration = false }) => {
8644
+ const addCommentInternal = ({ superdoc, comment, skipEditorUpdate = false, broadcastChanges = true, isHydration = false, preserveDraft = false }) => {
8303
8645
  if (commentsAreReadOnly() && !isHydration) return readOnlyMutationOutcome();
8304
8646
  const v2Adapter = !skipEditorUpdate && !isHydration ? getV2CommentsAdapter(superdoc) : null;
8305
8647
  if (v2Adapter && !comment.trackedChange) {
@@ -8327,7 +8669,7 @@ var useCommentsStore = defineStore("comments", () => {
8327
8669
  return {
8328
8670
  ok: false,
8329
8671
  reason: "adapter-threw",
8330
- detail: err?.message ?? String(err)
8672
+ detail: errorDetail(err)
8331
8673
  };
8332
8674
  }
8333
8675
  })().then((outcome) => {
@@ -8378,28 +8720,30 @@ var useCommentsStore = defineStore("comments", () => {
8378
8720
  };
8379
8721
  });
8380
8722
  }
8381
- let parentComment = commentsList.value.find((c) => c.commentId === activeComment.value);
8723
+ const activeId = activeComment.value;
8724
+ const parent = require__plugin_vue_export_helper.toRaw(commentsList.value).find((c) => require__plugin_vue_export_helper.unref(c.commentId) === activeId);
8725
+ let parentComment = parent ? require__plugin_vue_export_helper.reactive(parent) : void 0;
8382
8726
  if (!parentComment) parentComment = comment;
8383
8727
  const newComment = useComment(comment.getValues());
8384
- if (pendingComment.value) newComment.setText({
8385
- text: currentCommentText.value,
8386
- suppressUpdate: true
8387
- });
8388
- else newComment.setText({
8389
- text: comment.commentText,
8728
+ const text = pendingComment.value && !preserveDraft ? currentCommentText.value : comment.commentText;
8729
+ if (text === "") {
8730
+ newComment.commentText = "";
8731
+ newComment.mentions = [];
8732
+ } else newComment.setText({
8733
+ text,
8390
8734
  suppressUpdate: true
8391
8735
  });
8392
- newComment.selection.source = pendingComment.value?.selection?.source ?? newComment.selection.source;
8736
+ if (!preserveDraft) newComment.selection.source = pendingComment.value?.selection?.source ?? newComment.selection.source;
8393
8737
  if (parentComment) newComment.isInternal = parentComment.isInternal;
8394
8738
  if (!superdoc.config.isInternal) newComment.isInternal = false;
8395
8739
  commentsList.value.push(newComment);
8396
- const hadPendingComment = !!pendingComment.value;
8397
- removePendingComment(superdoc);
8740
+ const hadPendingComment = !preserveDraft && !!pendingComment.value;
8741
+ if (!preserveDraft) removePendingComment(superdoc);
8398
8742
  if (hadPendingComment) {
8399
8743
  activeComment.value = newComment.commentId;
8400
8744
  setActiveFloatingCommentInstance(newComment.commentId);
8401
8745
  }
8402
- if (!skipEditorUpdate && !comment.trackedChange && superdoc.activeEditor?.commands && !comment.parentCommentId) superdoc.activeEditor.commands.insertComment({
8746
+ if (!skipEditorUpdate && !comment.trackedChange && superdoc.activeEditor?.commands && !comment.parentCommentId) superdoc.activeEditor.commands.insertComment?.({
8403
8747
  ...newComment.getValues(),
8404
8748
  skipEmit: true
8405
8749
  });
@@ -8422,12 +8766,13 @@ var useCommentsStore = defineStore("comments", () => {
8422
8766
  skipEditorUpdate,
8423
8767
  broadcastChanges
8424
8768
  });
8425
- const addHydratedComment = ({ superdoc, comment, skipEditorUpdate = false, broadcastChanges = true }) => addCommentInternal({
8769
+ const addHydratedComment = ({ superdoc, comment, skipEditorUpdate = false, broadcastChanges = true, preserveDraft = false }) => addCommentInternal({
8426
8770
  superdoc,
8427
8771
  comment,
8428
8772
  skipEditorUpdate,
8429
8773
  broadcastChanges,
8430
- isHydration: true
8774
+ isHydration: true,
8775
+ preserveDraft
8431
8776
  });
8432
8777
  const deleteComment = ({ commentId: commentIdToDelete, superdoc }) => {
8433
8778
  if (commentsAreReadOnly()) return Promise.resolve(readOnlyMutationOutcome());
@@ -8447,7 +8792,7 @@ var useCommentsStore = defineStore("comments", () => {
8447
8792
  return {
8448
8793
  ok: false,
8449
8794
  reason: "adapter-threw",
8450
- detail: err?.message ?? String(err)
8795
+ detail: errorDetail(err)
8451
8796
  };
8452
8797
  }
8453
8798
  })().then((outcome) => {
@@ -8467,16 +8812,16 @@ var useCommentsStore = defineStore("comments", () => {
8467
8812
  });
8468
8813
  return outcome;
8469
8814
  }
8470
- const removedIds = new Set((Array.isArray(outcome.removedCommentIds) ? outcome.removedCommentIds : []).map(normalizeCommentId).filter(Boolean));
8471
- if (removedIds.has(normalizeCommentId(commentId))) {
8472
- if (importedId != null) removedIds.add(normalizeCommentId(importedId));
8815
+ const removedIds = new Set((Array.isArray(outcome.removedCommentIds) ? outcome.removedCommentIds : []).map(normalizeCommentId).filter(isPresent));
8816
+ if (removedIds.has(normalizeCommentId(commentId) ?? "")) {
8817
+ if (importedId != null) removedIds.add(String(importedId));
8473
8818
  let addedChild = true;
8474
8819
  while (addedChild) {
8475
8820
  addedChild = false;
8476
8821
  for (const row of commentsList.value) {
8477
8822
  const parentId = normalizeCommentId(row?.parentCommentId);
8478
8823
  if (!parentId || !removedIds.has(parentId)) continue;
8479
- for (const alias of [row?.commentId, row?.importedId].map(normalizeCommentId).filter(Boolean)) {
8824
+ for (const alias of [row?.commentId, row?.importedId].map(normalizeCommentId).filter(isPresent)) {
8480
8825
  if (removedIds.has(alias)) continue;
8481
8826
  removedIds.add(alias);
8482
8827
  addedChild = true;
@@ -8484,9 +8829,9 @@ var useCommentsStore = defineStore("comments", () => {
8484
8829
  }
8485
8830
  }
8486
8831
  commentsList.value = commentsList.value.filter((row) => {
8487
- return ![row?.commentId, row?.importedId].map(normalizeCommentId).filter(Boolean).some((alias) => removedIds.has(alias));
8832
+ return ![row?.commentId, row?.importedId].map(normalizeCommentId).filter(isPresent).some((alias) => removedIds.has(alias));
8488
8833
  });
8489
- if (removedIds.has(normalizeCommentId(activeComment.value))) clearActiveCommentSelection();
8834
+ if (removedIds.has(normalizeCommentId(activeComment.value) ?? "")) clearActiveCommentSelection();
8490
8835
  } else reconcileCommentsFromV2({
8491
8836
  superdoc,
8492
8837
  adapter: v2Adapter,
@@ -8494,18 +8839,18 @@ var useCommentsStore = defineStore("comments", () => {
8494
8839
  items: outcome.items ?? [],
8495
8840
  pruneStale: outcome.complete !== false
8496
8841
  });
8842
+ const payload = comment.getValues();
8497
8843
  superdoc.emit("comments-update", {
8498
8844
  type: COMMENT_EVENTS.DELETED,
8499
- comment: comment.getValues(),
8500
- changes: [{
8501
- key: "deleted",
8845
+ comment: payload,
8846
+ changes: getDeletedCommentChanges([{
8502
8847
  commentId,
8503
- fileId
8504
- }]
8848
+ importedId
8849
+ }, payload], fileId)
8505
8850
  });
8506
8851
  return { ok: true };
8507
8852
  });
8508
- superdoc.activeEditor?.commands?.removeComment({
8853
+ superdoc.activeEditor?.commands?.removeComment?.({
8509
8854
  commentId,
8510
8855
  importedId
8511
8856
  });
@@ -8513,14 +8858,14 @@ var useCommentsStore = defineStore("comments", () => {
8513
8858
  const childCommentIds = commentsList.value.filter((c) => c.parentCommentId === commentId).map((c) => c.commentId || c.importedId);
8514
8859
  commentsList.value = commentsList.value.filter((c) => !childCommentIds.includes(c.commentId));
8515
8860
  if (activeComment.value === commentId || childCommentIds.includes(activeComment.value)) clearActiveCommentSelection();
8861
+ const payload = comment.getValues();
8516
8862
  const event = {
8517
8863
  type: COMMENT_EVENTS.DELETED,
8518
- comment: comment.getValues(),
8519
- changes: [{
8520
- key: "deleted",
8864
+ comment: payload,
8865
+ changes: getDeletedCommentChanges([{
8521
8866
  commentId,
8522
- fileId
8523
- }]
8867
+ importedId
8868
+ }, payload], fileId)
8524
8869
  };
8525
8870
  superdoc.emit("comments-update", event);
8526
8871
  syncCommentsToClients(superdoc, event);
@@ -8532,7 +8877,7 @@ var useCommentsStore = defineStore("comments", () => {
8532
8877
  * otherwise keep the source bubble after the document comment is gone.
8533
8878
  */
8534
8879
  const dropCommentsFromMutationImpact = ({ superdoc, documentId, removedIds } = {}) => {
8535
- const seedIds = new Set([...removedIds instanceof Set ? removedIds : removedIds ?? []].map((id) => normalizeCommentId(id)).filter(Boolean));
8880
+ const seedIds = new Set([...removedIds instanceof Set ? removedIds : removedIds ?? []].map((id) => normalizeCommentId(id)).filter(isPresent));
8536
8881
  if (!seedIds.size) return {
8537
8882
  ok: true,
8538
8883
  removedIds: []
@@ -8556,7 +8901,7 @@ var useCommentsStore = defineStore("comments", () => {
8556
8901
  if (!isDroppableCommentRow(row)) continue;
8557
8902
  const aliases = getCommentAliasIds(row);
8558
8903
  const alreadyDropped = aliases.some((alias) => droppedIds.has(alias));
8559
- const parentDropped = droppedIds.has(normalizeCommentId(row?.parentCommentId)) || droppedIds.has(normalizeCommentId(row?.threadingParentCommentId));
8904
+ const parentDropped = droppedIds.has(normalizeCommentId(row?.parentCommentId) ?? "") || droppedIds.has(normalizeCommentId(row?.threadingParentCommentId) ?? "");
8560
8905
  if (!alreadyDropped && !parentDropped) continue;
8561
8906
  for (const alias of aliases) {
8562
8907
  if (droppedIds.has(alias)) continue;
@@ -8584,11 +8929,7 @@ var useCommentsStore = defineStore("comments", () => {
8584
8929
  const event = {
8585
8930
  type: COMMENT_EVENTS.DELETED,
8586
8931
  comment: payload,
8587
- changes: [{
8588
- key: "deleted",
8589
- commentId: payload?.commentId,
8590
- fileId: payload?.fileId
8591
- }]
8932
+ changes: getDeletedCommentChanges([payload, comment], payload?.fileId)
8592
8933
  };
8593
8934
  superdoc?.emit?.("comments-update", event);
8594
8935
  });
@@ -8610,7 +8951,7 @@ var useCommentsStore = defineStore("comments", () => {
8610
8951
  const byAlias = /* @__PURE__ */ new Map();
8611
8952
  const childrenByParentAlias = /* @__PURE__ */ new Map();
8612
8953
  for (const row of rows) {
8613
- for (const alias of [row.commentId, row.importedId].map(normalizeCommentId).filter(Boolean)) if (!byAlias.has(alias)) byAlias.set(alias, row);
8954
+ for (const alias of [row.commentId, row.importedId].map(normalizeCommentId).filter(isPresent)) if (!byAlias.has(alias)) byAlias.set(alias, row);
8614
8955
  const parentId = normalizeCommentId(row.parentCommentId);
8615
8956
  if (parentId) {
8616
8957
  const children = childrenByParentAlias.get(parentId) ?? [];
@@ -8637,7 +8978,7 @@ var useCommentsStore = defineStore("comments", () => {
8637
8978
  if (!row || visited.has(row)) continue;
8638
8979
  visited.add(row);
8639
8980
  family.push(row);
8640
- for (const alias of [row.commentId, row.importedId].map(normalizeCommentId).filter(Boolean)) queue.push(...childrenByParentAlias.get(alias) ?? []);
8981
+ for (const alias of [row.commentId, row.importedId].map(normalizeCommentId).filter(isPresent)) queue.push(...childrenByParentAlias.get(alias) ?? []);
8641
8982
  }
8642
8983
  const isResolved = status === "resolved";
8643
8984
  const resolvedAt = Date.now();
@@ -8660,7 +9001,7 @@ var useCommentsStore = defineStore("comments", () => {
8660
9001
  outcome = {
8661
9002
  ok: false,
8662
9003
  reason: "adapter-threw",
8663
- detail: err?.message ?? String(err)
9004
+ detail: errorDetail(err)
8664
9005
  };
8665
9006
  }
8666
9007
  if (!isCurrentV2CommentsAdapter(adapter)) return {
@@ -8732,14 +9073,14 @@ var useCommentsStore = defineStore("comments", () => {
8732
9073
  return (outcome.items ?? []).map((item) => adapter.mapV2CommentToUseCommentInput(item, {
8733
9074
  fileId,
8734
9075
  fileType: null
8735
- })).filter(Boolean);
9076
+ })).filter(isPresent);
8736
9077
  };
8737
9078
  const isBlankDirectoryCommentText = (value) => typeof value !== "string" || value.replace(/<[^>]*>/g, "").replace(/&nbsp;/gi, " ").trim().length === 0;
8738
9079
  const trackedChangeDirectoryComment = (params) => {
8739
9080
  if (!params || params.event === "omit" || params.changeId == null) return null;
8740
9081
  return getPendingComment({
8741
9082
  documentId: params.documentId,
8742
- commentId: params.changeId,
9083
+ commentId: String(params.changeId),
8743
9084
  trackedChange: true,
8744
9085
  trackedChangeText: params.trackedChangeText,
8745
9086
  trackedChangeType: params.trackedChangeType,
@@ -8786,7 +9127,7 @@ var useCommentsStore = defineStore("comments", () => {
8786
9127
  const mappedCommentInputs = commentItems.filter((item) => !require_create_super_doc_ui.isSyntheticTrackedChangeCommentLaneItem(item)).map((item) => commentsAdapter.mapV2CommentToUseCommentInput(item, {
8787
9128
  fileId: documentId,
8788
9129
  fileType: document?.type ?? null
8789
- })).filter(Boolean);
9130
+ })).filter(isPresent);
8790
9131
  const trackedParentBySidecarId = /* @__PURE__ */ new Map();
8791
9132
  for (const input of mappedCommentInputs) if (input.trackedChange !== true && input.trackedChangeThreadParentId && !input.parentCommentId && isBlankDirectoryCommentText(input.commentText)) trackedParentBySidecarId.set(String(input.commentId), String(input.trackedChangeThreadParentId));
8792
9133
  const commentRows = mappedCommentInputs.filter((input) => !trackedParentBySidecarId.has(String(input.commentId))).map((input) => {
@@ -8797,7 +9138,7 @@ var useCommentsStore = defineStore("comments", () => {
8797
9138
  }
8798
9139
  return useComment(input);
8799
9140
  });
8800
- const trackedRows = trackedChangeItems.map((item) => trackedChangesAdapter.mapV2TrackedChangeToCommentParams(item)).map((params) => trackedChangeDirectoryComment(params)).filter(Boolean);
9141
+ const trackedRows = trackedChangeItems.map((item) => trackedChangesAdapter.mapV2TrackedChangeToCommentParams(item)).map((params) => trackedChangeDirectoryComment(params)).filter(isPresent);
8801
9142
  reviewDirectoryList.value = [...commentRows, ...trackedRows];
8802
9143
  return {
8803
9144
  ok: true,
@@ -8878,13 +9219,6 @@ var useCommentsStore = defineStore("comments", () => {
8878
9219
  * - successful mutation refreshes from v2 list and reconciles
8879
9220
  * - rejection preserves rows and emits a rejected `comments-update` event
8880
9221
  * - committed-but-refresh-failed surfaces honestly (no reconcile with `[]`)
8881
- *
8882
- * @param {Object} [param0]
8883
- * @param {Object} [param0.superdoc] The SuperDoc instance.
8884
- * @param {string | null} [param0.parentCommentId] The comment or tracked-change row being replied to.
8885
- * @param {string} [param0.text] The reply text.
8886
- * @param {Array<{ name?: string | null, email?: string | null }>} [param0.mentions] Users mentioned in the reply.
8887
- * @param {{ kind: 'trackedChange', trackedChangeId: string, story?: unknown, side?: import('./helpers/tracked-change-thread-index.js').TrackedChangeSideGroup }} [param0.trackedChangeTarget] The tracked change a first reply anchors to.
8888
9222
  */
8889
9223
  const replyCommentV2 = async ({ superdoc, parentCommentId, text, mentions = [], trackedChangeTarget } = {}) => {
8890
9224
  if (commentsAreReadOnly()) return readOnlyMutationOutcome();
@@ -9159,10 +9493,15 @@ var useCommentsStore = defineStore("comments", () => {
9159
9493
  row?.threadingParentCommentId,
9160
9494
  row?.trackedChangeParentId,
9161
9495
  row?.trackedChangeThreadParentId
9162
- ].map((value) => normalizeCommentId(value)).filter(Boolean));
9496
+ ].map((value) => normalizeCommentId(value)).filter(isPresent));
9163
9497
  /** Keep one mounted review window plus rows whose interaction is still live. */
9164
9498
  const boundReviewPresentationRows = ({ documentId, visibleIds }) => {
9165
9499
  const currentRows = commentsList.value;
9500
+ if (currentRows.every((row) => {
9501
+ if (!belongsToTrackedChangeSyncDocument(row, documentId)) return true;
9502
+ const id = normalizeCommentId(row.commentId);
9503
+ return Boolean(id && visibleIds.has(id));
9504
+ })) return;
9166
9505
  const identityIdsByRow = /* @__PURE__ */ new Map();
9167
9506
  const identityIdsFor = (row) => {
9168
9507
  let ids = identityIdsByRow.get(row);
@@ -9180,7 +9519,7 @@ var useCommentsStore = defineStore("comments", () => {
9180
9519
  pendingComment.value?.commentId,
9181
9520
  instantSidebarAlignmentThreadId.value,
9182
9521
  instantSidebarAlignmentInstanceId.value
9183
- ].map((value) => normalizeCommentId(value)).filter(Boolean));
9522
+ ].map((value) => normalizeCommentId(value)).filter(isPresent));
9184
9523
  let changed = true;
9185
9524
  while (changed) {
9186
9525
  changed = false;
@@ -9248,7 +9587,8 @@ var useCommentsStore = defineStore("comments", () => {
9248
9587
  if (preparedReview?.reuseCatalog === true && committedReviewPresentations.value[normalizedDocumentId]) {
9249
9588
  const previous = committedReviewPresentations.value[normalizedDocumentId];
9250
9589
  const next = preparedReview.presentation;
9251
- if (!next || !Number.isSafeInteger(preparedReview.catalogVersion) || preparedReview.catalogVersion < 1 || previous.catalogVersion > preparedReview.catalogVersion || next.catalogVersion !== preparedReview.catalogVersion || previous.coordinate?.documentEpoch !== next.coordinate?.documentEpoch || previous.coordinate?.mountId !== next.coordinate?.mountId || next.coordinate?.reviewVersion <= previous.coordinate?.reviewVersion || next.coordinate?.commitSequence < previous.coordinate?.commitSequence) return {
9590
+ const catalogVersion = preparedReview.catalogVersion ?? NaN;
9591
+ if (!next || !Number.isSafeInteger(catalogVersion) || catalogVersion < 1 || (previous.catalogVersion ?? 0) > catalogVersion || next.catalogVersion !== preparedReview.catalogVersion || previous.coordinate?.documentEpoch !== next.coordinate?.documentEpoch || previous.coordinate?.mountId !== next.coordinate?.mountId || next.coordinate?.reviewVersion <= previous.coordinate?.reviewVersion || next.coordinate?.commitSequence < previous.coordinate?.commitSequence) return {
9252
9592
  ok: false,
9253
9593
  reason: "review-catalog-stale"
9254
9594
  };
@@ -9294,8 +9634,8 @@ var useCommentsStore = defineStore("comments", () => {
9294
9634
  previousPresentation.updateContext = presentation.updateContext;
9295
9635
  return {
9296
9636
  ok: true,
9297
- commentItems: preparedReview.comments.length,
9298
- trackedItems: preparedReview.trackedChanges.length
9637
+ commentItems: preparedReview?.comments.length,
9638
+ trackedItems: preparedReview?.trackedChanges.length
9299
9639
  };
9300
9640
  }
9301
9641
  let effectiveCommentItems = commentItems;
@@ -9309,7 +9649,7 @@ var useCommentsStore = defineStore("comments", () => {
9309
9649
  reason: seeded?.reason ?? "comment-catalog-seed-failed"
9310
9650
  };
9311
9651
  const selected = commentsAdapter.selectVisibleReviewComments?.();
9312
- if (selected?.ok === true && Array.isArray(selected.items) && (!Array.isArray(selected.unresolvedIds) || selected.unresolvedIds.length === 0)) effectiveCommentItems = selected.items;
9652
+ if (!require__plugin_vue_export_helper.isThenable(selected) && selected?.ok === true && Array.isArray(selected.items) && (!Array.isArray(selected.unresolvedIds) || selected.unresolvedIds.length === 0)) effectiveCommentItems = selected.items;
9313
9653
  }
9314
9654
  const fileType = (normalizedDocumentId ? superdocStore.getDocument(normalizedDocumentId) : null)?.type ?? null;
9315
9655
  let preparedInputs;
@@ -9326,16 +9666,16 @@ var useCommentsStore = defineStore("comments", () => {
9326
9666
  })) : effectiveCommentItems.filter((item) => !require_create_super_doc_ui.isSyntheticTrackedChangeCommentLaneItem(item)).map((item) => commentsAdapter.mapV2CommentToUseCommentInput(item, {
9327
9667
  fileId: normalizedDocumentId,
9328
9668
  fileType
9329
- })).filter(Boolean);
9669
+ })).filter(isPresent);
9330
9670
  preparedParams = preparedReview ? preparedReview.trackedChanges.map((params) => ({
9331
9671
  ...params,
9332
9672
  documentId: normalizedDocumentId
9333
- })) : trackedChangeItems.map((item) => trackedChangesAdapter.mapV2TrackedChangeToCommentParams(item)).filter(Boolean);
9673
+ })) : trackedChangeItems.map((item) => trackedChangesAdapter.mapV2TrackedChangeToCommentParams(item)).filter(isPresent);
9334
9674
  } catch (error) {
9335
9675
  return {
9336
9676
  ok: false,
9337
9677
  reason: "mapper-failed",
9338
- detail: error?.message ?? String(error)
9678
+ detail: errorDetail(error)
9339
9679
  };
9340
9680
  }
9341
9681
  if (typeof patch !== "function") return {
@@ -9363,7 +9703,7 @@ var useCommentsStore = defineStore("comments", () => {
9363
9703
  params?.trackedChangeCanonicalId,
9364
9704
  params?.trackedChangeAnchorKey
9365
9705
  ])
9366
- ].map((value) => normalizeCommentId(value)).filter(Boolean));
9706
+ ].map((value) => normalizeCommentId(value)).filter(isPresent));
9367
9707
  patch(() => {
9368
9708
  const previousPreparedPresentation = committedReviewPresentations.value[normalizedDocumentId] ?? null;
9369
9709
  if (preparedReview?.presentation) committedReviewPresentations.value = {
@@ -9378,7 +9718,8 @@ var useCommentsStore = defineStore("comments", () => {
9378
9718
  preparedParams,
9379
9719
  preparedPresentation: preparedReview?.presentation ?? null,
9380
9720
  previousPreparedPresentation,
9381
- pruneStale: false
9721
+ pruneStale: false,
9722
+ preserveDraft: true
9382
9723
  });
9383
9724
  reconcileCommentsFromV2({
9384
9725
  superdoc,
@@ -9411,7 +9752,7 @@ var useCommentsStore = defineStore("comments", () => {
9411
9752
  };
9412
9753
  const effectiveDocumentId = documentId ?? adapter.documentId ?? null;
9413
9754
  const normalizedEffectiveDocumentId = effectiveDocumentId != null ? String(effectiveDocumentId) : null;
9414
- const fileType = (effectiveDocumentId ? superdocStore.getDocument(effectiveDocumentId) : null)?.type ?? null;
9755
+ const fileType = (effectiveDocumentId ? findDocument(effectiveDocumentId) : null)?.type ?? null;
9415
9756
  const isBlankV2CommentText = (value) => {
9416
9757
  if (typeof value !== "string") return true;
9417
9758
  return value.replace(/<[^>]*>/g, "").replace(/&nbsp;/gi, " ").trim().length === 0;
@@ -9431,7 +9772,7 @@ var useCommentsStore = defineStore("comments", () => {
9431
9772
  const candidateInputs = Array.isArray(preparedInputs) ? preparedInputs : items.filter((item) => !require_create_super_doc_ui.isSyntheticTrackedChangeCommentLaneItem(item)).map((item) => adapter.mapV2CommentToUseCommentInput(item, {
9432
9773
  fileId: effectiveDocumentId,
9433
9774
  fileType
9434
- })).filter(Boolean);
9775
+ })).filter(isPresent);
9435
9776
  for (const input of candidateInputs) {
9436
9777
  if (isV2TrackedChangeSidecarCommentInput(input)) {
9437
9778
  trackedChangeSidecarParentByCommentId.set(String(input.commentId), String(input.trackedChangeThreadParentId));
@@ -9484,7 +9825,7 @@ var useCommentsStore = defineStore("comments", () => {
9484
9825
  existing.mentions = Array.isArray(input.mentions) ? input.mentions : [];
9485
9826
  existing.isInternal = typeof input.isInternal === "boolean" ? input.isInternal : existing.isInternal;
9486
9827
  if (typeof input.resolvedTime === "number") {
9487
- existing.resolvedTime = input.resolvedTimeWasSynthesized === true && typeof existing.resolvedTime === "number" ? existing.resolvedTime : input.resolvedTime;
9828
+ existing.resolvedTime = input.resolvedTimeWasSynthesized === true && typeof existing.resolvedTime === "number" ? existing.resolvedTime : input.resolvedTime ?? null;
9488
9829
  existing.resolvedByEmail = input.resolvedByEmail ?? null;
9489
9830
  existing.resolvedByName = input.resolvedByName ?? null;
9490
9831
  } else {
@@ -9558,7 +9899,7 @@ var useCommentsStore = defineStore("comments", () => {
9558
9899
  return {
9559
9900
  ok: false,
9560
9901
  reason: "comment-read-failed",
9561
- detail: err?.message ?? String(err)
9902
+ detail: errorDetail(err)
9562
9903
  };
9563
9904
  }
9564
9905
  if (!isCurrentV2CommentsAdapter(adapter)) return {
@@ -9584,8 +9925,6 @@ var useCommentsStore = defineStore("comments", () => {
9584
9925
  };
9585
9926
  /**
9586
9927
  * Cancel the pending comment
9587
- *
9588
- * @returns {void}
9589
9928
  */
9590
9929
  const cancelComment = (superdoc) => {
9591
9930
  removePendingComment(superdoc);
@@ -9595,9 +9934,6 @@ var useCommentsStore = defineStore("comments", () => {
9595
9934
  *
9596
9935
  * Replace-file swaps call this before hydrating the replacement so stale
9597
9936
  * comments never survive long enough to render beside the new content.
9598
- *
9599
- * @param {string | null | undefined} documentId
9600
- * @returns {void}
9601
9937
  */
9602
9938
  function removeCommentsForDocument(documentId) {
9603
9939
  const activeDocumentId = documentId != null ? String(documentId) : null;
@@ -9624,139 +9960,20 @@ var useCommentsStore = defineStore("comments", () => {
9624
9960
  const activeCommentId = activeComment.value != null ? String(activeComment.value) : null;
9625
9961
  if (activeCommentId && removedAliasIds.has(activeCommentId)) clearActiveCommentSelection();
9626
9962
  }
9627
- const getCommentDocumentId = (comment) => {
9628
- if (!comment) return null;
9629
- if (comment.fileId != null) return String(comment.fileId);
9630
- if (comment.documentId != null) return String(comment.documentId);
9631
- if (comment.selection?.documentId != null) return String(comment.selection.documentId);
9632
- return null;
9633
- };
9634
- const getOpenDocuments = () => {
9635
- const docs = Array.isArray(superdocStore.documents) ? superdocStore.documents : superdocStore.documents?.value;
9636
- return Array.isArray(docs) ? docs : [];
9637
- };
9638
- const getSingleOpenDocumentId = () => {
9639
- const docs = getOpenDocuments();
9640
- if (docs.length !== 1) return null;
9641
- return docs[0]?.id != null ? String(docs[0].id) : null;
9642
- };
9643
- const belongsToDocument = (comment, activeDocumentId, options = {}) => {
9644
- const { allowSingleDocumentMismatch = false } = options;
9645
- if (!activeDocumentId) return false;
9646
- const commentDocumentId = getCommentDocumentId(comment);
9647
- if (commentDocumentId) {
9648
- if (commentDocumentId === activeDocumentId) return true;
9649
- const singleOpenDocumentId = getSingleOpenDocumentId();
9650
- return allowSingleDocumentMismatch && singleOpenDocumentId === activeDocumentId;
9651
- }
9652
- return getSingleOpenDocumentId() === activeDocumentId;
9653
- };
9654
- const belongsToTrackedChangeSyncDocument = (comment, activeDocumentId) => {
9655
- return belongsToDocument(comment, activeDocumentId, { allowSingleDocumentMismatch: true });
9656
- };
9657
- const normalizeTrackedChangeDecisionType = (value) => {
9658
- const lower = typeof value === "string" ? value.toLowerCase() : "";
9659
- if (!lower) return null;
9660
- if (lower === "insert" || lower === "insertion" || lower === "trackinsert" || lower === "tableinsert" || lower === "paragraphsplit") return "insertion";
9661
- if (lower === "delete" || lower === "deletion" || lower === "trackdelete" || lower === "tabledelete") return "deletion";
9662
- return lower;
9663
- };
9664
- const trackedChangeDecisionKeepsCommentAnchor = ({ comment, decision } = {}) => {
9665
- const normalizedDecision = decision === "accept" || decision === "reject" ? decision : null;
9666
- if (!normalizedDecision) return false;
9667
- const type = normalizeTrackedChangeDecisionType(comment?.trackedChangeDisplayType) ?? normalizeTrackedChangeDecisionType(comment?.trackedChangeType);
9668
- return normalizedDecision === "accept" && type === "insertion" || normalizedDecision === "reject" && type === "deletion";
9669
- };
9670
- const getBodyTrackedChangeIdentityIds = (comment) => {
9671
- return [normalizeCommentId(comment.commentId), ...!normalizeCommentId(comment.trackedChangeCanonicalId) ? [
9672
- comment.importedId,
9673
- comment.trackedChangeAnchorKey,
9674
- ...normalizeTrackedChangePositionAliases(comment.trackedChangePositionAliases)
9675
- ] : []].map((id) => normalizeCommentId(id)).filter(Boolean);
9676
- };
9677
- const groupBodyTrackedChangeCommentsByIdentity = (comments) => {
9678
- const parents = comments.map((_, index) => index);
9679
- const findRoot = (index) => {
9680
- let root = index;
9681
- while (parents[root] !== root) root = parents[root];
9682
- while (parents[index] !== index) {
9683
- const next = parents[index];
9684
- parents[index] = root;
9685
- index = next;
9686
- }
9687
- return root;
9688
- };
9689
- const join = (left, right) => {
9690
- const leftRoot = findRoot(left);
9691
- const rightRoot = findRoot(right);
9692
- if (leftRoot === rightRoot) return;
9693
- parents[Math.max(leftRoot, rightRoot)] = Math.min(leftRoot, rightRoot);
9694
- };
9695
- const identityOwner = /* @__PURE__ */ new Map();
9696
- comments.forEach((comment, index) => {
9697
- getBodyTrackedChangeIdentityIds(comment).forEach((identityId) => {
9698
- const owner = identityOwner.get(identityId);
9699
- if (owner === void 0) identityOwner.set(identityId, index);
9700
- else join(index, owner);
9701
- });
9702
- });
9703
- const groups = /* @__PURE__ */ new Map();
9704
- comments.forEach((comment, index) => {
9705
- const root = findRoot(index);
9706
- const group = groups.get(root) ?? [];
9707
- group.push(comment);
9708
- groups.set(root, group);
9709
- });
9710
- return groups;
9711
- };
9712
- const mergeDuplicateBodyTrackedChangeComments = (groups) => {
9713
- const duplicates = /* @__PURE__ */ new Map();
9714
- groups.forEach(([survivor, ...duplicateRows]) => {
9715
- if (!survivor || duplicateRows.length === 0) return;
9716
- const resolvedDuplicate = duplicateRows.find((comment) => comment.resolvedTime != null);
9717
- if (survivor.resolvedTime == null && resolvedDuplicate) {
9718
- survivor.resolvedTime = resolvedDuplicate.resolvedTime;
9719
- survivor.resolvedById = resolvedDuplicate.resolvedById;
9720
- survivor.resolvedByEmail = resolvedDuplicate.resolvedByEmail;
9721
- survivor.resolvedByName = resolvedDuplicate.resolvedByName;
9722
- survivor.trackedChangeDecision = resolvedDuplicate.trackedChangeDecision;
9723
- }
9724
- survivor.trackedChangePositionAliases = normalizeTrackedChangePositionAliases([...normalizeTrackedChangePositionAliases(survivor.trackedChangePositionAliases), ...duplicateRows.flatMap((comment) => [
9725
- comment.commentId,
9726
- comment.importedId,
9727
- comment.trackedChangeCanonicalId,
9728
- ...normalizeTrackedChangePositionAliases(comment.trackedChangePositionAliases)
9729
- ])]);
9730
- duplicateRows.forEach((comment) => duplicates.set(comment, survivor));
9731
- });
9732
- return duplicates;
9733
- };
9734
- const createDroppedCommentIdMap = (duplicates) => {
9735
- const droppedCommentIds = /* @__PURE__ */ new Map();
9736
- duplicates.forEach((survivor, duplicate) => {
9737
- const fromId = normalizeCommentId(duplicate.commentId);
9738
- const toId = normalizeCommentId(survivor.commentId);
9739
- if (fromId && toId) droppedCommentIds.set(fromId, toId);
9740
- });
9741
- return droppedCommentIds;
9742
- };
9963
+ const { belongsToDocument, belongsToTrackedChangeSyncDocument } = createCommentDocumentScope(() => superdocStore.documents);
9743
9964
  const remapTrackedChangeReferences = (droppedCommentIds, activeDocumentId) => {
9744
9965
  const remapSelection = (selection) => {
9745
9966
  const selectedId = normalizeCommentId(selection.value);
9746
- if (selectedId && droppedCommentIds.has(selectedId)) selection.value = droppedCommentIds.get(selectedId);
9967
+ const replacementId = selectedId ? droppedCommentIds.get(selectedId) : void 0;
9968
+ if (replacementId) selection.value = replacementId;
9747
9969
  };
9748
9970
  remapSelection(activeComment);
9749
9971
  remapSelection(activeFloatingCommentInstanceId);
9750
9972
  commentsList.value.forEach((row) => {
9751
9973
  if (!belongsToTrackedChangeSyncDocument(row, activeDocumentId)) return;
9752
9974
  const rowIdentityUpdates = {};
9753
- for (const field of [
9754
- "trackedChangeThreadParentId",
9755
- "trackedChangeParentId",
9756
- "threadingParentCommentId",
9757
- "parentCommentId"
9758
- ]) {
9759
- const replacementId = droppedCommentIds.get(normalizeCommentId(row?.[field]));
9975
+ for (const field of PARENT_LINK_FIELDS) {
9976
+ const replacementId = droppedCommentIds.get(normalizeCommentId(row?.[field]) ?? "");
9760
9977
  if (!replacementId) continue;
9761
9978
  row[field] = replacementId;
9762
9979
  rowIdentityUpdates[field] = replacementId;
@@ -9765,9 +9982,7 @@ var useCommentsStore = defineStore("comments", () => {
9765
9982
  });
9766
9983
  };
9767
9984
  const compactDuplicateBodyTrackedChangeComments = (activeDocumentId) => {
9768
- const candidates = commentsList.value.filter((comment) => isBodyTrackedChangeComment(comment) && belongsToTrackedChangeSyncDocument(comment, activeDocumentId));
9769
- const groups = groupBodyTrackedChangeCommentsByIdentity(candidates);
9770
- const duplicates = mergeDuplicateBodyTrackedChangeComments(groups);
9985
+ const duplicates = mergeDuplicateBodyTrackedChangeComments(groupBodyTrackedChangeCommentsByIdentity(commentsList.value.filter((comment) => isBodyTrackedChangeComment(comment) && belongsToTrackedChangeSyncDocument(comment, activeDocumentId))));
9771
9986
  if (!duplicates.size) return 0;
9772
9987
  commentsList.value = commentsList.value.filter((comment) => !duplicates.has(comment));
9773
9988
  remapTrackedChangeReferences(createDroppedCommentIdMap(duplicates), activeDocumentId);
@@ -9779,10 +9994,6 @@ var useCommentsStore = defineStore("comments", () => {
9779
9994
  *
9780
9995
  * Pruning is scoped to the active editor document so replay in one document does not
9781
9996
  * delete tracked-change comments from other open documents.
9782
- *
9783
- * @param {Set<string>} liveTrackedChangeIds IDs currently present in editor marks.
9784
- * @param {string | null} activeDocumentId Document currently being synced.
9785
- * @returns {void}
9786
9997
  */
9787
9998
  const pruneStaleTrackedChangeComments = (liveTrackedChangeIds, liveTrackedChangeAnchorKeys, activeDocumentId, superdoc = null, { broadcastChanges = true } = {}) => withInteractionSpan("store.trackedChanges.pruneStaleComments", "store-reconciliation", {
9788
9999
  activeDocumentId: activeDocumentId ?? null,
@@ -9827,7 +10038,7 @@ var useCommentsStore = defineStore("comments", () => {
9827
10038
  comment: payload
9828
10039
  };
9829
10040
  if (broadcastChanges) {
9830
- syncCommentsToClients(superdoc, event);
10041
+ syncCommentsToClients(requireHost(superdoc, "pruneStaleTrackedChangeComments"), event);
9831
10042
  superdoc?.emit?.("comments-update", event);
9832
10043
  }
9833
10044
  });
@@ -9859,14 +10070,10 @@ var useCommentsStore = defineStore("comments", () => {
9859
10070
  const event = {
9860
10071
  type: COMMENT_EVENTS.DELETED,
9861
10072
  comment: payload,
9862
- changes: [{
9863
- key: "deleted",
9864
- commentId: payload.commentId,
9865
- fileId: payload.fileId
9866
- }]
10073
+ changes: getDeletedCommentChanges([payload, comment], payload.fileId)
9867
10074
  };
9868
10075
  if (broadcastChanges) {
9869
- syncCommentsToClients(superdoc, event);
10076
+ syncCommentsToClients(requireHost(superdoc, "pruneStaleTrackedChangeComments"), event);
9870
10077
  superdoc?.emit?.("comments-update", event);
9871
10078
  }
9872
10079
  });
@@ -9889,7 +10096,6 @@ var useCommentsStore = defineStore("comments", () => {
9889
10096
  const resolveArgs = {
9890
10097
  email: superdoc?.user?.email ?? null,
9891
10098
  name: superdoc?.user?.name ?? null,
9892
- superdoc,
9893
10099
  reconciliationToken: COMMENT_RECONCILIATION_TOKEN
9894
10100
  };
9895
10101
  let resolvedCount = 0;
@@ -9900,27 +10106,18 @@ var useCommentsStore = defineStore("comments", () => {
9900
10106
  trackedChangeThreadParentIdForComment(linkedComment),
9901
10107
  linkedComment.threadingParentCommentId,
9902
10108
  linkedComment.parentCommentId
9903
- ].map((id) => normalizeCommentId(id)).filter(Boolean).some((id) => trackedChangeIds.has(id))) return;
10109
+ ].map((id) => normalizeCommentId(id)).filter(isPresent).some((id) => trackedChangeIds.has(id))) return;
9904
10110
  if (typeof linkedComment.resolveComment === "function") {
9905
- linkedComment.resolveComment(resolveArgs);
10111
+ linkedComment.resolveComment({
10112
+ ...resolveArgs,
10113
+ superdoc: requireHost(superdoc, "resolveLinkedCommentsForTrackedChangeDecision")
10114
+ });
9906
10115
  resolvedCount += 1;
9907
10116
  }
9908
10117
  });
9909
10118
  return resolvedCount;
9910
10119
  };
9911
- const collectTrackedChangeDecisionIds = (comment) => {
9912
- const trackedChangeIds = new Set(getCommentAliasIds(comment));
9913
- if (comment?.trackedChangeCanonicalId != null) trackedChangeIds.add(String(comment.trackedChangeCanonicalId));
9914
- const anchorKey = comment?.trackedChangeAnchorKey != null ? String(comment.trackedChangeAnchorKey) : null;
9915
- if (anchorKey) {
9916
- trackedChangeIds.add(anchorKey);
9917
- if (anchorKey.startsWith("tc::")) {
9918
- const rawId = anchorKey.slice(anchorKey.lastIndexOf("::") + 2);
9919
- if (rawId) trackedChangeIds.add(rawId);
9920
- }
9921
- }
9922
- return trackedChangeIds;
9923
- };
10120
+ const collectTrackedChangeDecisionIds = (comment) => collectTrackedChangeDecisionIdsWithAliases(comment, getCommentAliasIds(comment));
9924
10121
  const getTrackedChangeDecisionLinks = (comment) => {
9925
10122
  const linked = [];
9926
10123
  const seen = /* @__PURE__ */ new Set();
@@ -9931,28 +10128,6 @@ var useCommentsStore = defineStore("comments", () => {
9931
10128
  }
9932
10129
  return linked;
9933
10130
  };
9934
- const collectTrackedChangeEntityIdsFromReceipt = (receipt) => {
9935
- const record = receipt && typeof receipt === "object" ? receipt : null;
9936
- if (!record?.success) return /* @__PURE__ */ new Set();
9937
- const ids = /* @__PURE__ */ new Set();
9938
- const collect = (entry) => {
9939
- const ref = entry && typeof entry === "object" ? entry : null;
9940
- if (ref?.kind !== "entity" || ref.entityType !== "trackedChange") return;
9941
- if (ref.entityId != null && String(ref.entityId).length > 0) ids.add(String(ref.entityId));
9942
- };
9943
- if (Array.isArray(record.removed)) record.removed.forEach(collect);
9944
- if (Array.isArray(record.invalidatedRefs)) record.invalidatedRefs.forEach(collect);
9945
- return ids;
9946
- };
9947
- const collectReliableDecidedTrackedChangeIds = (outcome) => {
9948
- const ids = /* @__PURE__ */ new Set();
9949
- if (outcome?.decidedId != null && String(outcome.decidedId).length > 0) ids.add(String(outcome.decidedId));
9950
- if (Array.isArray(outcome?.decidedIds)) outcome.decidedIds.forEach((id) => {
9951
- if (id != null && String(id).length > 0) ids.add(String(id));
9952
- });
9953
- collectTrackedChangeEntityIdsFromReceipt(outcome?.receipt).forEach((id) => ids.add(id));
9954
- return ids;
9955
- };
9956
10131
  const detachLinkedCommentsForTrackedChangeDecision = ({ comment, decision } = {}) => {
9957
10132
  if (!comment?.trackedChange) return 0;
9958
10133
  if (!trackedChangeDecisionKeepsCommentAnchor({
@@ -10033,7 +10208,7 @@ var useCommentsStore = defineStore("comments", () => {
10033
10208
  if (previousCommentId) anchorSourceIds.add(previousCommentId);
10034
10209
  if (previousCanonicalId) anchorSourceIds.add(previousCanonicalId);
10035
10210
  }
10036
- if (comment.trackedChangeAnchorKey == null || anchorSourceIds.has(currentAnchorParts?.rawId)) comment.trackedChangeAnchorKey = toAnchor;
10211
+ if (comment.trackedChangeAnchorKey == null || anchorSourceIds.has(currentAnchorParts?.rawId ?? "")) comment.trackedChangeAnchorKey = toAnchor;
10037
10212
  comment.trackedChangePositionAliases = normalizeTrackedChangePositionAliases([...Array.isArray(comment.trackedChangePositionAliases) ? comment.trackedChangePositionAliases : [], fromId]);
10038
10213
  const identitySourceIds = /* @__PURE__ */ new Set([fromId]);
10039
10214
  if (advancesRemapLineage) {
@@ -10044,33 +10219,28 @@ var useCommentsStore = defineStore("comments", () => {
10044
10219
  if (row === comment) return;
10045
10220
  if (!belongsToTrackedChangeSyncDocument(row, normalizedDocumentId)) return;
10046
10221
  const rowIdentityUpdates = {};
10047
- for (const field of [
10048
- "trackedChangeThreadParentId",
10049
- "trackedChangeParentId",
10050
- "threadingParentCommentId",
10051
- "parentCommentId"
10052
- ]) {
10053
- if (!identitySourceIds.has(normalizeCommentId(row?.[field]))) continue;
10222
+ for (const field of PARENT_LINK_FIELDS) {
10223
+ if (!identitySourceIds.has(normalizeCommentId(row?.[field]) ?? "")) continue;
10054
10224
  row[field] = toId;
10055
10225
  rowIdentityUpdates[field] = toId;
10056
10226
  }
10057
10227
  if (Object.keys(rowIdentityUpdates).length && typeof row.updateIdentityValues === "function") row.updateIdentityValues(rowIdentityUpdates);
10058
10228
  });
10059
10229
  if (Object.keys(commentIdentityUpdates).length && typeof comment.updateIdentityValues === "function") comment.updateIdentityValues(commentIdentityUpdates);
10060
- const previousEntry = previousPositionEntry ?? [positions[fromId], positions[buildBodyTrackedChangeAnchorKey(fromId)]].find((entry) => entry && positionEntryMatchesTrackedChangeStory(entry, comment));
10230
+ const previousEntry = previousPositionEntry ?? [positions[fromId], positions[String(buildBodyTrackedChangeAnchorKey(fromId))]].find((entry) => entry && positionEntryMatchesTrackedChangeStory(entry, comment));
10061
10231
  if (previousEntry) {
10062
- for (const key of [toId, toAnchor]) if (positions[key] === void 0) {
10232
+ for (const key of [toId, String(toAnchor)]) if (positions[key] === void 0) {
10063
10233
  positions[key] = previousEntry;
10064
10234
  positionsChanged = true;
10065
10235
  }
10066
10236
  }
10067
- if (identitySourceIds.has(normalizeCommentId(activeComment.value))) activeComment.value = toId;
10068
- if (identitySourceIds.has(normalizeCommentId(activeFloatingCommentInstanceId.value))) activeFloatingCommentInstanceId.value = toId;
10237
+ if (identitySourceIds.has(normalizeCommentId(activeComment.value) ?? "")) activeComment.value = toId;
10238
+ if (identitySourceIds.has(normalizeCommentId(activeFloatingCommentInstanceId.value) ?? "")) activeFloatingCommentInstanceId.value = toId;
10069
10239
  }
10070
10240
  if (positionsChanged) editorCommentPositions.value = { ...positions };
10071
10241
  };
10072
10242
  const pruneDecidedTrackedChangeRow = ({ superdoc, comment: targetComment, decidedId, decidedIds, documentId } = {}) => {
10073
- const normalizedDecidedIds = new Set((Array.isArray(decidedIds) || decidedIds instanceof Set ? Array.from(decidedIds) : [decidedId]).map((id) => normalizeCommentId(id)).filter(Boolean));
10243
+ const normalizedDecidedIds = new Set((Array.isArray(decidedIds) || decidedIds instanceof Set ? Array.from(decidedIds) : [decidedId]).map((id) => normalizeCommentId(id)).filter(isPresent));
10074
10244
  const normalizedDocumentId = normalizeCommentId(documentId);
10075
10245
  if (!normalizedDecidedIds.size || !normalizedDocumentId) return {
10076
10246
  removed: false,
@@ -10128,39 +10298,8 @@ var useCommentsStore = defineStore("comments", () => {
10128
10298
  removedIds
10129
10299
  };
10130
10300
  };
10131
- const clearV2ActiveTrackedChangeTarget = (adapter, decidedId) => {
10132
- if (!decidedId || typeof adapter?.clearActiveTrackedChangeTargetIfMatches !== "function") return;
10133
- try {
10134
- adapter.clearActiveTrackedChangeTargetIfMatches(decidedId);
10135
- } catch {}
10136
- };
10137
- const waitForTrackedDecisionCanonicalPaint = async ({ superdoc, receipt } = {}) => {
10138
- const readiness = superdoc?.activeEditor?.documentMutationReadiness;
10139
- if (receipt?.success !== true || typeof receipt?.txId !== "string" || !receipt.txId || typeof readiness?.whenPainted !== "function") return;
10140
- try {
10141
- await readiness.whenPainted(receipt);
10142
- const requestFrame = globalThis.requestAnimationFrame;
10143
- if (typeof requestFrame === "function") await new Promise((resolve) => {
10144
- let settled = false;
10145
- const finish = () => {
10146
- if (settled) return;
10147
- settled = true;
10148
- clearTimeout(fallback);
10149
- resolve();
10150
- };
10151
- const fallback = setTimeout(finish, 250);
10152
- requestFrame(() => requestFrame(() => setTimeout(finish, 0)));
10153
- });
10154
- } catch {}
10155
- };
10156
10301
  /**
10157
10302
  * Accept or reject the tracked change behind a sidebar row.
10158
- *
10159
- * @param {Object} param0
10160
- * @param {Object} param0.superdoc The SuperDoc instance.
10161
- * @param {Object} param0.comment The tracked-change row.
10162
- * @param {string} param0.decision `'accept'` or `'reject'`.
10163
- * @returns {{ ok: boolean, success?: boolean, reason?: string } | Promise<{ ok: boolean, success?: boolean, reason?: string }>} The decision outcome.
10164
10303
  */
10165
10304
  const decideTrackedChangeFromSidebar = ({ superdoc, comment, decision }) => {
10166
10305
  const disabledReason = trackedChangeDecisionDisabledReason(superdoc);
@@ -10188,7 +10327,7 @@ var useCommentsStore = defineStore("comments", () => {
10188
10327
  return {
10189
10328
  ok: false,
10190
10329
  reason: "adapter-threw",
10191
- detail: err?.message ?? String(err)
10330
+ detail: errorDetail(err)
10192
10331
  };
10193
10332
  }
10194
10333
  })().then(async (outcome) => {
@@ -10241,9 +10380,11 @@ var useCommentsStore = defineStore("comments", () => {
10241
10380
  if (!activeEditor) return { ok: false };
10242
10381
  const id = comment.commentId ?? comment.importedId;
10243
10382
  if (!id) return { ok: false };
10244
- const story = comment.trackedChangeStory ?? void 0;
10383
+ const rawStory = comment.trackedChangeStory ?? void 0;
10384
+ const story = require_create_super_doc_ui.isStoryLocator(rawStory) ? rawStory : void 0;
10245
10385
  const documentApi = typeof activeEditor.doc === "object" ? activeEditor.doc : null;
10246
10386
  if (documentApi?.trackChanges?.decide) try {
10387
+ if (rawStory && !story) throw new TypeError("trackedChangeStory must be a valid StoryLocator");
10247
10388
  const target = story ? {
10248
10389
  id,
10249
10390
  story
@@ -10256,7 +10397,7 @@ var useCommentsStore = defineStore("comments", () => {
10256
10397
  success: Boolean(receipt?.success)
10257
10398
  }));
10258
10399
  } catch (error) {
10259
- if (story) return {
10400
+ if (rawStory) return {
10260
10401
  ok: false,
10261
10402
  error
10262
10403
  };
@@ -10303,9 +10444,9 @@ var useCommentsStore = defineStore("comments", () => {
10303
10444
  documentId: effectiveDocumentId
10304
10445
  })).removed
10305
10446
  };
10306
- const normalizedRemovedIds = new Set(Array.from(removedIds ?? []).map((id) => normalizeCommentId(id)).filter(Boolean));
10307
- const normalizedUpsertIds = [...new Set(Array.from(upsertIds ?? []).map((id) => normalizeCommentId(id)).filter(Boolean))];
10308
- const remappedSourceIds = new Set((Array.isArray(remappedPairs) ? remappedPairs : []).map((pair) => normalizeCommentId(pair?.from)).filter(Boolean));
10447
+ const normalizedRemovedIds = new Set(Array.from(removedIds ?? []).map((id) => normalizeCommentId(id)).filter(isPresent));
10448
+ const normalizedUpsertIds = [...new Set(Array.from(upsertIds ?? []).map((id) => normalizeCommentId(id)).filter(isPresent))];
10449
+ const remappedSourceIds = new Set((Array.isArray(remappedPairs) ? remappedPairs : []).map((pair) => normalizeCommentId(pair?.from)).filter(isPresent));
10309
10450
  const locallyRemovedIds = new Set([...normalizedRemovedIds].filter((id) => !remappedSourceIds.has(id)));
10310
10451
  if (locallyRemovedIds.size > 0 && effectiveDocumentId != null) pruneDecidedTrackedChangeRow({
10311
10452
  superdoc,
@@ -10324,6 +10465,10 @@ var useCommentsStore = defineStore("comments", () => {
10324
10465
  const byIdentityAlias = /* @__PURE__ */ new Map();
10325
10466
  const aliasesByRow = /* @__PURE__ */ new Map();
10326
10467
  const indexedRows = /* @__PURE__ */ new Set();
10468
+ const indexedIdentities = [];
10469
+ let building = true;
10470
+ let reusable = true;
10471
+ let reused = false;
10327
10472
  let aliasLookups = 0;
10328
10473
  let candidateVisits = 0;
10329
10474
  let rowAliasBuilds = 0;
@@ -10347,6 +10492,7 @@ var useCommentsStore = defineStore("comments", () => {
10347
10492
  index.set(alias, bucket);
10348
10493
  };
10349
10494
  const add = (comment) => {
10495
+ if (!building) reusable = false;
10350
10496
  if (!comment?.trackedChange) return;
10351
10497
  if (documentId && !belongsToTrackedChangeSyncDocument(comment, documentId)) return;
10352
10498
  indexedRows.add(comment);
@@ -10358,19 +10504,49 @@ var useCommentsStore = defineStore("comments", () => {
10358
10504
  rowAliasBuilds += 1;
10359
10505
  aliasesByRow.set(comment, aliases);
10360
10506
  aliases.forEach((alias) => addAlias(byIdentityAlias, alias, comment));
10507
+ if (building) indexedIdentities.push({
10508
+ row: comment,
10509
+ aliases,
10510
+ canonicalId: normalizeCommentId(comment.trackedChangeCanonicalId)
10511
+ });
10361
10512
  };
10362
10513
  commentsList.value.forEach(add);
10514
+ building = false;
10363
10515
  return {
10516
+ inUse: false,
10364
10517
  add,
10365
10518
  aliasesFor,
10366
- work: () => ({
10367
- trackedRowsIndexed: indexedRows.size,
10368
- invalidatedIdMembershipChecks: 0,
10369
- incomingAliasLookups: aliasLookups,
10370
- candidateVisits,
10371
- rowAliasBuilds,
10372
- rowAliasCacheHits
10373
- }),
10519
+ isCurrent: () => {
10520
+ if (!reusable) return false;
10521
+ let index = 0;
10522
+ for (const row of commentsList.value) {
10523
+ if (!row?.trackedChange || documentId && !belongsToTrackedChangeSyncDocument(row, documentId)) continue;
10524
+ const previous = indexedIdentities[index++];
10525
+ if (!previous || previous.row !== row || previous.canonicalId !== normalizeCommentId(row.trackedChangeCanonicalId)) return false;
10526
+ const aliases = getCommentAliasIds(row);
10527
+ rowAliasBuilds += 1;
10528
+ if (aliases.length !== previous.aliases.length || aliases.some((alias, i) => alias !== previous.aliases[i])) return false;
10529
+ }
10530
+ reused = index === indexedIdentities.length;
10531
+ return reused;
10532
+ },
10533
+ work: () => {
10534
+ const result = {
10535
+ trackedRowsIndexed: indexedRows.size,
10536
+ invalidatedIdMembershipChecks: 0,
10537
+ incomingAliasLookups: aliasLookups,
10538
+ candidateVisits,
10539
+ rowAliasBuilds,
10540
+ rowAliasCacheHits,
10541
+ indexReused: Number(reused)
10542
+ };
10543
+ aliasLookups = 0;
10544
+ candidateVisits = 0;
10545
+ rowAliasBuilds = 0;
10546
+ rowAliasCacheHits = 0;
10547
+ reused = false;
10548
+ return result;
10549
+ },
10374
10550
  candidates({ changeId, importedId, anchorKey, canonicalId, positionAliases = [] } = {}) {
10375
10551
  const out = /* @__PURE__ */ new Set();
10376
10552
  const include = (value) => {
@@ -10393,7 +10569,30 @@ var useCommentsStore = defineStore("comments", () => {
10393
10569
  }
10394
10570
  };
10395
10571
  };
10396
- const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null, preparedPresentation = null, previousPreparedPresentation = null, liveIds: suppliedLiveIds = null, liveAnchorKeys: suppliedLiveAnchorKeys = null, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
10572
+ const getTrackedChangeBatchIdentityIndex = (documentId) => {
10573
+ const cached = cachedTrackedChangeBatchIdentityIndex;
10574
+ if (cached?.documentId === documentId && !cached.index.inUse) {
10575
+ cached.index.inUse = true;
10576
+ let current = false;
10577
+ try {
10578
+ current = cached.index.isCurrent() && cachedTrackedChangeBatchIdentityIndex === cached;
10579
+ } finally {
10580
+ if (!current) {
10581
+ cached.index.inUse = false;
10582
+ if (cachedTrackedChangeBatchIdentityIndex === cached) cachedTrackedChangeBatchIdentityIndex = null;
10583
+ }
10584
+ }
10585
+ if (current) return cached.index;
10586
+ }
10587
+ const index = createTrackedChangeBatchIdentityIndex(documentId);
10588
+ index.inUse = true;
10589
+ cachedTrackedChangeBatchIdentityIndex = {
10590
+ documentId,
10591
+ index
10592
+ };
10593
+ return index;
10594
+ };
10595
+ const reconcileTrackedChangesFromV2 = ({ superdoc, adapter, documentId, items, pruneStale = true, preparedParams = null, preserveDraft = false, preparedPresentation = null, previousPreparedPresentation = null, liveIds: suppliedLiveIds = null, liveAnchorKeys: suppliedLiveAnchorKeys = null, hydrationGeneration } = {}) => withInteractionSpan("store.trackedChanges.reconcile", "store-reconciliation", {
10397
10596
  documentId: documentId ?? null,
10398
10597
  itemCount: Array.isArray(items) ? items.length : null,
10399
10598
  pruneStale,
@@ -10405,33 +10604,36 @@ var useCommentsStore = defineStore("comments", () => {
10405
10604
  const liveAnchorKeys = suppliedLiveAnchorKeys instanceof Set ? suppliedLiveAnchorKeys : /* @__PURE__ */ new Set();
10406
10605
  const liveIds = suppliedLiveIds instanceof Set ? suppliedLiveIds : /* @__PURE__ */ new Set();
10407
10606
  let appliedCount = 0;
10408
- const trackedChangeIdentityIndex = createTrackedChangeBatchIdentityIndex(effectiveDocumentId == null ? null : String(effectiveDocumentId));
10607
+ const trackedChangeIdentityIndex = getTrackedChangeBatchIdentityIndex(effectiveDocumentId == null ? null : String(effectiveDocumentId));
10409
10608
  const identitySpan = startInteractionSpan("store.trackedChanges.batchIdentity", "store-reconciliation", { itemCount: items.length });
10410
- const paramsList = Array.isArray(preparedParams) ? preparedParams : items.map((item) => adapter.mapV2TrackedChangeToCommentParams(item));
10411
- const previousCoordinate = previousPreparedPresentation?.coordinate;
10412
- const coordinate = preparedPresentation?.coordinate;
10413
- const retainUnchangedRows = !pruneStale && previousCoordinate && coordinate && coordinate.documentEpoch === preparedPresentation.epoch && coordinate.documentEpoch === previousPreparedPresentation.epoch && coordinate.documentEpoch === previousCoordinate.documentEpoch && typeof coordinate.mountId === "string" && coordinate.mountId.length > 0 && coordinate.mountId === previousCoordinate.mountId && preparedPresentation.baseVersion === previousPreparedPresentation.version && preparedPresentation.version === preparedPresentation.baseVersion + 1 && coordinate.reviewVersion === preparedPresentation.version && previousCoordinate.reviewVersion === previousPreparedPresentation.version && Number.isSafeInteger(coordinate.commitSequence) && Number.isSafeInteger(previousCoordinate.commitSequence) && coordinate.commitSequence >= previousCoordinate.commitSequence;
10609
+ let enteredBatch = false;
10414
10610
  try {
10611
+ const paramsList = Array.isArray(preparedParams) ? preparedParams : items.map((item) => adapter.mapV2TrackedChangeToCommentParams(item));
10612
+ const previousCoordinate = previousPreparedPresentation?.coordinate;
10613
+ const coordinate = preparedPresentation?.coordinate;
10614
+ const retainUnchangedRows = !pruneStale && previousCoordinate && coordinate && coordinate.documentEpoch === preparedPresentation.epoch && coordinate.documentEpoch === previousPreparedPresentation.epoch && coordinate.documentEpoch === previousCoordinate.documentEpoch && typeof coordinate.mountId === "string" && coordinate.mountId.length > 0 && coordinate.mountId === previousCoordinate.mountId && preparedPresentation.baseVersion === previousPreparedPresentation.version && preparedPresentation.version === preparedPresentation.baseVersion + 1 && coordinate.reviewVersion === preparedPresentation.version && previousCoordinate.reviewVersion === previousPreparedPresentation.version && Number.isSafeInteger(coordinate.commitSequence) && Number.isSafeInteger(previousCoordinate.commitSequence) && coordinate.commitSequence >= previousCoordinate.commitSequence;
10615
+ enteredBatch = true;
10415
10616
  for (const params of paramsList) {
10416
10617
  if (!params) continue;
10417
10618
  let retainUnchangedRow = false;
10619
+ const anchorParts = parseTrackedChangeAnchorKey(params.trackedChangeAnchorKey);
10620
+ const anchorStoryKey = anchorParts ? normalizeTrackedChangeStoryKey(anchorParts.storyKey) : void 0;
10418
10621
  if (preparedPresentation) {
10419
10622
  if (preparedPresentation !== committedReviewPresentations.value[String(effectiveDocumentId)]) continue;
10420
10623
  if (params.documentId != null && String(params.documentId) !== String(effectiveDocumentId)) continue;
10421
10624
  const id = normalizeCommentId(params.changeId);
10422
- const version = preparedPresentation.rowVersions?.[id];
10625
+ const version = preparedPresentation.rowVersions?.[String(id)] ?? NaN;
10423
10626
  if (!id || !Number.isSafeInteger(version) || version < 1) continue;
10424
10627
  const existing = [...trackedChangeIdentityIndex.candidates({ changeId: id })].filter((row) => String(row.fileId) === String(effectiveDocumentId) && String(row.commentId) === id);
10425
10628
  if (existing.length > 1) continue;
10426
10629
  const row = existing[0];
10427
10630
  if (row && row.trackedChangeCanonicalId !== params.trackedChangeCanonicalId) {
10428
- const previousVersion = previousPreparedPresentation?.rowVersions?.[id];
10429
- if (!row.trackedChange || params.event !== "add" || typeof params.trackedChangeCanonicalId !== "string" || !params.trackedChangeCanonicalId || !Number.isSafeInteger(previousVersion) || previousVersion < 1 || version <= previousVersion || normalizeTrackedChangeStoryKey(getTrackedChangeStoryKey(row)) !== normalizeTrackedChangeStoryKey(parseTrackedChangeAnchorKey(params.trackedChangeAnchorKey)?.storyKey) || row.trackedChangeType !== params.trackedChangeType || row.trackedChangeDisplayType !== params.trackedChangeDisplayType) continue;
10631
+ const previousVersion = previousPreparedPresentation?.rowVersions?.[id] ?? NaN;
10632
+ if (!row.trackedChange || params.event !== "add" || typeof params.trackedChangeCanonicalId !== "string" || !params.trackedChangeCanonicalId || !Number.isSafeInteger(previousVersion) || previousVersion < 1 || version <= previousVersion || normalizeTrackedChangeStoryKey(getTrackedChangeStoryKey(row)) !== anchorStoryKey || row.trackedChangeType !== params.trackedChangeType || row.trackedChangeDisplayType !== params.trackedChangeDisplayType) continue;
10430
10633
  row.trackedChangeCanonicalId = params.trackedChangeCanonicalId;
10431
- row.updateIdentityValues?.({ trackedChangeCanonicalId: params.trackedChangeCanonicalId });
10432
10634
  trackedChangeIdentityIndex.add(row);
10433
10635
  }
10434
- retainUnchangedRow = retainUnchangedRows && row?.trackedChange === true && previousPreparedPresentation.rowVersions?.[id] === version && row.trackedChangeCanonicalId === params.trackedChangeCanonicalId && row.trackedChangeType === params.trackedChangeType && row.trackedChangeDisplayType === params.trackedChangeDisplayType && normalizeTrackedChangeStoryKey(getTrackedChangeStoryKey(row)) === normalizeTrackedChangeStoryKey(parseTrackedChangeAnchorKey(params.trackedChangeAnchorKey)?.storyKey) && !row.resolvedTime && !row.resolvedById && !row.resolvedByEmail && !row.resolvedByName;
10636
+ retainUnchangedRow = retainUnchangedRows === true && row?.trackedChange === true && previousPreparedPresentation.rowVersions?.[id] === version && row.trackedChangeCanonicalId === params.trackedChangeCanonicalId && row.trackedChangeType === params.trackedChangeType && row.trackedChangeDisplayType === params.trackedChangeDisplayType && normalizeTrackedChangeStoryKey(getTrackedChangeStoryKey(row)) === anchorStoryKey && !row.resolvedTime && !row.resolvedById && !row.resolvedByEmail && !row.resolvedByName;
10435
10637
  }
10436
10638
  if (params.event === "omit") {
10437
10639
  if (params.changeId != null) liveIds.add(String(params.changeId));
@@ -10445,12 +10647,15 @@ var useCommentsStore = defineStore("comments", () => {
10445
10647
  superdoc,
10446
10648
  params,
10447
10649
  broadcastChanges: false,
10448
- trackedChangeIdentityIndex
10650
+ trackedChangeIdentityIndex,
10651
+ preserveDraft
10449
10652
  });
10450
10653
  appliedCount += 1;
10451
10654
  }
10452
10655
  } finally {
10453
- endInteractionSpan(identitySpan, trackedChangeIdentityIndex.work());
10656
+ const work = trackedChangeIdentityIndex.work();
10657
+ trackedChangeIdentityIndex.inUse = false;
10658
+ if (enteredBatch) endInteractionSpan(identitySpan, work);
10454
10659
  }
10455
10660
  if (!effectiveDocumentId || !pruneStale) {
10456
10661
  if (effectiveDocumentId) compactDuplicateBodyTrackedChangeComments(String(effectiveDocumentId));
@@ -10472,22 +10677,18 @@ var useCommentsStore = defineStore("comments", () => {
10472
10677
  return commentsList.value.filter((comment) => {
10473
10678
  if (comment?.trackedChange !== true) return false;
10474
10679
  if (normalizedDocumentId == null) return true;
10475
- const rowDocumentId = comment?.documentId ?? comment?.fileId ?? null;
10680
+ const rowDocumentId = Reflect.get(comment, "documentId") ?? comment?.fileId ?? null;
10476
10681
  return rowDocumentId != null && String(rowDocumentId) === normalizedDocumentId;
10477
10682
  }).length;
10478
10683
  };
10479
10684
  /**
10480
10685
  * Triggered when the editor locations are updated
10481
10686
  * Updates floating comment locations from the editor
10482
- *
10483
- * @param {Object} allCommentPositions The collected geometry keyed by comment / tracked-change id
10484
- * @param {{ retainMissingTrackedChangeGeometry?: boolean, retainedTrackedChangeIds?: Iterable<string> }} options Geometry reconciliation options
10485
- * @returns {void}
10486
10687
  */
10487
10688
  const handleEditorLocationsUpdate = (allCommentPositions, options = {}) => {
10488
10689
  if (allCommentPositions == null) return;
10489
10690
  const retainMissingTrackedChangeGeometry = options?.retainMissingTrackedChangeGeometry === true;
10490
- const retainedTrackedChangeIds = retainMissingTrackedChangeGeometry && options?.retainedTrackedChangeIds != null ? new Set(Array.from(options.retainedTrackedChangeIds, (id) => normalizeCommentId(id)).filter(Boolean)) : null;
10691
+ const retainedTrackedChangeIds = retainMissingTrackedChangeGeometry && options?.retainedTrackedChangeIds != null ? new Set(Array.from(options.retainedTrackedChangeIds, (id) => normalizeCommentId(id)).filter(isPresent)) : null;
10491
10692
  const previousPositions = editorCommentPositions.value || {};
10492
10693
  const normalizedPositions = {};
10493
10694
  Object.entries(allCommentPositions).forEach(([key, entry]) => {
@@ -10514,7 +10715,7 @@ var useCommentsStore = defineStore("comments", () => {
10514
10715
  return null;
10515
10716
  };
10516
10717
  const writeTrackedChangeAliases = (entry, comment, extraKeys = []) => {
10517
- const keys = [...aliasesFor(comment), ...extraKeys.map((id) => normalizeCommentId(id)).filter(Boolean)];
10718
+ const keys = [...aliasesFor(comment), ...extraKeys.map((id) => normalizeCommentId(id)).filter(isPresent)];
10518
10719
  for (const key of new Set(keys)) if (normalizedPositions[key] === void 0) normalizedPositions[key] = entry;
10519
10720
  };
10520
10721
  commentsList.value.forEach((comment) => {
@@ -10713,7 +10914,7 @@ var ellipsis_vertical_solid_default = "<svg xmlns=\"http://www.w3.org/2000/svg\"
10713
10914
  //#region ../../shared/common/icons/rotate-left-solid.svg?raw
10714
10915
  var rotate_left_solid_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M48.5 224L40 224c-13.3 0-24-10.7-24-24L16 72c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2L98.6 96.6c87.6-86.5 228.7-86.2 315.8 1c87.5 87.5 87.5 229.3 0 316.8s-229.3 87.5-316.8 0c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0c62.5 62.5 163.8 62.5 226.3 0s62.5-163.8 0-226.3c-62.2-62.2-162.7-62.5-225.3-1L185 183c6.9 6.9 8.9 17.2 5.2 26.2s-12.5 14.8-22.2 14.8L48.5 224z\"/></svg>";
10715
10916
  //#endregion
10716
- //#region src/icons.js
10917
+ //#region src/icons.ts
10717
10918
  var superdocIcons = {
10718
10919
  comment: comment_solid_default,
10719
10920
  caretDown: caret_down_solid_default,
@@ -10798,8 +10999,8 @@ var scrollThreadAnchorToFocusTarget = (presentation, primaryThreadId, fallbackTh
10798
10999
  var DEFAULT_UI_FONT_FAMILY$1 = "Arial, Helvetica, sans-serif";
10799
11000
  function configuredUiFontFamily(proxy) {
10800
11001
  const superdoc = proxy ? Reflect.get(proxy, "$superdoc") : void 0;
10801
- const config = require_create_super_doc_ui.isPlainObject(superdoc) ? superdoc.config : void 0;
10802
- return require_create_super_doc_ui.isPlainObject(config) ? config.uiDisplayFallbackFont : void 0;
11002
+ const config = require__plugin_vue_export_helper.isPlainObject(superdoc) ? superdoc.config : void 0;
11003
+ return require__plugin_vue_export_helper.isPlainObject(config) ? config.uiDisplayFallbackFont : void 0;
10803
11004
  }
10804
11005
  /**
10805
11006
  * Vue composable that returns the computed UI font-family for SuperDoc surfaces.
@@ -11077,12 +11278,9 @@ var InternalDropdown_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
11077
11278
  //#region src/components/CommentsLayer/InternalDropdown.vue
11078
11279
  var InternalDropdown_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(InternalDropdown_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-026f5d66"]]);
11079
11280
  //#endregion
11080
- //#region src/components/CommentsLayer/helpers.js
11281
+ //#region src/components/CommentsLayer/helpers.ts
11081
11282
  /**
11082
11283
  * Comments helper to format dates from timestamp
11083
- *
11084
- * @param {Number} timestamp The timestamp to format
11085
- * @returns {String} The formatted date
11086
11284
  */
11087
11285
  function formatDate(timestamp) {
11088
11286
  const date = new Date(timestamp);
@@ -11683,7 +11881,7 @@ var CommentInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ req
11683
11881
  //#region src/components/CommentsLayer/CommentInput.vue
11684
11882
  var CommentInput_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(CommentInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-aa97de44"]]);
11685
11883
  //#endregion
11686
- //#region src/internal/toolbar/built-in/url-safety.js
11884
+ //#region src/internal/toolbar/built-in/url-safety.ts
11687
11885
  /**
11688
11886
  * Minimal href sanitizer for the built-in link popover.
11689
11887
  *
@@ -11699,8 +11897,6 @@ var DANGEROUS_SCHEME = /^(javascript|data|vbscript):/i;
11699
11897
  var HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
11700
11898
  /**
11701
11899
  * Validate and normalize an href. Returns `{ href }` for safe values, or `null`.
11702
- * @param {string} value
11703
- * @returns {{ href: string }|null}
11704
11900
  */
11705
11901
  function sanitizeHref(value) {
11706
11902
  if (typeof value !== "string") return null;
@@ -11712,7 +11908,7 @@ function sanitizeHref(value) {
11712
11908
  return { href: trimmed };
11713
11909
  }
11714
11910
  //#endregion
11715
- //#region src/components/CommentsLayer/comment-urls.js
11911
+ //#region src/components/CommentsLayer/comment-urls.ts
11716
11912
  function isAbsoluteWebUrl(value) {
11717
11913
  if (!/^https?:\/\/[^\s/?#\\]+/i.test(value) || /[\s\\]/u.test(value)) return false;
11718
11914
  try {
@@ -11736,7 +11932,7 @@ function trimUrlPunctuation(value) {
11736
11932
  for (const character of value) {
11737
11933
  const close = closingDelimiter[character];
11738
11934
  if (close) balance[close] += 1;
11739
- else if (Object.hasOwn(balance, character)) balance[character] -= 1;
11935
+ else if (Object.prototype.hasOwnProperty.call(balance, character)) balance[character] -= 1;
11740
11936
  }
11741
11937
  let end = value.length;
11742
11938
  while (end > 0) {
@@ -11760,17 +11956,18 @@ function renderCommentHtml(value) {
11760
11956
  if (typeof document === "undefined") return value;
11761
11957
  const template = document.createElement("template");
11762
11958
  template.innerHTML = value;
11763
- for (const link of template.content.querySelectorAll("a")) {
11764
- const safe = sanitizeHref(link.getAttribute("href"));
11959
+ for (const link of Array.from(template.content.querySelectorAll("a"))) {
11960
+ const rawHref = link.getAttribute("href");
11961
+ const safe = rawHref === null ? null : sanitizeHref(rawHref);
11765
11962
  if (safe && (isAbsoluteWebUrl(safe.href) || /^(mailto|tel):\S+$/i.test(safe.href))) configureLink(link, safe.href);
11766
- else link.replaceWith(...link.childNodes);
11963
+ else link.replaceWith(...Array.from(link.childNodes));
11767
11964
  }
11768
11965
  const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_TEXT);
11769
11966
  const textNodes = [];
11770
- while (walker.nextNode()) textNodes.push(walker.currentNode);
11967
+ while (walker.nextNode()) if (walker.currentNode instanceof Text) textNodes.push(walker.currentNode);
11771
11968
  for (const node of textNodes) {
11772
11969
  if (node.parentElement?.closest("a, script, style, textarea, code, pre")) continue;
11773
- const text = node.textContent;
11970
+ const text = node.data;
11774
11971
  const fragment = document.createDocumentFragment();
11775
11972
  let end = 0;
11776
11973
  for (const match of text.matchAll(/(^|[\s([{])(https?:\/\/[^\s<>"']+)/gi)) {
@@ -11829,8 +12026,8 @@ var _hoisted_11$3 = {
11829
12026
  key: 0,
11830
12027
  class: "card-section comment-body"
11831
12028
  };
11832
- var _hoisted_12$2 = ["data-track-change-semantic-color-key"];
11833
- var _hoisted_13$2 = { key: 0 };
12029
+ var _hoisted_12$3 = ["data-track-change-semantic-color-key"];
12030
+ var _hoisted_13$3 = { key: 0 };
11834
12031
  var _hoisted_14$2 = { class: "change-type tracked-change-label" };
11835
12032
  var _hoisted_15$2 = {
11836
12033
  key: 0,
@@ -12613,6 +12810,16 @@ var CommentDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
12613
12810
  }
12614
12811
  handleResolve();
12615
12812
  };
12813
+ const ownsTrackedChangeDecision = (superdoc, editor) => editor !== null && proxy.$superdoc === superdoc && superdoc.activeEditor === editor;
12814
+ const restoreTrackedChangeDecisionFocus = (superdoc, editor) => {
12815
+ require__plugin_vue_export_helper.nextTick(() => {
12816
+ if (!ownsTrackedChangeDecision(superdoc, editor)) return;
12817
+ commentsStore.lastUpdate = /* @__PURE__ */ new Date();
12818
+ activeComment.value = null;
12819
+ commentsStore.setActiveComment(superdoc, activeComment.value);
12820
+ if (ownsTrackedChangeDecision(superdoc, editor)) superdoc.focus?.({ preventScroll: true });
12821
+ });
12822
+ };
12616
12823
  const handleReject = async () => {
12617
12824
  if (props.comment.trackedChange) {
12618
12825
  if (trackedChangeDecisionsAreDisabled()) return trackedChangeDecisionDisabledOutcome();
@@ -12620,23 +12827,21 @@ var CommentDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
12620
12827
  const customHandler = proxy.$superdoc.config.onTrackedChangeBubbleReject;
12621
12828
  if (props.comment.trackedChange) {
12622
12829
  if (isV2Mode.value) {
12830
+ const superdoc = proxy.$superdoc;
12831
+ const editor = superdoc.activeEditor;
12623
12832
  const outcome = await commentsStore.decideTrackedChangeFromSidebar({
12624
- superdoc: proxy.$superdoc,
12833
+ superdoc,
12625
12834
  comment: props.comment,
12626
12835
  decision: "reject"
12627
12836
  });
12837
+ if (!ownsTrackedChangeDecision(superdoc, editor)) return;
12628
12838
  if (!outcome?.ok || outcome.success === false) {
12629
12839
  reportTrackedChangeDecisionFailure("reject", outcome);
12630
12840
  return;
12631
12841
  }
12632
12842
  clearTrackedChangeDecisionFailure();
12633
- if (typeof customHandler === "function") customHandler(props.comment, proxy.$superdoc.activeEditor);
12634
- require__plugin_vue_export_helper.nextTick(() => {
12635
- commentsStore.lastUpdate = /* @__PURE__ */ new Date();
12636
- activeComment.value = null;
12637
- commentsStore.setActiveComment(proxy.$superdoc, activeComment.value);
12638
- proxy.$superdoc.focus?.({ preventScroll: true });
12639
- });
12843
+ if (typeof customHandler === "function") customHandler(props.comment, editor);
12844
+ restoreTrackedChangeDecisionFocus(superdoc, editor);
12640
12845
  return;
12641
12846
  }
12642
12847
  let decisionApplied = true;
@@ -12682,23 +12887,21 @@ var CommentDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
12682
12887
  }
12683
12888
  const customHandler = proxy.$superdoc.config.onTrackedChangeBubbleAccept;
12684
12889
  if (props.comment.trackedChange && isV2Mode.value) {
12890
+ const superdoc = proxy.$superdoc;
12891
+ const editor = superdoc.activeEditor;
12685
12892
  const outcome = await commentsStore.decideTrackedChangeFromSidebar({
12686
- superdoc: proxy.$superdoc,
12893
+ superdoc,
12687
12894
  comment: props.comment,
12688
12895
  decision: "accept"
12689
12896
  });
12897
+ if (!ownsTrackedChangeDecision(superdoc, editor)) return;
12690
12898
  if (!outcome?.ok || outcome.success === false) {
12691
12899
  reportTrackedChangeDecisionFailure("accept", outcome);
12692
12900
  return;
12693
12901
  }
12694
12902
  clearTrackedChangeDecisionFailure();
12695
- if (typeof customHandler === "function") customHandler(props.comment, proxy.$superdoc.activeEditor);
12696
- require__plugin_vue_export_helper.nextTick(() => {
12697
- commentsStore.lastUpdate = /* @__PURE__ */ new Date();
12698
- activeComment.value = null;
12699
- commentsStore.setActiveComment(proxy.$superdoc, activeComment.value);
12700
- proxy.$superdoc.focus?.({ preventScroll: true });
12701
- });
12903
+ if (typeof customHandler === "function") customHandler(props.comment, editor);
12904
+ restoreTrackedChangeDecisionFocus(superdoc, editor);
12702
12905
  return;
12703
12906
  }
12704
12907
  let v1TrackedChangeDecisionApplied = true;
@@ -13002,7 +13205,7 @@ var CommentDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
13002
13205
  "data-track-change-semantic-color-key": comment.semanticColorKey ?? void 0,
13003
13206
  ref_for: true,
13004
13207
  ref: index === 0 ? setParentBodyRef : void 0
13005
- }, [comment.trackedChangeLabel ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", _hoisted_13$2, [require__plugin_vue_export_helper.createElementVNode("span", _hoisted_14$2, require__plugin_vue_export_helper.toDisplayString(comment.trackedChangeLabel), 1), comment.trackedChangeDetailLines && comment.trackedChangeDetailLines.length ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", _hoisted_15$2, [(require__plugin_vue_export_helper.openBlock(true), require__plugin_vue_export_helper.createElementBlock(require__plugin_vue_export_helper.Fragment, null, require__plugin_vue_export_helper.renderList(comment.trackedChangeDetailLines, (line, lineIndex) => {
13208
+ }, [comment.trackedChangeLabel ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", _hoisted_13$3, [require__plugin_vue_export_helper.createElementVNode("span", _hoisted_14$2, require__plugin_vue_export_helper.toDisplayString(comment.trackedChangeLabel), 1), comment.trackedChangeDetailLines && comment.trackedChangeDetailLines.length ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", _hoisted_15$2, [(require__plugin_vue_export_helper.openBlock(true), require__plugin_vue_export_helper.createElementBlock(require__plugin_vue_export_helper.Fragment, null, require__plugin_vue_export_helper.renderList(comment.trackedChangeDetailLines, (line, lineIndex) => {
13006
13209
  return require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", {
13007
13210
  key: lineIndex,
13008
13211
  class: "tracked-change-detail-line"
@@ -13027,7 +13230,7 @@ var CommentDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
13027
13230
  style: require__plugin_vue_export_helper.normalizeStyle(trackedChangeImagePreviewStyle(comment.trackedChangeImagePreview)),
13028
13231
  loading: "lazy",
13029
13232
  decoding: "async"
13030
- }, null, 12, _hoisted_38)], 8, _hoisted_37)) : require__plugin_vue_export_helper.createCommentVNode("", true)], 10, _hoisted_12$2),
13233
+ }, null, 12, _hoisted_38)], 8, _hoisted_37)) : require__plugin_vue_export_helper.createCommentVNode("", true)], 10, _hoisted_12$3),
13031
13234
  shouldTruncate.value && isTextOverflowing.value && index === 0 ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", {
13032
13235
  key: 0,
13033
13236
  class: "show-more-toggle",
@@ -13124,7 +13327,7 @@ var CommentDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
13124
13327
  });
13125
13328
  //#endregion
13126
13329
  //#region src/components/CommentsLayer/CommentDialog.vue
13127
- var CommentDialog_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(CommentDialog_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-4220ce17"]]);
13330
+ var CommentDialog_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(CommentDialog_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-04c17a1a"]]);
13128
13331
  //#endregion
13129
13332
  //#region src/components/CommentsLayer/commentsList/ReviewDirectoryListItem.vue?vue&type=script&setup=true&lang.ts
13130
13333
  var _hoisted_1$25 = [
@@ -13454,21 +13657,25 @@ var commentsList_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ req
13454
13657
  //#region src/components/CommentsLayer/commentsList/commentsList.vue
13455
13658
  var commentsList_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(commentsList_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-8eca48e1"]]);
13456
13659
  //#endregion
13457
- //#region src/components/CommentsLayer/commentsList/super-comments-list.js
13660
+ //#region src/components/CommentsLayer/commentsList/super-comments-list.ts
13661
+ var isReviewDirectoryStore = (value) => require__plugin_vue_export_helper.isPlainObject(value) && typeof value.setReviewDirectoryFromV2 === "function" && typeof value.clearReviewDirectory === "function";
13662
+ var readCommentsStore = (superdoc) => {
13663
+ const store = superdoc?.["commentsStore"];
13664
+ return isReviewDirectoryStore(store) ? store : void 0;
13665
+ };
13458
13666
  /**
13459
13667
  * Comments list renderer (not floating comments)
13460
13668
  *
13461
13669
  * This renders a list of comments into an element, connected to main SuperDoc instance
13462
13670
  */
13463
13671
  var SuperComments = class extends require_eventemitter3.import_eventemitter3.default {
13464
- element;
13465
- config = {
13466
- comments: [],
13467
- element: null,
13468
- commentsStore: null
13469
- };
13470
13672
  constructor(options, superdoc) {
13471
13673
  super();
13674
+ this.config = {
13675
+ comments: [],
13676
+ element: null,
13677
+ commentsStore: null
13678
+ };
13472
13679
  this.config = {
13473
13680
  ...this.config,
13474
13681
  ...options
@@ -13489,7 +13696,7 @@ var SuperComments = class extends require_eventemitter3.import_eventemitter3.def
13489
13696
  this.open();
13490
13697
  }
13491
13698
  syncDirectory() {
13492
- const store = this.superdoc?.commentsStore;
13699
+ const store = readCommentsStore(this.superdoc);
13493
13700
  if (!store) return;
13494
13701
  const comments = this.directorySnapshots.comments;
13495
13702
  const trackChanges = this.directorySnapshots.trackChanges;
@@ -13507,12 +13714,14 @@ var SuperComments = class extends require_eventemitter3.import_eventemitter3.def
13507
13714
  const acceptDirectorySnapshot = (snapshot) => {
13508
13715
  if (generation !== this.directoryGeneration) return;
13509
13716
  if ((snapshot?.listStatus ?? snapshot?.status) !== "ready") {
13510
- if (this.superdoc?.commentsStore) this.superdoc.commentsStore.isReviewDirectoryLoading = true;
13717
+ const store = readCommentsStore(this.superdoc);
13718
+ if (store) store.isReviewDirectoryLoading = true;
13511
13719
  return;
13512
13720
  }
13513
13721
  const items = Array.isArray(snapshot.items) ? snapshot.items : [];
13514
13722
  if (this.directoryItemRefs[family] === items) {
13515
- if (this.superdoc?.commentsStore) this.superdoc.commentsStore.isReviewDirectoryLoading = this.directorySnapshots.comments == null || this.directorySnapshots.trackChanges == null;
13723
+ const store = readCommentsStore(this.superdoc);
13724
+ if (store) store.isReviewDirectoryLoading = this.directorySnapshots.comments == null || this.directorySnapshots.trackChanges == null;
13516
13725
  return;
13517
13726
  }
13518
13727
  this.directoryItemRefs[family] = items;
@@ -13529,15 +13738,16 @@ var SuperComments = class extends require_eventemitter3.import_eventemitter3.def
13529
13738
  };
13530
13739
  const ui = this.superdoc?.ui;
13531
13740
  if (!ui) return;
13532
- if (this.superdoc?.commentsStore) {
13533
- this.superdoc.commentsStore.isReviewDirectoryActive = true;
13534
- this.superdoc.commentsStore.isReviewDirectoryLoading = true;
13741
+ const store = readCommentsStore(this.superdoc);
13742
+ if (store) {
13743
+ store.isReviewDirectoryActive = true;
13744
+ store.isReviewDirectoryLoading = true;
13535
13745
  }
13536
13746
  this.stopDirectoryObservers = [subscribe(ui.comments, "comments"), subscribe(ui.trackChanges, "trackChanges")];
13537
13747
  }
13538
13748
  createVueApp() {
13539
13749
  this.app = require__plugin_vue_export_helper.createApp(commentsList_default);
13540
- const parentProvides = this.superdoc?.app?._context?.provides;
13750
+ const parentProvides = this.superdoc?.["app"]?._context?.provides;
13541
13751
  if (parentProvides && this.app?._context?.provides) Object.setPrototypeOf(this.app._context.provides, parentProvides);
13542
13752
  if (this.superdoc?.pinia) {
13543
13753
  setActivePinia(this.superdoc.pinia);
@@ -13561,10 +13771,11 @@ var SuperComments = class extends require_eventemitter3.import_eventemitter3.def
13561
13771
  comments: null,
13562
13772
  trackChanges: null
13563
13773
  };
13564
- if (this.superdoc?.commentsStore) {
13565
- this.superdoc.commentsStore.clearReviewDirectory();
13566
- this.superdoc.commentsStore.isReviewDirectoryActive = false;
13567
- this.superdoc.commentsStore.isReviewDirectoryLoading = false;
13774
+ const store = readCommentsStore(this.superdoc);
13775
+ if (store) {
13776
+ store.clearReviewDirectory();
13777
+ store.isReviewDirectoryActive = false;
13778
+ store.isReviewDirectoryLoading = false;
13568
13779
  }
13569
13780
  if (this.app) {
13570
13781
  this.app.unmount();
@@ -13578,7 +13789,7 @@ var SuperComments = class extends require_eventemitter3.import_eventemitter3.def
13578
13789
  }
13579
13790
  };
13580
13791
  //#endregion
13581
- //#region src/composables/use-viewport-fit.js
13792
+ //#region src/composables/use-viewport-fit.ts
13582
13793
  var CSS_PX_PER_INCH = 96;
13583
13794
  var SIDEBAR_SELECTOR = ".superdoc__right-sidebar";
13584
13795
  var PDF_PAGE_SELECTOR = ".sd-pdf-viewer-page";
@@ -13683,7 +13894,7 @@ function useViewportFit({ getSuperdoc, superdocContainerWidth, isReady, activeZo
13683
13894
  const root = superdocRoot.value;
13684
13895
  if (!root?.querySelectorAll) return null;
13685
13896
  let widest = 0;
13686
- for (const page of root.querySelectorAll(PDF_PAGE_SELECTOR)) {
13897
+ for (const page of Array.from(root.querySelectorAll(PDF_PAGE_SELECTOR))) {
13687
13898
  const measured = Number(page.clientWidth) || Number(page.getBoundingClientRect?.().width) || 0;
13688
13899
  let scaleFactor = NaN;
13689
13900
  if (typeof window !== "undefined" && typeof window.getComputedStyle === "function") scaleFactor = Number.parseFloat(window.getComputedStyle(page).getPropertyValue("--scale-factor"));
@@ -13885,124 +14096,6 @@ var composeAuthorColorResolver = (config) => {
13885
14096
  };
13886
14097
  };
13887
14098
  //#endregion
13888
- //#region ../document-api/src/errors.ts
13889
- /**
13890
- * Structured validation error thrown by document-api execute* functions.
13891
- *
13892
- * Consumers should prefer checking `error.code` over `instanceof` for resilience
13893
- * across package boundaries and bundling scenarios.
13894
- */
13895
- var DocumentApiValidationError = class DocumentApiValidationError extends Error {
13896
- constructor(code, message, details) {
13897
- super(message);
13898
- this.name = "DocumentApiValidationError";
13899
- this.code = code;
13900
- this.details = details;
13901
- Object.setPrototypeOf(this, DocumentApiValidationError.prototype);
13902
- }
13903
- };
13904
- //#endregion
13905
- //#region ../document-api/src/export/export.types.ts
13906
- /** Canonical tracked-change export modes accepted by every public export surface. */
13907
- var SD_EXPORT_MODES = [
13908
- "review-preserving",
13909
- "final",
13910
- "original"
13911
- ];
13912
- /** Default mode for modeful DOCX export. */
13913
- var DEFAULT_SD_EXPORT_MODE = "review-preserving";
13914
- var SD_COMMENT_EXPORT_POLICIES = [
13915
- "preserve",
13916
- "resolve",
13917
- "remove"
13918
- ];
13919
- var SD_CONTENT_CONTROL_EXPORT_POLICIES = ["preserve", "flatten"];
13920
- //#endregion
13921
- //#region ../document-api/src/export/export.ts
13922
- /**
13923
- * Export namespace: engine-agnostic public API and adapter contract.
13924
- *
13925
- * Validates the requested mode at the public boundary so an invalid mode fails
13926
- * closed with `INVALID_INPUT` before any document work happens, then delegates
13927
- * byte production and degradation reporting to the engine adapter.
13928
- */
13929
- function resolveMode$1(input) {
13930
- if (input != null && !require_create_super_doc_ui.isRecord(input)) throw new DocumentApiValidationError("INVALID_INPUT", "export.toDocx input must be an object.");
13931
- const raw = input?.mode;
13932
- if (raw === void 0) return DEFAULT_SD_EXPORT_MODE;
13933
- 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(", ")}.`, {
13934
- mode: raw,
13935
- allowedModes: [...SD_EXPORT_MODES]
13936
- });
13937
- return raw;
13938
- }
13939
- function resolveDocxExportPolicies(input = {}) {
13940
- if (!require_create_super_doc_ui.isRecord(input)) throw new DocumentApiValidationError("INVALID_INPUT", "DOCX export input must be an object.");
13941
- const mode = resolveMode$1(input);
13942
- const policies = input.policies;
13943
- if (policies !== void 0 && !require_create_super_doc_ui.isRecord(policies)) throw new DocumentApiValidationError("INVALID_INPUT", "DOCX export policies must be an object.");
13944
- const allowed = {
13945
- trackedChanges: SD_EXPORT_MODES,
13946
- comments: SD_COMMENT_EXPORT_POLICIES,
13947
- contentControls: SD_CONTENT_CONTROL_EXPORT_POLICIES
13948
- };
13949
- 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}.`, {
13950
- policy: key,
13951
- value
13952
- });
13953
- const requested = policies;
13954
- if (input.mode !== void 0 && requested?.trackedChanges !== void 0 && mode !== requested.trackedChanges) throw new DocumentApiValidationError("INVALID_INPUT", "mode conflicts with policies.trackedChanges.");
13955
- return {
13956
- trackedChanges: requested?.trackedChanges ?? mode,
13957
- comments: requested?.comments ?? "preserve",
13958
- contentControls: requested?.contentControls ?? "preserve"
13959
- };
13960
- }
13961
- //#endregion
13962
- //#region ../document-api/src/permission-ranges/permission-ranges.ts
13963
- function editorKey(editor) {
13964
- return editor.id?.trim() ? editor.id : editor.email?.trim() || void 0;
13965
- }
13966
- function editorMatches(editor, id) {
13967
- return Boolean(id.trim()) && (editor.id === id || Boolean(editor.email?.trim() && editor.email.trim().toLowerCase() === id.toLowerCase()));
13968
- }
13969
- /**
13970
- * Resolve a host ID or imported Word email against an explicitly supplied roster.
13971
- * Word receives the email when available; opaque IDs remain host-specific.
13972
- * Duplicate IDs/emails are ambiguous. This does not authenticate a user.
13973
- */
13974
- function resolvePermissionRangeEditor(editors, id) {
13975
- const matches = editors.filter((editor) => editorMatches(editor, id));
13976
- if (matches.length === 0) return {
13977
- status: "unknown",
13978
- id
13979
- };
13980
- if (matches.length !== 1) return {
13981
- status: "ambiguous",
13982
- id
13983
- };
13984
- const editor = matches[0];
13985
- const wordId = editor.email?.trim() || editor.id;
13986
- if (editors.filter((candidate) => editorMatches(candidate, wordId)).length !== 1) return {
13987
- status: "ambiguous",
13988
- id
13989
- };
13990
- return {
13991
- status: "resolved",
13992
- id,
13993
- editor: { ...editor },
13994
- principal: {
13995
- kind: "editor",
13996
- id: wordId
13997
- }
13998
- };
13999
- }
14000
- /** Enumerate the host roster for an editor picker, including ambiguous entries. */
14001
- function listPermissionRangeEditors(editors) {
14002
- const ids = new Set(editors.map(editorKey).filter((id) => id !== void 0));
14003
- return Array.from(ids, (id) => resolvePermissionRangeEditor(editors, id));
14004
- }
14005
- //#endregion
14006
14099
  //#region src/core/superdoc-ui-owner.ts
14007
14100
  var ownerIds = /* @__PURE__ */ new WeakMap();
14008
14101
  function getSuperDocUiOwnerId(superdoc) {
@@ -14113,18 +14206,42 @@ var FloatingComments_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
14113
14206
  const { activeComment, activeFloatingCommentInstanceId, editorCommentPositions, pendingComment, editingCommentId, instantSidebarAlignmentTargetY, instantSidebarAlignmentThreadId, instantSidebarAlignmentInstanceId } = storeToRefs(piniaCommentsStore);
14114
14207
  const { activeZoom } = storeToRefs(superdocStore);
14115
14208
  const committedPresentation = require__plugin_vue_export_helper.computed(() => commentsStore.committedReviewPresentations?.[String(props.currentDocument?.id)] ?? null);
14209
+ const committedInstanceCache = /* @__PURE__ */ new Map();
14210
+ let committedInstanceCacheOwner = "";
14211
+ const sameReviewInstance = (cached, next) => {
14212
+ const before = Object.entries(cached).filter(([key]) => key !== "comment" && key !== "rowVersion");
14213
+ const after = Object.entries(next);
14214
+ if (before.length !== after.length) return false;
14215
+ const previous = new Map(before);
14216
+ return after.every(([key, value]) => previous.has(key) && (key === "positionEntry" ? JSON.stringify(previous.get(key)) === JSON.stringify(value) : Object.is(previous.get(key), value)));
14217
+ };
14116
14218
  const committedInstances = require__plugin_vue_export_helper.computed(() => {
14117
14219
  const presentation = committedPresentation.value;
14118
14220
  if (!presentation) return null;
14119
14221
  const rows = new Map(commentsStore.commentsList.filter((row) => String(row.fileId) === String(props.currentDocument?.id)).map((row) => [String(row.commentId), row]));
14120
- return presentation.instances.flatMap((instance) => {
14222
+ const owner = `${presentation.epoch}\u0000${presentation.coordinate?.mountId ?? ""}`;
14223
+ if (owner !== committedInstanceCacheOwner) {
14224
+ committedInstanceCache.clear();
14225
+ committedInstanceCacheOwner = owner;
14226
+ }
14227
+ const live = /* @__PURE__ */ new Set();
14228
+ const instances = presentation.instances.flatMap((instance) => {
14121
14229
  const comment = instance.rowId === "pending" ? pendingComment.value : rows.get(instance.rowId);
14122
- return comment ? [{
14230
+ if (!comment) return [];
14231
+ const rowVersion = presentation.rowVersions[instance.rowId] ?? 0;
14232
+ live.add(instance.id);
14233
+ const cached = committedInstanceCache.get(instance.id);
14234
+ if (cached && cached.comment === comment && cached.rowVersion === rowVersion && sameReviewInstance(cached, instance)) return [cached];
14235
+ const merged = {
14123
14236
  ...instance,
14124
14237
  comment,
14125
- rowVersion: presentation.rowVersions[instance.rowId] ?? 0
14126
- }] : [];
14238
+ rowVersion
14239
+ };
14240
+ committedInstanceCache.set(instance.id, merged);
14241
+ return [merged];
14127
14242
  });
14243
+ for (const id of committedInstanceCache.keys()) if (!live.has(id)) committedInstanceCache.delete(id);
14244
+ return instances;
14128
14245
  });
14129
14246
  const floatingCommentInstances = require__plugin_vue_export_helper.computed(() => {
14130
14247
  if (committedInstances.value) return committedInstances.value.filter((instance) => instance.rowId !== "pending");
@@ -14540,6 +14657,18 @@ var FloatingComments_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
14540
14657
  scheduleDeferredRemeasure(() => allPositions.value.map((pos) => pos.id));
14541
14658
  });
14542
14659
  };
14660
+ const resizeHandlers = /* @__PURE__ */ new Map();
14661
+ const resizeHandlerFor = (id) => {
14662
+ let handler = resizeHandlers.get(id);
14663
+ if (!handler) {
14664
+ handler = () => {
14665
+ const position = allPositions.value.find((candidate) => candidate.id === id);
14666
+ if (position) handleResize(position);
14667
+ };
14668
+ resizeHandlers.set(id, handler);
14669
+ }
14670
+ return handler;
14671
+ };
14543
14672
  const setInstantLayoutTransitionsDisabled = (disabled) => {
14544
14673
  if (!disabled && directDecisionContinuityTargetId.value != null) return;
14545
14674
  disableInstantLayoutTransitions.value = disabled;
@@ -14944,6 +15073,7 @@ var FloatingComments_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
14944
15073
  visibilityChanged = true;
14945
15074
  }
14946
15075
  if (visibilityChanged) visibleIds.value = newVisible;
15076
+ for (const id of resizeHandlers.keys()) if (!currentIds.has(id)) resizeHandlers.delete(id);
14947
15077
  for (const id of prevPositionIds) if (!currentIds.has(id)) delete _heightsCache[id];
14948
15078
  const setChanged = prevPositionIds.size !== currentIds.size || [...prevPositionIds].some((id) => !currentIds.has(id));
14949
15079
  const orderChanged = renderedPositionOrder.length !== positionOrder.length || renderedPositionOrder.some((id, index) => id !== positionOrder[index]);
@@ -15036,12 +15166,13 @@ var FloatingComments_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
15036
15166
  style: require__plugin_vue_export_helper.normalizeStyle({
15037
15167
  top: (pos.isOffscreenReviewCard && !committedPresentation.value ? pos.top - sidebarOffsetY.value : pos.top) + "px",
15038
15168
  height: pos.height + "px",
15039
- transition: committedPresentation.value || disableInstantLayoutTransitions.value ? "none" : void 0
15169
+ transition: committedPresentation.value || disableInstantLayoutTransitions.value ? "none" : void 0,
15170
+ visibility: pos.instanceRef?.provisional ? "hidden" : void 0
15040
15171
  })
15041
15172
  }, [shouldRenderDialog(pos) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createBlock(CommentDialog_default, {
15042
15173
  key: pos.id + commentsRenderKey.value,
15043
15174
  onReady: handleDialog,
15044
- onResize: ($event) => handleResize(pos),
15175
+ onResize: resizeHandlerFor(pos.id),
15045
15176
  class: "floating-comment",
15046
15177
  parent: __props.parent,
15047
15178
  comment: pos.commentRef,
@@ -15064,7 +15195,7 @@ var FloatingComments_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
15064
15195
  });
15065
15196
  //#endregion
15066
15197
  //#region src/components/CommentsLayer/FloatingComments.vue
15067
- var FloatingComments_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(FloatingComments_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-aaf2c537"]]);
15198
+ var FloatingComments_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(FloatingComments_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-1070f5a1"]]);
15068
15199
  //#endregion
15069
15200
  //#region src/components/CommentsLayer/PdfCommentsLayer.vue?vue&type=script&setup=true&lang.ts
15070
15201
  var _hoisted_1$22 = {
@@ -15198,7 +15329,7 @@ var PdfCommentsLayer_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
15198
15329
  });
15199
15330
  //#endregion
15200
15331
  //#region src/components/CommentsLayer/PdfCommentsLayer.vue
15201
- var PdfCommentsLayer_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(PdfCommentsLayer_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-86166837"]]);
15332
+ var PdfCommentsLayer_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(PdfCommentsLayer_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e3ae65fa"]]);
15202
15333
  //#endregion
15203
15334
  //#region src/components/Whiteboard/use-whiteboard.ts
15204
15335
  var useWhiteboard = ({ proxy, layers, documents, modules }) => {
@@ -15493,7 +15624,7 @@ var WhiteboardPage_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ r
15493
15624
  });
15494
15625
  //#endregion
15495
15626
  //#region src/components/Whiteboard/WhiteboardPage.vue
15496
- var WhiteboardPage_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(WhiteboardPage_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-f730b33d"]]);
15627
+ var WhiteboardPage_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(WhiteboardPage_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-fdae8749"]]);
15497
15628
  //#endregion
15498
15629
  //#region src/components/Whiteboard/WhiteboardLayer.vue?vue&type=script&setup=true&lang.ts
15499
15630
  var WhiteboardLayer_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require__plugin_vue_export_helper.defineComponent({
@@ -15567,16 +15698,11 @@ var WhiteboardLayer_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
15567
15698
  });
15568
15699
  //#endregion
15569
15700
  //#region src/components/Whiteboard/WhiteboardLayer.vue
15570
- var WhiteboardLayer_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(WhiteboardLayer_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-980e1f94"]]);
15701
+ var WhiteboardLayer_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(WhiteboardLayer_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-800e1970"]]);
15571
15702
  //#endregion
15572
- //#region src/components/CommentsLayer/collect-removed-comment-ids.js
15703
+ //#region src/components/CommentsLayer/collect-removed-comment-ids.ts
15573
15704
  /**
15574
15705
  * Expand deleted comment ids through comment and tracked-change descendants.
15575
- *
15576
- * @param {ReadonlyArray<Record<string, any>>} comments
15577
- * @param {ReadonlyArray<string>} targetIds
15578
- * @param {(comment: Record<string, any>) => boolean} [isInScope]
15579
- * @returns {Set<string>}
15580
15706
  */
15581
15707
  var collectRemovedCommentIds = (comments, targetIds, isInScope = () => true) => {
15582
15708
  const targets = new Set(targetIds.map(String));
@@ -15638,7 +15764,7 @@ function isActiveTrackedChangeContextMenuTarget(target) {
15638
15764
  function normalizeCommentsUiConfig(commentsConfig) {
15639
15765
  if (!commentsConfig || typeof commentsConfig !== "object") return commentsConfig;
15640
15766
  const normalized = { ...commentsConfig };
15641
- const responsive = require_create_super_doc_ui.isPlainObject(commentsConfig.responsive) ? commentsConfig.responsive : {};
15767
+ const responsive = require__plugin_vue_export_helper.isPlainObject(commentsConfig.responsive) ? commentsConfig.responsive : {};
15642
15768
  const layout = firstDefined$1(commentsConfig.layout, commentsConfig.displayMode);
15643
15769
  const target = normalizeResponsiveTarget(firstDefined$1(responsive.target, commentsConfig.compactMeasurementSelector));
15644
15770
  const breakpoint = firstDefined$1(responsive.breakpoint, commentsConfig.compactBreakpointPx);
@@ -15659,7 +15785,7 @@ function normalizeCommentsUiConfig(commentsConfig) {
15659
15785
  return normalized;
15660
15786
  }
15661
15787
  //#endregion
15662
- //#region src/composables/use-comment-small-screen.js
15788
+ //#region src/composables/use-comment-small-screen.ts
15663
15789
  var SUPERDOC_DOCUMENT_SELECTOR = ".superdoc__document";
15664
15790
  var isValidCompactBreakpoint = (value) => {
15665
15791
  return require_is_finite_number.isFiniteNumber(value) && value >= 0;
@@ -15739,10 +15865,11 @@ function useCommentSmallScreen({ commentsModuleConfig, superdocRoot, layers }) {
15739
15865
  }
15740
15866
  documentWidthTargets = nextTargets;
15741
15867
  if (!nextTargets.length) return;
15742
- documentWidthResizeObserver = new ResizeObserverClass(() => {
15868
+ const observer = new ResizeObserverClass(() => {
15743
15869
  recalculateCompactCommentsMode();
15744
15870
  });
15745
- nextTargets.forEach((el) => documentWidthResizeObserver.observe(el));
15871
+ documentWidthResizeObserver = observer;
15872
+ nextTargets.forEach((el) => observer.observe(el));
15746
15873
  };
15747
15874
  const getMeasuredDocumentWidth = () => {
15748
15875
  ensureDocumentWidthObserver();
@@ -15798,7 +15925,22 @@ function useCommentSmallScreen({ commentsModuleConfig, superdocRoot, layers }) {
15798
15925
  };
15799
15926
  }
15800
15927
  //#endregion
15801
- //#region src/composables/use-compact-comment-popover.js
15928
+ //#region src/composables/use-comment-sidebar.ts
15929
+ function useCommentSidebar({ documentKey, enabled, hasContent }) {
15930
+ const reserved = require__plugin_vue_export_helper.ref(false);
15931
+ require__plugin_vue_export_helper.watch(documentKey, () => {
15932
+ reserved.value = false;
15933
+ }, { flush: "sync" });
15934
+ require__plugin_vue_export_helper.watch(() => enabled.value && hasContent.value, (visible) => {
15935
+ if (visible) reserved.value = true;
15936
+ }, {
15937
+ immediate: true,
15938
+ flush: "sync"
15939
+ });
15940
+ return require__plugin_vue_export_helper.computed(() => enabled.value && (hasContent.value || reserved.value));
15941
+ }
15942
+ //#endregion
15943
+ //#region src/composables/use-compact-comment-popover.ts
15802
15944
  var POPOVER_WIDTH_PX = 320;
15803
15945
  var SAFE_MARGIN_PX = 12;
15804
15946
  var MIN_BOTTOM_SPACE_PX = 220;
@@ -15828,7 +15970,7 @@ var resolveInteractionAnchor = (lastClickAnchor) => {
15828
15970
  var resolveInlineHighlightAnchorRect = ({ rootEl, comment, pendingComment }) => {
15829
15971
  if (Boolean(pendingComment?.value && comment?.commentId === pendingComment.value?.commentId)) {
15830
15972
  const nodes = rootEl.querySelectorAll(COMMENT_HIGHLIGHT_SELECTOR);
15831
- for (const node of nodes) {
15973
+ for (const node of Array.from(nodes)) {
15832
15974
  if (!parseCommentIds(node.getAttribute(COMMENT_HIGHLIGHT_DATA_ATTR)).includes("pending")) continue;
15833
15975
  if (typeof node.getBoundingClientRect !== "function") continue;
15834
15976
  return node.getBoundingClientRect();
@@ -15838,7 +15980,7 @@ var resolveInlineHighlightAnchorRect = ({ rootEl, comment, pendingComment }) =>
15838
15980
  if (!anchorId) return null;
15839
15981
  const safeId = String(anchorId);
15840
15982
  const highlightNodes = rootEl.querySelectorAll(COMMENT_HIGHLIGHT_SELECTOR);
15841
- for (const node of highlightNodes) {
15983
+ for (const node of Array.from(highlightNodes)) {
15842
15984
  if (!parseCommentIds(node.getAttribute(COMMENT_HIGHLIGHT_DATA_ATTR)).includes(safeId)) continue;
15843
15985
  if (typeof node.getBoundingClientRect !== "function") continue;
15844
15986
  return node.getBoundingClientRect();
@@ -15923,9 +16065,10 @@ function useCompactCommentPopover({ activeComment, pendingComment, activeCompact
15923
16065
  };
15924
16066
  const trackCompactPopoverClickAnchor = (e) => {
15925
16067
  const root = superdocRoot.value;
15926
- if (!root || !layers.value?.contains(e.target)) return;
15927
- const anchorElement = (typeof document.elementsFromPoint === "function" ? document.elementsFromPoint(e.clientX, e.clientY) : []).find((node) => node?.nodeType === 1 && root.contains(node) && node.closest("[data-track-change-id], .superdoc-comment-highlight, .sd-comment-anchor"))?.closest("[data-track-change-id], .superdoc-comment-highlight, .sd-comment-anchor") ?? (e.target?.nodeType === 1 ? e.target.closest("[data-track-change-id], .superdoc-comment-highlight, .sd-comment-anchor") : null);
15928
- if (clearCompactPopoverIfPdfClickedOutside(root, e.target, anchorElement)) return;
16068
+ const target = e.target instanceof Node ? e.target : null;
16069
+ if (!root || !layers.value?.contains(target)) return;
16070
+ const anchorElement = (typeof document.elementsFromPoint === "function" ? document.elementsFromPoint(e.clientX, e.clientY) : []).find((node) => node?.nodeType === 1 && root.contains(node) && node.closest("[data-track-change-id], .superdoc-comment-highlight, .sd-comment-anchor"))?.closest("[data-track-change-id], .superdoc-comment-highlight, .sd-comment-anchor") ?? (target instanceof Element ? target.closest("[data-track-change-id], .superdoc-comment-highlight, .sd-comment-anchor") : null);
16071
+ if (clearCompactPopoverIfPdfClickedOutside(root, target, anchorElement)) return;
15929
16072
  if (e.button !== 0 || e.pointerType !== "mouse") return;
15930
16073
  const anchorRect = anchorElement && typeof anchorElement.getBoundingClientRect === "function" ? anchorElement.getBoundingClientRect() : null;
15931
16074
  if (!anchorRect) return;
@@ -16128,10 +16271,10 @@ function mergeCommentsConfig(config, presentation) {
16128
16271
  * existing UI suppression rules keep their current behavior.
16129
16272
  */
16130
16273
  function normalizeHyperlinksConfig(config = {}) {
16131
- const canonical = require_create_super_doc_ui.isPlainObject(config.hyperlinks) ? config.hyperlinks : {};
16274
+ const canonical = require__plugin_vue_export_helper.isPlainObject(config.hyperlinks) ? config.hyperlinks : {};
16132
16275
  const hasCanonicalHandler = typeof canonical.onActivate === "function";
16133
- const ui = require_create_super_doc_ui.isPlainObject(config.ui) ? config.ui : {};
16134
- const legacyUi = require_create_super_doc_ui.isPlainObject(ui.linkPopover) ? ui.linkPopover : {};
16276
+ const ui = require__plugin_vue_export_helper.isPlainObject(config.ui) ? config.ui : {};
16277
+ const legacyUi = require__plugin_vue_export_helper.isPlainObject(ui.linkPopover) ? ui.linkPopover : {};
16135
16278
  const allActivationDisabled = config.hyperlinks === false;
16136
16279
  const builtInEditorDisabled = config.ui === false || ui.linkPopover === false;
16137
16280
  const selectedHandler = [
@@ -16159,7 +16302,7 @@ function normalizeHyperlinksConfig(config = {}) {
16159
16302
  };
16160
16303
  }
16161
16304
  //#endregion
16162
- //#region src/helpers/v2-review-target.js
16305
+ //#region src/helpers/v2-review-target.ts
16163
16306
  /**
16164
16307
  * Resolve the comments-store identity for a document-origin v2 review target.
16165
16308
  * Painted review carriers can become interactive before the asynchronous row
@@ -16175,15 +16318,126 @@ function resolveV2ReviewTargetCommentId(target, getComment) {
16175
16318
  return commentId != null ? String(commentId) : null;
16176
16319
  }
16177
16320
  //#endregion
16178
- //#region src/helpers/v2-mutation-exception.js
16321
+ //#region src/helpers/v2-review-geometry-delivery.ts
16322
+ function createReviewGeometryDelivery(deliver) {
16323
+ const packets = /* @__PURE__ */ new Map();
16324
+ let stageOwners = /* @__PURE__ */ new WeakMap();
16325
+ let active = null;
16326
+ const documentOf = (current) => current.documentId != null ? String(current.documentId) : current.mountContainer?.dataset.superdocV2DocumentId ?? null;
16327
+ const matches = (documentId, current) => current.mountContainer?.dataset.superdocV2DocumentId === documentId && (current.documentId == null || String(current.documentId) === documentId);
16328
+ const matchesPaint = (packet, current) => typeof packet.payload.paintEpoch !== "number" || packet.payload.paintEpoch === current.epoch;
16329
+ const observe = (current) => {
16330
+ const stage = current.mountContainer;
16331
+ const documentId = documentOf(current);
16332
+ if (!stage || !documentId || !matches(documentId, current)) return;
16333
+ const previousOwner = stageOwners.get(stage);
16334
+ if (previousOwner && previousOwner !== documentId) packets.delete(previousOwner);
16335
+ stageOwners.set(stage, documentId);
16336
+ const packet = packets.get(documentId);
16337
+ if (packet?.stage && packet.stage !== stage) packets.delete(documentId);
16338
+ else if (packet && (!active || active.stage !== stage || active.documentId !== documentId || active.epoch !== current.epoch)) packet.delivered = false;
16339
+ active = {
16340
+ documentId,
16341
+ stage,
16342
+ epoch: current.epoch
16343
+ };
16344
+ };
16345
+ const dispatch = (documentId, packet, current, replay = false) => {
16346
+ if (!current.mountContainer || !matches(documentId, current) || !matchesPaint(packet, current)) return false;
16347
+ if (packet.stage && packet.stage !== current.mountContainer || packet.delivering || packet.delivered && !replay) return false;
16348
+ const wasDelivered = packet.delivered;
16349
+ const previousStage = packet.stage;
16350
+ packet.stage = current.mountContainer;
16351
+ packet.delivered = true;
16352
+ packet.delivering = true;
16353
+ try {
16354
+ deliver(current, packet.payload);
16355
+ } catch (error) {
16356
+ packet.delivered = wasDelivered;
16357
+ packet.stage = previousStage;
16358
+ throw error;
16359
+ } finally {
16360
+ packet.delivering = false;
16361
+ }
16362
+ return true;
16363
+ };
16364
+ const notify = (documentId, payload, current, ready = true) => {
16365
+ if (!payload.reviewGeometry || !Array.isArray(payload.pageIndices)) return false;
16366
+ let key;
16367
+ try {
16368
+ key = JSON.stringify([
16369
+ documentId,
16370
+ payload.documentEpoch,
16371
+ payload.paintEpoch,
16372
+ payload.commitSequence,
16373
+ payload.pageIndices,
16374
+ payload.zoomScale,
16375
+ payload.reviewGeometry
16376
+ ]);
16377
+ } catch {
16378
+ return false;
16379
+ }
16380
+ const isCurrent = current != null && matches(documentId, current);
16381
+ if (isCurrent) observe(current);
16382
+ const previous = packets.get(documentId);
16383
+ if (previous && previous.payload.documentEpoch === payload.documentEpoch && typeof previous.payload.paintEpoch === "number" && typeof payload.paintEpoch === "number" && payload.paintEpoch < previous.payload.paintEpoch) return false;
16384
+ if (previous && previous.payload.documentEpoch === payload.documentEpoch && typeof previous.payload.commitSequence === "number" && typeof payload.commitSequence === "number" && payload.commitSequence < previous.payload.commitSequence) return false;
16385
+ if (previous && previous.payload.documentEpoch === payload.documentEpoch && typeof previous.payload.generation === "number" && typeof payload.generation === "number" && payload.generation < previous.payload.generation) return false;
16386
+ if (isCurrent && typeof payload.paintEpoch === "number" && typeof current.epoch === "number" && payload.paintEpoch < current.epoch) return false;
16387
+ if (previous?.key === key) {
16388
+ previous.payload = payload;
16389
+ return isCurrent && ready ? dispatch(documentId, previous, current) : false;
16390
+ }
16391
+ const packet = {
16392
+ payload,
16393
+ key,
16394
+ stage: isCurrent ? current.mountContainer : previous && previous.payload.documentEpoch === payload.documentEpoch ? previous.stage : null,
16395
+ delivered: false,
16396
+ delivering: false
16397
+ };
16398
+ packets.set(documentId, packet);
16399
+ if (!isCurrent || !ready) return false;
16400
+ try {
16401
+ return dispatch(documentId, packet, current);
16402
+ } catch (error) {
16403
+ if (previous) packets.set(documentId, previous);
16404
+ else packets.delete(documentId);
16405
+ throw error;
16406
+ }
16407
+ };
16408
+ return {
16409
+ notify,
16410
+ observe,
16411
+ flush(current) {
16412
+ observe(current);
16413
+ const documentId = documentOf(current);
16414
+ const packet = documentId == null ? null : packets.get(documentId);
16415
+ return documentId && packet ? dispatch(documentId, packet, current) : false;
16416
+ },
16417
+ replay(current) {
16418
+ observe(current);
16419
+ const documentId = documentOf(current);
16420
+ const packet = documentId == null ? null : packets.get(documentId);
16421
+ return documentId && packet ? dispatch(documentId, packet, current, true) : false;
16422
+ },
16423
+ reset() {
16424
+ packets.clear();
16425
+ stageOwners = /* @__PURE__ */ new WeakMap();
16426
+ active = null;
16427
+ }
16428
+ };
16429
+ }
16430
+ //#endregion
16431
+ //#region src/helpers/v2-mutation-exception.ts
16179
16432
  var FAILURE_SOURCES = /* @__PURE__ */ new Set(["shell", "receipt"]);
16180
16433
  var DIAGNOSTIC_CODE = /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/;
16181
16434
  var COMMAND_KIND = /^[a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?$/;
16182
16435
  function createV2MutationRejectionCause(event) {
16183
- if (!event || typeof event !== "object") return {};
16184
- const reason = event.reason ?? (event.failureSource === "receipt" ? event.failure?.code : void 0);
16436
+ if (!require__plugin_vue_export_helper.isPlainObject(event)) return {};
16437
+ const failure = require__plugin_vue_export_helper.isPlainObject(event.failure) ? event.failure : void 0;
16438
+ const reason = event.reason ?? (event.failureSource === "receipt" ? failure?.code : void 0);
16185
16439
  return {
16186
- ...FAILURE_SOURCES.has(event.failureSource) ? { failureSource: event.failureSource } : {},
16440
+ ...typeof event.failureSource === "string" && FAILURE_SOURCES.has(event.failureSource) ? { failureSource: event.failureSource } : {},
16187
16441
  ...typeof reason === "string" && DIAGNOSTIC_CODE.test(reason) ? { reason } : {},
16188
16442
  ...typeof event.inputKind === "string" && DIAGNOSTIC_CODE.test(event.inputKind) ? { inputKind: event.inputKind } : {},
16189
16443
  ...typeof event.editableCommandKind === "string" && event.editableCommandKind.length <= 128 && COMMAND_KIND.test(event.editableCommandKind) ? { editableCommandKind: event.editableCommandKind } : {}
@@ -16211,7 +16465,7 @@ function createV2MutationRejectionNotificationGate(matches) {
16211
16465
  };
16212
16466
  }
16213
16467
  //#endregion
16214
- //#region src/helpers/v2-author-required-rejection.js
16468
+ //#region src/helpers/v2-author-required-rejection.ts
16215
16469
  var NO_AUTHOR_SIGNAL = "no-author-configured";
16216
16470
  /** Stable, non-terminal exception code surfaced to consumers. */
16217
16471
  var V2_AUTHOR_REQUIRED_CODE = "author-required";
@@ -16223,15 +16477,11 @@ var V2_AUTHOR_REQUIRED_MESSAGE = "This edit needs an author identity. Set `user.
16223
16477
  function messageHasNoAuthorSignal(message) {
16224
16478
  return typeof message === "string" && message.includes(NO_AUTHOR_SIGNAL);
16225
16479
  }
16226
- /**
16227
- * @param {any} event - a `v2-host-event` payload.
16228
- * @returns {boolean} true when the rejection means the session needs an author.
16229
- */
16230
16480
  function isV2AuthorRequiredRejection(event) {
16231
- if (!event || event.type !== "mutation:rejected") return false;
16481
+ if (!require__plugin_vue_export_helper.isPlainObject(event) || event.type !== "mutation:rejected") return false;
16232
16482
  if (event.failureSource === "receipt") {
16233
16483
  const failure = event.failure;
16234
- if (!failure) return false;
16484
+ if (!require__plugin_vue_export_helper.isPlainObject(failure)) return false;
16235
16485
  return failure.code === "PRECONDITION_FAILED" && messageHasNoAuthorSignal(failure.message);
16236
16486
  }
16237
16487
  if (event.failureSource === "shell") {
@@ -16244,7 +16494,7 @@ function createV2AuthorRequiredNotificationGate() {
16244
16494
  return createV2MutationRejectionNotificationGate(isV2AuthorRequiredRejection);
16245
16495
  }
16246
16496
  //#endregion
16247
- //#region src/helpers/v2-bulk-decision-event.js
16497
+ //#region src/helpers/v2-bulk-decision-event.ts
16248
16498
  function toV2BulkDecisionEvent(documentId, fact) {
16249
16499
  if (fact?.schemaVersion !== 1 || fact.decision !== "accept" && fact.decision !== "reject") return null;
16250
16500
  return {
@@ -16256,7 +16506,7 @@ function toV2BulkDecisionEvent(documentId, fact) {
16256
16506
  };
16257
16507
  }
16258
16508
  //#endregion
16259
- //#region src/helpers/v2-keyboard-edit-rejection.js
16509
+ //#region src/helpers/v2-keyboard-edit-rejection.ts
16260
16510
  var EDIT_INPUT_KINDS = /* @__PURE__ */ new Set([
16261
16511
  "keydown",
16262
16512
  "beforeinput",
@@ -16306,7 +16556,7 @@ var EDIT_FAILURE_SOURCES = /* @__PURE__ */ new Set(["shell", "receipt"]);
16306
16556
  var V2_EDIT_REJECTED_CODE = "edit-rejected";
16307
16557
  var V2_EDIT_REJECTED_MESSAGE = "This edit couldn’t be completed. Adjust the selection and try again.";
16308
16558
  function isV2KeyboardEditRejection(event) {
16309
- return Boolean(event && event.type === "mutation:rejected" && event.origin === "document-surface" && EDIT_FAILURE_SOURCES.has(event.failureSource) && EDIT_INPUT_KINDS.has(event.inputKind) && (EDIT_COMMAND_KINDS.has(event.editableCommandKind) || event.editableCommandKind == null && EDIT_INPUT_WITHOUT_COMMAND_KINDS.has(event.inputKind)));
16559
+ return require__plugin_vue_export_helper.isPlainObject(event) && event.type === "mutation:rejected" && event.origin === "document-surface" && EDIT_FAILURE_SOURCES.has(event.failureSource) && EDIT_INPUT_KINDS.has(event.inputKind) && (EDIT_COMMAND_KINDS.has(event.editableCommandKind) || event.editableCommandKind == null && EDIT_INPUT_WITHOUT_COMMAND_KINDS.has(event.inputKind));
16310
16560
  }
16311
16561
  function createV2KeyboardEditRejectionException(documentId, event) {
16312
16562
  return {
@@ -16320,24 +16570,17 @@ function createV2KeyboardEditRejectionNotificationGate() {
16320
16570
  return createV2MutationRejectionNotificationGate(isV2KeyboardEditRejection);
16321
16571
  }
16322
16572
  //#endregion
16323
- //#region src/helpers/v2-selection-sync.js
16573
+ //#region src/helpers/v2-selection-sync.ts
16324
16574
  /**
16325
16575
  * A logical v2 selection snapshot represents a non-empty range when its anchor
16326
16576
  * and focus point at different block positions. Mirrors the range check the v2
16327
16577
  * shell uses when it emits `v2-selection-changed`.
16328
- *
16329
- * @param {{ anchor?: { blockId?: unknown, blockOffset?: unknown }, focus?: { blockId?: unknown, blockOffset?: unknown } } | null | undefined} snapshot
16330
- * @returns {boolean}
16331
16578
  */
16332
16579
  var isV2RangeSnapshot = (snapshot) => Boolean(snapshot?.anchor && snapshot?.focus && (snapshot.anchor.blockId !== snapshot.focus.blockId || snapshot.anchor.blockOffset !== snapshot.focus.blockOffset));
16333
16580
  /**
16334
16581
  * Detect a real browser text selection whose endpoints are outside the active
16335
16582
  * v2 mount. Editable host selections can have no native DOM range, so an
16336
16583
  * absent range must not count as an outside selection.
16337
- *
16338
- * @param {Selection | null | undefined} selection
16339
- * @param {Node | null | undefined} root
16340
- * @returns {boolean}
16341
16584
  */
16342
16585
  var hasOutsideV2DomRangeSelection = (selection, root) => {
16343
16586
  if (!selection || selection.rangeCount < 1 || selection.isCollapsed || !root) return false;
@@ -16353,10 +16596,6 @@ var hasOutsideV2DomRangeSelection = (selection, root) => {
16353
16596
  * host snapshot rather than clobber the selection the host just published.
16354
16597
  * Only editable modes use the host snapshot. Viewing mode keeps native DOM
16355
16598
  * selection, and unknown modes should not preserve stale host state.
16356
- *
16357
- * @param {string | null | undefined} documentMode
16358
- * @param {unknown} hostSnapshot
16359
- * @returns {boolean}
16360
16599
  */
16361
16600
  var shouldPreserveHostV2Selection = (documentMode, hostSnapshot) => {
16362
16601
  if (documentMode !== "editing" && documentMode !== "suggesting") return false;
@@ -16367,10 +16606,6 @@ var shouldPreserveHostV2Selection = (documentMode, hostSnapshot) => {
16367
16606
  * rebuilt. Keep an already-positioned comment affordance during that gap when
16368
16607
  * the host still owns a range; otherwise the button unmounts and remounts on
16369
16608
  * consecutive paint frames, making it blink and intercepting its own click.
16370
- *
16371
- * @param {boolean} hasHostRange
16372
- * @param {{ source?: unknown } | null | undefined} selectionPosition
16373
- * @returns {boolean}
16374
16609
  */
16375
16610
  var shouldRetainV2FloatingSelection = (hasHostRange, selectionPosition) => hasHostRange === true && selectionPosition?.source === "document-editor";
16376
16611
  //#endregion
@@ -16562,7 +16797,7 @@ function usePasswordPrompt({ getSurfaceManager, getPasswordPromptConfig, onUnhan
16562
16797
  })
16563
16798
  });
16564
16799
  } else {
16565
- const mod = await Promise.resolve().then(() => require("./chunks/PasswordPromptSurface-BNkaztaP.cjs"));
16800
+ const mod = await Promise.resolve().then(() => require("./chunks/PasswordPromptSurface-VFPnQOML.cjs"));
16566
16801
  const surfaceId = `password-prompt-${doc.id}`;
16567
16802
  handle = manager.open({
16568
16803
  id: surfaceId,
@@ -16664,9 +16899,6 @@ function createReplaceContinuation(session, { getCurrentSession, applySlice, onS
16664
16899
  }
16665
16900
  //#endregion
16666
16901
  //#region src/composables/use-find-replace.ts
16667
- function isThenable$2(value) {
16668
- return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
16669
- }
16670
16902
  var DEFAULT_TEXTS = {
16671
16903
  findPlaceholder: "Find",
16672
16904
  findAriaLabel: "Find text",
@@ -16841,7 +17073,7 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
16841
17073
  try {
16842
17074
  result = search.replace(replaceText.value);
16843
17075
  } catch {}
16844
- if (isThenable$2(result)) Promise.resolve(result).then(finish, finish);
17076
+ if (require__plugin_vue_export_helper.isThenable(result)) Promise.resolve(result).then(finish, finish);
16845
17077
  else finish();
16846
17078
  }
16847
17079
  function replaceAll() {
@@ -16863,7 +17095,7 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
16863
17095
  try {
16864
17096
  result = search.replaceAll(replaceText.value);
16865
17097
  } catch {}
16866
- if (isThenable$2(result)) Promise.resolve(result).then(finish, finish);
17098
+ if (require__plugin_vue_export_helper.isThenable(result)) Promise.resolve(result).then(finish, finish);
16867
17099
  else finish();
16868
17100
  }
16869
17101
  function syncFromSearchSession() {
@@ -17225,7 +17457,7 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
17225
17457
  } else {
17226
17458
  let FindReplaceSurface;
17227
17459
  try {
17228
- FindReplaceSurface = (await Promise.resolve().then(() => require("./chunks/FindReplaceSurface-BNDrJ6VS.cjs"))).default;
17460
+ FindReplaceSurface = (await Promise.resolve().then(() => require("./chunks/FindReplaceSurface-DWXgWgg7.cjs"))).default;
17229
17461
  } catch {
17230
17462
  opening = false;
17231
17463
  return;
@@ -17492,7 +17724,7 @@ var plus_solid_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0
17492
17724
  //#region ../../shared/common/icons/trash-can-solid.svg?raw
17493
17725
  var trash_can_solid_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M135.2 17.7C140.6 6.8 151.7 0 163.8 0L284.2 0c12.1 0 23.2 6.8 28.6 17.7L320 32l96 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 96C14.3 96 0 81.7 0 64S14.3 32 32 32l96 0 7.2-14.3zM32 128l384 0 0 320c0 35.3-28.7 64-64 64L96 512c-35.3 0-64-28.7-64-64l0-320zm96 64c-8.8 0-16 7.2-16 16l0 224c0 8.8 7.2 16 16 16s16-7.2 16-16l0-224c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16l0 224c0 8.8 7.2 16 16 16s16-7.2 16-16l0-224c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16l0 224c0 8.8 7.2 16 16 16s16-7.2 16-16l0-224c0-8.8-7.2-16-16-16z\"/></svg>";
17494
17726
  //#endregion
17495
- //#region src/internal/toolbar/built-in/toolbarIcons.js
17727
+ //#region src/internal/toolbar/built-in/toolbarIcons.ts
17496
17728
  var toolbarIcons = {
17497
17729
  undo: rotate_left_solid_default,
17498
17730
  redo: rotate_right_solid_default,
@@ -17599,11 +17831,11 @@ var _hoisted_8$3 = { class: "input-row url-input-row" };
17599
17831
  var _hoisted_9$2 = ["innerHTML"];
17600
17832
  var _hoisted_10$2 = ["readonly", "onKeydown"];
17601
17833
  var _hoisted_11$2 = ["innerHTML"];
17602
- var _hoisted_12$1 = {
17834
+ var _hoisted_12$2 = {
17603
17835
  key: 0,
17604
17836
  class: "input-row link-buttons"
17605
17837
  };
17606
- var _hoisted_13$1 = ["disabled"];
17838
+ var _hoisted_13$2 = ["disabled"];
17607
17839
  var _hoisted_14$1 = ["innerHTML"];
17608
17840
  var _hoisted_15$1 = ["disabled"];
17609
17841
  var _hoisted_16$1 = {
@@ -17876,7 +18108,7 @@ var LinkInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ requir
17876
18108
  "data-item": "btn-link-open"
17877
18109
  }, null, 10, _hoisted_11$2)
17878
18110
  ]),
17879
- !isViewingMode.value ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", _hoisted_12$1, [isEditing.value ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("button", {
18111
+ !isViewingMode.value ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", _hoisted_12$2, [isEditing.value ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("button", {
17880
18112
  key: 0,
17881
18113
  class: "remove-btn",
17882
18114
  onClick: handleRemove,
@@ -17885,7 +18117,7 @@ var LinkInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ requir
17885
18117
  }, [require__plugin_vue_export_helper.createElementVNode("div", {
17886
18118
  class: "remove-btn__icon",
17887
18119
  innerHTML: require__plugin_vue_export_helper.unref(toolbarIcons).removeLink
17888
- }, null, 8, _hoisted_14$1), _cache[6] || (_cache[6] = require__plugin_vue_export_helper.createTextVNode(" Remove ", -1))], 8, _hoisted_13$1)) : require__plugin_vue_export_helper.createCommentVNode("", true), require__plugin_vue_export_helper.createElementVNode("button", {
18120
+ }, null, 8, _hoisted_14$1), _cache[6] || (_cache[6] = require__plugin_vue_export_helper.createTextVNode(" Remove ", -1))], 8, _hoisted_13$2)) : require__plugin_vue_export_helper.createCommentVNode("", true), require__plugin_vue_export_helper.createElementVNode("button", {
17889
18121
  class: require__plugin_vue_export_helper.normalizeClass(["sd-submit-btn", { "disable-btn": isDisabled.value }]),
17890
18122
  onClick: handleSubmit,
17891
18123
  disabled: isSubmitting.value,
@@ -17902,7 +18134,7 @@ var LinkInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ requir
17902
18134
  //#region src/internal/toolbar/built-in/LinkInput.vue
17903
18135
  var LinkInput_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(LinkInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-172107e4"]]);
17904
18136
  //#endregion
17905
- //#region src/internal/toolbar/built-in/scroll-helpers.js
18137
+ //#region src/internal/toolbar/built-in/scroll-helpers.ts
17906
18138
  function getScrollableParent(element) {
17907
18139
  let currentElement = element;
17908
18140
  while (currentElement) {
@@ -17935,26 +18167,25 @@ function scrollToElement(targetElement, options = {
17935
18167
  var FLOATING_SURFACE_ID = "link-popover";
17936
18168
  var RECENT_OUTSIDE_CLOSE_MS = 500;
17937
18169
  var MAX_ANCHOR_NAVIGATION_STEPS = 4;
17938
- var isThenable$1 = (value) => Boolean(value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function");
17939
18170
  function isLinkPopoverDocumentApi(value) {
17940
- return require_create_super_doc_ui.isPlainObject(value) || typeof value === "function";
18171
+ return require__plugin_vue_export_helper.isPlainObject(value) || typeof value === "function";
17941
18172
  }
17942
18173
  function linkPopoverDocumentApi(editor) {
17943
18174
  const doc = editor?.doc;
17944
18175
  return isLinkPopoverDocumentApi(doc) ? doc : null;
17945
18176
  }
17946
18177
  function isLinkNavigationHost(value) {
17947
- return require_create_super_doc_ui.isPlainObject(value) || typeof value === "function";
18178
+ return require__plugin_vue_export_helper.isPlainObject(value) || typeof value === "function";
17948
18179
  }
17949
18180
  function isHyperlinkTarget(value) {
17950
- if (!require_create_super_doc_ui.isPlainObject(value) || value.kind !== "inline" || value.nodeType !== "hyperlink") return false;
17951
- const anchor = require_create_super_doc_ui.isPlainObject(value.anchor) ? value.anchor : null;
17952
- const start = anchor && require_create_super_doc_ui.isPlainObject(anchor.start) ? anchor.start : null;
17953
- const end = anchor && require_create_super_doc_ui.isPlainObject(anchor.end) ? anchor.end : null;
18181
+ if (!require__plugin_vue_export_helper.isPlainObject(value) || value.kind !== "inline" || value.nodeType !== "hyperlink") return false;
18182
+ const anchor = require__plugin_vue_export_helper.isPlainObject(value.anchor) ? value.anchor : null;
18183
+ const start = anchor && require__plugin_vue_export_helper.isPlainObject(anchor.start) ? anchor.start : null;
18184
+ const end = anchor && require__plugin_vue_export_helper.isPlainObject(anchor.end) ? anchor.end : null;
17954
18185
  return typeof start?.blockId === "string" && typeof start.offset === "number" && typeof end?.blockId === "string" && typeof end.offset === "number";
17955
18186
  }
17956
18187
  function isValidResolution(value) {
17957
- if (!require_create_super_doc_ui.isPlainObject(value)) return false;
18188
+ if (!require__plugin_vue_export_helper.isPlainObject(value)) return false;
17958
18189
  if (value.type === "default" || value.type === "suppress" || value.type === "none") return true;
17959
18190
  if (value.type === "custom") return value.component != null;
17960
18191
  if (value.type === "external") return typeof value.render === "function";
@@ -17991,8 +18222,8 @@ function readPaintedSourceRef(element) {
17991
18222
  if (!encoded) return null;
17992
18223
  try {
17993
18224
  const parsed = JSON.parse(encoded);
17994
- const sourceRef = require_create_super_doc_ui.isPlainObject(parsed) ? parsed.sourceRef : void 0;
17995
- if (!require_create_super_doc_ui.isPlainObject(sourceRef)) return null;
18225
+ const sourceRef = require__plugin_vue_export_helper.isPlainObject(parsed) ? parsed.sourceRef : void 0;
18226
+ if (!require__plugin_vue_export_helper.isPlainObject(sourceRef)) return null;
17996
18227
  const partUri = typeof sourceRef.partUri === "string" ? sourceRef.partUri : void 0;
17997
18228
  const xpathLikePath = typeof sourceRef.xpathLikePath === "string" ? sourceRef.xpathLikePath : void 0;
17998
18229
  return partUri || xpathLikePath ? {
@@ -18580,7 +18811,7 @@ function useLinkPopover({ getSurfaceManager, getActiveEditor, getUi, getActivati
18580
18811
  const fallbackResolution = () => usesOnActivate ? { type: "suppress" } : { type: "default" };
18581
18812
  try {
18582
18813
  const resolution = handler(ctx);
18583
- if (isThenable$1(resolution)) {
18814
+ if (require__plugin_vue_export_helper.isThenable(resolution)) {
18584
18815
  Promise.resolve(resolution).catch(() => void 0);
18585
18816
  emitException({
18586
18817
  error: /* @__PURE__ */ new Error(usesOnActivate ? "hyperlinks.onActivate must return synchronously; Promises are not supported." : "The hyperlink activation handler must return synchronously."),
@@ -18799,6 +19030,7 @@ function createV2EditorRuntimeAdapter(options) {
18799
19030
  const { id, documentId, root, host, getLegacyEditorProjection, onUnregister } = options;
18800
19031
  let snapshot = host.getSnapshot();
18801
19032
  let didDispose = false;
19033
+ let detached = false;
18802
19034
  let unregistered = false;
18803
19035
  let mountedFocusHandle = null;
18804
19036
  let tokenRevision = 0;
@@ -19095,7 +19327,17 @@ function createV2EditorRuntimeAdapter(options) {
19095
19327
  };
19096
19328
  }
19097
19329
  }
19330
+ function releaseHostSubscriptions() {
19331
+ hostUnsubscribe?.();
19332
+ hostUnsubscribe = null;
19333
+ pageMetricsUnsubscribe?.();
19334
+ pageMetricsUnsubscribe = null;
19335
+ selectionUnsubscribe?.();
19336
+ selectionUnsubscribe = null;
19337
+ activeSelectionController = null;
19338
+ }
19098
19339
  function handleHostSnapshot(next) {
19340
+ if (detached || didDispose) return;
19099
19341
  snapshot = next;
19100
19342
  invalidatePositionTokens();
19101
19343
  syncSelectionSubscription();
@@ -19109,10 +19351,7 @@ function createV2EditorRuntimeAdapter(options) {
19109
19351
  });
19110
19352
  if (next.state === "disposed" && !didDispose) {
19111
19353
  didDispose = true;
19112
- hostUnsubscribe?.();
19113
- pageMetricsUnsubscribe?.();
19114
- selectionUnsubscribe?.();
19115
- selectionUnsubscribe = null;
19354
+ releaseHostSubscriptions();
19116
19355
  emit({ type: "disposed" });
19117
19356
  listeners.clear();
19118
19357
  if (!unregistered) {
@@ -19259,10 +19498,7 @@ function createV2EditorRuntimeAdapter(options) {
19259
19498
  await host.dispose();
19260
19499
  if (!didDispose) {
19261
19500
  didDispose = true;
19262
- hostUnsubscribe?.();
19263
- pageMetricsUnsubscribe?.();
19264
- selectionUnsubscribe?.();
19265
- selectionUnsubscribe = null;
19501
+ releaseHostSubscriptions();
19266
19502
  emit({ type: "disposed" });
19267
19503
  listeners.clear();
19268
19504
  if (!unregistered) {
@@ -19341,8 +19577,17 @@ function createV2EditorRuntimeAdapter(options) {
19341
19577
  }
19342
19578
  },
19343
19579
  attachMountHandle(handle) {
19580
+ if (detached || didDispose) return;
19344
19581
  mountedFocusHandle = handle;
19345
19582
  syncSelectionSubscription();
19583
+ },
19584
+ detach() {
19585
+ if (detached) return;
19586
+ detached = true;
19587
+ unregistered = true;
19588
+ releaseHostSubscriptions();
19589
+ mountedFocusHandle = null;
19590
+ listeners.clear();
19346
19591
  }
19347
19592
  };
19348
19593
  }
@@ -19373,10 +19618,10 @@ function isPromiseLike(value) {
19373
19618
  return Boolean(value && typeof value === "object" && typeof value.then === "function");
19374
19619
  }
19375
19620
  function isTextTarget(value) {
19376
- return require_create_super_doc_ui.isPlainObject(value) && value.kind === "text" && Array.isArray(value.segments) && value.segments.length > 0;
19621
+ return require__plugin_vue_export_helper.isPlainObject(value) && value.kind === "text" && Array.isArray(value.segments) && value.segments.length > 0;
19377
19622
  }
19378
19623
  function isHeaderFooterStory(story) {
19379
- return require_create_super_doc_ui.isPlainObject(story) && story.kind === "story" && (story.storyType === "headerFooterSlot" || story.storyType === "headerFooterPart");
19624
+ return require__plugin_vue_export_helper.isPlainObject(story) && story.kind === "story" && (story.storyType === "headerFooterSlot" || story.storyType === "headerFooterPart");
19380
19625
  }
19381
19626
  function resolveCurrentHeaderFooterTextTarget(doc) {
19382
19627
  if (!isFn(doc.selection?.current)) return {
@@ -19396,7 +19641,7 @@ function resolveCurrentHeaderFooterTextTarget(doc) {
19396
19641
  handled: false,
19397
19642
  reason: "page-field-selection-async"
19398
19643
  };
19399
- if (!require_create_super_doc_ui.isPlainObject(currentSelection) || !isTextTarget(currentSelection.target)) return {
19644
+ if (!require__plugin_vue_export_helper.isPlainObject(currentSelection) || !isTextTarget(currentSelection.target)) return {
19400
19645
  handled: false,
19401
19646
  reason: "page-field-selection-unavailable"
19402
19647
  };
@@ -19494,7 +19739,7 @@ function createV2SessionShortcutRoutes(deps) {
19494
19739
  mode: "raw"
19495
19740
  });
19496
19741
  if (isPromiseLike(result)) result.catch(() => {});
19497
- else if (require_create_super_doc_ui.isPlainObject(result) && result.success === false) return {
19742
+ else if (require__plugin_vue_export_helper.isPlainObject(result) && result.success === false) return {
19498
19743
  handled: false,
19499
19744
  reason: "page-field-insert-failed"
19500
19745
  };
@@ -20511,7 +20756,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
20511
20756
  __name: "SuperDoc",
20512
20757
  emits: ["selection-update"],
20513
20758
  setup(__props, { emit: __emit }) {
20514
- const PdfViewer = require__plugin_vue_export_helper.defineAsyncComponent(() => Promise.resolve().then(() => require("./chunks/PdfViewer-DmSkZehl.cjs")));
20759
+ const PdfViewer = require__plugin_vue_export_helper.defineAsyncComponent(() => Promise.resolve().then(() => require("./chunks/PdfViewer-DYTbPVUr.cjs")));
20515
20760
  const getDocumentLoadPassword = (doc) => doc.password ?? proxy.$superdoc.config.password;
20516
20761
  const resolveDocumentV2Collaboration = (doc) => {
20517
20762
  const rawConfig = doc?.v2Collaboration;
@@ -20596,7 +20841,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
20596
20841
  if (commentsConfig.highlightHoverColor) vars["--sd-comments-highlight-hover"] = commentsConfig.highlightHoverColor;
20597
20842
  const activeTrackChangeColors = {
20598
20843
  ...commentsConfig.trackChangeHighlightColors || {},
20599
- ...commentsConfig.trackChangeActiveHighlightColors || {}
20844
+ ...commentsConfig.trackChangeActiveHighlightColors
20600
20845
  };
20601
20846
  if (activeTrackChangeColors.insertBorder) vars["--sd-tracked-changes-insert-border"] = activeTrackChangeColors.insertBorder;
20602
20847
  if (activeTrackChangeColors.insertBackground) vars["--sd-tracked-changes-insert-background"] = activeTrackChangeColors.insertBackground;
@@ -20625,6 +20870,8 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
20625
20870
  const v2ReviewSidebarUnlocked = require__plugin_vue_export_helper.ref(false);
20626
20871
  const v2GeometryEpoch = require__plugin_vue_export_helper.ref(null);
20627
20872
  let v2GeometryRafHandle = 0;
20873
+ let v2GeometryReplayRafHandle = 0;
20874
+ let v2GeometryReplayGeneration = 0;
20628
20875
  let v2TrackedChangeRestampRetainPaints = 0;
20629
20876
  let v2TrackedChangeRestampRetentionReason = null;
20630
20877
  const activeEditorRef = require__plugin_vue_export_helper.computed(() => proxy.$superdoc.activeEditor);
@@ -20808,6 +21055,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
20808
21055
  if (document && provider?.sendStateless) document.provider = null;
20809
21056
  const entry = v2Runtimes.get(documentId);
20810
21057
  if (!entry) return;
21058
+ entry.adapter.detach();
20811
21059
  proxy.$superdoc["unregisterEditorRuntime"](entry.runtimeId);
20812
21060
  v2Runtimes.delete(documentId);
20813
21061
  const hostRoot = subDocumentRoots.get(documentId);
@@ -20961,7 +21209,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
20961
21209
  if (loadingDocument?.loadScope && !loadingDocument.loadScope.finish()) return;
20962
21210
  clearV2EditorFailure(payload.documentId ?? null);
20963
21211
  clearV2MutationRejectionNotifications(payload.documentId ?? null);
20964
- const { host, firstPartyCommandMutation, mount, documentId, capabilities, editCommands, bindEditShortcuts, bindSessionShortcuts, commentsAdapter, trackedChangesAdapter, contextMenu, documentApi, documentMutationReadiness, documentApiUnavailableReason, pageMetrics, pageLayout, pageFurniture, presence, lock, connection, collaborationProvider, fonts, replaceFile, upgradeToCollaboration, documentOpenToken } = payload;
21212
+ const { host, firstPartyCommandMutation, mount, documentId, capabilities, editCommands, bindEditShortcuts, bindSessionShortcuts, commentsAdapter, trackedChangesAdapter, contextMenu, viewportQuery, documentApi, documentMutationReadiness, documentApiUnavailableReason, pageMetrics, pageLayout, pageFurniture, presence, lock, connection, collaborationProvider, fonts, replaceFile, upgradeToCollaboration, documentOpenToken } = payload;
20965
21213
  documentOpenTelemetry?.trackDocumentOpen(documentOpenToken ?? null, documentId ?? null);
20966
21214
  const saveV2Bytes = createV2SaveQueue(async (saveOptions = {}) => {
20967
21215
  if (!host || typeof host.save !== "function") throw new Error("v2-editor: save unavailable");
@@ -21057,21 +21305,21 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21057
21305
  };
21058
21306
  };
21059
21307
  const currentV2AuthoringMode = () => proxy.$superdoc.config.documentMode === "suggesting" ? "tracked" : "direct";
21060
- const readV2CurrentSelectionTarget = () => {
21061
- const selection = (host?.getHandles?.()?.editing ?? null)?.selection ?? null;
21062
- if (typeof selection?.toSelectionTarget !== "function") return createV2AuthoringFailure("selection-target-unavailable", "editing.selection.toSelectionTarget is not available");
21063
- const result = selection.toSelectionTarget();
21064
- if (!result || result.kind === "rejected") {
21065
- const rejection = result?.rejection ?? {};
21066
- return createV2AuthoringFailure(rejection.reason ?? rejection.code ?? "selection-target-rejected", rejection.detail);
21308
+ const confirmedV2SelectionTarget = async () => {
21309
+ const selectionTargets = host?.getHandles?.()?.editing?.selectionTargets;
21310
+ if (typeof selectionTargets?.confirmedSelectionTarget !== "function") return createV2AuthoringFailure("selection-confirmation-unavailable");
21311
+ try {
21312
+ const result = await selectionTargets.confirmedSelectionTarget();
21313
+ if (!result?.ok || !result.target) return createV2AuthoringFailure(result?.reason ?? "selection-unconfirmed");
21314
+ return {
21315
+ ok: true,
21316
+ target: result.target,
21317
+ mode: result.mode,
21318
+ story: result.story
21319
+ };
21320
+ } catch (error) {
21321
+ return createV2AuthoringFailure("selection-unconfirmed", error instanceof Error ? error.message : String(error));
21067
21322
  }
21068
- if (!result.target || typeof result.target !== "object") return createV2AuthoringFailure("selection-target-rejected", "selection target was not produced");
21069
- return {
21070
- ok: true,
21071
- target: result.target,
21072
- mode: result.mode ?? "range",
21073
- story: result.story
21074
- };
21075
21323
  };
21076
21324
  const failureFromV2Receipt = (receipt, fallbackReason) => {
21077
21325
  const failure = receipt?.failure ?? receipt;
@@ -21145,7 +21393,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21145
21393
  },
21146
21394
  serializeSelectionToClipboard: async ({ includeHtml = true } = {}) => {
21147
21395
  if (!documentApi?.clipboard || typeof documentApi.clipboard.serializeSelection !== "function") return createV2AuthoringFailure("clipboard-serialize-unavailable", "activeEditor.doc.clipboard.serializeSelection is not available");
21148
- const selected = readV2CurrentSelectionTarget();
21396
+ const selected = await confirmedV2SelectionTarget();
21149
21397
  if (!selected.ok) return selected;
21150
21398
  let serialized;
21151
21399
  try {
@@ -21171,7 +21419,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21171
21419
  let pasteTarget = target;
21172
21420
  let selectionMode = null;
21173
21421
  if (!pasteTarget) {
21174
- const selected = readV2CurrentSelectionTarget();
21422
+ const selected = await confirmedV2SelectionTarget();
21175
21423
  if (!selected.ok) return selected;
21176
21424
  pasteTarget = selected.target;
21177
21425
  selectionMode = selected.mode;
@@ -21232,6 +21480,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21232
21480
  v2Comments: commentsAdapter ?? null,
21233
21481
  v2TrackedChanges: trackedChangesAdapter ?? null,
21234
21482
  contextMenu: contextMenu ?? null,
21483
+ viewportQuery: viewportQuery ?? null,
21235
21484
  pageMetrics: pageMetrics ?? null,
21236
21485
  pageLayout: pageLayout ?? null,
21237
21486
  pageFurniture: pageFurniture ?? null,
@@ -21314,7 +21563,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21314
21563
  let v2SelectionToolbarRafHandle = 0;
21315
21564
  let v2SelectionToolbarTimeoutHandle = 0;
21316
21565
  let v2DomSelectionRafHandle = 0;
21317
- const buildV2EditorUpdatePayload = ({ editor, sourceEditor, surface = "body", headerId = null, sectionType = null } = {}) => {
21566
+ const buildV2EditorUpdatePayload = ({ editor, sourceEditor, surface = "body", headerId = null, sectionType = null, isRemote = false } = {}) => {
21318
21567
  const activeEditor = proxy.$superdoc?.activeEditor ?? null;
21319
21568
  const effectiveEditor = editor ?? sourceEditor ?? activeEditor ?? void 0;
21320
21569
  return {
@@ -21322,7 +21571,8 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21322
21571
  sourceEditor: sourceEditor ?? effectiveEditor,
21323
21572
  surface,
21324
21573
  headerId,
21325
- sectionType
21574
+ sectionType,
21575
+ isRemote
21326
21576
  };
21327
21577
  };
21328
21578
  const emitV2EditorUpdate = (payload = {}) => {
@@ -21572,10 +21822,11 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21572
21822
  const publishV2PendingPositionEntry = (entry) => {
21573
21823
  if (!entry) return;
21574
21824
  handleEditorLocationsUpdate({
21575
- ...editorCommentPositions.value ?? {},
21825
+ ...editorCommentPositions.value,
21576
21826
  pending: entry
21577
21827
  });
21578
21828
  };
21829
+ let scheduleV2GeometryReplay = () => {};
21579
21830
  const v2GeometryPublisher = resolvedEditorIntegration.createGeometryPublisher({
21580
21831
  getLayersContainer: () => layers.value ?? null,
21581
21832
  isCommentsEnabled: () => Boolean(commentsModuleConfig.value) && shouldRenderCommentsInViewing.value,
@@ -21591,7 +21842,8 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21591
21842
  v2ReviewSidebarUnlocked.value = true;
21592
21843
  v2GeometryEpoch.value = v2GeometryPublisher.getLastEpoch();
21593
21844
  }
21594
- }
21845
+ },
21846
+ onCommittedPagePaint: ({ payload }) => scheduleV2GeometryReplay(payload)
21595
21847
  });
21596
21848
  const armV2TrackedChangeRestampGeometryRetention = (reason = "tracked-change-restamp") => {
21597
21849
  v2TrackedChangeRestampRetainPaints = Math.max(v2TrackedChangeRestampRetainPaints, 3);
@@ -21611,20 +21863,53 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21611
21863
  v2TrackedChangeRestampRetentionReason = null;
21612
21864
  };
21613
21865
  const resolveV2GeometryPublishOptions = (options) => typeof options === "function" ? options() : options;
21866
+ const isV2GeometryReady = (current) => {
21867
+ if (!current?.mountContainer || !commentsModuleConfig.value || !shouldRenderCommentsInViewing.value) return false;
21868
+ const mount = current.mount;
21869
+ let liveEpoch;
21870
+ try {
21871
+ liveEpoch = mount?.getRenderEpoch?.();
21872
+ } catch {
21873
+ return false;
21874
+ }
21875
+ return v2GeometryPublisher.getLastPayload() === current && v2GeometryPublisher.getLastEpoch() != null && v2GeometryPublisher.getLastEpoch() === current.epoch && (liveEpoch == null || liveEpoch === current.epoch);
21876
+ };
21614
21877
  const scheduleV2GeometryPublish = (payload, options = void 0) => {
21615
21878
  v2GeometryRender.value = payload;
21616
21879
  if (v2GeometryRafHandle && typeof cancelAnimationFrame === "function") cancelAnimationFrame(v2GeometryRafHandle);
21880
+ const publish = () => {
21881
+ const current = v2GeometryRender.value;
21882
+ Promise.resolve(v2GeometryPublisher.publish(current, resolveV2GeometryPublishOptions(options))).then(() => {
21883
+ if (current === v2GeometryRender.value && isV2GeometryReady(current)) v2ReviewGeometryDelivery.flush(current);
21884
+ });
21885
+ };
21617
21886
  if (typeof requestAnimationFrame !== "function") {
21618
- v2GeometryPublisher.publish(v2GeometryRender.value, resolveV2GeometryPublishOptions(options));
21887
+ publish();
21619
21888
  return;
21620
21889
  }
21621
21890
  v2GeometryRafHandle = requestAnimationFrame(() => {
21622
21891
  v2GeometryRafHandle = 0;
21623
- v2GeometryPublisher.publish(v2GeometryRender.value, resolveV2GeometryPublishOptions(options));
21892
+ publish();
21624
21893
  });
21625
21894
  };
21895
+ const v2ReviewGeometryDelivery = createReviewGeometryDelivery((current, packet) => {
21896
+ v2GeometryPublisher.noteCommittedPageWindow?.(packet);
21897
+ scheduleV2GeometryPublish(current);
21898
+ });
21899
+ scheduleV2GeometryReplay = (payload) => {
21900
+ if (!payload || payload !== v2GeometryRender.value) return;
21901
+ const generation = ++v2GeometryReplayGeneration;
21902
+ if (v2GeometryReplayRafHandle && typeof cancelAnimationFrame === "function") cancelAnimationFrame(v2GeometryReplayRafHandle);
21903
+ const replay = () => {
21904
+ v2GeometryReplayRafHandle = 0;
21905
+ if (generation === v2GeometryReplayGeneration && payload === v2GeometryRender.value && isV2GeometryReady(payload)) v2ReviewGeometryDelivery.replay(payload);
21906
+ };
21907
+ if (typeof requestAnimationFrame === "function") v2GeometryReplayRafHandle = requestAnimationFrame(replay);
21908
+ else queueMicrotask(replay);
21909
+ };
21626
21910
  const onV2Render = (payload) => {
21627
21911
  if (!payload) return;
21912
+ v2ReviewGeometryDelivery.observe(payload);
21628
21913
  scheduleV2GeometryPublish(payload, () => takeV2TrackedChangeRestampGeometryRetention());
21629
21914
  if (v2HasRangeSelection.value) scheduleV2SelectionToolbarStateSync();
21630
21915
  };
@@ -21657,7 +21942,11 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21657
21942
  cancelScheduledV2SelectionToolbarSync();
21658
21943
  if (v2GeometryRafHandle && typeof cancelAnimationFrame === "function") cancelAnimationFrame(v2GeometryRafHandle);
21659
21944
  v2GeometryRafHandle = 0;
21945
+ if (v2GeometryReplayRafHandle && typeof cancelAnimationFrame === "function") cancelAnimationFrame(v2GeometryReplayRafHandle);
21946
+ v2GeometryReplayRafHandle = 0;
21947
+ v2GeometryReplayGeneration++;
21660
21948
  v2GeometryRender.value = null;
21949
+ v2ReviewGeometryDelivery.reset();
21661
21950
  v2GeometryEpoch.value = null;
21662
21951
  v2GeometryAvailable.value = false;
21663
21952
  v2ReviewSidebarUnlocked.value = false;
@@ -21716,6 +22005,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21716
22005
  v2ReviewWindowController.invalidate("collaboration:remote-review-changed");
21717
22006
  v2ReviewWindowController.refreshCommittedWindow("collaboration:remote-review-changed");
21718
22007
  }
22008
+ emitV2EditorUpdate({ isRemote: true });
21719
22009
  return;
21720
22010
  }
21721
22011
  if (event.type === "source:complete") {
@@ -21804,14 +22094,15 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
21804
22094
  if (!isV2Mode.value) return;
21805
22095
  if (!v2GeometryPublisher.getLastPayload()) return;
21806
22096
  if (v2GeometryRafHandle && typeof cancelAnimationFrame === "function") cancelAnimationFrame(v2GeometryRafHandle);
21807
- if (typeof requestAnimationFrame !== "function") {
21808
- v2GeometryPublisher.recollect(resolveV2GeometryPublishOptions(options));
21809
- return;
21810
- }
21811
- v2GeometryRafHandle = requestAnimationFrame(() => {
22097
+ const recollect = () => {
21812
22098
  v2GeometryRafHandle = 0;
21813
- v2GeometryPublisher.recollect(resolveV2GeometryPublishOptions(options));
21814
- });
22099
+ const current = v2GeometryRender.value;
22100
+ Promise.resolve(v2GeometryPublisher.recollect(resolveV2GeometryPublishOptions(options))).then(() => {
22101
+ if (current === v2GeometryRender.value && isV2GeometryReady(current)) v2ReviewGeometryDelivery.replay(current);
22102
+ });
22103
+ };
22104
+ if (typeof requestAnimationFrame !== "function") recollect();
22105
+ else v2GeometryRafHandle = requestAnimationFrame(recollect);
21815
22106
  };
21816
22107
  const handleV2DocumentModeChange = () => {
21817
22108
  if (!isV2Mode.value) return;
@@ -22039,13 +22330,17 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
22039
22330
  ...payload,
22040
22331
  documentId: doc.id
22041
22332
  });
22042
- v2GeometryPublisher.noteCommittedPageWindow?.(payload);
22333
+ if (payload.reviewGeometry && Array.isArray(payload.pageIndices)) {
22334
+ const current = v2GeometryRender.value;
22335
+ v2ReviewGeometryDelivery.notify(String(doc.id), payload, current, isV2GeometryReady(current));
22336
+ } else v2GeometryPublisher.noteCommittedPageWindow?.(payload);
22043
22337
  },
22044
22338
  fontAssets: proxy.$superdoc.config.fonts,
22045
22339
  workerUrls: proxy.$superdoc.config.workerUrls,
22046
22340
  fieldContext: doc.fieldContext,
22047
22341
  fieldUpdatePolicy: proxy.$superdoc.config.fieldUpdatePolicy,
22048
22342
  workerStartupTimeoutMs: proxy.$superdoc.config.workerStartupTimeoutMs,
22343
+ ...proxy.$superdoc.config.changes ? { changes: proxy.$superdoc.config.changes } : {},
22049
22344
  proofing: resolvedProofingConfig.value,
22050
22345
  isNewFile,
22051
22346
  password: getDocumentLoadPassword(doc),
@@ -22066,7 +22361,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
22066
22361
  documentLoading: proxy.$superdoc.uiConfig.loading.enabled,
22067
22362
  linkPopoverResolver: getHyperlinkActivationHandler(),
22068
22363
  layoutEngineOptions: useLayoutEngine ? {
22069
- ...proxy.$superdoc.config.layoutEngineOptions || {},
22364
+ ...proxy.$superdoc.config.layoutEngineOptions,
22070
22365
  proofing: resolvedProofingConfig.value,
22071
22366
  debugLabel: proxy.$superdoc.config.layoutEngineOptions?.debugLabel ?? doc.name ?? doc.id,
22072
22367
  zoom: (activeZoom.value ?? 100) / 100,
@@ -22329,11 +22624,16 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
22329
22624
  if (layout !== "auto") return true;
22330
22625
  return !isCompactCommentsMode.value;
22331
22626
  });
22332
- const showCommentsSidebar = require__plugin_vue_export_helper.computed(() => {
22627
+ const sidebarEnabled = require__plugin_vue_export_helper.computed(() => {
22333
22628
  if (isV2Mode.value && !v2GeometryAvailable.value && !v2ReviewSidebarUnlocked.value && !hasPdfFloatingComments.value) return false;
22334
22629
  if (!shouldRenderCommentsInViewing.value) return false;
22335
22630
  if (!shouldUseSidebarComments.value) return false;
22336
- return pendingComment.value || (floatingComments.value.length > 0 || hasOpenTrackedChanges.value) && isReady.value && layers.value && isCommentsEnabled.value && !isCommentsListVisible.value;
22631
+ return Boolean(pendingComment.value || isReady.value && layers.value && isCommentsEnabled.value && !isCommentsListVisible.value);
22632
+ });
22633
+ const showCommentsSidebar = useCommentSidebar({
22634
+ documentKey: require__plugin_vue_export_helper.computed(() => JSON.stringify(documents.value.map((document) => document.id))),
22635
+ enabled: sidebarEnabled,
22636
+ hasContent: require__plugin_vue_export_helper.computed(() => Boolean(pendingComment.value || floatingComments.value.length || hasOpenTrackedChanges.value))
22337
22637
  });
22338
22638
  const activeCompactComment = require__plugin_vue_export_helper.computed(() => {
22339
22639
  if (showCommentsSidebar.value) return null;
@@ -22957,7 +23257,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
22957
23257
  ref_key: "superdocRoot",
22958
23258
  ref: superdocRoot,
22959
23259
  class: require__plugin_vue_export_helper.normalizeClass(["superdoc", {
22960
- "superdoc--with-sidebar": showCommentsSidebar.value,
23260
+ "superdoc--with-sidebar": require__plugin_vue_export_helper.unref(showCommentsSidebar),
22961
23261
  "superdoc--web-layout": require__plugin_vue_export_helper.unref(proxy).$superdoc.config.viewOptions?.layout === "web",
22962
23262
  "superdoc--contained": require__plugin_vue_export_helper.unref(proxy).$superdoc.config.contained,
22963
23263
  "high-contrast": require__plugin_vue_export_helper.unref(isHighContrastMode)
@@ -23105,7 +23405,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
23105
23405
  onAnchorActivate: handleHighlightClick
23106
23406
  })) : require__plugin_vue_export_helper.createCommentVNode("", true)
23107
23407
  ])], 512),
23108
- showCommentsSidebar.value ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", {
23408
+ require__plugin_vue_export_helper.unref(showCommentsSidebar) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", {
23109
23409
  key: 0,
23110
23410
  ref_key: "rightSidebarRef",
23111
23411
  ref: rightSidebarRef,
@@ -23131,7 +23431,7 @@ var SuperDoc_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
23131
23431
  });
23132
23432
  //#endregion
23133
23433
  //#region src/SuperDoc.vue
23134
- var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(SuperDoc_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-26bcc2bd"]]);
23434
+ var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(SuperDoc_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-b5da778c"]]);
23135
23435
  //#endregion
23136
23436
  //#region src/core/create-app.ts
23137
23437
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
@@ -32546,7 +32846,7 @@ function checkDefaultFill(config) {
32546
32846
  if (!config.fillLinearGradientColorStops && !config.fillRadialGradientColorStops && !config.fillPatternImage) config.fill = config.fill || "black";
32547
32847
  return config;
32548
32848
  }
32549
- var Text = class extends Shape {
32849
+ var Text$1 = class extends Shape {
32550
32850
  constructor(config) {
32551
32851
  super(checkDefaultFill(config));
32552
32852
  this._partialTextX = 0;
@@ -32808,10 +33108,10 @@ var Text = class extends Shape {
32808
33108
  return super._useBufferCanvas();
32809
33109
  }
32810
33110
  };
32811
- Text.prototype._fillFunc = _fillFunc$1;
32812
- Text.prototype._strokeFunc = _strokeFunc$1;
32813
- Text.prototype.className = TEXT_UPPER;
32814
- Text.prototype._attrsAffectingSize = [
33111
+ Text$1.prototype._fillFunc = _fillFunc$1;
33112
+ Text$1.prototype._strokeFunc = _strokeFunc$1;
33113
+ Text$1.prototype.className = TEXT_UPPER;
33114
+ Text$1.prototype._attrsAffectingSize = [
32815
33115
  "text",
32816
33116
  "fontSize",
32817
33117
  "padding",
@@ -32819,25 +33119,25 @@ Text.prototype._attrsAffectingSize = [
32819
33119
  "lineHeight",
32820
33120
  "letterSpacing"
32821
33121
  ];
32822
- _registerNode(Text);
32823
- Factory.overWriteSetter(Text, "width", getNumberOrAutoValidator());
32824
- Factory.overWriteSetter(Text, "height", getNumberOrAutoValidator());
32825
- Factory.addGetterSetter(Text, "direction", INHERIT);
32826
- Factory.addGetterSetter(Text, "fontFamily", "Arial");
32827
- Factory.addGetterSetter(Text, "fontSize", 12, getNumberValidator());
32828
- Factory.addGetterSetter(Text, "fontStyle", NORMAL$1);
32829
- Factory.addGetterSetter(Text, "fontVariant", NORMAL$1);
32830
- Factory.addGetterSetter(Text, "padding", 0, getNumberValidator());
32831
- Factory.addGetterSetter(Text, "align", LEFT);
32832
- Factory.addGetterSetter(Text, "verticalAlign", TOP);
32833
- Factory.addGetterSetter(Text, "lineHeight", 1, getNumberValidator());
32834
- Factory.addGetterSetter(Text, "wrap", WORD);
32835
- Factory.addGetterSetter(Text, "ellipsis", false, getBooleanValidator());
32836
- Factory.addGetterSetter(Text, "letterSpacing", 0, getNumberValidator());
32837
- Factory.addGetterSetter(Text, "text", "", getStringValidator());
32838
- Factory.addGetterSetter(Text, "textDecoration", "");
32839
- Factory.addGetterSetter(Text, "underlineOffset", void 0, getNumberValidator());
32840
- Factory.addGetterSetter(Text, "charRenderFunc", void 0);
33122
+ _registerNode(Text$1);
33123
+ Factory.overWriteSetter(Text$1, "width", getNumberOrAutoValidator());
33124
+ Factory.overWriteSetter(Text$1, "height", getNumberOrAutoValidator());
33125
+ Factory.addGetterSetter(Text$1, "direction", INHERIT);
33126
+ Factory.addGetterSetter(Text$1, "fontFamily", "Arial");
33127
+ Factory.addGetterSetter(Text$1, "fontSize", 12, getNumberValidator());
33128
+ Factory.addGetterSetter(Text$1, "fontStyle", NORMAL$1);
33129
+ Factory.addGetterSetter(Text$1, "fontVariant", NORMAL$1);
33130
+ Factory.addGetterSetter(Text$1, "padding", 0, getNumberValidator());
33131
+ Factory.addGetterSetter(Text$1, "align", LEFT);
33132
+ Factory.addGetterSetter(Text$1, "verticalAlign", TOP);
33133
+ Factory.addGetterSetter(Text$1, "lineHeight", 1, getNumberValidator());
33134
+ Factory.addGetterSetter(Text$1, "wrap", WORD);
33135
+ Factory.addGetterSetter(Text$1, "ellipsis", false, getBooleanValidator());
33136
+ Factory.addGetterSetter(Text$1, "letterSpacing", 0, getNumberValidator());
33137
+ Factory.addGetterSetter(Text$1, "text", "", getStringValidator());
33138
+ Factory.addGetterSetter(Text$1, "textDecoration", "");
33139
+ Factory.addGetterSetter(Text$1, "underlineOffset", void 0, getNumberValidator());
33140
+ Factory.addGetterSetter(Text$1, "charRenderFunc", void 0);
32841
33141
  //#endregion
32842
33142
  //#region ../../node_modules/.pnpm/konva@10.2.5/node_modules/konva/lib/shapes/TextPath.js
32843
33143
  var EMPTY_STRING = "";
@@ -32943,10 +33243,10 @@ var TextPath = class extends Shape {
32943
33243
  return this.textHeight;
32944
33244
  }
32945
33245
  setText(text) {
32946
- return Text.prototype.setText.call(this, text);
33246
+ return Text$1.prototype.setText.call(this, text);
32947
33247
  }
32948
33248
  _getContextFont() {
32949
- return Text.prototype._getContextFont.call(this);
33249
+ return Text$1.prototype._getContextFont.call(this);
32950
33250
  }
32951
33251
  _getTextSize(text) {
32952
33252
  const _context = this.dummyCanvas.getContext("2d");
@@ -35486,7 +35786,7 @@ var lib_default = Konva$1.Util._assign(Konva$1, {
35486
35786
  Ring,
35487
35787
  Sprite,
35488
35788
  Star,
35489
- Text,
35789
+ Text: Text$1,
35490
35790
  TextPath,
35491
35791
  Transformer,
35492
35792
  Wedge,
@@ -35708,6 +36008,16 @@ var SurfaceManager = class {
35708
36008
  };
35709
36009
  //#endregion
35710
36010
  //#region src/helpers/deprecation.ts
36011
+ /**
36012
+ * Deprecation utilities for steering consumers toward the Document API.
36013
+ *
36014
+ * ProseMirror will be removed in a future major version. These helpers emit
36015
+ * one-time console warnings when deprecated properties are accessed on an
36016
+ * editor instance handed to consumer callbacks (onEditorCreate, etc.).
36017
+ *
36018
+ * Internal code continues to use the raw Editor — only the consumer-facing
36019
+ * boundary wraps the editor with a Proxy.
36020
+ */
35711
36021
  var MIGRATION_URL = "https://docs.superdoc.dev/guides/migration/document-api";
35712
36022
  var _warned = /* @__PURE__ */ new Set();
35713
36023
  /**
@@ -35896,7 +36206,8 @@ function normalizeSuperDocUser(user) {
35896
36206
  if (!user || typeof user !== "object") return { ...DEFAULT_SUPERDOC_USER };
35897
36207
  return {
35898
36208
  ...DEFAULT_SUPERDOC_USER,
35899
- ...user
36209
+ ...user,
36210
+ ...user.commentIdentity !== void 0 ? { commentIdentity: normalizeCommentIdentity(user.commentIdentity) } : {}
35900
36211
  };
35901
36212
  }
35902
36213
  //#endregion
@@ -35951,7 +36262,7 @@ var TOOLBAR_ITEM_ALIASES = Object.freeze({
35951
36262
  * historical default rather than inheriting from its siblings.
35952
36263
  */
35953
36264
  var isUnknownArray = (value) => Array.isArray(value);
35954
- var isOptionsBag = (value) => require_create_super_doc_ui.isPlainObject(value);
36265
+ var isOptionsBag = (value) => require__plugin_vue_export_helper.isPlainObject(value);
35955
36266
  var hasSelectHandler = (item) => typeof item.onSelect === "function";
35956
36267
  /** Surfaces that render when the consumer says nothing at all. */
35957
36268
  var HISTORICAL_DEFAULTS = Object.freeze({
@@ -36080,7 +36391,7 @@ var SEARCH_STRING_KEYS = Object.freeze({
36080
36391
  invalidPattern: "invalidPatternLabel"
36081
36392
  });
36082
36393
  function normalizeSearchStrings(strings) {
36083
- if (!require_create_super_doc_ui.isPlainObject(strings)) return {};
36394
+ if (!require__plugin_vue_export_helper.isPlainObject(strings)) return {};
36084
36395
  return Object.fromEntries(Object.entries(strings).filter(([key, value]) => SEARCH_STRING_KEYS[key] !== void 0 && value !== void 0).map(([key, value]) => [SEARCH_STRING_KEYS[key], value]));
36085
36396
  }
36086
36397
  function normalizeSearchOptions(options) {
@@ -36174,7 +36485,7 @@ function mapToolbarKey(key, aliases) {
36174
36485
  return aliases[String(key)] ?? key;
36175
36486
  }
36176
36487
  function mapToolbarRecord(record, aliases) {
36177
- if (!require_create_super_doc_ui.isPlainObject(record)) return void 0;
36488
+ if (!require__plugin_vue_export_helper.isPlainObject(record)) return void 0;
36178
36489
  const entries = Object.entries(record);
36179
36490
  const passthroughEntries = entries.filter(([key]) => aliases[key] === void 0);
36180
36491
  const aliasedEntries = entries.filter(([key]) => aliases[key] !== void 0);
@@ -36185,14 +36496,14 @@ function mapToolbarItems(items) {
36185
36496
  return items.map((item) => mapToolbarKey(item, TOOLBAR_ITEM_ALIASES));
36186
36497
  }
36187
36498
  function mapToolbarRegions(regions) {
36188
- if (!require_create_super_doc_ui.isPlainObject(regions)) return regions;
36499
+ if (!require__plugin_vue_export_helper.isPlainObject(regions)) return regions;
36189
36500
  return Object.fromEntries(Object.entries(regions).map(([region, items]) => [region, mapToolbarItems(items)]));
36190
36501
  }
36191
36502
  function addCustomItemRegions(regions, customItems) {
36192
- if (!require_create_super_doc_ui.isPlainObject(regions) || !isUnknownArray(customItems)) return regions;
36503
+ if (!require__plugin_vue_export_helper.isPlainObject(regions) || !isUnknownArray(customItems)) return regions;
36193
36504
  const result = { ...regions };
36194
36505
  for (const item of customItems) {
36195
- if (!require_create_super_doc_ui.isPlainObject(item)) continue;
36506
+ if (!require__plugin_vue_export_helper.isPlainObject(item)) continue;
36196
36507
  const region = item.region ?? "center";
36197
36508
  if (result[region] === void 0) result[region] = [];
36198
36509
  }
@@ -36205,7 +36516,7 @@ var TOOLBAR_OPTIONAL_ITEM_REGIONS = Object.freeze({
36205
36516
  "table-of-contents": "center"
36206
36517
  });
36207
36518
  function addIncludedToolbarItems(regions, includeItems) {
36208
- if (!require_create_super_doc_ui.isPlainObject(regions) || !isUnknownArray(includeItems)) return regions;
36519
+ if (!require__plugin_vue_export_helper.isPlainObject(regions) || !isUnknownArray(includeItems)) return regions;
36209
36520
  const result = Object.fromEntries(Object.entries(regions).map(([region, items]) => [region, isUnknownArray(items) ? [...items] : items]));
36210
36521
  const configuredItems = new Set(Object.values(result).flatMap((items) => isUnknownArray(items) ? items : []).map((item) => mapToolbarKey(item, TOOLBAR_ITEM_ALIASES)));
36211
36522
  for (const item of includeItems) {
@@ -36225,7 +36536,7 @@ function extendToolbarRegions(regions, options) {
36225
36536
  function mapToolbarFontOptions(options) {
36226
36537
  if (!isUnknownArray(options)) return options;
36227
36538
  return options.map((option) => {
36228
- if (!require_create_super_doc_ui.isPlainObject(option)) return option;
36539
+ if (!require__plugin_vue_export_helper.isPlainObject(option)) return option;
36229
36540
  const { value, label, previewFamily } = option;
36230
36541
  return {
36231
36542
  key: value,
@@ -36238,7 +36549,7 @@ function mapToolbarFontOptions(options) {
36238
36549
  function mapToolbarCustomItems(items) {
36239
36550
  if (!isUnknownArray(items)) return items;
36240
36551
  return items.map((item) => {
36241
- if (!require_create_super_doc_ui.isPlainObject(item) || typeof item.id !== "string") return item;
36552
+ if (!require__plugin_vue_export_helper.isPlainObject(item) || typeof item.id !== "string") return item;
36242
36553
  const size = item.size ?? "default";
36243
36554
  const layoutWidth = item.type === "separator" ? void 0 : CUSTOM_TOOLBAR_ITEM_WIDTHS[String(size)];
36244
36555
  const style = item.style;
@@ -36266,7 +36577,7 @@ function mapToolbarCustomItems(items) {
36266
36577
  }
36267
36578
  if (item.type === "dropdown" && isUnknownArray(item.options)) {
36268
36579
  mapped.options = item.options.map((option) => {
36269
- if (!require_create_super_doc_ui.isPlainObject(option)) return option;
36580
+ if (!require__plugin_vue_export_helper.isPlainObject(option)) return option;
36270
36581
  return {
36271
36582
  ...option,
36272
36583
  key: option.value ?? option.id,
@@ -36288,14 +36599,14 @@ function mapToolbarCustomItems(items) {
36288
36599
  }
36289
36600
  function normalizeToolbarOptions(options) {
36290
36601
  const normalized = { ...options };
36291
- const configuredItems = firstDefined(options.items, require_create_super_doc_ui.isPlainObject(options.groups) ? options.groups : void 0);
36292
- const items = require_create_super_doc_ui.isPlainObject(options.items) && Object.keys(options.items).length === 0 ? { center: [] } : configuredItems;
36602
+ const configuredItems = firstDefined(options.items, require__plugin_vue_export_helper.isPlainObject(options.groups) ? options.groups : void 0);
36603
+ const items = require__plugin_vue_export_helper.isPlainObject(options.items) && Object.keys(options.items).length === 0 ? { center: [] } : configuredItems;
36293
36604
  const groupedItems = extendToolbarRegions(items, options);
36294
36605
  const groups = groupedItems === void 0 ? options.groups : mapToolbarRegions(groupedItems);
36295
36606
  const icons = mapToolbarRecord(options.icons, TOOLBAR_ICON_ALIASES);
36296
36607
  const texts = mergeDefined(mapToolbarRecord(options.texts, {}), mapToolbarRecord(options.strings, TOOLBAR_STRING_ALIASES));
36297
36608
  const includeItems = isUnknownArray(options.includeItems) ? new Set(options.includeItems) : null;
36298
- const itemIds = require_create_super_doc_ui.isPlainObject(items) ? new Set(Object.values(items).flatMap((regionItems) => isUnknownArray(regionItems) ? regionItems : [])) : /* @__PURE__ */ new Set();
36609
+ const itemIds = require__plugin_vue_export_helper.isPlainObject(items) ? new Set(Object.values(items).flatMap((regionItems) => isUnknownArray(regionItems) ? regionItems : [])) : /* @__PURE__ */ new Set();
36299
36610
  delete normalized.items;
36300
36611
  delete normalized.includeItems;
36301
36612
  delete normalized.overflow;
@@ -36324,7 +36635,7 @@ function normalizeToolbarOptions(options) {
36324
36635
  function normalizeUiConfig(config = {}) {
36325
36636
  const raw = config.ui;
36326
36637
  const allDisabled = raw === false;
36327
- const ui = require_create_super_doc_ui.isPlainObject(raw) ? raw : void 0;
36638
+ const ui = require__plugin_vue_export_helper.isPlainObject(raw) ? raw : void 0;
36328
36639
  const enabled = (key) => !allDisabled && resolveSurface(ui, key);
36329
36640
  const explicit = (key) => {
36330
36641
  if (allDisabled) return false;
@@ -36338,16 +36649,16 @@ function normalizeUiConfig(config = {}) {
36338
36649
  const legacyContentControlsChrome = config.modules?.contentControls?.chrome === "none" ? void 0 : config.modules?.contentControls?.chrome;
36339
36650
  const rawToolbarOptions = options("toolbar");
36340
36651
  const toolbarOptions = normalizeToolbarOptions(rawToolbarOptions);
36341
- const hasCanonicalToolbarItems = require_create_super_doc_ui.isPlainObject(rawToolbarOptions.items);
36652
+ const hasCanonicalToolbarItems = require__plugin_vue_export_helper.isPlainObject(rawToolbarOptions.items);
36342
36653
  const legacyToolbar = config.modules?.toolbar;
36343
- const legacyToolbarOptions = require_create_super_doc_ui.isPlainObject(legacyToolbar) ? legacyToolbar : {};
36654
+ const legacyToolbarOptions = require__plugin_vue_export_helper.isPlainObject(legacyToolbar) ? legacyToolbar : {};
36344
36655
  const legacyContextMenuRaw = config.modules?.contextMenu ?? config.modules?.slashMenu;
36345
- const legacyContextMenu = require_create_super_doc_ui.isPlainObject(legacyContextMenuRaw) ? legacyContextMenuRaw : {};
36656
+ const legacyContextMenu = require__plugin_vue_export_helper.isPlainObject(legacyContextMenuRaw) ? legacyContextMenuRaw : {};
36346
36657
  const legacySearchRaw = config.modules?.surfaces?.findReplace;
36347
- const legacySearch = normalizeSearchOptions(require_create_super_doc_ui.isPlainObject(legacySearchRaw) ? legacySearchRaw : {});
36348
- const legacyToolbarGroups = require_create_super_doc_ui.isPlainObject(legacyToolbarOptions.groups) ? mapToolbarRegions(extendToolbarRegions(legacyToolbarOptions.groups, rawToolbarOptions)) : legacyToolbarOptions.groups;
36658
+ const legacySearch = normalizeSearchOptions(require__plugin_vue_export_helper.isPlainObject(legacySearchRaw) ? legacySearchRaw : {});
36659
+ const legacyToolbarGroups = require__plugin_vue_export_helper.isPlainObject(legacyToolbarOptions.groups) ? mapToolbarRegions(extendToolbarRegions(legacyToolbarOptions.groups, rawToolbarOptions)) : legacyToolbarOptions.groups;
36349
36660
  const groupCandidates = [toolbarOptions.groups, legacyToolbarGroups];
36350
- const composedGroups = groupCandidates.find(require_create_super_doc_ui.isPlainObject);
36661
+ const composedGroups = groupCandidates.find(require__plugin_vue_export_helper.isPlainObject);
36351
36662
  const orderedGroups = groupCandidates.find(isUnknownArray);
36352
36663
  const selectedGroups = hasCanonicalToolbarItems ? Object.keys(toolbarOptions.groups ?? {}) : firstDefined(orderedGroups, legacyToolbarOptions.toolbarGroups, config.toolbarGroups);
36353
36664
  const selection = isUnknownArray(selectedGroups) ? selectedGroups.map(String) : null;
@@ -36415,6 +36726,7 @@ function normalizeUiConfig(config = {}) {
36415
36726
  * Keeping policy separate means an application can disable the built-in
36416
36727
  * comments UI without losing the rules enforced by its custom UI.
36417
36728
  */
36729
+ var isAutocapitalize = (value) => value === "off" || value === "sentences" || value === "words" || value === "characters";
36418
36730
  var isCommentInteractionLevel = (value) => value === "read" || value === "write" || value === "resolve";
36419
36731
  /**
36420
36732
  * Resolve the effective interaction policy.
@@ -36425,23 +36737,35 @@ var isCommentInteractionLevel = (value) => value === "read" || value === "write"
36425
36737
  * resolve and reopen actions.
36426
36738
  */
36427
36739
  function normalizeInteractionConfig(config = {}) {
36428
- const interaction = require_create_super_doc_ui.isPlainObject(config.interaction) ? config.interaction : {};
36429
- const interactionComments = require_create_super_doc_ui.isPlainObject(interaction.comments) ? interaction.comments : {};
36430
- const interactionTrackedChanges = require_create_super_doc_ui.isPlainObject(interaction.trackedChanges) ? interaction.trackedChanges : {};
36431
- const legacyComments = require_create_super_doc_ui.isPlainObject(config.modules?.comments) ? config.modules.comments : {};
36740
+ const interaction = require__plugin_vue_export_helper.isPlainObject(config.interaction) ? config.interaction : {};
36741
+ const interactionComments = require__plugin_vue_export_helper.isPlainObject(interaction.comments) ? interaction.comments : {};
36742
+ const interactionTrackedChanges = require__plugin_vue_export_helper.isPlainObject(interaction.trackedChanges) ? interaction.trackedChanges : {};
36743
+ const legacyComments = require__plugin_vue_export_helper.isPlainObject(config.modules?.comments) ? config.modules.comments : {};
36432
36744
  const legacyReadOnly = (interactionComments.readOnly ?? legacyComments.readOnly ?? false) === true;
36433
36745
  const legacyAllowResolve = (interactionComments.allowResolve ?? legacyComments.allowResolve ?? true) !== false;
36434
36746
  const canonicalLevel = interactionComments.level;
36435
36747
  const hasCanonicalLevel = isCommentInteractionLevel(canonicalLevel);
36436
36748
  const level = hasCanonicalLevel ? canonicalLevel : legacyReadOnly ? "read" : legacyAllowResolve ? "resolve" : "write";
36749
+ const interactionWritingAssistance = require__plugin_vue_export_helper.isPlainObject(interaction.writingAssistance) ? interaction.writingAssistance : {};
36750
+ const autocorrect = interactionWritingAssistance.autocorrect === true;
36751
+ const autocapitalize = isAutocapitalize(interactionWritingAssistance.autocapitalize) ? interactionWritingAssistance.autocapitalize : "off";
36752
+ const spellcheck = interactionWritingAssistance.spellcheck === true;
36437
36753
  const canonicalAllowDecisions = interactionTrackedChanges.allowDecisions;
36754
+ const interactionTouch = require__plugin_vue_export_helper.isPlainObject(interaction.touch) ? interaction.touch : {};
36438
36755
  return {
36439
36756
  comments: {
36440
36757
  level,
36441
36758
  readOnly: hasCanonicalLevel ? level === "read" : legacyReadOnly,
36442
36759
  allowResolve: hasCanonicalLevel ? level === "resolve" : legacyAllowResolve
36443
36760
  },
36444
- trackedChanges: { allowDecisions: typeof canonicalAllowDecisions === "boolean" ? canonicalAllowDecisions : !legacyReadOnly }
36761
+ trackedChanges: { allowDecisions: typeof canonicalAllowDecisions === "boolean" ? canonicalAllowDecisions : !legacyReadOnly },
36762
+ touch: { gestures: interactionTouch.gestures === true },
36763
+ writingAssistance: {
36764
+ enabled: autocorrect || autocapitalize !== "off" || spellcheck,
36765
+ autocorrect,
36766
+ autocapitalize,
36767
+ spellcheck
36768
+ }
36445
36769
  };
36446
36770
  }
36447
36771
  //#endregion
@@ -36472,8 +36796,8 @@ function normalizeInteractionConfig(config = {}) {
36472
36796
  * is a function or `null` once a non-function value has been rejected.
36473
36797
  */
36474
36798
  function normalizeSurfacesConfig(config = {}) {
36475
- const next = require_create_super_doc_ui.isPlainObject(config.surfaces) ? config.surfaces : {};
36476
- const legacy = require_create_super_doc_ui.isPlainObject(config.modules?.surfaces) ? config.modules.surfaces : {};
36799
+ const next = require__plugin_vue_export_helper.isPlainObject(config.surfaces) ? config.surfaces : {};
36800
+ const legacy = require__plugin_vue_export_helper.isPlainObject(config.modules?.surfaces) ? config.modules.surfaces : {};
36477
36801
  const resolver = next.resolver === void 0 ? legacy.resolver : next.resolver;
36478
36802
  return {
36479
36803
  resolver: typeof resolver === "function" ? resolver : null,
@@ -37010,23 +37334,21 @@ function resolveBuiltInItemCommandId(name) {
37010
37334
  return resolveToolbarCommandId(name) ?? UNCATALOGED_ITEM_COMMAND_IDS[name] ?? null;
37011
37335
  }
37012
37336
  //#endregion
37013
- //#region src/internal/toolbar/built-in/helpers.js
37337
+ //#region src/internal/toolbar/built-in/helpers.ts
37014
37338
  var sanitizeNumber = (value, defaultNumber) => {
37015
- let sanitized = value.replace(/[^0-9.]/g, "");
37016
- sanitized = parseFloat(sanitized);
37017
- if (isNaN(sanitized)) sanitized = defaultNumber;
37018
- sanitized = parseFloat(sanitized);
37019
- return sanitized;
37020
- };
37021
- var throttle = (func, wait, options) => {
37022
- let timeout, args, result;
37339
+ const parsed = parseFloat(String(value ?? "").replace(/[^0-9.]/g, ""));
37340
+ return isNaN(parsed) ? defaultNumber : parsed;
37341
+ };
37342
+ var throttle = (func, wait, options = {}) => {
37343
+ let timeout;
37344
+ let args;
37345
+ let result;
37023
37346
  let previous = 0;
37024
- if (!options) options = {};
37025
37347
  const later = () => {
37026
37348
  previous = options.leading === false ? 0 : Date.now();
37027
- timeout = null;
37028
- result = func(...args);
37029
- if (!timeout) args = null;
37349
+ timeout = void 0;
37350
+ if (args) result = func(...args);
37351
+ if (!timeout) args = void 0;
37030
37352
  };
37031
37353
  const throttled = (...callArgs) => {
37032
37354
  const _now = Date.now();
@@ -37036,18 +37358,18 @@ var throttle = (func, wait, options) => {
37036
37358
  if (remaining <= 0 || remaining > wait) {
37037
37359
  if (timeout) {
37038
37360
  clearTimeout(timeout);
37039
- timeout = null;
37361
+ timeout = void 0;
37040
37362
  }
37041
37363
  previous = _now;
37042
37364
  result = func(...callArgs);
37043
- if (!timeout) args = null;
37365
+ if (!timeout) args = void 0;
37044
37366
  } else if (!timeout && options.trailing !== false) timeout = setTimeout(later, remaining);
37045
37367
  return result;
37046
37368
  };
37047
37369
  throttled.cancel = function() {
37048
37370
  clearTimeout(timeout);
37049
37371
  previous = 0;
37050
- timeout = args = null;
37372
+ timeout = args = void 0;
37051
37373
  };
37052
37374
  return throttled;
37053
37375
  };
@@ -37100,26 +37422,39 @@ var ToolbarButtonIcon_default = /* @__PURE__ */ require__plugin_vue_export_helpe
37100
37422
  var _hoisted_1$15 = [
37101
37423
  "role",
37102
37424
  "aria-label",
37103
- "aria-disabled"
37425
+ "aria-disabled",
37426
+ "aria-busy"
37104
37427
  ];
37105
37428
  var _hoisted_2$11 = ["data-item"];
37106
37429
  var _hoisted_3$10 = ["data-item"];
37107
37430
  var _hoisted_4$8 = {
37108
- key: 1,
37431
+ key: 0,
37432
+ role: "status",
37433
+ "aria-label": "Applying list",
37434
+ style: { "font-weight": "700" }
37435
+ };
37436
+ var _hoisted_5$6 = {
37437
+ key: 2,
37109
37438
  class: "sd-button-label"
37110
37439
  };
37111
- var _hoisted_5$6 = ["data-item", "aria-label"];
37112
- var _hoisted_6$4 = ["innerHTML"];
37113
- var _hoisted_7$2 = { key: 2 };
37114
- var _hoisted_8$2 = ["onKeydown", "id"];
37115
- var _hoisted_9$1 = [
37440
+ var _hoisted_6$4 = ["data-item", "aria-label"];
37441
+ var _hoisted_7$2 = ["innerHTML"];
37442
+ var _hoisted_8$2 = {
37443
+ key: 0,
37444
+ role: "status",
37445
+ "aria-label": "Applying list",
37446
+ style: { "font-weight": "700" }
37447
+ };
37448
+ var _hoisted_9$1 = { key: 3 };
37449
+ var _hoisted_10$1 = ["onKeydown", "id"];
37450
+ var _hoisted_11$1 = [
37116
37451
  "placeholder",
37117
37452
  "onKeydown",
37118
37453
  "id",
37119
37454
  "data-item"
37120
37455
  ];
37121
- var _hoisted_10$1 = ["data-item", "innerHTML"];
37122
- var _hoisted_11$1 = {
37456
+ var _hoisted_12$1 = ["data-item", "innerHTML"];
37457
+ var _hoisted_13$1 = {
37123
37458
  "aria-live": "polite",
37124
37459
  class: "sd-visually-hidden"
37125
37460
  };
@@ -37290,6 +37625,7 @@ var ToolbarButton_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
37290
37625
  role: __props.isOverflowItem ? "menuitem" : "button",
37291
37626
  "aria-label": require__plugin_vue_export_helper.unref(attributes).ariaLabel,
37292
37627
  "aria-disabled": require__plugin_vue_export_helper.unref(disabled) ? "true" : void 0,
37628
+ "aria-busy": require__plugin_vue_export_helper.unref(attributes).ariaBusy || void 0,
37293
37629
  "data-sd-part": "toolbar-item",
37294
37630
  onClick: handleOuterClick,
37295
37631
  onKeydown: _cache[9] || (_cache[9] = require__plugin_vue_export_helper.withKeys(($event) => onEnterKeydown($event), ["enter"])),
@@ -37311,17 +37647,21 @@ var ToolbarButton_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
37311
37647
  class: "sd-toolbar-button__main",
37312
37648
  "data-item": `btn-${require__plugin_vue_export_helper.unref(name) || ""}-main`,
37313
37649
  onClick: _cache[0] || (_cache[0] = ($event) => handleSplitMainClick($event))
37314
- }, [require__plugin_vue_export_helper.unref(icon) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createBlock(ToolbarButtonIcon_default, {
37315
- key: 0,
37316
- color: require__plugin_vue_export_helper.unref(iconColor),
37317
- class: "sd-toolbar-icon",
37318
- icon: require__plugin_vue_export_helper.unref(icon),
37319
- name: require__plugin_vue_export_helper.unref(name)
37320
- }, null, 8, [
37321
- "color",
37322
- "icon",
37323
- "name"
37324
- ])) : require__plugin_vue_export_helper.createCommentVNode("", true), require__plugin_vue_export_helper.unref(label) && !require__plugin_vue_export_helper.unref(hideLabel) && !require__plugin_vue_export_helper.unref(inlineTextInputVisible) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", _hoisted_4$8, require__plugin_vue_export_helper.toDisplayString(require__plugin_vue_export_helper.unref(label)), 1)) : require__plugin_vue_export_helper.createCommentVNode("", true)], 8, _hoisted_3$10)) : require__plugin_vue_export_helper.createCommentVNode("", true),
37650
+ }, [
37651
+ require__plugin_vue_export_helper.unref(attributes).ariaBusy && isSplit.value ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("span", _hoisted_4$8, "…")) : require__plugin_vue_export_helper.createCommentVNode("", true),
37652
+ require__plugin_vue_export_helper.unref(icon) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createBlock(ToolbarButtonIcon_default, {
37653
+ key: 1,
37654
+ color: require__plugin_vue_export_helper.unref(iconColor),
37655
+ class: "sd-toolbar-icon",
37656
+ icon: require__plugin_vue_export_helper.unref(icon),
37657
+ name: require__plugin_vue_export_helper.unref(name)
37658
+ }, null, 8, [
37659
+ "color",
37660
+ "icon",
37661
+ "name"
37662
+ ])) : require__plugin_vue_export_helper.createCommentVNode("", true),
37663
+ require__plugin_vue_export_helper.unref(label) && !require__plugin_vue_export_helper.unref(hideLabel) && !require__plugin_vue_export_helper.unref(inlineTextInputVisible) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", _hoisted_5$6, require__plugin_vue_export_helper.toDisplayString(require__plugin_vue_export_helper.unref(label)), 1)) : require__plugin_vue_export_helper.createCommentVNode("", true)
37664
+ ], 8, _hoisted_3$10)) : require__plugin_vue_export_helper.createCommentVNode("", true),
37325
37665
  isSplit.value ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", {
37326
37666
  key: 1,
37327
37667
  class: "sd-toolbar-button__caret",
@@ -37332,9 +37672,10 @@ var ToolbarButton_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
37332
37672
  class: "sd-dropdown-caret",
37333
37673
  innerHTML: caretIcon.value,
37334
37674
  style: require__plugin_vue_export_helper.normalizeStyle({ opacity: require__plugin_vue_export_helper.unref(disabled) ? .6 : 1 })
37335
- }, null, 12, _hoisted_6$4)], 8, _hoisted_5$6)) : (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock(require__plugin_vue_export_helper.Fragment, { key: 2 }, [
37675
+ }, null, 12, _hoisted_7$2)], 8, _hoisted_6$4)) : (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock(require__plugin_vue_export_helper.Fragment, { key: 2 }, [
37676
+ require__plugin_vue_export_helper.unref(attributes).ariaBusy ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("span", _hoisted_8$2, "…")) : require__plugin_vue_export_helper.createCommentVNode("", true),
37336
37677
  require__plugin_vue_export_helper.unref(icon) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createBlock(ToolbarButtonIcon_default, {
37337
- key: 0,
37678
+ key: 1,
37338
37679
  color: require__plugin_vue_export_helper.unref(iconColor),
37339
37680
  class: "sd-toolbar-icon",
37340
37681
  icon: require__plugin_vue_export_helper.unref(icon),
@@ -37345,10 +37686,10 @@ var ToolbarButton_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
37345
37686
  "name"
37346
37687
  ])) : require__plugin_vue_export_helper.createCommentVNode("", true),
37347
37688
  require__plugin_vue_export_helper.unref(label) && !require__plugin_vue_export_helper.unref(hideLabel) && (!require__plugin_vue_export_helper.unref(inlineTextInputVisible) || itemName.value === "fontFamily") ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", {
37348
- key: 1,
37689
+ key: 2,
37349
37690
  class: require__plugin_vue_export_helper.normalizeClass(["sd-button-label", { "sd-visually-hidden": require__plugin_vue_export_helper.unref(inlineTextInputVisible) && itemName.value === "fontFamily" }])
37350
37691
  }, require__plugin_vue_export_helper.toDisplayString(require__plugin_vue_export_helper.unref(label)), 3)) : require__plugin_vue_export_helper.createCommentVNode("", true),
37351
- require__plugin_vue_export_helper.unref(inlineTextInputVisible) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("span", _hoisted_7$2, [require__plugin_vue_export_helper.unref(name) === "fontSize" ? require__plugin_vue_export_helper.withDirectives((require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("input", {
37692
+ require__plugin_vue_export_helper.unref(inlineTextInputVisible) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("span", _hoisted_9$1, [require__plugin_vue_export_helper.unref(name) === "fontSize" ? require__plugin_vue_export_helper.withDirectives((require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("input", {
37352
37693
  key: 0,
37353
37694
  "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => inlineTextInput.value = $event),
37354
37695
  onKeydown: [require__plugin_vue_export_helper.withKeys(require__plugin_vue_export_helper.withModifiers(handleInlineInputEnter, ["stop", "prevent"]), ["enter"]), _cache[2] || (_cache[2] = require__plugin_vue_export_helper.withKeys(($event) => handleInlineInputTab($event), ["tab"]))],
@@ -37360,7 +37701,7 @@ var ToolbarButton_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
37360
37701
  autocomplete: "off",
37361
37702
  ref_key: "inlineInput",
37362
37703
  ref: inlineInput
37363
- }, null, 42, _hoisted_8$2)), [[require__plugin_vue_export_helper.vModelText, inlineTextInput.value]]) : require__plugin_vue_export_helper.withDirectives((require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("input", {
37704
+ }, null, 42, _hoisted_10$1)), [[require__plugin_vue_export_helper.vModelText, inlineTextInput.value]]) : require__plugin_vue_export_helper.withDirectives((require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("input", {
37364
37705
  key: 1,
37365
37706
  "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => inlineTextInput.value = $event),
37366
37707
  placeholder: require__plugin_vue_export_helper.unref(label),
@@ -37377,23 +37718,23 @@ var ToolbarButton_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ re
37377
37718
  autocomplete: "off",
37378
37719
  ref_key: "inlineInput",
37379
37720
  ref: inlineInput
37380
- }, null, 42, _hoisted_9$1)), [[require__plugin_vue_export_helper.vModelText, inlineTextInput.value]])])) : require__plugin_vue_export_helper.createCommentVNode("", true),
37721
+ }, null, 42, _hoisted_11$1)), [[require__plugin_vue_export_helper.vModelText, inlineTextInput.value]])])) : require__plugin_vue_export_helper.createCommentVNode("", true),
37381
37722
  require__plugin_vue_export_helper.unref(hasCaret) ? (require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("div", {
37382
- key: 3,
37723
+ key: 4,
37383
37724
  class: "sd-dropdown-caret",
37384
37725
  "data-item": `btn-${require__plugin_vue_export_helper.unref(name) || ""}-toggle`,
37385
37726
  innerHTML: caretIcon.value,
37386
37727
  style: require__plugin_vue_export_helper.normalizeStyle({ opacity: require__plugin_vue_export_helper.unref(disabled) ? .6 : 1 })
37387
- }, null, 12, _hoisted_10$1)) : require__plugin_vue_export_helper.createCommentVNode("", true)
37728
+ }, null, 12, _hoisted_12$1)) : require__plugin_vue_export_helper.createCommentVNode("", true)
37388
37729
  ], 64)),
37389
- require__plugin_vue_export_helper.createElementVNode("div", _hoisted_11$1, require__plugin_vue_export_helper.toDisplayString(`${require__plugin_vue_export_helper.unref(attributes).ariaLabel} ${require__plugin_vue_export_helper.unref(active) ? "selected" : "unset"}`), 1)
37730
+ require__plugin_vue_export_helper.createElementVNode("div", _hoisted_13$1, require__plugin_vue_export_helper.toDisplayString(`${require__plugin_vue_export_helper.unref(attributes).ariaLabel} ${require__plugin_vue_export_helper.unref(active) ? "selected" : "unset"}`), 1)
37390
37731
  ], 10, _hoisted_2$11)], 46, _hoisted_1$15);
37391
37732
  };
37392
37733
  }
37393
37734
  });
37394
37735
  //#endregion
37395
37736
  //#region src/internal/toolbar/built-in/ToolbarButton.vue
37396
- var ToolbarButton_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(ToolbarButton_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e599674c"]]);
37737
+ var ToolbarButton_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(ToolbarButton_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-b49ede12"]]);
37397
37738
  //#endregion
37398
37739
  //#region src/internal/toolbar/built-in/ToolbarSeparator.vue?vue&type=script&setup=true&lang.ts
37399
37740
  var _hoisted_1$14 = {
@@ -37953,24 +38294,11 @@ var OverflowMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ req
37953
38294
  //#region src/internal/toolbar/built-in/OverflowMenu.vue
37954
38295
  var OverflowMenu_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(OverflowMenu_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-d2e189fd"]]);
37955
38296
  //#endregion
37956
- //#region src/internal/toolbar/built-in/font-typeahead.js
37957
- /**
37958
- * Pure typeahead/autocomplete helpers for the font comboboxes (family + size).
37959
- *
37960
- * Matching is case-insensitive prefix matching on the logical font labels.
37961
- * Space is a normal query character, so the query is never split on spaces;
37962
- * only the outer whitespace is ignored when comparing.
37963
- *
37964
- * These functions hold no Vue or DOM state so CI can unit-test them in isolation.
37965
- */
38297
+ //#region src/internal/toolbar/built-in/font-typeahead.ts
37966
38298
  var normalize = (value) => String(value ?? "").trim().toLowerCase();
37967
38299
  /**
37968
38300
  * Index of the first label that starts with `query` (case-insensitive).
37969
- * An empty/whitespace query never matches.
37970
- *
37971
- * @param {string} query
37972
- * @param {ReadonlyArray<string>} labels
37973
- * @returns {number} matching index or -1
38301
+ * An empty/whitespace query never matches. Returns the matching index or -1.
37974
38302
  */
37975
38303
  var findPrefixMatchIndex = (query, labels) => {
37976
38304
  const q = normalize(query);
@@ -37984,12 +38312,7 @@ var findPrefixMatchIndex = (query, labels) => {
37984
38312
  * When `autocomplete` is true and a prefix match exists that is longer than the
37985
38313
  * typed query, the completion is shown with the suffix selected so the next
37986
38314
  * keystroke replaces it. When false (deletion) or no match exists, the raw
37987
- * query is shown with the caret at its end.
37988
- *
37989
- * @param {string} query - the user-typed portion
37990
- * @param {ReadonlyArray<string>} labels
37991
- * @param {{ autocomplete?: boolean }} [options]
37992
- * @returns {{ matchIndex: number, display: string, selectionStart: number, selectionEnd: number }}
38315
+ * query is shown with the caret at its end. `query` is the user-typed portion.
37993
38316
  */
37994
38317
  var computeTypeahead = (query, labels, { autocomplete = true } = {}) => {
37995
38318
  const typed = String(query ?? "");
@@ -38041,9 +38364,6 @@ var MAX_FONT_SIZE = 1638;
38041
38364
  * the nearest half point (DOCX/Word support half points such as 10.5), and clamps
38042
38365
  * to the supported range. Returns '' when nothing usable was typed, including
38043
38366
  * negative or sub-minimum values.
38044
- *
38045
- * @param {string} value
38046
- * @returns {string} point size (whole or half), or '' when empty/invalid
38047
38367
  */
38048
38368
  var normalizeCustomFontSize = (value) => {
38049
38369
  const cleaned = String(value ?? "").replace(/[^0-9.-]/g, "");
@@ -38710,7 +39030,7 @@ var SdTooltip_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ requir
38710
39030
  ]);
38711
39031
  const contentStyle = require__plugin_vue_export_helper.computed(() => ({
38712
39032
  ...props.contentStyle,
38713
- ...attrs.style || {},
39033
+ ...attrs.style,
38714
39034
  position: "fixed",
38715
39035
  top: position.value.top,
38716
39036
  left: position.value.left,
@@ -38882,7 +39202,7 @@ var SdTooltip_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ requir
38882
39202
  });
38883
39203
  //#endregion
38884
39204
  //#region src/internal/toolbar/built-in/SdTooltip.vue
38885
- var SdTooltip_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(SdTooltip_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-dfd6f1d1"]]);
39205
+ var SdTooltip_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(SdTooltip_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-87967ab1"]]);
38886
39206
  //#endregion
38887
39207
  //#region src/internal/toolbar/built-in/ButtonGroup.vue?vue&type=script&setup=true&lang.ts
38888
39208
  var _hoisted_1$11 = [
@@ -39738,7 +40058,7 @@ var Toolbar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require_
39738
40058
  //#region src/internal/toolbar/built-in/Toolbar.vue
39739
40059
  var Toolbar_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(Toolbar_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-bce7c04a"]]);
39740
40060
  //#endregion
39741
- //#region src/internal/toolbar/built-in/font-options.js
40061
+ //#region src/internal/toolbar/built-in/font-options.ts
39742
40062
  /**
39743
40063
  * Normalize a font dropdown option so each row renders in its own typeface.
39744
40064
  *
@@ -40096,7 +40416,7 @@ var StyleButtonsList_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
40096
40416
  //#region src/internal/toolbar/built-in/StyleButtonsList.vue
40097
40417
  var StyleButtonsList_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(StyleButtonsList_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-539d0995"]]);
40098
40418
  //#endregion
40099
- //#region src/internal/toolbar/built-in/list-style-buttons.js
40419
+ //#region src/internal/toolbar/built-in/list-style-buttons.ts
40100
40420
  var bulletStyleButtons = [
40101
40421
  {
40102
40422
  key: "disc",
@@ -40429,13 +40749,13 @@ var AIWriter_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ require
40429
40749
  });
40430
40750
  function extractGeneratedText(payload) {
40431
40751
  if (typeof payload === "string") return payload;
40432
- if (!require_create_super_doc_ui.isPlainObject(payload)) return "";
40752
+ if (!require__plugin_vue_export_helper.isPlainObject(payload)) return "";
40433
40753
  const customPrompt = payload.custom_prompt;
40434
40754
  if (Array.isArray(customPrompt)) {
40435
40755
  const first = customPrompt[0];
40436
- if (require_create_super_doc_ui.isPlainObject(first) && typeof first.value === "string") return first.value;
40756
+ if (require__plugin_vue_export_helper.isPlainObject(first) && typeof first.value === "string") return first.value;
40437
40757
  }
40438
- if (require_create_super_doc_ui.isPlainObject(customPrompt) && typeof customPrompt.value === "string") return customPrompt.value;
40758
+ if (require__plugin_vue_export_helper.isPlainObject(customPrompt) && typeof customPrompt.value === "string") return customPrompt.value;
40439
40759
  if (typeof payload.value === "string") return payload.value;
40440
40760
  if (typeof payload.text === "string") return payload.text;
40441
40761
  return "";
@@ -41314,7 +41634,7 @@ var PageNumberMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ r
41314
41634
  }
41315
41635
  function failureDetails(result) {
41316
41636
  if (typeof result !== "object" || result === null || result.success) return null;
41317
- return require_create_super_doc_ui.isPlainObject(result.failure?.details) ? result.failure.details : null;
41637
+ return require__plugin_vue_export_helper.isPlainObject(result.failure?.details) ? result.failure.details : null;
41318
41638
  }
41319
41639
  function failureMessage(result, action) {
41320
41640
  const details = failureDetails(result);
@@ -41426,7 +41746,7 @@ var PageNumberMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ r
41426
41746
  onClick: ($event) => selectTile(tile),
41427
41747
  onDblclick: applyPageNumbers,
41428
41748
  onKeydown: onTileKeydown
41429
- }, [(require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("svg", _hoisted_5, [_cache[4] || (_cache[4] = require__plugin_vue_export_helper.createStaticVNode("<rect class=\"sd-page-number-menu__sheet\" x=\"0.75\" y=\"0.75\" width=\"34.5\" height=\"44.5\" rx=\"2.5\" data-v-a6c124c0></rect><rect class=\"sd-page-number-menu__line\" x=\"7\" y=\"14\" width=\"22\" height=\"2\" rx=\"1\" data-v-a6c124c0></rect><rect class=\"sd-page-number-menu__line\" x=\"7\" y=\"19\" width=\"18\" height=\"2\" rx=\"1\" data-v-a6c124c0></rect><rect class=\"sd-page-number-menu__line\" x=\"7\" y=\"24\" width=\"22\" height=\"2\" rx=\"1\" data-v-a6c124c0></rect><rect class=\"sd-page-number-menu__line\" x=\"7\" y=\"29\" width=\"14\" height=\"2\" rx=\"1\" data-v-a6c124c0></rect>", 5)), require__plugin_vue_export_helper.createElementVNode("rect", {
41749
+ }, [(require__plugin_vue_export_helper.openBlock(), require__plugin_vue_export_helper.createElementBlock("svg", _hoisted_5, [_cache[4] || (_cache[4] = require__plugin_vue_export_helper.createStaticVNode("<rect class=\"sd-page-number-menu__sheet\" x=\"0.75\" y=\"0.75\" width=\"34.5\" height=\"44.5\" rx=\"2.5\" data-v-e3105afd></rect><rect class=\"sd-page-number-menu__line\" x=\"7\" y=\"14\" width=\"22\" height=\"2\" rx=\"1\" data-v-e3105afd></rect><rect class=\"sd-page-number-menu__line\" x=\"7\" y=\"19\" width=\"18\" height=\"2\" rx=\"1\" data-v-e3105afd></rect><rect class=\"sd-page-number-menu__line\" x=\"7\" y=\"24\" width=\"22\" height=\"2\" rx=\"1\" data-v-e3105afd></rect><rect class=\"sd-page-number-menu__line\" x=\"7\" y=\"29\" width=\"14\" height=\"2\" rx=\"1\" data-v-e3105afd></rect>", 5)), require__plugin_vue_export_helper.createElementVNode("rect", {
41430
41750
  class: "sd-page-number-menu__chip",
41431
41751
  x: CHIP_X[tile.alignment],
41432
41752
  y: CHIP_Y[tile.position],
@@ -41509,23 +41829,21 @@ var PageNumberMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ r
41509
41829
  });
41510
41830
  //#endregion
41511
41831
  //#region src/internal/toolbar/built-in/PageNumberMenu.vue
41512
- var PageNumberMenu_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(PageNumberMenu_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-a6c124c0"]]);
41832
+ var PageNumberMenu_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(PageNumberMenu_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e3105afd"]]);
41513
41833
  //#endregion
41514
- //#region src/internal/toolbar/built-in/page-number-feedback.js
41834
+ //#region src/internal/toolbar/built-in/page-number-feedback.ts
41515
41835
  var FLASH_CLASS = "sd-page-number-flash";
41516
41836
  var FLASH_MS = 1400;
41517
41837
  var nextFrame = (view) => new Promise((resolve) => {
41518
- if (typeof view?.requestAnimationFrame === "function") view.requestAnimationFrame(() => resolve());
41838
+ if (typeof view.requestAnimationFrame === "function") view.requestAnimationFrame(() => resolve());
41519
41839
  else setTimeout(resolve, 16);
41520
41840
  });
41521
41841
  /**
41522
41842
  * Briefly highlight the painted header or footer regions that are on screen,
41523
41843
  * so the user sees where page numbers landed without the caret leaving the
41524
41844
  * body. Regions are read after the repaint that follows the mutation; nothing
41525
- * happens when none is visible or the host is unavailable.
41526
- *
41527
- * @param {HTMLElement | null | undefined} host Document viewport host element.
41528
- * @param {'header' | 'footer'} kind
41845
+ * happens when none is visible or the host is unavailable. `host` is the
41846
+ * document viewport host element.
41529
41847
  */
41530
41848
  async function flashPageNumberRegions(host, kind) {
41531
41849
  const view = host?.ownerDocument?.defaultView;
@@ -41533,7 +41851,7 @@ async function flashPageNumberRegions(host, kind) {
41533
41851
  await nextFrame(view);
41534
41852
  await nextFrame(view);
41535
41853
  const viewportHeight = view.innerHeight;
41536
- const regions = [...host.querySelectorAll(`[data-sd-headerfooter-kind="${kind}"]`)].filter((region) => {
41854
+ const regions = Array.from(host.querySelectorAll(`[data-sd-headerfooter-kind="${kind}"]`)).filter((region) => {
41537
41855
  const rect = region.getBoundingClientRect();
41538
41856
  return rect.height > 0 && rect.bottom > 0 && rect.top < viewportHeight;
41539
41857
  });
@@ -41711,7 +42029,7 @@ function currentSelectionSnapshot(superToolbar) {
41711
42029
  return superToolbar.ui?.selection?.get?.() ?? superToolbar.ui?.selection?.current?.() ?? null;
41712
42030
  }
41713
42031
  function readMember(value, key) {
41714
- return require_create_super_doc_ui.isPlainObject(value) ? value[key] : void 0;
42032
+ return require__plugin_vue_export_helper.isPlainObject(value) ? value[key] : void 0;
41715
42033
  }
41716
42034
  function configuredAiModule(superToolbar) {
41717
42035
  return readMember(readMember(readMember(readMember(superToolbar.config, "superdoc"), "config"), "modules"), "ai");
@@ -41734,6 +42052,8 @@ var makeDefaultItems = ({ superToolbar, toolbarIcons: configuredIcons, toolbarTe
41734
42052
  attributes: { ariaLabel: "Bold" }
41735
42053
  });
41736
42054
  const fontOptions = (toolbarFonts ?? TOOLBAR_FONTS).map(normalizeFontOption);
42055
+ const isFontOption = (option) => typeof option.label === "string" && typeof option.key === "string";
42056
+ const currentFontOptions = () => fontButton.nestedOptions.value.filter(isFontOption);
41737
42057
  const fontButton = useToolbarItem({
41738
42058
  type: "dropdown",
41739
42059
  name: "fontFamily",
@@ -41760,8 +42080,9 @@ var makeDefaultItems = ({ superToolbar, toolbarIcons: configuredIcons, toolbarTe
41760
42080
  if (typeof fontFamily !== "string" || !fontFamily) return;
41761
42081
  const family = fontFamily.split(",")[0];
41762
42082
  const optionValue = (option) => option.value ?? option.label;
41763
- const defaultFont = fontOptions.find((option) => optionValue(option) === fontButton.defaultLabel.value);
41764
- const foundFont = fontOptions.find((option) => optionValue(option) === family);
42083
+ const options = currentFontOptions();
42084
+ const defaultFont = options.find((option) => optionValue(option) === fontButton.defaultLabel.value);
42085
+ const foundFont = options.find((option) => optionValue(option) === family);
41765
42086
  if (foundFont) {
41766
42087
  fontButton.label.value = foundFont.label;
41767
42088
  fontButton.selectedValue.value = foundFont.key;
@@ -41774,7 +42095,7 @@ var makeDefaultItems = ({ superToolbar, toolbarIcons: configuredIcons, toolbarTe
41774
42095
  }
41775
42096
  },
41776
42097
  onDeactivate: () => {
41777
- const defaultFont = fontOptions.find((option) => (option.value ?? option.label) === fontButton.defaultLabel.value);
42098
+ const defaultFont = currentFontOptions().find((option) => (option.value ?? option.label) === fontButton.defaultLabel.value);
41778
42099
  fontButton.label.value = defaultFont?.label ?? fontButton.defaultLabel.value;
41779
42100
  fontButton.selectedValue.value = defaultFont?.key ?? "";
41780
42101
  }
@@ -42881,7 +43202,7 @@ var makeDefaultItems = ({ superToolbar, toolbarIcons: configuredIcons, toolbarTe
42881
43202
  };
42882
43203
  };
42883
43204
  //#endregion
42884
- //#region src/internal/toolbar/built-in/general.js
43205
+ //#region src/internal/toolbar/built-in/general.ts
42885
43206
  /**
42886
43207
  * Minimal DOM helpers for the built-in toolbar shell.
42887
43208
  *
@@ -42892,8 +43213,6 @@ var makeDefaultItems = ({ superToolbar, toolbarIcons: configuredIcons, toolbarTe
42892
43213
  */
42893
43214
  /**
42894
43215
  * Resolve a toolbar mount target from a selector string or element id.
42895
- * @param {string|HTMLElement|null|undefined} selector
42896
- * @returns {HTMLElement|null}
42897
43216
  */
42898
43217
  var findElementBySelector = (selector) => {
42899
43218
  if (!selector) return null;
@@ -42933,9 +43252,6 @@ function toSelectedValue(value) {
42933
43252
  function nonEmptyString(value) {
42934
43253
  return typeof value === "string" && value ? value : void 0;
42935
43254
  }
42936
- function isThenable(value) {
42937
- return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
42938
- }
42939
43255
  function isToolbarCommandCallback(value) {
42940
43256
  return typeof value === "function";
42941
43257
  }
@@ -42958,7 +43274,7 @@ function executeCommand(ui, commandId, argument, options = {}) {
42958
43274
  if (!options.reportUnhandled || settled !== false) return;
42959
43275
  options.onError?.(/* @__PURE__ */ new Error(`[superdoc toolbar] Command "${commandId}" did not run. Check that it is enabled and has the required input.`));
42960
43276
  };
42961
- if (isThenable(result)) Promise.resolve(result).then((settled) => {
43277
+ if (require__plugin_vue_export_helper.isThenable(result)) Promise.resolve(result).then((settled) => {
42962
43278
  reportFailure(settled);
42963
43279
  options.onSettled?.();
42964
43280
  }, (error) => {
@@ -42991,7 +43307,7 @@ var V1_ENABLED_ON_SELECTION_REASON = /* @__PURE__ */ new Set([
42991
43307
  ]);
42992
43308
  var V1_ENABLED_ON_EMPTY_REASON = /* @__PURE__ */ new Set(["list", "numberedlist"]);
42993
43309
  function shouldKeepEnabledForV1ToolbarParity(name, commandState) {
42994
- if (name === "fontFamily" || name === "fontSize") return true;
43310
+ if (name === "fontFamily" || name === "fontSize") return commandState?.reason !== "document-readonly" && commandState?.reason !== "deleted-text-formatting-unsupported";
42995
43311
  if (V1_ENABLED_ON_EMPTY_REASON.has(name) && commandState?.disabled && commandState?.supported !== false && commandState?.reason == null) return true;
42996
43312
  if (!V1_ENABLED_ON_SELECTION_REASON.has(name)) return false;
42997
43313
  const reason = commandState?.reason;
@@ -43025,6 +43341,7 @@ var RESERVED_TOOLBAR_ITEM_NAMES = /* @__PURE__ */ new Set([
43025
43341
  * proof lane, and behavior tests resolve against a real object.
43026
43342
  */
43027
43343
  var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.default {
43344
+ #formattingRefusalTooltips;
43028
43345
  #imagePicker;
43029
43346
  #groupItems;
43030
43347
  #highlightOptions;
@@ -43056,6 +43373,7 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
43056
43373
  showPageNumberButton: false
43057
43374
  };
43058
43375
  this.toolbarItems = [];
43376
+ this.#formattingRefusalTooltips = /* @__PURE__ */ new WeakMap();
43059
43377
  this.overflowItems = [];
43060
43378
  this.pendingSelectionCapture = void 0;
43061
43379
  this.#imagePicker = null;
@@ -43182,7 +43500,7 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
43182
43500
  const signature = this.#fontOptionsSignature();
43183
43501
  if (signature !== this._lastFontOptionsSignature) {
43184
43502
  this._lastFontOptionsSignature = signature;
43185
- this.#rebuildToolbarItems();
43503
+ if (!this.#refreshFontFamilyOptions()) this.#rebuildToolbarItems();
43186
43504
  }
43187
43505
  this.updateToolbarState();
43188
43506
  };
@@ -43310,7 +43628,7 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
43310
43628
  argument: payload.argument,
43311
43629
  option: payload.option
43312
43630
  });
43313
- if (isThenable(result)) return Promise.resolve(result).catch((error) => {
43631
+ if (require__plugin_vue_export_helper.isThenable(result)) return Promise.resolve(result).catch((error) => {
43314
43632
  this.#emitCommandException(error, config.name);
43315
43633
  return false;
43316
43634
  });
@@ -43330,6 +43648,13 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
43330
43648
  this.#makeToolbarItems();
43331
43649
  this.emit("toolbar-items-changed");
43332
43650
  }
43651
+ #refreshFontFamilyOptions() {
43652
+ const items = this.#getAllToolbarItems().filter((item) => item.name.value === "fontFamily");
43653
+ if (!items.length) return false;
43654
+ const options = (this.#resolveToolbarFonts(this.config.fonts) ?? TOOLBAR_FONTS).map(normalizeFontOption);
43655
+ for (const item of items) item.nestedOptions.value = options.map((option) => ({ ...option }));
43656
+ return true;
43657
+ }
43333
43658
  #fontOptionsSignature() {
43334
43659
  if (this.config.fonts) return "custom-fonts";
43335
43660
  const options = this.superdoc?.fonts?.getFontFamilyOptions?.() ?? [];
@@ -43509,6 +43834,17 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
43509
43834
  const commandId = resolveBuiltInItemCommandId(name);
43510
43835
  if (!commandId) return false;
43511
43836
  const commandState = this.snapshot?.commands?.[commandId];
43837
+ if (commandState?.reason === "deleted-text-formatting-unsupported") {
43838
+ if (!this.#formattingRefusalTooltips.has(item)) this.#formattingRefusalTooltips.set(item, item.tooltip.value);
43839
+ item.tooltip.value = "Select kept text, or accept or reject the deletion before formatting.";
43840
+ } else if (this.#formattingRefusalTooltips.has(item)) {
43841
+ item.tooltip.value = this.#formattingRefusalTooltips.get(item);
43842
+ this.#formattingRefusalTooltips.delete(item);
43843
+ }
43844
+ if ((name === "list" || name === "numberedlist") && item.attributes.value.ariaBusy !== Boolean(commandState?.pending)) item.attributes.value = {
43845
+ ...item.attributes.value,
43846
+ ariaBusy: Boolean(commandState?.pending)
43847
+ };
43512
43848
  if (shouldKeepEnabledForV1ToolbarParity(name, commandState)) item.setDisabled(false);
43513
43849
  else item.setDisabled(Boolean(commandState?.disabled));
43514
43850
  const handlers = {
@@ -43787,7 +44123,7 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
43787
44123
  ui: this.ui,
43788
44124
  superdoc: this.superdoc
43789
44125
  });
43790
- if (isThenable(result)) Promise.resolve(result).catch((error) => this.#emitCommandException(error, name));
44126
+ if (require__plugin_vue_export_helper.isThenable(result)) Promise.resolve(result).catch((error) => this.#emitCommandException(error, name));
43791
44127
  }
43792
44128
  this.updateToolbarState();
43793
44129
  return;
@@ -43976,6 +44312,9 @@ function deriveCollaborationConnectionKind(snapshot, hasSyncedBefore) {
43976
44312
  default: return hasSyncedBefore ? "reconnecting" : "initial";
43977
44313
  }
43978
44314
  }
44315
+ function destroyedDuringUpgradeError() {
44316
+ return /* @__PURE__ */ new Error("SuperDoc: instance was destroyed during upgrade");
44317
+ }
43979
44318
  function isV2ActiveEditorFacade(editor) {
43980
44319
  return Boolean(editor && typeof editor === "object" && editor.editorVersion === 2);
43981
44320
  }
@@ -44025,6 +44364,7 @@ function runtimeUserOf(user) {
44025
44364
  const text = (value) => typeof value === "string" && value ? value : void 0;
44026
44365
  return {
44027
44366
  name: text(user.name) ?? "",
44367
+ ...user.commentIdentity !== void 0 ? { commentIdentity: user.commentIdentity ? { ...user.commentIdentity } : null } : {},
44028
44368
  ...text(user.id) ? { id: text(user.id) } : {},
44029
44369
  ...text(user.email) ? { email: text(user.email) } : {},
44030
44370
  ...text(user.initials) ? { initials: text(user.initials) } : {}
@@ -44036,10 +44376,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44036
44376
  }
44037
44377
  #destroyed;
44038
44378
  #diagnostics;
44039
- #isUpgrading;
44040
44379
  #pendingUpgrade;
44041
- /** Aborts an in-flight upgrade (sync wait or ready wait). */
44042
- #abortUpgrade;
44043
44380
  /**
44044
44381
  * Unsubscribe handle for the v2 presence → `awareness-update` bridge. Set
44045
44382
  * while a v2 collaborative editor is mounted and torn down on remount,
@@ -44053,6 +44390,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44053
44390
  #v2ConnectionUnsub;
44054
44391
  /** Latest `collaboration-connection-change` payload, for late readers. */
44055
44392
  #v2ConnectionState;
44393
+ #v2ConnectionFailureReported;
44056
44394
  /** Whether the current collaboration room has completed a sync at least once. */
44057
44395
  #v2ConnectionHasSynced;
44058
44396
  /** Lock state captured before a local → v2 collaboration promotion remount. */
@@ -44148,13 +44486,12 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44148
44486
  constructor(config) {
44149
44487
  super();
44150
44488
  this.#destroyed = false;
44151
- this.#isUpgrading = false;
44152
44489
  this.#pendingUpgrade = null;
44153
- this.#abortUpgrade = null;
44154
44490
  this.#v2AwarenessUnsub = null;
44155
44491
  this.#v2LockUnsub = null;
44156
44492
  this.#v2ConnectionUnsub = null;
44157
44493
  this.#v2ConnectionState = null;
44494
+ this.#v2ConnectionFailureReported = false;
44158
44495
  this.#v2ConnectionHasSynced = false;
44159
44496
  this.#pendingV2LockSeed = null;
44160
44497
  this.#mountWrapper = null;
@@ -44269,6 +44606,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44269
44606
  if (!config.selector) throw new Error("SuperDoc: selector is required");
44270
44607
  const container = typeof config.selector === "string" ? document.querySelector(config.selector) : config.selector;
44271
44608
  if (!(container instanceof HTMLElement)) throw new Error("SuperDoc: selector must be a valid CSS selector string or DOM element");
44609
+ const user = normalizeSuperDocUser(config.user);
44272
44610
  this.#diagnostics = require_create_super_doc_ui.createInteractionHistory(this, config, () => this.version, container);
44273
44611
  this.#surfaceManager = new SurfaceManager({ getModuleConfig: () => this.#surfacesConfig });
44274
44612
  this.#contentControlClickRoot = container;
@@ -44278,7 +44616,10 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44278
44616
  container.addEventListener("keydown", this.#handleContentControlKeyDown, true);
44279
44617
  container.addEventListener("click", this.#handleContentControlClick, true);
44280
44618
  this.#onConfig("content-control:active-change", config.onContentControlActiveChange);
44281
- this.#init(config, container);
44619
+ this.#init({
44620
+ ...config,
44621
+ user
44622
+ }, container);
44282
44623
  this.#contentControlEventBridgeReady = true;
44283
44624
  if (this.listenerCount("content-control:active-change") > 0) this.ui;
44284
44625
  }
@@ -44331,7 +44672,6 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44331
44672
  }
44332
44673
  this.editorVersion = 2;
44333
44674
  this.#validateLegacyConfig();
44334
- this.config.user = normalizeSuperDocUser(this.config.user);
44335
44675
  if (!this.config.layoutEngineOptions.virtualization) this.config.layoutEngineOptions.virtualization = {
44336
44676
  enabled: true,
44337
44677
  window: 5,
@@ -44357,7 +44697,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44357
44697
  }
44358
44698
  this.userColorMap = /* @__PURE__ */ new Map();
44359
44699
  this.colorIndex = 0;
44360
- this.version = "2.29.0-next.9";
44700
+ this.version = "2.30.0-next.13";
44361
44701
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
44362
44702
  this.superdocId = config.superdocId || require_uuid.v4();
44363
44703
  this.colors = this.config.colors ?? [];
@@ -44776,6 +45116,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44776
45116
  if (this.#v2ConnectionState?.documentId !== documentId) {
44777
45117
  this.#v2ConnectionState = null;
44778
45118
  this.#v2ConnectionHasSynced = false;
45119
+ this.#v2ConnectionFailureReported = false;
44779
45120
  }
44780
45121
  const publish = (snapshot) => {
44781
45122
  if (this.#destroyed) return;
@@ -44790,8 +45131,21 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44790
45131
  superdoc: this
44791
45132
  };
44792
45133
  this.#v2ConnectionState = payload;
44793
- if (snapshot.state === "synced") this.#v2ConnectionHasSynced = true;
44794
- this.emit("collaboration-connection-change", payload);
45134
+ if (snapshot.state === "synced") {
45135
+ this.#v2ConnectionHasSynced = true;
45136
+ this.#v2ConnectionFailureReported = false;
45137
+ }
45138
+ const firstFailure = snapshot.state === "failed" && !this.#v2ConnectionFailureReported;
45139
+ if (firstFailure) this.#v2ConnectionFailureReported = true;
45140
+ const reportFailure = firstFailure && snapshot.detail !== "worker-transport-failed";
45141
+ try {
45142
+ this.emit("collaboration-connection-change", payload);
45143
+ } finally {
45144
+ if (reportFailure) {
45145
+ const exception = createCollaborationException("collaboration-connection-failed", documentId);
45146
+ if (exception) this.emit("exception", exception);
45147
+ }
45148
+ }
44795
45149
  };
44796
45150
  try {
44797
45151
  const initialSnapshot = connection.getSnapshot?.();
@@ -44904,41 +45258,43 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
44904
45258
  throw Object.assign(/* @__PURE__ */ new Error("SuperDoc: a different collaboration target is already upgrading"), { code: "collaboration-upgrade-target-conflict" });
44905
45259
  }
44906
45260
  const { target } = this.#validateUpgradePrerequisites(options);
44907
- this.#isUpgrading = true;
44908
- const operation = (async () => {
44909
- try {
44910
- const localSource = await this.#captureCurrentDocxSourceForUpgrade();
44911
- const rollback = this.#snapshotV2UpgradeState();
44912
- const lockSeed = this.#snapshotV2LockSeed();
44913
- this.#assertNotDestroyed();
44914
- try {
44915
- this.#pendingV2LockSeed = lockSeed;
44916
- const promotion = await this.#promoteSingleDocumentToV2Collaboration(target, localSource);
44917
- this.#finalizeSingleDocumentV2Collaboration(promotion, target);
44918
- this.#pendingV2LockSeed = null;
44919
- const attachedDocumentId = this.activeEditor?.options?.documentId;
44920
- const attachedRoomId = promotion.configDoc.v2Collaboration?.documentId;
44921
- if (typeof attachedDocumentId !== "string" || attachedDocumentId !== promotion.configDoc.id || typeof attachedRoomId !== "string" || attachedRoomId !== target.documentId) throw new Error("SuperDoc: collaboration upgrade did not attach the expected room and document");
44922
- return {
44923
- roomId: attachedRoomId,
44924
- documentId: attachedDocumentId
44925
- };
44926
- } catch (err) {
44927
- this.#rollbackV2UpgradeState(rollback);
44928
- throw err;
44929
- }
44930
- } finally {
44931
- this.#abortUpgrade = null;
44932
- this.#isUpgrading = false;
44933
- this.#pendingUpgrade = null;
44934
- }
44935
- })();
45261
+ let rejectOnDestroy = () => {};
45262
+ const destroyed = new Promise((_resolve, reject) => {
45263
+ rejectOnDestroy = reject;
45264
+ });
45265
+ const operation = Promise.race([this.#runUpgrade(target), destroyed]).finally(() => {
45266
+ this.#pendingUpgrade = null;
45267
+ });
44936
45268
  this.#pendingUpgrade = {
44937
45269
  target,
44938
- promise: operation
45270
+ promise: operation,
45271
+ rejectOnDestroy
44939
45272
  };
44940
45273
  return operation;
44941
45274
  }
45275
+ async #runUpgrade(target) {
45276
+ const localSource = await this.#captureCurrentDocxSourceForUpgrade();
45277
+ const rollback = this.#snapshotV2UpgradeState();
45278
+ const lockSeed = this.#snapshotV2LockSeed();
45279
+ this.#assertNotDestroyed();
45280
+ try {
45281
+ this.#pendingV2LockSeed = lockSeed;
45282
+ const promotion = await this.#promoteSingleDocumentToV2Collaboration(target, localSource);
45283
+ this.#assertNotDestroyed();
45284
+ this.#finalizeSingleDocumentV2Collaboration(promotion, target);
45285
+ this.#pendingV2LockSeed = null;
45286
+ const attachedDocumentId = this.activeEditor?.options?.documentId;
45287
+ const attachedRoomId = promotion.configDoc.v2Collaboration?.documentId;
45288
+ if (typeof attachedDocumentId !== "string" || attachedDocumentId !== promotion.configDoc.id || typeof attachedRoomId !== "string" || attachedRoomId !== target.documentId) throw new Error("SuperDoc: collaboration upgrade did not attach the expected room and document");
45289
+ return {
45290
+ roomId: attachedRoomId,
45291
+ documentId: attachedDocumentId
45292
+ };
45293
+ } catch (err) {
45294
+ if (!this.#destroyed) this.#rollbackV2UpgradeState(rollback);
45295
+ throw err;
45296
+ }
45297
+ }
44942
45298
  #sameUpgradeTarget(left, right) {
44943
45299
  if (left.token !== right.token) return false;
44944
45300
  const seen = /* @__PURE__ */ new WeakMap();
@@ -45003,7 +45359,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45003
45359
  * async waits inside upgradeToCollaboration().
45004
45360
  */
45005
45361
  #assertNotDestroyed() {
45006
- if (this.#destroyed) throw new Error("SuperDoc: instance was destroyed during upgrade");
45362
+ if (this.#destroyed) throw destroyedDuringUpgradeError();
45007
45363
  }
45008
45364
  /**
45009
45365
  * Return the superdoc store, throwing a clear lifecycle error if
@@ -45102,6 +45458,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45102
45458
  this.#writeStoreDocV2Collaboration(storeDoc, v2Collaboration);
45103
45459
  this.isCollaborative = true;
45104
45460
  await editor.upgradeToCollaboration(localSource, v2Collaboration);
45461
+ this.#assertNotDestroyed();
45105
45462
  configDoc.data = localSource;
45106
45463
  storeDoc.data = localSource;
45107
45464
  return {
@@ -45161,7 +45518,6 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45161
45518
  */
45162
45519
  #validateUpgradePrerequisites(options) {
45163
45520
  if (this.#destroyed) throw new Error("SuperDoc: cannot upgrade a destroyed instance");
45164
- if (this.#isUpgrading) throw new Error("SuperDoc: upgrade already in progress");
45165
45521
  if (this.isCollaborative) throw new Error("SuperDoc: instance is already collaborative");
45166
45522
  const cfg = this.config;
45167
45523
  const docxDocs = cfg.documents.filter((d) => d.type === DOCX);
@@ -45216,10 +45572,15 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45216
45572
  this.#requireReady("setUser");
45217
45573
  const name = typeof user?.name === "string" ? user.name.trim() : "";
45218
45574
  if (!name) return Promise.reject(/* @__PURE__ */ new TypeError("SuperDoc.setUser requires a non-empty user name."));
45219
- const next = normalizeSuperDocUser({
45220
- ...user,
45221
- name
45222
- });
45575
+ let next;
45576
+ try {
45577
+ next = normalizeSuperDocUser({
45578
+ ...user,
45579
+ name
45580
+ });
45581
+ } catch (error) {
45582
+ return Promise.reject(error);
45583
+ }
45223
45584
  const applied = this.#userSwitch.then(() => this.#applyUser(next));
45224
45585
  this.#userSwitch = applied.catch(() => {});
45225
45586
  return applied;
@@ -45233,7 +45594,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45233
45594
  "email",
45234
45595
  "image",
45235
45596
  "initials"
45236
- ].every((key) => (current[key] ?? null) === (next[key] ?? null))) return;
45597
+ ].every((key) => (current[key] ?? null) === (next[key] ?? null)) && current.commentIdentity === void 0 === (next.commentIdentity === void 0) && (current.commentIdentity?.providerId ?? null) === (next.commentIdentity?.providerId ?? null) && (current.commentIdentity?.userId ?? null) === (next.commentIdentity?.userId ?? null)) return;
45237
45598
  const runtimes = this.#editorRuntimeRegistry.getAll();
45238
45599
  const results = await Promise.allSettled(runtimes.map((runtime) => runtime.setUser?.(runtimeUserOf(next))));
45239
45600
  const failure = results.find((result) => result.status === "rejected");
@@ -46568,10 +46929,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46568
46929
  this.#contentControlClickRoot = null;
46569
46930
  this.#contentControlActiveChangeUnsub?.();
46570
46931
  this.#contentControlActiveChangeUnsub = null;
46571
- if (this.#abortUpgrade) {
46572
- this.#abortUpgrade();
46573
- this.#abortUpgrade = null;
46574
- }
46932
+ this.#pendingUpgrade?.rejectOnDestroy(destroyedDuringUpgradeError());
46575
46933
  if (this.#surfaceManager) this.#surfaceManager.destroy();
46576
46934
  this.toolbar?.destroy?.();
46577
46935
  this.commentsList?.close();