superdoc 2.13.0-next.10 → 2.13.0-next.11

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.
@@ -3111,6 +3111,18 @@ function commandResultFromOperationResult(result) {
3111
3111
  function isSuccessfulReceipt(result) {
3112
3112
  return Boolean(result) && typeof result === "object" && result.success === true;
3113
3113
  }
3114
+ /**
3115
+ * The host also emits `mutation:committed` for previews and no-op receipts;
3116
+ * those events must not mark the document as having unsaved edits.
3117
+ */
3118
+ function mutationCommittedEventChangedDocument(event) {
3119
+ if (event.dryRun === true) return false;
3120
+ const receipt = event.receipt;
3121
+ if (receipt && typeof receipt === "object" && receipt.changed === false) return false;
3122
+ if (receipt && typeof receipt === "object" && receipt.noop === true) return false;
3123
+ if (receipt && typeof receipt === "object" && receipt.status === "NO_OP") return false;
3124
+ return true;
3125
+ }
3114
3126
  function commandResultSucceeded(result) {
3115
3127
  if (result === false) return false;
3116
3128
  if (result && typeof result === "object" && result.success === false) return false;
@@ -3917,6 +3929,30 @@ function createSuperDocUI(options) {
3917
3929
  let allTrackedChangesResolvedToken = null;
3918
3930
  let selectionEpoch = 0;
3919
3931
  let lastCoordinatorEditor = null;
3932
+ /**
3933
+ * Fallback dirty state for editors that do not expose `isDirty` (V2). Kept
3934
+ * per host so switching the active editor away and back does not forget an
3935
+ * edit, and seeded from the host's local mutation revision so a controller
3936
+ * created after the first edit still reports it. A document replacement or
3937
+ * a verified zero revision clears an entry: `save:completed` fires for every DOCX export,
3938
+ * including a download, and producing bytes is not persistence.
3939
+ */
3940
+ const dirtyHosts = /* @__PURE__ */ new WeakSet();
3941
+ const hostSeededMutationRevision = /* @__PURE__ */ new WeakMap();
3942
+ const seedLocalDocumentMutation = (host) => {
3943
+ if (hostSeededMutationRevision.has(host)) return;
3944
+ const revision = typeof host.getLocalMutationRevision === "function" ? safeCall(() => host.getLocalMutationRevision(), null) : null;
3945
+ const seeded = typeof revision === "number" ? revision : 0;
3946
+ hostSeededMutationRevision.set(host, seeded);
3947
+ if (seeded > 0) dirtyHosts.add(host);
3948
+ else if (revision === 0) dirtyHosts.delete(host);
3949
+ };
3950
+ const hasLocalDocumentMutation = () => {
3951
+ const host = getHost();
3952
+ if (!host) return false;
3953
+ seedLocalDocumentMutation(host);
3954
+ return dirtyHosts.has(host);
3955
+ };
3920
3956
  /** Token shared by document-content reads (editor identity + mutation revision). */
3921
3957
  const contentToken = () => `${editorIdentityId(getEditor())}|m${documentMutationRevision}`;
3922
3958
  const clearPostDecisionTrackChanges = () => {
@@ -5184,10 +5220,11 @@ function createSuperDocUI(options) {
5184
5220
  };
5185
5221
  const computeDocument = () => {
5186
5222
  const editor = getEditor();
5223
+ const editorDirty = editor ? editor.isDirty : void 0;
5187
5224
  return {
5188
5225
  ready: editor != null,
5189
5226
  mode: readDocumentMode(),
5190
- dirty: editor ? Boolean(editor.isDirty) : false
5227
+ dirty: editor ? editorDirty === void 0 ? hasLocalDocumentMutation() : Boolean(editorDirty) : false
5191
5228
  };
5192
5229
  };
5193
5230
  /**
@@ -7114,7 +7151,8 @@ function createSuperDocUI(options) {
7114
7151
  state = computeState("initial");
7115
7152
  lastOptimisticInlineSelectionSignature = selectionInlineValueSignature(state.selection);
7116
7153
  const syncHostEventsSubscription = () => {
7117
- const events = (getEditor()?.host)?.events;
7154
+ const host = getEditor()?.host;
7155
+ const events = host?.events;
7118
7156
  const next = events && typeof events.subscribe === "function" ? events : null;
7119
7157
  if (next === currentHostEventsSource) return;
7120
7158
  if (detachHostEvents) {
@@ -7123,9 +7161,24 @@ function createSuperDocUI(options) {
7123
7161
  }
7124
7162
  currentHostEventsSource = next;
7125
7163
  if (!next) return;
7164
+ if (host) {
7165
+ hostSeededMutationRevision.delete(host);
7166
+ seedLocalDocumentMutation(host);
7167
+ }
7126
7168
  try {
7127
7169
  const off = next.subscribe((event) => {
7128
7170
  const type = event?.type;
7171
+ const isStandaloneDocumentMutation = type === "document:mutated" && event.hasCommitEvent !== true;
7172
+ if ((type === "document:mutated" || type === "mutation:committed" && mutationCommittedEventChangedDocument(event)) && host && !dirtyHosts.has(host)) {
7173
+ dirtyHosts.add(host);
7174
+ recompute("document-dirty");
7175
+ }
7176
+ if (type === "collaboration:document-replaced" && host) {
7177
+ dirtyHosts.delete(host);
7178
+ hostSeededMutationRevision.delete(host);
7179
+ seedLocalDocumentMutation(host);
7180
+ recompute("document-dirty");
7181
+ }
7129
7182
  if (type === "review-mutation:started") {
7130
7183
  beginUiReviewMutation(event.reviewMutation?.token);
7131
7184
  return;
@@ -7145,8 +7198,8 @@ function createSuperDocUI(options) {
7145
7198
  refreshIncompleteTrackChangesDirectories();
7146
7199
  return;
7147
7200
  }
7148
- if (type === "mutation:committed" || type === "collaboration:remote-changed") lastEditableMutationAtMs = Date.now();
7149
- if (type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
7201
+ if (isStandaloneDocumentMutation || type === "mutation:committed" || type === "collaboration:remote-changed") lastEditableMutationAtMs = Date.now();
7202
+ if (isStandaloneDocumentMutation || type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
7150
7203
  const impact = type === "mutation:committed" ? getV2TrackedChangeMutationImpact(event) : null;
7151
7204
  if (impact?.allResolved) {
7152
7205
  replaceTrackedChangeItemsInCache([]);
@@ -7161,7 +7214,7 @@ function createSuperDocUI(options) {
7161
7214
  return;
7162
7215
  }
7163
7216
  if (impact?.removedIds.size && impact.upsertIds.size === 0) return;
7164
- if (type === "collaboration:remote-changed" || type === "mutation:committed" && !isTypingBurst) schedulePostPaintContentRefresh();
7217
+ if (isStandaloneDocumentMutation || type === "collaboration:remote-changed" || type === "mutation:committed" && !isTypingBurst) schedulePostPaintContentRefresh();
7165
7218
  const remoteCommentsPartChanged = type === "collaboration:remote-changed" && Array.isArray(event.changedPartUris) && event.changedPartUris.some((partUri) => typeof partUri === "string" && COMMENTS_CATALOG_PART_URIS.has(partUri));
7166
7219
  const loadedCommentAnchorsMayHaveChanged = type === "collaboration:remote-changed" && Array.isArray(event.changedStoryIds) && event.changedStoryIds.length > 0 && commentsCatalogMayHaveRows();
7167
7220
  if (remoteCommentsPartChanged && !isTypingBurst) heavyReadsHeldUntilIdle = true;
@@ -7275,6 +7328,11 @@ function createSuperDocUI(options) {
7275
7328
  const matchesEditor = Boolean(replacedEditor) && replacedEditor === getEditor();
7276
7329
  const matchesHost = Boolean(replacedHost) && replacedHost === getHost();
7277
7330
  if (!matchesEditor && !matchesHost) return;
7331
+ const replacedDirtyHost = matchesHost ? replacedHost : getHost();
7332
+ if (replacedDirtyHost) {
7333
+ dirtyHosts.delete(replacedDirtyHost);
7334
+ hostSeededMutationRevision.delete(replacedDirtyHost);
7335
+ }
7278
7336
  runDocumentResetHooks();
7279
7337
  asyncReads.clear();
7280
7338
  invalidateDocumentContent();
@@ -3111,6 +3111,18 @@ function commandResultFromOperationResult(result) {
3111
3111
  function isSuccessfulReceipt(result) {
3112
3112
  return Boolean(result) && typeof result === "object" && result.success === true;
3113
3113
  }
3114
+ /**
3115
+ * The host also emits `mutation:committed` for previews and no-op receipts;
3116
+ * those events must not mark the document as having unsaved edits.
3117
+ */
3118
+ function mutationCommittedEventChangedDocument(event) {
3119
+ if (event.dryRun === true) return false;
3120
+ const receipt = event.receipt;
3121
+ if (receipt && typeof receipt === "object" && receipt.changed === false) return false;
3122
+ if (receipt && typeof receipt === "object" && receipt.noop === true) return false;
3123
+ if (receipt && typeof receipt === "object" && receipt.status === "NO_OP") return false;
3124
+ return true;
3125
+ }
3114
3126
  function commandResultSucceeded(result) {
3115
3127
  if (result === false) return false;
3116
3128
  if (result && typeof result === "object" && result.success === false) return false;
@@ -3917,6 +3929,30 @@ function createSuperDocUI(options) {
3917
3929
  let allTrackedChangesResolvedToken = null;
3918
3930
  let selectionEpoch = 0;
3919
3931
  let lastCoordinatorEditor = null;
3932
+ /**
3933
+ * Fallback dirty state for editors that do not expose `isDirty` (V2). Kept
3934
+ * per host so switching the active editor away and back does not forget an
3935
+ * edit, and seeded from the host's local mutation revision so a controller
3936
+ * created after the first edit still reports it. A document replacement or
3937
+ * a verified zero revision clears an entry: `save:completed` fires for every DOCX export,
3938
+ * including a download, and producing bytes is not persistence.
3939
+ */
3940
+ const dirtyHosts = /* @__PURE__ */ new WeakSet();
3941
+ const hostSeededMutationRevision = /* @__PURE__ */ new WeakMap();
3942
+ const seedLocalDocumentMutation = (host) => {
3943
+ if (hostSeededMutationRevision.has(host)) return;
3944
+ const revision = typeof host.getLocalMutationRevision === "function" ? safeCall(() => host.getLocalMutationRevision(), null) : null;
3945
+ const seeded = typeof revision === "number" ? revision : 0;
3946
+ hostSeededMutationRevision.set(host, seeded);
3947
+ if (seeded > 0) dirtyHosts.add(host);
3948
+ else if (revision === 0) dirtyHosts.delete(host);
3949
+ };
3950
+ const hasLocalDocumentMutation = () => {
3951
+ const host = getHost();
3952
+ if (!host) return false;
3953
+ seedLocalDocumentMutation(host);
3954
+ return dirtyHosts.has(host);
3955
+ };
3920
3956
  /** Token shared by document-content reads (editor identity + mutation revision). */
3921
3957
  const contentToken = () => `${editorIdentityId(getEditor())}|m${documentMutationRevision}`;
3922
3958
  const clearPostDecisionTrackChanges = () => {
@@ -5184,10 +5220,11 @@ function createSuperDocUI(options) {
5184
5220
  };
5185
5221
  const computeDocument = () => {
5186
5222
  const editor = getEditor();
5223
+ const editorDirty = editor ? editor.isDirty : void 0;
5187
5224
  return {
5188
5225
  ready: editor != null,
5189
5226
  mode: readDocumentMode(),
5190
- dirty: editor ? Boolean(editor.isDirty) : false
5227
+ dirty: editor ? editorDirty === void 0 ? hasLocalDocumentMutation() : Boolean(editorDirty) : false
5191
5228
  };
5192
5229
  };
5193
5230
  /**
@@ -7114,7 +7151,8 @@ function createSuperDocUI(options) {
7114
7151
  state = computeState("initial");
7115
7152
  lastOptimisticInlineSelectionSignature = selectionInlineValueSignature(state.selection);
7116
7153
  const syncHostEventsSubscription = () => {
7117
- const events = (getEditor()?.host)?.events;
7154
+ const host = getEditor()?.host;
7155
+ const events = host?.events;
7118
7156
  const next = events && typeof events.subscribe === "function" ? events : null;
7119
7157
  if (next === currentHostEventsSource) return;
7120
7158
  if (detachHostEvents) {
@@ -7123,9 +7161,24 @@ function createSuperDocUI(options) {
7123
7161
  }
7124
7162
  currentHostEventsSource = next;
7125
7163
  if (!next) return;
7164
+ if (host) {
7165
+ hostSeededMutationRevision.delete(host);
7166
+ seedLocalDocumentMutation(host);
7167
+ }
7126
7168
  try {
7127
7169
  const off = next.subscribe((event) => {
7128
7170
  const type = event?.type;
7171
+ const isStandaloneDocumentMutation = type === "document:mutated" && event.hasCommitEvent !== true;
7172
+ if ((type === "document:mutated" || type === "mutation:committed" && mutationCommittedEventChangedDocument(event)) && host && !dirtyHosts.has(host)) {
7173
+ dirtyHosts.add(host);
7174
+ recompute("document-dirty");
7175
+ }
7176
+ if (type === "collaboration:document-replaced" && host) {
7177
+ dirtyHosts.delete(host);
7178
+ hostSeededMutationRevision.delete(host);
7179
+ seedLocalDocumentMutation(host);
7180
+ recompute("document-dirty");
7181
+ }
7129
7182
  if (type === "review-mutation:started") {
7130
7183
  beginUiReviewMutation(event.reviewMutation?.token);
7131
7184
  return;
@@ -7145,8 +7198,8 @@ function createSuperDocUI(options) {
7145
7198
  refreshIncompleteTrackChangesDirectories();
7146
7199
  return;
7147
7200
  }
7148
- if (type === "mutation:committed" || type === "collaboration:remote-changed") lastEditableMutationAtMs = Date.now();
7149
- if (type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
7201
+ if (isStandaloneDocumentMutation || type === "mutation:committed" || type === "collaboration:remote-changed") lastEditableMutationAtMs = Date.now();
7202
+ if (isStandaloneDocumentMutation || type === "mutation:committed" || type === "save:completed" || type === "collaboration:remote-changed") {
7150
7203
  const impact = type === "mutation:committed" ? getV2TrackedChangeMutationImpact(event) : null;
7151
7204
  if (impact?.allResolved) {
7152
7205
  replaceTrackedChangeItemsInCache([]);
@@ -7161,7 +7214,7 @@ function createSuperDocUI(options) {
7161
7214
  return;
7162
7215
  }
7163
7216
  if (impact?.removedIds.size && impact.upsertIds.size === 0) return;
7164
- if (type === "collaboration:remote-changed" || type === "mutation:committed" && !isTypingBurst) schedulePostPaintContentRefresh();
7217
+ if (isStandaloneDocumentMutation || type === "collaboration:remote-changed" || type === "mutation:committed" && !isTypingBurst) schedulePostPaintContentRefresh();
7165
7218
  const remoteCommentsPartChanged = type === "collaboration:remote-changed" && Array.isArray(event.changedPartUris) && event.changedPartUris.some((partUri) => typeof partUri === "string" && COMMENTS_CATALOG_PART_URIS.has(partUri));
7166
7219
  const loadedCommentAnchorsMayHaveChanged = type === "collaboration:remote-changed" && Array.isArray(event.changedStoryIds) && event.changedStoryIds.length > 0 && commentsCatalogMayHaveRows();
7167
7220
  if (remoteCommentsPartChanged && !isTypingBurst) heavyReadsHeldUntilIdle = true;
@@ -7275,6 +7328,11 @@ function createSuperDocUI(options) {
7275
7328
  const matchesEditor = Boolean(replacedEditor) && replacedEditor === getEditor();
7276
7329
  const matchesHost = Boolean(replacedHost) && replacedHost === getHost();
7277
7330
  if (!matchesEditor && !matchesHost) return;
7331
+ const replacedDirtyHost = matchesHost ? replacedHost : getHost();
7332
+ if (replacedDirtyHost) {
7333
+ dirtyHosts.delete(replacedDirtyHost);
7334
+ hostSeededMutationRevision.delete(replacedDirtyHost);
7335
+ }
7278
7336
  runDocumentResetHooks();
7279
7337
  asyncReads.clear();
7280
7338
  invalidateDocumentContent();
@@ -19,7 +19,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
19
19
  var PRIVATE_ENGINE_INFO = (0, _superdoc_docx_engine_collaboration_upgrade_engine.getCollaborationUpgradeEngineInfo)();
20
20
  var ENGINE_INFO = Object.freeze({
21
21
  ...PRIVATE_ENGINE_INFO,
22
- superdocVersion: "2.13.0-next.10",
22
+ superdocVersion: "2.13.0-next.11",
23
23
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
24
24
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
25
25
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -18,7 +18,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
18
18
  var PRIVATE_ENGINE_INFO = getCollaborationUpgradeEngineInfo$1();
19
19
  var ENGINE_INFO = Object.freeze({
20
20
  ...PRIVATE_ENGINE_INFO,
21
- superdocVersion: "2.13.0-next.10",
21
+ superdocVersion: "2.13.0-next.11",
22
22
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
23
23
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
24
24
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-mHK2pqj3.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-DNfQTF2k.cjs");
3
3
  const require_slice_source = require("../chunks/slice-source-CFaqq0Vo.cjs");
4
4
  let react = require("react");
5
5
  //#region src/public/ui/react.ts
@@ -1,4 +1,4 @@
1
- import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-u1giSvlm.es.js";
1
+ import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-XWtQHPGP.es.js";
2
2
  import { t as toSliceSource } from "../chunks/slice-source-gfOhG2MW.es.js";
3
3
  import { createContext, createElement, useCallback, useContext, useEffect, useRef, useState } from "react";
4
4
  //#region src/public/ui/react.ts
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-mHK2pqj3.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-DNfQTF2k.cjs");
3
3
  const require_slice_source = require("../chunks/slice-source-CFaqq0Vo.cjs");
4
4
  let vue = require("vue");
5
5
  //#region src/public/ui/vue.ts
@@ -1,4 +1,4 @@
1
- import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-u1giSvlm.es.js";
1
+ import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-XWtQHPGP.es.js";
2
2
  import { t as toSliceSource } from "../chunks/slice-source-gfOhG2MW.es.js";
3
3
  import { computed, inject, onScopeDispose, provide, shallowRef, toRaw, toValue, watch } from "vue";
4
4
  //#region src/public/ui/vue.ts
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-mHK2pqj3.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-DNfQTF2k.cjs");
3
3
  exports.BUILT_IN_COMMAND_IDS = require_create_super_doc_ui.BUILT_IN_COMMAND_IDS;
4
4
  exports.createSuperDocUI = require_create_super_doc_ui.createSuperDocUI;
5
5
  exports.shallowEqual = require_create_super_doc_ui.shallowEqual;
@@ -1,2 +1,2 @@
1
- import { n as shallowEqual, r as BUILT_IN_COMMAND_IDS, t as createSuperDocUI } from "../chunks/create-super-doc-ui-u1giSvlm.es.js";
1
+ import { n as shallowEqual, r as BUILT_IN_COMMAND_IDS, t as createSuperDocUI } from "../chunks/create-super-doc-ui-XWtQHPGP.es.js";
2
2
  export { BUILT_IN_COMMAND_IDS, createSuperDocUI, shallowEqual };
@@ -48,3 +48,4 @@ export function resolveFitWidthOptions(rawFitConfig: any): {
48
48
  export function computeFitZoom(availableWidth: any, documentWidth: any): number | null;
49
49
  export function computeAppliedFitZoom(availableWidth: any, documentWidth: any, options: any): number | null;
50
50
  export function normalizePdfPageMeasurement(measured: any, scaleFactor: any, zoomFactor: any): any;
51
+ export function resolveEditorPageWidth(editor: any): number | null;
@@ -1,43 +1,55 @@
1
1
  export interface ThemeColors {
2
- /** Action/accent color (buttons, links, active states). Default: #1355ff */
2
+ /** Action color for buttons, links, and active states. @defaultValue `#1355ff` */
3
3
  action?: string;
4
- /** Action hover state. Default: #0f44cc */
4
+ /** Hover color for action elements. @defaultValue `#0f44cc` */
5
5
  actionHover?: string;
6
- /** Text color on action-colored buttons. Default: #ffffff */
6
+ /** Text color shown on action-colored elements. @defaultValue `#ffffff` */
7
7
  actionText?: string;
8
- /** Default background for panels, cards, dropdowns. Default: #ffffff */
8
+ /** Shared background for UI surfaces such as panels, cards, and dropdowns. @defaultValue `#ffffff` */
9
9
  bg?: string;
10
- /** Hover background. Default: #dbdbdb */
10
+ /** Background for hovered controls. @defaultValue `#dbdbdb` */
11
11
  hoverBg?: string;
12
- /** Active/pressed background. Default: #c8d0d8 */
12
+ /** Background for active and pressed controls. @defaultValue `#c8d0d8` */
13
13
  activeBg?: string;
14
- /** Disabled background. Default: #f5f5f5 */
14
+ /** Background for disabled controls. @defaultValue `#f5f5f5` */
15
15
  disabledBg?: string;
16
- /** Primary text color. Default: #47484a */
16
+ /** Primary UI text color. @defaultValue `#47484a` */
17
17
  text?: string;
18
- /** Secondary/muted text. Default: #666666 */
18
+ /** Secondary UI text color. @defaultValue `#666666` */
19
19
  textMuted?: string;
20
- /** Disabled text. Default: #ababab */
20
+ /** Text color for disabled controls. @defaultValue `#ababab` */
21
21
  textDisabled?: string;
22
- /** Default border color. Default: #dbdbdb */
22
+ /** Shared UI border color. @defaultValue `#dbdbdb` */
23
23
  border?: string;
24
24
  }
25
+ /** SuperDoc CSS variable overrides applied after the semantic theme values. */
26
+ export type ThemeVariableOverrides = {
27
+ readonly [name: `--sd-${string}`]: string | null | undefined;
28
+ };
25
29
  export interface ThemeConfig {
26
- /** Theme name — used in the generated class name (e.g., "dark" "sd-theme-dark") */
30
+ /** Name used in the generated class, such as `product` for `sd-theme-product`. */
27
31
  name?: string;
28
- /** UI font family */
32
+ /**
33
+ * Font family for SuperDoc UI surfaces that inherit the theme, such as body-mounted dialogs
34
+ * and floating surfaces. The Editor root and the external toolbar set `--sd-ui-font-family`
35
+ * inline from `uiDisplayFallbackFont`, and an inline declaration outranks the theme class —
36
+ * set `uiDisplayFallbackFont` to the same value to change those surfaces too.
37
+ */
29
38
  font?: string;
30
- /** Default border radius (e.g., "8px") */
39
+ /** Shared UI border radius, such as `8px`. */
31
40
  radius?: string;
32
- /** Default box shadow */
41
+ /** Shared UI box shadow. */
33
42
  shadow?: string;
34
- /** Core color palette cascades to every component */
43
+ /** Semantic colors shared by SuperDoc UI components. */
35
44
  colors?: ThemeColors;
36
- /** Escape hatch raw CSS variable overrides (e.g., { '--sd-ui-toolbar-bg': '#f8fafc' }) */
37
- vars?: Record<string, string | null | undefined>;
45
+ /** Component-specific overrides, such as `{ '--sd-ui-toolbar-bg': '#f8fafc' }`. */
46
+ vars?: ThemeVariableOverrides;
38
47
  }
48
+ /** CSS generated by {@link buildTheme}. */
39
49
  export interface ThemeResult {
50
+ /** Class that activates the generated theme. */
40
51
  className: string;
52
+ /** CSS rule containing the generated SuperDoc variables. */
41
53
  css: string;
42
54
  }
43
55
  /**
@@ -65,8 +77,8 @@ export interface ThemeResult {
65
77
  export declare function createTheme(config: ThemeConfig): string;
66
78
  /**
67
79
  * Build a SuperDoc theme and return both the class name and raw CSS.
68
- * Pure function does NOT inject styles into the DOM. Use this for SSR
69
- * or when you need to control style injection yourself (e.g., CSP nonce).
80
+ * This function does not access the DOM. Use it for server rendering or when
81
+ * your application controls style injection, such as with a CSP nonce.
70
82
  *
71
83
  * @example
72
84
  * ```ts
@@ -10,6 +10,7 @@ import { CustomCommandContext, FontFamilyOption as ToolbarFontFamilyOption } fro
10
10
  export type { DocumentFontOption, FontAssetUrlContext, FontAssetUrlResolver, FontFaceSlot, FontFamilyOption, FontLoadResult, FontLoadStatus, FontLoadSummary, FontResolutionReason, FontResolutionRecord, GlyphException, ResolvedFontEvidence, SubstitutePolicyAction, SubstituteVerdict, } from '../../../../shared/font-system/src/index.js';
11
11
  export type SuperDoc = SuperDocClass;
12
12
  export type { BrowserDocumentApi } from '../../public/browser-document-api.js';
13
+ export type { CommentsType, ExportParams, ExportType } from '../../public/export-types.js';
13
14
  /**
14
15
  * A row in a custom dropdown's option list, and the value handed back to the
15
16
  * `command` callback when one is chosen.
@@ -2789,12 +2790,6 @@ export interface TrackChangesModuleConfig {
2789
2790
  semanticColors?: TrackChangesSemanticColorsConfig;
2790
2791
  }
2791
2792
  export type DocumentMode = 'editing' | 'viewing' | 'suggesting';
2792
- export type ExportType = 'docx';
2793
- /**
2794
- * - 'external': Include only external comments (default)
2795
- * - 'clean': Export without any comments
2796
- */
2797
- export type CommentsType = 'external' | 'clean';
2798
2793
  /**
2799
2794
  * Document view layout values — mirrors OOXML ST_View (ECMA-376 §17.18.102).
2800
2795
  * - 'print': Print Layout View — displays document as it prints (default)
@@ -2813,30 +2808,6 @@ export interface ViewOptions {
2813
2808
  */
2814
2809
  layout?: ViewLayout;
2815
2810
  }
2816
- export interface ExportParams {
2817
- /** Browser export format. DOCX is the only supported output. */
2818
- exportType?: readonly [ExportType];
2819
- /** How to handle comments. */
2820
- commentsType?: CommentsType;
2821
- /** Custom filename (without extension). */
2822
- exportedName?: string;
2823
- /** Extra files to include in the export zip. */
2824
- additionalFiles?: globalThis.Blob[];
2825
- /** Filenames for the additional files. */
2826
- additionalFileNames?: string[];
2827
- /** Whether this is a final document export. */
2828
- isFinalDoc?: boolean;
2829
- /** Auto-download or return blob. */
2830
- triggerDownload?: boolean;
2831
- /**
2832
- * Color for field highlights. The runtime defaults to `null` when no
2833
- * value is supplied (and forwards `null` through to the underlying
2834
- * editor export, which accepts `string | null`); the typedef accepts
2835
- * `null` explicitly so consumers can pass an explicit "no highlight"
2836
- * value without a typecheck failure.
2837
- */
2838
- fieldsHighlightColor?: string | null;
2839
- }
2840
2811
  /** Surface where the edit originated. */
2841
2812
  export type EditorSurface = 'body' | 'header' | 'footer';
2842
2813
  export interface EditorUpdateEvent {
@@ -0,0 +1,23 @@
1
+ /** Browser export format. DOCX is the only supported output. */
2
+ export type ExportType = 'docx';
3
+ /** Comment output: `external` includes external comments; `clean` removes comments. */
4
+ export type CommentsType = 'external' | 'clean';
5
+ /** Options accepted by `SuperDoc.export()` and `ui.document.export()`. */
6
+ export interface ExportParams {
7
+ /** Browser export format. DOCX is the only supported output. */
8
+ exportType?: readonly [ExportType];
9
+ /** How to handle comments. */
10
+ commentsType?: CommentsType;
11
+ /** Custom filename without an extension. */
12
+ exportedName?: string;
13
+ /** Extra files to include in the export zip. */
14
+ additionalFiles?: globalThis.Blob[];
15
+ /** Filenames for the additional files. */
16
+ additionalFileNames?: string[];
17
+ /** Whether this is a final document export. */
18
+ isFinalDoc?: boolean;
19
+ /** Download the file or return its Blob without downloading. */
20
+ triggerDownload?: boolean;
21
+ /** Field-highlight color, or `null` to omit field highlighting. */
22
+ fieldsHighlightColor?: string | null;
23
+ }
@@ -215,6 +215,10 @@ import type { SurfacesModuleConfig as __Cjs_SurfacesModuleConfig } from './index
215
215
  import type { TextAddress as __Cjs_TextAddress } from './index.js' with { "resolution-mode": "import" };
216
216
  import type { TextSegment as __Cjs_TextSegment } from './index.js' with { "resolution-mode": "import" };
217
217
  import type { TextTarget as __Cjs_TextTarget } from './index.js' with { "resolution-mode": "import" };
218
+ import type { ThemeColors as __Cjs_ThemeColors } from './index.js' with { "resolution-mode": "import" };
219
+ import type { ThemeConfig as __Cjs_ThemeConfig } from './index.js' with { "resolution-mode": "import" };
220
+ import type { ThemeResult as __Cjs_ThemeResult } from './index.js' with { "resolution-mode": "import" };
221
+ import type { ThemeVariableOverrides as __Cjs_ThemeVariableOverrides } from './index.js' with { "resolution-mode": "import" };
218
222
  import type { ToolbarCommandId as __Cjs_ToolbarCommandId } from './index.js' with { "resolution-mode": "import" };
219
223
  import type { ToolbarConfig as __Cjs_ToolbarConfig } from './index.js' with { "resolution-mode": "import" };
220
224
  import type { ToolbarCustomButton as __Cjs_ToolbarCustomButton } from './index.js' with { "resolution-mode": "import" };
@@ -482,6 +486,10 @@ export type { __Cjs_SurfacesModuleConfig as SurfacesModuleConfig };
482
486
  export type { __Cjs_TextAddress as TextAddress };
483
487
  export type { __Cjs_TextSegment as TextSegment };
484
488
  export type { __Cjs_TextTarget as TextTarget };
489
+ export type { __Cjs_ThemeColors as ThemeColors };
490
+ export type { __Cjs_ThemeConfig as ThemeConfig };
491
+ export type { __Cjs_ThemeResult as ThemeResult };
492
+ export type { __Cjs_ThemeVariableOverrides as ThemeVariableOverrides };
485
493
  export type { __Cjs_ToolbarCommandId as ToolbarCommandId };
486
494
  export type { __Cjs_ToolbarConfig as ToolbarConfig };
487
495
  export type { __Cjs_ToolbarCustomButton as ToolbarCustomButton };
@@ -9,6 +9,7 @@ export { DOCX, PDF, HTML, getFileObject, compareVersions };
9
9
  export { SuperDoc } from '../core/SuperDoc.js';
10
10
  export { buildTheme } from '../core/theme/create-theme.js';
11
11
  export { createTheme } from '../core/theme/create-theme.js';
12
+ export type { ThemeColors, ThemeConfig, ThemeResult, ThemeVariableOverrides } from '../core/theme/create-theme.js';
12
13
  export type { AwarenessState } from '../core/types/index.js';
13
14
  export type { AwarenessUser } from '../core/types/index.js';
14
15
  export type { BlockNavigationAddress } from '../core/types/index.js';
@@ -1,5 +1,6 @@
1
1
  import { CommentsListQuery as DocumentApiCommentsListQuery, CommentsListResult, TrackChangesListResult, EntityAddress, TextAddress, TextTarget, ScrollIntoViewInput, ScrollIntoViewOutput, SelectionInfo, SelectionTarget, Receipt, ReceiptFailureCode, ContentControlInfo, StyleCatalogItem, StyleCatalogDiagnostic, StyleCatalogSourceStatus, StylesGetCatalogInput, StylesGetCatalogResult } from '../../../../document-api/src/index.js';
2
2
  import { PartialBrowserDocumentApi } from '../browser-document-api.js';
3
+ import { ExportParams } from '../export-types.js';
3
4
  import { SuperDocUIReason } from './reasons.js';
4
5
  import { BuiltInCommandId } from './commands.js';
5
6
  /**
@@ -657,7 +658,7 @@ export interface DocumentSlice {
657
658
  ready: boolean;
658
659
  /** Current document mode. */
659
660
  mode: 'editing' | 'suggesting' | 'viewing' | null;
660
- /** The document has unsaved changes. */
661
+ /** The current document has local changes. */
661
662
  dirty: boolean;
662
663
  }
663
664
  /**
@@ -735,7 +736,10 @@ export interface StylesHandle extends SnapshotSubscribable<StylesSlice> {
735
736
  /** Resolve the active paragraph style for the current selection. */
736
737
  getActiveParagraphStyle(): ActiveParagraphStyle;
737
738
  }
738
- /** A painted rectangle in viewport coordinates. */
739
+ /**
740
+ * A painted document rectangle. Coordinates use browser client space by
741
+ * default, or the element-relative space requested through `relativeTo`.
742
+ */
739
743
  export interface ViewportRect {
740
744
  /** Zero-based page index the rect belongs to. */
741
745
  pageIndex: number;
@@ -762,7 +766,7 @@ export type ViewportGetRectTarget = SelectionTarget | TextAddress | TextTarget |
762
766
  export interface ViewportGetRectInput {
763
767
  /** Target to resolve to painted geometry. */
764
768
  target: ViewportGetRectTarget;
765
- /** Optional element to anchor returned coordinates against. */
769
+ /** Return coordinates relative to this element instead of browser client space. */
766
770
  relativeTo?: HTMLElement;
767
771
  }
768
772
  /** Result of `ui.viewport.getRect`. */
@@ -791,7 +795,7 @@ export interface SelectionHandle extends SnapshotSubscribable<SelectionSlice> {
791
795
  * Returns `null` before the first async browser read settles.
792
796
  */
793
797
  current(): SelectionInfo | null;
794
- /** Freeze the current selection for later comment/format actions. */
798
+ /** Preserve the current non-empty selection for work that moves focus into application UI. */
795
799
  capture(): SelectionCapture | null;
796
800
  /**
797
801
  * Restore a previously captured selection, best-effort. Never throws;
@@ -820,7 +824,9 @@ export interface SelectionHandle extends SnapshotSubscribable<SelectionSlice> {
820
824
  relativeTo?: HTMLElement;
821
825
  }): readonly ViewportRect[];
822
826
  }
827
+ /** A non-empty selection snapshot preserved independently of browser focus. */
823
828
  export interface SelectionCapture extends SelectionSlice {
829
+ /** Unix time in milliseconds when the selection was captured. */
824
830
  capturedAt: number;
825
831
  }
826
832
  /**
@@ -1144,8 +1150,8 @@ export interface DocumentHandle extends SnapshotSubscribable<DocumentSlice> {
1144
1150
  getSnapshot(): DocumentSlice;
1145
1151
  /** Set the document mode (editing / suggesting / viewing). */
1146
1152
  setMode(mode: 'editing' | 'suggesting' | 'viewing'): void;
1147
- /** Export the document; returns the SuperDoc export promise when available. */
1148
- export(input?: unknown): Promise<unknown> | undefined;
1153
+ /** Export the document and return the produced Blob, optionally downloading it. */
1154
+ export(input?: ExportParams): Promise<Blob> | undefined;
1149
1155
  /** Read text through the Document API; `null` when unavailable. */
1150
1156
  getText(): string | null;
1151
1157
  /** Replace the active document file, when supported by the host. */
@@ -1153,9 +1159,12 @@ export interface DocumentHandle extends SnapshotSubscribable<DocumentSlice> {
1153
1159
  }
1154
1160
  /** Viewport handle. */
1155
1161
  export interface ViewportHandle {
1156
- /** Resolve painted geometry for an entity / content-control address. */
1162
+ /** Resolve current painted geometry for a selection, text target, or supported entity address. */
1157
1163
  getRect(input: ViewportGetRectInput): ViewportRectResult;
1158
- /** Subscribe to viewport/geometry invalidation. */
1164
+ /**
1165
+ * Subscribe to geometry invalidation after selection, zoom, scroll, resize,
1166
+ * layout, or repaint changes. The callback is coalesced to one per frame.
1167
+ */
1159
1168
  observe(listener: () => void): () => void;
1160
1169
  /** Painted editor host element, when available. */
1161
1170
  getHost(): HTMLElement | null;
@@ -1433,7 +1442,7 @@ export interface SuperDocLike {
1433
1442
  /** Set the document mode across the instance. */
1434
1443
  setDocumentMode?(mode: string): unknown;
1435
1444
  /** Export the active document. */
1436
- export?(...args: unknown[]): Promise<unknown> | unknown;
1445
+ export?(params?: ExportParams): Promise<Blob> | Blob;
1437
1446
  /** Set an absolute zoom value. */
1438
1447
  setZoom?(value: number): unknown;
1439
1448
  /** Set a zoom mode. */