superdoc 2.0.0-next.45 → 2.0.0-next.47

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 (36) hide show
  1. package/AGENTS.md +15 -8
  2. package/dist/chunks/{create-super-doc-ui-BTOlZen9.es.js → create-super-doc-ui-CKyCKKdl.es.js} +244 -143
  3. package/dist/chunks/{create-super-doc-ui-DDxbK_M7.cjs → create-super-doc-ui-Dk6T01KE.cjs} +243 -142
  4. package/dist/collaboration-upgrade-engine.cjs +1 -1
  5. package/dist/collaboration-upgrade-engine.es.js +1 -1
  6. package/dist/document-api/src/contract/command-catalog.d.ts +1 -1
  7. package/dist/document-api/src/contract/operation-definitions.d.ts +1 -1
  8. package/dist/public/ui-react.cjs +17 -14
  9. package/dist/public/ui-react.es.js +17 -14
  10. package/dist/public/ui.cjs +1 -1
  11. package/dist/public/ui.es.js +1 -1
  12. package/dist/style.css +23 -23
  13. package/dist/style.layered.css +23 -23
  14. package/dist/superdoc/src/components/surfaces/FindReplaceSurface.vue.d.ts +2 -2
  15. package/dist/superdoc/src/components/surfaces/PasswordPromptSurface.vue.d.ts +2 -2
  16. package/dist/superdoc/src/components/surfaces/SurfaceExternalMount.vue.d.ts +2 -2
  17. package/dist/superdoc/src/composables/replace-continuation.d.ts +37 -0
  18. package/dist/superdoc/src/composables/use-find-replace.d.ts +2 -2
  19. package/dist/superdoc/src/core/SuperDoc.d.ts +41 -0
  20. package/dist/superdoc/src/core/types/index.d.ts +2 -14
  21. package/dist/superdoc/src/internal/toolbar/built-in/default-items.d.ts +11 -0
  22. package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +5 -5
  23. package/dist/superdoc/src/public/browser-document-api.d.ts +53 -0
  24. package/dist/superdoc/src/public/index.d.cts +4 -0
  25. package/dist/superdoc/src/public/index.d.ts +2 -0
  26. package/dist/superdoc/src/public/ui/react.d.ts +18 -7
  27. package/dist/superdoc/src/public/ui/types.d.ts +81 -12
  28. package/dist/superdoc/src/public/ui-react.d.ts +4 -3
  29. package/dist/superdoc/src/public/ui.d.cts +8 -0
  30. package/dist/superdoc/src/public/ui.d.ts +1 -1
  31. package/dist/superdoc.cjs +84 -59
  32. package/dist/superdoc.es.js +84 -59
  33. package/dist-cdn/style.layered.css +1 -1
  34. package/dist-cdn/superdoc.min.css +1 -1
  35. package/dist-cdn/superdoc.min.js +35 -35
  36. package/package.json +1 -1
package/dist/superdoc.cjs CHANGED
@@ -6,7 +6,7 @@ const require_uuid = require("./chunks/uuid-CFp0WGVU.cjs");
6
6
  const require_jszip = require("./chunks/jszip-BdUBlUeG.cjs");
7
7
  const require__plugin_vue_export_helper = require("./chunks/_plugin-vue_export-helper-BTwbGDKw.cjs");
8
8
  const require_constants = require("./chunks/constants-sbCZ2O_A.cjs");
9
- const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-DDxbK_M7.cjs");
9
+ const require_create_super_doc_ui = require("./chunks/create-super-doc-ui-Dk6T01KE.cjs");
10
10
  let vue = require("vue");
11
11
  vue = require_rolldown_runtime.__toESM(vue);
12
12
  require("y-websocket");
@@ -10554,6 +10554,14 @@ function usePasswordPrompt({ getSurfaceManager, getPasswordPromptConfig, onUnhan
10554
10554
  destroy
10555
10555
  };
10556
10556
  }
10557
+ function createReplaceContinuation(session, { getCurrentSession, applySlice, onSettled }) {
10558
+ return () => {
10559
+ if (session === getCurrentSession()) try {
10560
+ applySlice(session.getSnapshot());
10561
+ } catch {}
10562
+ onSettled();
10563
+ };
10564
+ }
10557
10565
  var DEFAULT_TEXTS = {
10558
10566
  findPlaceholder: "Find",
10559
10567
  findAriaLabel: "Find text",
@@ -10738,12 +10746,13 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
10738
10746
  if (!canReplaceState.value) return;
10739
10747
  const search = currentV2Search;
10740
10748
  replacePending.value = true;
10741
- const finish = () => {
10742
- try {
10743
- applyV2Slice(search.getSnapshot());
10744
- } catch {}
10745
- replacePending.value = false;
10746
- };
10749
+ const finish = createReplaceContinuation(search, {
10750
+ getCurrentSession: () => currentV2Search,
10751
+ applySlice: applyV2Slice,
10752
+ onSettled: () => {
10753
+ replacePending.value = false;
10754
+ }
10755
+ });
10747
10756
  let result = null;
10748
10757
  try {
10749
10758
  result = search.replace(replaceText.value);
@@ -10767,12 +10776,13 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
10767
10776
  if (!canReplaceState.value) return;
10768
10777
  const search = currentV2Search;
10769
10778
  replacePending.value = true;
10770
- const finish = () => {
10771
- try {
10772
- applyV2Slice(search.getSnapshot());
10773
- } catch {}
10774
- replacePending.value = false;
10775
- };
10779
+ const finish = createReplaceContinuation(search, {
10780
+ getCurrentSession: () => currentV2Search,
10781
+ applySlice: applyV2Slice,
10782
+ onSettled: () => {
10783
+ replacePending.value = false;
10784
+ }
10785
+ });
10776
10786
  let result = null;
10777
10787
  try {
10778
10788
  result = search.replaceAll(replaceText.value);
@@ -13807,6 +13817,7 @@ var _hoisted_1$16 = {
13807
13817
  var _hoisted_2$13 = ["innerHTML"];
13808
13818
  var _hoisted_3$10 = { class: "superdoc__document document" };
13809
13819
  var _hoisted_4$7 = { class: "floating-comments" };
13820
+ var UNAVAILABLE_COMMAND_RESULT = false;
13810
13821
  var V2_SELECTION_TOOLBAR_SYNC_RETRY_FRAMES = 3;
13811
13822
  var V2_TYPING_REVIEW_HYDRATION_IDLE_MS = 6500;
13812
13823
  var V2_TYPING_REVIEW_HYDRATION_CEILING_MS = 8e3;
@@ -13927,19 +13938,19 @@ var _sfc_main$20 = {
13927
13938
  const v2GeometryEpoch = (0, vue.ref)(null);
13928
13939
  let v2GeometryRafHandle = 0;
13929
13940
  const activeEditorRef = (0, vue.computed)(() => proxy.$superdoc.activeEditor);
13930
- let linkPopoverUi = null;
13941
+ const getSuperDocUI = () => proxy.$superdoc?.ui ?? null;
13942
+ const UNAVAILABLE_COMMAND_STATE = Object.freeze({
13943
+ enabled: false,
13944
+ active: false,
13945
+ supported: false
13946
+ });
13931
13947
  const findReplace = useFindReplace({
13932
13948
  getSurfaceManager: () => surfaceManager,
13933
13949
  getActiveEditor: () => proxy.$superdoc?.activeEditor,
13934
13950
  activeEditorRef,
13935
13951
  getFindReplaceConfig: () => proxy.$superdoc?.config?.modules?.surfaces?.findReplace,
13936
- getSuperDocUI: () => getLinkPopoverUi()
13952
+ getSuperDocUI
13937
13953
  });
13938
- const getLinkPopoverUi = () => {
13939
- if (proxy.$superdoc?.toolbar?.ui) return proxy.$superdoc.toolbar.ui;
13940
- if (!linkPopoverUi && proxy.$superdoc) linkPopoverUi = require_create_super_doc_ui.createSuperDocUI({ superdoc: proxy.$superdoc });
13941
- return linkPopoverUi;
13942
- };
13943
13954
  const getLinkPopoverSurfaceManager = () => {
13944
13955
  if (surfaceManager) return surfaceManager;
13945
13956
  if (typeof proxy.$superdoc?.openSurface !== "function") return null;
@@ -13948,7 +13959,7 @@ var _sfc_main$20 = {
13948
13959
  const linkPopover = useLinkPopover({
13949
13960
  getSurfaceManager: getLinkPopoverSurfaceManager,
13950
13961
  getActiveEditor: () => proxy.$superdoc?.activeEditor,
13951
- getUi: getLinkPopoverUi,
13962
+ getUi: getSuperDocUI,
13952
13963
  getResolver: () => proxy.$superdoc?.config?.modules?.links?.popoverResolver,
13953
13964
  getLayerElement: () => layers.value,
13954
13965
  emitException: (payload) => {
@@ -14019,11 +14030,6 @@ var _sfc_main$20 = {
14019
14030
  } catch (err) {
14020
14031
  console.warn("[SuperDoc] v2 command-shortcut unbind failed", err);
14021
14032
  }
14022
- try {
14023
- entry.ui?.destroy?.();
14024
- } catch (err) {
14025
- console.warn("[SuperDoc] v2 command-shortcut UI teardown failed", err);
14026
- }
14027
14033
  };
14028
14034
  const resolveV2LinkWorkflowOpener = () => {
14029
14035
  const toolbar = proxy.$superdoc?.toolbar;
@@ -14039,20 +14045,19 @@ var _sfc_main$20 = {
14039
14045
  if (!documentId) return;
14040
14046
  clearV2CommandShortcutBinding(documentId);
14041
14047
  if (typeof bindEditShortcuts !== "function") return;
14042
- const fallbackUi = require_create_super_doc_ui.createSuperDocUI({ superdoc: proxy.$superdoc });
14043
- const resolveUi = () => proxy.$superdoc?.toolbar?.ui ?? fallbackUi;
14044
14048
  const openLinkWorkflow = resolveV2LinkWorkflowOpener();
14045
14049
  const unbind = bindEditShortcuts({
14046
14050
  commandRoute: {
14047
- executeAsync: (commandId, payload) => resolveUi().commands.executeAsync(commandId, payload),
14048
- getState: (commandId) => resolveUi().commands.get(commandId).getState()
14051
+ executeAsync: (commandId, payload) => {
14052
+ const ui = getSuperDocUI();
14053
+ if (!ui) return Promise.resolve(UNAVAILABLE_COMMAND_RESULT);
14054
+ return ui.commands.executeAsync(commandId, payload);
14055
+ },
14056
+ getState: (commandId) => getSuperDocUI()?.commands.get(commandId).getState() ?? UNAVAILABLE_COMMAND_STATE
14049
14057
  },
14050
14058
  ...openLinkWorkflow ? { openLinkWorkflow } : {}
14051
14059
  });
14052
- v2CommandShortcutBindings.set(documentId, {
14053
- unbind,
14054
- ui: fallbackUi
14055
- });
14060
+ v2CommandShortcutBindings.set(documentId, { unbind });
14056
14061
  };
14057
14062
  const clearV2SessionShortcutBinding = (documentId) => {
14058
14063
  const entry = v2SessionShortcutBindings.get(documentId);
@@ -15604,8 +15609,6 @@ var _sfc_main$20 = {
15604
15609
  passwordPrompt.destroy();
15605
15610
  findReplace.destroy();
15606
15611
  linkPopover.destroy();
15607
- linkPopoverUi?.destroy?.();
15608
- linkPopoverUi = null;
15609
15612
  cancelScheduledV2DomSelectionSync();
15610
15613
  cancelScheduledV2SelectionToolbarSync();
15611
15614
  for (const documentId of Array.from(v2Runtimes.keys())) clearV2RuntimeRegistration(documentId);
@@ -16122,7 +16125,7 @@ var _sfc_main$20 = {
16122
16125
  };
16123
16126
  }
16124
16127
  };
16125
- var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-91c4cd11"]]);
16128
+ var SuperDoc_default = /* @__PURE__ */ require__plugin_vue_export_helper.__plugin_vue_export_helper_default(_sfc_main$20, [["__scopeId", "data-v-41f40a40"]]);
16126
16129
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
16127
16130
  var PINIA_DEVTOOLS_PLUGIN_ID = "dev.esm.pinia";
16128
16131
  var piniaDevtoolsSuppressionState = {
@@ -32635,6 +32638,12 @@ var check_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448
32635
32638
  var closeDropdown = (dropdown) => {
32636
32639
  dropdown.expand.value = false;
32637
32640
  };
32641
+ function withLinkHref(attributes, href) {
32642
+ const next = { ...attributes ?? {} };
32643
+ if (href) next.href = href;
32644
+ else delete next.href;
32645
+ return next;
32646
+ }
32638
32647
  function selectionTargetFromTextTarget(target) {
32639
32648
  const segments = Array.isArray(target?.segments) ? target.segments : [];
32640
32649
  if (target?.kind !== "text" || !segments.length) return null;
@@ -32912,11 +32921,10 @@ const makeDefaultItems = ({ superToolbar, toolbarIcons: toolbarIcons$1, toolbarT
32912
32921
  render: () => renderLinkDropdown(link)
32913
32922
  }],
32914
32923
  onActivate: ({ href }) => {
32915
- if (href) link.attributes.value = { href };
32916
- else link.attributes.value = {};
32924
+ link.attributes.value = withLinkHref(link.attributes.value, href);
32917
32925
  },
32918
32926
  onDeactivate: () => {
32919
- link.attributes.value = {};
32927
+ link.attributes.value = withLinkHref(link.attributes.value, null);
32920
32928
  link.expand.value = false;
32921
32929
  }
32922
32930
  });
@@ -33930,24 +33938,31 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
33930
33938
  const uiFontFamily = (this.config?.uiDisplayFallbackFont || "").toString().trim() || "Arial, Helvetica, sans-serif";
33931
33939
  this.toolbarContainer.style.setProperty("--sd-ui-font-family", uiFontFamily);
33932
33940
  }
33933
- this.#initController();
33934
- this.#initToolbarGroups();
33935
- this.#makeToolbarItems();
33936
- this.#bindHostEvents();
33937
- this._lastFontOptionsSignature = this.#fontOptionsSignature();
33938
- if (!this.toolbarContainer) {
33941
+ try {
33942
+ this.#initController();
33943
+ this.#initToolbarGroups();
33944
+ this.#makeToolbarItems();
33945
+ this.#bindHostEvents();
33946
+ this._lastFontOptionsSignature = this.#fontOptionsSignature();
33947
+ if (!this.toolbarContainer) {
33948
+ this.updateToolbarState();
33949
+ return;
33950
+ }
33951
+ this.app = (0, vue.createApp)(Toolbar_default);
33952
+ this.app.directive("click-outside", v_click_outside_default);
33953
+ this.app.config.globalProperties.$toolbar = this;
33954
+ this.toolbar = this.app.mount(this.toolbarContainer);
33939
33955
  this.updateToolbarState();
33940
- return;
33956
+ } catch (error) {
33957
+ try {
33958
+ this.destroy();
33959
+ } catch {}
33960
+ throw error;
33941
33961
  }
33942
- this.app = (0, vue.createApp)(Toolbar_default);
33943
- this.app.directive("click-outside", v_click_outside_default);
33944
- this.app.config.globalProperties.$toolbar = this;
33945
- this.toolbar = this.app.mount(this.toolbarContainer);
33946
- this.updateToolbarState();
33947
33962
  }
33948
33963
  #initController() {
33949
- if (!this.superdoc) return;
33950
- this.ui = require_create_super_doc_ui.createSuperDocUI({ superdoc: this.superdoc });
33964
+ this.ui = this.superdoc?.ui ?? null;
33965
+ if (!this.ui) return;
33951
33966
  this.snapshot = this.ui.toolbar.getSnapshot();
33952
33967
  this._unsubscribeController = this.ui.toolbar.subscribe(() => {
33953
33968
  this.snapshot = this.ui.toolbar.getSnapshot();
@@ -33968,9 +33983,6 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
33968
33983
  reg.unregister?.();
33969
33984
  } catch {}
33970
33985
  this._customCommandRegs.clear();
33971
- try {
33972
- this.ui?.destroy?.();
33973
- } catch {}
33974
33986
  this.ui = null;
33975
33987
  this.snapshot = null;
33976
33988
  }
@@ -34195,7 +34207,7 @@ var BuiltInToolbar = class extends require_eventemitter3.import_eventemitter3.de
34195
34207
  },
34196
34208
  link: () => {
34197
34209
  item.active.value = Boolean(commandState?.active);
34198
- item.attributes.value = commandState?.value ? { href: commandState.value } : {};
34210
+ item.attributes.value = withLinkHref(item.attributes.value, commandState?.value ?? null);
34199
34211
  },
34200
34212
  fontFamily: () => {
34201
34213
  if (commandState?.value != null) {
@@ -34591,6 +34603,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
34591
34603
  #v2LockUnsub = null;
34592
34604
  #pendingV2LockSeed = null;
34593
34605
  #mountWrapper = null;
34606
+ #ui = null;
34594
34607
  #surfaceManager;
34595
34608
  #editorRuntimeRegistry = new EditorRuntimeRegistry();
34596
34609
  #editorRuntimeRegistryUnsub = null;
@@ -34697,7 +34710,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
34697
34710
  this.config.colors = shuffleArray(this.config.colors);
34698
34711
  this.userColorMap = /* @__PURE__ */ new Map();
34699
34712
  this.colorIndex = 0;
34700
- this.version = "2.0.0-next.45";
34713
+ this.version = "2.0.0-next.47";
34701
34714
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
34702
34715
  this.superdocId = config.superdocId || require_uuid.v4_default();
34703
34716
  this.colors = this.config.colors ?? [];
@@ -34749,6 +34762,13 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
34749
34762
  get requiredNumberOfEditors() {
34750
34763
  return this.#requireSuperdocStore("requiredNumberOfEditors").documents.filter((d) => d.type === DOCX).length;
34751
34764
  }
34765
+ get ui() {
34766
+ if (!this.#ui) {
34767
+ this.#ui = require_create_super_doc_ui.createSuperDocUI({ superdoc: this });
34768
+ if (this.#destroyed) this.#ui.destroy();
34769
+ }
34770
+ return this.#ui;
34771
+ }
34752
34772
  get state() {
34753
34773
  return {
34754
34774
  documents: this.#requireSuperdocStore("state").documents,
@@ -35456,10 +35476,12 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
35456
35476
  return this.#fontsApi;
35457
35477
  }
35458
35478
  #clearActiveEditorProjection() {
35479
+ const hadActiveEditor = this.activeEditor !== null;
35459
35480
  this.#teardownV2FontsRelay();
35460
35481
  this.activeEditor = null;
35461
35482
  if (this.toolbar?.setActiveEditor) this.toolbar.setActiveEditor(null);
35462
35483
  else if (this.toolbar) this.toolbar.activeEditor = null;
35484
+ if (hadActiveEditor) this.emit("active-editor-change");
35463
35485
  }
35464
35486
  #v2FontsUnsub = null;
35465
35487
  #teardownV2FontsRelay() {
@@ -35494,9 +35516,11 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
35494
35516
  #setActiveEditorCompatibilityProjection(editor) {
35495
35517
  if (isV2ActiveEditorFacade(editor)) {
35496
35518
  if (!this.#applyingRuntimeActiveChange && this.#editorRuntimeRegistry.getActive()) this.#editorRuntimeRegistry.setActive(null, "set-active-v2-facade");
35519
+ const previous = this.activeEditor;
35497
35520
  this.activeEditor = editor;
35498
35521
  this.#wireV2FontsRelay(editor);
35499
35522
  this.toolbar?.setActiveEditor?.(editor);
35523
+ if (previous !== this.activeEditor) this.emit("active-editor-change");
35500
35524
  return;
35501
35525
  }
35502
35526
  this.#clearActiveEditorProjection();
@@ -36215,6 +36239,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
36215
36239
  delete this.app.config.globalProperties.$config;
36216
36240
  delete this.app.config.globalProperties.$superdoc;
36217
36241
  }
36242
+ this.#ui?.destroy();
36218
36243
  this.#cleanupCollaboration();
36219
36244
  this.#editorRuntimeRegistryUnsub?.();
36220
36245
  this.#editorRuntimeRegistryUnsub = null;
@@ -5,7 +5,7 @@ import { t as v4_default } from "./chunks/uuid-B2Sqk-3p.es.js";
5
5
  import { a as init_dist, i as global, n as init_dist$1, r as process$1, t as require_jszip_min } from "./chunks/jszip-DzmwAHr3.es.js";
6
6
  import { t as __plugin_vue_export_helper_default } from "./chunks/_plugin-vue_export-helper-CInC0bKI.es.js";
7
7
  import { n as PDF_TO_CSS_UNITS } from "./chunks/constants-CY3R3_kF.es.js";
8
- import { a as createV2ReviewMutationReconciler, i as isV2EditableTextMutationEvent, o as getV2TrackedChangeMutationImpact, s as composeAuthorColorResolver, t as createSuperDocUI } from "./chunks/create-super-doc-ui-BTOlZen9.es.js";
8
+ import { a as createV2ReviewMutationReconciler, i as isV2EditableTextMutationEvent, o as getV2TrackedChangeMutationImpact, s as composeAuthorColorResolver, t as createSuperDocUI } from "./chunks/create-super-doc-ui-CKyCKKdl.es.js";
9
9
  import * as Vue from "vue";
10
10
  import { Fragment, Teleport, Transition, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineAsyncComponent, defineComponent, getCurrentInstance, h, inject, markRaw, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onActivated, onBeforeUnmount, onDeactivated, onMounted, openBlock, reactive, ref, renderList, renderSlot, resolveDirective, resolveDynamicComponent, shallowRef, toDisplayString, toRaw, toRef, unref, useAttrs, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
11
11
  import "y-websocket";
@@ -10532,6 +10532,14 @@ function usePasswordPrompt({ getSurfaceManager, getPasswordPromptConfig, onUnhan
10532
10532
  destroy
10533
10533
  };
10534
10534
  }
10535
+ function createReplaceContinuation(session, { getCurrentSession, applySlice, onSettled }) {
10536
+ return () => {
10537
+ if (session === getCurrentSession()) try {
10538
+ applySlice(session.getSnapshot());
10539
+ } catch {}
10540
+ onSettled();
10541
+ };
10542
+ }
10535
10543
  var DEFAULT_TEXTS = {
10536
10544
  findPlaceholder: "Find",
10537
10545
  findAriaLabel: "Find text",
@@ -10716,12 +10724,13 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
10716
10724
  if (!canReplaceState.value) return;
10717
10725
  const search = currentV2Search;
10718
10726
  replacePending.value = true;
10719
- const finish = () => {
10720
- try {
10721
- applyV2Slice(search.getSnapshot());
10722
- } catch {}
10723
- replacePending.value = false;
10724
- };
10727
+ const finish = createReplaceContinuation(search, {
10728
+ getCurrentSession: () => currentV2Search,
10729
+ applySlice: applyV2Slice,
10730
+ onSettled: () => {
10731
+ replacePending.value = false;
10732
+ }
10733
+ });
10725
10734
  let result = null;
10726
10735
  try {
10727
10736
  result = search.replace(replaceText.value);
@@ -10745,12 +10754,13 @@ function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, g
10745
10754
  if (!canReplaceState.value) return;
10746
10755
  const search = currentV2Search;
10747
10756
  replacePending.value = true;
10748
- const finish = () => {
10749
- try {
10750
- applyV2Slice(search.getSnapshot());
10751
- } catch {}
10752
- replacePending.value = false;
10753
- };
10757
+ const finish = createReplaceContinuation(search, {
10758
+ getCurrentSession: () => currentV2Search,
10759
+ applySlice: applyV2Slice,
10760
+ onSettled: () => {
10761
+ replacePending.value = false;
10762
+ }
10763
+ });
10754
10764
  let result = null;
10755
10765
  try {
10756
10766
  result = search.replaceAll(replaceText.value);
@@ -13768,6 +13778,7 @@ var _hoisted_1$16 = {
13768
13778
  var _hoisted_2$13 = ["innerHTML"];
13769
13779
  var _hoisted_3$10 = { class: "superdoc__document document" };
13770
13780
  var _hoisted_4$7 = { class: "floating-comments" };
13781
+ var UNAVAILABLE_COMMAND_RESULT = false;
13771
13782
  var V2_SELECTION_TOOLBAR_SYNC_RETRY_FRAMES = 3;
13772
13783
  var V2_TYPING_REVIEW_HYDRATION_IDLE_MS = 6500;
13773
13784
  var V2_TYPING_REVIEW_HYDRATION_CEILING_MS = 8e3;
@@ -13888,19 +13899,19 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
13888
13899
  const v2GeometryEpoch = ref(null);
13889
13900
  let v2GeometryRafHandle = 0;
13890
13901
  const activeEditorRef = computed(() => proxy.$superdoc.activeEditor);
13891
- let linkPopoverUi = null;
13902
+ const getSuperDocUI = () => proxy.$superdoc?.ui ?? null;
13903
+ const UNAVAILABLE_COMMAND_STATE = Object.freeze({
13904
+ enabled: false,
13905
+ active: false,
13906
+ supported: false
13907
+ });
13892
13908
  const findReplace = useFindReplace({
13893
13909
  getSurfaceManager: () => surfaceManager,
13894
13910
  getActiveEditor: () => proxy.$superdoc?.activeEditor,
13895
13911
  activeEditorRef,
13896
13912
  getFindReplaceConfig: () => proxy.$superdoc?.config?.modules?.surfaces?.findReplace,
13897
- getSuperDocUI: () => getLinkPopoverUi()
13913
+ getSuperDocUI
13898
13914
  });
13899
- const getLinkPopoverUi = () => {
13900
- if (proxy.$superdoc?.toolbar?.ui) return proxy.$superdoc.toolbar.ui;
13901
- if (!linkPopoverUi && proxy.$superdoc) linkPopoverUi = createSuperDocUI({ superdoc: proxy.$superdoc });
13902
- return linkPopoverUi;
13903
- };
13904
13915
  const getLinkPopoverSurfaceManager = () => {
13905
13916
  if (surfaceManager) return surfaceManager;
13906
13917
  if (typeof proxy.$superdoc?.openSurface !== "function") return null;
@@ -13909,7 +13920,7 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
13909
13920
  const linkPopover = useLinkPopover({
13910
13921
  getSurfaceManager: getLinkPopoverSurfaceManager,
13911
13922
  getActiveEditor: () => proxy.$superdoc?.activeEditor,
13912
- getUi: getLinkPopoverUi,
13923
+ getUi: getSuperDocUI,
13913
13924
  getResolver: () => proxy.$superdoc?.config?.modules?.links?.popoverResolver,
13914
13925
  getLayerElement: () => layers.value,
13915
13926
  emitException: (payload) => {
@@ -13980,11 +13991,6 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
13980
13991
  } catch (err) {
13981
13992
  console.warn("[SuperDoc] v2 command-shortcut unbind failed", err);
13982
13993
  }
13983
- try {
13984
- entry.ui?.destroy?.();
13985
- } catch (err) {
13986
- console.warn("[SuperDoc] v2 command-shortcut UI teardown failed", err);
13987
- }
13988
13994
  };
13989
13995
  const resolveV2LinkWorkflowOpener = () => {
13990
13996
  const toolbar = proxy.$superdoc?.toolbar;
@@ -14000,20 +14006,19 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
14000
14006
  if (!documentId) return;
14001
14007
  clearV2CommandShortcutBinding(documentId);
14002
14008
  if (typeof bindEditShortcuts !== "function") return;
14003
- const fallbackUi = createSuperDocUI({ superdoc: proxy.$superdoc });
14004
- const resolveUi = () => proxy.$superdoc?.toolbar?.ui ?? fallbackUi;
14005
14009
  const openLinkWorkflow = resolveV2LinkWorkflowOpener();
14006
14010
  const unbind = bindEditShortcuts({
14007
14011
  commandRoute: {
14008
- executeAsync: (commandId, payload) => resolveUi().commands.executeAsync(commandId, payload),
14009
- getState: (commandId) => resolveUi().commands.get(commandId).getState()
14012
+ executeAsync: (commandId, payload) => {
14013
+ const ui = getSuperDocUI();
14014
+ if (!ui) return Promise.resolve(UNAVAILABLE_COMMAND_RESULT);
14015
+ return ui.commands.executeAsync(commandId, payload);
14016
+ },
14017
+ getState: (commandId) => getSuperDocUI()?.commands.get(commandId).getState() ?? UNAVAILABLE_COMMAND_STATE
14010
14018
  },
14011
14019
  ...openLinkWorkflow ? { openLinkWorkflow } : {}
14012
14020
  });
14013
- v2CommandShortcutBindings.set(documentId, {
14014
- unbind,
14015
- ui: fallbackUi
14016
- });
14021
+ v2CommandShortcutBindings.set(documentId, { unbind });
14017
14022
  };
14018
14023
  const clearV2SessionShortcutBinding = (documentId) => {
14019
14024
  const entry = v2SessionShortcutBindings.get(documentId);
@@ -15565,8 +15570,6 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
15565
15570
  passwordPrompt.destroy();
15566
15571
  findReplace.destroy();
15567
15572
  linkPopover.destroy();
15568
- linkPopoverUi?.destroy?.();
15569
- linkPopoverUi = null;
15570
15573
  cancelScheduledV2DomSelectionSync();
15571
15574
  cancelScheduledV2SelectionToolbarSync();
15572
15575
  for (const documentId of Array.from(v2Runtimes.keys())) clearV2RuntimeRegistration(documentId);
@@ -16082,7 +16085,7 @@ var SuperDoc_default = /* @__PURE__ */ __plugin_vue_export_helper_default({
16082
16085
  ], 38);
16083
16086
  };
16084
16087
  }
16085
- }, [["__scopeId", "data-v-91c4cd11"]]);
16088
+ }, [["__scopeId", "data-v-41f40a40"]]);
16086
16089
  var PINIA_DEVTOOLS_SETUP_EVENT = "devtools-plugin:setup";
16087
16090
  var PINIA_DEVTOOLS_PLUGIN_ID = "dev.esm.pinia";
16088
16091
  var piniaDevtoolsSuppressionState = {
@@ -32572,6 +32575,12 @@ var check_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448
32572
32575
  var closeDropdown = (dropdown) => {
32573
32576
  dropdown.expand.value = false;
32574
32577
  };
32578
+ function withLinkHref(attributes, href) {
32579
+ const next = { ...attributes ?? {} };
32580
+ if (href) next.href = href;
32581
+ else delete next.href;
32582
+ return next;
32583
+ }
32575
32584
  function selectionTargetFromTextTarget(target) {
32576
32585
  const segments = Array.isArray(target?.segments) ? target.segments : [];
32577
32586
  if (target?.kind !== "text" || !segments.length) return null;
@@ -32849,11 +32858,10 @@ const makeDefaultItems = ({ superToolbar, toolbarIcons: toolbarIcons$1, toolbarT
32849
32858
  render: () => renderLinkDropdown(link)
32850
32859
  }],
32851
32860
  onActivate: ({ href }) => {
32852
- if (href) link.attributes.value = { href };
32853
- else link.attributes.value = {};
32861
+ link.attributes.value = withLinkHref(link.attributes.value, href);
32854
32862
  },
32855
32863
  onDeactivate: () => {
32856
- link.attributes.value = {};
32864
+ link.attributes.value = withLinkHref(link.attributes.value, null);
32857
32865
  link.expand.value = false;
32858
32866
  }
32859
32867
  });
@@ -33867,24 +33875,31 @@ var BuiltInToolbar = class extends import_eventemitter3.default {
33867
33875
  const uiFontFamily = (this.config?.uiDisplayFallbackFont || "").toString().trim() || "Arial, Helvetica, sans-serif";
33868
33876
  this.toolbarContainer.style.setProperty("--sd-ui-font-family", uiFontFamily);
33869
33877
  }
33870
- this.#initController();
33871
- this.#initToolbarGroups();
33872
- this.#makeToolbarItems();
33873
- this.#bindHostEvents();
33874
- this._lastFontOptionsSignature = this.#fontOptionsSignature();
33875
- if (!this.toolbarContainer) {
33878
+ try {
33879
+ this.#initController();
33880
+ this.#initToolbarGroups();
33881
+ this.#makeToolbarItems();
33882
+ this.#bindHostEvents();
33883
+ this._lastFontOptionsSignature = this.#fontOptionsSignature();
33884
+ if (!this.toolbarContainer) {
33885
+ this.updateToolbarState();
33886
+ return;
33887
+ }
33888
+ this.app = createApp(Toolbar_default);
33889
+ this.app.directive("click-outside", v_click_outside_default);
33890
+ this.app.config.globalProperties.$toolbar = this;
33891
+ this.toolbar = this.app.mount(this.toolbarContainer);
33876
33892
  this.updateToolbarState();
33877
- return;
33893
+ } catch (error) {
33894
+ try {
33895
+ this.destroy();
33896
+ } catch {}
33897
+ throw error;
33878
33898
  }
33879
- this.app = createApp(Toolbar_default);
33880
- this.app.directive("click-outside", v_click_outside_default);
33881
- this.app.config.globalProperties.$toolbar = this;
33882
- this.toolbar = this.app.mount(this.toolbarContainer);
33883
- this.updateToolbarState();
33884
33899
  }
33885
33900
  #initController() {
33886
- if (!this.superdoc) return;
33887
- this.ui = createSuperDocUI({ superdoc: this.superdoc });
33901
+ this.ui = this.superdoc?.ui ?? null;
33902
+ if (!this.ui) return;
33888
33903
  this.snapshot = this.ui.toolbar.getSnapshot();
33889
33904
  this._unsubscribeController = this.ui.toolbar.subscribe(() => {
33890
33905
  this.snapshot = this.ui.toolbar.getSnapshot();
@@ -33905,9 +33920,6 @@ var BuiltInToolbar = class extends import_eventemitter3.default {
33905
33920
  reg.unregister?.();
33906
33921
  } catch {}
33907
33922
  this._customCommandRegs.clear();
33908
- try {
33909
- this.ui?.destroy?.();
33910
- } catch {}
33911
33923
  this.ui = null;
33912
33924
  this.snapshot = null;
33913
33925
  }
@@ -34132,7 +34144,7 @@ var BuiltInToolbar = class extends import_eventemitter3.default {
34132
34144
  },
34133
34145
  link: () => {
34134
34146
  item.active.value = Boolean(commandState?.active);
34135
- item.attributes.value = commandState?.value ? { href: commandState.value } : {};
34147
+ item.attributes.value = withLinkHref(item.attributes.value, commandState?.value ?? null);
34136
34148
  },
34137
34149
  fontFamily: () => {
34138
34150
  if (commandState?.value != null) {
@@ -34528,6 +34540,7 @@ var SuperDoc = class extends import_eventemitter3.default {
34528
34540
  #v2LockUnsub = null;
34529
34541
  #pendingV2LockSeed = null;
34530
34542
  #mountWrapper = null;
34543
+ #ui = null;
34531
34544
  #surfaceManager;
34532
34545
  #editorRuntimeRegistry = new EditorRuntimeRegistry();
34533
34546
  #editorRuntimeRegistryUnsub = null;
@@ -34634,7 +34647,7 @@ var SuperDoc = class extends import_eventemitter3.default {
34634
34647
  this.config.colors = shuffleArray(this.config.colors);
34635
34648
  this.userColorMap = /* @__PURE__ */ new Map();
34636
34649
  this.colorIndex = 0;
34637
- this.version = "2.0.0-next.45";
34650
+ this.version = "2.0.0-next.47";
34638
34651
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
34639
34652
  this.superdocId = config.superdocId || v4_default();
34640
34653
  this.colors = this.config.colors ?? [];
@@ -34686,6 +34699,13 @@ var SuperDoc = class extends import_eventemitter3.default {
34686
34699
  get requiredNumberOfEditors() {
34687
34700
  return this.#requireSuperdocStore("requiredNumberOfEditors").documents.filter((d) => d.type === DOCX).length;
34688
34701
  }
34702
+ get ui() {
34703
+ if (!this.#ui) {
34704
+ this.#ui = createSuperDocUI({ superdoc: this });
34705
+ if (this.#destroyed) this.#ui.destroy();
34706
+ }
34707
+ return this.#ui;
34708
+ }
34689
34709
  get state() {
34690
34710
  return {
34691
34711
  documents: this.#requireSuperdocStore("state").documents,
@@ -35393,10 +35413,12 @@ var SuperDoc = class extends import_eventemitter3.default {
35393
35413
  return this.#fontsApi;
35394
35414
  }
35395
35415
  #clearActiveEditorProjection() {
35416
+ const hadActiveEditor = this.activeEditor !== null;
35396
35417
  this.#teardownV2FontsRelay();
35397
35418
  this.activeEditor = null;
35398
35419
  if (this.toolbar?.setActiveEditor) this.toolbar.setActiveEditor(null);
35399
35420
  else if (this.toolbar) this.toolbar.activeEditor = null;
35421
+ if (hadActiveEditor) this.emit("active-editor-change");
35400
35422
  }
35401
35423
  #v2FontsUnsub = null;
35402
35424
  #teardownV2FontsRelay() {
@@ -35431,9 +35453,11 @@ var SuperDoc = class extends import_eventemitter3.default {
35431
35453
  #setActiveEditorCompatibilityProjection(editor) {
35432
35454
  if (isV2ActiveEditorFacade(editor)) {
35433
35455
  if (!this.#applyingRuntimeActiveChange && this.#editorRuntimeRegistry.getActive()) this.#editorRuntimeRegistry.setActive(null, "set-active-v2-facade");
35456
+ const previous = this.activeEditor;
35434
35457
  this.activeEditor = editor;
35435
35458
  this.#wireV2FontsRelay(editor);
35436
35459
  this.toolbar?.setActiveEditor?.(editor);
35460
+ if (previous !== this.activeEditor) this.emit("active-editor-change");
35437
35461
  return;
35438
35462
  }
35439
35463
  this.#clearActiveEditorProjection();
@@ -36152,6 +36176,7 @@ var SuperDoc = class extends import_eventemitter3.default {
36152
36176
  delete this.app.config.globalProperties.$config;
36153
36177
  delete this.app.config.globalProperties.$superdoc;
36154
36178
  }
36179
+ this.#ui?.destroy();
36155
36180
  this.#cleanupCollaboration();
36156
36181
  this.#editorRuntimeRegistryUnsub?.();
36157
36182
  this.#editorRuntimeRegistryUnsub = null;