superdoc 2.0.0-next.45 → 2.0.0-next.46

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 (34) hide show
  1. package/AGENTS.md +15 -8
  2. package/dist/chunks/{create-super-doc-ui-DDxbK_M7.cjs → create-super-doc-ui-6FUZ9d-y.cjs} +201 -122
  3. package/dist/chunks/{create-super-doc-ui-BTOlZen9.es.js → create-super-doc-ui-DCFTmVRK.es.js} +202 -123
  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/use-find-replace.d.ts +2 -2
  18. package/dist/superdoc/src/core/SuperDoc.d.ts +41 -0
  19. package/dist/superdoc/src/core/types/index.d.ts +2 -14
  20. package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +5 -5
  21. package/dist/superdoc/src/public/browser-document-api.d.ts +53 -0
  22. package/dist/superdoc/src/public/index.d.cts +4 -0
  23. package/dist/superdoc/src/public/index.d.ts +2 -0
  24. package/dist/superdoc/src/public/ui/react.d.ts +18 -7
  25. package/dist/superdoc/src/public/ui/types.d.ts +81 -12
  26. package/dist/superdoc/src/public/ui-react.d.ts +4 -3
  27. package/dist/superdoc/src/public/ui.d.cts +8 -0
  28. package/dist/superdoc/src/public/ui.d.ts +1 -1
  29. package/dist/superdoc.cjs +53 -43
  30. package/dist/superdoc.es.js +53 -43
  31. package/dist-cdn/style.layered.css +1 -1
  32. package/dist-cdn/superdoc.min.css +1 -1
  33. package/dist-cdn/superdoc.min.js +35 -35
  34. package/package.json +1 -1
package/AGENTS.md CHANGED
@@ -179,7 +179,14 @@ For building your own browser UI (toolbars, selection popovers, comment panels,
179
179
  citation cards) around a live SuperDoc editor, use the v2-native public custom-UI
180
180
  entrypoints. They are the supported subpath exports for custom UI:
181
181
 
182
- - `superdoc/ui` — framework-agnostic controller: `createSuperDocUI({ superdoc })`.
182
+ - `superdoc.ui` — the framework-agnostic controller every instance owns. Read it;
183
+ do not build one. `superdoc.destroy()` tears it down. The property is typed
184
+ `BorrowedSuperDocUI`, which omits `destroy()`, so you cannot tear down state
185
+ the built-in toolbar and other consumers of that instance are still reading.
186
+ Only a controller you created yourself is yours to destroy.
187
+ - `superdoc/ui` — the controller's types, plus `createSuperDocUI({ superdoc })`
188
+ for the rare case you want a **second, independently owned** controller that
189
+ you create and destroy yourself.
183
190
  - `superdoc/ui/react` — React bindings: `SuperDocUIProvider`, `useSetSuperDoc`,
184
191
  `useSuperDocUI`, `useSuperDocHost`, and slice hooks.
185
192
 
@@ -207,14 +214,14 @@ painted output or reach into editor internals for coordinates.
207
214
  **Supported / unsupported.**
208
215
 
209
216
  - There is **no public headless path.** Backend / external Document API access uses
210
- the SDK (`@superdoc-dev/sdk`) — see *Document Engine* above. Browser custom UI uses
211
- `superdoc/ui`.
217
+ the SDK (`@superdoc-dev/sdk`) — see *Document Engine* above. Browser custom UI
218
+ reads `superdoc.ui`, typed by `superdoc/ui`.
212
219
  - **Migrating from v1 `superdoc/headless-toolbar*`?** Those package subpaths are
213
220
  intentionally removed in v2 (migration-only posture). Move v1 custom toolbar /
214
- headless-toolbar code to `superdoc/ui` (`createSuperDocUI`) and
215
- `superdoc/ui/react`. Unsupported or not-yet-migrated commands stay visible in
216
- the toolbar snapshot as disabled with a stable `reason` (the `SuperDocUIReason`
217
- taxonomy on `CommandState`) instead of silently disappearing.
221
+ headless-toolbar code to `superdoc.ui` and `superdoc/ui/react`. Unsupported or
222
+ not-yet-migrated commands stay visible in the toolbar snapshot as disabled with
223
+ a stable `reason` (the `SuperDocUIReason` taxonomy on `CommandState`) instead
224
+ of silently disappearing.
218
225
  - The SuperDoc shell may import only the supported `@superdoc/docx-engine`
219
226
  package entries. Do **not** import internal implementation packages such as
220
227
  `@superdoc/v2-host`, `@superdoc/document-api-v2-adapter`, or
@@ -241,7 +248,7 @@ painted output or reach into editor internals for coordinates.
241
248
  | Format text (programmatic) | Use Document API: `editor.doc.format.bold(...)`, `.italic(...)`, etc. |
242
249
  | Real-time collab | Configure `modules.collaboration` with a Yjs provider |
243
250
  | Custom built-in toolbar | Use `modules.toolbar.customButtons` array |
244
- | Build your own UI | Use `superdoc/ui` / `superdoc/ui/react` (`createSuperDocUI`) — see *Custom UI* above |
251
+ | Build your own UI | Read `superdoc.ui`, or use `superdoc/ui/react` — see *Custom UI* above |
245
252
  | Anchor citations to inserted text | Read the Document API receipt's `effects.insertedText[]` |
246
253
  | Listen to events | `superdoc.on('ready', ({ superdoc }) => { ... })` |
247
254
 
@@ -539,118 +539,6 @@ const isV2EditableTextMutationEvent = (event) => {
539
539
  if (event?.type !== "mutation:committed" || event.origin !== "command") return false;
540
540
  return V2_TYPING_COMMAND_KINDS.has(event.editableCommandKind);
541
541
  };
542
- function shallowEqual(a, b) {
543
- if (Object.is(a, b)) return true;
544
- if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
545
- if (Array.isArray(a) !== Array.isArray(b)) return false;
546
- const aKeys = Object.keys(a);
547
- const bKeys = Object.keys(b);
548
- if (aKeys.length !== bKeys.length) return false;
549
- for (const key of aKeys) {
550
- if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
551
- if (!Object.is(a[key], b[key])) return false;
552
- }
553
- return true;
554
- }
555
- function sdRunPropsToInlineRunPatch(props) {
556
- if (!props || typeof props !== "object") return {};
557
- const patch = {};
558
- if (props.fonts) patch.rFonts = {
559
- ascii: props.fonts.ascii,
560
- hAnsi: props.fonts.hAnsi,
561
- eastAsia: props.fonts.eastAsia,
562
- cs: props.fonts.cs,
563
- asciiTheme: props.fonts.asciiTheme,
564
- hAnsiTheme: props.fonts.hAnsiTheme,
565
- eastAsiaTheme: props.fonts.eastAsiaTheme,
566
- csTheme: props.fonts.csTheme,
567
- hint: props.fonts.hint
568
- };
569
- if (props.fontFamily != null) patch.fontFamily = props.fontFamily;
570
- if (props.lang) patch.lang = {
571
- val: props.lang.val,
572
- eastAsia: props.lang.eastAsia,
573
- bidi: props.lang.bidi
574
- };
575
- if (props.fontSize != null) patch.fontSize = props.fontSize;
576
- if (props.fontSizeCs != null) patch.fontSizeCs = props.fontSizeCs;
577
- const color = projectColorRefToInlineColor(props.color);
578
- if (color != null) patch.color = color;
579
- if (props.highlight != null) patch.highlight = props.highlight;
580
- const shading = projectShadingToInlinePatch(props.shading);
581
- if (shading) patch.shading = shading;
582
- if (props.cs != null) patch.cs = props.cs;
583
- if (props.rtl != null) patch.rtl = props.rtl;
584
- if (props.bold != null) patch.bold = props.bold;
585
- if (props.boldCs != null) patch.bCs = props.boldCs;
586
- if (props.italic != null) patch.italic = props.italic;
587
- if (props.italicCs != null) patch.iCs = props.italicCs;
588
- const underline = projectUnderlineToInlinePatch(props.underline);
589
- if (underline !== void 0) patch.underline = underline;
590
- if (props.strikethrough != null) patch.strike = props.strikethrough;
591
- if (props.doubleStrikethrough != null) patch.dstrike = props.doubleStrikethrough;
592
- if (props.caps != null) patch.caps = props.caps;
593
- if (props.smallCaps != null) patch.smallCaps = props.smallCaps;
594
- if (props.outline != null) patch.outline = props.outline;
595
- if (props.shadow != null) patch.shadow = props.shadow;
596
- if (props.emboss != null) patch.emboss = props.emboss;
597
- if (props.imprint != null) patch.imprint = props.imprint;
598
- if (props.verticalAlign != null) patch.vertAlign = props.verticalAlign;
599
- if (props.characterSpacing != null) patch.letterSpacing = props.characterSpacing;
600
- if (props.characterScale != null) patch.charScale = props.characterScale;
601
- if (props.kern != null) patch.kerning = props.kern;
602
- if (props.baselineShift != null) patch.position = props.baselineShift;
603
- if (props.fitTextWidth != null) patch.fitText = { val: props.fitTextWidth };
604
- if (props.vanish != null) patch.vanish = props.vanish;
605
- if (props.webHidden != null) patch.webHidden = props.webHidden;
606
- if (props.specVanish != null) patch.specVanish = props.specVanish;
607
- const border = projectBorderToInlinePatch(props.border);
608
- if (border) patch.border = border;
609
- return patch;
610
- }
611
- function projectColorRefToInlineColor(color) {
612
- if (!color) return void 0;
613
- if (typeof color === "string") return color;
614
- if (color.model === "rgb") return color.value;
615
- if (color.model === "auto") return "auto";
616
- }
617
- function projectUnderlineToInlinePatch(underline) {
618
- if (underline == null) return void 0;
619
- const patch = {};
620
- if (underline.style != null) patch.style = underline.style;
621
- if (underline.color?.model === "rgb") patch.color = underline.color.value;
622
- if (underline.color?.model === "theme") patch.themeColor = underline.color.theme;
623
- return Object.keys(patch).length > 0 ? patch : true;
624
- }
625
- function projectShadingToInlinePatch(shading) {
626
- if (!shading) return void 0;
627
- const patch = {};
628
- const fill = projectColorRefToInlineColor(shading.fill);
629
- if (fill != null) patch.fill = fill;
630
- const color = projectColorRefToInlineColor(shading.color);
631
- if (color != null) patch.color = color;
632
- if (shading.pattern != null) patch.val = shading.pattern;
633
- return Object.keys(patch).length > 0 ? patch : void 0;
634
- }
635
- function projectBorderToInlinePatch(border) {
636
- if (!border) return void 0;
637
- const patch = {};
638
- if (border.style != null) patch.val = border.style;
639
- if (border.width != null) patch.sz = border.width;
640
- if (border.space != null) patch.space = border.space;
641
- const color = projectColorRefToInlineColor(border.color);
642
- if (color != null) patch.color = color;
643
- return Object.keys(patch).length > 0 ? patch : void 0;
644
- }
645
- function selectionKey(selection) {
646
- const target = selection?.selectionTarget ?? selection?.target;
647
- if (!selection || !target) return "";
648
- try {
649
- return JSON.stringify(target);
650
- } catch {
651
- return String(target);
652
- }
653
- }
654
542
  const SUPERDOC_UI_REASONS = {
655
543
  notReady: "not-ready",
656
544
  documentApiUnavailable: "document-api-unavailable",
@@ -1313,6 +1201,118 @@ const ALL_BUILT_IN_COMMAND_IDS = COMMAND_CATALOG.map((d) => d.id);
1313
1201
  function getCommandDescriptor(id) {
1314
1202
  return CATALOG_BY_ID.get(id) ?? null;
1315
1203
  }
1204
+ function shallowEqual(a, b) {
1205
+ if (Object.is(a, b)) return true;
1206
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
1207
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
1208
+ const aKeys = Object.keys(a);
1209
+ const bKeys = Object.keys(b);
1210
+ if (aKeys.length !== bKeys.length) return false;
1211
+ for (const key of aKeys) {
1212
+ if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
1213
+ if (!Object.is(a[key], b[key])) return false;
1214
+ }
1215
+ return true;
1216
+ }
1217
+ function sdRunPropsToInlineRunPatch(props) {
1218
+ if (!props || typeof props !== "object") return {};
1219
+ const patch = {};
1220
+ if (props.fonts) patch.rFonts = {
1221
+ ascii: props.fonts.ascii,
1222
+ hAnsi: props.fonts.hAnsi,
1223
+ eastAsia: props.fonts.eastAsia,
1224
+ cs: props.fonts.cs,
1225
+ asciiTheme: props.fonts.asciiTheme,
1226
+ hAnsiTheme: props.fonts.hAnsiTheme,
1227
+ eastAsiaTheme: props.fonts.eastAsiaTheme,
1228
+ csTheme: props.fonts.csTheme,
1229
+ hint: props.fonts.hint
1230
+ };
1231
+ if (props.fontFamily != null) patch.fontFamily = props.fontFamily;
1232
+ if (props.lang) patch.lang = {
1233
+ val: props.lang.val,
1234
+ eastAsia: props.lang.eastAsia,
1235
+ bidi: props.lang.bidi
1236
+ };
1237
+ if (props.fontSize != null) patch.fontSize = props.fontSize;
1238
+ if (props.fontSizeCs != null) patch.fontSizeCs = props.fontSizeCs;
1239
+ const color = projectColorRefToInlineColor(props.color);
1240
+ if (color != null) patch.color = color;
1241
+ if (props.highlight != null) patch.highlight = props.highlight;
1242
+ const shading = projectShadingToInlinePatch(props.shading);
1243
+ if (shading) patch.shading = shading;
1244
+ if (props.cs != null) patch.cs = props.cs;
1245
+ if (props.rtl != null) patch.rtl = props.rtl;
1246
+ if (props.bold != null) patch.bold = props.bold;
1247
+ if (props.boldCs != null) patch.bCs = props.boldCs;
1248
+ if (props.italic != null) patch.italic = props.italic;
1249
+ if (props.italicCs != null) patch.iCs = props.italicCs;
1250
+ const underline = projectUnderlineToInlinePatch(props.underline);
1251
+ if (underline !== void 0) patch.underline = underline;
1252
+ if (props.strikethrough != null) patch.strike = props.strikethrough;
1253
+ if (props.doubleStrikethrough != null) patch.dstrike = props.doubleStrikethrough;
1254
+ if (props.caps != null) patch.caps = props.caps;
1255
+ if (props.smallCaps != null) patch.smallCaps = props.smallCaps;
1256
+ if (props.outline != null) patch.outline = props.outline;
1257
+ if (props.shadow != null) patch.shadow = props.shadow;
1258
+ if (props.emboss != null) patch.emboss = props.emboss;
1259
+ if (props.imprint != null) patch.imprint = props.imprint;
1260
+ if (props.verticalAlign != null) patch.vertAlign = props.verticalAlign;
1261
+ if (props.characterSpacing != null) patch.letterSpacing = props.characterSpacing;
1262
+ if (props.characterScale != null) patch.charScale = props.characterScale;
1263
+ if (props.kern != null) patch.kerning = props.kern;
1264
+ if (props.baselineShift != null) patch.position = props.baselineShift;
1265
+ if (props.fitTextWidth != null) patch.fitText = { val: props.fitTextWidth };
1266
+ if (props.vanish != null) patch.vanish = props.vanish;
1267
+ if (props.webHidden != null) patch.webHidden = props.webHidden;
1268
+ if (props.specVanish != null) patch.specVanish = props.specVanish;
1269
+ const border = projectBorderToInlinePatch(props.border);
1270
+ if (border) patch.border = border;
1271
+ return patch;
1272
+ }
1273
+ function projectColorRefToInlineColor(color) {
1274
+ if (!color) return void 0;
1275
+ if (typeof color === "string") return color;
1276
+ if (color.model === "rgb") return color.value;
1277
+ if (color.model === "auto") return "auto";
1278
+ }
1279
+ function projectUnderlineToInlinePatch(underline) {
1280
+ if (underline == null) return void 0;
1281
+ const patch = {};
1282
+ if (underline.style != null) patch.style = underline.style;
1283
+ if (underline.color?.model === "rgb") patch.color = underline.color.value;
1284
+ if (underline.color?.model === "theme") patch.themeColor = underline.color.theme;
1285
+ return Object.keys(patch).length > 0 ? patch : true;
1286
+ }
1287
+ function projectShadingToInlinePatch(shading) {
1288
+ if (!shading) return void 0;
1289
+ const patch = {};
1290
+ const fill = projectColorRefToInlineColor(shading.fill);
1291
+ if (fill != null) patch.fill = fill;
1292
+ const color = projectColorRefToInlineColor(shading.color);
1293
+ if (color != null) patch.color = color;
1294
+ if (shading.pattern != null) patch.val = shading.pattern;
1295
+ return Object.keys(patch).length > 0 ? patch : void 0;
1296
+ }
1297
+ function projectBorderToInlinePatch(border) {
1298
+ if (!border) return void 0;
1299
+ const patch = {};
1300
+ if (border.style != null) patch.val = border.style;
1301
+ if (border.width != null) patch.sz = border.width;
1302
+ if (border.space != null) patch.space = border.space;
1303
+ const color = projectColorRefToInlineColor(border.color);
1304
+ if (color != null) patch.color = color;
1305
+ return Object.keys(patch).length > 0 ? patch : void 0;
1306
+ }
1307
+ function selectionKey(selection) {
1308
+ const target = selection?.selectionTarget ?? selection?.target;
1309
+ if (!selection || !target) return "";
1310
+ try {
1311
+ return JSON.stringify(target);
1312
+ } catch {
1313
+ return String(target);
1314
+ }
1315
+ }
1316
1316
  function parseCommaSeparatedIds(value) {
1317
1317
  return value.split(",").map((id) => id.trim()).filter(Boolean);
1318
1318
  }
@@ -1725,6 +1725,7 @@ function normalizeHostSelectionApplyResult(result) {
1725
1725
  }
1726
1726
  var HOST_EVENTS = [
1727
1727
  "editorCreate",
1728
+ "active-editor-change",
1728
1729
  "document-mode-change",
1729
1730
  "zoomChange",
1730
1731
  "measurement-unit-change",
@@ -5950,11 +5951,20 @@ function createSuperDocUI(options) {
5950
5951
  state = nextState;
5951
5952
  for (const listener of [...listeners]) listener(state);
5952
5953
  };
5954
+ const activeEditorResetHooks = [];
5955
+ const runActiveEditorResetHooks = () => {
5956
+ for (const reset of activeEditorResetHooks) try {
5957
+ reset();
5958
+ } catch {}
5959
+ };
5953
5960
  const detachers = [];
5954
5961
  const attach = (source, events) => {
5955
5962
  if (!source || typeof source.on !== "function") return;
5956
5963
  for (const event of events) {
5957
- const handler = () => recompute();
5964
+ const handler = event === "active-editor-change" ? () => {
5965
+ runActiveEditorResetHooks();
5966
+ recompute();
5967
+ } : () => recompute();
5958
5968
  try {
5959
5969
  source.on(event, handler);
5960
5970
  detachers.push(() => {
@@ -8258,6 +8268,28 @@ function createSuperDocUI(options) {
8258
8268
  if (typeof xOrInput === "object") return pointEntityHits(xOrInput?.x, xOrInput?.y);
8259
8269
  return null;
8260
8270
  }
8271
+ const geometryObservers = /* @__PURE__ */ new Set();
8272
+ const bindGeometryObserver = (entry) => {
8273
+ const host = getHost();
8274
+ if (typeof host?.observeGeometry !== "function") return;
8275
+ const off = safeCall(() => host.observeGeometry(() => entry.schedule()), null);
8276
+ entry.detach = typeof off === "function" ? off : null;
8277
+ };
8278
+ const detachGeometryObserver = (entry) => {
8279
+ if (!entry.detach) return;
8280
+ try {
8281
+ entry.detach();
8282
+ } catch {}
8283
+ entry.detach = null;
8284
+ };
8285
+ const rebindGeometryObservers = () => {
8286
+ for (const entry of geometryObservers) {
8287
+ detachGeometryObserver(entry);
8288
+ bindGeometryObserver(entry);
8289
+ entry.schedule();
8290
+ }
8291
+ };
8292
+ activeEditorResetHooks.push(rebindGeometryObservers);
8261
8293
  const viewport = {
8262
8294
  getRect: (input) => {
8263
8295
  const host = getHost();
@@ -8293,12 +8325,15 @@ function createSuperDocUI(options) {
8293
8325
  zoom: s.zoom
8294
8326
  }));
8295
8327
  unsubs.push(sub.subscribe(() => schedule()));
8296
- const host = getHost();
8297
- if (typeof host?.observeGeometry === "function") {
8298
- const off = safeCall(() => host.observeGeometry(() => schedule()), null);
8299
- if (typeof off === "function") unsubs.push(off);
8300
- }
8328
+ const entry = {
8329
+ schedule,
8330
+ detach: null
8331
+ };
8332
+ bindGeometryObserver(entry);
8333
+ geometryObservers.add(entry);
8301
8334
  return () => {
8335
+ geometryObservers.delete(entry);
8336
+ detachGeometryObserver(entry);
8302
8337
  if (frame && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
8303
8338
  for (const unsub of unsubs.splice(0)) try {
8304
8339
  unsub();
@@ -8472,6 +8507,28 @@ function createSuperDocUI(options) {
8472
8507
  return searchState;
8473
8508
  };
8474
8509
  let searchRequestGeneration = 0;
8510
+ let releaseActiveSearchSession = null;
8511
+ const releaseSearchSession = () => {
8512
+ const release = releaseActiveSearchSession;
8513
+ releaseActiveSearchSession = null;
8514
+ if (!release) return;
8515
+ safeCall(() => {
8516
+ release();
8517
+ return null;
8518
+ }, null);
8519
+ };
8520
+ const resetSearchForActiveEditorChange = () => {
8521
+ searchRequestGeneration += 1;
8522
+ releaseSearchSession();
8523
+ const available = searchIsAvailable();
8524
+ searchState = {
8525
+ ...SEARCH_UNAVAILABLE_SLICE,
8526
+ available,
8527
+ reason: available ? void 0 : SUPERDOC_UI_REASONS.searchUnavailable
8528
+ };
8529
+ emitSearch();
8530
+ };
8531
+ activeEditorResetHooks.push(resetSearchForActiveEditorChange);
8475
8532
  const readSearchQueryError = (record) => {
8476
8533
  if (!record) return false;
8477
8534
  const queryError = record.queryError;
@@ -8623,11 +8680,14 @@ function createSuperDocUI(options) {
8623
8680
  },
8624
8681
  close: () => {
8625
8682
  searchRequestGeneration += 1;
8626
- const host = getHostSearch();
8627
- if (host && typeof host.clear === "function") safeCall(() => host.clear(), null);
8683
+ if (releaseActiveSearchSession) releaseSearchSession();
8628
8684
  else {
8629
- const editSearch = getEditCommandSearch();
8630
- if (editSearch && typeof editSearch.query === "function") safeCall(() => editSearch.query({ query: "" }), null);
8685
+ const host = getHostSearch();
8686
+ if (host && typeof host.clear === "function") safeCall(() => host.clear(), null);
8687
+ else {
8688
+ const editSearch = getEditCommandSearch();
8689
+ if (editSearch && typeof editSearch.query === "function") safeCall(() => editSearch.query({ query: "" }), null);
8690
+ }
8631
8691
  }
8632
8692
  searchState = {
8633
8693
  ...SEARCH_UNAVAILABLE_SLICE,
@@ -8655,6 +8715,9 @@ function createSuperDocUI(options) {
8655
8715
  open: true,
8656
8716
  reason: void 0
8657
8717
  });
8718
+ releaseActiveSearchSession = () => {
8719
+ editSearch.query({ query: "" });
8720
+ };
8658
8721
  const result = safeCall(() => editSearch.query({
8659
8722
  query,
8660
8723
  caseSensitive,
@@ -8695,6 +8758,9 @@ function createSuperDocUI(options) {
8695
8758
  open: true,
8696
8759
  reason: void 0
8697
8760
  });
8761
+ releaseActiveSearchSession = () => {
8762
+ if (typeof host.clear === "function") host.clear();
8763
+ };
8698
8764
  applyHostSearchResult(safeCall(() => host.setSession(query, {
8699
8765
  caseSensitive,
8700
8766
  includeDeletedText,
@@ -8704,6 +8770,11 @@ function createSuperDocUI(options) {
8704
8770
  if (query.length > 0 && searchState.total === 0 && searchState.reason !== SUPERDOC_UI_REASONS.searchInvalidPattern) {
8705
8771
  const editSearch = getEditCommandSearch();
8706
8772
  if (editSearch && typeof editSearch.query === "function" && typeof editSearch.getState === "function") {
8773
+ const releaseHostSession = releaseActiveSearchSession;
8774
+ releaseActiveSearchSession = () => {
8775
+ releaseHostSession?.();
8776
+ editSearch.query({ query: "" });
8777
+ };
8707
8778
  const commandResult = safeCall(() => editSearch.query({
8708
8779
  query,
8709
8780
  caseSensitive,
@@ -8968,6 +9039,8 @@ function createSuperDocUI(options) {
8968
9039
  currentDocumentSelectionSource = null;
8969
9040
  listeners.clear();
8970
9041
  searchListeners.clear();
9042
+ painterCaptureEpoch += 1;
9043
+ painterModeListeners.clear();
8971
9044
  customCommands.clear();
8972
9045
  };
8973
9046
  const controller = {
@@ -8991,12 +9064,14 @@ function createSuperDocUI(options) {
8991
9064
  styles,
8992
9065
  formatPainter: {
8993
9066
  setPointerSelecting(flag) {
9067
+ if (disposed) return;
8994
9068
  painter = {
8995
9069
  ...painter,
8996
9070
  pointerSelecting: flag
8997
9071
  };
8998
9072
  },
8999
9073
  notifyPointerUp() {
9074
+ if (disposed) return;
9000
9075
  painter = {
9001
9076
  ...painter,
9002
9077
  pointerSelecting: false
@@ -9004,12 +9079,14 @@ function createSuperDocUI(options) {
9004
9079
  maybeApply();
9005
9080
  },
9006
9081
  setKeyboardSelecting(flag) {
9082
+ if (disposed) return;
9007
9083
  painter = {
9008
9084
  ...painter,
9009
9085
  keyboardSelecting: flag
9010
9086
  };
9011
9087
  },
9012
9088
  notifyKeyUp() {
9089
+ if (disposed) return;
9013
9090
  painter = {
9014
9091
  ...painter,
9015
9092
  keyboardSelecting: false
@@ -9017,9 +9094,11 @@ function createSuperDocUI(options) {
9017
9094
  maybeApply();
9018
9095
  },
9019
9096
  cancel() {
9097
+ if (disposed) return;
9020
9098
  exitFormatPainter();
9021
9099
  },
9022
9100
  onModeChange(cb) {
9101
+ if (disposed) return () => {};
9023
9102
  painterModeListeners.add(cb);
9024
9103
  return () => painterModeListeners.delete(cb);
9025
9104
  }