@docx-editor.dev/core 0.0.1 → 2.1.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.
- package/LICENSE +201 -0
- package/README.md +91 -2
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/dist/automation.cjs +1 -0
- package/dist/automation.d.cts +74 -0
- package/dist/automation.d.ts +74 -0
- package/dist/automation.js +1 -0
- package/dist/binding.cjs +1 -0
- package/dist/binding.d.cts +88 -0
- package/dist/binding.d.ts +88 -0
- package/dist/binding.js +1 -0
- package/dist/chunk-2DTQDAN7.js +2 -0
- package/dist/chunk-3JKQE4QJ.cjs +2 -0
- package/dist/chunk-4WWEDTTE.js +2 -0
- package/dist/chunk-6WIIHJFY.js +1 -0
- package/dist/chunk-7VQ7YLW3.cjs +1 -0
- package/dist/chunk-BS554B6D.cjs +2 -0
- package/dist/chunk-BZK64YU3.cjs +10 -0
- package/dist/chunk-CZFUMACF.cjs +12 -0
- package/dist/chunk-GQQOL4PV.js +1 -0
- package/dist/chunk-HBL3NNH5.cjs +1 -0
- package/dist/chunk-JQFDLZXQ.cjs +2 -0
- package/dist/chunk-O2WQY7IT.cjs +5 -0
- package/dist/chunk-PC76F2HR.cjs +1 -0
- package/dist/chunk-QRAUDDVY.js +2 -0
- package/dist/chunk-REZUWYB7.js +1 -0
- package/dist/chunk-STCITBJK.js +12 -0
- package/dist/chunk-TBBXCC7D.js +5 -0
- package/dist/chunk-TSXT537P.cjs +12 -0
- package/dist/chunk-WOGYVM3W.js +12 -0
- package/dist/chunk-Y7TA7TPF.js +10 -0
- package/dist/content-control-walk-CbTqHq6O.d.cts +56 -0
- package/dist/content-control-walk-D06GijR0.d.ts +56 -0
- package/dist/contracts/document.cjs +1 -0
- package/dist/contracts/document.d.cts +246 -0
- package/dist/contracts/document.d.ts +246 -0
- package/dist/contracts/document.js +0 -0
- package/dist/contracts/editor.cjs +1 -0
- package/dist/contracts/editor.d.cts +11 -0
- package/dist/contracts/editor.d.ts +11 -0
- package/dist/contracts/editor.js +1 -0
- package/dist/contracts/interaction.cjs +1 -0
- package/dist/contracts/interaction.d.cts +11 -0
- package/dist/contracts/interaction.d.ts +11 -0
- package/dist/contracts/interaction.js +0 -0
- package/dist/contracts/modules.cjs +1 -0
- package/dist/contracts/modules.d.cts +117 -0
- package/dist/contracts/modules.d.ts +117 -0
- package/dist/contracts/modules.js +1 -0
- package/dist/contracts/types.cjs +1 -0
- package/dist/contracts/types.d.cts +452 -0
- package/dist/contracts/types.d.ts +452 -0
- package/dist/contracts/types.js +0 -0
- package/dist/custom-node-writes-YqISlSRl.d.cts +885 -0
- package/dist/custom-node-writes-ttKuYd0M.d.ts +885 -0
- package/dist/editor-B93PggnR.d.cts +1690 -0
- package/dist/editor-CFsSrxGR.d.ts +1690 -0
- package/dist/editor.cjs +1 -0
- package/dist/editor.css +7106 -0
- package/dist/editor.d.cts +271 -0
- package/dist/editor.d.ts +271 -0
- package/dist/editor.js +1 -0
- package/dist/hf-references-BdjsQNE_.d.ts +71 -0
- package/dist/hf-references-CgEOSw3i.d.cts +71 -0
- package/dist/image-resources-C_YnqPhn.d.ts +203 -0
- package/dist/image-resources-DwpNnTg3.d.cts +203 -0
- package/dist/index-BjZelfWL.d.cts +2532 -0
- package/dist/index-DP1yJJ3R.d.ts +2532 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +1 -0
- package/dist/layout.cjs +1 -0
- package/dist/layout.d.cts +2366 -0
- package/dist/layout.d.ts +2366 -0
- package/dist/layout.js +1 -0
- package/dist/note-nodes-BPSTVDMr.d.ts +108 -0
- package/dist/note-nodes-C6DLxlvj.d.cts +108 -0
- package/dist/ooxml-package-CR5us6ad.d.cts +354 -0
- package/dist/ooxml-package-D_CtywTW.d.ts +354 -0
- package/dist/ooxml-tree-BU0e3DVi.d.cts +871 -0
- package/dist/ooxml-tree-BU0e3DVi.d.ts +871 -0
- package/dist/output.cjs +1 -0
- package/dist/output.d.cts +158 -0
- package/dist/output.d.ts +158 -0
- package/dist/output.js +1 -0
- package/dist/protocol-BWVA3Q1p.d.ts +1255 -0
- package/dist/protocol-FAz_nPm_.d.cts +1255 -0
- package/dist/review-reads-CsoXSvUg.d.ts +401 -0
- package/dist/review-reads-qW0jvdF1.d.cts +401 -0
- package/dist/review-support-D64Wu236.d.cts +358 -0
- package/dist/review-support-nsLXC9jf.d.ts +358 -0
- package/dist/revision-projection-72ZApe-g.d.cts +84 -0
- package/dist/revision-projection-DHAkcD_L.d.ts +84 -0
- package/dist/semantic-cell-selection-D_8RbPII.d.ts +427 -0
- package/dist/semantic-cell-selection-DwLB71fF.d.cts +427 -0
- package/dist/semantic-interaction-CXH2wFqi.d.ts +187 -0
- package/dist/semantic-interaction-DqcEonqD.d.cts +187 -0
- package/dist/semantic-paint-drawings-B5Wk2so5.d.ts +21 -0
- package/dist/semantic-paint-drawings-x8g44lD_.d.cts +21 -0
- package/dist/semantic-records-COVFW5aS.d.cts +1505 -0
- package/dist/semantic-records-zTC0_1zi.d.ts +1505 -0
- package/dist/shaped-measurer-AFnFxoot.d.cts +613 -0
- package/dist/shaped-measurer-CZXL-a6v.d.ts +613 -0
- package/dist/store.cjs +1 -0
- package/dist/store.d.cts +2153 -0
- package/dist/store.d.ts +2153 -0
- package/dist/store.js +1 -0
- package/dist/tree-op-types-DWLCllG7.d.ts +1486 -0
- package/dist/tree-op-types-UOXlRUqQ.d.cts +1486 -0
- package/dist/tree-session-BtVFXsF6.d.ts +580 -0
- package/dist/tree-session-DxIOHUOD.d.cts +580 -0
- package/dist/tree-store-B1lEkdXc.d.cts +273 -0
- package/dist/tree-store-BscFPB7x.d.ts +273 -0
- package/package.json +110 -8
- package/index.js +0 -1
|
@@ -0,0 +1,2532 @@
|
|
|
1
|
+
import { i as FontSource, j as FontSourceSubstitution, F as FontConfiguration, k as FontFaceRequest, I as ImageContext, D as DocumentSource, E as EditorFontError, l as Editor, a as EditorCommand, C as CanResult, S as SelectedImageState, V as ViewScope, T as TableBorderEdgeTarget, m as TableBorderSpec, n as TableBorderStyle, o as TableContext } from './editor-CFsSrxGR.js';
|
|
2
|
+
import { T as TreeDocOp, d as DrawingPositionInput, k as DrawingTransform, m as DrawingTreeDocOp } from './tree-op-types-DWLCllG7.js';
|
|
3
|
+
import { b as ImageDecodePort, S as SupportedImageMime } from './image-resources-C_YnqPhn.js';
|
|
4
|
+
import { R as RevisionDisplayMode } from './revision-projection-DHAkcD_L.js';
|
|
5
|
+
import './review-support-nsLXC9jf.js';
|
|
6
|
+
import { a as SemanticSelection, S as SemanticPosition, N as NavigationCommand } from './semantic-interaction-CXH2wFqi.js';
|
|
7
|
+
import { R as ResolvedFootnoteProperties, a as ResolvedEndnoteProperties, A as AuthoredNoteProperties, l as ReviewRevisionKind } from './review-reads-CsoXSvUg.js';
|
|
8
|
+
import { S as SemanticLayout, C as ContentControlBoundaryRecord, T as TextMeasurer } from './semantic-records-zTC0_1zi.js';
|
|
9
|
+
import { S as StoryScope, A as ApplyImagePropertiesInput, d as ImageIntentResult, c as InsertImageInput, B as BookmarkIndex } from './custom-node-writes-ttKuYd0M.js';
|
|
10
|
+
import { C as CellSelection, S as SectionProperties } from './semantic-cell-selection-D_8RbPII.js';
|
|
11
|
+
import { EditorModule, ReviewModuleContribution } from './contracts/modules.js';
|
|
12
|
+
import { Unsubscribe, ExecResult, IndentFormatting } from './contracts/types.js';
|
|
13
|
+
import { D as DrawingPaintStrings } from './semantic-paint-drawings-B5Wk2so5.js';
|
|
14
|
+
import { T as TreeDocxSession, a as TreeApplyResult } from './tree-session-BtVFXsF6.js';
|
|
15
|
+
import './contracts/document.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A partial font configuration one origin contributes: sources, substitutions, or both.
|
|
19
|
+
* `loadDefaultFonts()` (the substitute package) and `loadFonts()` (the fetch helper) both
|
|
20
|
+
* return this shape, so every origin composes through `composeFontConfiguration` the
|
|
21
|
+
* same way.
|
|
22
|
+
*/
|
|
23
|
+
interface FontConfigurationFragment {
|
|
24
|
+
readonly sources?: readonly FontSource[];
|
|
25
|
+
readonly substitutions?: readonly FontSourceSubstitution[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The base of a composition: everything a `FontConfiguration` carries, all optional.
|
|
29
|
+
* Omitted fields take the documented defaults (`epoch` 0, `maxFontBytes` at the engine
|
|
30
|
+
* hard maximum, `defaultFont` Calibri at 11pt — Word's own default face and size).
|
|
31
|
+
*/
|
|
32
|
+
interface FontConfigurationBase extends FontConfigurationFragment {
|
|
33
|
+
/**
|
|
34
|
+
* Identity of this configuration's byte set. The engine uses it to tell one resolved
|
|
35
|
+
* font set from another; leave it unset and the editor supplies the load sequence.
|
|
36
|
+
*/
|
|
37
|
+
readonly epoch?: number;
|
|
38
|
+
/** Per-face byte ceiling. Defaults to the engine hard maximum; lower it to tighten intake. */
|
|
39
|
+
readonly maxFontBytes?: number;
|
|
40
|
+
/** The face used when a run names no font. Defaults to Word's own: Calibri at 11pt. */
|
|
41
|
+
readonly defaultFont?: FontConfiguration['defaultFont'];
|
|
42
|
+
/** BCP-47 tag passed to the shaper for language-sensitive shaping. */
|
|
43
|
+
readonly language?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* What the document turned out to need, handed to an on-demand resolver.
|
|
47
|
+
*
|
|
48
|
+
* The families are the ones the file actually names — already name-validated and capped,
|
|
49
|
+
* so a resolver may treat them as a list to look up, never as URLs or paths to build.
|
|
50
|
+
*/
|
|
51
|
+
interface FontResolutionRequest {
|
|
52
|
+
/**
|
|
53
|
+
* Families declared anywhere in the document (body, headers/footers, styles), deduped,
|
|
54
|
+
* sorted, and capped at {@link MAX_RESOLVER_FAMILIES}.
|
|
55
|
+
*/
|
|
56
|
+
readonly families: readonly string[];
|
|
57
|
+
/** The face a run naming no font resolves to, so a resolver can cover it too. */
|
|
58
|
+
readonly defaultFamily: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve fonts once the document's needs are known, instead of ahead of them.
|
|
62
|
+
*
|
|
63
|
+
* Called once per load, AFTER the file is parsed and mounted, with the families it
|
|
64
|
+
* declares; whatever it returns composes exactly like a statically supplied fragment.
|
|
65
|
+
* Returning nothing is a valid answer — it means "I cover none of this", and the
|
|
66
|
+
* document stays on the fixed measurer.
|
|
67
|
+
*
|
|
68
|
+
* A resolver that fetches makes opening a document perform network requests. That is a
|
|
69
|
+
* real change in posture and it must stay the APP's decision: the engine never supplies
|
|
70
|
+
* one, and the families here are file-derived, so a resolver must look them up in a set
|
|
71
|
+
* it shipped rather than interpolate them into a URL.
|
|
72
|
+
*/
|
|
73
|
+
type FontResolver = (request: FontResolutionRequest) => FontConfiguration | FontConfigurationFragment | undefined | Promise<FontConfiguration | FontConfigurationFragment | undefined>;
|
|
74
|
+
/**
|
|
75
|
+
* Ceiling on the families one document can put in front of a resolver.
|
|
76
|
+
*
|
|
77
|
+
* A resolver typically turns each family into up to four faces, and the resource snapshot
|
|
78
|
+
* refuses more than `HARD_MAX_FONT_SOURCES` (256) sources — so 64 families is the point
|
|
79
|
+
* past which a document could no longer be served anyway. Capping here means a file
|
|
80
|
+
* declaring thousands of distinct `w:rFonts` cannot fan a resolver out across thousands
|
|
81
|
+
* of lookups (or fetches) before that limit is ever reached.
|
|
82
|
+
*/
|
|
83
|
+
declare const MAX_RESOLVER_FAMILIES = 64;
|
|
84
|
+
/** Word's document default when nothing else says otherwise: Calibri at 11pt. */
|
|
85
|
+
declare const WORD_DEFAULT_FONT: FontConfiguration['defaultFont'];
|
|
86
|
+
/**
|
|
87
|
+
* Merge a base and any number of fragments into one frozen `FontConfiguration`.
|
|
88
|
+
*
|
|
89
|
+
* A bare fragment IS a valid base, so the single-origin case is one argument:
|
|
90
|
+
* `composeFontConfiguration(await loadDefaultFonts())`. Pass extra fragments to layer
|
|
91
|
+
* origins, and set `epoch`/`maxFontBytes`/`defaultFont` on the base only when you need
|
|
92
|
+
* something other than the documented defaults.
|
|
93
|
+
*
|
|
94
|
+
* - Sources dedupe first-wins by (family, weight, style), in argument order — base
|
|
95
|
+
* before fragments, earlier fragments before later ones.
|
|
96
|
+
* - Substitutions dedupe first-wins by their `from` face, in the same order, and every
|
|
97
|
+
* substitution whose `from` face has a direct source anywhere in the composition is
|
|
98
|
+
* dropped: a real face always beats a stand-in.
|
|
99
|
+
* - The result is frozen (arrays included); the byte arrays themselves are the callers'
|
|
100
|
+
* and are not copied here — the resource snapshot takes its own defensive copy.
|
|
101
|
+
*/
|
|
102
|
+
declare function composeFontConfiguration(base: FontConfigurationBase, ...fragments: readonly FontConfigurationFragment[]): FontConfiguration;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* A Word-faithful blank document, freshly zipped per call (the caller may hand the
|
|
106
|
+
* bytes to a loader that takes ownership). Calibri 11pt and Word's Normal paragraph
|
|
107
|
+
* spacing are authored in `w:docDefaults`, US Letter geometry in the section — a New
|
|
108
|
+
* document behaves like Word's, and saving it produces a file Word opens identically.
|
|
109
|
+
*
|
|
110
|
+
* @public
|
|
111
|
+
*/
|
|
112
|
+
declare function blankDocumentBytes(): Uint8Array;
|
|
113
|
+
|
|
114
|
+
/** One URL to fetch and the face it claims to be. */
|
|
115
|
+
interface FontUrlSource {
|
|
116
|
+
readonly url: string;
|
|
117
|
+
readonly family: string;
|
|
118
|
+
readonly weight: number;
|
|
119
|
+
readonly style: 'normal' | 'italic';
|
|
120
|
+
/**
|
|
121
|
+
* Expected `sha256:` content hash. When present, mismatching bytes are REFUSED —
|
|
122
|
+
* pin this for any URL not under the app's sole control.
|
|
123
|
+
*/
|
|
124
|
+
readonly hash?: string;
|
|
125
|
+
readonly faceIndex?: number;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* What to fetch, and under what limits.
|
|
129
|
+
*
|
|
130
|
+
* Only `sources` is required. Each carries its own expected hash, so bytes are trusted by
|
|
131
|
+
* CONTENT rather than by origin — a swapped asset fails admission even from a trusted host.
|
|
132
|
+
*/
|
|
133
|
+
interface LoadFontsRequest {
|
|
134
|
+
readonly sources: readonly FontUrlSource[];
|
|
135
|
+
/** Cache API bucket name; default `docx-editor-fonts`. */
|
|
136
|
+
readonly cacheName?: string;
|
|
137
|
+
/** Injectable for tests and CSP-constrained hosts; defaults to global `fetch`. */
|
|
138
|
+
readonly fetcher?: typeof fetch;
|
|
139
|
+
/** Per-font byte ceiling; defaults to the engine hard maximum. */
|
|
140
|
+
readonly maxFontBytes?: number;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Why one font did not load.
|
|
144
|
+
*
|
|
145
|
+
* Distinguished rather than collapsed to "failed" because the responses differ: `networkError`
|
|
146
|
+
* and `httpError` are worth retrying, while `hashMismatch` and `malformed` mean the bytes were
|
|
147
|
+
* not what the source claimed and retrying will fetch the same wrong thing.
|
|
148
|
+
*/
|
|
149
|
+
type FontLoadFailureReason = 'networkError' | 'httpError' | 'hashMismatch' | 'overLimit' | 'emptyResponse'
|
|
150
|
+
/** The declared face itself is unusable (empty family, out-of-range weight); nothing was fetched. */
|
|
151
|
+
| 'invalidRequest'
|
|
152
|
+
/** The bytes are not a font at all — most often an HTML error page served with 200. */
|
|
153
|
+
| 'malformed';
|
|
154
|
+
/**
|
|
155
|
+
* One face that did not load, with whatever evidence the failure produced.
|
|
156
|
+
*
|
|
157
|
+
* Non-fatal: {@link LoadFontsResult} still carries every source that succeeded, and the affected
|
|
158
|
+
* family falls back to the engine's fixed measurement.
|
|
159
|
+
*/
|
|
160
|
+
interface FontLoadFailure {
|
|
161
|
+
readonly url: string;
|
|
162
|
+
readonly request: FontFaceRequest;
|
|
163
|
+
readonly reason: FontLoadFailureReason;
|
|
164
|
+
/** HTTP status for `httpError`; hashes for `hashMismatch`. */
|
|
165
|
+
readonly status?: number;
|
|
166
|
+
readonly expectedHash?: string;
|
|
167
|
+
readonly actualHash?: string;
|
|
168
|
+
readonly diagnostic?: string;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* What one `loadFonts` call produced: the faces that arrived, plus the ones that did not.
|
|
172
|
+
*
|
|
173
|
+
* A `FontConfigurationFragment`, so it composes straight into `composeFontConfiguration`
|
|
174
|
+
* alongside other font sources. Partial success is the normal case — compose it even with
|
|
175
|
+
* failures present.
|
|
176
|
+
*/
|
|
177
|
+
interface LoadFontsResult extends FontConfigurationFragment {
|
|
178
|
+
readonly sources: readonly FontSource[];
|
|
179
|
+
readonly failures: readonly FontLoadFailure[];
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Fetch app-specified font URLs into verified, cache-backed `FontSource`s.
|
|
183
|
+
*
|
|
184
|
+
* Fetches ONLY the URLs listed — never a default host or engine-chosen CDN — and never
|
|
185
|
+
* rejects for a per-source failure: the result carries every admitted source and a
|
|
186
|
+
* typed entry for every drop. Compose the result with `composeFontConfiguration`.
|
|
187
|
+
*/
|
|
188
|
+
declare function loadFonts(request: LoadFontsRequest): Promise<LoadFontsResult>;
|
|
189
|
+
/**
|
|
190
|
+
* Turn font bytes you ALREADY hold into a `FontSource` — a file input, IndexedDB, a
|
|
191
|
+
* bundler import. `loadFonts` covers URLs; this covers everything else, so no caller has
|
|
192
|
+
* to hand-assemble the record or reach for a hashing helper.
|
|
193
|
+
*
|
|
194
|
+
* Returns a typed failure instead of throwing when the descriptor or the bytes are
|
|
195
|
+
* unusable, matching `loadFonts`: one bad face degrades itself, never its neighbours.
|
|
196
|
+
*/
|
|
197
|
+
declare function createFontSource(bytes: Uint8Array, request: FontFaceRequest & {
|
|
198
|
+
readonly faceIndex?: number;
|
|
199
|
+
}, options?: {
|
|
200
|
+
readonly id?: string;
|
|
201
|
+
readonly maxFontBytes?: number;
|
|
202
|
+
}): {
|
|
203
|
+
readonly source: FontSource;
|
|
204
|
+
} | {
|
|
205
|
+
readonly failure: FontLoadFailure;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* HOW a control reaches the engine — never WHETHER it is enabled.
|
|
210
|
+
*
|
|
211
|
+
* Enabled state has exactly one source: `toolbarCommandState(editor, slot)`, which
|
|
212
|
+
* asks `Editor.can`. The registry is static data and cannot know what the engine
|
|
213
|
+
* will honour at this selection, in this document, at this moment.
|
|
214
|
+
*
|
|
215
|
+
* There used to be a fourth member, `parityOnly`, meaning "visible but permanently
|
|
216
|
+
* disabled". It was a second, static answer to the question `Editor.can` already
|
|
217
|
+
* answers, and it went stale the moment the engine wired underline, strike, the four
|
|
218
|
+
* alignments, the list commands and the four value slots: the registry still said
|
|
219
|
+
* parity-only, React ignored it and ran them, and Vue believed it and rendered twelve
|
|
220
|
+
* WORKING commands permanently disabled. A slot the engine has not wired needs no
|
|
221
|
+
* registry flag — `commandForSlot` answers null and `toolbarCommandState` disables the
|
|
222
|
+
* control with the engine's own words ("not wired to an editor command").
|
|
223
|
+
*/
|
|
224
|
+
type ChromeControlState =
|
|
225
|
+
/**
|
|
226
|
+
* Dispatched as one fixed engine command: enabled when
|
|
227
|
+
* `Editor.can(commandForSlot(slot))` succeeds, a click runs
|
|
228
|
+
* `runToolbarCommand(editor, slot)`. The command is resolved from the SLOT id
|
|
229
|
+
* through `commandForSlot` in toolbar-commands.ts — the one command table both
|
|
230
|
+
* adapters share. A slot with no row there is simply not wired YET, and says so
|
|
231
|
+
* through the engine rather than through this descriptor.
|
|
232
|
+
*/
|
|
233
|
+
{
|
|
234
|
+
readonly kind: 'command';
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Dispatched with a PICKED value: `commandForSlotValue(slot, value)`. Enabled when
|
|
238
|
+
* the engine would honour a well-formed value right now (`toolbarCommandState`
|
|
239
|
+
* probes for exactly that), so the control needs chrome that produces a value — a
|
|
240
|
+
* font list, a size, a colour — before a click means anything.
|
|
241
|
+
*
|
|
242
|
+
* A distinct kind because 'command' cannot describe it: there is no fixed command
|
|
243
|
+
* to hand `Editor.can`, and a bare click has nothing to send.
|
|
244
|
+
*/
|
|
245
|
+
| {
|
|
246
|
+
readonly kind: 'value';
|
|
247
|
+
}
|
|
248
|
+
/** `Editor.save()` — not a command (see `runSave`). */
|
|
249
|
+
| {
|
|
250
|
+
readonly kind: 'save';
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* `Editor.load()` — not a command either, and the exact twin of `save`: bytes cross the
|
|
254
|
+
* boundary between the host and the engine, and only the host can produce them. The
|
|
255
|
+
* control needs chrome that reads a file (a picker, a drop target) before a click means
|
|
256
|
+
* anything, so a bare click has nothing to send — the same reason `save` is not `command`.
|
|
257
|
+
*
|
|
258
|
+
* A fourth kind rather than reusing `save` because the two dispatch in opposite
|
|
259
|
+
* directions, and an adapter branching on `kind` must be able to tell them apart. Unlike
|
|
260
|
+
* the deleted `parityOnly`, this one IS named by a control (`file.open`).
|
|
261
|
+
*/
|
|
262
|
+
| {
|
|
263
|
+
readonly kind: 'load';
|
|
264
|
+
};
|
|
265
|
+
/**
|
|
266
|
+
* The SHAPE a control renders as (task M6V.1).
|
|
267
|
+
*
|
|
268
|
+
* The legacy toolbar is not a row of uniform icon buttons: it mixes labelled dropdowns
|
|
269
|
+
* (`Normal`, `Arial`, alignment, line spacing), numeric steppers with visible values
|
|
270
|
+
* (zoom `- 100% +`, size `- 26 +`), split colour controls (a glyph over a colour swatch
|
|
271
|
+
* with its own caret), and a mode pill (`Editing`). Rendering all of them as icon
|
|
272
|
+
* buttons is the difference an owner review called out as "not visual parity" — the
|
|
273
|
+
* regions were all present and it still did not look like the product.
|
|
274
|
+
*/
|
|
275
|
+
/** `modePill` is deliberately absent. It was declared, never used by any control, and
|
|
276
|
+
* rendered nothing — the editing-mode control below is a `dropdown`, which is what the
|
|
277
|
+
* legacy product shows. A shape no descriptor names is a branch adapters must implement
|
|
278
|
+
* and can never exercise. */
|
|
279
|
+
type ChromeControlShape = 'icon' | 'stepper' | 'dropdown' | 'colorSplit';
|
|
280
|
+
/**
|
|
281
|
+
* One toolbar control as the registry describes it — what it renders as, never whether it is
|
|
282
|
+
* enabled.
|
|
283
|
+
*
|
|
284
|
+
* Enabled state has exactly ONE source, `toolbarCommandState`, which asks the engine. A
|
|
285
|
+
* descriptor carrying its own disabled flag would be a second answer that goes stale the moment
|
|
286
|
+
* the engine wires the slot.
|
|
287
|
+
*
|
|
288
|
+
* @public
|
|
289
|
+
*/
|
|
290
|
+
interface ChromeControl<Id extends string = string> {
|
|
291
|
+
/** Stable control id, unique WITHIN its group. Public API; renames are breaking. */
|
|
292
|
+
readonly id: Id;
|
|
293
|
+
/** How it renders. Defaults to `icon`. */
|
|
294
|
+
readonly shape?: ChromeControlShape;
|
|
295
|
+
/** Displayed value for a stepper or dropdown (an i18n key, or a literal for numbers). */
|
|
296
|
+
readonly valueText?: string;
|
|
297
|
+
/** Swatch colour for a `colorSplit` control. */
|
|
298
|
+
readonly swatch?: string;
|
|
299
|
+
/** i18n key for the accessible name and tooltip. Never hardcoded English. */
|
|
300
|
+
readonly labelKey: string;
|
|
301
|
+
/** Material Symbols path data, or null for a non-icon control (a picker). */
|
|
302
|
+
readonly paths: readonly string[] | null;
|
|
303
|
+
/** For pickers: the i18n key of the placeholder value shown. */
|
|
304
|
+
readonly valueKey?: string;
|
|
305
|
+
readonly state: ChromeControlState;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* One toolbar group: the taxonomy both adapters derive their default arrangement FROM.
|
|
309
|
+
*
|
|
310
|
+
* Never hand-list controls in an adapter — a default toolbar is built by walking `CHROME_GROUPS`,
|
|
311
|
+
* so a slot added here appears in React and Vue without either being edited.
|
|
312
|
+
*
|
|
313
|
+
* @public
|
|
314
|
+
*/
|
|
315
|
+
interface ChromeGroup<Id extends string = string, ControlId extends string = string> {
|
|
316
|
+
/** Stable group id. Public API; renames are breaking. */
|
|
317
|
+
readonly id: Id;
|
|
318
|
+
readonly labelKey: string;
|
|
319
|
+
/**
|
|
320
|
+
* Not part of the DEFAULT toolbar arrangement. The chrome spec shows these
|
|
321
|
+
* controls only in a context the engine does not model yet (an image or table
|
|
322
|
+
* selection), or not at all (save belongs in the host's File menu, never in the
|
|
323
|
+
* bar). Their slots stay public for composition — a host can still place
|
|
324
|
+
* `image.insert` or `file.save` explicitly — but the default chrome is the
|
|
325
|
+
* registry's default bar, which ends at the editing-mode picker.
|
|
326
|
+
*/
|
|
327
|
+
readonly contextual?: true;
|
|
328
|
+
readonly controls: readonly ChromeControl<ControlId>[];
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* The complete chrome, in bar order. Literal-typed (`as const`) so the slot-id
|
|
332
|
+
* vocabulary below is derived from the data and cannot drift from it.
|
|
333
|
+
*
|
|
334
|
+
* Taxonomy taste: ids are short, lowercaseCamel, and never repeat their group's name
|
|
335
|
+
* (`alignment.left`, not `alignment.alignLeft`; `font.family`, not `font.fontFamily`).
|
|
336
|
+
*/
|
|
337
|
+
declare const CHROME_GROUPS: readonly [{
|
|
338
|
+
readonly id: "history";
|
|
339
|
+
readonly labelKey: "formattingBar.groups.history";
|
|
340
|
+
readonly controls: readonly [{
|
|
341
|
+
readonly id: "undo";
|
|
342
|
+
readonly labelKey: "formattingBar.undoShortcut";
|
|
343
|
+
readonly paths: readonly string[];
|
|
344
|
+
readonly state: {
|
|
345
|
+
readonly kind: "command";
|
|
346
|
+
};
|
|
347
|
+
}, {
|
|
348
|
+
readonly id: "redo";
|
|
349
|
+
readonly labelKey: "formattingBar.redoShortcut";
|
|
350
|
+
readonly paths: readonly string[];
|
|
351
|
+
readonly state: {
|
|
352
|
+
readonly kind: "command";
|
|
353
|
+
};
|
|
354
|
+
}];
|
|
355
|
+
}, {
|
|
356
|
+
readonly id: "zoom";
|
|
357
|
+
readonly labelKey: "formattingBar.groups.zoom";
|
|
358
|
+
readonly controls: readonly [{
|
|
359
|
+
readonly id: "level";
|
|
360
|
+
readonly shape: "stepper";
|
|
361
|
+
readonly valueText: "100%";
|
|
362
|
+
readonly labelKey: "formattingBar.groups.zoom";
|
|
363
|
+
readonly paths: null;
|
|
364
|
+
readonly valueKey: "zoom.zoomLevel";
|
|
365
|
+
readonly state: {
|
|
366
|
+
readonly kind: "command";
|
|
367
|
+
};
|
|
368
|
+
}];
|
|
369
|
+
}, {
|
|
370
|
+
readonly id: "styles";
|
|
371
|
+
readonly labelKey: "formattingBar.groups.styles";
|
|
372
|
+
readonly controls: readonly [{
|
|
373
|
+
readonly id: "style";
|
|
374
|
+
readonly shape: "dropdown";
|
|
375
|
+
readonly labelKey: "styles.selectAriaLabel";
|
|
376
|
+
readonly paths: null;
|
|
377
|
+
readonly valueKey: "styles.normalText";
|
|
378
|
+
readonly state: {
|
|
379
|
+
readonly kind: "value";
|
|
380
|
+
};
|
|
381
|
+
}];
|
|
382
|
+
}, {
|
|
383
|
+
readonly id: "font";
|
|
384
|
+
readonly labelKey: "formattingBar.groups.font";
|
|
385
|
+
readonly controls: readonly [{
|
|
386
|
+
readonly id: "family";
|
|
387
|
+
readonly shape: "dropdown";
|
|
388
|
+
readonly labelKey: "font.selectAriaLabel";
|
|
389
|
+
readonly paths: null;
|
|
390
|
+
readonly valueKey: "font.sansSerif";
|
|
391
|
+
readonly state: {
|
|
392
|
+
readonly kind: "value";
|
|
393
|
+
};
|
|
394
|
+
}, {
|
|
395
|
+
readonly id: "size";
|
|
396
|
+
readonly shape: "stepper";
|
|
397
|
+
readonly valueText: "11";
|
|
398
|
+
readonly labelKey: "fontSize.listLabel";
|
|
399
|
+
readonly paths: null;
|
|
400
|
+
readonly valueKey: "fontSize.label";
|
|
401
|
+
readonly state: {
|
|
402
|
+
readonly kind: "value";
|
|
403
|
+
};
|
|
404
|
+
}];
|
|
405
|
+
}, {
|
|
406
|
+
readonly id: "text";
|
|
407
|
+
readonly labelKey: "formattingBar.groups.textFormatting";
|
|
408
|
+
readonly controls: readonly [{
|
|
409
|
+
readonly id: "bold";
|
|
410
|
+
readonly labelKey: "formattingBar.boldShortcut";
|
|
411
|
+
readonly paths: readonly string[];
|
|
412
|
+
readonly state: {
|
|
413
|
+
readonly kind: "command";
|
|
414
|
+
};
|
|
415
|
+
}, {
|
|
416
|
+
readonly id: "italic";
|
|
417
|
+
readonly labelKey: "formattingBar.italicShortcut";
|
|
418
|
+
readonly paths: readonly string[];
|
|
419
|
+
readonly state: {
|
|
420
|
+
readonly kind: "command";
|
|
421
|
+
};
|
|
422
|
+
}, {
|
|
423
|
+
readonly id: "underline";
|
|
424
|
+
readonly labelKey: "formattingBar.underlineShortcut";
|
|
425
|
+
readonly paths: readonly string[];
|
|
426
|
+
readonly state: {
|
|
427
|
+
readonly kind: "command";
|
|
428
|
+
};
|
|
429
|
+
}, {
|
|
430
|
+
readonly id: "strike";
|
|
431
|
+
readonly labelKey: "formattingBar.strikethrough";
|
|
432
|
+
readonly paths: readonly string[];
|
|
433
|
+
readonly state: {
|
|
434
|
+
readonly kind: "command";
|
|
435
|
+
};
|
|
436
|
+
}, {
|
|
437
|
+
readonly id: "color";
|
|
438
|
+
readonly shape: "colorSplit";
|
|
439
|
+
readonly swatch: "#ff0000";
|
|
440
|
+
readonly labelKey: "formattingBar.fontColor";
|
|
441
|
+
readonly paths: readonly string[];
|
|
442
|
+
readonly state: {
|
|
443
|
+
readonly kind: "value";
|
|
444
|
+
};
|
|
445
|
+
}, {
|
|
446
|
+
readonly id: "highlight";
|
|
447
|
+
readonly shape: "colorSplit";
|
|
448
|
+
readonly swatch: "#ffff00";
|
|
449
|
+
readonly labelKey: "formattingBar.highlightColor";
|
|
450
|
+
readonly paths: readonly string[];
|
|
451
|
+
readonly state: {
|
|
452
|
+
readonly kind: "value";
|
|
453
|
+
};
|
|
454
|
+
}, {
|
|
455
|
+
readonly id: "link";
|
|
456
|
+
readonly labelKey: "formattingBar.insertLinkShortcut";
|
|
457
|
+
readonly paths: readonly string[];
|
|
458
|
+
readonly state: {
|
|
459
|
+
readonly kind: "command";
|
|
460
|
+
};
|
|
461
|
+
}];
|
|
462
|
+
}, {
|
|
463
|
+
readonly id: "script";
|
|
464
|
+
readonly labelKey: "formattingBar.groups.script";
|
|
465
|
+
readonly controls: readonly [{
|
|
466
|
+
readonly id: "super";
|
|
467
|
+
readonly labelKey: "formattingBar.superscript";
|
|
468
|
+
readonly paths: readonly string[];
|
|
469
|
+
readonly state: {
|
|
470
|
+
readonly kind: "command";
|
|
471
|
+
};
|
|
472
|
+
}, {
|
|
473
|
+
readonly id: "sub";
|
|
474
|
+
readonly labelKey: "formattingBar.subscript";
|
|
475
|
+
readonly paths: readonly string[];
|
|
476
|
+
readonly state: {
|
|
477
|
+
readonly kind: "command";
|
|
478
|
+
};
|
|
479
|
+
}];
|
|
480
|
+
}, {
|
|
481
|
+
readonly id: "alignment";
|
|
482
|
+
readonly labelKey: "formattingBar.groups.alignment";
|
|
483
|
+
readonly controls: readonly [{
|
|
484
|
+
readonly id: "left";
|
|
485
|
+
readonly labelKey: "alignment.alignLeft";
|
|
486
|
+
readonly paths: readonly string[];
|
|
487
|
+
readonly state: {
|
|
488
|
+
readonly kind: "command";
|
|
489
|
+
};
|
|
490
|
+
}, {
|
|
491
|
+
readonly id: "center";
|
|
492
|
+
readonly labelKey: "alignment.center";
|
|
493
|
+
readonly paths: readonly string[];
|
|
494
|
+
readonly state: {
|
|
495
|
+
readonly kind: "command";
|
|
496
|
+
};
|
|
497
|
+
}, {
|
|
498
|
+
readonly id: "right";
|
|
499
|
+
readonly labelKey: "alignment.alignRight";
|
|
500
|
+
readonly paths: readonly string[];
|
|
501
|
+
readonly state: {
|
|
502
|
+
readonly kind: "command";
|
|
503
|
+
};
|
|
504
|
+
}, {
|
|
505
|
+
readonly id: "justify";
|
|
506
|
+
readonly labelKey: "alignment.justify";
|
|
507
|
+
readonly paths: readonly string[];
|
|
508
|
+
readonly state: {
|
|
509
|
+
readonly kind: "command";
|
|
510
|
+
};
|
|
511
|
+
}];
|
|
512
|
+
}, {
|
|
513
|
+
readonly id: "list";
|
|
514
|
+
readonly labelKey: "formattingBar.groups.listFormatting";
|
|
515
|
+
readonly controls: readonly [{
|
|
516
|
+
readonly id: "bullet";
|
|
517
|
+
readonly labelKey: "lists.bulletList";
|
|
518
|
+
readonly paths: readonly string[];
|
|
519
|
+
readonly state: {
|
|
520
|
+
readonly kind: "command";
|
|
521
|
+
};
|
|
522
|
+
}, {
|
|
523
|
+
readonly id: "numbered";
|
|
524
|
+
readonly labelKey: "lists.numberedList";
|
|
525
|
+
readonly paths: readonly string[];
|
|
526
|
+
readonly state: {
|
|
527
|
+
readonly kind: "command";
|
|
528
|
+
};
|
|
529
|
+
}, {
|
|
530
|
+
readonly id: "outdent";
|
|
531
|
+
readonly labelKey: "lists.decreaseIndent";
|
|
532
|
+
readonly paths: readonly string[];
|
|
533
|
+
readonly state: {
|
|
534
|
+
readonly kind: "command";
|
|
535
|
+
};
|
|
536
|
+
}, {
|
|
537
|
+
readonly id: "indent";
|
|
538
|
+
readonly labelKey: "lists.increaseIndent";
|
|
539
|
+
readonly paths: readonly string[];
|
|
540
|
+
readonly state: {
|
|
541
|
+
readonly kind: "command";
|
|
542
|
+
};
|
|
543
|
+
}, {
|
|
544
|
+
readonly id: "lineSpacing";
|
|
545
|
+
readonly shape: "dropdown";
|
|
546
|
+
readonly labelKey: "lineSpacing.label";
|
|
547
|
+
readonly paths: readonly string[];
|
|
548
|
+
readonly state: {
|
|
549
|
+
readonly kind: "command";
|
|
550
|
+
};
|
|
551
|
+
}];
|
|
552
|
+
}, {
|
|
553
|
+
readonly id: "format";
|
|
554
|
+
readonly labelKey: "formattingBar.clearFormatting";
|
|
555
|
+
readonly controls: readonly [{
|
|
556
|
+
readonly id: "clear";
|
|
557
|
+
readonly labelKey: "formattingBar.clearFormatting";
|
|
558
|
+
readonly paths: readonly string[];
|
|
559
|
+
readonly state: {
|
|
560
|
+
readonly kind: "command";
|
|
561
|
+
};
|
|
562
|
+
}];
|
|
563
|
+
}, {
|
|
564
|
+
readonly id: "review";
|
|
565
|
+
readonly labelKey: "formattingBar.commentsAndChanges";
|
|
566
|
+
readonly controls: readonly [{
|
|
567
|
+
readonly id: "comments";
|
|
568
|
+
readonly shape: "icon";
|
|
569
|
+
readonly labelKey: "formattingBar.commentsAndChanges";
|
|
570
|
+
readonly paths: readonly string[];
|
|
571
|
+
readonly state: {
|
|
572
|
+
readonly kind: "command";
|
|
573
|
+
};
|
|
574
|
+
}, {
|
|
575
|
+
readonly id: "editingMode";
|
|
576
|
+
readonly shape: "dropdown";
|
|
577
|
+
readonly labelKey: "editingMode.label";
|
|
578
|
+
readonly valueKey: "editingMode.editing";
|
|
579
|
+
readonly paths: readonly string[];
|
|
580
|
+
readonly state: {
|
|
581
|
+
readonly kind: "command";
|
|
582
|
+
};
|
|
583
|
+
}];
|
|
584
|
+
}, {
|
|
585
|
+
readonly id: "contentControl";
|
|
586
|
+
readonly labelKey: "contentControl.group";
|
|
587
|
+
readonly contextual: true;
|
|
588
|
+
readonly controls: readonly [{
|
|
589
|
+
readonly id: "showAll";
|
|
590
|
+
readonly labelKey: "contentControl.showAll";
|
|
591
|
+
readonly paths: readonly string[];
|
|
592
|
+
readonly state: {
|
|
593
|
+
readonly kind: "command";
|
|
594
|
+
};
|
|
595
|
+
}, {
|
|
596
|
+
readonly id: "formFill";
|
|
597
|
+
readonly labelKey: "contentControl.formFill";
|
|
598
|
+
readonly paths: readonly string[];
|
|
599
|
+
readonly state: {
|
|
600
|
+
readonly kind: "command";
|
|
601
|
+
};
|
|
602
|
+
}, {
|
|
603
|
+
readonly id: "inspector";
|
|
604
|
+
readonly labelKey: "contentControl.inspector";
|
|
605
|
+
readonly paths: readonly string[];
|
|
606
|
+
readonly state: {
|
|
607
|
+
readonly kind: "command";
|
|
608
|
+
};
|
|
609
|
+
}, {
|
|
610
|
+
readonly id: "remove";
|
|
611
|
+
readonly labelKey: "contentControl.remove";
|
|
612
|
+
readonly paths: readonly string[];
|
|
613
|
+
readonly state: {
|
|
614
|
+
readonly kind: "command";
|
|
615
|
+
};
|
|
616
|
+
}];
|
|
617
|
+
}, {
|
|
618
|
+
readonly id: "image";
|
|
619
|
+
readonly labelKey: "formattingBar.groups.image";
|
|
620
|
+
readonly contextual: true;
|
|
621
|
+
readonly controls: readonly [{
|
|
622
|
+
readonly id: "insert";
|
|
623
|
+
readonly labelKey: "toolbar.image";
|
|
624
|
+
readonly paths: readonly string[];
|
|
625
|
+
readonly state: {
|
|
626
|
+
readonly kind: "command";
|
|
627
|
+
};
|
|
628
|
+
}, {
|
|
629
|
+
readonly id: "properties";
|
|
630
|
+
readonly labelKey: "formattingBar.imagePropertiesShortcut";
|
|
631
|
+
readonly paths: readonly string[];
|
|
632
|
+
readonly state: {
|
|
633
|
+
readonly kind: "command";
|
|
634
|
+
};
|
|
635
|
+
}, {
|
|
636
|
+
readonly id: "wrap";
|
|
637
|
+
readonly shape: "dropdown";
|
|
638
|
+
readonly labelKey: "formattingBar.imageWrap";
|
|
639
|
+
readonly paths: readonly string[];
|
|
640
|
+
readonly valueKey: "imageWrap.inline";
|
|
641
|
+
readonly state: {
|
|
642
|
+
readonly kind: "value";
|
|
643
|
+
};
|
|
644
|
+
}, {
|
|
645
|
+
readonly id: "altText";
|
|
646
|
+
readonly shape: "dropdown";
|
|
647
|
+
readonly labelKey: "formattingBar.altText";
|
|
648
|
+
readonly paths: null;
|
|
649
|
+
readonly valueKey: "imageProperties.altText";
|
|
650
|
+
readonly state: {
|
|
651
|
+
readonly kind: "value";
|
|
652
|
+
};
|
|
653
|
+
}];
|
|
654
|
+
}, {
|
|
655
|
+
readonly id: "table";
|
|
656
|
+
readonly labelKey: "formattingBar.groups.table";
|
|
657
|
+
readonly contextual: true;
|
|
658
|
+
readonly controls: readonly [{
|
|
659
|
+
readonly id: "insert";
|
|
660
|
+
readonly labelKey: "toolbar.table";
|
|
661
|
+
readonly paths: readonly string[];
|
|
662
|
+
readonly state: {
|
|
663
|
+
readonly kind: "command";
|
|
664
|
+
};
|
|
665
|
+
}, {
|
|
666
|
+
readonly id: "borderTarget";
|
|
667
|
+
readonly shape: "dropdown";
|
|
668
|
+
readonly labelKey: "table.borders.tooltip";
|
|
669
|
+
readonly paths: readonly string[];
|
|
670
|
+
readonly state: {
|
|
671
|
+
readonly kind: "value";
|
|
672
|
+
};
|
|
673
|
+
}, {
|
|
674
|
+
readonly id: "borderColor";
|
|
675
|
+
readonly shape: "colorSplit";
|
|
676
|
+
readonly swatch: "#000000";
|
|
677
|
+
readonly labelKey: "table.borderColor";
|
|
678
|
+
readonly paths: readonly string[];
|
|
679
|
+
readonly state: {
|
|
680
|
+
readonly kind: "value";
|
|
681
|
+
};
|
|
682
|
+
}, {
|
|
683
|
+
readonly id: "borderStyle";
|
|
684
|
+
readonly shape: "dropdown";
|
|
685
|
+
readonly labelKey: "table.borders.styleAriaLabel";
|
|
686
|
+
readonly paths: readonly string[];
|
|
687
|
+
readonly state: {
|
|
688
|
+
readonly kind: "value";
|
|
689
|
+
};
|
|
690
|
+
}, {
|
|
691
|
+
readonly id: "borderWidth";
|
|
692
|
+
readonly shape: "dropdown";
|
|
693
|
+
readonly labelKey: "table.borderWidth";
|
|
694
|
+
readonly paths: readonly string[];
|
|
695
|
+
readonly state: {
|
|
696
|
+
readonly kind: "value";
|
|
697
|
+
};
|
|
698
|
+
}, {
|
|
699
|
+
readonly id: "cellFill";
|
|
700
|
+
readonly shape: "colorSplit";
|
|
701
|
+
readonly swatch: "#ffffff";
|
|
702
|
+
readonly labelKey: "table.cellFillColor";
|
|
703
|
+
readonly paths: readonly string[];
|
|
704
|
+
readonly state: {
|
|
705
|
+
readonly kind: "value";
|
|
706
|
+
};
|
|
707
|
+
}];
|
|
708
|
+
}, {
|
|
709
|
+
readonly id: "file";
|
|
710
|
+
readonly labelKey: "toolbar.file";
|
|
711
|
+
readonly contextual: true;
|
|
712
|
+
readonly controls: readonly [{
|
|
713
|
+
readonly id: "open";
|
|
714
|
+
readonly labelKey: "toolbar.open";
|
|
715
|
+
readonly paths: readonly string[];
|
|
716
|
+
readonly state: {
|
|
717
|
+
readonly kind: "load";
|
|
718
|
+
};
|
|
719
|
+
}, {
|
|
720
|
+
readonly id: "save";
|
|
721
|
+
readonly labelKey: "toolbar.saveShortcut";
|
|
722
|
+
readonly paths: readonly string[];
|
|
723
|
+
readonly state: {
|
|
724
|
+
readonly kind: "save";
|
|
725
|
+
};
|
|
726
|
+
}, {
|
|
727
|
+
readonly id: "pageSetup";
|
|
728
|
+
readonly labelKey: "toolbar.pageSetup";
|
|
729
|
+
readonly paths: readonly string[];
|
|
730
|
+
readonly state: {
|
|
731
|
+
readonly kind: "command";
|
|
732
|
+
};
|
|
733
|
+
}];
|
|
734
|
+
}, {
|
|
735
|
+
readonly id: "insert";
|
|
736
|
+
readonly labelKey: "toolbar.insert";
|
|
737
|
+
readonly contextual: true;
|
|
738
|
+
readonly controls: readonly [{
|
|
739
|
+
readonly id: "footnote";
|
|
740
|
+
readonly labelKey: "toolbar.insertFootnote";
|
|
741
|
+
readonly paths: readonly string[];
|
|
742
|
+
readonly state: {
|
|
743
|
+
readonly kind: "command";
|
|
744
|
+
};
|
|
745
|
+
}, {
|
|
746
|
+
readonly id: "endnote";
|
|
747
|
+
readonly labelKey: "toolbar.insertEndnote";
|
|
748
|
+
readonly paths: readonly string[];
|
|
749
|
+
readonly state: {
|
|
750
|
+
readonly kind: "command";
|
|
751
|
+
};
|
|
752
|
+
}, {
|
|
753
|
+
readonly id: "pageNumber";
|
|
754
|
+
readonly labelKey: "headerFooter.insertPageNumber";
|
|
755
|
+
readonly paths: readonly string[];
|
|
756
|
+
readonly state: {
|
|
757
|
+
readonly kind: "command";
|
|
758
|
+
};
|
|
759
|
+
}, {
|
|
760
|
+
readonly id: "totalPages";
|
|
761
|
+
readonly labelKey: "headerFooter.insertTotalPages";
|
|
762
|
+
readonly paths: readonly string[];
|
|
763
|
+
readonly state: {
|
|
764
|
+
readonly kind: "command";
|
|
765
|
+
};
|
|
766
|
+
}, {
|
|
767
|
+
readonly id: "sectionPages";
|
|
768
|
+
readonly labelKey: "headerFooter.insertSectionPages";
|
|
769
|
+
readonly paths: readonly string[];
|
|
770
|
+
readonly state: {
|
|
771
|
+
readonly kind: "command";
|
|
772
|
+
};
|
|
773
|
+
}, {
|
|
774
|
+
readonly id: "pageXofY";
|
|
775
|
+
readonly labelKey: "headerFooter.insertPageXofY";
|
|
776
|
+
readonly paths: readonly string[];
|
|
777
|
+
readonly state: {
|
|
778
|
+
readonly kind: "command";
|
|
779
|
+
};
|
|
780
|
+
}, {
|
|
781
|
+
readonly id: "pageBreak";
|
|
782
|
+
readonly labelKey: "toolbar.pageBreak";
|
|
783
|
+
readonly paths: readonly string[];
|
|
784
|
+
readonly state: {
|
|
785
|
+
readonly kind: "command";
|
|
786
|
+
};
|
|
787
|
+
}, {
|
|
788
|
+
readonly id: "sectionBreakNextPage";
|
|
789
|
+
readonly labelKey: "toolbar.sectionBreakNextPage";
|
|
790
|
+
readonly paths: readonly string[];
|
|
791
|
+
readonly state: {
|
|
792
|
+
readonly kind: "command";
|
|
793
|
+
};
|
|
794
|
+
}, {
|
|
795
|
+
readonly id: "sectionBreakContinuous";
|
|
796
|
+
readonly labelKey: "toolbar.sectionBreakContinuous";
|
|
797
|
+
readonly paths: readonly string[];
|
|
798
|
+
readonly state: {
|
|
799
|
+
readonly kind: "command";
|
|
800
|
+
};
|
|
801
|
+
}, {
|
|
802
|
+
readonly id: "toc";
|
|
803
|
+
readonly labelKey: "toolbar.tableOfContents";
|
|
804
|
+
readonly paths: readonly string[];
|
|
805
|
+
readonly state: {
|
|
806
|
+
readonly kind: "command";
|
|
807
|
+
};
|
|
808
|
+
}];
|
|
809
|
+
}];
|
|
810
|
+
/**
|
|
811
|
+
* Every group id in the chrome, as a literal union. Stable public API; renaming a group
|
|
812
|
+
* id is a breaking change.
|
|
813
|
+
*
|
|
814
|
+
* @public
|
|
815
|
+
*/
|
|
816
|
+
type ChromeGroupId = 'history' | 'zoom' | 'styles' | 'font' | 'text' | 'script' | 'alignment' | 'list' | 'format' | 'review' | 'contentControl' | 'image' | 'table' | 'file' | 'insert';
|
|
817
|
+
/**
|
|
818
|
+
* The public slot vocabulary: `${groupId}.${controlId}` for every control that actually
|
|
819
|
+
* exists — `text.bold`, `font.family`, `alignment.left`. THE stable contract a host
|
|
820
|
+
* composes against and `commandForSlot` resolves; renaming a slot is a breaking change.
|
|
821
|
+
*
|
|
822
|
+
* @public
|
|
823
|
+
*/
|
|
824
|
+
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.clear' | 'review.comments' | 'review.editingMode' | 'contentControl.showAll' | 'contentControl.formFill' | 'contentControl.inspector' | 'contentControl.remove' | 'image.insert' | 'image.properties' | 'image.wrap' | 'image.altText' | 'table.insert' | 'table.borderTarget' | 'table.borderColor' | 'table.borderStyle' | 'table.borderWidth' | 'table.cellFill' | 'file.open' | 'file.save' | 'file.pageSetup' | 'insert.footnote' | 'insert.endnote' | 'insert.pageNumber' | 'insert.totalPages' | 'insert.sectionPages' | 'insert.pageXofY' | 'insert.pageBreak' | 'insert.sectionBreakNextPage' | 'insert.sectionBreakContinuous' | 'insert.toc';
|
|
825
|
+
/**
|
|
826
|
+
* Every control id in the chrome, as a literal union. Unique WITHIN a group, not
|
|
827
|
+
* globally (`image.insert` / `table.insert`) — key consumers on {@link ChromeSlotId}.
|
|
828
|
+
*
|
|
829
|
+
* @public
|
|
830
|
+
*/
|
|
831
|
+
type ChromeControlId = ChromeSlotId extends `${string}.${infer C}` ? C : never;
|
|
832
|
+
/**
|
|
833
|
+
* The slot id of one control within its group. Only meaningful for entries of
|
|
834
|
+
* `CHROME_GROUPS` — the cast is sound because every group/control pair in the registry
|
|
835
|
+
* is, by construction, a member of the `ChromeSlotId` union.
|
|
836
|
+
*
|
|
837
|
+
* @public
|
|
838
|
+
*/
|
|
839
|
+
declare function chromeSlotId(group: {
|
|
840
|
+
readonly id: string;
|
|
841
|
+
}, control: {
|
|
842
|
+
readonly id: string;
|
|
843
|
+
}): ChromeSlotId;
|
|
844
|
+
/**
|
|
845
|
+
* The groups of the DEFAULT toolbar arrangement, in bar order: every group that is
|
|
846
|
+
* not `contextual`. This is the registry's default bar — undo/redo through the
|
|
847
|
+
* editing-mode picker — and what both adapters render when the host composes
|
|
848
|
+
* nothing. Contextual slots (`image.*`, `table.insert`, `file.save`) remain
|
|
849
|
+
* available for explicit composition.
|
|
850
|
+
*
|
|
851
|
+
* @public
|
|
852
|
+
*/
|
|
853
|
+
declare function defaultChromeGroups(): readonly ChromeGroup[];
|
|
854
|
+
/**
|
|
855
|
+
* The formatting-bar groups for one editor snapshot: the default bar, plus the
|
|
856
|
+
* contextual `image` group when a drawing is selected. Insertion without a selection is
|
|
857
|
+
* not in the packaged chrome at all — a host that wants it places `image.insert` itself,
|
|
858
|
+
* through `DocxEditor.Toolbar.ImageInsert` or `DocxEditor.Menu.ImageInsert`.
|
|
859
|
+
*
|
|
860
|
+
* @public
|
|
861
|
+
*/
|
|
862
|
+
declare function formattingBarChromeGroups(image: ImageContext | null): readonly ChromeGroup[];
|
|
863
|
+
/**
|
|
864
|
+
* A row that runs one chrome slot.
|
|
865
|
+
*
|
|
866
|
+
* @public
|
|
867
|
+
*/
|
|
868
|
+
interface ChromeMenuItemEntry {
|
|
869
|
+
readonly kind: 'item';
|
|
870
|
+
readonly slot: ChromeSlotId;
|
|
871
|
+
/**
|
|
872
|
+
* Plain-label override for this row.
|
|
873
|
+
*
|
|
874
|
+
* A slot's own `labelKey` is a TOOLTIP key, and several of them fold the shortcut into
|
|
875
|
+
* the text (`formattingBar.boldShortcut` is "Bold (Ctrl+B)"). A menu puts the shortcut
|
|
876
|
+
* in its own right-hand column, so the row needs the bare noun. Both keys already exist
|
|
877
|
+
* in the catalogue — this points at the plain one rather than minting a duplicate.
|
|
878
|
+
*/
|
|
879
|
+
readonly labelKey?: string;
|
|
880
|
+
/** i18n key of the shortcut shown right-aligned on the row (`toolbar.saveShortcut`). */
|
|
881
|
+
readonly shortcutKey?: string;
|
|
882
|
+
/**
|
|
883
|
+
* The row opens a size PICKER instead of firing on click — Word's insert-table grid.
|
|
884
|
+
* The slot still owns the label, the icon and the enabled state; only the dispatch
|
|
885
|
+
* differs, and the picked size is what the host sends.
|
|
886
|
+
*/
|
|
887
|
+
readonly picker?: 'tableGrid';
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* A row that opens a nested panel of rows (Insert › Break).
|
|
891
|
+
*
|
|
892
|
+
* It carries its own label and icon rather than a slot, because a submenu PARENT has no
|
|
893
|
+
* command: clicking it opens the panel. Giving it a slot would mint a public id for a
|
|
894
|
+
* control that can never be enabled, and `toolbarCommandState` would have to invent an
|
|
895
|
+
* answer about it.
|
|
896
|
+
*
|
|
897
|
+
* @public
|
|
898
|
+
*/
|
|
899
|
+
interface ChromeMenuSubmenuEntry {
|
|
900
|
+
readonly kind: 'submenu';
|
|
901
|
+
readonly labelKey: string;
|
|
902
|
+
readonly paths: readonly string[] | null;
|
|
903
|
+
readonly items: readonly ChromeMenuEntry[];
|
|
904
|
+
}
|
|
905
|
+
/** A horizontal rule between groups of rows. @public */
|
|
906
|
+
interface ChromeMenuSeparatorEntry {
|
|
907
|
+
readonly kind: 'separator';
|
|
908
|
+
}
|
|
909
|
+
/** One row of a chrome menu. @public */
|
|
910
|
+
type ChromeMenuEntry = ChromeMenuItemEntry | ChromeMenuSubmenuEntry | ChromeMenuSeparatorEntry;
|
|
911
|
+
/**
|
|
912
|
+
* Every menu id, as a literal union. Stable public API; renaming one is a breaking change,
|
|
913
|
+
* exactly like a group or slot id.
|
|
914
|
+
*
|
|
915
|
+
* @public
|
|
916
|
+
*/
|
|
917
|
+
type ChromeMenuId = 'file' | 'format' | 'insert' | 'help';
|
|
918
|
+
/** One menu of the menu bar. @public */
|
|
919
|
+
interface ChromeMenu {
|
|
920
|
+
readonly id: ChromeMenuId;
|
|
921
|
+
readonly labelKey: string;
|
|
922
|
+
readonly entries: readonly ChromeMenuEntry[];
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* The menu bar the chrome shows above the toolbar, in bar order: File, Format, Insert,
|
|
926
|
+
* Help.
|
|
927
|
+
*
|
|
928
|
+
* @public
|
|
929
|
+
*/
|
|
930
|
+
declare const CHROME_MENUS: readonly ChromeMenu[];
|
|
931
|
+
/**
|
|
932
|
+
* Every slot a menu places, in menu order, submenus flattened. What a parity test asserts
|
|
933
|
+
* against, and what a host enumerates to know which capabilities the menu bar reaches.
|
|
934
|
+
*
|
|
935
|
+
* @public
|
|
936
|
+
*/
|
|
937
|
+
declare function chromeMenuSlots(): readonly ChromeSlotId[];
|
|
938
|
+
/** Total controls, so a parity test can assert none were dropped. */
|
|
939
|
+
declare function chromeControlCount(): number;
|
|
940
|
+
/**
|
|
941
|
+
* i18n key for the tooltip on a control an ADAPTER renders but cannot drive yet — a
|
|
942
|
+
* value slot in a toolbar that has grown no picker for it, say. It is never the reason
|
|
943
|
+
* a control is disabled: when the ENGINE refuses, the tooltip is the engine's own
|
|
944
|
+
* `disabledReason`, never an adapter paraphrase.
|
|
945
|
+
*/
|
|
946
|
+
declare const CHROME_UNAVAILABLE_KEY = "formattingBar.unavailableInPreview";
|
|
947
|
+
|
|
948
|
+
type TableCommandSelectionPolicy = {
|
|
949
|
+
readonly kind: 'preserveSelection';
|
|
950
|
+
} | {
|
|
951
|
+
readonly kind: 'adoptCommittedCaret';
|
|
952
|
+
};
|
|
953
|
+
type TableCommandPlan = {
|
|
954
|
+
readonly ok: true;
|
|
955
|
+
readonly ops: readonly TreeDocOp[];
|
|
956
|
+
readonly selection: TableCommandSelectionPolicy;
|
|
957
|
+
} | {
|
|
958
|
+
readonly ok: false;
|
|
959
|
+
readonly code: 'unsupported' | 'invalidArgs' | 'locked';
|
|
960
|
+
readonly reason: string;
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
type NotePropertiesSlice = {
|
|
964
|
+
readonly resolved: ResolvedFootnoteProperties | ResolvedEndnoteProperties;
|
|
965
|
+
readonly documentAuthored?: AuthoredNoteProperties;
|
|
966
|
+
readonly sectionAuthored?: AuthoredNoteProperties;
|
|
967
|
+
};
|
|
968
|
+
type NotePropertiesStateSnapshot = {
|
|
969
|
+
readonly sectionIndex: number;
|
|
970
|
+
readonly footnote: NotePropertiesSlice;
|
|
971
|
+
readonly endnote: NotePropertiesSlice;
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* A hyperlink as the surface reports it: its identity, where it sits, and the SANITIZED
|
|
976
|
+
* target. `href: null` is an inert link — a refused scheme or a dangling relationship — which
|
|
977
|
+
* a UI shows and offers to edit but must never offer to open.
|
|
978
|
+
*/
|
|
979
|
+
interface SurfaceHyperlink {
|
|
980
|
+
/** Canonical node id of the `w:hyperlink`. */
|
|
981
|
+
readonly id: string;
|
|
982
|
+
readonly paragraphId: string;
|
|
983
|
+
/** UTF-16 range of the link's display text within its paragraph. */
|
|
984
|
+
readonly start: number;
|
|
985
|
+
readonly end: number;
|
|
986
|
+
readonly text: string;
|
|
987
|
+
readonly kind: 'external' | 'internal' | 'unresolved';
|
|
988
|
+
/** Sanitized projection: an absolute URL, `#anchor`, or null when inert. */
|
|
989
|
+
readonly href: string | null;
|
|
990
|
+
/** The authored target, for an editor to seed its input with. */
|
|
991
|
+
readonly authored: string;
|
|
992
|
+
readonly anchor?: string;
|
|
993
|
+
readonly tooltip?: string;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Reading and writing hyperlinks on the surface.
|
|
997
|
+
*
|
|
998
|
+
* Every href that leaves here has already been through `sanitizeHref` — targets come from files,
|
|
999
|
+
* so `javascript:`, `data:` and `vbscript:` are dropped at the parse boundary rather than trusted
|
|
1000
|
+
* to be filtered by whoever renders them.
|
|
1001
|
+
*/
|
|
1002
|
+
interface HyperlinkOps {
|
|
1003
|
+
/** Every link in the paragraph the caret is in. */
|
|
1004
|
+
linksInCaretParagraph(): SurfaceHyperlink[];
|
|
1005
|
+
/** The link the caret sits in, or null. */
|
|
1006
|
+
linkAtCaret(): SurfaceHyperlink | null;
|
|
1007
|
+
/** The link with this node id, or null. */
|
|
1008
|
+
linkById(linkId: string): SurfaceHyperlink | null;
|
|
1009
|
+
/**
|
|
1010
|
+
* Apply a link to the selection, or retarget the one the caret is already in.
|
|
1011
|
+
*
|
|
1012
|
+
* `text` replaces the display text when supplied. Returns whether anything committed;
|
|
1013
|
+
* a refusal leaves the document exactly as it was.
|
|
1014
|
+
*/
|
|
1015
|
+
applyHyperlink(input: {
|
|
1016
|
+
readonly url?: string;
|
|
1017
|
+
readonly anchor?: string;
|
|
1018
|
+
readonly text?: string;
|
|
1019
|
+
readonly tooltip?: string;
|
|
1020
|
+
}): boolean;
|
|
1021
|
+
/** Take the link off the one at the caret (or a named one). Returns whether it committed. */
|
|
1022
|
+
removeHyperlink(linkId?: string): boolean;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/** A click on a painted link, after native navigation was refused. */
|
|
1026
|
+
interface HyperlinkActivation {
|
|
1027
|
+
readonly link: SurfaceHyperlink;
|
|
1028
|
+
/** The clicked line fragment's viewport rect, so a popover can be placed under it. */
|
|
1029
|
+
readonly rect: {
|
|
1030
|
+
readonly left: number;
|
|
1031
|
+
readonly top: number;
|
|
1032
|
+
readonly bottom: number;
|
|
1033
|
+
readonly right: number;
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Moving the caret and the viewport: to a position, to a bookmark, or out to an external target.
|
|
1038
|
+
*
|
|
1039
|
+
* {@link SurfaceNavigation.openExternal} is THE external-activation call site, and it refuses
|
|
1040
|
+
* anything but an already-sanitized href. Routing an authored target through some other path is
|
|
1041
|
+
* how a document gets to choose where a click goes.
|
|
1042
|
+
*/
|
|
1043
|
+
interface SurfaceNavigation {
|
|
1044
|
+
/** Snap to a semantic position using layout geometry, then place the caret there. */
|
|
1045
|
+
goToPosition(position: {
|
|
1046
|
+
paragraphId: string;
|
|
1047
|
+
offset: number;
|
|
1048
|
+
}): boolean;
|
|
1049
|
+
/**
|
|
1050
|
+
* Scroll a bookmark into view and place the caret at it. Answers false for a name no
|
|
1051
|
+
* bookmark declares — an inert click, which is what Word does with a dangling anchor.
|
|
1052
|
+
*/
|
|
1053
|
+
goToBookmark(name: string): boolean;
|
|
1054
|
+
/**
|
|
1055
|
+
* THE external-activation call site. Refuses anything but a sanitized projection, so a
|
|
1056
|
+
* caller cannot route an authored target through it by mistake.
|
|
1057
|
+
*/
|
|
1058
|
+
openExternal(href: string | null): boolean;
|
|
1059
|
+
destroy(): void;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* Everything {@link createDocxEditor} accepts. Every field is optional.
|
|
1064
|
+
*
|
|
1065
|
+
* `container` is the one that changes the shape of the whole lifecycle: omitting it produces an
|
|
1066
|
+
* instance that does no DOM work until `attach(el)`, which is what lets a provider own the editor
|
|
1067
|
+
* before any component has rendered a mount point.
|
|
1068
|
+
*
|
|
1069
|
+
* @public
|
|
1070
|
+
*/
|
|
1071
|
+
interface DocxEditorConfig {
|
|
1072
|
+
/**
|
|
1073
|
+
* The element the paginated surface mounts into. The surface owns this subtree.
|
|
1074
|
+
*
|
|
1075
|
+
* Optional: an instance created WITHOUT a container stashes its document bytes and does
|
|
1076
|
+
* no DOM work until `attach(el)` — the provider-first shape, where the editor exists
|
|
1077
|
+
* before any component has rendered a mount point. With a container, the document mounts
|
|
1078
|
+
* immediately at construction, exactly as before.
|
|
1079
|
+
*/
|
|
1080
|
+
container?: HTMLElement;
|
|
1081
|
+
/**
|
|
1082
|
+
* A document to load at construction. Bytes only in practice: a `DocumentHandle` cannot
|
|
1083
|
+
* be re-opened (the handle is identity, not content), so passing one emits a typed
|
|
1084
|
+
* `error` event rather than silently loading nothing.
|
|
1085
|
+
*/
|
|
1086
|
+
document?: DocumentSource;
|
|
1087
|
+
/**
|
|
1088
|
+
* Font bytes for Word-accurate (HarfBuzz-shaped) line wrap and pagination. Omitted,
|
|
1089
|
+
* layout falls back to a fixed-width estimate; fonts embedded in the document are
|
|
1090
|
+
* wired in automatically either way. For Word's default faces (Calibri, Times New
|
|
1091
|
+
* Roman, …) pass `await loadDefaultFonts()` from `@docx-editor.dev/fonts` — a bare
|
|
1092
|
+
* fragment (`{ sources, substitutions }`) is accepted and composed with defaults, or
|
|
1093
|
+
* merge several origins yourself with `composeFontConfiguration`. Sampled per load;
|
|
1094
|
+
* failures degrade to the fixed measurer and report through `onFontError`.
|
|
1095
|
+
*
|
|
1096
|
+
* Pass a {@link FontResolver} instead to resolve ON DEMAND: the function is called once
|
|
1097
|
+
* per load, after the document is parsed, with the families it actually declares, and
|
|
1098
|
+
* only what it returns is loaded. A document naming nothing the resolver covers costs
|
|
1099
|
+
* nothing. Note that a fetching resolver makes opening a document perform network
|
|
1100
|
+
* requests — the engine never supplies one, so that stays your call.
|
|
1101
|
+
*/
|
|
1102
|
+
fonts?: FontConfiguration | FontConfigurationFragment | FontResolver;
|
|
1103
|
+
author?: string;
|
|
1104
|
+
locale?: string;
|
|
1105
|
+
/** Localized drawing refusal labels; defaults to English when omitted. */
|
|
1106
|
+
translate?: (key: string, params?: Record<string, string | number>) => string;
|
|
1107
|
+
/**
|
|
1108
|
+
* Capability modules to register — the seam `@docx-editor.dev/pro` plugs in
|
|
1109
|
+
* through. Omitted, the editor runs the free tier: lossless round-trip,
|
|
1110
|
+
* final-state revision rendering, review chrome disabled with the engine's
|
|
1111
|
+
* reason. See {@link EditorModule}.
|
|
1112
|
+
*/
|
|
1113
|
+
modules?: readonly EditorModule[];
|
|
1114
|
+
/** `'view'` refuses every mutating command through the facade; default `'edit'`. */
|
|
1115
|
+
mode?: 'edit' | 'view';
|
|
1116
|
+
/** Override raster decode for insert/replace image commands; defaults to browser/headless. */
|
|
1117
|
+
imageDecodePort?: ImageDecodePort;
|
|
1118
|
+
zoom?: number;
|
|
1119
|
+
onFontError?: (error: EditorFontError) => void;
|
|
1120
|
+
/** Localized labels for table insertion furniture on the painted surface. */
|
|
1121
|
+
tableInteractionLabel?: (key: 'table.insertRowBelow' | 'table.insertColumnRight') => string;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Which measurer the current document's layout runs on, and whether shaped resolution is
|
|
1125
|
+
* still in flight. Returned by {@link DocxEditorInstance.fontMeasurement}.
|
|
1126
|
+
*/
|
|
1127
|
+
interface FontMeasurementState {
|
|
1128
|
+
/** `fixed` estimates advance widths; `shaped` measures real font bytes with HarfBuzz. */
|
|
1129
|
+
readonly measurer: 'fixed' | 'shaped';
|
|
1130
|
+
/** True while font resolution for the current document is still running. */
|
|
1131
|
+
readonly resolving: boolean;
|
|
1132
|
+
/** The shaped measurer's identity (admitted face hashes); absent while fixed. */
|
|
1133
|
+
readonly producer?: string;
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* The host chrome that answers the engine's hyperlink gestures.
|
|
1137
|
+
*
|
|
1138
|
+
* A CLICK on an external link and Ctrl/Cmd+K both mean "the user wants the link UI", and the
|
|
1139
|
+
* engine deliberately does not know what that looks like. Registered rather than passed at
|
|
1140
|
+
* construction because the chrome mounts after the editor does, and it survives a document
|
|
1141
|
+
* reload — the surface is rebuilt, the handlers are not.
|
|
1142
|
+
*/
|
|
1143
|
+
interface HyperlinkChromeHandlers {
|
|
1144
|
+
/** A plain click on an external or inert link: show the popover at `activation.rect`. */
|
|
1145
|
+
readonly onPopover?: (activation: HyperlinkActivation) => void;
|
|
1146
|
+
/** Ctrl/Cmd+K: open insert-or-edit for the selection. */
|
|
1147
|
+
readonly onRequest?: () => void;
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* The concrete facade type: the full `Editor` contract plus the instance-only surface.
|
|
1151
|
+
*
|
|
1152
|
+
* `surface`, `stateVersion`, `attach` and `detach` live HERE rather than on `Editor`:
|
|
1153
|
+
* they are what a store binding and a mounting host need, not what document commands
|
|
1154
|
+
* need. Production adapters program against `Editor` for everything else.
|
|
1155
|
+
*/
|
|
1156
|
+
interface DocxEditorInstance extends Editor {
|
|
1157
|
+
/** Bumps on mount, detach, destroy, and document reload — guards async image intents. */
|
|
1158
|
+
readonly mountGeneration: number;
|
|
1159
|
+
/**
|
|
1160
|
+
* The underlying paginated surface for harnesses and tests that need capabilities the
|
|
1161
|
+
* contract does not carry yet (select-all, node-id addressed selection).
|
|
1162
|
+
*/
|
|
1163
|
+
readonly surface: PaginatedSurface | null;
|
|
1164
|
+
/**
|
|
1165
|
+
* Wire the host's hyperlink chrome to the engine's gestures — a click on an external
|
|
1166
|
+
* link, and Ctrl/Cmd+K. Returns an unsubscribe that restores whatever was registered
|
|
1167
|
+
* before, so a popover component can register in an effect and clean up in its teardown.
|
|
1168
|
+
*
|
|
1169
|
+
* Instance-only, like `surface`: it is what a MOUNTING host needs, not what a document
|
|
1170
|
+
* command needs.
|
|
1171
|
+
*/
|
|
1172
|
+
setHyperlinkChrome(handlers: HyperlinkChromeHandlers): Unsubscribe;
|
|
1173
|
+
/**
|
|
1174
|
+
* Monotonic version of the observable editor state. Bumps whenever anything
|
|
1175
|
+
* `snapshot()` reports could have moved — a committed change, a selection move, zoom,
|
|
1176
|
+
* load success or failure, attach/detach, destroy. An external store (React's
|
|
1177
|
+
* `useSyncExternalStore`) uses it as a cheap "did anything change" signal; `snapshot()`
|
|
1178
|
+
* itself is cached per version and returns a stable reference between bumps.
|
|
1179
|
+
*/
|
|
1180
|
+
stateVersion(): number;
|
|
1181
|
+
/**
|
|
1182
|
+
* Which measurer the current document's layout runs on, and whether shaped
|
|
1183
|
+
* resolution is still in flight — the honest "are wrap points Word-accurate yet?"
|
|
1184
|
+
* readout a host shows instead of guessing. `fixed` with `resolving: false` is the
|
|
1185
|
+
* steady state for a document with no usable font source (the documented zero-config
|
|
1186
|
+
* fallback); `shaped` means HarfBuzz measurement over real font bytes. Changes bump
|
|
1187
|
+
* `stateVersion()`.
|
|
1188
|
+
*/
|
|
1189
|
+
fontMeasurement(): FontMeasurementState;
|
|
1190
|
+
/**
|
|
1191
|
+
* Mount into `el`. If the instance holds pending document bytes (created without a
|
|
1192
|
+
* container, or previously detached), they mount now — under the shaped measurer when
|
|
1193
|
+
* fonts have resolved in the meantime. Attaching while already mounted elsewhere moves
|
|
1194
|
+
* the live content via `session.save()`.
|
|
1195
|
+
*
|
|
1196
|
+
* HONEST COSTS: a mount from bytes is a fresh session — the undo stack and the caret do
|
|
1197
|
+
* not survive re-attach (the same cost as the async font remount). After `destroy()`
|
|
1198
|
+
* this is a no-op that emits a typed `error` event: a destroyed instance never remounts.
|
|
1199
|
+
*/
|
|
1200
|
+
attach(el: HTMLElement): void;
|
|
1201
|
+
/**
|
|
1202
|
+
* Tear down the painted surface, stashing the CURRENT document bytes
|
|
1203
|
+
* (`session.save()`) so a later `attach` restores the content — but not the undo stack
|
|
1204
|
+
* or the caret. No-op when already detached or destroyed.
|
|
1205
|
+
*/
|
|
1206
|
+
detach(): void;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
type ImageMutationPreconditions = Readonly<{
|
|
1210
|
+
mountGeneration: number;
|
|
1211
|
+
packageRevision: number;
|
|
1212
|
+
drawingNodeId: string | null;
|
|
1213
|
+
selectionParagraphId: string;
|
|
1214
|
+
selectionOffset: number;
|
|
1215
|
+
}>;
|
|
1216
|
+
/**
|
|
1217
|
+
* The selected image and what may be done to it, or null when nothing image-like is selected.
|
|
1218
|
+
*
|
|
1219
|
+
* Null covers more than "no selection": a placeholder graphic, a drawing the file marks hidden,
|
|
1220
|
+
* and one whose `select` lock is set all read as no selection, because chrome that offered
|
|
1221
|
+
* resize handles on them would promise an edit the store is about to refuse.
|
|
1222
|
+
*/
|
|
1223
|
+
declare function selectedImageStateOf(surface: PaginatedSurface | null): SelectedImageState | null;
|
|
1224
|
+
/**
|
|
1225
|
+
* Snapshot the state an image mutation was planned against: mount generation, package revision,
|
|
1226
|
+
* and the selection anchor.
|
|
1227
|
+
*
|
|
1228
|
+
* Taken at the START of a drag so the commit can be checked against it with
|
|
1229
|
+
* {@link isStaleImageInteractionCommit}. A pointer gesture spans many frames, and a document that
|
|
1230
|
+
* moved underneath it must not have the gesture's final coordinates applied to it.
|
|
1231
|
+
*/
|
|
1232
|
+
declare function captureImageMutationPreconditions(editor: Pick<DocxEditorInstance, 'surface' | 'mountGeneration'>): ImageMutationPreconditions | null;
|
|
1233
|
+
/**
|
|
1234
|
+
* Whether an insert or replace would be accepted — the `can` half of the can-before-exec pair.
|
|
1235
|
+
*
|
|
1236
|
+
* Refuses in suggesting mode, since an image property edit has no tracked-change representation.
|
|
1237
|
+
*/
|
|
1238
|
+
declare function canExecuteImageCommand(command: Extract<EditorCommand, {
|
|
1239
|
+
type: 'insertImage' | 'replaceImage';
|
|
1240
|
+
}>, surface: PaginatedSurface | null): CanResult;
|
|
1241
|
+
/**
|
|
1242
|
+
* Run an insert or replace, re-checking the same gates {@link canExecuteImageCommand} applies.
|
|
1243
|
+
*
|
|
1244
|
+
* Async because image bytes must be decoded to derive their natural extent before the drawing can
|
|
1245
|
+
* be projected — the one editor command that cannot complete synchronously.
|
|
1246
|
+
*/
|
|
1247
|
+
declare function executeImageCommand(editor: DocxEditorInstance, command: Extract<EditorCommand, {
|
|
1248
|
+
type: 'insertImage' | 'replaceImage';
|
|
1249
|
+
}>): Promise<ExecResult>;
|
|
1250
|
+
/** Which of the eight resize handles a drag started from, by compass direction. */
|
|
1251
|
+
type ImageResizeHandle = 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw';
|
|
1252
|
+
/** How far one arrow-key press nudges a selected image, in points. */
|
|
1253
|
+
declare const IMAGE_OVERLAY_NUDGE_PT = 1;
|
|
1254
|
+
/** How far Shift+arrow nudges a selected image, in points. */
|
|
1255
|
+
declare const IMAGE_OVERLAY_NUDGE_SHIFT_PT = 10;
|
|
1256
|
+
/** EMUs per point. DrawingML stores extents in EMU; layout works in points. */
|
|
1257
|
+
declare const EMU_PER_POINT = 12700;
|
|
1258
|
+
/**
|
|
1259
|
+
* One in-flight image drag: where it started, and everything needed to decide at commit time
|
|
1260
|
+
* whether the document still describes what the gesture was planned against.
|
|
1261
|
+
*
|
|
1262
|
+
* Both revisions are captured because they move independently — layout can re-flow without the
|
|
1263
|
+
* package changing, and vice versa.
|
|
1264
|
+
*/
|
|
1265
|
+
interface ImageInteractionSession {
|
|
1266
|
+
readonly drawingNodeId: string;
|
|
1267
|
+
readonly startBounds: {
|
|
1268
|
+
readonly x: number;
|
|
1269
|
+
readonly y: number;
|
|
1270
|
+
readonly width: number;
|
|
1271
|
+
readonly height: number;
|
|
1272
|
+
};
|
|
1273
|
+
readonly startWidthEmu: number;
|
|
1274
|
+
readonly startHeightEmu: number;
|
|
1275
|
+
readonly startPosition: DrawingPositionInput | null;
|
|
1276
|
+
readonly anchorFrameOrigin: {
|
|
1277
|
+
readonly x: number;
|
|
1278
|
+
readonly y: number;
|
|
1279
|
+
} | null;
|
|
1280
|
+
readonly transform: DrawingTransform;
|
|
1281
|
+
readonly mode: 'move' | 'resize';
|
|
1282
|
+
readonly handle: ImageResizeHandle | null;
|
|
1283
|
+
readonly preconditions: ImageMutationPreconditions;
|
|
1284
|
+
readonly layoutRevision: number;
|
|
1285
|
+
readonly packageRevision: number;
|
|
1286
|
+
readonly kind: 'inline' | 'anchored';
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* How an image drag scrolls the page when it reaches the viewport edge.
|
|
1290
|
+
*
|
|
1291
|
+
* Returns the delta ACTUALLY applied rather than the one requested, because a drag at the end of
|
|
1292
|
+
* the document cannot scroll further and the overlay must not move the image by a distance the
|
|
1293
|
+
* page did not travel.
|
|
1294
|
+
*/
|
|
1295
|
+
interface ImageOverlayScrollPort {
|
|
1296
|
+
/** Scroll by a preview delta and return the actual applied document-space delta in points. */
|
|
1297
|
+
scrollBy(deltaY: number): number;
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* The painted geometry of the selected drawing, plus what the overlay is allowed to do to it.
|
|
1301
|
+
*
|
|
1302
|
+
* Carries BOTH the painted rect (points, for hit-testing and handle placement) and the stored
|
|
1303
|
+
* extent (EMU, for writing back), so the overlay never has to convert between the two spaces to
|
|
1304
|
+
* decide what it is looking at.
|
|
1305
|
+
*/
|
|
1306
|
+
interface SelectedDrawingOverlayTarget {
|
|
1307
|
+
readonly id: string;
|
|
1308
|
+
readonly pageIndex: number;
|
|
1309
|
+
readonly x: number;
|
|
1310
|
+
readonly y: number;
|
|
1311
|
+
readonly width: number;
|
|
1312
|
+
readonly height: number;
|
|
1313
|
+
readonly kind: 'inline' | 'anchored';
|
|
1314
|
+
readonly widthEmu: number;
|
|
1315
|
+
readonly heightEmu: number;
|
|
1316
|
+
readonly position: DrawingPositionInput | null;
|
|
1317
|
+
readonly anchorFrameOrigin: {
|
|
1318
|
+
readonly x: number;
|
|
1319
|
+
readonly y: number;
|
|
1320
|
+
} | null;
|
|
1321
|
+
readonly transform: DrawingTransform;
|
|
1322
|
+
readonly canResize: boolean;
|
|
1323
|
+
readonly canMove: boolean;
|
|
1324
|
+
/** Hard lock from `noChangeAspect` — never overridden by Shift. */
|
|
1325
|
+
readonly aspectLocked: boolean;
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* The painted geometry of the selected drawing, for the resize/move overlay — or null.
|
|
1329
|
+
*
|
|
1330
|
+
* Stricter than {@link selectedImageStateOf}: it also requires a COLLAPSED selection, because a
|
|
1331
|
+
* range that merely contains a drawing is a text selection, and drawing handles over it would
|
|
1332
|
+
* claim an object the user did not single out.
|
|
1333
|
+
*/
|
|
1334
|
+
declare function selectedDrawingOverlayTargetOf(surface: PaginatedSurface | null): SelectedDrawingOverlayTarget | null;
|
|
1335
|
+
/** Points to EMU, rounded — EMUs are integral in the file. */
|
|
1336
|
+
declare function pointsToEmu(points: number): number;
|
|
1337
|
+
/** EMU to points. Unrounded, so overlay geometry keeps sub-point precision during a drag. */
|
|
1338
|
+
declare function emuToOverlayPoints(emu: number): number;
|
|
1339
|
+
/**
|
|
1340
|
+
* The extent a resize drag produces, in EMU.
|
|
1341
|
+
*
|
|
1342
|
+
* Computed from the drag's START extent rather than the previous frame's, so a drag that reverses
|
|
1343
|
+
* direction lands exactly where it began instead of accumulating rounding error.
|
|
1344
|
+
*
|
|
1345
|
+
* `preserveAspect` behaves the way Word's handles do: a corner handle scales by whichever axis
|
|
1346
|
+
* moved further, while an edge handle drives the other axis from the original ratio. Both axes
|
|
1347
|
+
* are floored at one point, so a drag past the opposite edge cannot invert the image.
|
|
1348
|
+
*/
|
|
1349
|
+
declare function computeResizedImageExtentEmu(startWidthEmu: number, startHeightEmu: number, handle: ImageResizeHandle, deltaWidthPt: number, deltaHeightPt: number, preserveAspect: boolean): {
|
|
1350
|
+
readonly cx: number;
|
|
1351
|
+
readonly cy: number;
|
|
1352
|
+
};
|
|
1353
|
+
/**
|
|
1354
|
+
* The position a move drag produces, preserving the anchoring the file already used.
|
|
1355
|
+
*
|
|
1356
|
+
* A `frame`-mode position keeps its `relativeToH`/`relativeToV` bases and only shifts the offsets
|
|
1357
|
+
* it actually had — writing an offset the file omitted would re-anchor the drawing to a different
|
|
1358
|
+
* reference and move it somewhere the drag never pointed.
|
|
1359
|
+
*/
|
|
1360
|
+
declare function computeMovedImagePosition(start: DrawingPositionInput, deltaXPt: number, deltaYPt: number): DrawingPositionInput;
|
|
1361
|
+
/**
|
|
1362
|
+
* Whether a drag's commit should be refused because the document moved under it — the refusal to
|
|
1363
|
+
* return, or null when the commit is still valid.
|
|
1364
|
+
*
|
|
1365
|
+
* Checks the mount generation and both revisions captured by
|
|
1366
|
+
* {@link captureImageMutationPreconditions}. A gesture spans many frames, so this is the one
|
|
1367
|
+
* place that decides its coordinates still describe the document they were measured against.
|
|
1368
|
+
*/
|
|
1369
|
+
declare function isStaleImageInteractionCommit(editor: Pick<DocxEditorInstance, 'surface' | 'mountGeneration'>, session: ImageInteractionSession): ExecResult | null;
|
|
1370
|
+
|
|
1371
|
+
/** Points → CSS pixels at the given zoom (matches `mountPaginatedSurface` / semantic paint). */
|
|
1372
|
+
declare function surfacePaintScale(zoom: number): number;
|
|
1373
|
+
/** Layout points to CSS pixels. Pair with {@link surfacePaintScale} for the current zoom. */
|
|
1374
|
+
declare function layoutPointsToCssPixels(points: number, paintScale: number): number;
|
|
1375
|
+
/** CSS pixels back to layout points — what a pointer event's coordinates must go through. */
|
|
1376
|
+
declare function cssPixelsToLayoutPoints(pixels: number, paintScale: number): number;
|
|
1377
|
+
/**
|
|
1378
|
+
* What an overlay needs to place itself over the painted pages: the zoom scale, and where each
|
|
1379
|
+
* page sits horizontally.
|
|
1380
|
+
*
|
|
1381
|
+
* Per-page X offsets rather than one origin, because pages are centred independently and a
|
|
1382
|
+
* narrower page in a mixed-size document does not start where its neighbours do.
|
|
1383
|
+
*/
|
|
1384
|
+
interface SurfaceOverlayCoordinates {
|
|
1385
|
+
readonly paintScale: number;
|
|
1386
|
+
readonly pageOffsetX: ReadonlyMap<number, number>;
|
|
1387
|
+
}
|
|
1388
|
+
/** A rectangle in one page's content frame, in layout points. */
|
|
1389
|
+
interface OverlayFrameRect {
|
|
1390
|
+
readonly pageIndex: number;
|
|
1391
|
+
readonly x: number;
|
|
1392
|
+
readonly y: number;
|
|
1393
|
+
readonly width: number;
|
|
1394
|
+
readonly height: number;
|
|
1395
|
+
}
|
|
1396
|
+
/** Page-content frame → sheet-space CSS pixels (matches `paintSelectionOverlay`). */
|
|
1397
|
+
declare function overlayFrameToSheetCssPixels(layout: SemanticLayout, frame: OverlayFrameRect, coordinates: SurfaceOverlayCoordinates): {
|
|
1398
|
+
readonly left: number;
|
|
1399
|
+
readonly top: number;
|
|
1400
|
+
readonly width: number;
|
|
1401
|
+
readonly height: number;
|
|
1402
|
+
};
|
|
1403
|
+
/** Whether this handle drag should preserve aspect ratio. */
|
|
1404
|
+
declare function resizePreservesAspect(handle: ImageResizeHandle, aspectLocked: boolean, shiftKey: boolean): boolean;
|
|
1405
|
+
/**
|
|
1406
|
+
* Where an anchored drawing's positioning frame begins, in layout points.
|
|
1407
|
+
*
|
|
1408
|
+
* An anchored drawing's offsets are relative to a base the file names (page, margin, column, …),
|
|
1409
|
+
* so a move drag needs that base's origin to turn a pointer delta into a stored offset.
|
|
1410
|
+
*/
|
|
1411
|
+
interface AnchorFrameOrigin {
|
|
1412
|
+
readonly x: number;
|
|
1413
|
+
readonly y: number;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* One resize frame: the extent to store, and the box to draw while the pointer is still down.
|
|
1417
|
+
*
|
|
1418
|
+
* Both, because they are different spaces — the extent is EMU for the file, the preview is
|
|
1419
|
+
* points for the overlay — and computing them separately would let the handle drift from the
|
|
1420
|
+
* rectangle it is dragging.
|
|
1421
|
+
*/
|
|
1422
|
+
interface ImageResizeResult {
|
|
1423
|
+
readonly widthEmu: number;
|
|
1424
|
+
readonly heightEmu: number;
|
|
1425
|
+
readonly previewBounds: {
|
|
1426
|
+
readonly x: number;
|
|
1427
|
+
readonly y: number;
|
|
1428
|
+
readonly width: number;
|
|
1429
|
+
readonly height: number;
|
|
1430
|
+
};
|
|
1431
|
+
readonly position: DrawingPositionInput | null;
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Resolve one resize frame from the pointer's current position.
|
|
1435
|
+
*
|
|
1436
|
+
* Handles rotation and flips by mapping the SCREEN-space handle back to the drawing's local axes
|
|
1437
|
+
* first: dragging the visually-right handle of a 90°-rotated image must change its stored height,
|
|
1438
|
+
* and a flipped image's handles move in the opposite direction from where they appear.
|
|
1439
|
+
*/
|
|
1440
|
+
declare function computeImageResizeResult(options: {
|
|
1441
|
+
readonly handle: ImageResizeHandle;
|
|
1442
|
+
readonly startWidthEmu: number;
|
|
1443
|
+
readonly startHeightEmu: number;
|
|
1444
|
+
readonly startBounds: {
|
|
1445
|
+
readonly x: number;
|
|
1446
|
+
readonly y: number;
|
|
1447
|
+
readonly width: number;
|
|
1448
|
+
readonly height: number;
|
|
1449
|
+
};
|
|
1450
|
+
readonly startPosition: DrawingPositionInput | null;
|
|
1451
|
+
readonly anchorFrameOrigin?: AnchorFrameOrigin | null;
|
|
1452
|
+
readonly deltaXPt: number;
|
|
1453
|
+
readonly deltaYPt: number;
|
|
1454
|
+
readonly transform: DrawingTransform;
|
|
1455
|
+
readonly preserveAspect: boolean;
|
|
1456
|
+
readonly kind: 'inline' | 'anchored';
|
|
1457
|
+
}): ImageResizeResult;
|
|
1458
|
+
/**
|
|
1459
|
+
* An {@link ImageOverlayScrollPort} over a real scroll container.
|
|
1460
|
+
*
|
|
1461
|
+
* Reports the delta the element ACTUALLY scrolled, converted back to points — at the end of the
|
|
1462
|
+
* document that is less than asked for, and the overlay must not move the image further than the
|
|
1463
|
+
* page travelled.
|
|
1464
|
+
*/
|
|
1465
|
+
declare function createImageOverlayScrollPort(scroller: HTMLElement, paintScale: number): {
|
|
1466
|
+
scrollBy(deltaYPoints: number): number;
|
|
1467
|
+
};
|
|
1468
|
+
/**
|
|
1469
|
+
* The committed result of a whole drag, recomputed from the release coordinates.
|
|
1470
|
+
*
|
|
1471
|
+
* Recomputed rather than accumulated from the per-frame previews, so rounding applied once per
|
|
1472
|
+
* frame cannot add up into a final extent that differs from where the pointer actually stopped.
|
|
1473
|
+
*/
|
|
1474
|
+
interface FinalizedImageOverlayInteraction extends ImageResizeResult {
|
|
1475
|
+
readonly position: DrawingPositionInput | null;
|
|
1476
|
+
}
|
|
1477
|
+
/** Recompute the committed overlay result from release pointer coordinates. */
|
|
1478
|
+
declare function finalizeImageOverlayInteraction(options: {
|
|
1479
|
+
readonly session: ImageInteractionSession;
|
|
1480
|
+
readonly deltaXPt: number;
|
|
1481
|
+
readonly deltaYPt: number;
|
|
1482
|
+
readonly accumulatedScrollPt: number;
|
|
1483
|
+
readonly aspectLocked: boolean;
|
|
1484
|
+
readonly shiftKey: boolean;
|
|
1485
|
+
readonly anchorFrameOrigin: AnchorFrameOrigin | null;
|
|
1486
|
+
}): FinalizedImageOverlayInteraction;
|
|
1487
|
+
|
|
1488
|
+
/**
|
|
1489
|
+
* How an edit is written.
|
|
1490
|
+
*
|
|
1491
|
+
* `'suggest'` is the one that changes what the ops MEAN: the same keystroke becomes a `w:ins`
|
|
1492
|
+
* and the same Backspace becomes a `w:del` over the words it would have removed. `'view'`
|
|
1493
|
+
* refuses edits outright.
|
|
1494
|
+
*/
|
|
1495
|
+
type SurfaceEditingMode = 'edit' | 'suggest' | 'view';
|
|
1496
|
+
/**
|
|
1497
|
+
* Content-control interaction lane on the paginated surface.
|
|
1498
|
+
*
|
|
1499
|
+
* Chrome toggles are surface state; value / remove commit through tree ops.
|
|
1500
|
+
*/
|
|
1501
|
+
interface ContentControlOps {
|
|
1502
|
+
/** Toggle show-all boundary chrome. No layout reflow. */
|
|
1503
|
+
setShowAll(show: boolean): void;
|
|
1504
|
+
/** Toggle form-fill Tab navigation mode. */
|
|
1505
|
+
setFormFill(active: boolean): void;
|
|
1506
|
+
/** Whether show-all chrome is on. */
|
|
1507
|
+
showAll(): boolean;
|
|
1508
|
+
/** Whether form-fill navigation is on. */
|
|
1509
|
+
formFill(): boolean;
|
|
1510
|
+
/** Innermost control at the caret from layout boundary records. */
|
|
1511
|
+
atCaret(): ContentControlBoundaryRecord | null;
|
|
1512
|
+
/**
|
|
1513
|
+
* Move to the next or previous editable control (tabIndex, then document order).
|
|
1514
|
+
*
|
|
1515
|
+
* Skips content-locked and bound controls. Selects the control's content for replacement.
|
|
1516
|
+
* Returns whether navigation landed somewhere.
|
|
1517
|
+
*/
|
|
1518
|
+
navigate(direction: 'next' | 'previous'): boolean;
|
|
1519
|
+
/**
|
|
1520
|
+
* Set a control's value through `setContentControlValue`. Honours lock / bound refusals.
|
|
1521
|
+
* Returns whether the op committed.
|
|
1522
|
+
*/
|
|
1523
|
+
setValue(controlId: string, value: string): boolean;
|
|
1524
|
+
/**
|
|
1525
|
+
* Unwrap a control keeping its content (`removeContentControl`). Defaults to the control
|
|
1526
|
+
* at the caret. Returns whether the op committed.
|
|
1527
|
+
*/
|
|
1528
|
+
remove(controlId?: string): boolean;
|
|
1529
|
+
/**
|
|
1530
|
+
* Engine reason a widget or remove action is disabled, or null when allowed.
|
|
1531
|
+
*
|
|
1532
|
+
* `edit` covers content / value changes; `remove` covers unwrap.
|
|
1533
|
+
*/
|
|
1534
|
+
disabledReason(controlId: string, action: 'edit' | 'remove'): string | null;
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* How a paginated surface opens. Every field is optional.
|
|
1538
|
+
*
|
|
1539
|
+
* `measurer` is the injection seam that keeps layout DOM-free — supply one to lay a document out
|
|
1540
|
+
* on a server, or leave it off in a browser to get the canvas measurer.
|
|
1541
|
+
*/
|
|
1542
|
+
interface PaginatedSurfaceOptions {
|
|
1543
|
+
readonly measurer?: TextMeasurer;
|
|
1544
|
+
/** Ambient author for tracked edits. Required before suggesting can write anything. */
|
|
1545
|
+
readonly author?: string;
|
|
1546
|
+
/** Opening mode; changeable at runtime with `setEditingMode`. */
|
|
1547
|
+
readonly editingMode?: SurfaceEditingMode;
|
|
1548
|
+
/**
|
|
1549
|
+
* Identifies the measurer for cache invalidation.
|
|
1550
|
+
*
|
|
1551
|
+
* Fonts resolve asynchronously, so a host that swaps its measurer must change this or the
|
|
1552
|
+
* cached pre-font layout is served for the rest of the session.
|
|
1553
|
+
*/
|
|
1554
|
+
readonly producer?: string;
|
|
1555
|
+
/**
|
|
1556
|
+
* Maps a document-declared font family to the alias its registered bytes live under, so
|
|
1557
|
+
* painted runs can use embedded glyphs without the file's family name entering the
|
|
1558
|
+
* page-global CSS font namespace.
|
|
1559
|
+
*/
|
|
1560
|
+
readonly fontAlias?: (family: string) => string | undefined;
|
|
1561
|
+
/** Points to CSS pixels. */
|
|
1562
|
+
readonly scale?: number;
|
|
1563
|
+
/**
|
|
1564
|
+
* How revisions project into layout and paint. Omitted keeps the layout default
|
|
1565
|
+
* (`all-markup`). The editor facade passes `proposed` when no review module is
|
|
1566
|
+
* registered — the free tier's final-state rendering; the machinery below this
|
|
1567
|
+
* option is shared either way.
|
|
1568
|
+
*/
|
|
1569
|
+
readonly revisionDisplayMode?: RevisionDisplayMode;
|
|
1570
|
+
/**
|
|
1571
|
+
* The review module's derivation hooks for this surface's session. Absent,
|
|
1572
|
+
* `session.reviewItems()` is the typed empty queue and every review affordance
|
|
1573
|
+
* built on it stays inert.
|
|
1574
|
+
*/
|
|
1575
|
+
readonly reviewModel?: ReviewModuleContribution;
|
|
1576
|
+
/**
|
|
1577
|
+
* The family a run with no authored font is reported as by `formatting()` AND painted
|
|
1578
|
+
* in — the face the measurer falls back to. Absent, such a run reports
|
|
1579
|
+
* `fontFamily: null` and paints in whatever font the page inherits, which the measurer
|
|
1580
|
+
* did not measure: visible glyphs drift from wrap points and caret geometry.
|
|
1581
|
+
*/
|
|
1582
|
+
readonly defaultFontFamily?: string;
|
|
1583
|
+
/**
|
|
1584
|
+
* Who resolves a pointer to a caret.
|
|
1585
|
+
*
|
|
1586
|
+
* `'engine'` (the default) answers from the layout records, which is what makes a click in
|
|
1587
|
+
* a margin, an indent or a cell's padding land where it was aimed. `'native'` binds no
|
|
1588
|
+
* pointer handlers and leaves the browser's own caret placement in charge.
|
|
1589
|
+
*/
|
|
1590
|
+
readonly pointer?: 'engine' | 'native';
|
|
1591
|
+
readonly onChange?: (state: PaginatedSurfaceState) => void;
|
|
1592
|
+
/**
|
|
1593
|
+
* A plain click on an external (or inert) hyperlink, for a host to open its popover with.
|
|
1594
|
+
*
|
|
1595
|
+
* Absent means such a click does nothing. That is deliberate: a host with no popover
|
|
1596
|
+
* mounted must not have clicks silently opening tabs, and the popover is the only path to
|
|
1597
|
+
* activation (see the navigation module's single `window.open` gate).
|
|
1598
|
+
*/
|
|
1599
|
+
readonly onHyperlinkPopover?: (activation: HyperlinkActivation) => void;
|
|
1600
|
+
/**
|
|
1601
|
+
* Ctrl/Cmd+K — Word's Insert Hyperlink. The engine reports the request; the host's chrome
|
|
1602
|
+
* decides what a link dialog looks like. A host that passes nothing leaves the key alone
|
|
1603
|
+
* rather than doing something surprising with it.
|
|
1604
|
+
*/
|
|
1605
|
+
readonly onRequestHyperlink?: () => void;
|
|
1606
|
+
/**
|
|
1607
|
+
* Localized accessible names for core-owned table insertion furniture.
|
|
1608
|
+
* Defaults to English from `@docx-editor.dev/i18n` when omitted.
|
|
1609
|
+
*/
|
|
1610
|
+
readonly tableInteractionLabel?: (key: 'table.insertRowBelow' | 'table.insertColumnRight') => string;
|
|
1611
|
+
/** Localized drawing refusal labels; defaults to English when omitted. */
|
|
1612
|
+
readonly drawingStrings?: DrawingPaintStrings;
|
|
1613
|
+
/** Override raster decode for package image intents; defaults to browser/headless. */
|
|
1614
|
+
readonly imageDecodePort?: ImageDecodePort;
|
|
1615
|
+
/**
|
|
1616
|
+
* Localized name for a generated TOC, written as the control's `w:alias` on insert.
|
|
1617
|
+
*
|
|
1618
|
+
* The update ACTIONS are not here: they are rows in the host's context menu, which owns
|
|
1619
|
+
* its own labels. The engine paints no menu of its own.
|
|
1620
|
+
*/
|
|
1621
|
+
readonly tocLabels?: {
|
|
1622
|
+
readonly title: string;
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1625
|
+
/**
|
|
1626
|
+
* What the selection is currently formatted as.
|
|
1627
|
+
*
|
|
1628
|
+
* A value is present only when EVERY span in the selection agrees on it: a selection running
|
|
1629
|
+
* from 11pt into 14pt has no font size, and a toolbar should show a blank rather than pick
|
|
1630
|
+
* one of the two and imply the whole selection is that.
|
|
1631
|
+
*/
|
|
1632
|
+
interface SurfaceFormatting {
|
|
1633
|
+
readonly bold: boolean;
|
|
1634
|
+
readonly italic: boolean;
|
|
1635
|
+
readonly underline: boolean;
|
|
1636
|
+
readonly strikethrough: boolean;
|
|
1637
|
+
readonly superscript: boolean;
|
|
1638
|
+
readonly subscript: boolean;
|
|
1639
|
+
readonly fontFamily: string | null;
|
|
1640
|
+
/** Half-points, the unit OOXML stores and the picker expects. */
|
|
1641
|
+
readonly fontSizeHalfPoints: number | null;
|
|
1642
|
+
readonly color: string | null;
|
|
1643
|
+
readonly highlight: string | null;
|
|
1644
|
+
readonly alignment: 'left' | 'center' | 'right' | 'both' | null;
|
|
1645
|
+
readonly styleId: string | null;
|
|
1646
|
+
/**
|
|
1647
|
+
* `w:spacing`'s line rule and its value: LINES for `multiple`, points for the other two
|
|
1648
|
+
* (`w:line` is 240ths of a line under `auto` and twentieths of a point otherwise).
|
|
1649
|
+
* Null when the selection's paragraphs disagree, or state no line spacing at all.
|
|
1650
|
+
*/
|
|
1651
|
+
readonly lineSpacing: {
|
|
1652
|
+
readonly rule: 'multiple' | 'exact' | 'atLeast';
|
|
1653
|
+
readonly value: number;
|
|
1654
|
+
} | null;
|
|
1655
|
+
/** `w:spacing/@w:before` and `@w:after` in points, null when the selection disagrees. */
|
|
1656
|
+
readonly spaceBeforePt: number | null;
|
|
1657
|
+
readonly spaceAfterPt: number | null;
|
|
1658
|
+
/**
|
|
1659
|
+
* Effective indent at the selection, in twips, or null with no selection or inside a
|
|
1660
|
+
* table.
|
|
1661
|
+
*
|
|
1662
|
+
* The one field here that does NOT go null on disagreement: the values are the FIRST
|
|
1663
|
+
* touched paragraph's and `mixed` reports the disagreement per field, because a ruler
|
|
1664
|
+
* must draw its handles somewhere and Word draws them at the first selected paragraph.
|
|
1665
|
+
*/
|
|
1666
|
+
readonly indent: IndentFormatting | null;
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Where the last pass spent its time, and how much work it actually did.
|
|
1670
|
+
*
|
|
1671
|
+
* The durations are the surface's own three phases — layout, paint, selection sync — timed
|
|
1672
|
+
* separately because they fail separately: a full relayout, a full repaint and a forced
|
|
1673
|
+
* reflow each have a different fix. The counters come free from machinery that already
|
|
1674
|
+
* exists: the layout session says how much was re-placed versus reused, and the scheduler
|
|
1675
|
+
* says how often work was thrown away as stale. `placed` equal to `total` on every
|
|
1676
|
+
* keystroke is the one-glance sign that incremental layout is not engaging.
|
|
1677
|
+
*/
|
|
1678
|
+
interface PaginatedSurfacePerf {
|
|
1679
|
+
/** Time the last layout pass took, in milliseconds. */
|
|
1680
|
+
readonly layoutMs: number;
|
|
1681
|
+
/** Time the last paint took — building and swapping the page DOM. */
|
|
1682
|
+
readonly paintMs: number;
|
|
1683
|
+
/** Time the last selection sync took — writing the model selection into the browser. */
|
|
1684
|
+
readonly selectionMs: number;
|
|
1685
|
+
/** Paragraphs the last pass re-placed, against the number in the document. */
|
|
1686
|
+
readonly placed: number;
|
|
1687
|
+
readonly total: number;
|
|
1688
|
+
/** Pages carried over from the previous layout without being rebuilt. */
|
|
1689
|
+
readonly reusedPages: number;
|
|
1690
|
+
/** Passes that could not resume and laid the document out from the top. */
|
|
1691
|
+
readonly fullPasses: number;
|
|
1692
|
+
/** Layouts discarded because the model had already moved on. */
|
|
1693
|
+
readonly staleDiscards: number;
|
|
1694
|
+
/** Cooperative runs abandoned mid-flight for a newer revision. */
|
|
1695
|
+
readonly cancelledRuns: number;
|
|
1696
|
+
}
|
|
1697
|
+
/** How a reveal places its target in the viewport. */
|
|
1698
|
+
interface RevealOptions {
|
|
1699
|
+
/**
|
|
1700
|
+
* `'start'` puts the target near the top (a heading the user jumped to), `'center'`
|
|
1701
|
+
* centres it, `'nearest'` scrolls only when it is out of view. Default `'start'`.
|
|
1702
|
+
*/
|
|
1703
|
+
readonly block?: 'start' | 'center' | 'nearest';
|
|
1704
|
+
/** Padding above the target, in CSS pixels. Default 24. */
|
|
1705
|
+
readonly offsetPx?: number;
|
|
1706
|
+
readonly behavior?: ScrollBehavior;
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Everything observable about the surface right now, as one immutable value.
|
|
1710
|
+
*
|
|
1711
|
+
* `revision` is the change token: it moves whenever anything else here does, which is what lets
|
|
1712
|
+
* `snapshot()` hand back the same reference until state actually changes.
|
|
1713
|
+
*/
|
|
1714
|
+
interface PaginatedSurfaceState {
|
|
1715
|
+
readonly revision: number;
|
|
1716
|
+
readonly pageCount: number;
|
|
1717
|
+
readonly selection: SemanticSelection;
|
|
1718
|
+
/**
|
|
1719
|
+
* The rectangle of table cells a drag across cells selected, or null.
|
|
1720
|
+
*
|
|
1721
|
+
* `selection` always holds the equivalent TEXT range, so a reader that does not care about
|
|
1722
|
+
* rectangles needs no branch. This is for the ones that do — the highlight, and table
|
|
1723
|
+
* commands that act on cells rather than characters.
|
|
1724
|
+
*/
|
|
1725
|
+
readonly cellSelection: CellSelection | null;
|
|
1726
|
+
readonly canUndo: boolean;
|
|
1727
|
+
readonly canRedo: boolean;
|
|
1728
|
+
readonly lastRejection: string | null;
|
|
1729
|
+
/**
|
|
1730
|
+
* The typing format armed at the caret (Word's stored marks), or null.
|
|
1731
|
+
*
|
|
1732
|
+
* NOT document state — nothing is written until the next characters are typed — but it
|
|
1733
|
+
* IS observable state: `formatting()` reports it, so a host that reflects the toolbar
|
|
1734
|
+
* has to learn when it moves. Reference-stable while unchanged, so a host can compare
|
|
1735
|
+
* it to decide whether to re-derive. See `toggleRunProperty` for the lane itself.
|
|
1736
|
+
*/
|
|
1737
|
+
readonly pendingFormat: readonly {
|
|
1738
|
+
readonly localName: string;
|
|
1739
|
+
}[] | null;
|
|
1740
|
+
/**
|
|
1741
|
+
* Content-control chrome and form-fill mode.
|
|
1742
|
+
*
|
|
1743
|
+
* Surface-owned (not document bytes). Updates report through the same `onChange` path as
|
|
1744
|
+
* selection moves — hosts must not maintain a parallel channel.
|
|
1745
|
+
*/
|
|
1746
|
+
readonly contentControls: ContentControlSurfaceState;
|
|
1747
|
+
/**
|
|
1748
|
+
* The TOC the last right-click landed on, or null.
|
|
1749
|
+
*
|
|
1750
|
+
* A right-click deliberately does not move the caret, and a TOC refuses the caret
|
|
1751
|
+
* entirely, so `selection` can never say which table of contents the user is pointing at.
|
|
1752
|
+
* This is how a host's context menu learns it. Surface chrome, not document state.
|
|
1753
|
+
*/
|
|
1754
|
+
readonly contextTocId: string | null;
|
|
1755
|
+
/** Timing and reuse counters for the last pass. Diagnostics, not document state. */
|
|
1756
|
+
readonly perf: PaginatedSurfacePerf;
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Observable content-control interaction state on the paginated surface.
|
|
1760
|
+
*
|
|
1761
|
+
* Boundary furniture visibility and form-fill navigation are surface chrome, not model
|
|
1762
|
+
* bytes — toggling them never reflows layout records.
|
|
1763
|
+
*/
|
|
1764
|
+
interface ContentControlSurfaceState {
|
|
1765
|
+
/** Show boundary chrome for every control. */
|
|
1766
|
+
readonly showAll: boolean;
|
|
1767
|
+
/** Tab / Shift+Tab navigate between editable controls. */
|
|
1768
|
+
readonly formFill: boolean;
|
|
1769
|
+
/** Innermost control containing the caret, or null. */
|
|
1770
|
+
readonly activeControlId: string | null;
|
|
1771
|
+
}
|
|
1772
|
+
/**
|
|
1773
|
+
* The mounted, painted, editable document — the layer `createDocxEditor` builds its contract on.
|
|
1774
|
+
*
|
|
1775
|
+
* The painted pages ARE the editable surface: they are `contenteditable`, but the DOM is a
|
|
1776
|
+
* picture. Browser mutations are prevented and re-expressed as tree ops, and selection maps only
|
|
1777
|
+
* through `data-paragraph-id`/`data-start`, never through DOM node identity.
|
|
1778
|
+
*
|
|
1779
|
+
* Every write goes through the guarded mutation path on this object. Reaching past it into
|
|
1780
|
+
* `session` to apply ops directly bypasses the layout invalidation and the caret bookkeeping.
|
|
1781
|
+
*/
|
|
1782
|
+
interface PaginatedSurface {
|
|
1783
|
+
readonly session: TreeDocxSession;
|
|
1784
|
+
storyScope(): StoryScope;
|
|
1785
|
+
imageDecodePort(): ImageDecodePort;
|
|
1786
|
+
applyDrawingOps(ops: readonly DrawingTreeDocOp[]): ReturnType<TreeDocxSession['applyTreeOps']>;
|
|
1787
|
+
applyImageProperties(input: ApplyImagePropertiesInput): ImageIntentResult;
|
|
1788
|
+
deleteImage(drawingNodeId: string): ImageIntentResult;
|
|
1789
|
+
insertImage(input: Omit<InsertImageInput, 'decodePort'>): Promise<ImageIntentResult>;
|
|
1790
|
+
replaceImage(drawingNodeId: string, bytes: Uint8Array, mime: SupportedImageMime, options: {
|
|
1791
|
+
readonly expectedPackageRevision: number;
|
|
1792
|
+
readonly commitGuard?: () => boolean;
|
|
1793
|
+
}): Promise<ImageIntentResult>;
|
|
1794
|
+
layout(): SemanticLayout;
|
|
1795
|
+
state(): PaginatedSurfaceState;
|
|
1796
|
+
/** One-based page at the caret, or at the centre of the mounted viewport. */
|
|
1797
|
+
currentPage(mode?: 'viewport' | 'caret'): number;
|
|
1798
|
+
type(text: string): void;
|
|
1799
|
+
/**
|
|
1800
|
+
* Insert text whose newlines are PARAGRAPH BOUNDARIES, in one commit.
|
|
1801
|
+
*
|
|
1802
|
+
* `type` writes its argument into run text verbatim, so a newline reaching it is a
|
|
1803
|
+
* control character the store refuses — which vetoes the whole transaction and makes
|
|
1804
|
+
* the insert do nothing at all. This is the lane for text that arrives from outside the
|
|
1805
|
+
* editor (a paste, a drop), where line breaks are structure rather than characters.
|
|
1806
|
+
*
|
|
1807
|
+
* Plain text only, by construction: no markup is parsed and no DOM is built from the
|
|
1808
|
+
* payload, whatever its origin.
|
|
1809
|
+
*/
|
|
1810
|
+
insertPlainText(text: string): void;
|
|
1811
|
+
deleteBackward(): void;
|
|
1812
|
+
/** Delete forward — the Delete key, and `deleteContentForward` from an IME. */
|
|
1813
|
+
deleteForward(): void;
|
|
1814
|
+
/** Delete to the previous word boundary — Alt/Ctrl+Backspace. */
|
|
1815
|
+
deleteWordBackward(): void;
|
|
1816
|
+
/** Delete to the next word boundary — Alt/Ctrl+Delete. */
|
|
1817
|
+
deleteWordForward(): void;
|
|
1818
|
+
splitParagraph(): void;
|
|
1819
|
+
/** A tab character as a `w:tab` element, not a literal tab in the run text. */
|
|
1820
|
+
insertTab(): void;
|
|
1821
|
+
/** A `w:br` — Shift+Enter, a line break inside the same paragraph. */
|
|
1822
|
+
insertLineBreak(): void;
|
|
1823
|
+
/** A `w:br w:type="page"` — Ctrl+Enter, a hard page break inside the paragraph. */
|
|
1824
|
+
insertPageBreak(): void;
|
|
1825
|
+
/**
|
|
1826
|
+
* Word's Increase/Decrease Indent, over every paragraph the selection touches.
|
|
1827
|
+
*
|
|
1828
|
+
* A NUMBERED or BULLETED paragraph changes LEVEL: `w:numPr/w:ilvl` moves by one, which
|
|
1829
|
+
* re-resolves its marker from `numbering.xml` — so a bullet becomes a hollow circle, a
|
|
1830
|
+
* `1.` becomes an `a.`, exactly as Word demotes a list item. A level the definition
|
|
1831
|
+
* does not declare is DECLARED on the way, with Word's default format for that depth
|
|
1832
|
+
* (its stock bullets and number formats cycle every three levels) — a definition that
|
|
1833
|
+
* stops at `ilvl 0` never blocks the press. Everything else moves its `w:ind/@left` by
|
|
1834
|
+
* one default tab stop, never past the margin.
|
|
1835
|
+
*
|
|
1836
|
+
* Answers whether anything changed, so a caller can fall back (Tab inserting a tab
|
|
1837
|
+
* where there is no list to demote).
|
|
1838
|
+
*/
|
|
1839
|
+
adjustIndent(direction: 'increase' | 'decrease'): boolean;
|
|
1840
|
+
/**
|
|
1841
|
+
* Set indent to exact values on every paragraph the selection touches — what a ruler
|
|
1842
|
+
* drag and an indent spinner both need, where {@link adjustIndent} only steps.
|
|
1843
|
+
*
|
|
1844
|
+
* Twips. Omitting a field leaves it as authored; `null` CLEARS it, so the paragraph
|
|
1845
|
+
* falls back to its style — distinct from zero, which blocks the cascade.
|
|
1846
|
+
*
|
|
1847
|
+
* `firstLine` is ONE SIGNED offset, negative for a hanging indent; the two OOXML
|
|
1848
|
+
* spellings are written for it, the unused one as an explicit zero. Answers whether
|
|
1849
|
+
* anything was committed.
|
|
1850
|
+
*/
|
|
1851
|
+
setIndent(update: {
|
|
1852
|
+
readonly left?: number | null;
|
|
1853
|
+
readonly right?: number | null;
|
|
1854
|
+
readonly firstLine?: number | null;
|
|
1855
|
+
}): boolean;
|
|
1856
|
+
/**
|
|
1857
|
+
* Whether Increase/Decrease Indent would do anything right now.
|
|
1858
|
+
*
|
|
1859
|
+
* A list item at level 0 cannot outdent and one at level 8 cannot indent — `w:ilvl`
|
|
1860
|
+
* has nine levels and Word greys the control out at the ends. A missing level
|
|
1861
|
+
* DEFINITION never disables it: `adjustIndent` declares the level as it goes. The one
|
|
1862
|
+
* residue: a `w:numStyleLink` definition missing the level refuses the declaration
|
|
1863
|
+
* (its levels belong to the linked style), so there the press is a safe no-op rather
|
|
1864
|
+
* than a greyed control.
|
|
1865
|
+
*/
|
|
1866
|
+
canAdjustIndent(direction: 'increase' | 'decrease'): boolean;
|
|
1867
|
+
/**
|
|
1868
|
+
* Enter on an empty list item: outdent a level, or leave the list at level 0.
|
|
1869
|
+
*
|
|
1870
|
+
* Answers false when the caret is not on an empty list item, so the caller falls
|
|
1871
|
+
* through to an ordinary paragraph split.
|
|
1872
|
+
*/
|
|
1873
|
+
exitListOnEmptyItem(): boolean;
|
|
1874
|
+
/** Whether the paragraph at the caret is a list item, for Tab's Word-like fallback. */
|
|
1875
|
+
isListParagraph(): boolean;
|
|
1876
|
+
/**
|
|
1877
|
+
* Word's Bullets and Numbering buttons.
|
|
1878
|
+
*
|
|
1879
|
+
* Turns every paragraph the selection touches into a list of `kind`, or takes them all
|
|
1880
|
+
* out when they are already one. The definition is created in `numbering.xml` on first
|
|
1881
|
+
* use — a document that has never carried a list has no numbering part at all.
|
|
1882
|
+
*/
|
|
1883
|
+
toggleList(kind: 'bullet' | 'ordered'): boolean;
|
|
1884
|
+
/** Whether every paragraph the selection touches is already a list of `kind`. */
|
|
1885
|
+
isListActive(kind: 'bullet' | 'ordered'): boolean;
|
|
1886
|
+
/** Select the whole document. */
|
|
1887
|
+
selectAll(): void;
|
|
1888
|
+
/**
|
|
1889
|
+
* Turn the browser's editing affordance on the pages layer on or off.
|
|
1890
|
+
*
|
|
1891
|
+
* The facade's `mode` gates COMMANDS, which stops `exec` but not the keyboard: the pages
|
|
1892
|
+
* layer is `contentEditable` and binds `beforeinput` itself, so a document the facade
|
|
1893
|
+
* called read-only still accepted typing straight into it. Read-only has to reach the
|
|
1894
|
+
* surface to be true.
|
|
1895
|
+
*/
|
|
1896
|
+
setEditable(editable: boolean): void;
|
|
1897
|
+
/**
|
|
1898
|
+
* Scroll a page, or the page a paragraph sits on, into view. Returns whether it
|
|
1899
|
+
* scrolled — false when the target is not laid out, or the surface is not inside a
|
|
1900
|
+
* scroll container, so a caller can tell "no such target" from "done".
|
|
1901
|
+
*
|
|
1902
|
+
* The geometry comes from the LAYOUT, never from the DOM: a page that has not been
|
|
1903
|
+
* materialized yet has no element to measure, and that is exactly the page a reveal is
|
|
1904
|
+
* usually asked for. `revealParagraph` scrolls to the paragraph's own line rather than
|
|
1905
|
+
* the top of its page, so a heading deep in a page lands in view.
|
|
1906
|
+
*/
|
|
1907
|
+
revealPage(pageIndex: number, options?: RevealOptions): boolean;
|
|
1908
|
+
revealParagraph(paragraphId: string, options?: RevealOptions): boolean;
|
|
1909
|
+
/**
|
|
1910
|
+
* Scroll an exact position into view — `revealParagraph` for a caret that is not at
|
|
1911
|
+
* offset 0. Focus-independent and virtualization-safe like every reveal: geometry
|
|
1912
|
+
* comes from the layout and the target page is materialized on the way. Defaults to
|
|
1913
|
+
* `block: 'nearest'`, so an already-visible target never yanks the viewport.
|
|
1914
|
+
*/
|
|
1915
|
+
revealPosition(position: SemanticPosition, options?: RevealOptions): boolean;
|
|
1916
|
+
/** Set the selection directly, for a host driving the surface programmatically. */
|
|
1917
|
+
setSelection(next: SemanticSelection): void;
|
|
1918
|
+
/**
|
|
1919
|
+
* Select a rectangle of table cells, or clear one with null.
|
|
1920
|
+
*
|
|
1921
|
+
* The equivalent text range is installed alongside it, so `state().selection` stays valid
|
|
1922
|
+
* for every reader that does not know rectangles exist.
|
|
1923
|
+
*/
|
|
1924
|
+
setCellSelection(next: CellSelection | null): void;
|
|
1925
|
+
/**
|
|
1926
|
+
* Toggle a run property over the selection, e.g. `b`, `i`, `u`.
|
|
1927
|
+
*
|
|
1928
|
+
* AT A COLLAPSED CARET this ARMS the property instead of writing it — Word's stored
|
|
1929
|
+
* marks. Nothing reaches the document until the next characters are typed there, and
|
|
1930
|
+
* those take the armed format; the armed state shows in `formatting()` and in
|
|
1931
|
+
* `state().pendingFormat` immediately, so a toolbar reflects the press. It survives the
|
|
1932
|
+
* caret-preserving edits (Backspace, Delete, Enter) and IME composition, and is
|
|
1933
|
+
* discarded when the caret moves elsewhere or the document is undone. A property the
|
|
1934
|
+
* store cannot author is refused at arm time rather than left to poison the keystroke.
|
|
1935
|
+
*/
|
|
1936
|
+
toggleRunProperty(localName: string, attributes?: Record<string, string>): void;
|
|
1937
|
+
/**
|
|
1938
|
+
* SET a run property over the selection, rather than toggling it.
|
|
1939
|
+
*
|
|
1940
|
+
* Font family, size and colour are values, not switches: picking Arial twice must leave
|
|
1941
|
+
* the text in Arial, which a toggle would not. Arms at a collapsed caret on the same
|
|
1942
|
+
* terms as `toggleRunProperty`.
|
|
1943
|
+
*/
|
|
1944
|
+
setRunProperty(localName: string, attributes?: Record<string, string>): void;
|
|
1945
|
+
/**
|
|
1946
|
+
* Set a property on every paragraph the selection touches — alignment, style, spacing.
|
|
1947
|
+
*
|
|
1948
|
+
* `mergeAttributes` keeps the attributes the call does not name, for the properties that
|
|
1949
|
+
* carry several independent settings in one element: `w:spacing` holds the line rule and
|
|
1950
|
+
* the space before and after, so a line-spacing pick must not delete the space-before. A
|
|
1951
|
+
* null-valued attribute removes just that one.
|
|
1952
|
+
*/
|
|
1953
|
+
setParagraphProperty(localName: string, attributes?: Record<string, string | null>, options?: {
|
|
1954
|
+
readonly mergeAttributes?: boolean;
|
|
1955
|
+
}): void;
|
|
1956
|
+
/**
|
|
1957
|
+
* Word's Clear All Formatting: direct run properties off the selected text, and every
|
|
1958
|
+
* paragraph the selection touches back to the default style with its direct paragraph
|
|
1959
|
+
* properties and mark dropped.
|
|
1960
|
+
*
|
|
1961
|
+
* Only what the document states DIRECTLY — formatting inherited from a style survives, so
|
|
1962
|
+
* the text falls back to its style rather than to nothing. Properties an op cannot name
|
|
1963
|
+
* (`w:rStyle`, `w:lang`, `w:sectPr`, `w:pBdr`) are preserved for the same reason every
|
|
1964
|
+
* other write preserves them.
|
|
1965
|
+
*/
|
|
1966
|
+
clearFormatting(): void;
|
|
1967
|
+
/**
|
|
1968
|
+
* Formatting as it stands at the selection, for a toolbar to reflect.
|
|
1969
|
+
*
|
|
1970
|
+
* With a typing format armed at the caret this reports what the NEXT characters typed
|
|
1971
|
+
* will look like, not what the document holds — which is the answer a toolbar wants and
|
|
1972
|
+
* the one Word gives.
|
|
1973
|
+
*/
|
|
1974
|
+
formatting(): SurfaceFormatting;
|
|
1975
|
+
/**
|
|
1976
|
+
* The section the document declares: page size, margins, columns, orientation.
|
|
1977
|
+
*
|
|
1978
|
+
* What a ruler is made of, and what pagination is measured against.
|
|
1979
|
+
*/
|
|
1980
|
+
sectionProperties(): SectionProperties;
|
|
1981
|
+
/**
|
|
1982
|
+
* The section GOVERNING one paragraph — what a ruler or dialog reflects when the
|
|
1983
|
+
* caret sits in a multi-section document. Falls back to the body-level section for
|
|
1984
|
+
* an unknown id.
|
|
1985
|
+
*/
|
|
1986
|
+
sectionPropertiesAt(paragraphId: string): SectionProperties;
|
|
1987
|
+
/**
|
|
1988
|
+
* Write section page-setup fields — size, orientation, margins — as ONE undoable
|
|
1989
|
+
* transaction. Twips throughout; omitted fields are left as authored. With
|
|
1990
|
+
* `anchorParagraphId` only that paragraph's governing section is written (Word's
|
|
1991
|
+
* "Apply to: This section"); without it, every section. Returns whether the write
|
|
1992
|
+
* committed (a hostile value is refused by the op layer).
|
|
1993
|
+
*/
|
|
1994
|
+
setSectionProperties(update: {
|
|
1995
|
+
readonly pageWidthTwips?: number;
|
|
1996
|
+
readonly pageHeightTwips?: number;
|
|
1997
|
+
readonly orientation?: 'portrait' | 'landscape';
|
|
1998
|
+
readonly marginTopTwips?: number;
|
|
1999
|
+
readonly marginRightTwips?: number;
|
|
2000
|
+
readonly marginBottomTwips?: number;
|
|
2001
|
+
readonly marginLeftTwips?: number;
|
|
2002
|
+
readonly anchorParagraphId?: string;
|
|
2003
|
+
}): boolean;
|
|
2004
|
+
/**
|
|
2005
|
+
* Insert a next-page section break at the caret: the paragraph splits, and the head
|
|
2006
|
+
* ends a new section cloning the governing section's page setup — Word's Layout >
|
|
2007
|
+
* Breaks > Next Page. One undoable step. Returns whether the break committed.
|
|
2008
|
+
*/
|
|
2009
|
+
insertSectionBreak(): boolean;
|
|
2010
|
+
/** The layout session, so a host or a test can see how much work a pass actually did. */
|
|
2011
|
+
layoutSession(): {
|
|
2012
|
+
readonly stats: {
|
|
2013
|
+
readonly placed: number;
|
|
2014
|
+
readonly total: number;
|
|
2015
|
+
readonly reusedPages: number;
|
|
2016
|
+
};
|
|
2017
|
+
};
|
|
2018
|
+
/**
|
|
2019
|
+
* The hyperlink lane: what link the caret is in, and the insert / retarget / unlink verbs.
|
|
2020
|
+
*
|
|
2021
|
+
* Every verb is one `transact`, so it is one undo step. Targets going IN are host-supplied
|
|
2022
|
+
* and pass the package's own URL allowlist; targets coming OUT are the sanitized
|
|
2023
|
+
* projection, so a caller cannot accidentally hand a refused scheme to a sink.
|
|
2024
|
+
*/
|
|
2025
|
+
readonly hyperlinks: HyperlinkOps;
|
|
2026
|
+
/**
|
|
2027
|
+
* Content-control chrome, form-fill navigation, and value / remove verbs.
|
|
2028
|
+
*
|
|
2029
|
+
* Value and remove commit through `session.applyTreeOps` — the same write path as typing.
|
|
2030
|
+
* Show-all and form-fill are surface chrome and never reflow layout.
|
|
2031
|
+
*/
|
|
2032
|
+
readonly contentControls: ContentControlOps;
|
|
2033
|
+
/** Whether a `rows`×`cols` table can be inserted at the caret. */
|
|
2034
|
+
canInsertTable(rows: number, cols: number): boolean;
|
|
2035
|
+
/**
|
|
2036
|
+
* Insert an empty `rows`×`cols` table at the caret, columns evenly dividing the content
|
|
2037
|
+
* width of the caret's section, and leave the caret in the first cell.
|
|
2038
|
+
*/
|
|
2039
|
+
insertTable(rows: number, cols: number): boolean;
|
|
2040
|
+
/** Whether the addressed (or caret-local) body TOC can be refreshed. */
|
|
2041
|
+
canRefreshToc(tocId?: string): boolean;
|
|
2042
|
+
/** Whether a generated body TOC can be inserted before the caret paragraph. */
|
|
2043
|
+
canInsertToc(): boolean;
|
|
2044
|
+
/** Insert and populate a generated body TOC before the caret paragraph. */
|
|
2045
|
+
insertToc(): boolean;
|
|
2046
|
+
/** Refresh cached TOC entries and/or page numbers through the two-pass layout pipeline. */
|
|
2047
|
+
refreshToc(tocId?: string, mode?: 'entire' | 'pageNumbers'): boolean;
|
|
2048
|
+
/** Whether a body paragraph belongs to a detected TOC boundary or cached result. */
|
|
2049
|
+
isInsideToc(paragraphId: string): boolean;
|
|
2050
|
+
/**
|
|
2051
|
+
* Bookmark jumps and the ONE external-activation gate. A host's popover "open" action
|
|
2052
|
+
* calls `openExternal`; nothing else in the engine may call `window.open`.
|
|
2053
|
+
*/
|
|
2054
|
+
readonly navigation: SurfaceNavigation;
|
|
2055
|
+
/**
|
|
2056
|
+
* Pin the current selection so it stays VISIBLY selected while focus is elsewhere.
|
|
2057
|
+
*
|
|
2058
|
+
* A document has one selection: the moment a panel focuses an input of its own the browser
|
|
2059
|
+
* takes the highlight off the text, which is when the user most needs to see what the panel
|
|
2060
|
+
* is about to act on. This draws the range on the engine's own overlay instead, so it
|
|
2061
|
+
* survives the focus move. The MODEL selection is untouched — the op the panel finally runs
|
|
2062
|
+
* addresses the same characters it always would.
|
|
2063
|
+
*
|
|
2064
|
+
* The pin releases itself when the caret leaves the range (either edge counts as inside),
|
|
2065
|
+
* which is what lets a host close its panel on "the user clicked somewhere else" without
|
|
2066
|
+
* every adapter reimplementing that comparison.
|
|
2067
|
+
*/
|
|
2068
|
+
retainSelection(): void;
|
|
2069
|
+
/** Drop the pin and stop drawing it, whether or not the caret ever left. */
|
|
2070
|
+
releaseSelection(): void;
|
|
2071
|
+
/** The pinned range, or null once it was released or escaped. */
|
|
2072
|
+
retainedSelection(): SemanticSelection | null;
|
|
2073
|
+
/**
|
|
2074
|
+
* How edits are written right now.
|
|
2075
|
+
*
|
|
2076
|
+
* Lives on the SURFACE, not on the store. The store's write vocabulary stays explicit —
|
|
2077
|
+
* an op says whether it is tracked — and the surface is the one thing that knows a
|
|
2078
|
+
* keystroke happened, so it is the right place to decide what that keystroke becomes.
|
|
2079
|
+
*/
|
|
2080
|
+
editingMode(): SurfaceEditingMode;
|
|
2081
|
+
setEditingMode(mode: SurfaceEditingMode): void;
|
|
2082
|
+
/**
|
|
2083
|
+
* Commit ops that came from automation, through the gate a keystroke goes through.
|
|
2084
|
+
*
|
|
2085
|
+
* The narrow entry an automation host writes with, and the reason it needs one: reaching
|
|
2086
|
+
* `session.applyTreeOps` past this skips the editing-mode gate entirely — a document open for
|
|
2087
|
+
* viewing accepts a scripted edit, and a suggesting document records one as a permanent
|
|
2088
|
+
* change with no proposal and no author. Here, viewing refuses, suggesting attributes, the
|
|
2089
|
+
* refusal reason is reported like any other, and the pages repaint from the commit.
|
|
2090
|
+
*
|
|
2091
|
+
* The ops address the story the CALLER named, whatever story the reader is in: the caller
|
|
2092
|
+
* identified its target before calling, so following the caret into a header would write
|
|
2093
|
+
* somewhere else entirely. They default to the body rather than to the reader's story.
|
|
2094
|
+
*
|
|
2095
|
+
* They arrive as a BUILDER, given a way to mint the relationship an external hyperlink names.
|
|
2096
|
+
* That mint changes the package outside the transaction and outside the undo stack, so it must not
|
|
2097
|
+
* happen until the mode has allowed the write — a link minted while the batch was still being
|
|
2098
|
+
* planned left its target in a read-only document's `.rels`. A builder answering null means the
|
|
2099
|
+
* target is one this engine will not author, and the write is refused having changed nothing.
|
|
2100
|
+
*/
|
|
2101
|
+
applyAutomationOps(staged: (relate: (url: string) => string | null) => readonly TreeDocOp[] | null, scope?: StoryScope): TreeApplyResult;
|
|
2102
|
+
/**
|
|
2103
|
+
* Commit review ops — accept, reject, a new comment — through the SAME path a keystroke
|
|
2104
|
+
* takes: layout, paint, and a caret clamped to what the document now holds.
|
|
2105
|
+
*
|
|
2106
|
+
* Applying them straight to the session skipped all three. Rejecting an insertion left the
|
|
2107
|
+
* pages painting text the tree no longer had, every card anchored where it used to be, and
|
|
2108
|
+
* the caret past the end of the paragraph — after which every keystroke was refused with
|
|
2109
|
+
* `offset-out-of-range` until the user happened to click somewhere else.
|
|
2110
|
+
*/
|
|
2111
|
+
commitReviewOps(run: () => {
|
|
2112
|
+
readonly committed: boolean;
|
|
2113
|
+
readonly reason?: unknown;
|
|
2114
|
+
}): void;
|
|
2115
|
+
/**
|
|
2116
|
+
* The layout as last PUBLISHED, without forcing pending work.
|
|
2117
|
+
*
|
|
2118
|
+
* `layout()` flushes first, which is right for a caller that is about to act on geometry
|
|
2119
|
+
* and wrong for one that merely decorates it. The review rail read through `layout()` and
|
|
2120
|
+
* so forced a synchronous full pass on every keystroke — eleven seconds per read on a
|
|
2121
|
+
* 2432-block document. A card whose anchor is one frame stale is invisible; the paint that
|
|
2122
|
+
* follows the flush republishes it.
|
|
2123
|
+
*/
|
|
2124
|
+
publishedLayout(): SemanticLayout;
|
|
2125
|
+
/**
|
|
2126
|
+
* Paint-scale coordinate context for overlay chrome.
|
|
2127
|
+
*
|
|
2128
|
+
* Internal seam — not part of the public editor contract. Image overlay uses the same
|
|
2129
|
+
* `zoom * 96/72` scale and per-page horizontal offsets the painter applied.
|
|
2130
|
+
*/
|
|
2131
|
+
overlayCoordinates(): SurfaceOverlayCoordinates;
|
|
2132
|
+
/**
|
|
2133
|
+
* The comment or tracked change the caret is in, as the painted bands report it.
|
|
2134
|
+
*
|
|
2135
|
+
* ONE source for "which item is open". The band under the text and the card beside it are
|
|
2136
|
+
* two views of the same answer, and deriving it twice let them disagree — the card closed
|
|
2137
|
+
* while the text stayed highlighted.
|
|
2138
|
+
*/
|
|
2139
|
+
activeReviewKey(): string | null;
|
|
2140
|
+
/**
|
|
2141
|
+
* Close the open item until the caret next moves.
|
|
2142
|
+
*
|
|
2143
|
+
* What a click on the canvas means. The caret does not move when someone clicks the grey
|
|
2144
|
+
* around the page, so nothing else would ever put the item away.
|
|
2145
|
+
*/
|
|
2146
|
+
dismissActiveReview(): void;
|
|
2147
|
+
/**
|
|
2148
|
+
* Revision kinds the CARET must not activate, or null for none.
|
|
2149
|
+
*
|
|
2150
|
+
* The review rail filters what it renders (structural and format cards are hidden by
|
|
2151
|
+
* default), but {@link activeReviewKey} used to compute over the unfiltered queue — a
|
|
2152
|
+
* click on tracked text under a format change activated a card the rail does not draw,
|
|
2153
|
+
* and nothing on screen lit up. A host that filters its list tells the surface, so the
|
|
2154
|
+
* band and the visible cards stay one answer.
|
|
2155
|
+
*/
|
|
2156
|
+
setReviewActivationExclusions(kinds: readonly ReviewRevisionKind[] | null): void;
|
|
2157
|
+
/**
|
|
2158
|
+
* `bookmarkName -> position` over the current revision, for resolving an internal link.
|
|
2159
|
+
* First in document order wins a duplicate name, matching Word.
|
|
2160
|
+
*/
|
|
2161
|
+
bookmarks(): BookmarkIndex;
|
|
2162
|
+
/** The selected text, for copy and cut. */
|
|
2163
|
+
selectedText(): string;
|
|
2164
|
+
/** Remove the selection, if any. Returns whether anything was deleted. */
|
|
2165
|
+
deleteSelection(): boolean;
|
|
2166
|
+
navigate(command: NavigationCommand, extend?: boolean): void;
|
|
2167
|
+
/** Reverse the last history entry and put the caret back where it was made. */
|
|
2168
|
+
undo(): void;
|
|
2169
|
+
redo(): void;
|
|
2170
|
+
/**
|
|
2171
|
+
* Refresh table insertion furniture labels without remounting or relayout.
|
|
2172
|
+
*
|
|
2173
|
+
* @public
|
|
2174
|
+
*/
|
|
2175
|
+
refreshTableInteractionLabels(): void;
|
|
2176
|
+
focus(): void;
|
|
2177
|
+
/**
|
|
2178
|
+
* Refresh table insertion furniture labels without remounting the surface.
|
|
2179
|
+
*
|
|
2180
|
+
* @public
|
|
2181
|
+
*/
|
|
2182
|
+
setTableInteractionLabel(resolver: (key: 'table.insertRowBelow' | 'table.insertColumnRight') => string): void;
|
|
2183
|
+
destroy(): void;
|
|
2184
|
+
/** Active editing view — body, or an open header/footer story by rId. */
|
|
2185
|
+
activeScope(): ViewScope;
|
|
2186
|
+
/** Activate a view scope. Returns false when a header/footer rId cannot be opened. */
|
|
2187
|
+
setActiveScope(scope: ViewScope): boolean;
|
|
2188
|
+
/**
|
|
2189
|
+
* Open a header/footer story for editing on the painted surface.
|
|
2190
|
+
* Refuses dangling / unknown relationship ids.
|
|
2191
|
+
*/
|
|
2192
|
+
enterHeaderFooter(args: {
|
|
2193
|
+
readonly rId: string;
|
|
2194
|
+
readonly pageIndex?: number;
|
|
2195
|
+
readonly sectionIndex?: number;
|
|
2196
|
+
readonly kind?: 'header' | 'footer';
|
|
2197
|
+
readonly variant?: 'default' | 'first' | 'even';
|
|
2198
|
+
readonly position?: SemanticPosition;
|
|
2199
|
+
}): boolean;
|
|
2200
|
+
/** Leave furniture editing and restore the prior body selection. */
|
|
2201
|
+
exitHeaderFooter(): void;
|
|
2202
|
+
/** Chrome read-model for the open furniture scope, or null when editing the body. */
|
|
2203
|
+
headerFooterState(): {
|
|
2204
|
+
readonly editing: 'header' | 'footer' | null;
|
|
2205
|
+
readonly sectionIndex: number;
|
|
2206
|
+
readonly variant?: 'default' | 'first' | 'even';
|
|
2207
|
+
readonly rId?: string;
|
|
2208
|
+
readonly partName?: string;
|
|
2209
|
+
readonly inherited?: boolean;
|
|
2210
|
+
readonly titlePage?: boolean;
|
|
2211
|
+
readonly evenAndOddHeaders?: boolean;
|
|
2212
|
+
readonly headerDistanceTwips?: number;
|
|
2213
|
+
readonly footerDistanceTwips?: number;
|
|
2214
|
+
} | null;
|
|
2215
|
+
/**
|
|
2216
|
+
* Commit one package-level furniture lifecycle op (create/delete/link/unlink/options).
|
|
2217
|
+
* Flushes layout so the next enter/rebind sees the new resolution.
|
|
2218
|
+
*/
|
|
2219
|
+
applyHeaderFooterLifecycle(op: {
|
|
2220
|
+
readonly op: 'createHeaderFooter' | 'deleteHeaderFooter' | 'linkToPrevious' | 'unlinkFromPrevious' | 'setSectionFurnitureOptions';
|
|
2221
|
+
readonly sectionIndex?: number;
|
|
2222
|
+
readonly kind?: 'header' | 'footer';
|
|
2223
|
+
readonly variant?: 'default' | 'first' | 'even';
|
|
2224
|
+
readonly titlePage?: boolean;
|
|
2225
|
+
readonly evenAndOddHeaders?: boolean;
|
|
2226
|
+
readonly headerDistanceTwips?: number;
|
|
2227
|
+
readonly footerDistanceTwips?: number;
|
|
2228
|
+
}): {
|
|
2229
|
+
readonly ok: true;
|
|
2230
|
+
} | {
|
|
2231
|
+
readonly ok: false;
|
|
2232
|
+
readonly reason: string;
|
|
2233
|
+
};
|
|
2234
|
+
/** Insert an allowlisted page field at the caret in the open HF story. */
|
|
2235
|
+
insertPageField(field: 'PAGE' | 'NUMPAGES' | 'SECTIONPAGES' | 'PAGE_X_OF_Y'): boolean;
|
|
2236
|
+
/** Insert a footnote/endnote at the body caret. */
|
|
2237
|
+
insertNote(noteKind: 'footnote' | 'endnote'): boolean;
|
|
2238
|
+
deleteNote(noteKind: 'footnote' | 'endnote', noteId: number): boolean;
|
|
2239
|
+
convertNote(fromKind: 'footnote' | 'endnote', noteId: number): boolean;
|
|
2240
|
+
convertAllNotes(fromKind: 'footnote' | 'endnote'): boolean;
|
|
2241
|
+
setNoteProperties(args: {
|
|
2242
|
+
readonly scope: 'document' | 'section';
|
|
2243
|
+
readonly sectionIndex?: number;
|
|
2244
|
+
readonly footnote?: {
|
|
2245
|
+
readonly numFmt?: string;
|
|
2246
|
+
readonly numRestart?: string;
|
|
2247
|
+
readonly position?: string;
|
|
2248
|
+
readonly numStart?: number;
|
|
2249
|
+
};
|
|
2250
|
+
readonly endnote?: {
|
|
2251
|
+
readonly numFmt?: string;
|
|
2252
|
+
readonly numRestart?: string;
|
|
2253
|
+
readonly position?: string;
|
|
2254
|
+
readonly numStart?: number;
|
|
2255
|
+
};
|
|
2256
|
+
}): boolean;
|
|
2257
|
+
enterNote(scopeId: string, position?: {
|
|
2258
|
+
paragraphId: string;
|
|
2259
|
+
offset: number;
|
|
2260
|
+
}): boolean;
|
|
2261
|
+
exitNote(): void;
|
|
2262
|
+
/** Resolved/authored note properties for the caret section — chrome read-model. */
|
|
2263
|
+
notePropertiesState(): NotePropertiesStateSnapshot | null;
|
|
2264
|
+
/** Plain-text preview for hover chrome — never returns markup. */
|
|
2265
|
+
notePreviewText(scopeId: string): string | null;
|
|
2266
|
+
/** Commit one table-command plan as a single store transaction. */
|
|
2267
|
+
applyTableCommandPlan(plan: TableCommandPlan): ExecResult;
|
|
2268
|
+
}
|
|
2269
|
+
/**
|
|
2270
|
+
* What opening a document produced: a mounted surface, or a refusal.
|
|
2271
|
+
*
|
|
2272
|
+
* A result rather than a throw, because every refusal here comes from FILE input — a package the
|
|
2273
|
+
* bounded reader rejected, a part that exceeded a limit — and a malformed upload should surface
|
|
2274
|
+
* as a message the host can show rather than an exception it has to catch.
|
|
2275
|
+
*/
|
|
2276
|
+
type OpenPaginatedResult = {
|
|
2277
|
+
readonly ok: true;
|
|
2278
|
+
readonly surface: PaginatedSurface;
|
|
2279
|
+
} | {
|
|
2280
|
+
readonly ok: false;
|
|
2281
|
+
readonly reason: string;
|
|
2282
|
+
readonly detail?: string;
|
|
2283
|
+
};
|
|
2284
|
+
|
|
2285
|
+
/** Material Symbol name → SVG path data (viewBox "0 -960 960 960"). */
|
|
2286
|
+
declare const GENERATED_ICON_PATHS: Readonly<Record<string, readonly string[]>>;
|
|
2287
|
+
|
|
2288
|
+
/** Border target picker value — concrete scopes plus clear (`none`). */
|
|
2289
|
+
type TableBorderTargetValue = TableBorderEdgeTarget | 'none';
|
|
2290
|
+
/** UI draft: last active edge scope and the complete border spec to reapply. */
|
|
2291
|
+
interface TableChromeDraft {
|
|
2292
|
+
readonly activeTarget: TableBorderEdgeTarget;
|
|
2293
|
+
readonly spec: TableBorderSpec;
|
|
2294
|
+
}
|
|
2295
|
+
/** The draft a table's border chrome starts from: a 1pt black single border on every edge. */
|
|
2296
|
+
declare const DEFAULT_TABLE_CHROME_DRAFT: TableChromeDraft;
|
|
2297
|
+
/**
|
|
2298
|
+
* The chrome slots that only exist while the caret is inside a table.
|
|
2299
|
+
*
|
|
2300
|
+
* A subset of `ChromeSlotId`, so these names are public API on the same terms — renaming one is
|
|
2301
|
+
* a breaking change.
|
|
2302
|
+
*/
|
|
2303
|
+
type TableChromeSlotId = 'table.borderTarget' | 'table.borderColor' | 'table.borderStyle' | 'table.borderWidth' | 'table.cellFill';
|
|
2304
|
+
/** Every {@link TableChromeSlotId}, for iteration and for {@link isTableChromeSlot}. */
|
|
2305
|
+
declare const TABLE_CHROME_SLOT_IDS: readonly TableChromeSlotId[];
|
|
2306
|
+
/** Furniture insertion controls (Task 8) share this label seam. */
|
|
2307
|
+
type TableInteractionLabelKey = 'table.insertRowBelow' | 'table.insertColumnRight';
|
|
2308
|
+
/**
|
|
2309
|
+
* The English label for a furniture-insertion control.
|
|
2310
|
+
*
|
|
2311
|
+
* The FALLBACK, for a host that has not wired its own translator — adapters pass their
|
|
2312
|
+
* `useTranslation` result instead so the control follows the app's locale.
|
|
2313
|
+
*/
|
|
2314
|
+
declare function defaultTableLabel(key: TableInteractionLabelKey): string;
|
|
2315
|
+
/** Whether a chrome slot is one of the table-only ones. Narrows the type. */
|
|
2316
|
+
declare function isTableChromeSlot(slot: ChromeSlotId): slot is TableChromeSlotId;
|
|
2317
|
+
/** Contextual table chrome is visible when the engine reports table context. */
|
|
2318
|
+
declare function tableChromeVisible(table: TableContext | null | undefined): boolean;
|
|
2319
|
+
/** One entry in the border-target picker: which edges it addresses, its icon, and its label key. */
|
|
2320
|
+
interface TableBorderTargetOption {
|
|
2321
|
+
readonly value: TableBorderTargetValue;
|
|
2322
|
+
readonly icon: keyof typeof GENERATED_ICON_PATHS;
|
|
2323
|
+
/** i18n key, never a literal string — both adapters translate it themselves. */
|
|
2324
|
+
readonly labelKey: string;
|
|
2325
|
+
}
|
|
2326
|
+
/** The border-target picker's entries, in Word's own order, ending with clear. */
|
|
2327
|
+
declare const TABLE_BORDER_TARGET_OPTIONS: readonly TableBorderTargetOption[];
|
|
2328
|
+
/** One entry in the border-style picker, with the CSS class that draws its preview line. */
|
|
2329
|
+
interface TableBorderStyleOption {
|
|
2330
|
+
readonly value: TableBorderStyle;
|
|
2331
|
+
readonly labelKey: string;
|
|
2332
|
+
/** Class on the preview swatch. Defined in the core stylesheet, which both adapters import. */
|
|
2333
|
+
readonly previewClass: string;
|
|
2334
|
+
}
|
|
2335
|
+
/** The border-style picker's entries. */
|
|
2336
|
+
declare const TABLE_BORDER_STYLE_OPTIONS: readonly TableBorderStyleOption[];
|
|
2337
|
+
/** One entry in the border-width picker. */
|
|
2338
|
+
interface TableBorderWidthOption {
|
|
2339
|
+
/** `w:sz` — eighths of a point, as OOXML stores border widths. */
|
|
2340
|
+
readonly size: number;
|
|
2341
|
+
readonly labelKey: string;
|
|
2342
|
+
/** Points, for drawing the preview swatch. `size / 8`. */
|
|
2343
|
+
readonly previewThickness: number;
|
|
2344
|
+
}
|
|
2345
|
+
/** Widths in eighths of a point — Word-like presets. */
|
|
2346
|
+
declare const TABLE_BORDER_WIDTH_OPTIONS: readonly TableBorderWidthOption[];
|
|
2347
|
+
/**
|
|
2348
|
+
* What one table-chrome selection produced: the command to run, and the draft to remember.
|
|
2349
|
+
*
|
|
2350
|
+
* Both halves matter. A border picker is stateful — choosing "dashed" and then "outside" must
|
|
2351
|
+
* apply a dashed outside border — so each pick returns the COMPLETE spec to execute alongside the
|
|
2352
|
+
* draft the next pick builds on.
|
|
2353
|
+
*/
|
|
2354
|
+
interface TableChromePick {
|
|
2355
|
+
readonly command: EditorCommand;
|
|
2356
|
+
readonly nextDraft: TableChromeDraft;
|
|
2357
|
+
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Build the engine command for one table chrome pick and the draft state after it.
|
|
2360
|
+
* Target picks apply the current complete spec; `none` clears the active target only.
|
|
2361
|
+
*/
|
|
2362
|
+
declare function applyTableChromePick(draft: TableChromeDraft, slot: TableChromeSlotId, value: unknown): TableChromePick | null;
|
|
2363
|
+
/** Probe command for `Editor.can` — uses the draft's active target and a well-formed value. */
|
|
2364
|
+
declare function probeTableChromeCommand(slot: TableChromeSlotId, draft?: TableChromeDraft): EditorCommand | null;
|
|
2365
|
+
/**
|
|
2366
|
+
* The i18n key naming one border target, for a trigger that shows the active scope.
|
|
2367
|
+
*
|
|
2368
|
+
* Falls back to the "all" key rather than throwing: a label is chrome, and a missing one should
|
|
2369
|
+
* not take the toolbar down.
|
|
2370
|
+
*/
|
|
2371
|
+
declare function tableChromeLabelKeyForTarget(target: TableBorderEdgeTarget): string;
|
|
2372
|
+
/** Material Symbol paths for one table chrome icon name. */
|
|
2373
|
+
declare function tableChromeIconPaths(name: keyof typeof GENERATED_ICON_PATHS): readonly string[];
|
|
2374
|
+
|
|
2375
|
+
/**
|
|
2376
|
+
* The probe a slot uses to ask "would the engine honour this right now?" when its real
|
|
2377
|
+
* command needs an argument the slot itself cannot supply.
|
|
2378
|
+
*
|
|
2379
|
+
* `text.link` is the case: whether this selection could become a link is the engine's
|
|
2380
|
+
* question, but WHICH link is a URL field's. Chrome that owns a link UI (React's
|
|
2381
|
+
* `ToolbarLink`) asks with this and dispatches through that UI.
|
|
2382
|
+
*
|
|
2383
|
+
* DELIBERATELY NOT in `SLOT_COMMANDS`. Enabled state has one source, and putting the probe
|
|
2384
|
+
* there would enable the control in EVERY adapter — including Vue, which has grown no link
|
|
2385
|
+
* UI, where the result is an enabled button whose click can only be refused. A dead button
|
|
2386
|
+
* is the worse lie: `file.save` was a disabled control for a capability that works, and this
|
|
2387
|
+
* would be an enabled control for one that is not reachable. Vue's slot therefore keeps
|
|
2388
|
+
* reporting the honest "not wired to an editor command" until its popover lands.
|
|
2389
|
+
*
|
|
2390
|
+
* @public
|
|
2391
|
+
*/
|
|
2392
|
+
declare function chromeProbeForSlot(slotId: ChromeSlotId): EditorCommand | null;
|
|
2393
|
+
/**
|
|
2394
|
+
* The public editor command behind one chrome slot, or `null` when the slot is
|
|
2395
|
+
* not wired to a command yet (parity-only chrome, or save — which is not a
|
|
2396
|
+
* command). The single source of command truth for both adapters.
|
|
2397
|
+
*
|
|
2398
|
+
* @public
|
|
2399
|
+
*/
|
|
2400
|
+
declare function commandForSlot(slotId: ChromeSlotId): EditorCommand | null;
|
|
2401
|
+
|
|
2402
|
+
/**
|
|
2403
|
+
* Build an engine command for one table chrome slot using the caller's draft state.
|
|
2404
|
+
*
|
|
2405
|
+
* @public
|
|
2406
|
+
*/
|
|
2407
|
+
declare function commandForTableChromeSlotValue(slotId: TableChromeSlotId, value: unknown, draft: TableChromeDraft): EditorCommand | null;
|
|
2408
|
+
/**
|
|
2409
|
+
* The engine command for a VALUE-TYPED slot carrying the picked value, or `null` for a
|
|
2410
|
+
* slot that does not take a value.
|
|
2411
|
+
*
|
|
2412
|
+
* Two families: the run-property pickers (`font.family`, `font.size`, `text.color`,
|
|
2413
|
+
* `text.highlight`) resolve to `setMarkAttr`, and `styles.style` resolves to
|
|
2414
|
+
* `setParagraphStyle` — a paragraph styleId, not a mark. Either way the value is
|
|
2415
|
+
* validated by the engine's own gate (`can` refuses a malformed one with `invalidArgs`;
|
|
2416
|
+
* a styleId the document does not define is refused at `exec`), so a host can pass user
|
|
2417
|
+
* input through unmodified.
|
|
2418
|
+
*
|
|
2419
|
+
* @public
|
|
2420
|
+
*/
|
|
2421
|
+
declare function commandForSlotValue(slotId: ChromeSlotId, value: unknown): EditorCommand | null;
|
|
2422
|
+
/**
|
|
2423
|
+
* Whether one control is enabled, and the engine's reason when it is not.
|
|
2424
|
+
*
|
|
2425
|
+
* @public
|
|
2426
|
+
*/
|
|
2427
|
+
interface ToolbarCommandState {
|
|
2428
|
+
readonly id: ChromeSlotId;
|
|
2429
|
+
readonly enabled: boolean;
|
|
2430
|
+
/** The engine's reason when disabled — surfaced as a tooltip, never invented. */
|
|
2431
|
+
readonly disabledReason: string | null;
|
|
2432
|
+
/**
|
|
2433
|
+
* What the control currently SHOWS, for the slots whose answer is a value rather than a
|
|
2434
|
+
* pressed state — the editing-mode pill, and image wrap when it lands.
|
|
2435
|
+
*
|
|
2436
|
+
* `active` cannot express this: "the mode is Suggesting" is not a boolean about one
|
|
2437
|
+
* command, and a parallel channel for it would be a second place a control could read its
|
|
2438
|
+
* own state from. Absent for every slot whose state really is just pressed-or-not.
|
|
2439
|
+
*/
|
|
2440
|
+
readonly value?: string;
|
|
2441
|
+
/** Whether the command is currently APPLIED at the selection, from `Editor.isActive` —
|
|
2442
|
+
* derived in the engine for marks and alignment, honest-false elsewhere. */
|
|
2443
|
+
readonly active: boolean;
|
|
2444
|
+
}
|
|
2445
|
+
/**
|
|
2446
|
+
* Enabled state for one table chrome slot using explicit draft state.
|
|
2447
|
+
*
|
|
2448
|
+
* @public
|
|
2449
|
+
*/
|
|
2450
|
+
declare function tableChromeToolbarState(editor: Editor | null, slot: TableChromeSlotId, draft?: TableChromeDraft): ToolbarCommandState;
|
|
2451
|
+
/**
|
|
2452
|
+
* Ask the engine whether one control should be enabled.
|
|
2453
|
+
*
|
|
2454
|
+
* @public
|
|
2455
|
+
*/
|
|
2456
|
+
declare function toolbarCommandState(editor: Editor | null, id: ChromeSlotId): ToolbarCommandState;
|
|
2457
|
+
/**
|
|
2458
|
+
* Enabled state for several controls in one pass.
|
|
2459
|
+
*
|
|
2460
|
+
* @public
|
|
2461
|
+
*/
|
|
2462
|
+
declare function toolbarCommandStates(editor: Editor | null, ids: readonly ChromeSlotId[]): readonly ToolbarCommandState[];
|
|
2463
|
+
/**
|
|
2464
|
+
* Result of {@link runTableChromeCommand}: engine outcome plus post-pick draft on success.
|
|
2465
|
+
*
|
|
2466
|
+
* @public
|
|
2467
|
+
*/
|
|
2468
|
+
interface RunTableChromeCommandResult {
|
|
2469
|
+
readonly result: ExecResult;
|
|
2470
|
+
readonly nextDraft: TableChromeDraft | null;
|
|
2471
|
+
}
|
|
2472
|
+
/**
|
|
2473
|
+
* Run one table chrome pick with explicit draft state; returns the post-pick draft on success.
|
|
2474
|
+
*
|
|
2475
|
+
* @public
|
|
2476
|
+
*/
|
|
2477
|
+
declare function runTableChromeCommand(editor: Editor | null, slot: TableChromeSlotId, value: unknown, draft: TableChromeDraft): RunTableChromeCommandResult;
|
|
2478
|
+
/**
|
|
2479
|
+
* Run a toolbar control: `can` first, then `exec` only if it said yes. Returns
|
|
2480
|
+
* the engine's refusal untouched when it said no, so a caller cannot mistake a
|
|
2481
|
+
* declined command for a no-op.
|
|
2482
|
+
*
|
|
2483
|
+
* @public
|
|
2484
|
+
*/
|
|
2485
|
+
declare function runToolbarCommand(editor: Editor | null, id: ChromeSlotId,
|
|
2486
|
+
/** The chosen value, for a slot whose command carries one (the editing-mode pill). */
|
|
2487
|
+
value?: unknown): ExecResult;
|
|
2488
|
+
/**
|
|
2489
|
+
* Save goes straight to `Editor.save()` — it is not a command.
|
|
2490
|
+
*
|
|
2491
|
+
* @public
|
|
2492
|
+
*/
|
|
2493
|
+
declare function runSave(editor: Editor | null): Promise<ArrayBuffer>;
|
|
2494
|
+
/**
|
|
2495
|
+
* Enabled state for a table command when the caller holds the paginated surface.
|
|
2496
|
+
*
|
|
2497
|
+
* Uses the same planner-backed `tableCommandState` as `Editor.can`/`gateTableCommand`.
|
|
2498
|
+
* Chrome slot mapping for table controls is Task 9 — this helper is the shared
|
|
2499
|
+
* can-before-exec seam for arbitrary table commands.
|
|
2500
|
+
*
|
|
2501
|
+
* @public
|
|
2502
|
+
*/
|
|
2503
|
+
declare function tableCommandToolbarState(surface: PaginatedSurface | null, command: EditorCommand): Pick<ToolbarCommandState, 'enabled' | 'disabledReason'>;
|
|
2504
|
+
/**
|
|
2505
|
+
* Run a table command: planner-backed `can` first, then `exec` only when allowed.
|
|
2506
|
+
*
|
|
2507
|
+
* @public
|
|
2508
|
+
*/
|
|
2509
|
+
declare function runTableCommand(editor: Editor | null, command: EditorCommand): ExecResult;
|
|
2510
|
+
|
|
2511
|
+
/**
|
|
2512
|
+
* Build an editor: the full `Editor` contract over a paginated surface.
|
|
2513
|
+
*
|
|
2514
|
+
* Construction is separate from mounting. Pass a `container` and the document mounts
|
|
2515
|
+
* immediately; omit it and nothing touches the DOM until `attach(el)` — the provider-first
|
|
2516
|
+
* shape. `detach()` remounts from the saved bytes, which resets undo and the caret.
|
|
2517
|
+
*
|
|
2518
|
+
* `snapshot()` is version-cached: the same reference until state actually moves, with
|
|
2519
|
+
* reference-stable sub-objects, so it is safe as a `useSyncExternalStore` source.
|
|
2520
|
+
*
|
|
2521
|
+
* @example
|
|
2522
|
+
* ```ts
|
|
2523
|
+
* const editor = createDocxEditor({ document: bytes, modules: [reviewModule()] });
|
|
2524
|
+
* editor.attach(element);
|
|
2525
|
+
* editor.on('change', () => setDirty(true));
|
|
2526
|
+
* ```
|
|
2527
|
+
*
|
|
2528
|
+
* @public
|
|
2529
|
+
*/
|
|
2530
|
+
declare function createDocxEditor(config: DocxEditorConfig): DocxEditorInstance;
|
|
2531
|
+
|
|
2532
|
+
export { TABLE_BORDER_STYLE_OPTIONS as $, type AnchorFrameOrigin as A, type HyperlinkOps as B, CHROME_GROUPS as C, type DocxEditorInstance as D, EMU_PER_POINT as E, type FinalizedImageOverlayInteraction as F, IMAGE_OVERLAY_NUDGE_SHIFT_PT as G, type HyperlinkActivation as H, IMAGE_OVERLAY_NUDGE_PT as I, type ImageInteractionSession as J, type ImageOverlayScrollPort as K, type ImageResizeHandle as L, type ImageResizeResult as M, type LoadFontsRequest as N, type OpenPaginatedResult as O, type PaginatedSurfaceOptions as P, type LoadFontsResult as Q, MAX_RESOLVER_FAMILIES as R, type OverlayFrameRect as S, type TableCommandPlan as T, type PaginatedSurfaceState as U, type RunTableChromeCommandResult as V, type SelectedDrawingOverlayTarget as W, type SurfaceFormatting as X, type SurfaceHyperlink as Y, type SurfaceNavigation as Z, type SurfaceOverlayCoordinates as _, type PaginatedSurface as a, TABLE_BORDER_TARGET_OPTIONS as a0, TABLE_BORDER_WIDTH_OPTIONS as a1, TABLE_CHROME_SLOT_IDS as a2, type TableBorderStyleOption as a3, type TableBorderTargetOption as a4, type TableBorderTargetValue as a5, type TableBorderWidthOption as a6, type TableChromeDraft as a7, type TableChromePick as a8, type TableChromeSlotId as a9, finalizeImageOverlayInteraction as aA, formattingBarChromeGroups as aB, isStaleImageInteractionCommit as aC, isTableChromeSlot as aD, layoutPointsToCssPixels as aE, loadFonts as aF, overlayFrameToSheetCssPixels as aG, pointsToEmu as aH, probeTableChromeCommand as aI, resizePreservesAspect as aJ, runSave as aK, runTableChromeCommand as aL, runTableCommand as aM, runToolbarCommand as aN, selectedDrawingOverlayTargetOf as aO, selectedImageStateOf as aP, surfacePaintScale as aQ, tableChromeIconPaths as aR, tableChromeLabelKeyForTarget as aS, tableChromeToolbarState as aT, tableChromeVisible as aU, tableCommandToolbarState as aV, toolbarCommandState as aW, toolbarCommandStates as aX, type TableInteractionLabelKey as aa, type ToolbarCommandState as ab, WORD_DEFAULT_FONT as ac, applyTableChromePick as ad, blankDocumentBytes as ae, canExecuteImageCommand as af, captureImageMutationPreconditions as ag, chromeControlCount as ah, chromeMenuSlots as ai, chromeProbeForSlot as aj, chromeSlotId as ak, commandForSlot as al, commandForSlotValue as am, commandForTableChromeSlotValue as an, composeFontConfiguration as ao, computeImageResizeResult as ap, computeMovedImagePosition as aq, computeResizedImageExtentEmu as ar, createDocxEditor as as, createFontSource as at, createImageOverlayScrollPort as au, cssPixelsToLayoutPoints as av, defaultChromeGroups as aw, defaultTableLabel as ax, emuToOverlayPoints as ay, executeImageCommand as az, CHROME_MENUS as b, 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 FontConfigurationBase as r, type FontConfigurationFragment as s, type FontLoadFailure as t, type FontLoadFailureReason as u, type FontMeasurementState as v, type FontResolutionRequest as w, type FontResolver as x, type FontUrlSource as y, type HyperlinkChromeHandlers as z };
|