@arbidocs/blocks 0.4.101 → 0.4.102

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 (180) hide show
  1. package/dist/chunk-6MG62I5B.cjs +272 -0
  2. package/dist/chunk-6MG62I5B.cjs.map +1 -0
  3. package/dist/chunk-EQB3WELX.js +269 -0
  4. package/dist/chunk-EQB3WELX.js.map +1 -0
  5. package/dist/document-tools/AdoptSignatureDialog.d.ts +25 -0
  6. package/dist/document-tools/DocumentToolButtons.d.ts +2 -0
  7. package/dist/document-tools/SignatureRequestBanner.d.ts +18 -0
  8. package/dist/document-tools/index.cjs +175 -0
  9. package/dist/document-tools/index.cjs.map +1 -1
  10. package/dist/document-tools/index.d.ts +3 -1
  11. package/dist/document-tools/index.js +168 -3
  12. package/dist/document-tools/index.js.map +1 -1
  13. package/dist/document-tools/viewer/GuidedSigningViewer.d.ts +26 -0
  14. package/dist/document-tools/viewer/SignatureFieldsOverlay.d.ts +41 -0
  15. package/dist/document-tools/viewer/SignatureRequestEditor.d.ts +26 -0
  16. package/dist/document-tools/viewer/index.cjs +983 -0
  17. package/dist/document-tools/viewer/index.cjs.map +1 -1
  18. package/dist/document-tools/viewer/index.d.ts +3 -0
  19. package/dist/document-tools/viewer/index.js +983 -5
  20. package/dist/document-tools/viewer/index.js.map +1 -1
  21. package/node_modules/@arbidocs/coedit/LICENSE +21 -0
  22. package/node_modules/@arbidocs/coedit/dist/encoding.cjs +751 -0
  23. package/node_modules/@arbidocs/coedit/dist/encoding.cjs.map +1 -0
  24. package/node_modules/@arbidocs/coedit/dist/encoding.d.cts +192 -0
  25. package/node_modules/@arbidocs/coedit/dist/encoding.d.ts +192 -0
  26. package/node_modules/@arbidocs/coedit/dist/encoding.js +716 -0
  27. package/node_modules/@arbidocs/coedit/dist/encoding.js.map +1 -0
  28. package/node_modules/@arbidocs/coedit/dist/hocuspocus.cjs +1759 -0
  29. package/node_modules/@arbidocs/coedit/dist/hocuspocus.cjs.map +1 -0
  30. package/node_modules/@arbidocs/coedit/dist/hocuspocus.d.cts +39 -0
  31. package/node_modules/@arbidocs/coedit/dist/hocuspocus.d.ts +39 -0
  32. package/node_modules/@arbidocs/coedit/dist/hocuspocus.js +1736 -0
  33. package/node_modules/@arbidocs/coedit/dist/hocuspocus.js.map +1 -0
  34. package/node_modules/@arbidocs/coedit/dist/index.cjs +1692 -0
  35. package/node_modules/@arbidocs/coedit/dist/index.cjs.map +1 -0
  36. package/node_modules/@arbidocs/coedit/dist/index.d.cts +16 -0
  37. package/node_modules/@arbidocs/coedit/dist/index.d.ts +16 -0
  38. package/node_modules/@arbidocs/coedit/dist/index.js +1664 -0
  39. package/node_modules/@arbidocs/coedit/dist/index.js.map +1 -0
  40. package/node_modules/@arbidocs/coedit/dist/server.cjs +1852 -0
  41. package/node_modules/@arbidocs/coedit/dist/server.cjs.map +1 -0
  42. package/node_modules/@arbidocs/coedit/dist/server.d.cts +43 -0
  43. package/node_modules/@arbidocs/coedit/dist/server.d.ts +43 -0
  44. package/node_modules/@arbidocs/coedit/dist/server.js +1822 -0
  45. package/node_modules/@arbidocs/coedit/dist/server.js.map +1 -0
  46. package/node_modules/@arbidocs/coedit/dist/session-Cf9iu1Vt.d.cts +82 -0
  47. package/node_modules/@arbidocs/coedit/dist/session-Cf9iu1Vt.d.ts +82 -0
  48. package/node_modules/@arbidocs/coedit/dist/template.cjs +1627 -0
  49. package/node_modules/@arbidocs/coedit/dist/template.cjs.map +1 -0
  50. package/node_modules/@arbidocs/coedit/dist/template.d.cts +125 -0
  51. package/node_modules/@arbidocs/coedit/dist/template.d.ts +125 -0
  52. package/node_modules/@arbidocs/coedit/dist/template.js +1612 -0
  53. package/node_modules/@arbidocs/coedit/dist/template.js.map +1 -0
  54. package/node_modules/@arbidocs/coedit/dist/versions-DXiFQMA6.d.cts +8 -0
  55. package/node_modules/@arbidocs/coedit/dist/versions-DXiFQMA6.d.ts +8 -0
  56. package/node_modules/@arbidocs/coedit/package.json +68 -0
  57. package/node_modules/@docx-editor.dev/core/LICENSE +201 -0
  58. package/node_modules/@docx-editor.dev/core/README.md +125 -0
  59. package/node_modules/@docx-editor.dev/core/THIRD_PARTY_NOTICES.md +56 -0
  60. package/node_modules/@docx-editor.dev/core/dist/automation.cjs +1 -0
  61. package/node_modules/@docx-editor.dev/core/dist/automation.d.ts +162 -0
  62. package/node_modules/@docx-editor.dev/core/dist/automation.js +1 -0
  63. package/node_modules/@docx-editor.dev/core/dist/binding.cjs +1 -0
  64. package/node_modules/@docx-editor.dev/core/dist/binding.d.ts +164 -0
  65. package/node_modules/@docx-editor.dev/core/dist/binding.js +1 -0
  66. package/node_modules/@docx-editor.dev/core/dist/chunk-2GO5T2JU.cjs +1 -0
  67. package/node_modules/@docx-editor.dev/core/dist/chunk-2RC2EPND.js +3 -0
  68. package/node_modules/@docx-editor.dev/core/dist/chunk-4GBTELJV.cjs +28 -0
  69. package/node_modules/@docx-editor.dev/core/dist/chunk-4R3TEXMN.js +18 -0
  70. package/node_modules/@docx-editor.dev/core/dist/chunk-5CSUYANV.js +1 -0
  71. package/node_modules/@docx-editor.dev/core/dist/chunk-6APGXLBB.cjs +3 -0
  72. package/node_modules/@docx-editor.dev/core/dist/chunk-6AWEKBLB.cjs +1 -0
  73. package/node_modules/@docx-editor.dev/core/dist/chunk-6EYYL7FL.js +1 -0
  74. package/node_modules/@docx-editor.dev/core/dist/chunk-6JIJOZDW.js +1 -0
  75. package/node_modules/@docx-editor.dev/core/dist/chunk-BTQKU64Q.cjs +1 -0
  76. package/node_modules/@docx-editor.dev/core/dist/chunk-E7BQA6UP.js +2 -0
  77. package/node_modules/@docx-editor.dev/core/dist/chunk-EO4C5QJW.cjs +2 -0
  78. package/node_modules/@docx-editor.dev/core/dist/chunk-ETTO6GK3.js +1 -0
  79. package/node_modules/@docx-editor.dev/core/dist/chunk-FIJZIQXA.cjs +18 -0
  80. package/node_modules/@docx-editor.dev/core/dist/chunk-FRXAOVTB.js +28 -0
  81. package/node_modules/@docx-editor.dev/core/dist/chunk-J6BVWIDB.js +2 -0
  82. package/node_modules/@docx-editor.dev/core/dist/chunk-JGNVNT2A.cjs +2 -0
  83. package/node_modules/@docx-editor.dev/core/dist/chunk-K5U2PLDP.cjs +2 -0
  84. package/node_modules/@docx-editor.dev/core/dist/chunk-KKIJG3C6.js +2 -0
  85. package/node_modules/@docx-editor.dev/core/dist/chunk-LWDSDCMO.js +27 -0
  86. package/node_modules/@docx-editor.dev/core/dist/chunk-NBCVVZOM.cjs +1 -0
  87. package/node_modules/@docx-editor.dev/core/dist/chunk-O2AL2HSJ.cjs +1 -0
  88. package/node_modules/@docx-editor.dev/core/dist/chunk-O5INAWZQ.js +1 -0
  89. package/node_modules/@docx-editor.dev/core/dist/chunk-QMLCVPCD.cjs +1 -0
  90. package/node_modules/@docx-editor.dev/core/dist/chunk-RCHS4ZEH.cjs +27 -0
  91. package/node_modules/@docx-editor.dev/core/dist/chunk-RIYSCEFQ.js +2 -0
  92. package/node_modules/@docx-editor.dev/core/dist/chunk-S6J4O5XP.js +1 -0
  93. package/node_modules/@docx-editor.dev/core/dist/chunk-SRPILEWV.cjs +5 -0
  94. package/node_modules/@docx-editor.dev/core/dist/chunk-TSLBZ26X.js +1 -0
  95. package/node_modules/@docx-editor.dev/core/dist/chunk-UKVVUHZL.cjs +1 -0
  96. package/node_modules/@docx-editor.dev/core/dist/chunk-VDNNLG6X.js +2 -0
  97. package/node_modules/@docx-editor.dev/core/dist/chunk-VHAVHCQY.js +7 -0
  98. package/node_modules/@docx-editor.dev/core/dist/chunk-VX43VBAX.cjs +7 -0
  99. package/node_modules/@docx-editor.dev/core/dist/chunk-Z6WBFXJU.js +5 -0
  100. package/node_modules/@docx-editor.dev/core/dist/chunk-ZUHOMK52.cjs +2 -0
  101. package/node_modules/@docx-editor.dev/core/dist/collaboration/replication.cjs +1 -0
  102. package/node_modules/@docx-editor.dev/core/dist/collaboration/replication.d.ts +270 -0
  103. package/node_modules/@docx-editor.dev/core/dist/collaboration/replication.js +1 -0
  104. package/node_modules/@docx-editor.dev/core/dist/collaboration.cjs +1 -0
  105. package/node_modules/@docx-editor.dev/core/dist/collaboration.d.ts +269 -0
  106. package/node_modules/@docx-editor.dev/core/dist/collaboration.js +1 -0
  107. package/node_modules/@docx-editor.dev/core/dist/contracts/document.cjs +1 -0
  108. package/node_modules/@docx-editor.dev/core/dist/contracts/document.d.ts +290 -0
  109. package/node_modules/@docx-editor.dev/core/dist/contracts/document.js +0 -0
  110. package/node_modules/@docx-editor.dev/core/dist/contracts/editor.cjs +1 -0
  111. package/node_modules/@docx-editor.dev/core/dist/contracts/editor.d.ts +22 -0
  112. package/node_modules/@docx-editor.dev/core/dist/contracts/editor.js +1 -0
  113. package/node_modules/@docx-editor.dev/core/dist/contracts/interaction.cjs +1 -0
  114. package/node_modules/@docx-editor.dev/core/dist/contracts/interaction.d.ts +103 -0
  115. package/node_modules/@docx-editor.dev/core/dist/contracts/interaction.js +0 -0
  116. package/node_modules/@docx-editor.dev/core/dist/contracts/modules.cjs +1 -0
  117. package/node_modules/@docx-editor.dev/core/dist/contracts/modules.d.ts +143 -0
  118. package/node_modules/@docx-editor.dev/core/dist/contracts/modules.js +1 -0
  119. package/node_modules/@docx-editor.dev/core/dist/contracts/types.cjs +1 -0
  120. package/node_modules/@docx-editor.dev/core/dist/contracts/types.d.ts +11 -0
  121. package/node_modules/@docx-editor.dev/core/dist/contracts/types.js +0 -0
  122. package/node_modules/@docx-editor.dev/core/dist/custom-node-writes-cvL5rhcD.d.ts +323 -0
  123. package/node_modules/@docx-editor.dev/core/dist/dist-PKZR6RSH.js +2 -0
  124. package/node_modules/@docx-editor.dev/core/dist/document-protection-BAGVGqaP.d.ts +20 -0
  125. package/node_modules/@docx-editor.dev/core/dist/editor-Ci7IZGmG.d.ts +2448 -0
  126. package/node_modules/@docx-editor.dev/core/dist/editor-scope-OHPwVQ5l.d.ts +84 -0
  127. package/node_modules/@docx-editor.dev/core/dist/editor.cjs +1 -0
  128. package/node_modules/@docx-editor.dev/core/dist/editor.css +15 -0
  129. package/node_modules/@docx-editor.dev/core/dist/editor.d.ts +1394 -0
  130. package/node_modules/@docx-editor.dev/core/dist/editor.js +1 -0
  131. package/node_modules/@docx-editor.dev/core/dist/export.cjs +2 -0
  132. package/node_modules/@docx-editor.dev/core/dist/export.d.ts +391 -0
  133. package/node_modules/@docx-editor.dev/core/dist/export.js +2 -0
  134. package/node_modules/@docx-editor.dev/core/dist/failure-NS2lsya4.d.ts +115 -0
  135. package/node_modules/@docx-editor.dev/core/dist/font-resolver-BVQB14qT.d.ts +256 -0
  136. package/node_modules/@docx-editor.dev/core/dist/harfbuzz.wasm +0 -0
  137. package/node_modules/@docx-editor.dev/core/dist/headless-document-view-qH331moE.d.ts +143 -0
  138. package/node_modules/@docx-editor.dev/core/dist/image-resources-BN-hUgCn.d.ts +211 -0
  139. package/node_modules/@docx-editor.dev/core/dist/index-Bsg7oIKP.d.ts +3869 -0
  140. package/node_modules/@docx-editor.dev/core/dist/index.cjs +1 -0
  141. package/node_modules/@docx-editor.dev/core/dist/index.d.ts +53 -0
  142. package/node_modules/@docx-editor.dev/core/dist/index.js +1 -0
  143. package/node_modules/@docx-editor.dev/core/dist/layout-shaping-BEyuiQOk.d.ts +246 -0
  144. package/node_modules/@docx-editor.dev/core/dist/layout.cjs +1 -0
  145. package/node_modules/@docx-editor.dev/core/dist/layout.d.ts +3151 -0
  146. package/node_modules/@docx-editor.dev/core/dist/layout.js +1 -0
  147. package/node_modules/@docx-editor.dev/core/dist/node-module-shim-TTKTT66I.js +1 -0
  148. package/node_modules/@docx-editor.dev/core/dist/note-properties-4Y9o6Gyk.d.ts +68 -0
  149. package/node_modules/@docx-editor.dev/core/dist/omml-equation-CuzBL5DD.d.ts +85 -0
  150. package/node_modules/@docx-editor.dev/core/dist/output.cjs +1 -0
  151. package/node_modules/@docx-editor.dev/core/dist/output.d.ts +97 -0
  152. package/node_modules/@docx-editor.dev/core/dist/output.js +1 -0
  153. package/node_modules/@docx-editor.dev/core/dist/protocol-Bqk4Izjc.d.ts +1651 -0
  154. package/node_modules/@docx-editor.dev/core/dist/review-pane-D9jm8DcY.d.ts +128 -0
  155. package/node_modules/@docx-editor.dev/core/dist/review-paragraph-order-DT-n6ouC.d.ts +85 -0
  156. package/node_modules/@docx-editor.dev/core/dist/revision-projection-DZ4kKVev.d.ts +242 -0
  157. package/node_modules/@docx-editor.dev/core/dist/semantic-cell-selection-D9D1KSXq.d.ts +464 -0
  158. package/node_modules/@docx-editor.dev/core/dist/semantic-interaction-CIC-PooQ.d.ts +135 -0
  159. package/node_modules/@docx-editor.dev/core/dist/semantic-paint-BME37OMv.d.ts +326 -0
  160. package/node_modules/@docx-editor.dev/core/dist/semantic-record-queries-CBlZqZNa.d.ts +177 -0
  161. package/node_modules/@docx-editor.dev/core/dist/semantic-records-4B3WwFAi.d.ts +3532 -0
  162. package/node_modules/@docx-editor.dev/core/dist/store.cjs +1 -0
  163. package/node_modules/@docx-editor.dev/core/dist/store.d.ts +2706 -0
  164. package/node_modules/@docx-editor.dev/core/dist/store.js +1 -0
  165. package/node_modules/@docx-editor.dev/core/dist/tree-package-fragment-BeeKxDw8.d.ts +1201 -0
  166. package/node_modules/@docx-editor.dev/core/dist/tree-session-contract-CVbmlMlq.d.ts +664 -0
  167. package/node_modules/@docx-editor.dev/core/dist/types-barrel-D3xCgQX6.d.ts +4269 -0
  168. package/node_modules/@docx-editor.dev/core/licenses/HarfBuzz-COPYING.txt +42 -0
  169. package/node_modules/@docx-editor.dev/core/package.json +140 -0
  170. package/node_modules/@docx-editor.dev/react/LICENSE +201 -0
  171. package/node_modules/@docx-editor.dev/react/README.md +141 -0
  172. package/node_modules/@docx-editor.dev/react/THIRD_PARTY_NOTICES.md +18 -0
  173. package/node_modules/@docx-editor.dev/react/dist/index.d.mts +4928 -0
  174. package/node_modules/@docx-editor.dev/react/dist/index.d.ts +4928 -0
  175. package/node_modules/@docx-editor.dev/react/dist/index.js +4 -0
  176. package/node_modules/@docx-editor.dev/react/dist/index.mjs +4 -0
  177. package/node_modules/@docx-editor.dev/react/package.json +74 -0
  178. package/node_modules/@docx-editor.dev/react/src/styles/editor.css +6 -0
  179. package/node_modules/@docx-editor.dev/react/src/styles/zIndex.ts +28 -0
  180. package/package.json +26 -15
@@ -0,0 +1,3869 @@
1
+ import { W as TreeDocOp, co as TextFormFieldRange, cn as TextFormFieldOptions, au as Unsubscribe, E as ExecResult, ao as DrawingPositionInput, aM as DrawingTransform, A as ParagraphTabStop, y as IndentFormatting, z as ParagraphFlags, aB as ParagraphDisagreements, aj as DrawingTreeDocOp, at as SelectionPin, Q as OoxmlPackage, g as ReviewRevisionKind, an as ImageWrapTarget } from './types-barrel-D3xCgQX6.js';
2
+ import { k as FieldResultsMode, I as InsertImageInput, S as StoryScope, A as ApplyImagePropertiesInput, i as ImageIntentResult } from './tree-package-fragment-BeeKxDw8.js';
3
+ import { a as ImageDecodePort, S as SupportedImageMime } from './image-resources-BN-hUgCn.js';
4
+ import './document-protection-BAGVGqaP.js';
5
+ import { EditorModule, ReviewModuleContribution } from './contracts/modules.js';
6
+ import { D as DocumentSource, a as FontConfiguration, Z as ZoomMode, E as EditorFontError, i as Editor, e as EditorCommand, C as CanResult, p as SelectedImageState, z as FormatPainterSurfaceState, g as ScrollPlacement, r as TrackedChangePredicate, q as TrackedChangeFilterMode, F as FontFaceRequest, b as FontSource, I as ImageContext, B as TableBorderEdgeTarget, G as TableBorderSpec, J as TableBorderStyle, K as TableContext } from './editor-Ci7IZGmG.js';
7
+ import { e as RevisionMarkupOptions, a as ReviewDisplayMode, i as RevisionMarkupChromeHandlers, d as ResolvedRevisionMarkup } from './revision-projection-DZ4kKVev.js';
8
+ import { S as SemanticPosition, a as SemanticSelection, N as NavigationCommand } from './semantic-interaction-CIC-PooQ.js';
9
+ import { e as FontConfigurationFragment, g as FontResolver, i as MarkedFontResolver, f as FontResolutionRequest } from './font-resolver-BVQB14qT.js';
10
+ import { R as ReviewPaneOptions } from './review-pane-D9jm8DcY.js';
11
+ import { EditorCollaborationSession, CollaborationRemoteSelection, CollaborationModuleContribution } from './collaboration.js';
12
+ import { d as RevisionStyles, R as ReviewAuthorInfo, c as RevisionAuthorStyle, F as FieldShadingMode, f as DrawingPaintStrings } from './semantic-paint-BME37OMv.js';
13
+ import { b as ResolvedFootnoteProperties, R as ResolvedEndnoteProperties, A as AuthoredNoteProperties } from './note-properties-4Y9o6Gyk.js';
14
+ import { S as SemanticLayout, T as TextMeasurer, C as ContentControlBoundaryRecord } from './semantic-records-4B3WwFAi.js';
15
+ import { B as BookmarkIndex } from './custom-node-writes-cvL5rhcD.js';
16
+ import { C as CellSelection, S as SectionProperties } from './semantic-cell-selection-D9D1KSXq.js';
17
+ import { T as TreeDocxSessionView, a as TreeApplyResult } from './tree-session-contract-CVbmlMlq.js';
18
+ import { C as CollaborationStatus } from './failure-NS2lsya4.js';
19
+ import { V as ViewScope, b as EditorExecOptions } from './editor-scope-OHPwVQ5l.js';
20
+ import './contracts/document.js';
21
+ import './contracts/interaction.js';
22
+
23
+ /**
24
+ * A blank document, freshly zipped per call (the caller may hand the
25
+ * bytes to a loader that takes ownership). Calibri 11pt and Word's Normal paragraph
26
+ * spacing are authored in `w:docDefaults`, Word's built-in style gallery in `styles.xml`,
27
+ * and US Letter geometry in the section. Word opens the saved file.
28
+ *
29
+ * @public
30
+ */
31
+ declare function blankDocumentBytes(): Uint8Array;
32
+
33
+ type TableCommandSelectionPolicy = {
34
+ readonly kind: 'preserveSelection';
35
+ } | {
36
+ readonly kind: 'adoptCommittedCaret';
37
+ };
38
+ type TableCommandPlan = {
39
+ readonly ok: true;
40
+ readonly ops: readonly TreeDocOp[];
41
+ readonly selection: TableCommandSelectionPolicy;
42
+ } | {
43
+ readonly ok: false;
44
+ readonly code: 'unsupported' | 'invalidArgs' | 'locked';
45
+ readonly reason: string;
46
+ };
47
+
48
+ type NotePropertiesSlice = {
49
+ readonly resolved: ResolvedFootnoteProperties | ResolvedEndnoteProperties;
50
+ readonly documentAuthored?: AuthoredNoteProperties;
51
+ readonly sectionAuthored?: AuthoredNoteProperties;
52
+ };
53
+ type NotePropertiesStateSnapshot = {
54
+ readonly sectionIndex: number;
55
+ readonly footnote: NotePropertiesSlice;
56
+ readonly endnote: NotePropertiesSlice;
57
+ };
58
+
59
+ /** Priority of an editor-owned popup renderer. @public */
60
+ interface PopupChromeRegistrationOptions {
61
+ /** Use only when no manually registered renderer exists. */
62
+ readonly fallback?: boolean;
63
+ }
64
+ /**
65
+ * A core-owned content-control value edit.
66
+ *
67
+ * `kind` names the widget that was pressed. A `checkbox` session carries the current state as
68
+ * `'true'` / `'false'` and expects the opposite (or the same) back through `apply`; the
69
+ * packaged pop-ups apply the toggle at once, so a host only sees it when it renders the
70
+ * widget itself. A `buildingBlockGallery` session is a list session: `items` are the
71
+ * glossary's blocks for the control's gallery, named by `w:docPartPr/w:name`, and `apply`
72
+ * takes a name. A `picture` session carries the control's drawing node id as `value` and
73
+ * takes new image bytes through `replaceImage`; `apply` refuses, since no text stands for an
74
+ * image.
75
+ * @public
76
+ */
77
+ interface ContentControlWidgetSession {
78
+ readonly controlId: string;
79
+ readonly kind: 'dropdown' | 'comboBox' | 'date' | 'checkbox' | 'picture' | 'buildingBlockGallery';
80
+ readonly items: readonly {
81
+ readonly displayText: string;
82
+ readonly value: string;
83
+ }[];
84
+ readonly value: string;
85
+ /** The editor's regional locale, for a date picker's month, weekday and first-day rules. */
86
+ readonly locale: string;
87
+ readonly anchor: HTMLElement | null;
88
+ readonly signal: AbortSignal;
89
+ canApply(): boolean;
90
+ apply(value: string): boolean;
91
+ cancel(): void;
92
+ /**
93
+ * Picture sessions only: replace the control's image with these bytes. The engine sniffs
94
+ * the format (PNG, JPEG, GIF, BMP or WebP) and keeps the drawing's size. Resolves false
95
+ * when the bytes are not a supported image, the control no longer takes a write, or the
96
+ * document is open for viewing or suggesting. Cancellation during decoding prevents
97
+ * the commit; only one replacement may be pending for a session.
98
+ */
99
+ replaceImage?(bytes: Uint8Array): Promise<boolean>;
100
+ }
101
+ /** Framework rendering for content-control value widgets. @public */
102
+ interface ContentControlWidgetChromeHandlers {
103
+ readonly onRequest?: (session: ContentControlWidgetSession) => void;
104
+ /**
105
+ * Session kinds this renderer takes. Defaults to `dropdown`, `comboBox`, `date` and
106
+ * `buildingBlockGallery` (the list-shaped sessions), so a renderer written for the pop-ups
107
+ * never receives a checkbox or picture press it does not expect. Include `'checkbox'` to
108
+ * take those presses too; the engine then leaves the toggle to `apply`, and a press nobody
109
+ * takes toggles the box as before. Include `'picture'` to own the image pick; a press nobody
110
+ * takes opens the engine's own file picker.
111
+ */
112
+ readonly kinds?: readonly ContentControlWidgetSession['kind'][];
113
+ }
114
+ /** An invalid protected-field acknowledgement. @public */
115
+ interface InvalidTextFormFieldSession {
116
+ readonly type: 'number' | 'date';
117
+ readonly signal: AbortSignal;
118
+ /** Clear the unchanged invalid value, if the target still permits it. */
119
+ acknowledge(): void;
120
+ /** Dismiss without clearing the authored value. */
121
+ cancel(): void;
122
+ }
123
+ /** Framework rendering for invalid protected-field acknowledgements. @public */
124
+ interface InvalidTextFormFieldChromeHandlers {
125
+ readonly onRequest?: (session: InvalidTextFormFieldSession) => void;
126
+ }
127
+
128
+ /** A core-owned options edit. Its signal aborts when the dialog must close. @public */
129
+ interface TextFormFieldDialogSession {
130
+ readonly field: TextFormFieldRange;
131
+ readonly signal: AbortSignal;
132
+ /** Whether the current target exists and permits editing. Draft validation happens on apply. */
133
+ canApply(): boolean;
134
+ /** Save one undoable edit. A refused write leaves the session open. */
135
+ apply(text: string, options: TextFormFieldOptions): boolean;
136
+ /** Close without changing the document. Safe to call more than once. */
137
+ cancel(): void;
138
+ }
139
+ /** Framework-owned presentation for core-owned Field Options sessions. @public */
140
+ interface TextFormFieldChromeHandlers {
141
+ readonly onRequest?: (session: TextFormFieldDialogSession) => void;
142
+ }
143
+
144
+ /**
145
+ * Receives the element that shows the loading indicator on the first page, while a large
146
+ * document lays out its remaining pages.
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * editor.setOpeningIndicatorHost({
151
+ * publish(element) {
152
+ * // Render your indicator into `element`, or remove it when `element` is null.
153
+ * },
154
+ * });
155
+ * ```
156
+ *
157
+ * @public
158
+ */
159
+ interface OpeningIndicatorHost {
160
+ /**
161
+ * Called with the indicator element when the first pages show, and with `null` when the
162
+ * remaining pages are laid out or the open is abandoned. The element is empty while a host
163
+ * is set: render the host's content into it. It is centered on the first page, at most 30%
164
+ * of the window height below the page top, and scrolls with the document.
165
+ */
166
+ publish(element: HTMLElement | null): void;
167
+ }
168
+
169
+ /**
170
+ * A hyperlink as the surface reports it: its identity, where it sits, and the SANITIZED
171
+ * target. `href: null` is an inert link — a refused scheme or a dangling relationship — which
172
+ * a UI shows and offers to edit but must never offer to open.
173
+ */
174
+ interface SurfaceHyperlink {
175
+ /** Canonical node id of the `w:hyperlink`. */
176
+ readonly id: string;
177
+ readonly paragraphId: string;
178
+ /** UTF-16 range of the link's display text within its paragraph. */
179
+ readonly start: number;
180
+ readonly end: number;
181
+ readonly text: string;
182
+ readonly kind: 'external' | 'internal' | 'unresolved';
183
+ /** Sanitized projection: an absolute URL, `#anchor`, or null when inert. */
184
+ readonly href: string | null;
185
+ /** The authored target, for an editor to seed its input with. */
186
+ readonly authored: string;
187
+ readonly anchor?: string;
188
+ readonly tooltip?: string;
189
+ }
190
+ /**
191
+ * Reading and writing hyperlinks on the surface.
192
+ *
193
+ * Every href that leaves here has already been through `sanitizeHref` — targets come from files,
194
+ * so `javascript:`, `data:` and `vbscript:` are dropped at the parse boundary rather than trusted
195
+ * to be filtered by whoever renders them.
196
+ */
197
+ interface HyperlinkOps {
198
+ /** Every link in the paragraph the caret is in. */
199
+ linksInCaretParagraph(): SurfaceHyperlink[];
200
+ /** The link the caret sits in, or null. */
201
+ linkAtCaret(): SurfaceHyperlink | null;
202
+ /**
203
+ * The FIELD link whose painted atom the caret sits on, or null.
204
+ *
205
+ * Separate from {@link linkAtCaret} on purpose: a `HYPERLINK` field is not a tree node, so
206
+ * the typed lane never returns one, and link-create must not mistake a field atom for an
207
+ * editable link. Resolved from the layout projection, boundary-inclusive.
208
+ */
209
+ fieldLinkAtCaret(): SurfaceHyperlink | null;
210
+ /** The link with this node id, or null. */
211
+ linkById(linkId: string): SurfaceHyperlink | null;
212
+ /**
213
+ * Apply a link to the selection, or retarget the one the caret is already in.
214
+ *
215
+ * `text` replaces the display text when supplied. Returns whether anything committed;
216
+ * a refusal leaves the document exactly as it was.
217
+ */
218
+ applyHyperlink(input: {
219
+ readonly url?: string;
220
+ readonly anchor?: string;
221
+ readonly text?: string;
222
+ readonly tooltip?: string;
223
+ }): boolean;
224
+ /** Take the link off the one at the caret (or a named one). Returns whether it committed. */
225
+ removeHyperlink(linkId?: string): boolean;
226
+ }
227
+
228
+ /** A click on a painted link, after native navigation was refused. */
229
+ interface HyperlinkActivation {
230
+ readonly link: SurfaceHyperlink;
231
+ /** The clicked line fragment's viewport rect, so a popover can be placed under it. */
232
+ readonly rect: {
233
+ readonly left: number;
234
+ readonly top: number;
235
+ readonly bottom: number;
236
+ readonly right: number;
237
+ };
238
+ }
239
+ /**
240
+ * Moving the caret and the viewport: to a position, to a bookmark, or out to an external target.
241
+ *
242
+ * {@link SurfaceNavigation.openExternal} is THE external-activation call site, and it refuses
243
+ * anything but an already-sanitized href. Routing an authored target through some other path is
244
+ * how a document gets to choose where a click goes.
245
+ */
246
+ interface SurfaceNavigation {
247
+ /** Snap to a semantic position using layout geometry, then place the caret there. */
248
+ goToPosition(position: {
249
+ paragraphId: string;
250
+ offset: number;
251
+ }): boolean;
252
+ /**
253
+ * Scroll a bookmark into view and place the caret at it. Answers false for a name no
254
+ * bookmark declares — an inert click, which is what Word does with a dangling anchor.
255
+ */
256
+ goToBookmark(name: string): boolean;
257
+ /**
258
+ * THE external-activation call site. Refuses anything but a sanitized projection, so a
259
+ * caller cannot route an authored target through it by mistake.
260
+ */
261
+ openExternal(href: string | null): boolean;
262
+ destroy(): void;
263
+ }
264
+
265
+ /** One addressable inline equation and its compact editable projection. */
266
+ interface SurfaceEquation {
267
+ readonly id: string;
268
+ readonly paragraphId: string;
269
+ readonly start: number;
270
+ readonly end: number;
271
+ readonly linear: string;
272
+ readonly fallbackText: string;
273
+ /** True when every source construct belongs to the editable subset. */
274
+ readonly supported: boolean;
275
+ }
276
+ /** A user click on one painted equation. */
277
+ interface EquationActivation {
278
+ readonly equation: SurfaceEquation;
279
+ readonly rect: {
280
+ readonly left: number;
281
+ readonly top: number;
282
+ readonly right: number;
283
+ readonly bottom: number;
284
+ };
285
+ }
286
+ /** Boundary-inclusive lookup, matching the hyperlink and field atom popovers. */
287
+ declare function equationAtPosition(equations: readonly SurfaceEquation[], position: SemanticPosition): SurfaceEquation | null;
288
+ type EquationAction = 'replace' | 'remove';
289
+ /** Engine-owned capability result for equation editing chrome. */
290
+ type EquationCanResult = {
291
+ readonly ok: true;
292
+ } | {
293
+ readonly ok: false;
294
+ readonly code: 'locked' | 'notFound' | 'unsupported';
295
+ readonly reason: string;
296
+ };
297
+ /** Surface equation reads and atomic replace/remove writes. */
298
+ interface EquationOps {
299
+ equationsInCaretParagraph(): SurfaceEquation[];
300
+ equationAtCaret(): SurfaceEquation | null;
301
+ equationById(equationId: string): SurfaceEquation | null;
302
+ /** Whether equation chrome can run an action, with the engine-owned refusal reason. */
303
+ can(equationId: string, action: EquationAction): EquationCanResult;
304
+ applyEquation(equationId: string, linear: string): boolean;
305
+ removeEquation(equationId: string): boolean;
306
+ }
307
+
308
+ /**
309
+ * Everything {@link createDocxEditor} accepts. Every field is optional.
310
+ *
311
+ * `container` is the one that changes the shape of the whole lifecycle: omitting it produces an
312
+ * instance that does no DOM work until `attach(el)`, which is what lets a provider own the editor
313
+ * before any component has rendered a mount point.
314
+ *
315
+ * @public
316
+ */
317
+ interface DocxEditorConfig {
318
+ /**
319
+ * The element the paginated surface mounts into. The surface owns this subtree.
320
+ *
321
+ * Optional: an instance created WITHOUT a container stashes its document bytes and does
322
+ * no DOM work until `attach(el)` — the provider-first shape, where the editor exists
323
+ * before any component has rendered a mount point. With a container, the document mounts
324
+ * immediately at construction, exactly as before.
325
+ */
326
+ container?: HTMLElement;
327
+ /**
328
+ * A document to load at construction: DOCX bytes, or `'blank'` for Word's blank
329
+ * template. A `DocumentHandle` cannot be re-opened (the handle is identity, not
330
+ * content), so passing one emits a typed `error` event rather than silently loading
331
+ * nothing. Omitting this mounts NO document, which is not the same as an empty one.
332
+ */
333
+ document?: DocumentSource;
334
+ /**
335
+ * Font bytes for Word-accurate (HarfBuzz-shaped) line wrap and pagination. Omitted,
336
+ * layout falls back to a fixed-width estimate; fonts embedded in the document are
337
+ * wired in automatically either way. For Word's default faces (Calibri, Times New
338
+ * Roman, …) pass `await loadDefaultFonts()` from `@docx-editor.dev/fonts` — a bare
339
+ * fragment (`{ sources, substitutions }`) is accepted and composed with defaults, or
340
+ * merge several origins yourself with `composeFontConfiguration`. Sampled per load;
341
+ * failures degrade to the fixed measurer and report through `onFontError`.
342
+ *
343
+ * Pass a {@link FontResolver} instead to resolve ON DEMAND: the function is called once
344
+ * per load, after the document is parsed, with the families it actually declares, and
345
+ * only what it returns is loaded. A document naming nothing the resolver covers costs
346
+ * nothing. Note that a fetching resolver makes opening a document perform network
347
+ * requests — the engine never supplies one, so that stays your call.
348
+ */
349
+ fonts?: FontConfiguration | FontConfigurationFragment | FontResolver;
350
+ author?: string;
351
+ /** BCP-47 locale for regional date input and generated labels; defaults to en-US. */
352
+ locale?: string;
353
+ /** Drawing and form-control UI labels; defaults to English when omitted. */
354
+ translate?: (key: string, params?: Record<string, string | number>) => string;
355
+ /**
356
+ * Capability modules to register — the seam `@docx-editor.dev/pro` plugs in
357
+ * through. Omitted, the editor runs the free tier: lossless round-trip,
358
+ * final-state revision rendering, review chrome disabled with the engine's
359
+ * reason. See {@link EditorModule}.
360
+ */
361
+ modules?: readonly EditorModule[];
362
+ /**
363
+ * The mode the editor opens in — one prop, matching the toolbar's three-state pill.
364
+ *
365
+ * - `'edit'` — opens in editing, even when the document's `w:trackRevisions` asks for
366
+ * tracked changes; the reader still moves between modes from the toolbar.
367
+ * - `'suggesting'` — opens in suggesting. It needs what suggesting always needs — a
368
+ * review module and an {@link DocxEditorConfig.author} — and falls back to editing
369
+ * with the reason published when either is missing. A missing author is a host
370
+ * configuration error and is also reported once on the console; the editor enters
371
+ * suggesting as soon as {@link DocxEditorInstance.setAuthor} names one.
372
+ * - `'view'` — read-only: every mutating command through the facade is refused, and
373
+ * the toolbar cannot leave viewing.
374
+ * - Omitted — the DOCUMENT decides: a package carrying `w:trackRevisions` opens in
375
+ * suggesting, everything else in editing.
376
+ */
377
+ mode?: 'edit' | 'view' | 'suggesting';
378
+ /**
379
+ * How painted tracked changes are coloured. Presentation only — nothing is serialised.
380
+ *
381
+ * - `'author'` (the DEFAULT) — every change takes its author's colour from the
382
+ * `--doc-review-author-N` ramp, by order of first appearance, as Word does. Restyle a
383
+ * slot under `.docx-editor` to change the ramp.
384
+ * - `'kind'` — insertions green, deletions red, so "added" and "removed" are what a
385
+ * glance tells apart, whoever proposed them.
386
+ * - {@link RevisionAuthorAssignments} — style the named authors; `others` decides
387
+ * whether the rest take the ramp (the default) or the kind colours.
388
+ *
389
+ * The opening value. In React this is authored declaratively — `DocxEditor.ColorByChangeType`
390
+ * and `DocxEditor.AuthorStyle` compose and apply it, seeding this config for the first
391
+ * paint — so React hosts never pass it by hand; it is the entry for headless hosts. Read
392
+ * the document's resolved roster with `getReviewAuthors`. Applies wherever revision
393
+ * markup paints: the full all-markup view needs a review module registered; without one
394
+ * the proposed view still marks surviving insertions.
395
+ */
396
+ revisionStyles?: RevisionStyles;
397
+ /** Initial local revision presentation and tracking preferences. */
398
+ revisionMarkup?: RevisionMarkupOptions;
399
+ /** Initial review projection. Markup modes require a review module. */
400
+ reviewDisplayMode?: ReviewDisplayMode;
401
+ /**
402
+ * How the reader edits saved field results.
403
+ *
404
+ * - `'atomic'` (the DEFAULT) — every field is one unit: typing beside a field lands before
405
+ * or after it, and Backspace removes it whole.
406
+ * - `'editable'` — fields that show their saved result (DATE, TIME, MERGEFIELD, HYPERLINK
407
+ * display text, QUOTE, FILENAME, FILLIN, SEQ, and the save, print, and creation dates)
408
+ * accept typing, deletion, and selection inside the result. Fields the engine computes
409
+ * live (PAGE, NUMPAGES, REF, PAGEREF, DOCPROPERTY, and others) stay one unit.
410
+ *
411
+ * Editable results must be unnested. Simple fields inside complex field results are not
412
+ * supported in editable mode.
413
+ *
414
+ * Fixed for the instance. `'editable'` with a collaboration module throws a `TypeError`:
415
+ * shared paragraph text keeps every field one unit.
416
+ */
417
+ fieldResults?: FieldResultsMode;
418
+ /** Override raster decode for insert/replace image commands; defaults to browser/headless. */
419
+ imageDecodePort?: ImageDecodePort;
420
+ /**
421
+ * The scale to open at, as a fixed number.
422
+ *
423
+ * Supplying one also picks the mode: an editor given a `zoom` and no `zoomMode` opens
424
+ * FIXED at that value and stays there. An embedder that pinned 100% keeps 100%.
425
+ */
426
+ zoom?: number;
427
+ /**
428
+ * Where the scale comes from. Defaults to `'auto'` — fit the page width, between 50% and
429
+ * 100% — unless {@link DocxEditorConfig.zoom} is supplied, which means fixed.
430
+ *
431
+ * `'auto'` leaves a window wide enough for the sheet exactly where it is today and shrinks
432
+ * a narrower one instead of growing a horizontal scrollbar. Pass `{ type: 'fixed' }` for
433
+ * the old unconditional behaviour.
434
+ */
435
+ zoomMode?: ZoomMode | 'auto';
436
+ onFontError?: (error: EditorFontError) => void;
437
+ /** Localized labels for table insertion furniture on the painted surface. */
438
+ tableInteractionLabel?: (key: 'table.insertRowBelow' | 'table.insertColumnRight') => string;
439
+ }
440
+ /**
441
+ * Which measurer the current document's layout runs on, and whether shaped resolution is
442
+ * still in flight. Returned by {@link DocxEditorInstance.fontMeasurement}.
443
+ */
444
+ interface FontMeasurementState {
445
+ /** `fixed` estimates advance widths; `shaped` measures real font bytes with HarfBuzz. */
446
+ readonly measurer: 'fixed' | 'shaped';
447
+ /** True while font resolution for the current document is still running. */
448
+ readonly resolving: boolean;
449
+ /** The shaped measurer's identity (admitted face hashes); absent while fixed. */
450
+ readonly producer?: string;
451
+ }
452
+ /**
453
+ * The host chrome that answers the engine's hyperlink gestures.
454
+ *
455
+ * A CLICK on an external link and Ctrl/Cmd+K both mean "the user wants the link UI", and the
456
+ * engine deliberately does not know what that looks like. Registered rather than passed at
457
+ * construction because the chrome mounts after the editor does, and it survives a document
458
+ * reload — the surface is rebuilt, the handlers are not.
459
+ */
460
+ interface HyperlinkChromeHandlers {
461
+ /** A plain click on an external or inert link: show the popover at `activation.rect`. */
462
+ readonly onPopover?: (activation: HyperlinkActivation) => void;
463
+ /** Ctrl/Cmd+K: open insert-or-edit for the selection. */
464
+ readonly onRequest?: () => void;
465
+ }
466
+ /** Host chrome that edits a clicked Office Math equation. */
467
+ interface EquationChromeHandlers {
468
+ readonly onPopover?: (activation: EquationActivation) => void;
469
+ }
470
+ /**
471
+ * The concrete facade type: the full `Editor` contract plus the instance-only surface.
472
+ *
473
+ * `surface`, `stateVersion`, `attach` and `detach` live HERE rather than on `Editor`:
474
+ * they are what a store binding and a mounting host need, not what document commands
475
+ * need. Production adapters program against `Editor` for everything else.
476
+ */
477
+ interface DocxEditorInstance extends Editor {
478
+ /** Bumps on mount, detach, destroy, and document reload — guards async image intents. */
479
+ readonly mountGeneration: number;
480
+ /**
481
+ * The underlying paginated surface for harnesses and tests that need capabilities the
482
+ * contract does not carry yet (select-all, node-id addressed selection).
483
+ */
484
+ readonly surface: PaginatedSurface | null;
485
+ /**
486
+ * Wire the host's hyperlink chrome to the engine's gestures — a click on an external
487
+ * link, and Ctrl/Cmd+K. Returns an unsubscribe that restores whatever was registered
488
+ * before, so a popover component can register in an effect and clean up in its teardown.
489
+ *
490
+ * Instance-only, like `surface`: it is what a MOUNTING host needs, not what a document
491
+ * command needs.
492
+ */
493
+ setHyperlinkChrome(handlers: HyperlinkChromeHandlers): Unsubscribe;
494
+ /**
495
+ * Register local revision settings chrome. Disposal cancels its active sessions.
496
+ * Manual renderers take priority over fallback renderers. Pass null to use native chrome
497
+ * until disposal restores the previous registration.
498
+ */
499
+ setRevisionMarkupChrome(handlers: RevisionMarkupChromeHandlers | null, options?: PopupChromeRegistrationOptions): Unsubscribe;
500
+ /** Register Field Options chrome. Disposal closes sessions owned by this registration. */
501
+ setTextFormFieldChrome(handlers: TextFormFieldChromeHandlers, options?: PopupChromeRegistrationOptions): Unsubscribe;
502
+ /** Register typed content-control widget chrome. */
503
+ setContentControlWidgetChrome(handlers: ContentControlWidgetChromeHandlers, options?: PopupChromeRegistrationOptions): Unsubscribe;
504
+ /** Register invalid protected-field acknowledgement chrome. */
505
+ setInvalidTextFormFieldChrome(handlers: InvalidTextFormFieldChromeHandlers, options?: PopupChromeRegistrationOptions): Unsubscribe;
506
+ /** Wire the host equation popover to painted equation clicks. */
507
+ setEquationChrome(handlers: EquationChromeHandlers): Unsubscribe;
508
+ /**
509
+ * Render the host's own component as the remote-caret label, or restore the default
510
+ * collaborator-name label with `null`. The engine keeps owning label geometry, class,
511
+ * and presence colour; the host owns the content of each published element.
512
+ *
513
+ * Instance-only, like `setHyperlinkChrome`: it is what a MOUNTING host needs. Tolerated
514
+ * before `attach` and after `detach` — the registration waits and applies on the next
515
+ * mount, and it survives a document reload the way the hyperlink chrome does.
516
+ */
517
+ setRemoteCaretLabelHost(host: RemoteCaretLabelHost | null): void;
518
+ /**
519
+ * Render the host's own loading indicator on the first page while a large document lays out
520
+ * its remaining pages, or restore the packaged spinner with `null`. The engine keeps owning
521
+ * the element and its place on the page; the host owns its content.
522
+ *
523
+ * Instance-only, like `setRemoteCaretLabelHost`, and tolerated at any time: a host set
524
+ * before the open applies when the first pages show. `DocxEditor.Loading` with `overlay`
525
+ * registers one for you, so set this only when you build your own loading screen.
526
+ *
527
+ * @example
528
+ * ```ts
529
+ * editor.setOpeningIndicatorHost({
530
+ * publish(element) {
531
+ * element?.replaceChildren(document.createTextNode('Opening…'));
532
+ * },
533
+ * });
534
+ * ```
535
+ */
536
+ setOpeningIndicatorHost(host: OpeningIndicatorHost | null): void;
537
+ /**
538
+ * Monotonic version of the observable editor state. Bumps whenever anything
539
+ * `snapshot()` reports could have moved — a committed change, a selection move, zoom,
540
+ * load success or failure, attach/detach, destroy. An external store (React's
541
+ * `useSyncExternalStore`) uses it as a cheap "did anything change" signal; `snapshot()`
542
+ * itself is cached per version and returns a stable reference between bumps.
543
+ */
544
+ stateVersion(): number;
545
+ /**
546
+ * Which measurer the current document's layout runs on, and whether shaped
547
+ * resolution is still in flight — the honest "are wrap points Word-accurate yet?"
548
+ * readout a host shows instead of guessing. `fixed` with `resolving: false` is the
549
+ * steady state for a document with no usable font source (the documented zero-config
550
+ * fallback); `shaped` means HarfBuzz measurement over real font bytes. Changes bump
551
+ * `stateVersion()`.
552
+ */
553
+ fontMeasurement(): FontMeasurementState;
554
+ /**
555
+ * Every author the review surface DRAWS, in Word's slot order, with the colour the review
556
+ * chrome draws them in. The discovery surface a legend or colour picker builds on —
557
+ * authors depend on the loaded file, so they cannot be known at configuration time.
558
+ *
559
+ * The colour is the author's, not the document's: under `'kind'` the painted text goes to
560
+ * the insertion/deletion colours while the cards keep these accents, so a legend built
561
+ * from this describes the rail rather than the page.
562
+ *
563
+ * BOTH HALVES OF REVIEW. Authors of tracked changes come first, numbered by where their
564
+ * first change appears; authors who only commented follow. One person therefore draws in
565
+ * one colour across their comments and their edits, which is what a reader assumes the
566
+ * moment they learn the pairing on either. The order puts commenters last so that adding
567
+ * a comment can never renumber a tracked change the painter has already drawn.
568
+ *
569
+ * The complete attached-document roster. A reviewer remains listed while this view hides
570
+ * their changes, so the reviewer menu can turn them on again. Empty while detached.
571
+ * Reference-stable between changes, so it is safe as a dependency; changes bump
572
+ * `stateVersion()`.
573
+ */
574
+ getReviewAuthors(): readonly ReviewAuthorInfo[];
575
+ /** Whether this author's revisions and comments are shown in the current review view. */
576
+ isReviewAuthorVisible(author: string): boolean;
577
+ /**
578
+ * Show one author's markup, or render their revisions as accepted and hide their comments.
579
+ * This changes view state only. It does not apply tree operations or change saved bytes.
580
+ */
581
+ setReviewAuthorVisible(author: string, visible: boolean): void;
582
+ /** Show or hide every reviewer in one layout pass. */
583
+ setAllReviewAuthorsVisible(visible: boolean): void;
584
+ /** Restore every reviewer to the shown state. */
585
+ showAllReviewAuthors(): void;
586
+ /**
587
+ * The presence colour the engine paints for one display name — the answer the remote
588
+ * caret label takes, so chrome built on this cannot disagree with the painted caret.
589
+ *
590
+ * A name the review roster draws takes its resolved colour, sanitized exactly as the
591
+ * paint sink sanitizes it: a declared colour the paint refuses falls to the author's
592
+ * ramp-slot token. Any other name takes the next slot from the engine's stable
593
+ * allocator, in first-resolution order, and keeps it for the session. While no document
594
+ * is attached this returns `'var(--doc-accent)'`, the same default the overlay CSS
595
+ * falls back to.
596
+ */
597
+ presenceColorFor(name: string): string;
598
+ /**
599
+ * The live collaboration replica, or null when this editor is not in a room.
600
+ *
601
+ * Presence chrome reads it from here rather than being handed it: the editor already holds
602
+ * the session a `collaborationModule` contributed, so a host that threads it down to every
603
+ * avatar and caret consumer is passing something the tree below it can already see.
604
+ */
605
+ collaborationSession(): EditorCollaborationSession | null;
606
+ /**
607
+ * The configured author used when a comment or reply omits an explicit author.
608
+ *
609
+ * @internal Review compose chrome uses this to draw an unfinished comment in the same
610
+ * author colour it will receive after commit.
611
+ */
612
+ getConfiguredAuthor(): string | null;
613
+ /**
614
+ * Set the author for runtime editor state.
615
+ *
616
+ * Unlike the construction-time {@link DocxEditorConfig.author}, this value applies to every
617
+ * later comment, reply, and tracked change. It does not rewrite existing revisions. The value
618
+ * survives document reloads and font remounts. An empty or whitespace value clears the author,
619
+ * after which suggesting refuses writes with its existing reason.
620
+ *
621
+ * Naming an author also completes a request for suggesting that was refused for want of
622
+ * one — a `mode: 'suggesting'` or a document's `w:trackRevisions` that opened in editing —
623
+ * unless the reader has chosen a mode since.
624
+ *
625
+ * @public
626
+ */
627
+ setAuthor(author: string | undefined): void;
628
+ /**
629
+ * Set the host editing mode without rebuilding the editor.
630
+ *
631
+ * This has the same meaning as {@link DocxEditorConfig.mode}. Passing `undefined` lets the
632
+ * document's tracking settings select the mode again. A host change clears the reader's
633
+ * toolbar choice, so a later document reload can adopt `w:trackRevisions` again.
634
+ *
635
+ * @public
636
+ */
637
+ setMode(mode: 'edit' | 'view' | 'suggesting' | undefined): void;
638
+ /**
639
+ * Set the drawing and form-control label resolver without rebuilding the editor.
640
+ * Open dialogs preserve their controls and input; later surface mounts use the same resolver.
641
+ *
642
+ * @public
643
+ */
644
+ setTranslate(translate: ((key: string, params?: Record<string, string | number>) => string) | undefined): void;
645
+ /**
646
+ * Set regional date input and generated labels without rebuilding the editor.
647
+ * Stored dates are preserved; an in-progress field edit retains its starting locale.
648
+ * Omitted, invalid, and unsupported locales use en-US. Translation catalogues fall back by language.
649
+ *
650
+ * @public
651
+ */
652
+ setLocale(locale: string | undefined): void;
653
+ /**
654
+ * The style declared for one author, whether or not the SURFACE has published them yet —
655
+ * so review chrome can draw a card the rail is holding before the roster catches up.
656
+ *
657
+ * {@link DocxEditorInstance.getReviewAuthors} answers for every author of a tracked
658
+ * change or a comment, so this is a narrow fallback rather than the way to reach a
659
+ * commenter.
660
+ *
661
+ * @internal The seam `@docx-editor.dev/pro`'s review rail resolves those authors
662
+ * through. A consumer reads `useReviewAuthor` (pro) or `useReviewAuthors` (react)
663
+ * instead; nothing here answers a question those two do not.
664
+ */
665
+ getReviewAuthorStyle(author: string): RevisionAuthorStyle | undefined;
666
+ /**
667
+ * Replace how tracked changes are coloured, live. Paint-level: pages repaint without a
668
+ * layout pass, and the caret, selection and undo history stay where they are. Pass
669
+ * `'author'` to restore the default, or `'kind'` to opt out to the green/red
670
+ * rendering. Survives a document reload.
671
+ *
672
+ * The imperative PRIMITIVE beneath React's declarative lane: `DocxEditor.ColorByChangeType`
673
+ * and `DocxEditor.AuthorStyle` drive this seam, and React hosts declare those instead
674
+ * of calling it. Call it directly from headless and non-React hosts.
675
+ */
676
+ setRevisionStyles(styles: RevisionStyles): void;
677
+ /** Merge local preferences and emit revisionMarkupChange after a change.
678
+ * Invalid settings throw TypeError without changing the previous settings.
679
+ */
680
+ setRevisionMarkup(options: RevisionMarkupOptions): void;
681
+ /**
682
+ * Change the review pane settings: every field of `ReviewPaneOptions`, such as when the
683
+ * pane opens by itself and what it does when its card column does not fit. An omitted
684
+ * field keeps its value. Read the settings in force
685
+ * from `snapshot().reviewPane`. They stay in force across `load()` and are never saved into
686
+ * the document. This sets how the pane behaves; to open or close the pane itself, use
687
+ * `useReview().setPaneOpen` or the `toggleReviewPane` command.
688
+ *
689
+ * Returns `changed: false` on success, like every view-only call, because `changed` answers
690
+ * for the document; to detect a settings change, compare the `snapshot().reviewPane`
691
+ * reference, which changes only when a setting changes. Refused with `unsupported` when no review module is registered, and
692
+ * with `invalidArgs` for an unknown field or value. A refusal changes nothing.
693
+ *
694
+ * @example
695
+ * ```ts
696
+ * const result = editor.setReviewPaneOptions({ opening: 'manual', overflow: 'shrinkPage' });
697
+ * if (!result.ok) console.warn(result.reason);
698
+ * ```
699
+ */
700
+ setReviewPaneOptions(options: ReviewPaneOptions): ExecResult;
701
+ /**
702
+ * Mount into `el`. If the instance holds pending document bytes (created without a
703
+ * container, or previously detached), they mount now — under the shaped measurer when
704
+ * fonts have resolved in the meantime. Attaching while already mounted elsewhere moves
705
+ * the live content via `session.save()`.
706
+ *
707
+ * HONEST COSTS: a mount from bytes is a fresh session — the undo stack and the caret do
708
+ * not survive re-attach (the same cost as the async font remount). After `destroy()`
709
+ * this is a no-op that emits a typed `error` event: a destroyed instance never remounts.
710
+ */
711
+ attach(el: HTMLElement): void;
712
+ /**
713
+ * Tear down the painted surface, stashing the CURRENT document bytes
714
+ * (`session.save()`) so a later `attach` restores the content — but not the undo stack
715
+ * or the caret. No-op when already detached or destroyed.
716
+ */
717
+ detach(): void;
718
+ }
719
+
720
+ /** Which of the eight resize handles a drag started from, by compass direction. */
721
+ type ImageResizeHandle = 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw';
722
+ /** EMUs per point. DrawingML stores extents in EMU; layout works in points. */
723
+ declare const EMU_PER_POINT = 12700;
724
+ /** Points to EMU, rounded — EMUs are integral in the file. */
725
+ declare function pointsToEmu(points: number): number;
726
+ /** EMU to points. Unrounded, so overlay geometry keeps sub-point precision during a drag. */
727
+ declare function emuToOverlayPoints(emu: number): number;
728
+ /**
729
+ * The extent a resize drag produces, in EMU.
730
+ *
731
+ * Computed from the drag's START extent rather than the previous frame's, so a drag that reverses
732
+ * direction lands exactly where it began instead of accumulating rounding error.
733
+ *
734
+ * `preserveAspect` behaves the way Word's handles do: a corner handle scales by whichever axis
735
+ * moved further, while an edge handle drives the other axis from the original ratio. Both axes
736
+ * are floored at one point, so a drag past the opposite edge cannot invert the image.
737
+ */
738
+ declare function computeResizedImageExtentEmu(startWidthEmu: number, startHeightEmu: number, handle: ImageResizeHandle, deltaWidthPt: number, deltaHeightPt: number, preserveAspect: boolean): {
739
+ readonly cx: number;
740
+ readonly cy: number;
741
+ };
742
+ /**
743
+ * The position a move drag produces, preserving the anchoring the file already used.
744
+ *
745
+ * A `frame`-mode position keeps its `relativeToH`/`relativeToV` bases and only shifts the offsets
746
+ * it actually had — writing an offset the file omitted would re-anchor the drawing to a different
747
+ * reference and move it somewhere the drag never pointed.
748
+ */
749
+ declare function computeMovedImagePosition(start: DrawingPositionInput, deltaXPt: number, deltaYPt: number): DrawingPositionInput;
750
+
751
+ type ImageMutationPreconditions = Readonly<{
752
+ mountGeneration: number;
753
+ packageRevision: number;
754
+ drawingNodeId: string | null;
755
+ selectionParagraphId: string;
756
+ selectionOffset: number;
757
+ }>;
758
+ /**
759
+ * The selected image and what may be done to it, or null when nothing image-like is selected.
760
+ *
761
+ * Unsupported placeholders, hidden drawings, and select-locked drawings cannot be selected.
762
+ */
763
+ declare function selectedImageStateOf(surface: PaginatedSurface | null): SelectedImageState | null;
764
+ /**
765
+ * Snapshot the state an image mutation was planned against: mount generation, package revision,
766
+ * and the selection anchor.
767
+ *
768
+ * Taken at the START of a drag so the commit can be checked against it with
769
+ * {@link isStaleImageInteractionCommit}. A pointer gesture spans many frames, and a document that
770
+ * moved underneath it must not have the gesture's final coordinates applied to it.
771
+ */
772
+ declare function captureImageMutationPreconditions(editor: Pick<DocxEditorInstance, 'surface' | 'mountGeneration'>): ImageMutationPreconditions | null;
773
+ /**
774
+ * Whether an insert or replace would be accepted — the `can` half of the can-before-exec pair.
775
+ *
776
+ * Refuses in suggesting mode, since an image property edit has no tracked-change representation.
777
+ */
778
+ declare function canExecuteImageCommand(command: Extract<EditorCommand, {
779
+ type: 'insertImage' | 'replaceImage';
780
+ }>, surface: PaginatedSurface | null): CanResult;
781
+ /**
782
+ * Run an insert or replace, re-checking the same gates {@link canExecuteImageCommand} applies.
783
+ *
784
+ * Async because image bytes must be decoded to derive their natural extent before the drawing can
785
+ * be projected — the one editor command that cannot complete synchronously.
786
+ */
787
+ declare function executeImageCommand(editor: DocxEditorInstance, command: Extract<EditorCommand, {
788
+ type: 'insertImage' | 'replaceImage';
789
+ }>): Promise<ExecResult>;
790
+ /** How far one arrow-key press nudges a selected image, in points. */
791
+ declare const IMAGE_OVERLAY_NUDGE_PT = 1;
792
+ /** How far Shift+arrow nudges a selected image, in points. */
793
+ declare const IMAGE_OVERLAY_NUDGE_SHIFT_PT = 10;
794
+ /**
795
+ * One in-flight image drag: where it started, and everything needed to decide at commit time
796
+ * whether the document still describes what the gesture was planned against.
797
+ *
798
+ * Both revisions are captured because they move independently — layout can re-flow without the
799
+ * package changing, and vice versa.
800
+ */
801
+ interface ImageInteractionSession {
802
+ readonly drawingNodeId: string;
803
+ readonly startBounds: {
804
+ readonly x: number;
805
+ readonly y: number;
806
+ readonly width: number;
807
+ readonly height: number;
808
+ };
809
+ readonly startWidthEmu: number;
810
+ readonly startHeightEmu: number;
811
+ readonly startPosition: DrawingPositionInput | null;
812
+ readonly anchorFrameOrigin: {
813
+ readonly x: number;
814
+ readonly y: number;
815
+ } | null;
816
+ readonly transform: DrawingTransform;
817
+ readonly mode: 'move' | 'resize';
818
+ readonly handle: ImageResizeHandle | null;
819
+ readonly preconditions: ImageMutationPreconditions;
820
+ readonly layoutRevision: number;
821
+ readonly packageRevision: number;
822
+ readonly kind: 'inline' | 'anchored';
823
+ }
824
+ /**
825
+ * How an image drag scrolls the page when it reaches the viewport edge.
826
+ *
827
+ * Returns the delta ACTUALLY applied rather than the one requested, because a drag at the end of
828
+ * the document cannot scroll further and the overlay must not move the image by a distance the
829
+ * page did not travel.
830
+ */
831
+ interface ImageOverlayScrollPort {
832
+ /** Scroll by a preview delta and return the actual applied document-space delta in points. */
833
+ scrollBy(deltaY: number): number;
834
+ }
835
+ /**
836
+ * The painted geometry of the selected drawing, plus what the overlay is allowed to do to it.
837
+ *
838
+ * Carries BOTH the painted rect (points, for hit-testing and handle placement) and the stored
839
+ * extent (EMU, for writing back), so the overlay never has to convert between the two spaces to
840
+ * decide what it is looking at.
841
+ */
842
+ interface SelectedDrawingOverlayTarget {
843
+ /** Keep the text area available for pointer editing through the frame. */
844
+ readonly textbox?: boolean;
845
+ readonly id: string;
846
+ readonly pageIndex: number;
847
+ readonly x: number;
848
+ readonly y: number;
849
+ readonly width: number;
850
+ readonly height: number;
851
+ readonly kind: 'inline' | 'anchored';
852
+ readonly widthEmu: number;
853
+ readonly heightEmu: number;
854
+ readonly position: DrawingPositionInput | null;
855
+ readonly anchorFrameOrigin: {
856
+ readonly x: number;
857
+ readonly y: number;
858
+ } | null;
859
+ readonly transform: DrawingTransform;
860
+ readonly canResize: boolean;
861
+ readonly canMove: boolean;
862
+ /** Hard lock from `noChangeAspect` — never overridden by Shift. */
863
+ readonly aspectLocked: boolean;
864
+ }
865
+ /**
866
+ * The painted geometry of the selected drawing, for the resize/move overlay — or null.
867
+ *
868
+ * Stricter than {@link selectedImageStateOf}: it also requires a COLLAPSED selection, because a
869
+ * range that merely contains a drawing is a text selection, and drawing handles over it would
870
+ * claim an object the user did not single out.
871
+ */
872
+ declare function selectedDrawingOverlayTargetOf(surface: PaginatedSurface | null): SelectedDrawingOverlayTarget | null;
873
+ /**
874
+ * Whether a drag's commit should be refused because the document moved under it — the refusal to
875
+ * return, or null when the commit is still valid.
876
+ *
877
+ * Checks the mount generation and both revisions captured by
878
+ * {@link captureImageMutationPreconditions}. A gesture spans many frames, so this is the one
879
+ * place that decides its coordinates still describe the document they were measured against.
880
+ */
881
+ declare function isStaleImageInteractionCommit(editor: Pick<DocxEditorInstance, 'surface' | 'mountGeneration'>, session: ImageInteractionSession): ExecResult | null;
882
+
883
+ /** Points → CSS pixels at the given zoom (matches `mountPaginatedSurface` / semantic paint). */
884
+ declare function surfacePaintScale(zoom: number): number;
885
+ /** Layout points to CSS pixels. Pair with {@link surfacePaintScale} for the current zoom. */
886
+ declare function layoutPointsToCssPixels(points: number, paintScale: number): number;
887
+ /** CSS pixels back to layout points — what a pointer event's coordinates must go through. */
888
+ declare function cssPixelsToLayoutPoints(pixels: number, paintScale: number): number;
889
+ /**
890
+ * What an overlay needs to place itself over the painted pages: the zoom scale, and where each
891
+ * page sits horizontally.
892
+ *
893
+ * Per-page X offsets rather than one origin, because pages are centred independently and a
894
+ * narrower page in a mixed-size document does not start where its neighbours do.
895
+ */
896
+ interface SurfaceOverlayCoordinates {
897
+ readonly paintScale: number;
898
+ readonly pageOffsetX: ReadonlyMap<number, number>;
899
+ }
900
+ /** A rectangle in one page's content frame, in layout points. */
901
+ interface OverlayFrameRect {
902
+ readonly pageIndex: number;
903
+ readonly x: number;
904
+ readonly y: number;
905
+ readonly width: number;
906
+ readonly height: number;
907
+ }
908
+ /** Page-content frame → sheet-space CSS pixels (matches `paintSelectionOverlay`). */
909
+ declare function overlayFrameToSheetCssPixels(layout: SemanticLayout, frame: OverlayFrameRect, coordinates: SurfaceOverlayCoordinates): {
910
+ readonly left: number;
911
+ readonly top: number;
912
+ readonly width: number;
913
+ readonly height: number;
914
+ };
915
+ /**
916
+ * Where the painted surface's box begins inside overlay chrome's containing block, in CSS pixels.
917
+ *
918
+ * {@link overlayFrameToSheetCssPixels} produces coordinates relative to the surface element —
919
+ * the box the pages paint into — but overlay chrome portals OUTSIDE that element, and its
920
+ * absolutely positioned pieces resolve against the nearest positioned ancestor. The surface
921
+ * centres itself inside that ancestor with a stylesheet margin, so a frame placed without this
922
+ * origin lands at the far left of the viewport, one full centring margin off the image it rings.
923
+ * `offsetLeft`/`offsetTop` measure against the same positioned ancestor the chrome resolves
924
+ * against — every element between the two is static — which is what makes the two spaces agree.
925
+ */
926
+ declare function overlayHostOrigin(surfaceElement: HTMLElement | null): {
927
+ readonly left: number;
928
+ readonly top: number;
929
+ };
930
+ /** Whether this handle drag should preserve aspect ratio. */
931
+ declare function resizePreservesAspect(handle: ImageResizeHandle, aspectLocked: boolean, shiftKey: boolean, textbox?: boolean): boolean;
932
+ /**
933
+ * Where an anchored drawing's positioning frame begins, in layout points.
934
+ *
935
+ * An anchored drawing's offsets are relative to a base the file names (page, margin, column, …),
936
+ * so a move drag needs that base's origin to turn a pointer delta into a stored offset.
937
+ */
938
+ interface AnchorFrameOrigin {
939
+ readonly x: number;
940
+ readonly y: number;
941
+ }
942
+ /**
943
+ * One resize frame: the extent to store, and the box to draw while the pointer is still down.
944
+ *
945
+ * Both, because they are different spaces — the extent is EMU for the file, the preview is
946
+ * points for the overlay — and computing them separately would let the handle drift from the
947
+ * rectangle it is dragging.
948
+ */
949
+ interface ImageResizeResult {
950
+ readonly widthEmu: number;
951
+ readonly heightEmu: number;
952
+ readonly previewBounds: {
953
+ readonly x: number;
954
+ readonly y: number;
955
+ readonly width: number;
956
+ readonly height: number;
957
+ };
958
+ readonly position: DrawingPositionInput | null;
959
+ }
960
+ /**
961
+ * Resolve one resize frame from the pointer's current position.
962
+ *
963
+ * Handles rotation and flips by mapping the SCREEN-space handle back to the drawing's local axes
964
+ * first: dragging the visually-right handle of a 90°-rotated image must change its stored height,
965
+ * and a flipped image's handles move in the opposite direction from where they appear.
966
+ */
967
+ declare function computeImageResizeResult(options: {
968
+ readonly handle: ImageResizeHandle;
969
+ readonly startWidthEmu: number;
970
+ readonly startHeightEmu: number;
971
+ readonly startBounds: {
972
+ readonly x: number;
973
+ readonly y: number;
974
+ readonly width: number;
975
+ readonly height: number;
976
+ };
977
+ readonly startPosition: DrawingPositionInput | null;
978
+ readonly anchorFrameOrigin?: AnchorFrameOrigin | null;
979
+ readonly deltaXPt: number;
980
+ readonly deltaYPt: number;
981
+ readonly transform: DrawingTransform;
982
+ readonly preserveAspect: boolean;
983
+ readonly kind: 'inline' | 'anchored';
984
+ }): ImageResizeResult;
985
+ /**
986
+ * An {@link ImageOverlayScrollPort} over a real scroll container.
987
+ *
988
+ * Reports the delta the element ACTUALLY scrolled, converted back to points — at the end of the
989
+ * document that is less than asked for, and the overlay must not move the image further than the
990
+ * page travelled.
991
+ */
992
+ declare function createImageOverlayScrollPort(scroller: HTMLElement, paintScale: number): {
993
+ scrollBy(deltaYPoints: number): number;
994
+ };
995
+ /**
996
+ * The committed result of a whole drag, recomputed from the release coordinates.
997
+ *
998
+ * Recomputed rather than accumulated from the per-frame previews, so rounding applied once per
999
+ * frame cannot add up into a final extent that differs from where the pointer actually stopped.
1000
+ */
1001
+ interface FinalizedImageOverlayInteraction extends ImageResizeResult {
1002
+ readonly position: DrawingPositionInput | null;
1003
+ }
1004
+ /** Recompute the committed overlay result from release pointer coordinates. */
1005
+ declare function finalizeImageOverlayInteraction(options: {
1006
+ readonly session: ImageInteractionSession;
1007
+ readonly deltaXPt: number;
1008
+ readonly deltaYPt: number;
1009
+ readonly accumulatedScrollPt: number;
1010
+ readonly aspectLocked: boolean;
1011
+ readonly shiftKey: boolean;
1012
+ readonly textbox?: boolean;
1013
+ readonly anchorFrameOrigin: AnchorFrameOrigin | null;
1014
+ }): FinalizedImageOverlayInteraction;
1015
+
1016
+ /**
1017
+ * How a section-addressed op should name the section a caret is in.
1018
+ *
1019
+ * `w:sectPr` lives on the body story, so the op can only name BODY content — and a caret in a
1020
+ * header or a note is not body content. The three answers are genuinely different, and
1021
+ * collapsing them to "a paragraph or `null`" is what let an unaddressable section quietly
1022
+ * become a document-wide write.
1023
+ */
1024
+ type SectionAnchor =
1025
+ /** Name this body paragraph. Its section is the one the caret is in. */
1026
+ {
1027
+ readonly kind: 'anchor';
1028
+ readonly paragraphId: string;
1029
+ }
1030
+ /** One section: an anchor names nothing extra, so the op may omit it. */
1031
+ | {
1032
+ readonly kind: 'whole-document';
1033
+ }
1034
+ /**
1035
+ * Several sections, and the caret's holds no paragraph to name.
1036
+ *
1037
+ * An omitted anchor here would write EVERY section, which is what `scope: 'document'` is
1038
+ * for — so answering it to a `scope: 'section'` request changes sections nobody asked
1039
+ * about. There is no anchor that reaches an empty final section: one exists only when every
1040
+ * paragraph already closes an earlier section, so nothing sits at or after it.
1041
+ */
1042
+ | {
1043
+ readonly kind: 'unaddressable';
1044
+ };
1045
+
1046
+ /**
1047
+ * What a host may set on a surface image insert.
1048
+ *
1049
+ * The decode port and the collaboration actor are the SURFACE's to supply. An actor a host
1050
+ * could pass would be a second identity for the same mint, which is the thing actor-scoped
1051
+ * allocation exists to prevent.
1052
+ */
1053
+ type SurfaceInsertImageInput = Omit<InsertImageInput, 'decodePort' | 'actorId'>;
1054
+
1055
+ /**
1056
+ * Every field of the Paragraph dialog, in the units the rest of this contract uses:
1057
+ * points for spacing, TWIPS for indents.
1058
+ *
1059
+ * An omitted field is left as authored. Where `null` is allowed it REMOVES the setting,
1060
+ * which is not the same as writing a zero — a zero blocks the cascade, a removal lets the
1061
+ * style through again.
1062
+ */
1063
+ interface SurfaceParagraphFormat {
1064
+ readonly alignment?: 'left' | 'center' | 'right' | 'both';
1065
+ /** Base direction; see `directionalParagraphEntry` for what each value writes. */
1066
+ readonly direction?: 'ltr' | 'rtl';
1067
+ readonly spaceBeforePt?: number | null;
1068
+ readonly spaceAfterPt?: number | null;
1069
+ readonly lineSpacing?: {
1070
+ readonly rule: 'multiple' | 'exact' | 'atLeast';
1071
+ readonly value: number;
1072
+ } | null;
1073
+ readonly indentLeftTwips?: number | null;
1074
+ readonly indentRightTwips?: number | null;
1075
+ /** ONE signed first-line offset: negative is a hanging indent (§17.3.1.12). */
1076
+ readonly indentFirstLineTwips?: number | null;
1077
+ readonly contextualSpacing?: boolean;
1078
+ readonly keepNext?: boolean;
1079
+ readonly keepLines?: boolean;
1080
+ readonly widowControl?: boolean;
1081
+ readonly pageBreakBefore?: boolean;
1082
+ /**
1083
+ * Replace the paragraph's custom tab stops. An empty list CLEARS them, which is what Word's
1084
+ * "Clear All" does; omit the field to leave them as authored.
1085
+ */
1086
+ readonly tabStops?: readonly ParagraphTabStop[];
1087
+ }
1088
+ /** One property in a batched paragraph write. */
1089
+ interface ParagraphPropertyEdit {
1090
+ readonly localName: string;
1091
+ /** A null-valued attribute REMOVES that attribute; see `setParagraphProperty`. */
1092
+ readonly attributes?: Record<string, string | null>;
1093
+ /** Keep the attributes this entry does not name, for multi-setting elements. */
1094
+ readonly mergeAttributes?: boolean;
1095
+ /**
1096
+ * For `w:jc` only: `attributes.val` names a PHYSICAL edge, as a toolbar button does. The
1097
+ * writer converts it per paragraph, because a bidi paragraph reaches its right margin
1098
+ * with `left` (see `jcValueForAlignment`).
1099
+ */
1100
+ readonly physicalAlignment?: boolean;
1101
+ /**
1102
+ * For `w:bidi` only: the base direction the paragraph must END in. The writer spells it per
1103
+ * paragraph and skips one already in that direction (see `directionalParagraphEntry`).
1104
+ */
1105
+ readonly paragraphDirection?: 'ltr' | 'rtl';
1106
+ /** Drop the paragraph's own element of this name instead of writing one. */
1107
+ readonly remove?: boolean;
1108
+ }
1109
+
1110
+ /**
1111
+ * Which review write is being committed through `commitReviewOps`.
1112
+ *
1113
+ * The callback that performs the write is opaque, so a lane deciding whether to allow it cannot
1114
+ * tell an Accept from a comment delete. That mattered once a replica was attached: these paths
1115
+ * reach the store directly rather than through `applyTreeOps`, and the ones that graft a package
1116
+ * and swap the shell record no primitive effects — they replicate as NOTHING, leaving the peer a
1117
+ * `commentReference` naming a comment it never received. Naming the write lets each be admitted
1118
+ * only once a two-replica test proves it arrives whole.
1119
+ */
1120
+ type ReviewWriteIntent = 'revision-resolve' | 'revision-attribution' | 'comment-add' | 'comment-reply' | 'comment-resolve' | 'comment-delete' | 'package-scoped';
1121
+
1122
+ /**
1123
+ * Everything an overlay needs to paint over one rendered frame of the surface.
1124
+ *
1125
+ * `pages` is the materialized page set (absent when every page is built), and `scale` and
1126
+ * `pageOffsetX` are the values the page painter used, so overlay geometry lands on the text.
1127
+ */
1128
+ interface SurfaceOverlayFrame {
1129
+ readonly layer: HTMLElement;
1130
+ readonly layout: SemanticLayout;
1131
+ readonly revision: number;
1132
+ readonly scale: number;
1133
+ readonly pages?: ReadonlySet<number>;
1134
+ readonly pageOffsetX?: ReadonlyMap<number, number>;
1135
+ readonly measurer?: TextMeasurer;
1136
+ }
1137
+ /** A painter the surface calls after every render, and on request. */
1138
+ type SurfaceOverlayPainter = (frame: SurfaceOverlayFrame) => void;
1139
+
1140
+ /**
1141
+ * Content-control interaction lane on the paginated surface.
1142
+ *
1143
+ * Chrome toggles are surface state; value / remove commit through tree ops.
1144
+ */
1145
+ interface ContentControlOps {
1146
+ /** Toggle show-all boundary chrome. No layout reflow. */
1147
+ setShowAll(show: boolean): void;
1148
+ /** Toggle form-fill Tab navigation mode. */
1149
+ setFormFill(active: boolean): void;
1150
+ /** Whether show-all chrome is on. */
1151
+ showAll(): boolean;
1152
+ /** Whether form-fill navigation is on. */
1153
+ formFill(): boolean;
1154
+ /** Innermost control at the caret from layout boundary records. */
1155
+ atCaret(): ContentControlBoundaryRecord | null;
1156
+ /**
1157
+ * Move to the next or previous editable control (tabIndex, then document order).
1158
+ *
1159
+ * Skips content-locked and bound controls. Selects the control's content for replacement.
1160
+ * Returns whether navigation landed somewhere.
1161
+ */
1162
+ navigate(direction: 'next' | 'previous'): boolean;
1163
+ /**
1164
+ * Set a control's value through `setContentControlValue`. Honours lock / bound refusals.
1165
+ * Returns whether the op committed.
1166
+ */
1167
+ setValue(controlId: string, value: string): boolean;
1168
+ /**
1169
+ * Unwrap a control keeping its content (`removeContentControl`). Defaults to the control
1170
+ * at the caret. Returns whether the op committed.
1171
+ */
1172
+ remove(controlId?: string): boolean;
1173
+ /**
1174
+ * Engine reason a widget or remove action is disabled, or null when allowed.
1175
+ *
1176
+ * `edit` covers content / value changes; `remove` covers unwrap.
1177
+ */
1178
+ disabledReason(controlId: string, action: 'edit' | 'remove'): string | null;
1179
+ }
1180
+ /**
1181
+ * Content-control chrome the surface owns, not the document.
1182
+ *
1183
+ * Boundary furniture visibility and form-fill navigation are surface chrome, not model
1184
+ * bytes — toggling them never reflows layout records.
1185
+ */
1186
+ interface ContentControlSurfaceState {
1187
+ /** Show boundary chrome for every control. */
1188
+ readonly showAll: boolean;
1189
+ /** Tab / Shift+Tab navigate between editable controls. */
1190
+ readonly formFill: boolean;
1191
+ /** Innermost control containing the caret, or null. */
1192
+ readonly activeControlId: string | null;
1193
+ }
1194
+
1195
+ /**
1196
+ * What one paint did.
1197
+ *
1198
+ * Four answers rather than a boolean, because the two FAILURES are different problems with
1199
+ * different words for the user: `'nothingToPaint'` says the selection holds nothing the
1200
+ * capture can reach, and `'refused'` says the document would not take the write — a locked
1201
+ * content control, a collaboration gate, a document open for viewing. Collapsed to false,
1202
+ * a refused paint told the reader to select some text.
1203
+ *
1204
+ * `'armed'` is the collapsed-caret outcome: no text to paint, so the character half went to
1205
+ * the stored-marks lane and the next characters typed will carry it.
1206
+ */
1207
+ type FormatPainterPaintResult = 'painted' | 'armed' | 'nothingToPaint' | 'refused';
1208
+ /** Word's Format Painter over the surface. */
1209
+ interface FormatPainterOps {
1210
+ state(): FormatPainterSurfaceState;
1211
+ /**
1212
+ * Capture the formatting at the selection. False when the selection resolves to no span
1213
+ * the layout has published yet — there is nothing to read.
1214
+ */
1215
+ capture(): boolean;
1216
+ /** Paint the captured formatting over the current selection. */
1217
+ apply(): FormatPainterPaintResult;
1218
+ /**
1219
+ * One press of the painter control, with Word's meaning.
1220
+ *
1221
+ * A press while the painter is off captures and arms it for a single application. A press
1222
+ * that lands within the double-press window locks it on. A press while it is armed and
1223
+ * outside that window turns it off.
1224
+ *
1225
+ * The double-press window is the ENGINE's, deliberately: the alternative is each adapter
1226
+ * binding its own `dblclick` beside its own `click`, which is two hosts deciding
1227
+ * separately what a double-click means and drifting the moment one of them changes.
1228
+ *
1229
+ * False when there was nothing at the selection to capture, so a control can report a
1230
+ * refusal rather than looking as though it armed.
1231
+ */
1232
+ press(): boolean;
1233
+ /** Turn the painter off, keeping the capture. `Esc` and a finished single application. */
1234
+ disarm(): void;
1235
+ }
1236
+
1237
+ /**
1238
+ * Where the last pass spent its time, and how much work it actually did.
1239
+ *
1240
+ * The durations are the surface's own three phases — layout, paint, selection sync — timed
1241
+ * separately because they fail separately: a full relayout, a full repaint and a forced
1242
+ * reflow each have a different fix. The counters come free from machinery that already
1243
+ * exists: the layout session says how much was re-placed versus reused, and the scheduler
1244
+ * says how often work was thrown away as stale. `placed` equal to `total` on every
1245
+ * keystroke is the one-glance sign that incremental layout is not engaging.
1246
+ */
1247
+ interface PaginatedSurfacePerf {
1248
+ /** Time the last layout pass took, in milliseconds. */
1249
+ readonly layoutMs: number;
1250
+ /** Time the last paint took — building and swapping the page DOM. */
1251
+ readonly paintMs: number;
1252
+ /** Time the last selection sync took — writing the model selection into the browser. */
1253
+ readonly selectionMs: number;
1254
+ /** Paragraphs the last pass re-placed, against the number in the document. */
1255
+ readonly placed: number;
1256
+ readonly total: number;
1257
+ /** Pages carried over from the previous layout without being rebuilt. */
1258
+ readonly reusedPages: number;
1259
+ /** Passes that could not resume and laid the document out from the top. */
1260
+ readonly fullPasses: number;
1261
+ /** Layouts discarded because the model had already moved on. */
1262
+ readonly staleDiscards: number;
1263
+ /** Cooperative runs abandoned mid-flight for a newer revision. */
1264
+ readonly cancelledRuns: number;
1265
+ }
1266
+
1267
+ /**
1268
+ * One live remote-caret label the engine positioned. The host owns its content; the engine
1269
+ * still owns the label's geometry, class, and presence colour, and rebuilds the labels
1270
+ * wholesale on every repaint that moves them.
1271
+ *
1272
+ * @public
1273
+ */
1274
+ interface RemoteCaretLabelAnchor {
1275
+ readonly element: HTMLElement;
1276
+ readonly selection: CollaborationRemoteSelection;
1277
+ }
1278
+ /**
1279
+ * A host that renders its own content inside the engine's remote-caret labels.
1280
+ *
1281
+ * @public
1282
+ */
1283
+ interface RemoteCaretLabelHost {
1284
+ /**
1285
+ * Called after every paint that rebuilt the labels, with the current anchors.
1286
+ *
1287
+ * A skipped paint (nothing moved) does not re-publish: the host keeps its last anchors
1288
+ * until the next publish, and elements from a previous publish are dead after the next
1289
+ * one. An empty array is a real publish — every remote caret left the screen.
1290
+ *
1291
+ * Never mutate editor state synchronously from `publish` — a mutation repaints, and the
1292
+ * nested rebuild's publish would arrive before this one returned; only set host state.
1293
+ */
1294
+ publish(anchors: readonly RemoteCaretLabelAnchor[]): void;
1295
+ }
1296
+
1297
+ /**
1298
+ * How a paginated surface opens. Every field is optional.
1299
+ *
1300
+ * `measurer` is the injection seam that keeps layout DOM-free — supply one to lay a document out
1301
+ * on a server, or leave it off in a browser to get the canvas measurer.
1302
+ */
1303
+ interface PaginatedSurfaceOptions {
1304
+ /** UI labels for shared form controls; omitted keys fall back to English. */
1305
+ readonly translate?: (key: string, params?: Record<string, string | number>) => string;
1306
+ /** Regional conventions for new date input; defaults to en-US. */
1307
+ readonly locale?: string;
1308
+ /**
1309
+ * The collaboration module's replica for this surface's session. Absent,
1310
+ * the surface does not attach, and local store history remains the undo
1311
+ * authority.
1312
+ */
1313
+ readonly collaborationModel?: CollaborationModuleContribution;
1314
+ /**
1315
+ * How saved field results are edited. `atomic` (the default) keeps every field one unit.
1316
+ * `editable` lets the reader type, delete, and select inside the saved result of a DATE,
1317
+ * MERGEFIELD, HYPERLINK, or similar field. Results must be unnested; simple fields inside
1318
+ * complex field results are not supported. Refused with a {@link collaborationModel}.
1319
+ */
1320
+ readonly fieldResults?: FieldResultsMode;
1321
+ readonly measurer?: TextMeasurer;
1322
+ /** Ambient author for tracked edits. Required before suggesting can write anything. */
1323
+ readonly author?: string;
1324
+ /** Opening mode; changeable at runtime with `setEditingMode`. */
1325
+ readonly editingMode?: SurfaceEditingMode;
1326
+ /**
1327
+ * Identifies the measurer for cache invalidation.
1328
+ *
1329
+ * Fonts resolve asynchronously, so a host that swaps its measurer must change this or the
1330
+ * cached pre-font layout is served for the rest of the session.
1331
+ */
1332
+ readonly producer?: string;
1333
+ /**
1334
+ * Maps a document-declared font family to the alias its registered bytes live under, so
1335
+ * painted runs can use embedded glyphs without the file's family name entering the
1336
+ * page-global CSS font namespace.
1337
+ */
1338
+ readonly fontAlias?: (family: string) => string | undefined;
1339
+ /** Points to CSS pixels. */
1340
+ readonly scale?: number;
1341
+ /**
1342
+ * How revisions project into layout and paint. Omitted keeps the layout default
1343
+ * (`all-markup`). The editor facade passes `proposed` when no review module is
1344
+ * registered — the free tier's final-state rendering; the machinery below this
1345
+ * option is shared either way.
1346
+ */
1347
+ readonly revisionDisplayMode?: ReviewDisplayMode;
1348
+ /** Authors whose changes open in their accepted view-time projection. */
1349
+ readonly hiddenRevisionAuthors?: readonly string[];
1350
+ /**
1351
+ * When a field's result wears Word's grey shading. Omitted keeps Word's own default,
1352
+ * `when-selected`.
1353
+ *
1354
+ * Applies to ORDINARY fields only. Legacy form fields follow the document's
1355
+ * `w:doNotShadeFormData`, because a form's blanks are the document's own statement about
1356
+ * itself rather than a reader's preference.
1357
+ *
1358
+ * A paint-level option, not a layout one: it changes no geometry, so switching it repaints
1359
+ * without remeasuring a single line.
1360
+ */
1361
+ readonly fieldShading?: FieldShadingMode;
1362
+ /** Show paragraph-end furniture without changing document content. */
1363
+ readonly showParagraphMarks?: boolean;
1364
+ readonly onToggleParagraphMarks?: () => void;
1365
+ /**
1366
+ * How tracked changes are coloured: by AUTHOR (the default), by kind, or by author with
1367
+ * host-pinned colours. A paint-level option like {@link fieldShading}: it changes no
1368
+ * geometry, so switching it repaints without remeasuring a line. Applies wherever
1369
+ * revision markup paints, whatever the {@link revisionDisplayMode} leaves visible.
1370
+ */
1371
+ readonly revisionStyles?: RevisionStyles;
1372
+ readonly revisionMarkup?: ResolvedRevisionMarkup;
1373
+ /**
1374
+ * The review module's derivation hooks for this surface's session. Absent,
1375
+ * `session.reviewItems()` is the typed empty queue and every review affordance
1376
+ * built on it stays inert.
1377
+ */
1378
+ readonly reviewModel?: ReviewModuleContribution;
1379
+ /**
1380
+ * The family a run with no authored font is reported as by `formatting()` AND painted
1381
+ * in — the face the measurer falls back to. Absent, such a run reports
1382
+ * `fontFamily: null` and paints in whatever font the page inherits, which the measurer
1383
+ * did not measure: visible glyphs drift from wrap points and caret geometry.
1384
+ */
1385
+ readonly defaultFontFamily?: string;
1386
+ /**
1387
+ * Who resolves a pointer to a caret.
1388
+ *
1389
+ * `'engine'` (the default) answers from the layout records, which is what makes a click in
1390
+ * a margin, an indent or a cell's padding land where it was aimed. `'native'` binds no
1391
+ * pointer handlers and leaves the browser's own caret placement in charge.
1392
+ */
1393
+ readonly pointer?: 'engine' | 'native';
1394
+ readonly onChange?: (state: PaginatedSurfaceState) => void;
1395
+ /**
1396
+ * A plain click on an external (or inert) hyperlink, for a host to open its popover with.
1397
+ *
1398
+ * Absent means such a click does nothing. That is deliberate: a host with no popover
1399
+ * mounted must not have clicks silently opening tabs, and the popover is the only path to
1400
+ * activation (see the navigation module's single `window.open` gate).
1401
+ */
1402
+ readonly onHyperlinkPopover?: (activation: HyperlinkActivation) => void;
1403
+ readonly onEquationPopover?: (activation: EquationActivation) => void;
1404
+ /**
1405
+ * Ctrl/Cmd+K — Word's Insert Hyperlink. The engine reports the request; the host's chrome
1406
+ * decides what a link dialog looks like. A host that passes nothing leaves the key alone
1407
+ * rather than doing something surprising with it.
1408
+ */
1409
+ readonly onRequestHyperlink?: () => void;
1410
+ /** Return true when host chrome handles this session. */
1411
+ readonly onRequestTextFormField?: (session: TextFormFieldDialogSession) => boolean;
1412
+ readonly onRequestContentControlWidget?: (session: ContentControlWidgetSession) => boolean;
1413
+ readonly onRequestInvalidTextFormField?: (session: InvalidTextFormFieldSession) => boolean;
1414
+ /**
1415
+ * Localized accessible names for core-owned table insertion furniture.
1416
+ * Defaults to English from `@docx-editor.dev/i18n` when omitted.
1417
+ */
1418
+ readonly tableInteractionLabel?: (key: 'table.insertRowBelow' | 'table.insertColumnRight') => string;
1419
+ /** Localized drawing refusal labels; defaults to English when omitted. */
1420
+ readonly drawingStrings?: DrawingPaintStrings;
1421
+ /** Override raster decode for package image intents; defaults to browser/headless. */
1422
+ readonly imageDecodePort?: ImageDecodePort;
1423
+ /**
1424
+ * Localized name for a generated TOC, written as the control's `w:alias` on insert.
1425
+ *
1426
+ * The update ACTIONS are not here: they are rows in the host's context menu, which owns
1427
+ * its own labels. The engine paints no menu of its own.
1428
+ */
1429
+ readonly tocLabels?: {
1430
+ readonly title: string;
1431
+ };
1432
+ }
1433
+
1434
+ /**
1435
+ * What the selection is currently formatted as.
1436
+ *
1437
+ * A value is present only when EVERY span in the selection agrees on it: a selection running
1438
+ * from 11pt into 14pt has no font size, and a toolbar should show a blank rather than pick
1439
+ * one of the two and imply the whole selection is that.
1440
+ */
1441
+ interface SurfaceFormatting {
1442
+ readonly bold: boolean;
1443
+ readonly italic: boolean;
1444
+ readonly underline: boolean;
1445
+ readonly strikethrough: boolean;
1446
+ readonly superscript: boolean;
1447
+ readonly subscript: boolean;
1448
+ readonly fontFamily: string | null;
1449
+ /** Half-points, the unit OOXML stores and the picker expects. */
1450
+ readonly fontSizeHalfPoints: number | null;
1451
+ readonly color: string | null;
1452
+ readonly highlight: string | null;
1453
+ readonly alignment: 'left' | 'center' | 'right' | 'both' | null;
1454
+ /** Paragraph base direction through the cascade; null when the selection mixes them. */
1455
+ readonly direction: 'ltr' | 'rtl' | null;
1456
+ readonly styleId: string | null;
1457
+ /**
1458
+ * `w:spacing`'s line rule and its value: LINES for `multiple`, points for the other two
1459
+ * (`w:line` is 240ths of a line under `auto` and twentieths of a point otherwise).
1460
+ * Null when the selection's paragraphs disagree, or state no line spacing at all.
1461
+ */
1462
+ readonly lineSpacing: {
1463
+ readonly rule: 'multiple' | 'exact' | 'atLeast';
1464
+ readonly value: number;
1465
+ } | null;
1466
+ /** `w:spacing/@w:before` and `@w:after` in points, null when the selection disagrees. */
1467
+ readonly spaceBeforePt: number | null;
1468
+ readonly spaceAfterPt: number | null;
1469
+ /**
1470
+ * Effective indent at the selection, in twips, or null with no selection or inside a
1471
+ * table.
1472
+ *
1473
+ * The one field here that does NOT go null on disagreement: the values are the FIRST
1474
+ * touched paragraph's and `mixed` reports the disagreement per field, because a ruler
1475
+ * must draw its handles somewhere and Word draws them at the first selected paragraph.
1476
+ */
1477
+ readonly indent: IndentFormatting | null;
1478
+ /**
1479
+ * The paragraph flags the Paragraph dialog shows as checkboxes, or null when the
1480
+ * selection's paragraphs disagree about that one.
1481
+ *
1482
+ * `contextualSpacing` is "Don't add space between paragraphs of the same style"; the
1483
+ * other four are its Pagination block. Each is read from the cascade, so a flag a STYLE
1484
+ * sets reads as on — which is what a checkbox has to show.
1485
+ */
1486
+ readonly paragraphFlags: ParagraphFlags;
1487
+ /**
1488
+ * The paragraph's resolved custom tab stops, cascade included, or null when the selection
1489
+ * disagrees or nothing is loaded. Positions in TWIPS, like every other measurement a
1490
+ * control writes back.
1491
+ */
1492
+ readonly tabStops: readonly ParagraphTabStop[] | null;
1493
+ /**
1494
+ * Which of the paragraph-level reads above are `null` because the selection DISAGREES,
1495
+ * as opposed to because nothing states them. See {@link ParagraphDisagreements}.
1496
+ */
1497
+ readonly disagrees: ParagraphDisagreements;
1498
+ }
1499
+ /** How a reveal places its target in the viewport. */
1500
+ interface RevealOptions {
1501
+ /**
1502
+ * `'start'` puts the target near the top (a heading the user jumped to), `'center'`
1503
+ * centres it, `'nearest'` scrolls only when it is out of view — and only far enough to
1504
+ * clear the edge, which parks the target flush against it. `'centerIfNeeded'` is the one
1505
+ * a jump-to-next-thing control wants: silent while the target is already on screen, and
1506
+ * centred when it has to move, so the reader lands looking AT the thing rather than at
1507
+ * the bottom line of the window. Default `'start'`.
1508
+ */
1509
+ readonly block?: ScrollPlacement;
1510
+ /** Padding above the target, in CSS pixels. Default 24. */
1511
+ readonly offsetPx?: number;
1512
+ readonly behavior?: ScrollBehavior;
1513
+ }
1514
+ /**
1515
+ * How the current selection came to address a drawing — see
1516
+ * {@link PaginatedSurface.drawingSelectionIntent}.
1517
+ */
1518
+ type DrawingSelectionIntent = {
1519
+ readonly kind: 'none';
1520
+ } | {
1521
+ readonly kind: 'pointer';
1522
+ readonly drawingNodeId: string;
1523
+ } | {
1524
+ readonly kind: 'programmatic';
1525
+ };
1526
+ /**
1527
+ * Everything observable about the surface right now, as one immutable value.
1528
+ *
1529
+ * `revision` is the change token: it moves whenever anything else here does, which is what lets
1530
+ * `snapshot()` hand back the same reference until state actually changes.
1531
+ */
1532
+ interface PaginatedSurfaceState {
1533
+ readonly revision: number;
1534
+ readonly pageCount: number;
1535
+ readonly selection: SemanticSelection;
1536
+ /**
1537
+ * The rectangle of table cells a drag across cells selected, or null.
1538
+ *
1539
+ * `selection` always holds the equivalent TEXT range, so a reader that does not care about
1540
+ * rectangles needs no branch. This is for the ones that do — the highlight, and table
1541
+ * commands that act on cells rather than characters.
1542
+ */
1543
+ readonly cellSelection: CellSelection | null;
1544
+ readonly canUndo: boolean;
1545
+ readonly canRedo: boolean;
1546
+ /**
1547
+ * Lifecycle of the attached replica, or `'inactive'` when no collaboration
1548
+ * module is registered on this surface.
1549
+ */
1550
+ readonly collaborationStatus: CollaborationStatus | 'inactive';
1551
+ readonly lastRejection: string | null;
1552
+ /**
1553
+ * The typing format armed at the caret (Word's stored marks), or null.
1554
+ *
1555
+ * NOT document state — nothing is written until the next characters are typed — but it
1556
+ * IS observable state: `formatting()` reports it, so a host that reflects the toolbar
1557
+ * has to learn when it moves. Reference-stable while unchanged, so a host can compare
1558
+ * it to decide whether to re-derive. See `toggleRunProperty` for the lane itself.
1559
+ */
1560
+ readonly pendingFormat: readonly {
1561
+ readonly localName: string;
1562
+ }[] | null;
1563
+ /**
1564
+ * Content-control chrome and form-fill mode.
1565
+ *
1566
+ * Surface-owned (not document bytes). Updates report through the same `onChange` path as
1567
+ * selection moves — hosts must not maintain a parallel channel.
1568
+ */
1569
+ readonly contentControls: ContentControlSurfaceState;
1570
+ /**
1571
+ * The TOC the last right-click landed on, or null.
1572
+ *
1573
+ * A right-click deliberately does not move the caret, and a TOC refuses the caret
1574
+ * entirely, so `selection` can never say which table of contents the user is pointing at.
1575
+ * This is how a host's context menu learns it. Surface chrome, not document state.
1576
+ */
1577
+ readonly contextTocId: string | null;
1578
+ /**
1579
+ * Format painter arming, and the level of what it holds.
1580
+ *
1581
+ * Surface chrome, not document bytes — the lane `contentControls` above sits in, reported
1582
+ * through the same `onChange` so a toolbar's pressed state has exactly one source.
1583
+ */
1584
+ readonly formatPainter: FormatPainterSurfaceState;
1585
+ /** Timing and reuse counters for the last pass. Diagnostics, not document state. */
1586
+ readonly perf: PaginatedSurfacePerf;
1587
+ }
1588
+
1589
+ /**
1590
+ * How an edit is written.
1591
+ *
1592
+ * `'suggest'` is the one that changes what the ops MEAN: the same keystroke becomes a `w:ins`
1593
+ * and the same Backspace becomes a `w:del` over the words it would have removed. `'view'`
1594
+ * refuses edits outright.
1595
+ */
1596
+ type SurfaceEditingMode = 'edit' | 'suggest' | 'view';
1597
+
1598
+ /**
1599
+ * Where the section after an inserted break begins — Word's Layout > Breaks menu.
1600
+ *
1601
+ * `evenPage` / `oddPage` sections from a file paginate with their blank parity sheet, but
1602
+ * inserting one is not offered here.
1603
+ *
1604
+ * @public
1605
+ */
1606
+ type SectionBreakInsertType = 'nextPage' | 'continuous';
1607
+ /**
1608
+ * The mounted, painted, editable document — the layer `createDocxEditor` builds its contract on.
1609
+ *
1610
+ * The painted pages ARE the editable surface: they are `contenteditable`, but the DOM is a
1611
+ * picture. Browser mutations are prevented and re-expressed as tree ops, and selection maps only
1612
+ * through `data-paragraph-id`/`data-start`, never through DOM node identity.
1613
+ *
1614
+ * Every write goes through the guarded mutation path on this object. Reaching past it into
1615
+ * `session` to apply ops directly bypasses the layout invalidation and the caret bookkeeping.
1616
+ */
1617
+ interface PaginatedSurface {
1618
+ readonly session: TreeDocxSessionView;
1619
+ /** The collaboration replica a `collaborationModule` attached, or null. */
1620
+ collaborationSession(): EditorCollaborationSession | null;
1621
+ storyScope(): StoryScope;
1622
+ imageDecodePort(): ImageDecodePort;
1623
+ applyDrawingOps(ops: readonly DrawingTreeDocOp[]): TreeApplyResult;
1624
+ applyImageProperties(input: ApplyImagePropertiesInput): ImageIntentResult;
1625
+ deleteImage(drawingNodeId: string): ImageIntentResult;
1626
+ insertImage(input: SurfaceInsertImageInput): Promise<ImageIntentResult>;
1627
+ replaceImage(drawingNodeId: string, bytes: Uint8Array, mime: SupportedImageMime, options: {
1628
+ readonly expectedPackageRevision: number;
1629
+ readonly commitGuard?: () => boolean;
1630
+ }): Promise<ImageIntentResult>;
1631
+ layout(): SemanticLayout;
1632
+ state(): PaginatedSurfaceState;
1633
+ /** One-based page at the caret, or at the centre of the mounted viewport. */
1634
+ currentPage(mode?: 'viewport' | 'caret'): number;
1635
+ type(text: string): void;
1636
+ /** Author one explicit tracked text change without changing the editing mode. */
1637
+ proposeTextChange(kind: 'insertion' | 'deletion' | 'replacement', text: string, author?: string): boolean;
1638
+ /**
1639
+ * Queue plain typed text for a batched commit at the caret.
1640
+ *
1641
+ * The DOM input lane's entry: a burst of keystrokes appends here and lands through ONE
1642
+ * `type()` call — one transaction, one undo step, one layout flush — when the queue drains.
1643
+ * Every surface mutation, selection or scope move, geometry read, composition start and
1644
+ * teardown flushes first. Code reading `session` directly sits BELOW the buffer and must
1645
+ * call {@link flushPendingInput}, as save/detach do. `type()` stays synchronous.
1646
+ */
1647
+ enqueueType(text: string): void;
1648
+ /**
1649
+ * Land any queued typed text now, as its own transaction, AND publish any layout pass a
1650
+ * commit deferred under input pressure — so the caller reads current text and current
1651
+ * geometry at one seam. Both halves are no-ops when nothing is pending, which is the
1652
+ * common case: an isolated commit lays out synchronously in its own tail, and deferral
1653
+ * only happens when the browser reports queued input behind an expensive pass.
1654
+ */
1655
+ flushPendingInput(): void;
1656
+ /**
1657
+ * Insert text whose newlines are PARAGRAPH BOUNDARIES, in one commit.
1658
+ *
1659
+ * `type` writes its argument into run text verbatim, so a newline reaching it is a
1660
+ * control character the store refuses — which vetoes the whole transaction and makes
1661
+ * the insert do nothing at all. This is the lane for text that arrives from outside the
1662
+ * editor (a paste, a drop), where line breaks are structure rather than characters.
1663
+ *
1664
+ * Plain text only, by construction: no markup is parsed and no DOM is built from the
1665
+ * payload, whatever its origin.
1666
+ */
1667
+ insertPlainText(text: string): void;
1668
+ deleteBackward(): void;
1669
+ /** Delete forward — the Delete key, and `deleteContentForward` from an IME. */
1670
+ deleteForward(): void;
1671
+ /** Delete to the previous word boundary — Alt/Ctrl+Backspace. */
1672
+ deleteWordBackward(): void;
1673
+ /** Delete to the next word boundary — Alt/Ctrl+Delete. */
1674
+ deleteWordForward(): void;
1675
+ splitParagraph(): void;
1676
+ /** A tab character as a `w:tab` element, not a literal tab in the run text. */
1677
+ insertTab(): void;
1678
+ /** A `w:br` — Shift+Enter, a line break inside the same paragraph. */
1679
+ insertLineBreak(): void;
1680
+ /** A `w:br w:type="page"` — Ctrl+Enter, a hard page break inside the paragraph. */
1681
+ insertPageBreak(): void;
1682
+ /**
1683
+ * Word's Increase/Decrease Indent, over every paragraph the selection touches.
1684
+ *
1685
+ * A NUMBERED or BULLETED paragraph changes LEVEL: `w:numPr/w:ilvl` moves by one, which
1686
+ * re-resolves its marker from `numbering.xml` — so a bullet becomes a hollow circle, a
1687
+ * `1.` becomes an `a.`, exactly as Word demotes a list item. A level the definition
1688
+ * does not declare is DECLARED on the way, with Word's default format for that depth
1689
+ * (its stock bullets and number formats cycle every three levels) — a definition that
1690
+ * stops at `ilvl 0` never blocks the press. Everything else moves its `w:ind/@left` by
1691
+ * one default tab stop, never past the margin.
1692
+ *
1693
+ * Answers whether anything changed, so a caller can fall back (Tab inserting a tab
1694
+ * where there is no list to demote).
1695
+ */
1696
+ adjustIndent(direction: 'increase' | 'decrease'): boolean;
1697
+ /**
1698
+ * Tab (`increase`) or Shift+Tab (`decrease`) over a selection outside a list: change the
1699
+ * indent and keep the text.
1700
+ *
1701
+ * A selection over two or more paragraphs, or a cell rectangle, steps the left indent of
1702
+ * each paragraph. A selection in one paragraph that starts at the paragraph start, whole or
1703
+ * partial, works on the first line: Tab sets a first-line indent of one default tab stop
1704
+ * (`w:defaultTabStop`), or steps the left indent when the first line already has that
1705
+ * indent or more, or a hanging indent. Shift+Tab clears a first-line indent that the
1706
+ * paragraph states itself, so a style value applies again, and otherwise steps the left
1707
+ * indent back. A paragraph the selection reaches only at its start is not touched by this
1708
+ * rule, unless it is the empty last paragraph of the story.
1709
+ *
1710
+ * Answers true when the selection takes this rule, also when the write is refused or
1711
+ * changes nothing, so the text is never replaced. Answers false for a caret and for a
1712
+ * selection in one paragraph that starts inside the text; there Tab types a tab character
1713
+ * and Shift+Tab steps the left indent.
1714
+ */
1715
+ indentWithTab(direction: 'increase' | 'decrease'): boolean;
1716
+ /**
1717
+ * Set indent to exact values on every paragraph the selection touches — what a ruler
1718
+ * drag and an indent spinner both need, where {@link adjustIndent} only steps.
1719
+ *
1720
+ * Twips. Omitting a field leaves it as authored; `null` CLEARS it, so the paragraph
1721
+ * falls back to its style — distinct from zero, which blocks the cascade.
1722
+ *
1723
+ * `firstLine` is ONE SIGNED offset, negative for a hanging indent; the two OOXML
1724
+ * spellings are written for it, the unused one as an explicit zero. Answers whether
1725
+ * anything was committed.
1726
+ */
1727
+ setIndent(update: {
1728
+ readonly left?: number | null;
1729
+ readonly right?: number | null;
1730
+ readonly firstLine?: number | null;
1731
+ }): boolean;
1732
+ /**
1733
+ * Whether Increase/Decrease Indent would do anything right now.
1734
+ *
1735
+ * A list item at level 0 cannot outdent and one at level 8 cannot indent — `w:ilvl`
1736
+ * has nine levels and Word greys the control out at the ends. A missing level
1737
+ * DEFINITION never disables it: `adjustIndent` declares the level as it goes. The one
1738
+ * residue: a `w:numStyleLink` definition missing the level refuses the declaration
1739
+ * (its levels belong to the linked style), so there the press is a safe no-op rather
1740
+ * than a greyed control.
1741
+ */
1742
+ canAdjustIndent(direction: 'increase' | 'decrease'): boolean;
1743
+ /**
1744
+ * Enter on an empty list item: outdent a level, or leave the list at level 0.
1745
+ *
1746
+ * Answers false when the caret is not on an empty list item, so the caller falls
1747
+ * through to an ordinary paragraph split.
1748
+ */
1749
+ exitListOnEmptyItem(): boolean;
1750
+ /** Whether the paragraph at the caret is a list item, for Tab's Word-like fallback. */
1751
+ isListParagraph(): boolean;
1752
+ /**
1753
+ * Word's Bullets and Numbering buttons.
1754
+ *
1755
+ * Turns every paragraph the selection touches into a list of `kind`, or takes them all
1756
+ * out when they are already one. The definition is created in `numbering.xml` on first
1757
+ * use — a document that has never carried a list has no numbering part at all.
1758
+ */
1759
+ toggleList(kind: 'bullet' | 'ordered'): boolean;
1760
+ /** Whether every paragraph the selection touches is already a list of `kind`. */
1761
+ isListActive(kind: 'bullet' | 'ordered'): boolean;
1762
+ /** Select the whole document. */
1763
+ selectAll(): void;
1764
+ /**
1765
+ * Turn the browser's editing affordance on the pages layer on or off.
1766
+ *
1767
+ * The facade's `mode` gates COMMANDS, which stops `exec` but not the keyboard: the pages
1768
+ * layer is `contentEditable` and binds `beforeinput` itself, so a document the facade
1769
+ * called read-only still accepted typing straight into it. Read-only has to reach the
1770
+ * surface to be true.
1771
+ */
1772
+ setEditable(editable: boolean): void;
1773
+ /**
1774
+ * Scroll a page, or the page a paragraph sits on, into view. Returns whether it
1775
+ * scrolled — false when the target is not laid out, or the surface is not inside a
1776
+ * scroll container, so a caller can tell "no such target" from "done".
1777
+ *
1778
+ * The geometry comes from the LAYOUT, never from the DOM: a page that has not been
1779
+ * materialized yet has no element to measure, and that is exactly the page a reveal is
1780
+ * usually asked for. `revealParagraph` scrolls to the paragraph's own line rather than
1781
+ * the top of its page, so a heading deep in a page lands in view.
1782
+ */
1783
+ revealPage(pageIndex: number, options?: RevealOptions): boolean;
1784
+ revealParagraph(paragraphId: string, options?: RevealOptions): boolean;
1785
+ /**
1786
+ * Scroll an exact position into view — `revealParagraph` for a caret that is not at
1787
+ * offset 0. Focus-independent and virtualization-safe like every reveal: geometry
1788
+ * comes from the layout and the target page is materialized on the way. Defaults to
1789
+ * `block: 'nearest'`, so an already-visible target never yanks the viewport.
1790
+ */
1791
+ revealPosition(position: SemanticPosition, options?: RevealOptions): boolean;
1792
+ /** Set the selection directly, for a host driving the surface programmatically. */
1793
+ setSelection(next: SemanticSelection): void;
1794
+ /**
1795
+ * Select one painted drawing at its host paragraph, as a pointer press would.
1796
+ *
1797
+ * False when the layout paints no such drawing on that paragraph, in which case nothing
1798
+ * moves: the caller decides what to do rather than being left mid-way.
1799
+ */
1800
+ selectDrawing(drawingNodeId: string, hostParagraphId: string): boolean;
1801
+ /**
1802
+ * Select a rectangle of table cells, or clear one with null.
1803
+ *
1804
+ * The equivalent text range is installed alongside it, so `state().selection` stays valid
1805
+ * for every reader that does not know rectangles exist.
1806
+ */
1807
+ setCellSelection(next: CellSelection | null): void;
1808
+ /**
1809
+ * Toggle a run property over the selection, e.g. `b`, `i`, `u`.
1810
+ *
1811
+ * AT A COLLAPSED CARET this ARMS the property instead of writing it — Word's stored
1812
+ * marks. Nothing reaches the document until the next characters are typed there, and
1813
+ * those take the armed format; the armed state shows in `formatting()` and in
1814
+ * `state().pendingFormat` immediately, so a toolbar reflects the press. It survives the
1815
+ * caret-preserving edits (Backspace, Delete, Enter) and IME composition, and is
1816
+ * discarded when the caret moves elsewhere or the document is undone. A property the
1817
+ * store cannot author is refused at arm time rather than left to poison the keystroke.
1818
+ */
1819
+ toggleRunProperty(localName: string, attributes?: Record<string, string>): void;
1820
+ /**
1821
+ * SET a run property over the selection, rather than toggling it.
1822
+ *
1823
+ * Font family, size and colour are values, not switches: picking Arial twice must leave
1824
+ * the text in Arial, which a toggle would not. Arms at a collapsed caret on the same
1825
+ * terms as `toggleRunProperty`.
1826
+ */
1827
+ setRunProperty(localName: string, attributes?: Record<string, string>): void;
1828
+ /**
1829
+ * Set a property on every paragraph the selection touches — alignment, style, spacing.
1830
+ *
1831
+ * `mergeAttributes` keeps the attributes the call does not name, for the properties that
1832
+ * carry several independent settings in one element: `w:spacing` holds the line rule and
1833
+ * the space before and after, so a line-spacing pick must not delete the space-before. A
1834
+ * null-valued attribute removes just that one.
1835
+ */
1836
+ setParagraphProperty(localName: string, attributes?: Record<string, string | null>, options?: Pick<ParagraphPropertyEdit, 'mergeAttributes' | 'physicalAlignment' | 'paragraphDirection'>): void;
1837
+ /**
1838
+ * Several paragraph properties in ONE transaction, so a dialog is one undo step.
1839
+ *
1840
+ * `setParagraphProperty` is this with a single entry. A dialog that fired one call per
1841
+ * field would leave the user pressing Ctrl+Z five times to undo one OK, and would paint
1842
+ * four intermediate layouts on the way.
1843
+ */
1844
+ setParagraphProperties(entries: readonly ParagraphPropertyEdit[]): void;
1845
+ /**
1846
+ * The Paragraph dialog as ONE write: alignment, indents, spacing, line spacing and the
1847
+ * five paragraph flags, over every paragraph the selection touches.
1848
+ *
1849
+ * One transaction, so pressing OK is one undo step and the page repaints once. An omitted
1850
+ * field is left as authored; `null` where the type allows it REMOVES the setting so the
1851
+ * style supplies it again. Returns whether anything was written.
1852
+ */
1853
+ setParagraphFormat(update: SurfaceParagraphFormat): boolean;
1854
+ /**
1855
+ * Word's Clear All Formatting: direct run properties off the selected text, and every
1856
+ * paragraph the selection touches back to the default style with its direct paragraph
1857
+ * properties and mark dropped.
1858
+ *
1859
+ * Only what the document states DIRECTLY — formatting inherited from a style survives, so
1860
+ * the text falls back to its style rather than to nothing. Properties an op cannot name
1861
+ * (`w:rStyle`, `w:lang`, `w:sectPr`, `w:pBdr`) are preserved for the same reason every
1862
+ * other write preserves them.
1863
+ */
1864
+ clearFormatting(): void;
1865
+ /**
1866
+ * Formatting as it stands at the selection, for a toolbar to reflect.
1867
+ *
1868
+ * With a typing format armed at the caret this reports what the NEXT characters typed
1869
+ * will look like, not what the document holds — which is the answer a toolbar wants and
1870
+ * the one Word gives.
1871
+ */
1872
+ formatting(): SurfaceFormatting;
1873
+ /**
1874
+ * The section the document declares: page size, margins, columns, orientation.
1875
+ *
1876
+ * What a ruler is made of, and what pagination is measured against.
1877
+ */
1878
+ sectionProperties(): SectionProperties;
1879
+ /**
1880
+ * The section GOVERNING one paragraph — what a ruler or dialog reflects when the caret sits
1881
+ * in a multi-section document.
1882
+ *
1883
+ * Body content answers for itself, whatever story is open. A header or footer belongs to the
1884
+ * section that names its relationship, and a note to the section holding its reference mark.
1885
+ * An id nothing settles falls back to the FIRST section: the tail is the document-wide answer
1886
+ * and is wrong for everything not on the last page.
1887
+ */
1888
+ sectionPropertiesAt(paragraphId: string): SectionProperties;
1889
+ /**
1890
+ * How a section-addressed op should name the section `paragraphId` is in.
1891
+ *
1892
+ * `w:sectPr` lives on the body story, so such an op can only name body content — and a caret
1893
+ * in a header or a note is not body content. Passing that caret straight through made every
1894
+ * section write from furniture fail `unknown-paragraph`.
1895
+ */
1896
+ sectionAnchorParagraphAt(paragraphId: string): SectionAnchor;
1897
+ /**
1898
+ * Write section page-setup fields — size, orientation, margins — as ONE undoable
1899
+ * transaction. Twips throughout; omitted fields are left as authored. With
1900
+ * `anchorParagraphId` only that paragraph's governing section is written (Word's
1901
+ * "Apply to: This section"); without it, every section. Returns whether the write
1902
+ * committed (a hostile value is refused by the op layer).
1903
+ */
1904
+ setSectionProperties(update: {
1905
+ readonly pageWidthTwips?: number;
1906
+ readonly pageHeightTwips?: number;
1907
+ readonly orientation?: 'portrait' | 'landscape';
1908
+ readonly marginTopTwips?: number;
1909
+ readonly marginRightTwips?: number;
1910
+ readonly marginBottomTwips?: number;
1911
+ readonly marginLeftTwips?: number;
1912
+ readonly anchorParagraphId?: string;
1913
+ }): boolean;
1914
+ /**
1915
+ * Insert a section break at the caret: the paragraph splits, and the head ends a new
1916
+ * section cloning the governing section's page setup — Word's Layout > Breaks. One
1917
+ * undoable step. Returns whether the break committed.
1918
+ *
1919
+ * `breakType` says where the section AFTER the break begins: `'nextPage'` (the default,
1920
+ * Word's Next Page) starts a new sheet, `'continuous'` keeps it on the sheet the
1921
+ * previous section ended, which is how a mid-page column or margin change is authored.
1922
+ */
1923
+ insertSectionBreak(breakType?: SectionBreakInsertType): boolean;
1924
+ /**
1925
+ * Why {@link insertSectionBreak} would refuse this kind right now, or `null`.
1926
+ *
1927
+ * THE authority for the BREAK's own questions, so `Editor.can` and the write cannot answer
1928
+ * those differently. Both halves are things only the surface knows: the LIVE editing mode
1929
+ * (a document that declares `w:trackRevisions` opens suggesting without anyone passing a
1930
+ * mode, and Review > Track Changes moves it again afterwards), and the paragraph the break
1931
+ * would actually land in — which for a range in suggesting mode is past the struck words,
1932
+ * not the selection's head.
1933
+ *
1934
+ * NOT the deletion's questions. A break replaces the selection first, and that deletion can
1935
+ * cross content a control holds or a region protected some other way; only the store sees
1936
+ * that, and it sees it at write time. So a range whose landing is fine while its deletion
1937
+ * is not answers `null` here and refuses at the press — as every other replacing command in
1938
+ * the engine does, less loudly. Story scope is gated separately again, because a caret in a
1939
+ * header refuses every break kind for a different reason.
1940
+ */
1941
+ sectionBreakRefusal(breakType?: SectionBreakInsertType): string | null;
1942
+ /** The layout session, so a host or a test can see how much work a pass actually did. */
1943
+ layoutSession(): {
1944
+ readonly stats: {
1945
+ readonly placed: number;
1946
+ readonly total: number;
1947
+ readonly reusedPages: number;
1948
+ };
1949
+ };
1950
+ /**
1951
+ * The hyperlink lane: what link the caret is in, and the insert / retarget / unlink verbs.
1952
+ *
1953
+ * Every verb is one `transact`, so it is one undo step. Targets going IN are host-supplied
1954
+ * and pass the package's own URL allowlist; targets coming OUT are the sanitized
1955
+ * projection, so a caller cannot accidentally hand a refused scheme to a sink.
1956
+ */
1957
+ readonly hyperlinks: HyperlinkOps;
1958
+ readonly equations: EquationOps;
1959
+ /**
1960
+ * Content-control chrome, form-fill navigation, and value / remove verbs.
1961
+ *
1962
+ * Value and remove commit through `session.applyTreeOps` — the same write path as typing.
1963
+ * Show-all and form-fill are surface chrome and never reflow layout.
1964
+ */
1965
+ readonly contentControls: ContentControlOps;
1966
+ /** Word's Format Painter: capture, apply, and the transient armed mode. */
1967
+ readonly formatPainter: FormatPainterOps;
1968
+ /** Whether a `rows`×`cols` table can be inserted at the caret. */
1969
+ canInsertTable(rows: number, cols: number): boolean;
1970
+ /**
1971
+ * Insert an empty `rows`×`cols` table at the caret, columns evenly dividing the content
1972
+ * width of the caret's section, and leave the caret in the first cell.
1973
+ */
1974
+ insertTable(rows: number, cols: number): boolean;
1975
+ /** Whether the addressed (or caret-local) body TOC can be refreshed. */
1976
+ canRefreshToc(tocId?: string): boolean;
1977
+ /** Whether a generated body TOC can be inserted before the caret paragraph. */
1978
+ canInsertToc(): boolean;
1979
+ /** Insert and populate a generated body TOC before the caret paragraph. */
1980
+ insertToc(): boolean;
1981
+ /** Refresh cached TOC entries and/or page numbers through the two-pass layout pipeline. */
1982
+ canEditTextFormField(): boolean;
1983
+ editTextFormField(): boolean;
1984
+ refreshToc(tocId?: string, mode?: 'entire' | 'pageNumbers'): boolean;
1985
+ /**
1986
+ * Rewrite stale REF field results in the body, footnote and endnote stories so a save
1987
+ * exports what the pages paint. Fresh results commit nothing (no transaction, no revision
1988
+ * bump, no undo entry); a rewrite is ONE transaction and ONE undo unit across every stale
1989
+ * part. Viewing, a non-editable session, and a collaborative session write nothing — the
1990
+ * collaboration gate cannot journal the rewrite, so those saves export cached results and
1991
+ * the call returns false.
1992
+ */
1993
+ refreshRefFieldResults(): boolean;
1994
+ /**
1995
+ * Commit pending form input, refresh REF results, and serialize the document.
1996
+ * Throws an error with code `invalidArgs` for invalid form values, or `invalidState`
1997
+ * during an active edit. Retry after the edit finishes. A destroyed surface throws
1998
+ * with code `destroyed`. Does not change focus.
1999
+ */
2000
+ save(): Uint8Array;
2001
+ /** Whether a body paragraph belongs to a detected TOC boundary or cached result. */
2002
+ isInsideToc(paragraphId: string): boolean;
2003
+ /**
2004
+ * Bookmark jumps and the ONE external-activation gate. A host's popover "open" action
2005
+ * calls `openExternal`; nothing else in the engine may call `window.open`.
2006
+ */
2007
+ readonly navigation: SurfaceNavigation;
2008
+ /**
2009
+ * Pin the current selection so it stays VISIBLY selected while focus is elsewhere.
2010
+ *
2011
+ * A document has one selection: the moment a panel focuses an input of its own the browser
2012
+ * takes the highlight off the text, which is when the user most needs to see what the panel
2013
+ * is about to act on. This draws the range on the engine's own overlay instead, so it
2014
+ * survives the focus move. The MODEL selection is untouched — the op the panel finally runs
2015
+ * addresses the same characters it always would.
2016
+ *
2017
+ * The pin releases itself when the caret leaves the range (either edge counts as inside),
2018
+ * which is what lets a host close its panel on "the user clicked somewhere else" without
2019
+ * every adapter reimplementing that comparison.
2020
+ */
2021
+ retainSelection(): SelectionPin;
2022
+ /** Drop one owned pin. Another owner's pin remains visible. */
2023
+ releaseSelection(pin: SelectionPin): void;
2024
+ /** The pinned range, or null once it was released or escaped. */
2025
+ retainedSelection(): SemanticSelection | null;
2026
+ /**
2027
+ * How edits are written right now.
2028
+ *
2029
+ * Lives on the SURFACE, not on the store. The store's write vocabulary stays explicit —
2030
+ * an op says whether it is tracked — and the surface is the one thing that knows a
2031
+ * keystroke happened, so it is the right place to decide what that keystroke becomes.
2032
+ */
2033
+ editingMode(): SurfaceEditingMode;
2034
+ setEditingMode(mode: SurfaceEditingMode): void;
2035
+ /** Set the ambient author after buffered text commits under the previous author. */
2036
+ setAuthor(author: string | undefined): void;
2037
+ /** The ambient author tracked edits and review writes record, or undefined. */
2038
+ author(): string | undefined;
2039
+ /** Replace localized drawing labels and repaint materialized pages. */
2040
+ setDrawingStrings(strings: DrawingPaintStrings): void;
2041
+ /** Update shared form-control labels without replacing open dialogs. */
2042
+ setTranslate(translate: PaginatedSurfaceOptions['translate']): void;
2043
+ /** Set regional conventions for subsequent date input without reformatting stored values. */
2044
+ setLocale(locale: string | undefined): void;
2045
+ /** Replace the localized title used by later TOC insertions. */
2046
+ setTocLabels(labels: NonNullable<PaginatedSurfaceOptions['tocLabels']>): void;
2047
+ /**
2048
+ * Every author with a revision in the CURRENT layout, mapped to Word's colour slot by
2049
+ * order of first appearance. One map instance per layout, so a caller can key caches on
2050
+ * its identity.
2051
+ */
2052
+ revisionAuthors(): ReadonlyMap<string, number>;
2053
+ /** Reviewers currently projected as accepted, without changing the document. */
2054
+ hiddenRevisionAuthors(): ReadonlySet<string>;
2055
+ /** Show one reviewer's markup, or render that reviewer's changes as accepted. */
2056
+ setRevisionAuthorVisible(author: string, visible: boolean): void;
2057
+ /** Show or hide every reviewer in one layout pass. */
2058
+ setAllRevisionAuthorsVisible(visible: boolean): void;
2059
+ /** Clear the reviewer filter in one layout pass. */
2060
+ showAllRevisionAuthors(): void;
2061
+ /** Apply a view-time predicate over complete tracked-change items. */
2062
+ setTrackedChangesFilter(predicate: TrackedChangePredicate | null, mode?: TrackedChangeFilterMode): void;
2063
+ /** The presence colour the caret paints for `name`, sanitized as the paint sink is. */
2064
+ remotePresenceColor(name: string): string | undefined;
2065
+ /**
2066
+ * Replace how tracked changes are coloured, live. Paint-level: the pages repaint without
2067
+ * remeasuring a line, and the caret, selection and undo history stay where they are.
2068
+ */
2069
+ setRevisionMarkup(settings: ResolvedRevisionMarkup): void;
2070
+ setRevisionStyles(colors: RevisionStyles | undefined): void;
2071
+ /** Toggle paragraph-end furniture without layout or document changes. */
2072
+ setShowParagraphMarks(show: boolean): void;
2073
+ /**
2074
+ * Hand remote-caret label content to the host, or take it back with `null`.
2075
+ *
2076
+ * With a host set, the engine still creates and positions each label (same class, same
2077
+ * presence colour) but leaves it empty, marks it `data-docx-remote-actor`, and calls
2078
+ * {@link RemoteCaretLabelHost.publish} after every paint that rebuilt the labels.
2079
+ * Registration and unregistration repaint immediately, so the first publish fires
2080
+ * without waiting for awareness to move and unregistering restores the default
2081
+ * collaborator-name labels.
2082
+ */
2083
+ setRemoteCaretLabelHost(host: RemoteCaretLabelHost | null): void;
2084
+ /**
2085
+ * Install the painter for host text highlights, or remove it with `null`. The surface calls
2086
+ * it after every render and once on installation, with the frame it just painted.
2087
+ */
2088
+ setHighlightPainter(painter: SurfaceOverlayPainter | null): void;
2089
+ /** Call the installed highlight painter against the current frame. */
2090
+ repaintHighlights(): void;
2091
+ /**
2092
+ * Commit ops that came from automation, through the gate a keystroke goes through.
2093
+ *
2094
+ * The narrow entry an automation host writes with, and the reason it needs one: reaching
2095
+ * `session.applyTreeOps` past this skips the editing-mode gate entirely — a document open for
2096
+ * viewing accepts a scripted edit, and a suggesting document records one as a permanent
2097
+ * change with no proposal and no author. Here, viewing refuses, suggesting attributes, the
2098
+ * refusal reason is reported like any other, and the pages repaint from the commit.
2099
+ *
2100
+ * The ops address the story the CALLER named, whatever story the reader is in: the caller
2101
+ * identified its target before calling, so following the caret into a header would write
2102
+ * somewhere else entirely. They default to the body rather than to the reader's story.
2103
+ *
2104
+ * They arrive as a BUILDER, given a way to mint the relationship an external hyperlink names.
2105
+ * That mint changes the package outside the transaction and outside the undo stack, so it must not
2106
+ * happen until the mode has allowed the write — a link minted while the batch was still being
2107
+ * planned left its target in a read-only document's `.rels`. A builder answering null means the
2108
+ * target is one this engine will not author, and the write is refused having changed nothing.
2109
+ */
2110
+ applyAutomationOps(staged: (relate: (url: string) => string | null) => readonly TreeDocOp[] | null, scope?: StoryScope, packageEdits?: readonly ((pkg: OoxmlPackage) => OoxmlPackage)[], requiresReview?: boolean): TreeApplyResult;
2111
+ /**
2112
+ * Which revision halves this surface is SHOWING.
2113
+ *
2114
+ * Read by the automation adapter so the object model's formatting reaches the same runs the
2115
+ * toolbar does. A range's offsets cover every revision half whatever the view does with
2116
+ * them, so with markup on, a selection over a struck word means one thing to a reader and
2117
+ * would mean another to a script that assumed the resolved result.
2118
+ */
2119
+ revisionDisplayMode(): ReviewDisplayMode;
2120
+ /** Change the review display without accepting, rejecting, or changing author filters. */
2121
+ setRevisionDisplayMode(mode: ReviewDisplayMode): void;
2122
+ /**
2123
+ * Where a replacement for `[start, end)` of a paragraph lands, or null when the edit would
2124
+ * not be tracked.
2125
+ *
2126
+ * Non-null exactly when suggesting: the struck words stay, so the replacement goes past
2127
+ * them, minus whatever of the range was this author's own pending insertion, which leaves.
2128
+ * The SAME rule every replacing lane of the keyboard reads, exposed so the automation object
2129
+ * model aims a scripted `Replace` where typing does and can answer the span it wrote.
2130
+ */
2131
+ replacementLanding(paragraphId: string, start: number, end: number): number | null;
2132
+ /**
2133
+ * Commit review ops — accept, reject, a new comment — through the SAME path a keystroke
2134
+ * takes: layout, paint, and a caret clamped to what the document now holds.
2135
+ *
2136
+ * `intent` names WHICH review write this is, so a lane that judges them can tell them apart.
2137
+ * The callback is opaque, and a replica admits only the writes proven to replicate — see
2138
+ * {@link ReviewWriteIntent}.
2139
+ *
2140
+ * Applying them straight to the session skipped all three. Rejecting an insertion left the
2141
+ * pages painting text the tree no longer had, every card anchored where it used to be, and
2142
+ * the caret past the end of the paragraph — after which every keystroke was refused with
2143
+ * `offset-out-of-range` until the user happened to click somewhere else.
2144
+ */
2145
+ commitReviewOps(run: () => {
2146
+ readonly committed: boolean;
2147
+ readonly reason?: unknown;
2148
+ }, intent?: ReviewWriteIntent): void;
2149
+ /**
2150
+ * The layout as last PUBLISHED, without forcing pending work.
2151
+ *
2152
+ * `layout()` flushes first, which is right for a caller that is about to act on geometry
2153
+ * and wrong for one that merely decorates it. The review rail read through `layout()` and
2154
+ * so forced a synchronous full pass on every keystroke — eleven seconds per read on a
2155
+ * 2432-block document. A card whose anchor is one frame stale is invisible; the paint that
2156
+ * follows the flush republishes it.
2157
+ */
2158
+ publishedLayout(): SemanticLayout;
2159
+ /**
2160
+ * How the current selection came to address a drawing, if it does at all.
2161
+ *
2162
+ * Word's rule: a caret NEXT TO a floating object is a text caret, never an object selection —
2163
+ * only clicking the object (or a host selection write) selects it. The engine's selection is a
2164
+ * caret at the anchor offset either way, so offsets cannot tell them apart; this is the
2165
+ * discriminator. `none` for a fresh mount (the initial caret routinely coincides with a drawing
2166
+ * anchored at offset zero) and after typing, caret keys, or a press on a non-drawing. `pointer`
2167
+ * names the drawing the press landed on, so a stale press cannot claim a later one.
2168
+ */
2169
+ drawingSelectionIntent(): DrawingSelectionIntent;
2170
+ /**
2171
+ * Paint-scale coordinate context for overlay chrome.
2172
+ *
2173
+ * Internal seam — not part of the public editor contract. Image overlay uses the same
2174
+ * `zoom * 96/72` scale and per-page horizontal offsets the painter applied.
2175
+ */
2176
+ overlayCoordinates(): SurfaceOverlayCoordinates;
2177
+ /**
2178
+ * The comment, tracked change or carded custom node the caret is in, as the painted bands
2179
+ * report it. A custom node without `reviewCard` is never the answer: it has no card.
2180
+ *
2181
+ * ONE source for "which item is open". The band under the text and the card beside it are
2182
+ * two views of the same answer, and deriving it twice let them disagree — the card closed
2183
+ * while the text stayed highlighted.
2184
+ */
2185
+ activeReviewKey(): string | null;
2186
+ /**
2187
+ * Open THIS item, named by key, for as long as `selection` stays the live one.
2188
+ *
2189
+ * Without it the caret is the only evidence of which card is open, and a caret cannot name a
2190
+ * card when two cards cover exactly the same characters: `w:ins` wrapping `w:del` — content
2191
+ * one reviewer added and another struck — gives the insertion and the deletion one identical
2192
+ * range, and every click on either card classified back to whichever the queue happened to
2193
+ * list first. The reader clicked "Deleted" and watched "Added" light up.
2194
+ *
2195
+ * A key, not a position, because the position is precisely what is ambiguous. It holds only
2196
+ * while the selection matches; a pointer or keyboard move hands the answer back to the caret,
2197
+ * which is what lets the reader step out of a card by clicking away from it.
2198
+ *
2199
+ * `selection` is what activation wants installed, and it is installed HERE rather than by a
2200
+ * `setSelection` of the caller's own so that the pin is up before anything is published. The
2201
+ * other order repainted the bands and reported state while the caret was still the only
2202
+ * evidence, so a host saw the wrong twin active for one frame and then a correction. Omit it
2203
+ * to pin against the live selection, which is what a header or note scope has already set.
2204
+ */
2205
+ activateReview(key: string, selection?: SemanticSelection, options?: {
2206
+ readonly allowExcluded?: boolean;
2207
+ }): void;
2208
+ /**
2209
+ * The key {@link activateReview} pinned, or null once its selection is no longer live.
2210
+ *
2211
+ * Exists so nothing outside the surface keeps its own copy of "the selection came from
2212
+ * opening a card". `selectionPlacement` needs that fact to stay quiet about offering a
2213
+ * comment on text the reader only selected by opening a card over it, and the copy it used to
2214
+ * keep was set on one of activation's three branches, so a header card offered to comment on
2215
+ * itself.
2216
+ */
2217
+ activatedReviewKey(): string | null;
2218
+ /**
2219
+ * Close the open item until the caret next moves.
2220
+ *
2221
+ * What a click on the canvas means. The caret does not move when someone clicks the grey
2222
+ * around the page, so nothing else would ever put the item away.
2223
+ */
2224
+ dismissActiveReview(): void;
2225
+ /**
2226
+ * Revision kinds the CARET must not activate, or null for none.
2227
+ *
2228
+ * The review rail filters what it renders (structural and format cards are hidden by
2229
+ * default), but {@link activeReviewKey} used to compute over the unfiltered queue — a
2230
+ * click on tracked text under a format change activated a card the rail does not draw,
2231
+ * and nothing on screen lit up. A host that filters its list tells the surface, so the
2232
+ * band and the visible cards stay one answer.
2233
+ */
2234
+ setReviewActivationExclusions(kinds: readonly ReviewRevisionKind[] | null, options?: {
2235
+ readonly formattingKinds?: readonly string[];
2236
+ }): void;
2237
+ /**
2238
+ * `bookmarkName -> position` over the current revision, for resolving an internal link.
2239
+ * First in document order wins a duplicate name, matching Word.
2240
+ */
2241
+ bookmarks(): BookmarkIndex;
2242
+ /** The selected text, for copy and cut. */
2243
+ selectedText(): string;
2244
+ /**
2245
+ * Every clipboard flavour for the current selection: plain text, and the interop HTML
2246
+ * carrying the embedded fragment when the selection is a body-story range. A cell
2247
+ * rectangle answers grid text plus a flattened table; `html` is null where only plain
2248
+ * text should be written. Unsupported object selections return a refusal reason.
2249
+ */
2250
+ copyFlavours(): {
2251
+ readonly text: string;
2252
+ readonly html: string | null;
2253
+ readonly reason?: 'unsupported-content';
2254
+ };
2255
+ /**
2256
+ * Route one paste payload by fidelity: embedded fragment, then external HTML, then
2257
+ * plain text. Unsupported object fragments refuse without fallback. Other decode, read,
2258
+ * or apply failures can degrade. Suggesting mode, non-body
2259
+ * stories and an armed force-plain all land on the plain lane. False when the payload
2260
+ * landed on no lane at all (nothing to insert).
2261
+ */
2262
+ pasteRich(text: string, html: string | null): boolean;
2263
+ /** The next paste routes plain, whatever its payload carries (Cmd+Shift+V). */
2264
+ armForcePlainPaste(): void;
2265
+ /** Remove the selection, if any. Returns whether anything was deleted. */
2266
+ deleteSelection(): boolean;
2267
+ navigate(command: NavigationCommand, extend?: boolean): void;
2268
+ /** Reverse the last history entry and put the caret back where it was made. */
2269
+ undo(): void;
2270
+ redo(): void;
2271
+ /**
2272
+ * Refresh table insertion furniture labels without remounting or relayout.
2273
+ *
2274
+ * @public
2275
+ */
2276
+ refreshTableInteractionLabels(): void;
2277
+ focus(): void;
2278
+ /**
2279
+ * Refresh table insertion furniture labels without remounting the surface.
2280
+ *
2281
+ * @public
2282
+ */
2283
+ setTableInteractionLabel(resolver: (key: 'table.insertRowBelow' | 'table.insertColumnRight') => string): void;
2284
+ destroy(): void;
2285
+ /**
2286
+ * The section a painted page belongs to, and the page that section starts on.
2287
+ *
2288
+ * Published because opening a furniture story without a page opens it without a section, and
2289
+ * the section is what the ruler clamps to and what a new table's grid is divided from. One
2290
+ * header part can serve several sections, so only the page settles which one the reader is
2291
+ * looking at.
2292
+ */
2293
+ sectionAtPage(pageIndex: number): {
2294
+ sectionIndex: number;
2295
+ sectionStart: number;
2296
+ };
2297
+ /** Active editing view — body, or an open header/footer story by rId. */
2298
+ activeScope(): ViewScope;
2299
+ /** Activate a view scope. Returns false when a header/footer rId cannot be opened. */
2300
+ setActiveScope(scope: ViewScope): boolean;
2301
+ /**
2302
+ * Open a header/footer story for editing on the painted surface.
2303
+ * Refuses dangling / unknown relationship ids.
2304
+ */
2305
+ enterHeaderFooter(args: {
2306
+ readonly rId: string;
2307
+ readonly pageIndex?: number;
2308
+ readonly sectionIndex?: number;
2309
+ readonly kind?: 'header' | 'footer';
2310
+ readonly variant?: 'default' | 'first' | 'even';
2311
+ readonly position?: SemanticPosition;
2312
+ }): boolean;
2313
+ /** Leave furniture editing and restore the prior body selection. */
2314
+ exitHeaderFooter(): void;
2315
+ /** Chrome read-model for the open furniture scope, or null when editing the body. */
2316
+ headerFooterState(): {
2317
+ readonly editing: 'header' | 'footer' | null;
2318
+ readonly sectionIndex: number;
2319
+ readonly variant?: 'default' | 'first' | 'even';
2320
+ readonly rId?: string;
2321
+ readonly partName?: string;
2322
+ readonly inherited?: boolean;
2323
+ readonly titlePage?: boolean;
2324
+ readonly evenAndOddHeaders?: boolean;
2325
+ readonly headerDistanceTwips?: number;
2326
+ readonly footerDistanceTwips?: number;
2327
+ } | null;
2328
+ /**
2329
+ * Commit one package-level furniture lifecycle op (create/delete/link/unlink/options).
2330
+ * Flushes layout so the next enter/rebind sees the new resolution.
2331
+ */
2332
+ applyHeaderFooterLifecycle(op: {
2333
+ readonly op: 'createHeaderFooter' | 'deleteHeaderFooter' | 'linkToPrevious' | 'unlinkFromPrevious' | 'setSectionFurnitureOptions' | 'setDocumentProtection';
2334
+ readonly sectionIndex?: number;
2335
+ /** `setDocumentProtection` only: enforce filling-in-forms protection, or lift it. */
2336
+ readonly enforce?: boolean;
2337
+ readonly kind?: 'header' | 'footer';
2338
+ readonly variant?: 'default' | 'first' | 'even';
2339
+ readonly titlePage?: boolean;
2340
+ readonly evenAndOddHeaders?: boolean;
2341
+ readonly headerDistanceTwips?: number;
2342
+ readonly footerDistanceTwips?: number;
2343
+ }): {
2344
+ readonly ok: true;
2345
+ } | {
2346
+ readonly ok: false;
2347
+ readonly reason: string;
2348
+ };
2349
+ /** Insert an allowlisted page field at the caret in the open HF story. */
2350
+ insertPageField(field: 'PAGE' | 'NUMPAGES' | 'SECTIONPAGES' | 'PAGE_X_OF_Y'): boolean;
2351
+ /** Insert a footnote/endnote at the body caret. */
2352
+ insertNote(noteKind: 'footnote' | 'endnote'): boolean;
2353
+ deleteNote(noteKind: 'footnote' | 'endnote', noteId: number): boolean;
2354
+ convertNote(fromKind: 'footnote' | 'endnote', noteId: number): boolean;
2355
+ convertAllNotes(fromKind: 'footnote' | 'endnote'): boolean;
2356
+ setNoteProperties(args: {
2357
+ readonly scope: 'document' | 'section';
2358
+ readonly sectionIndex?: number;
2359
+ readonly footnote?: {
2360
+ readonly numFmt?: string;
2361
+ readonly numRestart?: string;
2362
+ readonly position?: string;
2363
+ readonly numStart?: number;
2364
+ };
2365
+ readonly endnote?: {
2366
+ readonly numFmt?: string;
2367
+ readonly numRestart?: string;
2368
+ readonly position?: string;
2369
+ readonly numStart?: number;
2370
+ };
2371
+ }): boolean;
2372
+ enterNote(scopeId: string, position?: {
2373
+ paragraphId: string;
2374
+ offset: number;
2375
+ }): boolean;
2376
+ exitNote(): void;
2377
+ /** Resolved/authored note properties for the caret section — chrome read-model. */
2378
+ notePropertiesState(): NotePropertiesStateSnapshot | null;
2379
+ /** Plain-text preview for hover chrome — never returns markup. */
2380
+ notePreviewText(scopeId: string): string | null;
2381
+ /** Commit one table-command plan as a single store transaction. */
2382
+ applyTableCommandPlan(plan: TableCommandPlan): ExecResult;
2383
+ }
2384
+ /**
2385
+ * What opening a document produced: a mounted surface, or a refusal.
2386
+ *
2387
+ * A result rather than a throw, because every refusal here comes from FILE input — a package the
2388
+ * bounded reader rejected, a part that exceeded a limit — and a malformed upload should surface
2389
+ * as a message the host can show rather than an exception it has to catch.
2390
+ */
2391
+ type OpenPaginatedResult = {
2392
+ readonly ok: true;
2393
+ readonly surface: PaginatedSurface;
2394
+ } | {
2395
+ readonly ok: false;
2396
+ readonly reason: string;
2397
+ readonly detail?: string;
2398
+ };
2399
+
2400
+ /** One URL to fetch and the face it claims to be. */
2401
+ interface FontUrlSource {
2402
+ readonly url: string;
2403
+ readonly family: string;
2404
+ readonly weight: number;
2405
+ readonly style: 'normal' | 'italic';
2406
+ /**
2407
+ * Expected `sha256:` content hash. When present, mismatching bytes are REFUSED —
2408
+ * pin this for any URL not under the app's sole control.
2409
+ */
2410
+ readonly hash?: string;
2411
+ readonly faceIndex?: number;
2412
+ }
2413
+ /**
2414
+ * What to fetch, and under what limits.
2415
+ *
2416
+ * Only `sources` is required. Each carries its own expected hash, so bytes are trusted by
2417
+ * CONTENT rather than by origin — a swapped asset fails admission even from a trusted host.
2418
+ */
2419
+ interface LoadFontsRequest {
2420
+ readonly sources: readonly FontUrlSource[];
2421
+ /** Cache API bucket name; default `docx-editor-fonts`. */
2422
+ readonly cacheName?: string;
2423
+ /** Injectable for tests and CSP-constrained hosts; defaults to global `fetch`. */
2424
+ readonly fetcher?: typeof fetch;
2425
+ /** Per-font byte ceiling; defaults to the engine hard maximum. */
2426
+ readonly maxFontBytes?: number;
2427
+ /** Cancels loading with `signal.reason`, without returning per-source failures. */
2428
+ readonly signal?: AbortSignal;
2429
+ }
2430
+ /**
2431
+ * Why one font did not load.
2432
+ *
2433
+ * Distinguished rather than collapsed to "failed" because the responses differ: `networkError`
2434
+ * and `httpError` are worth retrying, while `hashMismatch` and `malformed` mean the bytes were
2435
+ * not what the source claimed and retrying will fetch the same wrong thing.
2436
+ */
2437
+ type FontLoadFailureReason = 'networkError' | 'httpError' | 'hashMismatch' | 'overLimit' | 'emptyResponse'
2438
+ /** The declared face itself is unusable (empty family, out-of-range weight); nothing was fetched. */
2439
+ | 'invalidRequest'
2440
+ /** The bytes are not a font at all — most often an HTML error page served with 200. */
2441
+ | 'malformed';
2442
+ /**
2443
+ * One face that did not load, with whatever evidence the failure produced.
2444
+ *
2445
+ * Non-fatal: {@link LoadFontsResult} still carries every source that succeeded, and the affected
2446
+ * family falls back to the engine's fixed measurement.
2447
+ */
2448
+ interface FontLoadFailure {
2449
+ readonly url: string;
2450
+ readonly request: FontFaceRequest;
2451
+ readonly reason: FontLoadFailureReason;
2452
+ /** HTTP status for `httpError`; hashes for `hashMismatch`. */
2453
+ readonly status?: number;
2454
+ readonly expectedHash?: string;
2455
+ readonly actualHash?: string;
2456
+ readonly diagnostic?: string;
2457
+ }
2458
+ /**
2459
+ * What one `loadFonts` call produced: the faces that arrived, plus the ones that did not.
2460
+ *
2461
+ * A `FontConfigurationFragment`, so it composes straight into `composeFontConfiguration`
2462
+ * alongside other font sources. Partial success is the normal case — compose it even with
2463
+ * failures present.
2464
+ */
2465
+ interface LoadFontsResult extends FontConfigurationFragment {
2466
+ readonly sources: readonly FontSource[];
2467
+ readonly failures: readonly FontLoadFailure[];
2468
+ }
2469
+ /**
2470
+ * Fetch app-specified font URLs into verified, cache-backed `FontSource`s.
2471
+ *
2472
+ * Fetches ONLY the URLs listed — never a default host or engine-chosen CDN — and never
2473
+ * rejects for a per-source failure: the result carries every admitted source and a
2474
+ * typed entry for every drop. Cancellation instead rejects with `signal.reason`. Compose the result with `composeFontConfiguration`.
2475
+ */
2476
+ declare function loadFonts(request: LoadFontsRequest): Promise<LoadFontsResult>;
2477
+ /**
2478
+ * Turn font bytes you ALREADY hold into a `FontSource` — a file input, IndexedDB, a
2479
+ * bundler import. `loadFonts` covers URLs; this covers everything else, so no caller has
2480
+ * to hand-assemble the record or reach for a hashing helper.
2481
+ *
2482
+ * Returns a typed failure instead of throwing when the descriptor or the bytes are
2483
+ * unusable, matching `loadFonts`: one bad face degrades itself, never its neighbours.
2484
+ */
2485
+ declare function createFontSource(bytes: Uint8Array, request: FontFaceRequest & {
2486
+ readonly faceIndex?: number;
2487
+ }, options?: {
2488
+ readonly id?: string;
2489
+ readonly maxFontBytes?: number;
2490
+ }): {
2491
+ readonly source: FontSource;
2492
+ } | {
2493
+ readonly failure: FontLoadFailure;
2494
+ };
2495
+
2496
+ /** Options for loading application fonts when the editor resolves its font configuration. @public */
2497
+ interface CustomFontsOptions extends Omit<LoadFontsRequest, 'signal'> {
2498
+ /** Reports each failed face. Defaults to a console warning. Cancellation does not call this handler. */
2499
+ readonly onFailure?: (failure: FontLoadFailure) => void;
2500
+ }
2501
+ /** A font origin that supplies validated application font bytes on demand. @public */
2502
+ type CustomFontsResolver = MarkedFontResolver<(request: FontResolutionRequest) => Promise<LoadFontsResult>>;
2503
+ /**
2504
+ * Supply application fonts without manual resolver wiring.
2505
+ *
2506
+ * Loads all listed faces when the editor resolves fonts, including families the document
2507
+ * does not use yet. This makes company fonts available in the font picker for new documents.
2508
+ * Faces supplied by earlier origins are skipped by family, weight, and style; family
2509
+ * matching ignores case. URLs always come from `sources`, never from document text.
2510
+ *
2511
+ * Uses {@link loadFonts} for validation, optional hash checks, and browser caching.
2512
+ * The editor registers the returned bytes under private aliases. This function does not
2513
+ * change the document's selected fonts or register page-wide family names.
2514
+ *
2515
+ * Constructing the resolver does not fetch. Cancellation of the document load rejects
2516
+ * with `signal.reason`, without warnings or `onFailure` calls. Other face failures are
2517
+ * reported once per resolution, and successful faces remain available to the editor.
2518
+ *
2519
+ * ```ts
2520
+ * const fonts = useFonts(
2521
+ * customFonts({ sources: companyFontFiles, onFailure: reportFontFailure }),
2522
+ * packagedFonts(),
2523
+ * googleFonts(),
2524
+ * );
2525
+ * ```
2526
+ *
2527
+ * Use {@link loadFonts} directly to load every listed face eagerly.
2528
+ * @public
2529
+ */
2530
+ declare function customFonts(options: CustomFontsOptions): CustomFontsResolver;
2531
+
2532
+ /**
2533
+ * A row that runs one chrome slot.
2534
+ *
2535
+ * @public
2536
+ */
2537
+ interface ChromeMenuItemEntry {
2538
+ readonly kind: 'item';
2539
+ readonly slot: ChromeSlotId;
2540
+ /**
2541
+ * Plain-label override for this row.
2542
+ *
2543
+ * A slot's own `labelKey` is a TOOLTIP key, and several of them fold the shortcut into
2544
+ * the text (`formattingBar.boldShortcut` is "Bold (Ctrl+B)"). A menu puts the shortcut
2545
+ * in its own right-hand column, so the row needs the bare noun. Both keys already exist
2546
+ * in the catalogue — this points at the plain one rather than minting a duplicate.
2547
+ */
2548
+ readonly labelKey?: string;
2549
+ /** i18n key of the shortcut shown right-aligned on the row (`toolbar.saveShortcut`). */
2550
+ readonly shortcutKey?: string;
2551
+ /**
2552
+ * The row opens a size PICKER instead of firing on click — Word's insert-table grid.
2553
+ * The slot still owns the label, the icon and the enabled state; only the dispatch
2554
+ * differs, and the picked size is what the host sends.
2555
+ */
2556
+ readonly picker?: 'tableGrid';
2557
+ }
2558
+ /**
2559
+ * A row that opens a nested panel of rows (Insert › Break).
2560
+ *
2561
+ * It carries its own label and icon rather than a slot, because a submenu PARENT has no
2562
+ * command: clicking it opens the panel. Giving it a slot would mint a public id for a
2563
+ * control that can never be enabled, and `toolbarCommandState` would have to invent an
2564
+ * answer about it.
2565
+ *
2566
+ * @public
2567
+ */
2568
+ interface ChromeMenuSubmenuEntry {
2569
+ readonly kind: 'submenu';
2570
+ readonly labelKey: string;
2571
+ readonly paths: readonly string[] | null;
2572
+ readonly items: readonly ChromeMenuEntry[];
2573
+ }
2574
+ /** A horizontal rule between groups of rows. @public */
2575
+ interface ChromeMenuSeparatorEntry {
2576
+ readonly kind: 'separator';
2577
+ }
2578
+ /** One row of a chrome menu. @public */
2579
+ type ChromeMenuEntry = ChromeMenuItemEntry | ChromeMenuSubmenuEntry | ChromeMenuSeparatorEntry;
2580
+ /**
2581
+ * Every menu id, as a literal union. Stable public API; renaming one is a breaking change,
2582
+ * exactly like a group or slot id.
2583
+ *
2584
+ * @public
2585
+ */
2586
+ type ChromeMenuId = 'file' | 'format' | 'insert' | 'review' | 'help';
2587
+ /** One menu of the menu bar. @public */
2588
+ interface ChromeMenu {
2589
+ readonly id: ChromeMenuId;
2590
+ readonly labelKey: string;
2591
+ readonly entries: readonly ChromeMenuEntry[];
2592
+ }
2593
+
2594
+ /**
2595
+ * HOW a control reaches the engine — never WHETHER it is enabled.
2596
+ *
2597
+ * Enabled state has exactly one source: `toolbarCommandState(editor, slot)`, which
2598
+ * asks `Editor.can`. The registry is static data and cannot know what the engine
2599
+ * will honour at this selection, in this document, at this moment.
2600
+ *
2601
+ * There used to be a fourth member, `parityOnly`, meaning "visible but permanently
2602
+ * disabled". It was a second, static answer to the question `Editor.can` already
2603
+ * answers, and it went stale the moment the engine wired underline, strike, the four
2604
+ * alignments, the list commands and the four value slots: the registry still said
2605
+ * parity-only, React ignored it and ran them, and Vue believed it and rendered twelve
2606
+ * WORKING commands permanently disabled. A slot the engine has not wired needs no
2607
+ * registry flag — `commandForSlot` answers null and `toolbarCommandState` disables the
2608
+ * control with the engine's own words ("not wired to an editor command").
2609
+ */
2610
+ type ChromeControlState =
2611
+ /**
2612
+ * Dispatched as one fixed engine command: enabled when
2613
+ * `Editor.can(commandForSlot(slot))` succeeds, a click runs
2614
+ * `runToolbarCommand(editor, slot)`. The command is resolved from the SLOT id
2615
+ * through `commandForSlot` in toolbar-commands.ts — the one command table both
2616
+ * adapters share. A slot with no row there is simply not wired YET, and says so
2617
+ * through the engine rather than through this descriptor.
2618
+ */
2619
+ {
2620
+ readonly kind: 'command';
2621
+ }
2622
+ /**
2623
+ * Dispatched with a PICKED value: `commandForSlotValue(slot, value)`. Enabled when
2624
+ * the engine would honour a well-formed value right now (`toolbarCommandState`
2625
+ * probes for exactly that), so the control needs chrome that produces a value — a
2626
+ * font list, a size, a colour — before a click means anything.
2627
+ *
2628
+ * A distinct kind because 'command' cannot describe it: there is no fixed command
2629
+ * to hand `Editor.can`, and a bare click has nothing to send.
2630
+ */
2631
+ | {
2632
+ readonly kind: 'value';
2633
+ }
2634
+ /** `Editor.save()` — not a command (see `runSave`). */
2635
+ | {
2636
+ readonly kind: 'save';
2637
+ }
2638
+ /**
2639
+ * `Editor.load()` — not a command either, and the exact twin of `save`: bytes cross the
2640
+ * boundary between the host and the engine, and only the host can produce them. The
2641
+ * control needs chrome that reads a file (a picker, a drop target) before a click means
2642
+ * anything, so a bare click has nothing to send — the same reason `save` is not `command`.
2643
+ *
2644
+ * A fourth kind rather than reusing `save` because the two dispatch in opposite
2645
+ * directions, and an adapter branching on `kind` must be able to tell them apart. Unlike
2646
+ * the deleted `parityOnly`, this one IS named by a control (`file.open`).
2647
+ */
2648
+ | {
2649
+ readonly kind: 'load';
2650
+ }
2651
+ /** Host conversion through `runChromeExport` or `runChromePrint`; not an editing command. */
2652
+ | {
2653
+ readonly kind: 'export';
2654
+ };
2655
+ /**
2656
+ * The SHAPE a control renders as (task M6V.1).
2657
+ *
2658
+ * The legacy toolbar is not a row of uniform icon buttons: it mixes labelled dropdowns
2659
+ * (`Normal`, `Arial`, alignment, line spacing), numeric steppers with visible values
2660
+ * (zoom `- 100% +`, size `- 26 +`), split colour controls (a glyph over a colour swatch
2661
+ * with its own caret), and a mode pill (`Editing`). Rendering all of them as icon
2662
+ * buttons is the difference an owner review called out as "not visual parity" — the
2663
+ * regions were all present and it still did not look like the product.
2664
+ */
2665
+ /** `modePill` is deliberately absent. It was declared, never used by any control, and
2666
+ * rendered nothing — the editing-mode control below is a `dropdown`, which is what the
2667
+ * legacy product shows. A shape no descriptor names is a branch adapters must implement
2668
+ * and can never exercise. */
2669
+ type ChromeControlShape = 'icon' | 'stepper' | 'dropdown' | 'colorSplit';
2670
+ /**
2671
+ * One toolbar control as the registry describes it — what it renders as, never whether it is
2672
+ * enabled.
2673
+ *
2674
+ * Enabled state has exactly ONE source, `toolbarCommandState`, which asks the engine. A
2675
+ * descriptor carrying its own disabled flag would be a second answer that goes stale the moment
2676
+ * the engine wires the slot.
2677
+ *
2678
+ * @public
2679
+ */
2680
+ interface ChromeControl<Id extends string = string> {
2681
+ /** Stable control id, unique WITHIN its group. Public API; renames are breaking. */
2682
+ readonly id: Id;
2683
+ /** How it renders. Defaults to `icon`. */
2684
+ readonly shape?: ChromeControlShape;
2685
+ /** Displayed value for a stepper or dropdown (an i18n key, or a literal for numbers). */
2686
+ readonly valueText?: string;
2687
+ /** Swatch colour for a `colorSplit` control. */
2688
+ readonly swatch?: string;
2689
+ /** i18n key for the accessible name and tooltip. Never hardcoded English. */
2690
+ readonly labelKey: string;
2691
+ /** Material Symbols path data, or null for a non-icon control (a picker). */
2692
+ readonly paths: readonly string[] | null;
2693
+ /** For pickers: the i18n key of the placeholder value shown. */
2694
+ readonly valueKey?: string;
2695
+ /** `false` keeps this public slot composable but omits it from the default toolbar. */
2696
+ readonly defaultToolbar?: false;
2697
+ readonly state: ChromeControlState;
2698
+ }
2699
+ /**
2700
+ * One toolbar group: the taxonomy both adapters derive their default arrangement FROM.
2701
+ *
2702
+ * Never hand-list controls in an adapter — a default toolbar is built by walking `CHROME_GROUPS`,
2703
+ * so a slot added here appears in React and Vue without either being edited.
2704
+ *
2705
+ * @public
2706
+ */
2707
+ interface ChromeGroup<Id extends string = string, ControlId extends string = string> {
2708
+ /** Stable group id. Public API; renames are breaking. */
2709
+ readonly id: Id;
2710
+ readonly labelKey: string;
2711
+ /**
2712
+ * Not part of the DEFAULT toolbar arrangement. The chrome spec shows these
2713
+ * controls only in a context the engine does not model yet (an image or table
2714
+ * selection), or not at all (save belongs in the host's File menu, never in the
2715
+ * bar). Their slots stay public for composition — a host can still place
2716
+ * `image.insert` or `file.save` explicitly — but the default chrome is the
2717
+ * registry's default bar, which ends at the editing-mode picker.
2718
+ */
2719
+ readonly contextual?: true;
2720
+ readonly controls: readonly ChromeControl<ControlId>[];
2721
+ }
2722
+ /**
2723
+ * The complete chrome, in bar order. Literal-typed (`as const`) so the slot-id
2724
+ * vocabulary below is derived from the data and cannot drift from it.
2725
+ *
2726
+ * Taxonomy taste: ids are short, lowercaseCamel, and never repeat their group's name
2727
+ * (`alignment.left`, not `alignment.alignLeft`; `font.family`, not `font.fontFamily`).
2728
+ */
2729
+ declare const CHROME_GROUPS: readonly [{
2730
+ readonly id: 'history';
2731
+ readonly labelKey: 'formattingBar.groups.history';
2732
+ readonly controls: readonly [{
2733
+ readonly id: 'undo';
2734
+ readonly labelKey: 'formattingBar.undoShortcut';
2735
+ readonly paths: readonly string[];
2736
+ readonly state: {
2737
+ readonly kind: 'command';
2738
+ };
2739
+ }, {
2740
+ readonly id: 'redo';
2741
+ readonly labelKey: 'formattingBar.redoShortcut';
2742
+ readonly paths: readonly string[];
2743
+ readonly state: {
2744
+ readonly kind: 'command';
2745
+ };
2746
+ }];
2747
+ }, {
2748
+ readonly id: 'zoom';
2749
+ readonly labelKey: 'formattingBar.groups.zoom';
2750
+ readonly controls: readonly [{
2751
+ readonly id: 'level';
2752
+ readonly shape: 'stepper';
2753
+ readonly valueText: '100%';
2754
+ readonly labelKey: 'formattingBar.groups.zoom';
2755
+ readonly paths: null;
2756
+ readonly valueKey: 'zoom.zoomLevel';
2757
+ readonly state: {
2758
+ readonly kind: 'command';
2759
+ };
2760
+ }];
2761
+ }, {
2762
+ readonly id: 'styles';
2763
+ readonly labelKey: 'formattingBar.groups.styles';
2764
+ readonly controls: readonly [{
2765
+ readonly id: 'style';
2766
+ readonly shape: 'dropdown';
2767
+ readonly labelKey: 'styles.selectAriaLabel';
2768
+ readonly paths: null;
2769
+ readonly valueKey: 'styles.normalText';
2770
+ readonly state: {
2771
+ readonly kind: 'value';
2772
+ };
2773
+ }];
2774
+ }, {
2775
+ readonly id: 'font';
2776
+ readonly labelKey: 'formattingBar.groups.font';
2777
+ readonly controls: readonly [{
2778
+ readonly id: 'family';
2779
+ readonly shape: 'dropdown';
2780
+ readonly labelKey: 'font.selectAriaLabel';
2781
+ readonly paths: null;
2782
+ readonly valueKey: 'font.sansSerif';
2783
+ readonly state: {
2784
+ readonly kind: 'value';
2785
+ };
2786
+ }, {
2787
+ readonly id: 'size';
2788
+ readonly shape: 'stepper';
2789
+ readonly valueText: '11';
2790
+ readonly labelKey: 'fontSize.listLabel';
2791
+ readonly paths: null;
2792
+ readonly valueKey: 'fontSize.label';
2793
+ readonly state: {
2794
+ readonly kind: 'value';
2795
+ };
2796
+ }];
2797
+ }, {
2798
+ readonly id: 'text';
2799
+ readonly labelKey: 'formattingBar.groups.textFormatting';
2800
+ readonly controls: readonly [{
2801
+ readonly id: 'bold';
2802
+ readonly labelKey: 'formattingBar.boldShortcut';
2803
+ readonly paths: readonly string[];
2804
+ readonly state: {
2805
+ readonly kind: 'command';
2806
+ };
2807
+ }, {
2808
+ readonly id: 'italic';
2809
+ readonly labelKey: 'formattingBar.italicShortcut';
2810
+ readonly paths: readonly string[];
2811
+ readonly state: {
2812
+ readonly kind: 'command';
2813
+ };
2814
+ }, {
2815
+ readonly id: 'underline';
2816
+ readonly labelKey: 'formattingBar.underlineShortcut';
2817
+ readonly paths: readonly string[];
2818
+ readonly state: {
2819
+ readonly kind: 'command';
2820
+ };
2821
+ }, {
2822
+ readonly id: 'strike';
2823
+ readonly labelKey: 'formattingBar.strikethrough';
2824
+ readonly paths: readonly string[];
2825
+ readonly state: {
2826
+ readonly kind: 'command';
2827
+ };
2828
+ }, {
2829
+ readonly id: 'color';
2830
+ readonly shape: 'colorSplit';
2831
+ readonly swatch: '#ff0000';
2832
+ readonly labelKey: 'formattingBar.fontColor';
2833
+ readonly paths: readonly string[];
2834
+ readonly state: {
2835
+ readonly kind: 'value';
2836
+ };
2837
+ }, {
2838
+ readonly id: 'highlight';
2839
+ readonly shape: 'colorSplit';
2840
+ readonly swatch: '#ffff00';
2841
+ readonly labelKey: 'formattingBar.highlightColor';
2842
+ readonly paths: readonly string[];
2843
+ readonly state: {
2844
+ readonly kind: 'value';
2845
+ };
2846
+ }, {
2847
+ readonly id: 'link';
2848
+ readonly labelKey: 'formattingBar.insertLinkShortcut';
2849
+ readonly paths: readonly string[];
2850
+ readonly state: {
2851
+ readonly kind: 'command';
2852
+ };
2853
+ }];
2854
+ }, {
2855
+ readonly id: 'script';
2856
+ readonly labelKey: 'formattingBar.groups.script';
2857
+ readonly controls: readonly [{
2858
+ readonly id: 'super';
2859
+ readonly labelKey: 'formattingBar.superscript';
2860
+ readonly paths: readonly string[];
2861
+ readonly state: {
2862
+ readonly kind: 'command';
2863
+ };
2864
+ }, {
2865
+ readonly id: 'sub';
2866
+ readonly labelKey: 'formattingBar.subscript';
2867
+ readonly paths: readonly string[];
2868
+ readonly state: {
2869
+ readonly kind: 'command';
2870
+ };
2871
+ }];
2872
+ }, {
2873
+ readonly id: 'alignment';
2874
+ readonly labelKey: 'formattingBar.groups.alignment';
2875
+ readonly controls: readonly [{
2876
+ readonly id: 'left';
2877
+ readonly labelKey: 'alignment.alignLeft';
2878
+ readonly paths: readonly string[];
2879
+ readonly state: {
2880
+ readonly kind: 'command';
2881
+ };
2882
+ }, {
2883
+ readonly id: 'center';
2884
+ readonly labelKey: 'alignment.center';
2885
+ readonly paths: readonly string[];
2886
+ readonly state: {
2887
+ readonly kind: 'command';
2888
+ };
2889
+ }, {
2890
+ readonly id: 'right';
2891
+ readonly labelKey: 'alignment.alignRight';
2892
+ readonly paths: readonly string[];
2893
+ readonly state: {
2894
+ readonly kind: 'command';
2895
+ };
2896
+ }, {
2897
+ readonly id: 'justify';
2898
+ readonly labelKey: 'alignment.justify';
2899
+ readonly paths: readonly string[];
2900
+ readonly state: {
2901
+ readonly kind: 'command';
2902
+ };
2903
+ }];
2904
+ }, {
2905
+ readonly id: 'direction';
2906
+ readonly labelKey: 'formattingBar.groups.direction';
2907
+ readonly contextual: true;
2908
+ readonly controls: readonly [{
2909
+ readonly id: 'ltr';
2910
+ readonly labelKey: 'toolbar.leftToRight';
2911
+ readonly paths: readonly string[];
2912
+ readonly state: {
2913
+ readonly kind: 'command';
2914
+ };
2915
+ }, {
2916
+ readonly id: 'rtl';
2917
+ readonly labelKey: 'toolbar.rightToLeft';
2918
+ readonly paths: readonly string[];
2919
+ readonly state: {
2920
+ readonly kind: 'command';
2921
+ };
2922
+ }];
2923
+ }, {
2924
+ readonly id: 'list';
2925
+ readonly labelKey: 'formattingBar.groups.listFormatting';
2926
+ readonly controls: readonly [{
2927
+ readonly id: 'bullet';
2928
+ readonly labelKey: 'lists.bulletList';
2929
+ readonly paths: readonly string[];
2930
+ readonly state: {
2931
+ readonly kind: 'command';
2932
+ };
2933
+ }, {
2934
+ readonly id: 'numbered';
2935
+ readonly labelKey: 'lists.numberedList';
2936
+ readonly paths: readonly string[];
2937
+ readonly state: {
2938
+ readonly kind: 'command';
2939
+ };
2940
+ }, {
2941
+ readonly id: 'outdent';
2942
+ readonly labelKey: 'lists.decreaseIndent';
2943
+ readonly paths: readonly string[];
2944
+ readonly state: {
2945
+ readonly kind: 'command';
2946
+ };
2947
+ }, {
2948
+ readonly id: 'indent';
2949
+ readonly labelKey: 'lists.increaseIndent';
2950
+ readonly paths: readonly string[];
2951
+ readonly state: {
2952
+ readonly kind: 'command';
2953
+ };
2954
+ }, {
2955
+ readonly id: 'lineSpacing';
2956
+ readonly shape: 'dropdown';
2957
+ readonly labelKey: 'lineSpacing.label';
2958
+ readonly paths: readonly string[];
2959
+ readonly state: {
2960
+ readonly kind: 'command';
2961
+ };
2962
+ }];
2963
+ }, {
2964
+ readonly id: 'format';
2965
+ readonly labelKey: 'formattingBar.groups.format';
2966
+ readonly controls: readonly [{
2967
+ readonly id: 'painter';
2968
+ readonly labelKey: 'formattingBar.formatPainterShortcut';
2969
+ readonly paths: readonly string[];
2970
+ readonly state: {
2971
+ readonly kind: 'command';
2972
+ };
2973
+ }, {
2974
+ readonly id: 'clear';
2975
+ readonly labelKey: 'formattingBar.clearFormatting';
2976
+ readonly paths: readonly string[];
2977
+ readonly state: {
2978
+ readonly kind: 'command';
2979
+ };
2980
+ }];
2981
+ }, {
2982
+ readonly id: 'review';
2983
+ readonly labelKey: 'formattingBar.commentsAndChanges';
2984
+ readonly controls: readonly [{
2985
+ readonly id: 'revisionMarkup';
2986
+ readonly shape: 'icon';
2987
+ readonly labelKey: 'revisionMarkup.title';
2988
+ readonly defaultToolbar: false;
2989
+ readonly paths: readonly string[];
2990
+ readonly state: {
2991
+ readonly kind: 'command';
2992
+ };
2993
+ }, {
2994
+ readonly id: 'simpleMarkup';
2995
+ readonly shape: 'icon';
2996
+ readonly labelKey: 'review.simpleMarkup';
2997
+ readonly defaultToolbar: false;
2998
+ readonly paths: readonly string[];
2999
+ readonly state: {
3000
+ readonly kind: 'command';
3001
+ };
3002
+ }, {
3003
+ readonly id: 'allMarkup';
3004
+ readonly shape: 'icon';
3005
+ readonly labelKey: 'review.allMarkup';
3006
+ readonly defaultToolbar: false;
3007
+ readonly paths: readonly string[];
3008
+ readonly state: {
3009
+ readonly kind: 'command';
3010
+ };
3011
+ }, {
3012
+ readonly id: 'noMarkup';
3013
+ readonly shape: 'icon';
3014
+ readonly labelKey: 'review.noMarkup';
3015
+ readonly defaultToolbar: false;
3016
+ readonly paths: readonly string[];
3017
+ readonly state: {
3018
+ readonly kind: 'command';
3019
+ };
3020
+ }, {
3021
+ readonly id: 'original';
3022
+ readonly shape: 'icon';
3023
+ readonly labelKey: 'review.original';
3024
+ readonly defaultToolbar: false;
3025
+ readonly paths: readonly string[];
3026
+ readonly state: {
3027
+ readonly kind: 'command';
3028
+ };
3029
+ }, {
3030
+ readonly id: 'previousChange';
3031
+ readonly shape: 'icon';
3032
+ readonly labelKey: 'review.previousChange';
3033
+ readonly defaultToolbar: false;
3034
+ readonly paths: readonly string[];
3035
+ readonly state: {
3036
+ readonly kind: 'command';
3037
+ };
3038
+ }, {
3039
+ readonly id: 'nextChange';
3040
+ readonly shape: 'icon';
3041
+ readonly labelKey: 'review.nextChange';
3042
+ readonly defaultToolbar: false;
3043
+ readonly paths: readonly string[];
3044
+ readonly state: {
3045
+ readonly kind: 'command';
3046
+ };
3047
+ }, {
3048
+ readonly id: 'acceptAllChanges';
3049
+ readonly shape: 'icon';
3050
+ readonly labelKey: 'review.acceptAllChanges';
3051
+ readonly defaultToolbar: false;
3052
+ readonly paths: readonly string[];
3053
+ readonly state: {
3054
+ readonly kind: 'command';
3055
+ };
3056
+ }, {
3057
+ readonly id: 'rejectAllChanges';
3058
+ readonly shape: 'icon';
3059
+ readonly labelKey: 'review.rejectAllChanges';
3060
+ readonly defaultToolbar: false;
3061
+ readonly paths: readonly string[];
3062
+ readonly state: {
3063
+ readonly kind: 'command';
3064
+ };
3065
+ }, {
3066
+ readonly id: 'paragraphMarks';
3067
+ readonly shape: 'icon';
3068
+ readonly labelKey: 'formattingBar.paragraphMarks';
3069
+ readonly defaultToolbar: false;
3070
+ readonly paths: readonly string[];
3071
+ readonly state: {
3072
+ readonly kind: 'command';
3073
+ };
3074
+ }, {
3075
+ readonly id: 'protectDocument';
3076
+ readonly shape: 'icon';
3077
+ readonly labelKey: 'review.protectDocument';
3078
+ readonly defaultToolbar: false;
3079
+ readonly paths: readonly string[];
3080
+ readonly state: {
3081
+ readonly kind: 'command';
3082
+ };
3083
+ }, {
3084
+ readonly id: 'comments';
3085
+ readonly shape: 'icon';
3086
+ readonly labelKey: 'formattingBar.commentsAndChanges';
3087
+ readonly paths: readonly string[];
3088
+ readonly state: {
3089
+ readonly kind: 'command';
3090
+ };
3091
+ }, {
3092
+ readonly id: 'addComment';
3093
+ readonly shape: 'icon';
3094
+ readonly labelKey: 'formattingBar.addComment';
3095
+ readonly defaultToolbar: false;
3096
+ readonly paths: readonly string[];
3097
+ readonly state: {
3098
+ readonly kind: 'command';
3099
+ };
3100
+ }, {
3101
+ readonly id: 'authors';
3102
+ readonly shape: 'dropdown';
3103
+ readonly labelKey: 'reviewers.label';
3104
+ readonly paths: readonly string[];
3105
+ readonly defaultToolbar: false;
3106
+ readonly state: {
3107
+ readonly kind: 'command';
3108
+ };
3109
+ }, {
3110
+ readonly id: 'editingMode';
3111
+ readonly shape: 'dropdown';
3112
+ readonly labelKey: 'editingMode.label';
3113
+ readonly valueKey: 'editingMode.editing';
3114
+ readonly paths: readonly string[];
3115
+ readonly state: {
3116
+ readonly kind: 'command';
3117
+ };
3118
+ }];
3119
+ }, {
3120
+ readonly id: 'contentControl';
3121
+ readonly labelKey: 'contentControl.group';
3122
+ readonly contextual: true;
3123
+ readonly controls: readonly [{
3124
+ readonly id: 'showAll';
3125
+ readonly labelKey: 'contentControl.showAll';
3126
+ readonly paths: readonly string[];
3127
+ readonly state: {
3128
+ readonly kind: 'command';
3129
+ };
3130
+ }, {
3131
+ readonly id: 'formFill';
3132
+ readonly labelKey: 'contentControl.formFill';
3133
+ readonly paths: readonly string[];
3134
+ readonly state: {
3135
+ readonly kind: 'command';
3136
+ };
3137
+ }, {
3138
+ readonly id: 'inspector';
3139
+ readonly labelKey: 'contentControl.inspector';
3140
+ readonly paths: readonly string[];
3141
+ readonly state: {
3142
+ readonly kind: 'command';
3143
+ };
3144
+ }, {
3145
+ readonly id: 'remove';
3146
+ readonly labelKey: 'contentControl.remove';
3147
+ readonly paths: readonly string[];
3148
+ readonly state: {
3149
+ readonly kind: 'command';
3150
+ };
3151
+ }];
3152
+ }, {
3153
+ readonly id: 'image';
3154
+ readonly labelKey: 'formattingBar.groups.image';
3155
+ readonly contextual: true;
3156
+ readonly controls: readonly [{
3157
+ readonly id: 'insert';
3158
+ readonly labelKey: 'toolbar.image';
3159
+ readonly paths: readonly string[];
3160
+ readonly state: {
3161
+ readonly kind: 'command';
3162
+ };
3163
+ }, {
3164
+ readonly id: 'properties';
3165
+ readonly labelKey: 'formattingBar.imagePropertiesShortcut';
3166
+ readonly paths: readonly string[];
3167
+ readonly state: {
3168
+ readonly kind: 'command';
3169
+ };
3170
+ }, {
3171
+ readonly id: 'wrap';
3172
+ readonly shape: 'dropdown';
3173
+ readonly labelKey: 'formattingBar.imageWrap';
3174
+ readonly paths: readonly string[];
3175
+ readonly valueKey: 'imageWrap.inline';
3176
+ readonly state: {
3177
+ readonly kind: 'value';
3178
+ };
3179
+ }, {
3180
+ readonly id: 'altText';
3181
+ readonly shape: 'dropdown';
3182
+ readonly labelKey: 'formattingBar.altText';
3183
+ readonly paths: null;
3184
+ readonly valueKey: 'imageProperties.altText';
3185
+ readonly state: {
3186
+ readonly kind: 'value';
3187
+ };
3188
+ }];
3189
+ }, {
3190
+ readonly id: 'table';
3191
+ readonly labelKey: 'formattingBar.groups.table';
3192
+ readonly contextual: true;
3193
+ readonly controls: readonly [{
3194
+ readonly id: 'insert';
3195
+ readonly labelKey: 'toolbar.table';
3196
+ readonly paths: readonly string[];
3197
+ readonly state: {
3198
+ readonly kind: 'command';
3199
+ };
3200
+ }, {
3201
+ readonly id: 'borderTarget';
3202
+ readonly shape: 'dropdown';
3203
+ readonly labelKey: 'table.borders.tooltip';
3204
+ readonly paths: readonly string[];
3205
+ readonly state: {
3206
+ readonly kind: 'value';
3207
+ };
3208
+ }, {
3209
+ readonly id: 'borderColor';
3210
+ readonly shape: 'colorSplit';
3211
+ readonly swatch: '#000000';
3212
+ readonly labelKey: 'table.borderColor';
3213
+ readonly paths: readonly string[];
3214
+ readonly state: {
3215
+ readonly kind: 'value';
3216
+ };
3217
+ }, {
3218
+ readonly id: 'borderStyle';
3219
+ readonly shape: 'dropdown';
3220
+ readonly labelKey: 'table.borders.styleAriaLabel';
3221
+ readonly paths: readonly string[];
3222
+ readonly state: {
3223
+ readonly kind: 'value';
3224
+ };
3225
+ }, {
3226
+ readonly id: 'borderWidth';
3227
+ readonly shape: 'dropdown';
3228
+ readonly labelKey: 'table.borderWidth';
3229
+ readonly paths: readonly string[];
3230
+ readonly state: {
3231
+ readonly kind: 'value';
3232
+ };
3233
+ }, {
3234
+ readonly id: 'cellFill';
3235
+ readonly shape: 'colorSplit';
3236
+ readonly swatch: '#ffffff';
3237
+ readonly labelKey: 'table.cellFillColor';
3238
+ readonly paths: readonly string[];
3239
+ readonly state: {
3240
+ readonly kind: 'value';
3241
+ };
3242
+ }];
3243
+ }, {
3244
+ readonly id: 'paragraph';
3245
+ readonly labelKey: 'dialogs.paragraph.title';
3246
+ readonly contextual: true;
3247
+ readonly controls: readonly [{
3248
+ readonly id: 'dialog';
3249
+ readonly labelKey: 'lineSpacing.options';
3250
+ readonly paths: readonly string[];
3251
+ readonly state: {
3252
+ readonly kind: 'command';
3253
+ };
3254
+ }];
3255
+ }, {
3256
+ readonly id: 'file';
3257
+ readonly labelKey: 'toolbar.file';
3258
+ readonly contextual: true;
3259
+ readonly controls: readonly [{
3260
+ readonly id: 'open';
3261
+ readonly labelKey: 'toolbar.open';
3262
+ readonly paths: readonly string[];
3263
+ readonly state: {
3264
+ readonly kind: 'load';
3265
+ };
3266
+ }, {
3267
+ readonly id: 'save';
3268
+ readonly labelKey: 'toolbar.saveShortcut';
3269
+ readonly paths: readonly string[];
3270
+ readonly state: {
3271
+ readonly kind: 'save';
3272
+ };
3273
+ }, {
3274
+ readonly id: 'exportMarkdown';
3275
+ readonly labelKey: 'toolbar.exportMarkdown';
3276
+ readonly paths: readonly string[];
3277
+ readonly state: {
3278
+ readonly kind: 'export';
3279
+ };
3280
+ }, {
3281
+ readonly id: 'exportPdf';
3282
+ readonly labelKey: 'toolbar.exportPdf';
3283
+ readonly paths: readonly string[];
3284
+ readonly state: {
3285
+ readonly kind: 'export';
3286
+ };
3287
+ }, {
3288
+ readonly id: 'print';
3289
+ readonly labelKey: 'toolbar.print';
3290
+ readonly paths: readonly string[];
3291
+ readonly state: {
3292
+ readonly kind: 'export';
3293
+ };
3294
+ }, {
3295
+ readonly id: 'pageSetup';
3296
+ readonly labelKey: 'toolbar.pageSetup';
3297
+ readonly paths: readonly string[];
3298
+ readonly state: {
3299
+ readonly kind: 'command';
3300
+ };
3301
+ }];
3302
+ }, {
3303
+ readonly id: 'insert';
3304
+ readonly labelKey: 'toolbar.insert';
3305
+ readonly contextual: true;
3306
+ readonly controls: readonly [{
3307
+ readonly id: 'textBox';
3308
+ readonly labelKey: 'toolbar.insertTextBox';
3309
+ readonly paths: readonly string[];
3310
+ readonly state: {
3311
+ readonly kind: 'command';
3312
+ };
3313
+ }, {
3314
+ readonly id: 'footnote';
3315
+ readonly labelKey: 'toolbar.insertFootnote';
3316
+ readonly paths: readonly string[];
3317
+ readonly state: {
3318
+ readonly kind: 'command';
3319
+ };
3320
+ }, {
3321
+ readonly id: 'endnote';
3322
+ readonly labelKey: 'toolbar.insertEndnote';
3323
+ readonly paths: readonly string[];
3324
+ readonly state: {
3325
+ readonly kind: 'command';
3326
+ };
3327
+ }, {
3328
+ readonly id: 'pageNumber';
3329
+ readonly labelKey: 'headerFooter.insertPageNumber';
3330
+ readonly paths: readonly string[];
3331
+ readonly state: {
3332
+ readonly kind: 'command';
3333
+ };
3334
+ }, {
3335
+ readonly id: 'totalPages';
3336
+ readonly labelKey: 'headerFooter.insertTotalPages';
3337
+ readonly paths: readonly string[];
3338
+ readonly state: {
3339
+ readonly kind: 'command';
3340
+ };
3341
+ }, {
3342
+ readonly id: 'sectionPages';
3343
+ readonly labelKey: 'headerFooter.insertSectionPages';
3344
+ readonly paths: readonly string[];
3345
+ readonly state: {
3346
+ readonly kind: 'command';
3347
+ };
3348
+ }, {
3349
+ readonly id: 'pageXofY';
3350
+ readonly labelKey: 'headerFooter.insertPageXofY';
3351
+ readonly paths: readonly string[];
3352
+ readonly state: {
3353
+ readonly kind: 'command';
3354
+ };
3355
+ }, {
3356
+ readonly id: 'pageBreak';
3357
+ readonly labelKey: 'toolbar.pageBreak';
3358
+ readonly paths: readonly string[];
3359
+ readonly state: {
3360
+ readonly kind: 'command';
3361
+ };
3362
+ }, {
3363
+ readonly id: 'sectionBreakNextPage';
3364
+ readonly labelKey: 'toolbar.sectionBreakNextPage';
3365
+ readonly paths: readonly string[];
3366
+ readonly state: {
3367
+ readonly kind: 'command';
3368
+ };
3369
+ }, {
3370
+ readonly id: 'sectionBreakContinuous';
3371
+ readonly labelKey: 'toolbar.sectionBreakContinuous';
3372
+ readonly paths: readonly string[];
3373
+ readonly state: {
3374
+ readonly kind: 'command';
3375
+ };
3376
+ }, {
3377
+ readonly id: 'toc';
3378
+ readonly labelKey: 'toolbar.tableOfContents';
3379
+ readonly paths: readonly string[];
3380
+ readonly state: {
3381
+ readonly kind: 'command';
3382
+ };
3383
+ }];
3384
+ }];
3385
+ /**
3386
+ * Every group id in the chrome, as a literal union. Stable public API; renaming a group
3387
+ * id is a breaking change.
3388
+ *
3389
+ * @public
3390
+ */
3391
+ type ChromeGroupId = 'history' | 'zoom' | 'styles' | 'font' | 'text' | 'script' | 'alignment' | 'direction' | 'list' | 'format' | 'review' | 'contentControl' | 'image' | 'table' | 'paragraph' | 'file' | 'insert';
3392
+ /**
3393
+ * The public slot vocabulary: `${groupId}.${controlId}` for every control that actually
3394
+ * exists — `text.bold`, `font.family`, `alignment.left`. THE stable contract a host
3395
+ * composes against and `commandForSlot` resolves; renaming a slot is a breaking change.
3396
+ *
3397
+ * @public
3398
+ */
3399
+ type ChromeSlotId = 'history.undo' | 'history.redo' | 'zoom.level' | 'styles.style' | 'font.family' | 'font.size' | 'text.bold' | 'text.italic' | 'text.underline' | 'text.strike' | 'text.color' | 'text.highlight' | 'text.link' | 'script.super' | 'script.sub' | 'alignment.left' | 'alignment.center' | 'alignment.right' | 'alignment.justify' | 'direction.ltr' | 'direction.rtl' | 'list.bullet' | 'list.numbered' | 'list.outdent' | 'list.indent' | 'list.lineSpacing' | 'format.painter' | 'format.clear' | 'review.revisionMarkup' | 'review.comments' | 'review.addComment' | 'review.paragraphMarks' | 'review.protectDocument' | 'review.simpleMarkup' | 'review.allMarkup' | 'review.noMarkup' | 'review.original' | 'review.previousChange' | 'review.nextChange' | 'review.acceptAllChanges' | 'review.rejectAllChanges' | 'review.authors' | 'review.editingMode' | 'contentControl.showAll' | 'contentControl.formFill' | 'contentControl.inspector' | 'contentControl.remove' | 'image.insert' | 'image.properties' | 'image.wrap' | 'image.altText' | 'table.insert' | 'table.borderTarget' | 'table.borderColor' | 'table.borderStyle' | 'table.borderWidth' | 'table.cellFill' | 'file.open' | 'file.save' | 'file.exportMarkdown' | 'file.exportPdf' | 'file.print' | 'paragraph.dialog' | 'file.pageSetup' | 'insert.textBox' | 'insert.footnote' | 'insert.endnote' | 'insert.pageNumber' | 'insert.totalPages' | 'insert.sectionPages' | 'insert.pageXofY' | 'insert.pageBreak' | 'insert.sectionBreakNextPage' | 'insert.sectionBreakContinuous' | 'insert.toc';
3400
+ /**
3401
+ * Every control id in the chrome, as a literal union. Unique WITHIN a group, not
3402
+ * globally (`image.insert` / `table.insert`) — key consumers on {@link ChromeSlotId}.
3403
+ *
3404
+ * @public
3405
+ */
3406
+ type ChromeControlId = ChromeSlotId extends `${string}.${infer C}` ? C : never;
3407
+ /**
3408
+ * The slot id of one control within its group. Only meaningful for entries of
3409
+ * `CHROME_GROUPS` — the cast is sound because every group/control pair in the registry
3410
+ * is, by construction, a member of the `ChromeSlotId` union.
3411
+ *
3412
+ * @public
3413
+ */
3414
+ declare function chromeSlotId(group: {
3415
+ readonly id: string;
3416
+ }, control: {
3417
+ readonly id: string;
3418
+ }): ChromeSlotId;
3419
+ /**
3420
+ * The groups of the DEFAULT toolbar arrangement, in bar order: every group that is
3421
+ * not `contextual`. This is the registry's default bar — undo/redo through the
3422
+ * editing-mode picker — and what both adapters render when the host composes
3423
+ * nothing. Contextual slots (`image.*`, `table.insert`, `file.save`) remain
3424
+ * available for explicit composition.
3425
+ *
3426
+ * @public
3427
+ */
3428
+ declare function defaultChromeGroups(): readonly ChromeGroup[];
3429
+ /**
3430
+ * The formatting-bar groups for one editor snapshot: the default bar, plus the
3431
+ * contextual `image` group when a drawing is selected. Insertion without a selection
3432
+ * lives in the packaged Insert menu (`CHROME_MENUS`), not in the bar — a host that wants
3433
+ * a bar button places `DocxEditor.Toolbar.ImageInsert` itself.
3434
+ *
3435
+ * @public
3436
+ */
3437
+ declare function formattingBarChromeGroups(image: ImageContext | null): readonly ChromeGroup[];
3438
+
3439
+ /**
3440
+ * The menu bar the chrome shows above the toolbar, in bar order: File, Format, Insert, Review,
3441
+ * Help.
3442
+ *
3443
+ * @public
3444
+ */
3445
+ declare const CHROME_MENUS: readonly ChromeMenu[];
3446
+ /**
3447
+ * Every slot a menu places, in menu order, submenus flattened. What a parity test asserts
3448
+ * against, and what a host enumerates to know which capabilities the menu bar reaches.
3449
+ *
3450
+ * @public
3451
+ */
3452
+ declare function chromeMenuSlots(): readonly ChromeSlotId[];
3453
+ /** Total controls, so a parity test can assert none were dropped. */
3454
+ declare function chromeControlCount(): number;
3455
+ /** Tooltip for adapter controls without a picker; command refusals use engine reasons. */
3456
+ declare const CHROME_UNAVAILABLE_KEY = "formattingBar.unavailableInPreview";
3457
+
3458
+ /** Material Symbol name → SVG path data (viewBox "0 -960 960 960"). */
3459
+ declare const GENERATED_ICON_PATHS: Readonly<Record<string, readonly string[]>>;
3460
+
3461
+ /** Border target picker value — concrete scopes plus clear (`none`). */
3462
+ type TableBorderTargetValue = TableBorderEdgeTarget | 'none';
3463
+ /** UI draft: last active edge scope and the complete border spec to reapply. */
3464
+ interface TableChromeDraft {
3465
+ readonly activeTarget: TableBorderEdgeTarget;
3466
+ readonly spec: TableBorderSpec;
3467
+ }
3468
+ /** The draft a table's border chrome starts from: a 1pt black single border on every edge. */
3469
+ declare const DEFAULT_TABLE_CHROME_DRAFT: TableChromeDraft;
3470
+ /**
3471
+ * The chrome slots that only exist while the caret is inside a table.
3472
+ *
3473
+ * A subset of `ChromeSlotId`, so these names are public API on the same terms — renaming one is
3474
+ * a breaking change.
3475
+ */
3476
+ type TableChromeSlotId = 'table.borderTarget' | 'table.borderColor' | 'table.borderStyle' | 'table.borderWidth' | 'table.cellFill';
3477
+ /** Every {@link TableChromeSlotId}, for iteration and for {@link isTableChromeSlot}. */
3478
+ declare const TABLE_CHROME_SLOT_IDS: readonly TableChromeSlotId[];
3479
+ /** Furniture insertion controls (Task 8) share this label seam. */
3480
+ type TableInteractionLabelKey = 'table.insertRowBelow' | 'table.insertColumnRight';
3481
+ /**
3482
+ * The English label for a furniture-insertion control.
3483
+ *
3484
+ * The FALLBACK, for a host that has not wired its own translator — adapters pass their
3485
+ * `useTranslation` result instead so the control follows the app's locale.
3486
+ */
3487
+ declare function defaultTableLabel(key: TableInteractionLabelKey): string;
3488
+ /** Whether a chrome slot is one of the table-only ones. Narrows the type. */
3489
+ declare function isTableChromeSlot(slot: ChromeSlotId): slot is TableChromeSlotId;
3490
+ /** Contextual table chrome is visible when the engine reports table context. */
3491
+ declare function tableChromeVisible(table: TableContext | null | undefined): boolean;
3492
+ /** One entry in the border-target picker: which edges it addresses, its icon, and its label key. */
3493
+ interface TableBorderTargetOption {
3494
+ readonly value: TableBorderTargetValue;
3495
+ readonly icon: keyof typeof GENERATED_ICON_PATHS;
3496
+ /** i18n key, never a literal string — both adapters translate it themselves. */
3497
+ readonly labelKey: string;
3498
+ }
3499
+ /** The border-target picker's entries, in Word's own order, ending with clear. */
3500
+ declare const TABLE_BORDER_TARGET_OPTIONS: readonly TableBorderTargetOption[];
3501
+ /** One entry in the border-style picker, with the CSS class that draws its preview line. */
3502
+ interface TableBorderStyleOption {
3503
+ readonly value: TableBorderStyle;
3504
+ readonly labelKey: string;
3505
+ /** Class on the preview swatch. Defined in the core stylesheet, which both adapters import. */
3506
+ readonly previewClass: string;
3507
+ }
3508
+ /** The border-style picker's entries. */
3509
+ declare const TABLE_BORDER_STYLE_OPTIONS: readonly TableBorderStyleOption[];
3510
+ /** One entry in the border-width picker. */
3511
+ interface TableBorderWidthOption {
3512
+ /** `w:sz` — eighths of a point, as OOXML stores border widths. */
3513
+ readonly size: number;
3514
+ readonly labelKey: string;
3515
+ /** Points, for drawing the preview swatch. `size / 8`. */
3516
+ readonly previewThickness: number;
3517
+ }
3518
+ /** Widths in eighths of a point — Word-like presets. */
3519
+ declare const TABLE_BORDER_WIDTH_OPTIONS: readonly TableBorderWidthOption[];
3520
+ /**
3521
+ * What one table-chrome selection produced: the command to run, and the draft to remember.
3522
+ *
3523
+ * Both halves matter. A border picker is stateful — choosing "dashed" and then "outside" must
3524
+ * apply a dashed outside border — so each pick returns the COMPLETE spec to execute alongside the
3525
+ * draft the next pick builds on.
3526
+ */
3527
+ interface TableChromePick {
3528
+ readonly command: EditorCommand;
3529
+ readonly nextDraft: TableChromeDraft;
3530
+ }
3531
+ /**
3532
+ * Build the engine command for one table chrome pick and the draft state after it.
3533
+ * Target picks apply the current complete spec; `none` clears the active target only.
3534
+ */
3535
+ declare function applyTableChromePick(draft: TableChromeDraft, slot: TableChromeSlotId, value: unknown): TableChromePick | null;
3536
+ /** Probe command for `Editor.can` — uses the draft's active target and a well-formed value. */
3537
+ declare function probeTableChromeCommand(slot: TableChromeSlotId, draft?: TableChromeDraft): EditorCommand | null;
3538
+ /**
3539
+ * The i18n key naming one border target, for a trigger that shows the active scope.
3540
+ *
3541
+ * Falls back to the "all" key rather than throwing: a label is chrome, and a missing one should
3542
+ * not take the toolbar down.
3543
+ */
3544
+ declare function tableChromeLabelKeyForTarget(target: TableBorderEdgeTarget): string;
3545
+ /** Material Symbol paths for one table chrome icon name. */
3546
+ declare function tableChromeIconPaths(name: keyof typeof GENERATED_ICON_PATHS): readonly string[];
3547
+
3548
+ /** Value types accepted by toolbar controls. Font size uses half-points. @public */
3549
+ interface ToolbarValueMap {
3550
+ 'font.family': string;
3551
+ 'font.size': number;
3552
+ 'text.color': string;
3553
+ 'text.highlight': string;
3554
+ 'styles.style': string;
3555
+ 'list.lineSpacing': number;
3556
+ 'image.wrap': ImageWrapTarget;
3557
+ 'image.altText': string;
3558
+ 'review.editingMode': 'editing' | 'suggesting' | 'viewing';
3559
+ }
3560
+ /** @public */
3561
+ type ToolbarValueSlot = keyof ToolbarValueMap | TableChromeSlotId;
3562
+ /** @public */
3563
+ type ToolbarSlotValue<K extends ToolbarValueSlot> = K extends keyof ToolbarValueMap ? ToolbarValueMap[K] : unknown;
3564
+ /** A command hook keeps its nullary event-handler form and accepts explicit options. @public */
3565
+ interface EditorCommandExecute {
3566
+ (): boolean;
3567
+ (options: EditorExecOptions): boolean;
3568
+ }
3569
+ /** Ignore framework events passed to a command used directly as an event handler. */
3570
+ declare function commandExecOptions(value: unknown): EditorExecOptions | undefined;
3571
+
3572
+ /**
3573
+ * The probe a slot uses to ask "would the engine honour this right now?" when its real
3574
+ * command needs an argument the slot itself cannot supply.
3575
+ *
3576
+ * `text.link` is the case: whether this selection could become a link is the engine's
3577
+ * question, but WHICH link is a URL field's. Chrome that owns a link UI (React's
3578
+ * `ToolbarLink`) asks with this and dispatches through that UI.
3579
+ *
3580
+ * DELIBERATELY NOT in `SLOT_COMMANDS`. Enabled state has one source, and putting the probe
3581
+ * there would enable the control in EVERY adapter — including Vue, which has grown no link
3582
+ * UI, where the result is an enabled button whose click can only be refused. A dead button
3583
+ * is the worse lie: `file.save` was a disabled control for a capability that works, and this
3584
+ * would be an enabled control for one that is not reachable. Vue's slot therefore keeps
3585
+ * reporting the honest "not wired to an editor command" until its popover lands.
3586
+ *
3587
+ * @public
3588
+ */
3589
+ declare function chromeProbeForSlot(slotId: ChromeSlotId): EditorCommand | null;
3590
+ /**
3591
+ * The public editor command behind one chrome slot, or `null` when the slot is
3592
+ * not wired to a command yet (parity-only chrome, or save — which is not a
3593
+ * command). The single source of command truth for both adapters.
3594
+ *
3595
+ * @public
3596
+ */
3597
+ declare function commandForSlot(slotId: ChromeSlotId): EditorCommand | null;
3598
+
3599
+ /**
3600
+ * Build an engine command for one table chrome slot using the caller's draft state.
3601
+ *
3602
+ * @public
3603
+ */
3604
+ declare function commandForTableChromeSlotValue(slotId: TableChromeSlotId, value: unknown, draft: TableChromeDraft): EditorCommand | null;
3605
+ /**
3606
+ * The engine command for a VALUE-TYPED slot carrying the picked value, or `null` for a
3607
+ * slot that does not take a value.
3608
+ *
3609
+ * Two families: the run-property pickers (`font.family`, `font.size`, `text.color`,
3610
+ * `text.highlight`) resolve to `setMarkAttr`, and `styles.style` resolves to
3611
+ * `setParagraphStyle` — a paragraph styleId, not a mark. Either way the value is
3612
+ * validated by the engine's own gate (`can` refuses a malformed one with `invalidArgs`;
3613
+ * a styleId the document does not define is refused at `exec`), so a host can pass user
3614
+ * input through unmodified.
3615
+ *
3616
+ * @public
3617
+ */
3618
+ declare function commandForSlotValue(slotId: ChromeSlotId, value: unknown): EditorCommand | null;
3619
+ /**
3620
+ * Whether one control is enabled, and the engine's reason when it is not.
3621
+ *
3622
+ * @public
3623
+ */
3624
+ interface ToolbarCommandState {
3625
+ readonly id: ChromeSlotId;
3626
+ readonly enabled: boolean;
3627
+ /** The engine's reason when disabled — surfaced as a tooltip, never invented. */
3628
+ readonly disabledReason: string | null;
3629
+ /**
3630
+ * What the control currently SHOWS, for the slots whose answer is a value rather than a
3631
+ * pressed state — the editing-mode pill, and image wrap when it lands.
3632
+ *
3633
+ * `active` cannot express this: "the mode is Suggesting" is not a boolean about one
3634
+ * command, and a parallel channel for it would be a second place a control could read its
3635
+ * own state from. Absent for every slot whose state really is just pressed-or-not.
3636
+ */
3637
+ readonly value?: string;
3638
+ /** Whether the command is currently APPLIED at the selection, from `Editor.isActive` —
3639
+ * derived in the engine for marks and alignment, honest-false elsewhere. */
3640
+ readonly active: boolean;
3641
+ }
3642
+ /**
3643
+ * Enabled state for one table chrome slot using explicit draft state.
3644
+ *
3645
+ * @public
3646
+ */
3647
+ declare function tableChromeToolbarState(editor: Editor | null, slot: TableChromeSlotId, draft?: TableChromeDraft): ToolbarCommandState;
3648
+ /**
3649
+ * Ask the engine whether one control should be enabled.
3650
+ *
3651
+ * @public
3652
+ */
3653
+ declare function toolbarCommandState(editor: Editor | null, id: ChromeSlotId): ToolbarCommandState;
3654
+ /**
3655
+ * Whether a slot's control renders as a TOGGLE — pressed or not — so it carries
3656
+ * `aria-pressed`.
3657
+ *
3658
+ * Shared rather than derived per adapter, because it is not derivable from the command table
3659
+ * alone: the format painter has no fixed command (a press captures, arms, locks or stands
3660
+ * down, which no single `EditorCommand` describes), so a rule that only read `commandForSlot`
3661
+ * left it announcing nothing at all to a screen reader while it was armed.
3662
+ *
3663
+ * @public
3664
+ */
3665
+ declare function chromeSlotIsToggle(slotId: ChromeSlotId): boolean;
3666
+ /**
3667
+ * Enabled state for several controls in one pass.
3668
+ *
3669
+ * @public
3670
+ */
3671
+ declare function toolbarCommandStates(editor: Editor | null, ids: readonly ChromeSlotId[]): readonly ToolbarCommandState[];
3672
+ /**
3673
+ * Result of {@link runTableChromeCommand}: engine outcome plus post-pick draft on success.
3674
+ *
3675
+ * @public
3676
+ */
3677
+ interface RunTableChromeCommandResult {
3678
+ readonly result: ExecResult;
3679
+ readonly nextDraft: TableChromeDraft | null;
3680
+ }
3681
+ /**
3682
+ * Run one table chrome pick with explicit draft state; returns the post-pick draft on success.
3683
+ *
3684
+ * @public
3685
+ */
3686
+ declare function runTableChromeCommand(editor: Editor | null, slot: TableChromeSlotId, value: unknown, draft: TableChromeDraft): RunTableChromeCommandResult;
3687
+ /**
3688
+ * Run a toolbar control: `can` first, then `exec` only if it said yes. Returns
3689
+ * the engine's refusal untouched when it said no, so a caller cannot mistake a
3690
+ * declined command for a no-op.
3691
+ *
3692
+ * @public
3693
+ */
3694
+ declare function runToolbarCommand(editor: Editor | null, id: ChromeSlotId): ExecResult;
3695
+ /** @public */
3696
+ declare function runToolbarCommand(editor: Editor | null, id: Exclude<ChromeSlotId, ToolbarValueSlot>, options: EditorExecOptions): ExecResult;
3697
+ /** @public */
3698
+ declare function runToolbarCommand<K extends keyof ToolbarValueMap>(editor: Editor | null, id: K, value: ToolbarValueMap[NoInfer<K>], options?: EditorExecOptions): ExecResult;
3699
+ /** @public */
3700
+ declare function runToolbarCommand(editor: Editor | null, id: TableChromeSlotId, value: unknown, options?: EditorExecOptions): ExecResult;
3701
+ /** @public */
3702
+ declare function runToolbarCommand(editor: Editor | null, id: ChromeSlotId, value: undefined, options: EditorExecOptions): ExecResult;
3703
+ /**
3704
+ * Save goes straight to `Editor.save()` — it is not a command.
3705
+ *
3706
+ * @public
3707
+ */
3708
+ declare function runSave(editor: Editor | null): Promise<ArrayBuffer>;
3709
+ /**
3710
+ * Enabled state for a table command when the caller holds the paginated surface.
3711
+ *
3712
+ * Uses the same planner-backed `tableCommandState` as `Editor.can`/`gateTableCommand`.
3713
+ * Chrome slot mapping for table controls is Task 9 — this helper is the shared
3714
+ * can-before-exec seam for arbitrary table commands.
3715
+ *
3716
+ * @public
3717
+ */
3718
+ declare function tableCommandToolbarState(surface: PaginatedSurface | null, command: EditorCommand): Pick<ToolbarCommandState, 'enabled' | 'disabledReason'>;
3719
+ /**
3720
+ * Run a table command: planner-backed `can` first, then `exec` only when allowed.
3721
+ *
3722
+ * @public
3723
+ */
3724
+ declare function runTableCommand(editor: Editor | null, command: EditorCommand, options?: EditorExecOptions): ExecResult;
3725
+
3726
+ /**
3727
+ * Build an editor: the full `Editor` contract over a paginated surface.
3728
+ *
3729
+ * Construction is separate from mounting. Pass a `container` and the document mounts
3730
+ * immediately; omit it and nothing touches the DOM until `attach(el)` — the provider-first
3731
+ * shape. `detach()` remounts from the saved bytes, which resets undo and the caret.
3732
+ *
3733
+ * `snapshot()` is version-cached: the same reference until state actually moves, with
3734
+ * reference-stable sub-objects, so it is safe as a `useSyncExternalStore` source.
3735
+ *
3736
+ * @example
3737
+ * ```ts
3738
+ * const editor = createDocxEditor({ document: bytes, modules: [reviewModule()] });
3739
+ * editor.attach(element);
3740
+ * editor.on('change', () => setDirty(true));
3741
+ * ```
3742
+ *
3743
+ * @public
3744
+ */
3745
+ declare function createDocxEditor(config: DocxEditorConfig): DocxEditorInstance;
3746
+
3747
+ /** Native event policy for one continuous control gesture. @public */
3748
+ interface HistoryGroupBindingOptions {
3749
+ readonly kind: 'native-color' | 'range' | 'repeat' | 'keyboard';
3750
+ }
3751
+ /** Dispose when the element or editor changes. @public */
3752
+ interface HistoryGroupBinding {
3753
+ /** Options for the next synchronous formatting command. */
3754
+ options(): EditorExecOptions;
3755
+ /** Close the gesture and remove every listener; does not revert edits. */
3756
+ dispose(): void;
3757
+ }
3758
+ /**
3759
+ * Bind native gesture events. Framework change handlers apply values; this binding ends groups.
3760
+ * Native color `change` means value commitment, not portable popup closure. Controls without
3761
+ * a terminal change event end on the next activation, Escape, blur, or disposal.
3762
+ * Range/repeat controls end on pointer release/cancel or keyup, including outside releases.
3763
+ * Terminal events close after propagation so the final value can use the same handle.
3764
+ * @public
3765
+ */
3766
+ declare function bindHistoryGroup(editor: Editor, element: HTMLElement, config: HistoryGroupBindingOptions): HistoryGroupBinding;
3767
+
3768
+ /** File menu conversion formats. @public */
3769
+ type ChromeExportFormat = 'markdown' | 'pdf';
3770
+ /** Viewer settings captured before PDF conversion. @public */
3771
+ interface ChromeExportView {
3772
+ readonly displayMode: ReviewDisplayMode;
3773
+ readonly revisionMarkup: ResolvedRevisionMarkup;
3774
+ /** Stable session slots, including gaps left by removed authors. */
3775
+ readonly revisionAuthorSlots?: Readonly<Record<string, number>>;
3776
+ }
3777
+ /**
3778
+ * Conversion handlers for File > Export. Install the corresponding converter package.
3779
+ * Use `exportMarkdown` for Markdown. PDF requires `exportPdf` on a Node.js server.
3780
+ * Browser hosts supply a PDF handler that calls that server after the user selects Export.
3781
+ * @public
3782
+ */
3783
+ interface ChromeExportHandlers {
3784
+ /** Returns continuous document Markdown. Page output is not downloaded. */
3785
+ readonly markdown?: (source: Uint8Array) => Promise<{
3786
+ readonly markdown: string;
3787
+ }>;
3788
+ /** Returns PDF bytes from `@docx-editor.dev/docx-to-pdf` on Node.js. */
3789
+ readonly pdf?: (source: Uint8Array, view?: ChromeExportView) => Promise<{
3790
+ readonly bytes: Uint8Array;
3791
+ }>;
3792
+ }
3793
+ /** Download data from a completed conversion. @public */
3794
+ interface ChromeExportResult {
3795
+ readonly bytes: Uint8Array;
3796
+ readonly extension: 'md' | 'pdf';
3797
+ readonly mimeType: string;
3798
+ }
3799
+ /** An export has no configured converter. @public */
3800
+ declare class ChromeExportError extends Error {
3801
+ readonly format: ChromeExportFormat;
3802
+ readonly code = "missing-exporter";
3803
+ constructor(format: ChromeExportFormat);
3804
+ }
3805
+ /**
3806
+ * Saves the current document and converts those bytes through the configured handler.
3807
+ * Missing handlers fail before saving. Conversion never changes the editor document.
3808
+ * @public
3809
+ */
3810
+ declare function runChromeExport(editor: Pick<Editor, 'save'> & Partial<Pick<DocxEditorInstance, 'snapshot' | 'getReviewAuthors'>>, format: ChromeExportFormat, handlers?: ChromeExportHandlers): Promise<ChromeExportResult>;
3811
+
3812
+ /** Why the browser could not print the converted PDF. @public */
3813
+ type ChromePrintErrorCode = 'pdf-viewer-unavailable' | 'pdf-load-failed' | 'print-refused' | 'print-ended';
3814
+ /**
3815
+ * The browser could not print the converted PDF. The PDF at `ChromePrintJob.url` is still
3816
+ * available, so the user can open it and print from the PDF viewer.
3817
+ * @public
3818
+ */
3819
+ declare class ChromePrintError extends Error {
3820
+ /** Why the browser could not print. */
3821
+ readonly code: ChromePrintErrorCode;
3822
+ constructor(code: ChromePrintErrorCode);
3823
+ }
3824
+ /**
3825
+ * True for the print shortcut: Cmd+P on Apple platforms, Ctrl+P elsewhere. On macOS,
3826
+ * Ctrl+P moves the caret to the previous line, so it is not a print shortcut there. The P
3827
+ * key matches by `code` too when it types no Latin letter, as on Cyrillic or Hebrew layouts.
3828
+ * @public
3829
+ */
3830
+ declare function isChromePrintShortcut(event: KeyboardEvent): boolean;
3831
+ /** Options for `ChromePrintJob.print`. @public */
3832
+ interface ChromePrintOptions {
3833
+ /**
3834
+ * Runs after the PDF loads and before the print dialog opens. Close any modal dialog
3835
+ * here: a modal dialog makes the rest of the page, including the print frame, inert.
3836
+ */
3837
+ readonly beforePrint?: () => void | Promise<void>;
3838
+ }
3839
+ /**
3840
+ * A converted PDF, ready for the browser print dialog.
3841
+ * Call `dispose()` when the job ends: it removes the print frame and revokes `url`.
3842
+ * @public
3843
+ */
3844
+ interface ChromePrintJob {
3845
+ /** An object URL for the PDF. It stays valid until `dispose()`. */
3846
+ readonly url: string;
3847
+ /**
3848
+ * Opens the browser print dialog for the PDF from a hidden frame.
3849
+ * Rejects with `ChromePrintError` when the browser has no PDF viewer, the frame cannot
3850
+ * load the PDF, or the job has ended. A browser without a PDF viewer would download the
3851
+ * PDF instead of loading it, so the frame is not created in that case.
3852
+ */
3853
+ print(options?: ChromePrintOptions): Promise<void>;
3854
+ /** Removes the print frame and revokes `url`. Later `print()` calls reject. */
3855
+ dispose(): void;
3856
+ }
3857
+ /**
3858
+ * Saves the current document, converts it with the configured PDF handler, and prepares
3859
+ * the result for printing. Uses the same handler and checks as File > Export > PDF, so a
3860
+ * missing handler rejects with `ChromeExportError` before the document is saved.
3861
+ * Saving commits pending form input and can refresh field results with an undo step.
3862
+ * `container` receives the hidden print frame. For an editor inside a modal dialog,
3863
+ * pass an element inside that dialog.
3864
+ * @public
3865
+ */
3866
+ declare function runChromePrint(editor: Pick<Editor, 'save'> & Partial<Pick<Editor, 'snapshot'>>, handlers?: ChromeExportHandlers, container?: Document | Element): Promise<ChromePrintJob>;
3867
+
3868
+ export { IMAGE_OVERLAY_NUDGE_SHIFT_PT as $, CHROME_GROUPS as C, DEFAULT_TABLE_CHROME_DRAFT as F, EMU_PER_POINT as I, IMAGE_OVERLAY_NUDGE_PT as _, createFontSource as a$, applyTableChromePick as aJ, bindHistoryGroup as aK, blankDocumentBytes as aL, canExecuteImageCommand as aM, captureImageMutationPreconditions as aN, chromeControlCount as aO, chromeMenuSlots as aP, chromeProbeForSlot as aQ, chromeSlotId as aR, chromeSlotIsToggle as aS, commandExecOptions as aT, commandForSlot as aU, commandForSlotValue as aV, commandForTableChromeSlotValue as aW, computeImageResizeResult as aX, computeMovedImagePosition as aY, computeResizedImageExtentEmu as aZ, createDocxEditor as a_, TABLE_BORDER_STYLE_OPTIONS as ar, TABLE_BORDER_TARGET_OPTIONS as as, TABLE_BORDER_WIDTH_OPTIONS as at, TABLE_CHROME_SLOT_IDS as au, CHROME_MENUS as b, createImageOverlayScrollPort as b0, cssPixelsToLayoutPoints as b1, customFonts as b2, defaultChromeGroups as b3, defaultTableLabel as b4, emuToOverlayPoints as b5, equationAtPosition as b6, executeImageCommand as b7, finalizeImageOverlayInteraction as b8, formattingBarChromeGroups as b9, isChromePrintShortcut as ba, isStaleImageInteractionCommit as bb, isTableChromeSlot as bc, layoutPointsToCssPixels as bd, loadFonts as be, overlayFrameToSheetCssPixels as bf, overlayHostOrigin as bg, pointsToEmu as bh, probeTableChromeCommand as bi, resizePreservesAspect as bj, runChromeExport as bk, runChromePrint as bl, runSave as bm, runTableChromeCommand as bn, runTableCommand as bo, runToolbarCommand as bp, selectedDrawingOverlayTargetOf as bq, selectedImageStateOf as br, surfacePaintScale as bs, tableChromeIconPaths as bt, tableChromeLabelKeyForTarget as bu, tableChromeToolbarState as bv, tableChromeVisible as bw, tableCommandToolbarState as bx, toolbarCommandState as by, toolbarCommandStates as bz, CHROME_UNAVAILABLE_KEY as c, ChromeExportError as g, ChromePrintError as t };
3869
+ export type { AnchorFrameOrigin as A, CustomFontsOptions as B, DocxEditorInstance as D, CustomFontsResolver as E, DocxEditorConfig as G, DrawingSelectionIntent as H, EditorCommandExecute as J, EquationActivation as K, EquationChromeHandlers as L, EquationOps as M, FinalizedImageOverlayInteraction as N, OpenPaginatedResult as O, PaginatedSurfaceOptions as P, FontLoadFailure as Q, FontLoadFailureReason as R, FontMeasurementState as S, TableCommandPlan as T, FontUrlSource as U, HistoryGroupBinding as V, HistoryGroupBindingOptions as W, HyperlinkActivation as X, HyperlinkChromeHandlers as Y, HyperlinkOps as Z, PaginatedSurface as a, ImageInteractionSession as a0, ImageOverlayScrollPort as a1, ImageResizeHandle as a2, ImageResizeResult as a3, InvalidTextFormFieldChromeHandlers as a4, InvalidTextFormFieldSession as a5, LoadFontsRequest as a6, LoadFontsResult as a7, OpeningIndicatorHost as a8, OverlayFrameRect as a9, TableChromePick as aA, TableChromeSlotId as aB, TableInteractionLabelKey as aC, TextFormFieldChromeHandlers as aD, TextFormFieldDialogSession as aE, ToolbarCommandState as aF, ToolbarSlotValue as aG, ToolbarValueMap as aH, ToolbarValueSlot as aI, PaginatedSurfaceState as aa, ParagraphPropertyEdit as ab, PopupChromeRegistrationOptions as ac, RemoteCaretLabelAnchor as ad, RemoteCaretLabelHost as ae, ReviewWriteIntent as af, RunTableChromeCommandResult as ag, SectionAnchor as ah, SectionBreakInsertType as ai, SelectedDrawingOverlayTarget as aj, SurfaceEquation as ak, SurfaceFormatting as al, SurfaceHyperlink as am, SurfaceInsertImageInput as an, SurfaceNavigation as ao, SurfaceOverlayCoordinates as ap, SurfaceParagraphFormat as aq, TableBorderStyleOption as av, TableBorderTargetOption as aw, TableBorderTargetValue as ax, TableBorderWidthOption as ay, TableChromeDraft as az, ChromeControl as d, ChromeControlId as e, ChromeControlState as f, ChromeExportFormat as h, ChromeExportHandlers as i, ChromeExportResult as j, ChromeExportView as k, ChromeGroup as l, ChromeGroupId as m, ChromeMenu as n, ChromeMenuEntry as o, ChromeMenuId as p, ChromeMenuItemEntry as q, ChromeMenuSeparatorEntry as r, ChromeMenuSubmenuEntry as s, ChromePrintErrorCode as u, ChromePrintJob as v, ChromePrintOptions as w, ChromeSlotId as x, ContentControlWidgetChromeHandlers as y, ContentControlWidgetSession as z };