superdoc 2.0.0-next.44 → 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-DYky1UEo.cjs → create-super-doc-ui-6FUZ9d-y.cjs} +204 -159
  3. package/dist/chunks/{create-super-doc-ui-BFz0iim0.es.js → create-super-doc-ui-DCFTmVRK.es.js} +205 -160
  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 +28 -28
  13. package/dist/style.layered.css +28 -28
  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 +76 -30
  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 +85 -141
  30. package/dist/superdoc.es.js +85 -141
  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 +36 -36
  34. package/package.json +2 -2
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
  }
@@ -1703,12 +1703,6 @@ const INLINE_PROPERTY_KEYS_BY_STORAGE = {
1703
1703
  mark: INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "mark").map((entry) => entry.key),
1704
1704
  runAttribute: INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "runAttribute").map((entry) => entry.key)
1705
1705
  };
1706
- var POST_DECISION_TRACKED_CHANGES_LIST_OPTIONS = Object.freeze({
1707
- mode: "background-reconcile",
1708
- refreshReason: "post-decision-background",
1709
- blocking: false
1710
- });
1711
- var POST_DECISION_TRACKED_CHANGES_RECONCILE_DELAY_MS = 3e3;
1712
1706
  var SUPERDOC_UI_REASON_VALUES = new Set(Object.values(SUPERDOC_UI_REASONS));
1713
1707
  function coerceSuperDocUIReason(reason, fallback) {
1714
1708
  return typeof reason === "string" && SUPERDOC_UI_REASON_VALUES.has(reason) ? reason : fallback;
@@ -1731,6 +1725,7 @@ function normalizeHostSelectionApplyResult(result) {
1731
1725
  }
1732
1726
  var HOST_EVENTS = [
1733
1727
  "editorCreate",
1728
+ "active-editor-change",
1734
1729
  "document-mode-change",
1735
1730
  "zoomChange",
1736
1731
  "measurement-unit-change",
@@ -3133,7 +3128,6 @@ function createSuperDocUI(options) {
3133
3128
  let foregroundAsyncRetryTimer = null;
3134
3129
  let pendingSelectionSeedValidationToken = null;
3135
3130
  let typingContentInvalidationTimer = null;
3136
- let postDecisionTrackChangesReconcileTimer = null;
3137
3131
  const scheduleAsyncRefresh = () => {
3138
3132
  if (asyncRefreshScheduled || disposed) return;
3139
3133
  asyncRefreshScheduled = true;
@@ -3180,14 +3174,12 @@ function createSuperDocUI(options) {
3180
3174
  };
3181
3175
  let scheduleAuthoritativeTrackChangesRetry = (_reconcileToken) => void 0;
3182
3176
  let postDecisionTrackChangesToken = null;
3183
- let postDecisionTrackChangesReconcileToken = null;
3184
3177
  let postDecisionTrackChangeIds = /* @__PURE__ */ new Set();
3185
3178
  let selectionEpoch = 0;
3186
3179
  let lastCoordinatorEditor = null;
3187
3180
  const contentToken = () => `${editorIdentityId(getEditor())}|m${documentMutationRevision}`;
3188
3181
  const clearPostDecisionTrackChanges = () => {
3189
3182
  postDecisionTrackChangesToken = null;
3190
- postDecisionTrackChangesReconcileToken = null;
3191
3183
  postDecisionTrackChangeIds = /* @__PURE__ */ new Set();
3192
3184
  };
3193
3185
  const applyPostDecisionTrackChangesToCache = (ids) => {
@@ -3205,25 +3197,6 @@ function createSuperDocUI(options) {
3205
3197
  });
3206
3198
  }
3207
3199
  };
3208
- const schedulePostDecisionTrackChangesReconcile = () => {
3209
- if (disposed || postDecisionTrackChangesReconcileTimer) return;
3210
- postDecisionTrackChangesReconcileTimer = setTimeout(() => {
3211
- postDecisionTrackChangesReconcileTimer = null;
3212
- const run = () => {
3213
- if (disposed || postDecisionTrackChangeIds.size === 0) return;
3214
- invalidateDocumentContent({ preservePostDecisionTrackChanges: true });
3215
- postDecisionTrackChangesToken = contentToken();
3216
- postDecisionTrackChangesReconcileToken = postDecisionTrackChangesToken;
3217
- recompute();
3218
- };
3219
- const requestIdle = globalThis.requestIdleCallback;
3220
- if (typeof requestIdle === "function") {
3221
- requestIdle(run, { timeout: 2e3 });
3222
- return;
3223
- }
3224
- run();
3225
- }, POST_DECISION_TRACKED_CHANGES_RECONCILE_DELAY_MS);
3226
- };
3227
3200
  const notifyPostDecisionTrackChanges = (receipt) => {
3228
3201
  const notify = () => {
3229
3202
  if (disposed) return;
@@ -3289,7 +3262,6 @@ function createSuperDocUI(options) {
3289
3262
  postDecisionTrackChangesToken = token;
3290
3263
  postDecisionTrackChangeIds = new Set([...alreadyRemoved, ...newlyRemoved]);
3291
3264
  applyPostDecisionTrackChangesToCache(postDecisionTrackChangeIds);
3292
- schedulePostDecisionTrackChangesReconcile();
3293
3265
  publishPostDecisionTrackChanges(newlyRemoved, receipt);
3294
3266
  };
3295
3267
  const postDecisionTrackChangeIdsForToken = (token) => postDecisionTrackChangesToken === token && postDecisionTrackChangeIds.size > 0 ? postDecisionTrackChangeIds : null;
@@ -3958,11 +3930,11 @@ function createSuperDocUI(options) {
3958
3930
  sourceLoadingSubscriptionHost = null;
3959
3931
  clearPostDecisionTrackChanges();
3960
3932
  };
3961
- const invalidateDocumentContent = (options$1) => {
3933
+ const invalidateDocumentContent = () => {
3962
3934
  const carryAuthoritativeTrackChangesHold = authoritativeTrackChangesPendingToken !== null;
3963
3935
  documentMutationRevision += 1;
3964
3936
  if (carryAuthoritativeTrackChangesHold) authoritativeTrackChangesPendingToken = contentToken();
3965
- if (!options$1?.preservePostDecisionTrackChanges) clearPostDecisionTrackChanges();
3937
+ clearPostDecisionTrackChanges();
3966
3938
  };
3967
3939
  const insertText = (text) => {
3968
3940
  if (typeof text !== "string" || text.length === 0) return failedReceipt("insertText requires a non-empty string.", "INVALID_INPUT");
@@ -4173,10 +4145,9 @@ function createSuperDocUI(options) {
4173
4145
  value: heldEntry?.hasSettled ? heldEntry.value : null,
4174
4146
  status: heldEntry?.hasSettled ? "stale" : "pending"
4175
4147
  } : readAsync("trackChanges", token, () => {
4176
- if (listTrackedChanges) return postDecisionTrackChangesToken === token ? listTrackedChanges.call(v2TrackedChanges, POST_DECISION_TRACKED_CHANGES_LIST_OPTIONS) : listTrackedChanges.call(v2TrackedChanges);
4148
+ if (listTrackedChanges) return listTrackedChanges.call(v2TrackedChanges);
4177
4149
  return tcApi?.list ? tcApi.list() : void 0;
4178
4150
  }, (raw) => raw && Array.isArray(raw.items) ? raw.items : []);
4179
- if (listStatus === "ready" && postDecisionTrackChangesReconcileToken === token) clearPostDecisionTrackChanges();
4180
4151
  const items = (value ?? []).map(projectTrackChangesItem).filter((item) => item != null).filter((item) => {
4181
4152
  const id = readEntityId(item);
4182
4153
  return !id || !postDecisionIds?.has(id);
@@ -5980,11 +5951,20 @@ function createSuperDocUI(options) {
5980
5951
  state = nextState;
5981
5952
  for (const listener of [...listeners]) listener(state);
5982
5953
  };
5954
+ const activeEditorResetHooks = [];
5955
+ const runActiveEditorResetHooks = () => {
5956
+ for (const reset of activeEditorResetHooks) try {
5957
+ reset();
5958
+ } catch {}
5959
+ };
5983
5960
  const detachers = [];
5984
5961
  const attach = (source, events) => {
5985
5962
  if (!source || typeof source.on !== "function") return;
5986
5963
  for (const event of events) {
5987
- const handler = () => recompute();
5964
+ const handler = event === "active-editor-change" ? () => {
5965
+ runActiveEditorResetHooks();
5966
+ recompute();
5967
+ } : () => recompute();
5988
5968
  try {
5989
5969
  source.on(event, handler);
5990
5970
  detachers.push(() => {
@@ -8288,6 +8268,28 @@ function createSuperDocUI(options) {
8288
8268
  if (typeof xOrInput === "object") return pointEntityHits(xOrInput?.x, xOrInput?.y);
8289
8269
  return null;
8290
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);
8291
8293
  const viewport = {
8292
8294
  getRect: (input) => {
8293
8295
  const host = getHost();
@@ -8323,12 +8325,15 @@ function createSuperDocUI(options) {
8323
8325
  zoom: s.zoom
8324
8326
  }));
8325
8327
  unsubs.push(sub.subscribe(() => schedule()));
8326
- const host = getHost();
8327
- if (typeof host?.observeGeometry === "function") {
8328
- const off = safeCall(() => host.observeGeometry(() => schedule()), null);
8329
- if (typeof off === "function") unsubs.push(off);
8330
- }
8328
+ const entry = {
8329
+ schedule,
8330
+ detach: null
8331
+ };
8332
+ bindGeometryObserver(entry);
8333
+ geometryObservers.add(entry);
8331
8334
  return () => {
8335
+ geometryObservers.delete(entry);
8336
+ detachGeometryObserver(entry);
8332
8337
  if (frame && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
8333
8338
  for (const unsub of unsubs.splice(0)) try {
8334
8339
  unsub();
@@ -8502,6 +8507,28 @@ function createSuperDocUI(options) {
8502
8507
  return searchState;
8503
8508
  };
8504
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);
8505
8532
  const readSearchQueryError = (record) => {
8506
8533
  if (!record) return false;
8507
8534
  const queryError = record.queryError;
@@ -8653,11 +8680,14 @@ function createSuperDocUI(options) {
8653
8680
  },
8654
8681
  close: () => {
8655
8682
  searchRequestGeneration += 1;
8656
- const host = getHostSearch();
8657
- if (host && typeof host.clear === "function") safeCall(() => host.clear(), null);
8683
+ if (releaseActiveSearchSession) releaseSearchSession();
8658
8684
  else {
8659
- const editSearch = getEditCommandSearch();
8660
- 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
+ }
8661
8691
  }
8662
8692
  searchState = {
8663
8693
  ...SEARCH_UNAVAILABLE_SLICE,
@@ -8685,6 +8715,9 @@ function createSuperDocUI(options) {
8685
8715
  open: true,
8686
8716
  reason: void 0
8687
8717
  });
8718
+ releaseActiveSearchSession = () => {
8719
+ editSearch.query({ query: "" });
8720
+ };
8688
8721
  const result = safeCall(() => editSearch.query({
8689
8722
  query,
8690
8723
  caseSensitive,
@@ -8725,6 +8758,9 @@ function createSuperDocUI(options) {
8725
8758
  open: true,
8726
8759
  reason: void 0
8727
8760
  });
8761
+ releaseActiveSearchSession = () => {
8762
+ if (typeof host.clear === "function") host.clear();
8763
+ };
8728
8764
  applyHostSearchResult(safeCall(() => host.setSession(query, {
8729
8765
  caseSensitive,
8730
8766
  includeDeletedText,
@@ -8734,6 +8770,11 @@ function createSuperDocUI(options) {
8734
8770
  if (query.length > 0 && searchState.total === 0 && searchState.reason !== SUPERDOC_UI_REASONS.searchInvalidPattern) {
8735
8771
  const editSearch = getEditCommandSearch();
8736
8772
  if (editSearch && typeof editSearch.query === "function" && typeof editSearch.getState === "function") {
8773
+ const releaseHostSession = releaseActiveSearchSession;
8774
+ releaseActiveSearchSession = () => {
8775
+ releaseHostSession?.();
8776
+ editSearch.query({ query: "" });
8777
+ };
8737
8778
  const commandResult = safeCall(() => editSearch.query({
8738
8779
  query,
8739
8780
  caseSensitive,
@@ -8974,10 +9015,6 @@ function createSuperDocUI(options) {
8974
9015
  clearTimeout(typingContentInvalidationTimer);
8975
9016
  typingContentInvalidationTimer = null;
8976
9017
  }
8977
- if (postDecisionTrackChangesReconcileTimer) {
8978
- clearTimeout(postDecisionTrackChangesReconcileTimer);
8979
- postDecisionTrackChangesReconcileTimer = null;
8980
- }
8981
9018
  if (heavyReadCompletionRecomputeTimer) {
8982
9019
  clearTimeout(heavyReadCompletionRecomputeTimer);
8983
9020
  heavyReadCompletionRecomputeTimer = null;
@@ -9002,6 +9039,8 @@ function createSuperDocUI(options) {
9002
9039
  currentDocumentSelectionSource = null;
9003
9040
  listeners.clear();
9004
9041
  searchListeners.clear();
9042
+ painterCaptureEpoch += 1;
9043
+ painterModeListeners.clear();
9005
9044
  customCommands.clear();
9006
9045
  };
9007
9046
  const controller = {
@@ -9025,12 +9064,14 @@ function createSuperDocUI(options) {
9025
9064
  styles,
9026
9065
  formatPainter: {
9027
9066
  setPointerSelecting(flag) {
9067
+ if (disposed) return;
9028
9068
  painter = {
9029
9069
  ...painter,
9030
9070
  pointerSelecting: flag
9031
9071
  };
9032
9072
  },
9033
9073
  notifyPointerUp() {
9074
+ if (disposed) return;
9034
9075
  painter = {
9035
9076
  ...painter,
9036
9077
  pointerSelecting: false
@@ -9038,12 +9079,14 @@ function createSuperDocUI(options) {
9038
9079
  maybeApply();
9039
9080
  },
9040
9081
  setKeyboardSelecting(flag) {
9082
+ if (disposed) return;
9041
9083
  painter = {
9042
9084
  ...painter,
9043
9085
  keyboardSelecting: flag
9044
9086
  };
9045
9087
  },
9046
9088
  notifyKeyUp() {
9089
+ if (disposed) return;
9047
9090
  painter = {
9048
9091
  ...painter,
9049
9092
  keyboardSelecting: false
@@ -9051,9 +9094,11 @@ function createSuperDocUI(options) {
9051
9094
  maybeApply();
9052
9095
  },
9053
9096
  cancel() {
9097
+ if (disposed) return;
9054
9098
  exitFormatPainter();
9055
9099
  },
9056
9100
  onModeChange(cb) {
9101
+ if (disposed) return () => {};
9057
9102
  painterModeListeners.add(cb);
9058
9103
  return () => painterModeListeners.delete(cb);
9059
9104
  }