@docx-editor.dev/core 2.14.0 → 2.15.0

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