@docx-editor.dev/core
v2.1.3 · 12 published subpaths with full TypeScript signatures and JSDoc.
Subpaths
@docx-editor.dev/core/automation
`@docx-editor.dev/core/automation` — the host protocol document automation runs against.
@docx-editor.dev/core/binding
`@docx-editor.dev/core/binding` — the canonical tree ↔ ProseMirror binding.
@docx-editor.dev/core/contracts/editor
`@docx-editor.dev/core/contracts/editor` — the `Editor` contract adapters are written against.
@docx-editor.dev/core/contracts/document
`@docx-editor.dev/core/contracts/document` — the document-level edit and query vocabulary.
@docx-editor.dev/core/contracts/interaction
`@docx-editor.dev/core/contracts/interaction` — semantic addressing and interaction outcomes.
@docx-editor.dev/core/contracts/modules
`@docx-editor.dev/core/contracts/modules` — the `EditorModule` seam.
@docx-editor.dev/core/contracts/types
@docx-editor.dev/core/layout
`@docx-editor.dev/core/layout` — DOM-free pagination, shaping, and hit testing.
@docx-editor.dev/core/output
`@docx-editor.dev/core/output` — painting a layout into DOM.
@docx-editor.dev/core/store
`@docx-editor.dev/core/store` — the canonical OOXML tree and the only write path into it.
@docx-editor.dev/core/editor
`@docx-editor.dev/core/editor` — the editor facade and its chrome vocabulary.
Package root
One preservation model and one pipeline: bytes are read into a canonical typed-and-generic OOXML tree, mutated only through the store's ops, laid out DOM-free, and painted onto pages that ARE the editable surface. Content the engine does not model is carried losslessly rather than dropped, so an unfamiliar document never locks editing.
Functions (10)
blankDocumentBytesfunctionSource ↗
A Word-faithful blank document, freshly zipped per call (the caller may hand the bytes to a loader that takes ownership). Calibri 11pt and Word's Normal paragraph spacing are authored in w:docDefaults, US Letter geometry in the section — a New document behaves like Word's, and saving it produces a file Word opens identically.
declare function blankDocumentBytes(): Uint8Array;chromeMenuSlotsfunctionSource ↗
Every slot a menu places, in menu order, submenus flattened. What a parity test asserts against, and what a host enumerates to know which capabilities the menu bar reaches.
declare function chromeMenuSlots(): readonly ChromeSlotId[];commandForSlotfunctionSource ↗
The public editor command behind one chrome slot, or null when the slot is not wired to a command yet (parity-only chrome, or save — which is not a command). The single source of command truth for both adapters.
declare function commandForSlot(slotId: ChromeSlotId): EditorCommand | null;commandForSlotValuefunctionSource ↗
The engine command for a VALUE-TYPED slot carrying the picked value, or null for a slot that does not take a value.
Two families: the run-property pickers (font.family, font.size, text.color, text.highlight) resolve to setMarkAttr, and styles.style resolves to setParagraphStyle — a paragraph styleId, not a mark. Either way the value is validated by the engine's own gate (can refuses a malformed one with invalidArgs; a styleId the document does not define is refused at exec), so a host can pass user input through unmodified.
declare function commandForSlotValue(slotId: ChromeSlotId, value: unknown): EditorCommand | null;composeFontConfigurationfunctionSource ↗
Merge a base and any number of fragments into one frozen FontConfiguration.
A bare fragment IS a valid base, so the single-origin case is one argument: composeFontConfiguration(await loadDefaultFonts()). Pass extra fragments to layer origins, and set epoch/maxFontBytes/defaultFont on the base only when you need something other than the documented defaults.
- Sources dedupe first-wins by (family, weight, style), in argument order — base before fragments, earlier fragments before later ones. - Substitutions dedupe first-wins by their from face, in the same order, and every substitution whose from face has a direct source anywhere in the composition is dropped: a real face always beats a stand-in. - The result is frozen (arrays included); the byte arrays themselves are the callers' and are not copied here — the resource snapshot takes its own defensive copy.
declare function composeFontConfiguration(base: FontConfigurationBase, ...fragments: readonly FontConfigurationFragment[]): FontConfiguration;createDocxEditorfunctionSource ↗
Build an editor: the full Editor contract over a paginated surface.
Construction is separate from mounting. Pass a container and the document mounts immediately; omit it and nothing touches the DOM until attach(el) — the provider-first shape. detach() remounts from the saved bytes, which resets undo and the caret.
snapshot() is version-cached: the same reference until state actually moves, with reference-stable sub-objects, so it is safe as a useSyncExternalStore source.
declare function createDocxEditor(config: DocxEditorConfig): DocxEditorInstance;```ts
const editor = createDocxEditor({ document: bytes, modules: [reviewModule()] });
editor.attach(element);
editor.on('change', () => setDirty(true));
```createFontSourcefunctionSource ↗
Turn font bytes you ALREADY hold into a FontSource — a file input, IndexedDB, a bundler import. loadFonts covers URLs; this covers everything else, so no caller has to hand-assemble the record or reach for a hashing helper.
Returns a typed failure instead of throwing when the descriptor or the bytes are unusable, matching loadFonts: one bad face degrades itself, never its neighbours.
declare function createFontSource(bytes: Uint8Array, request: FontFaceRequest & {
readonly faceIndex?: number;
}, options?: {
readonly id?: string;
readonly maxFontBytes?: number;
}): {
readonly source: FontSource;
} | {
readonly failure: FontLoadFailure;
};loadFontsfunctionSource ↗
Fetch app-specified font URLs into verified, cache-backed FontSources.
Fetches ONLY the URLs listed — never a default host or engine-chosen CDN — and never rejects for a per-source failure: the result carries every admitted source and a typed entry for every drop. Compose the result with composeFontConfiguration.
declare function loadFonts(request: LoadFontsRequest): Promise<LoadFontsResult>;runToolbarCommandfunctionSource ↗
Run a toolbar control: can first, then exec only if it said yes. Returns the engine's refusal untouched when it said no, so a caller cannot mistake a declined command for a no-op.
declare function runToolbarCommand(editor: Editor | null, id: ChromeSlotId,
value?: unknown): ExecResult;toolbarCommandStatefunctionSource ↗
Ask the engine whether one control should be enabled.
declare function toolbarCommandState(editor: Editor | null, id: ChromeSlotId): ToolbarCommandState;Classes (1)
EditorFontErrorclassSource ↗
Typed adapter error reported both through onFontError and accessible alert UI.
declare class EditorFontError extends Error| Member | Type | Summary |
|---|---|---|
| (constructor) | | Constructs a new instance of the `EditorFontError` class |
| code | EditorFontErrorCode | |
| diagnostic? | string | |
| name | string | |
| request? | FontFaceRequest |
Interfaces (109)
ApplyResultinterfaceSource ↗
What applying a batch of edits produced: the new document, and a per-edit verdict.
results is positionally aligned with the input, so an edit that failed is identified by its index rather than by anything the caller has to correlate.
interface ApplyResult| Member | Type | Summary |
|---|---|---|
| doc | DocxDocument | |
| results | ExecResult[] | One per edit, positionally aligned with the input. |
AuthoredNoteNumberinginterfaceSource ↗
Authored note-numbering fields as Word's properties dialog writes them.
interface AuthoredNoteNumbering| Member | Type | Summary |
|---|---|---|
| numFmt? | string | |
| numRestart? | string | |
| numStart? | number | |
| pos? | string |
ChromeMenuinterfaceSource ↗
One menu of the menu bar.
interface ChromeMenu| Member | Type | Summary |
|---|---|---|
| entries | readonly ChromeMenuEntry[] | |
| id | ChromeMenuId | |
| labelKey | string |
ChromeMenuItemEntryinterfaceSource ↗
A row that runs one chrome slot.
interface ChromeMenuItemEntry| Member | Type | Summary |
|---|---|---|
| kind | 'item' | |
| labelKey? | string | Plain-label override for this row. |
| picker? | 'tableGrid' | The row opens a size PICKER instead of firing on click — Word's insert-table grid. The slot still owns the label, the icon and the enabled state; only the dispatch differs, and the picked size is what the host sends. |
| shortcutKey? | string | i18n key of the shortcut shown right-aligned on the row (`toolbar.saveShortcut`). |
| slot | ChromeSlotId |
ChromeMenuSeparatorEntryinterfaceSource ↗
A horizontal rule between groups of rows.
interface ChromeMenuSeparatorEntry| Member | Type | Summary |
|---|---|---|
| kind | 'separator' |
ChromeMenuSubmenuEntryinterfaceSource ↗
A row that opens a nested panel of rows (Insert › Break).
It carries its own label and icon rather than a slot, because a submenu PARENT has no command: clicking it opens the panel. Giving it a slot would mint a public id for a control that can never be enabled, and toolbarCommandState would have to invent an answer about it.
interface ChromeMenuSubmenuEntry| Member | Type | Summary |
|---|---|---|
| items | readonly ChromeMenuEntry[] | |
| kind | 'submenu' | |
| labelKey | string | |
| paths | readonly string[] | null |
CommentRecordinterfaceSource ↗
One comment as authored in word/comments.xml.
interface CommentRecord| Member | Type | Summary |
|---|---|---|
| author | string | |
| blocks | readonly OoxmlElement[] | Body paragraphs, as tree nodes, so the surface renders measured text rather than a string. |
| date? | string | |
| id | string | |
| initials? | string | |
| paraId? | string | `w14:paraId` of the first body paragraph — the key thread state is stored under. |
| parentCommentId? | string | `@w16cid:parentId` — the `w:id` of the comment this replies to, when the file names it. |
ContentControlinterfaceSource ↗
Structured document tag (w:sdt).
interface ContentControl| Member | Type | Summary |
|---|---|---|
| alias? | string | |
| content | readonly Block[] | |
| controlType | ContentControlType | |
| id | string | |
| kind | 'contentControl' | |
| locked? | boolean | |
| tag? | string |
ContentControlFilterinterfaceSource ↗
Narrows a content-control query. Fields combine with AND; an empty filter matches every control.
interface ContentControlFilter| Member | Type | Summary |
|---|---|---|
| alias? | string | |
| controlType? | ContentControlType | |
| tag? | string |
ContentControlSummaryinterfaceSource ↗
A content control reduced to what a listing needs: its identity, kind, and lock state.
interface ContentControlSummary| Member | Type | Summary |
|---|---|---|
| alias? | string | |
| controlType | ContentControlType | |
| id | string | |
| locked? | boolean | |
| tag? | string |
DocAnchorinterfaceSource ↗
The LLM- and JSON-facing address for a piece of a document.
paraId is the 8-hex w14:paraId, matched case-insensitively. search is a phrase that must match EXACTLY ONCE inside that paragraph; ambiguous or missing matches fail with 'ambiguous' / 'notFound' rather than falling back to first-match.
Offset-based addressing was tried and abandoned: an agent cannot compute a character offset it has not seen, and offsets do not survive concurrent edits. Do not reintroduce { blockId, offset }.
interface DocAnchor| Member | Type | Summary |
|---|---|---|
| occurrence? | number | Opt-in disambiguation. Omit to require uniqueness. |
| paraId | string | |
| search? | string |
DocAnchorRangeinterfaceSource ↗
A position in one story: a paragraph and a UTF-16 offset inside it.
The same offset space the ops and the caret use, so an anchor read here can be handed straight back to a selection without re-deriving anything.
interface DocAnchorRange| Member | Type | Summary |
|---|---|---|
| endOffset | number | |
| endParagraphId | string | May sit in a later paragraph: the range markers are independent elements. |
| part | string | Canonical part name of the story the range lives in, e.g. `/word/document.xml`. |
| startOffset | number | |
| startParagraphId | string |
DocCommentinterfaceSource ↗
One comment or reply, as comments.xml records it.
A reply is a comment with a parentId; OOXML gives replies no separate element, so the thread is reconstructed from that link rather than from nesting.
interface DocComment| Member | Type | Summary |
|---|---|---|
| anchor? | DocAnchorRange | Where the comment is anchored, absent when the file gave it no usable range. |
| author | string | |
| date? | string | OPTIONAL, because `CT_Comment` makes `@w:date` optional and files omit it. A comment with no date is a comment, not a defect, and fabricating one is a content change. |
| id | string | |
| orphaned? | boolean | True when the file gave this comment no usable range — a reference with no markers, or a start with no end. Reported rather than dropped: a reviewer's remark vanishing silently is worse than one that says it lost its text. |
| parentId? | string | |
| resolved? | boolean | |
| text | string |
DocEditsinterfaceSource ↗
The document-executable edit vocabulary.
An interface rather than a closed union so extensions can widen it by declaration merging. A sealed union cannot be extended by a plugin, and the runtime dispatch is already registry-backed.
interface DocEdits| Member | Type | Summary |
|---|---|---|
| acceptAllRevisions | Record<never, never> | |
| acceptRevision | {
id: number;
part?: 'body' | 'footnote' | 'endnote';
noteId?: number;
} | |
| addComment | {
target: DocTarget;
text: string;
author: string;
} | |
| addRepeatingSectionItem | {
target: DocTarget;
index?: number;
} | |
| adjustIndent | {
target: DocTarget;
direction: 'increase' | 'decrease';
} | Word's Increase/Decrease Indent. |
| applyFormatting | {
target: DocTarget;
marks: RunFormatting;
} | |
| applyVariables | {
values: Record<string, string>;
} | |
| deleteText | {
target: DocTarget;
} | |
| insertBreak | {
target: DocTarget;
kind: 'page' | 'column' | 'line' | 'section';
} | |
| insertHyperlink | {
target: DocTarget;
href: string;
text?: string;
} | |
| insertImage | {
target: DocTarget;
data: Uint8Array;
extent?: Extent;
} | |
| insertTable | {
target: DocTarget;
rows: number;
cols: number;
} | |
| insertText | {
target: DocTarget;
text: string;
} | |
| mergeParagraphs | {
target: DocTarget;
} | |
| proposeDeletion | {
target: DocTarget;
author: string;
} | |
| proposeInsertion | {
target: DocTarget;
text: string;
author: string;
} | |
| proposeReplacement | {
target: DocTarget;
replaceWith: string;
author: string;
} | Authored family. `author` is required: tracked-ness is verb identity, not a boolean flag, so there is no global trackChanges toggle to forget. |
| rejectAllRevisions | Record<never, never> | |
| rejectRevision | {
id: number;
part?: 'body' | 'footnote' | 'endnote';
noteId?: number;
} | |
| removeContentControl | {
target: DocTarget;
} | |
| removeHyperlink | {
target: DocTarget;
} | |
| removeRepeatingSectionItem | {
target: DocTarget;
index: number;
} | |
| replaceText | {
target: DocTarget;
text: string;
} | |
| replyComment | {
commentId: string;
text: string;
author: string;
} | |
| resolveComment | {
commentId: string;
} | |
| setContentControlValue | {
target: DocTarget;
value: string;
} | |
| setParagraphStyle | {
target: DocTarget;
styleId: string;
} | |
| setVariable | {
name: string;
value: string;
} | |
| splitParagraph | {
target: DocTarget;
} | |
| toggleList | {
target: DocTarget;
kind: 'bullet' | 'ordered';
} | Word's Bullets and Numbering. |
DocLocationinterfaceSource ↗
Structural addressing for content the paraId map cannot reach.
interface DocLocation| Member | Type | Summary |
|---|---|---|
| container | ContainerRef | |
| offset? | number | |
| path | number[] | Block indices, descending into tables and content controls. |
DocQueriesinterfaceSource ↗
The document-readable query vocabulary, keyed identically to [DocQueryResults](DocQueryResults).
An interface rather than a closed union for the same reason [DocEdits](DocEdits) is: an extension widens it by declaration merging, and the runtime dispatch is registry-backed.
interface DocQueries| Member | Type | Summary |
|---|---|---|
| comments | {
resolved?: boolean;
} | |
| contentControls | {
filter?: ContentControlFilter;
} | |
| findText | {
text: string;
container?: ContainerRef;
} | |
| paragraphs | {
container?: ContainerRef;
} | |
| revisions | {
part?: 'body' | 'footnote' | 'endnote';
} | |
| styles | Record<never, never> | |
| variables | Record<never, never> |
DocQueryResultsinterfaceSource ↗
What each query returns. Keyed identically to DocQueries.
interface DocQueryResults| Member | Type | Summary |
|---|---|---|
| comments | readonly DocComment[] | |
| contentControls | readonly ContentControlSummary[] | |
| findText | readonly DocRange[] | |
| paragraphs | readonly ParagraphSummary[] | |
| revisions | readonly Revision[] | |
| styles | StyleDefinitions | |
| variables | Readonly<Record<string, string>> |
DocRangeinterfaceSource ↗
A span between two positions. The endpoints may be addressed either way, independently.
interface DocRange| Member | Type | Summary |
|---|---|---|
| from | DocAnchor | DocLocation | |
| to | DocAnchor | DocLocation |
DocumentBodyinterfaceSource ↗
The main story: its blocks in reading order, plus the sections derived from them.
interface DocumentBody| Member | Type | Summary |
|---|---|---|
| content | readonly Block[] | |
| sections | readonly Section[] | Derived, not stored: recomputed on read from section-break markers and section inheritance. Never treat it as a spreadable field. |
DocumentChangeinterfaceSource ↗
The payload of the change event / onChange. It carries revision + identity deltas, NOT serialized bytes: serializing a whole DOCX on every keystroke would be prohibitive for large documents. Call save() to get bytes on demand.
interface DocumentChange| Member | Type | Summary |
|---|---|---|
| created? | readonly string[] | Block ids created/deleted/edited by this change, when the engine reports them. |
| deleted? | readonly string[] | |
| dirty? | readonly string[] | |
| revision | number | The store revision after this change. |
DocumentHandleinterfaceSource ↗
An opaque handle to a loaded document — its stable identity and current revision. The canonical authored state is the engine's PackageModel, NOT a simplified tree; advanced automation (DocxEditor.run(handle, …)) addresses a document through this handle rather than a serialized structure. Kept deliberately minimal and open so it can carry more identity later without a breaking change.
interface DocumentHandle| Member | Type | Summary |
|---|---|---|
| revision | number | The document's current store revision. |
DocxDocumentinterfaceSource ↗
A parsed .docx.
NOT JSON-round-trippable: it holds Maps and Dates, plus an internal side-table of verbatim XML used for lossless round-tripping. Use toJSON / fromJSON before sending it over JSON-RPC or handing it to a model.
interface DocxDocument| Member | Type | Summary |
|---|---|---|
| body | DocumentBody | |
| comments | readonly DocComment[] | |
| revisions | readonly Revision[] | |
| styles | StyleDefinitions | |
| theme? | Theme |
DocxDocumentJSONinterfaceSource ↗
The JSON-safe projection of a document.
interface DocxDocumentJSON| Member | Type | Summary |
|---|---|---|
| (member-0) | |
DocxEditorConfiginterfaceSource ↗
Everything [createDocxEditor](createDocxEditor) accepts. Every field is optional.
container is the one that changes the shape of the whole lifecycle: omitting it produces an instance that does no DOM work until attach(el), which is what lets a provider own the editor before any component has rendered a mount point.
interface DocxEditorConfig| Member | Type | Summary |
|---|---|---|
| author? | string | |
| container? | HTMLElement | The element the paginated surface mounts into. The surface owns this subtree. |
| document? | DocumentSource | A document to load at construction. Bytes only in practice: a `DocumentHandle` cannot be re-opened (the handle is identity, not content), so passing one emits a typed `error` event rather than silently loading nothing. |
| fonts? | FontConfiguration | FontConfigurationFragment | FontResolver | Font bytes for Word-accurate (HarfBuzz-shaped) line wrap and pagination. Omitted, layout falls back to a fixed-width estimate; fonts embedded in the document are wired in automatically either way. For Word's default faces (Calibri, Times New Roman, …) pass `await loadDefaultFonts()` from `@docx-editor.dev/fonts` — a bare fragment (`{ sources, substitutions }`) is accepted and composed with defaults, or merge several origins yourself with `composeFontConfiguration`. Sampled per load; failures degrade to the fixed measurer and report through `onFontError`. |
| imageDecodePort? | ImageDecodePort | Override raster decode for insert/replace image commands; defaults to browser/headless. |
| locale? | string | |
| mode? | 'edit' | 'view' | `'view'` refuses every mutating command through the facade; default `'edit'`. |
| modules? | readonly EditorModule[] | Capability modules to register — the seam `@docx-editor.dev/pro` plugs in through. Omitted, the editor runs the free tier: lossless round-trip, final-state revision rendering, review chrome disabled with the engine's reason. See [EditorModule](EditorModule). |
| onFontError? | (error: EditorFontError) => void | |
| tableInteractionLabel? | (key: 'table.insertRowBelow' | 'table.insertColumnRight') => string | Localized labels for table insertion furniture on the painted surface. |
| translate? | (key: string, params?: Record<string, string | number>) => string | Localized drawing refusal labels; defaults to English when omitted. |
| zoom? | number |
DocxEditorInstanceinterfaceSource ↗
The concrete facade type: the full Editor contract plus the instance-only surface.
surface, stateVersion, attach and detach live HERE rather than on Editor: they are what a store binding and a mounting host need, not what document commands need. Production adapters program against Editor for everything else.
interface DocxEditorInstance extends Editor| Member | Type | Summary |
|---|---|---|
| attach | | Mount into `el`. If the instance holds pending document bytes (created without a container, or previously detached), they mount now — under the shaped measurer when fonts have resolved in the meantime. Attaching while already mounted elsewhere moves the live content via `session.save()`. |
| detach | | Tear down the painted surface, stashing the CURRENT document bytes (`session.save()`) so a later `attach` restores the content — but not the undo stack or the caret. No-op when already detached or destroyed. |
| fontMeasurement | | Which measurer the current document's layout runs on, and whether shaped resolution is still in flight — the honest "are wrap points Word-accurate yet?" readout a host shows instead of guessing. `fixed` with `resolving: false` is the steady state for a document with no usable font source (the documented zero-config fallback); `shaped` means HarfBuzz measurement over real font bytes. Changes bump `stateVersion()`. |
| mountGeneration | number | Bumps on mount, detach, destroy, and document reload — guards async image intents. |
| setHyperlinkChrome | | Wire the host's hyperlink chrome to the engine's gestures — a click on an external link, and Ctrl/Cmd+K. Returns an unsubscribe that restores whatever was registered before, so a popover component can register in an effect and clean up in its teardown. |
| stateVersion | | Monotonic version of the observable editor state. Bumps whenever anything `snapshot()` reports could have moved — a committed change, a selection move, zoom, load success or failure, attach/detach, destroy. An external store (React's `useSyncExternalStore`) uses it as a cheap "did anything change" signal; `snapshot()` itself is cached per version and returns a stable reference between bumps. |
| surface | PaginatedSurface | null | The underlying paginated surface for harnesses and tests that need capabilities the contract does not carry yet (select-all, node-id addressed selection). |
DrawingLocksinterfaceSource ↗
What a drawing refuses: selection, movement, resizing, aspect change.
Read and honoured rather than advisory — chrome that offered a handle the store will refuse would promise an edit that cannot happen.
interface DrawingLocks| Member | Type | Summary |
|---|---|---|
| changeAspect | boolean | |
| move | boolean | |
| resize | boolean | |
| select | boolean |
DrawingPositionInputinterfaceSource ↗
An anchored drawing's position: offsets, and the frames they are relative to.
The relative-to bases matter as much as the offsets. Writing an offset without preserving its base re-anchors the drawing against a different reference and moves it somewhere nobody asked.
interface DrawingPositionInput| Member | Type | Summary |
|---|---|---|
| horizontalEmu? | number | |
| mode? | 'frame' | 'simple' | `'simple'` when `@simplePos="1"`: `horizontalEmu` / `verticalEmu` are authoritative `wp:simplePos` x/y. `'frame'` (default) uses positionH/V relative frames. |
| relativeToH? | DrawingHorizontalReferenceFrame | |
| relativeToV? | DrawingVerticalReferenceFrame | |
| verticalEmu? | number |
EditorinterfaceSource ↗
The engine's whole public surface: load and save, execute and query, observe and subscribe.
Commands go through can before exec — the same check chrome uses to decide whether a control is enabled, so a button and the engine never disagree about what is possible.
snapshot() is version-cached: the same reference until state actually moves, with reference-stable sub-objects, which is what makes it safe as a useSyncExternalStore source.
interface Editor```ts
const editor = createDocxEditor({ container });
editor.load(bytes);
if (editor.can({ type: 'toggleBold' }).ok) editor.exec({ type: 'toggleBold' });
const bytesOut = await editor.save();
```| Member | Type | Summary |
|---|---|---|
| acceptReviewItem | | Accept or reject the revision behind a card. |
| addComment | | Comment on the current selection. |
| can | | Dry run: reports whether `exec` would apply. Never reports `changed`. |
| canExecuteImageCommand | | Dry run for byte commands that require [Editor.executeImageCommand](Editor.executeImageCommand). Generic [Editor.can](Editor.can) on `insertImage` / `replaceImage` refuses with an async-path reason; this method answers whether async execution can proceed right now. |
| deleteReviewItem | | Discard the item behind a card: the destructive half of the review verbs. |
| destroy | | |
| exec | | |
| executeImageCommand | | Insert or replace picture bytes as one package undo unit. |
| findMatches | | Find matches for a query, for the find/replace dialog. |
| focus | | |
| getActiveScope | | |
| getAvailableFonts | | Every font family the editor can offer: the configured catalog (the default face, the Word-name families the substitution map stands in for, and host-registered source families) merged with [getDocumentFonts](getDocumentFonts). Never empty — a brand-new document offers the configured catalog rather than a dead picker. |
| getComments | | Comment threads anchored in the document. |
| getCurrentPage | | One-based page at the caret (default), or at the centre of the mounted scroll viewport. Viewport mode falls back to the caret when no measurable viewport is attached. |
| getCustomNodeDefinitions | | Custom-node definitions registered through `createDocxEditor({ modules })`, in registration order. |
| getDocumentFonts | | Font families the document actually uses, for the font picker. |
| getDocumentHandle | | An opaque handle to the current document (identity + revision). Replaces the former structured `getDocument()`; the canonical state is the engine `PackageModel`, not a tree. |
| getDocumentStyles | | Paragraph/character styles defined by the document, for the style picker. |
| getDocumentThemeColors | | The document theme's ten picker colours (`a:clrScheme`) in Word's column order (Background 1, Text 1, Background 2, Text 2, Accent 1-6), each a six-digit hex without '#'. Empty when the document has no complete scheme — the picker then falls back to a default palette. |
| getEditingMode | | How edits are written: directly, as suggestions, or not at all. |
| getHeaderFooterState | | Header/footer editing state: which region is being edited, if any. |
| getNotePreviewText | | Plain-text note preview for hover chrome. |
| getNotePropertiesState | | Resolved and authored note properties for the caret section — properties dialog read-model. |
| getOutline | | Heading outline for the navigation panel, in document order. |
| getPageGeometry | | Page boxes in stack coordinates, each with the text area the engine laid out. `contentBox` is the page inset by the section margin — rulers draw margin zones from it instead of assuming a default. The engine's margin is uniform on all four sides today, so this must not be presented as per-side fidelity it does not have. |
| getPageSetup | | Section page setup — size, orientation and margins — for the page-setup dialog. |
| getRenderScale | | Layout points to CSS pixels, zoom included. |
| getReviewItems | | Every pending decision in the document, with where its card belongs. |
| getReviewRevision | | A counter that changes exactly when [getReviewItems](getReviewItems) would return something new. |
| getSelectedImage | | The image at the selection, for the image toolbar and transform controls. |
| getSelectedTable | | The table containing the selection, for the table toolbar. `null` outside a table. |
| getSelectionFormatting | | Formatting at the current selection, for toolbar value display (font, size, colour, alignment, list state). `null` when nothing is selected or nothing is derivable. |
| getSelectionPlacement | | Where a comment on the current selection would sit, in the same space as [ReviewItemPlacement.anchorY](ReviewItemPlacement.anchorY), or null when nothing is selected. |
| getTableCellSelection | | Live rectangular cell selection, if any. `null` when the caret is not in a cell rectangle. |
| getTotalPages | | |
| getTrackedChanges | | Tracked changes in the document — body AND header/footer stories. |
| getWatermark | | The document watermark, for the watermark dialog. |
| getZoom | | |
| isActive | | Whether a formatting command is currently APPLIED at the selection — distinct from `can`, which answers whether it may run. |
| isReviewPaneOpen | | Whether the review pane is showing its cards. |
| load | | Load a new document (DOCX bytes or a handle), replacing the current one. |
| on | | |
| query | | |
| rejectReviewItem | | |
| relayout | | Replaces the module-scope cache-invalidation calls adapters make today. |
| replyToReviewItem | | Reply to a review item. |
| reportCustomNodeDiagnostic | | Report a custom-node diagnostic to the modules registered on THIS editor. |
| save | | Serialize the current canonical document to DOCX bytes — on demand, never per keystroke. |
| scrollToBlock | | |
| scrollToPage | | Scroll a page or a block into view. Returns false when the target does not exist or the host has no scroll container — a caller can tell "not found" from "scrolled". |
| selectMatch | | Move the selection to a found match — what a find dialog's next/previous do. |
| setActiveReviewItem | | Card to document: select the item's range and scroll to it. `null` clears the active item. |
| setActiveScope | | |
| setEditingMode | | |
| setReviewActivationExclusions | | Revision kinds the caret must never activate, or null for none. |
| setTableInteractionLabel | | Update table furniture aria labels without remounting the editor. |
| setZoom | | Set the display scale. Values outside a sane range are rejected rather than clamped silently, so a caller learns its input was refused. |
| snapshot | |
EditorCommandsinterfaceSource ↗
Every command the editor accepts, keyed by name with its payload as the value.
Extends the document-level [DocEdits](DocEdits) vocabulary with the things only a LIVE editor has: selection, view state, chrome modes, header/footer and note editing. An interface rather than a closed union so an extension can widen it by declaration merging.
interface EditorCommands extends EditorCommandShape<DocEdits>, EditorHeaderFooterCommands, EditorNoteCommands| Member | Type | Summary |
|---|---|---|
| clearFormatting | Record<never, never> | Word's Clear All Formatting (Home Font the eraser). |
| commitTableColumnDividerResize | {
target: TableColumnDividerResizeTarget;
leftWidthTwips: number;
rightWidthTwips: number;
} | Commit an internal column-divider resize from an explicit pointer target. Widths are twips for the adjacent pair; their sum must match the pre-drag total. |
| commitTableRightEdgeResize | {
target: TableRightEdgeResizeTarget;
columnWidthTwips: number;
tableWidthTwips: number;
} | Commit an outer-right table-edge resize from an explicit pointer target. Updates the last grid column and overall table width together. |
| copy | Record<never, never> | Put the selected text on the clipboard. Reports `changed: false` — the document is untouched. |
| cut | Record<never, never> | Put the selected text on the clipboard and delete it. Refused at a collapsed selection, and — unlike `copy` — in a read-only document. |
| deleteColumn | {
target?: TableColumnOccurrenceTarget;
} | |
| deleteImage | {
drawingNodeId?: string;
expectedPackageRevision?: number;
} | Delete the selected picture drawing as one package undo unit. |
| deleteRow | {
target?: TableRowOccurrenceTarget;
} | |
| deleteTable | Record<never, never> | |
| insertColumn | {
where: 'left' | 'right';
target?: TableColumnOccurrenceTarget;
} | |
| insertImage | {
data: Uint8Array;
mime: SupportedImageMime;
widthPoints: number;
heightPoints: number;
expectedPackageRevision?: number;
title?: string;
description?: string;
hyperlink?: string;
} | Insert a raster image at the caret as one package undo unit. |
| insertRow | {
where: 'above' | 'below';
target?: TableRowOccurrenceTarget;
} | |
| insertToc | Record<never, never> | Insert a generated, hyperlink-enabled TOC for heading levels 1–3 at the selection. |
| mergeCells | Record<never, never> | |
| paste | {
text: string;
} | Insert `text` at the selection, replacing it, with newlines becoming real paragraph boundaries. |
| redo | Record<never, never> | |
| refreshToc | {
tocId?: string;
mode?: 'entire' | 'pageNumbers';
} | |
| removeTabMark | {
positionTwips: number;
} | Remove the tab stop at this position (twips) from the current paragraph. |
| replaceAllMatches | {
query: string;
text: string;
matchCase?: boolean;
wholeWord?: boolean;
} | Replace EVERY match of `query` in one undoable step. Separate from looping `replaceMatch` because each replacement shifts the offsets of the ones after it — legacy applied its edits back-to-front for exactly this reason, and that ordering belongs with whoever owns the offsets. |
| replaceImage | {
data: Uint8Array;
mime?: SupportedImageMime;
drawingNodeId?: string;
expectedPackageRevision?: number;
} | Replace the selected picture's bytes as one package undo unit. |
| replaceMatch | {
match: TextMatch;
text: string;
} | Replace one found match with `text`. Addressed by [TextMatch](TextMatch) rather than a `DocTarget` because that is what `findMatches` hands back, and re-deriving a target from it in the caller is where an off-by-one would come from. An empty `text` deletes the match, which is what a find/replace dialog means by replacing with nothing. |
| selectAll | Record<never, never> | Select the whole body. Word's Ctrl+A, as a command rather than only a keystroke. |
| selectTableRegion | {
region: 'table' | 'row' | 'column';
} | Select a table region — the whole table, the current row, or the current column. Legacy's table toolbar offers all three. |
| setAlignment | {
align: 'left' | 'center' | 'right' | 'justify';
} | |
| setCellFill | {
color: ColorValue | null;
} | Selected-cell fill. `null` clears direct fill so the table-style cascade applies again. |
| setEditingMode | {
mode: DocumentEditingMode;
} | Switch how edits are written. A view command: it changes no document state. |
| setImagePosition | {
drawingNodeId?: string;
expectedPackageRevision?: number;
horizontalEmu?: number;
verticalEmu?: number;
relativeToH?: string;
relativeToV?: string;
} | Anchor position of the selected floating image, from the position dialog. |
| setImageProperties | {
drawingNodeId?: string;
expectedPackageRevision?: number;
selectionParagraphId?: string;
selectionOffset?: number;
widthEmu?: number;
heightEmu?: number;
alt?: string;
title?: string;
description?: string;
hyperlink?: string | null;
crop?: ImageCropPercent;
resetToNaturalSize?: boolean;
wrap?: ImageWrapTarget;
horizontalEmu?: number;
verticalEmu?: number;
relativeToH?: string;
relativeToV?: string;
borderWidthEmu?: number;
borderColor?: ColorValue;
} | Size, alt text, crop, position, and border of the selected image, from the properties dialog. |
| setImageWrapType | {
drawingNodeId?: string;
expectedPackageRevision?: number;
target: 'inline' | 'square' | 'squareLeft' | 'squareRight' | 'tight' | 'through' | 'topAndBottom' | 'behind' | 'inFront';
initialPositionEmu?: {
horizontalEmu: number;
verticalEmu: number;
};
} | How the selected image sits relative to text. `inline` flows in the line; the rest are `wp:anchor` variants, with `squareLeft`/`squareRight` distinguishing which side text wraps on. Legacy's vocabulary, unchanged. |
| setIndent | {
left?: number | null;
right?: number | null;
firstLine?: number | null;
} | Exact paragraph indent, in twips, on every paragraph the selection touches. |
| setLineSpacing | {
rule: 'multiple' | 'exact' | 'atLeast';
value: number;
} | Word's Line Spacing, on every paragraph the selection touches. |
| setMarkAttr | {
mark: string;
attr: string;
value: unknown;
} | |
| setPageSetup | {
pageWidth?: number;
pageHeight?: number;
marginTop?: number;
marginRight?: number;
marginBottom?: number;
marginLeft?: number;
orientation?: 'portrait' | 'landscape';
scope?: 'document' | 'section';
} | Section-level page setup: the fields Word's Page Setup dialog and the rulers' margin drags change. Twips throughout, matching OOXML. Every field is optional — a margin drag sends one, the dialog sends several — and an omitted field is left as it is rather than reset. `scope` is Word's "Apply to": `'document'` (the default) writes every section; `'section'` writes only the section the selection is in. An orientation change without explicit dimensions swaps each written section's own dimensions, preserving distinct paper sizes. |
| setParagraphSpacing | {
beforePt?: number | null;
afterPt?: number | null;
} | Space above and below a paragraph, in points, on every paragraph the selection touches. Omitting a field leaves it as authored; `null` clears it, which is how Word's "Remove space before/after paragraph" differs from setting it to zero. |
| setSelection | {
anchor: DocAnchor;
} | {
range: EditorSelection;
} | Move the selection. Three accepted forms, and `can()` names all three when it refuses: a collapsed paraId anchor, a range of two paraId anchors, or a semantic anchor/head pair. |
| setTableBorders | {
scope: 'none';
target: TableBorderEdgeTarget;
} | {
scope: TableBorderEdgeTarget;
spec: TableBorderSpec;
} | Selected-cell borders. Concrete edge scopes require a complete spec; `{ scope: 'none', target }` clears only that active edge target and MUST NOT carry `spec`. |
| setTableCellVerticalAlignment | {
alignment: TableCellVerticalAlignment;
} | Vertically align content inside the selected table cells. |
| setTableProperties | {
width?: number | null;
widthType?: string | null;
justification?: 'left' | 'center' | 'right' | null;
} | Table-level properties from the table properties dialog: preferred width and its unit (`dxa`, `pct`, `auto`), and horizontal justification. `null` clears a property; omitting it leaves the current value alone. |
| setWatermark | {
watermark: Watermark | null;
} | |
| splitCell | {
rows: number;
cols: number;
} | |
| toggleHeaderRow | Record<never, never> | |
| toggleList | {
kind: 'bullet' | 'ordered';
} | |
| toggleMark | {
mark: string;
} | |
| toggleReviewPane | Record<never, never> | Show or hide the review pane. |
| transformImage | {
drawingNodeId?: string;
expectedPackageRevision?: number;
action: 'rotateCW' | 'rotateCCW' | 'flipH' | 'flipV';
} | Rotate or flip the selected image. Legacy composed these into a CSS transform. |
| undo | Record<never, never> |
EditorErrorinterfaceSource ↗
An error the engine raised, carrying a machine-readable code alongside the message.
code is optional because an Error from deeper down (a parser, a codec) is surfaced as-is rather than wrapped in a fabricated code.
interface EditorError extends Error| Member | Type | Summary |
|---|---|---|
| code? | string |
EditorEventsinterfaceSource ↗
What editor.on(...) can be subscribed to, and what each handler receives.
These are PUSH notifications and are not interchangeable with reading snapshot(): a snapshot read cannot observe an event that was never emitted, which is why adapter behaviour is asserted against these rather than against the snapshot.
interface EditorEvents| Member | Type | Summary |
|---|---|---|
| change | (change: DocumentChange) => void | A document mutation committed, with the ids it touched. |
| error | (error: EditorError) => void | |
| selectionChange | (snapshot: EditorSnapshot) => void | The selection or its derived formatting moved. |
EditorHeaderFooterCommandsinterfaceSource ↗
Header/footer lifecycle and page-field commands on [EditorCommands](EditorCommands).
Kept as a mixin so editor.ts can extend it without inlining the furniture vocabulary.
interface EditorHeaderFooterCommands| Member | Type | Summary |
|---|---|---|
| editHeaderFooter | {
position: 'header' | 'footer';
variant?: FurnitureVariant;
firstPage?: boolean;
evenPage?: boolean;
sectionIndex?: number;
} | Open a header or footer for editing, materialising an empty one if the section has none — which is what a double-click on the header band means in Word. |
| exitHeaderFooter | Record<never, never> | Leave header/footer editing and return to the body. |
| insertPageField | {
field: 'PAGE' | 'NUMPAGES' | 'SECTIONPAGES' | 'PAGE_X_OF_Y';
} | Insert an allowlisted page-number field at the caret. Only valid while a header or footer scope is open. `PAGE_X_OF_Y` writes PAGE + " of " + NUMPAGES as one undo unit. |
| linkHeaderFooterToPrevious | HeaderFooterSlotArgs | Turn on "Same as Previous" for a section's furniture slot (drop its declared ref). Refused on the first section. Omitted fields default to the active story when scoped. |
| removeHeaderFooter | HeaderFooterSlotArgs | Delete a declared header/footer reference (and GC the part when orphaned). When the editor is already in furniture scope, omitted fields default to the active story. |
| setHeaderFooterOptions | {
sectionIndex?: number;
titlePage?: boolean;
evenAndOddHeaders?: boolean;
headerDistanceTwips?: number;
footerDistanceTwips?: number;
} | Section/document furniture options: `titlePg` and header/footer distances on a section; `evenAndOddHeaders` document-wide in settings. |
| unlinkHeaderFooterFromPrevious | HeaderFooterSlotArgs | Turn off "Same as Previous": clone the inherited part into a declared reference. When the active scope was the inherited rId, the editor rebinds to the clone. |
EditorModuleinterfaceSource ↗
One registered capability module. Registration is construction-time (createDocxEditor({ modules })) and immutable for the instance's lifetime.
interface EditorModule| Member | Type | Summary |
|---|---|---|
| customNodePayloadNamespaces? | readonly string[] | customXml payload namespaces this module OWNS, swept for orphans when a document opens. |
| customNodes? | readonly unknown[] | Custom inline node definitions. Reserved: the definition shape lands with the custom-nodes lane; the registry carries them opaquely until then. |
| id | string | Diagnostic identity (`'review'`, `'custom-nodes'`); not a dispatch key. |
| onCustomNodeDiagnostic? | (diagnostic: unknown) => void | Told when the recognition pass finds something wrong with a node in THIS editor's document. |
| review? | ReviewModuleContribution | Review capability: queue derivation, commands gate, display modes. |
EditorNoteCommandsinterfaceSource ↗
Footnote/endnote lifecycle and properties commands on [EditorCommands](EditorCommands).
interface EditorNoteCommands| Member | Type | Summary |
|---|---|---|
| convertAllNotes | {
fromKind: NoteKind;
} | Convert every note of one kind to the other in document order (one undo step). |
| convertNote | {
fromKind: NoteKind;
noteId: number;
} | Convert one note to the other kind. |
| deleteNote | {
noteKind: NoteKind;
noteId: number;
} | Delete a note and its body reference together. |
| insertNote | {
noteKind: NoteKind;
} | Insert a footnote or endnote reference at the caret (body only). |
| setNoteProperties | {
scope?: 'document' | 'section';
sectionIndex?: number;
footnote?: {
numFmt?: string;
numRestart?: string;
position?: string;
numStart?: number;
};
endnote?: {
numFmt?: string;
numRestart?: string;
position?: string;
numStart?: number;
};
} | Footnote and endnote properties for the section — numbering format, restart rule and position, as Word's dialog offers them. |
EditorQueriesinterfaceSource ↗
Every query the editor answers, keyed by name with its arguments as the value.
Extends [DocQueries](DocQueries) with the reads that only mean something against a live, laid-out document: the selection, its formatting, the table or hyperlink under the caret.
interface EditorQueries extends DocQueries| Member | Type | Summary |
|---|---|---|
| contentControlAt | {
filter?: ContentControlFilter;
} | |
| hyperlinkAt | {
pos?: number;
fallbackHref?: string;
} | |
| isInsideToc | {
pos: number;
} | |
| selectedText | Record<never, never> | |
| selection | Record<never, never> | |
| selectionFormatting | Record<never, never> | |
| splitCellConfig | Record<never, never> | |
| tableContext | Record<never, never> | |
| trackedChanges | Record<never, never> | |
| watermark | Record<never, never> |
EditorQueryResultsinterfaceSource ↗
What each editor query returns. Keyed identically to EditorQueries.
interface EditorQueryResults extends DocQueryResults| Member | Type | Summary |
|---|---|---|
| contentControlAt | ContentControlSummary | null | |
| hyperlinkAt | HyperlinkInfo | null | |
| isInsideToc | boolean | |
| selectedText | string | |
| selection | DocRange | null | |
| selectionFormatting | RunFormatting | null | |
| splitCellConfig | {
maxRows: number;
maxCols: number;
} | null | |
| tableContext | TableContext | null | |
| trackedChanges | readonly Revision[] | |
| watermark | Watermark | null |
EditorSnapshotinterfaceSource ↗
A read model of the current editor state, safe to hand to framework rendering. Named EditorSnapshot rather than EditorState so it never collides with an editing engine's own state type.
interface EditorSnapshot| Member | Type | Summary |
|---|---|---|
| canRedo? | boolean | |
| canUndo? | boolean | Whether undo/redo have anything to apply, derived from the session's history. Optional and additive: an implementation that has not derived them omits them, and a consumer treats absent as `false` — the honest empty answer. |
| editable | boolean | Whether the loaded document is being edited: a patchable document opened in edit mode. A read-only document (tables/SDTs/unpreservable) or `mode: 'view'` reports false. |
| editingMode? | DocumentEditingMode | How edits are written right now. |
| fontSubstitutions? | readonly string[] | Document font families rendering in a substitute face: declared by the document but not resolvable on this platform, not embedded in the file, and not supplied by the app's font configuration. Chrome shows a compatibility notice from this the way Word does. Optional and additive like `canUndo`: absent means the implementation has not derived it; empty means every family resolved (or no document is loaded). |
| formatting | RunFormatting | null | |
| hasReviewContent? | boolean | Whether the document carries review content — tracked changes or comment anchors — independent of any registered review module. |
| image | ImageContext | null | |
| isLoading | boolean | Whether the editor is still waiting for a document: no bytes handed over yet, and no parse failure. Bytes count from the moment they are supplied, not from the moment pages paint, so this stays false across a detach and remount. Safe to gate a mount point on — it never depends on one existing. |
| lastRejection? | string | null | Why the last edit was refused, or null. |
| page | {
readonly current: number;
readonly total: number;
} | |
| pageSetup? | PageSetup | null | The section's page setup, reference-stable across ticks that did not change it. Optional and additive like `canUndo`: absent means the implementation has not derived it, `null` means no document is loaded. |
| parseError | string | null | |
| reviewPaneOpen? | boolean | Whether the review pane is showing its cards. |
| scope | EditorScope | |
| selection | DocRange | null | |
| selectionCollapsed | boolean | Whether the selection is a CARET rather than a range. `true` when nothing is loaded. |
| table | TableContext | null | |
| tocContext | {
readonly id: string;
} | null | The table of contents the last right-click landed on, or null. |
| zoom | number |
ExtentinterfaceSource ↗
A size in EMUs, the unit DrawingML stores extents in. 914400 EMU = 1 inch.
interface Extent| Member | Type | Summary |
|---|---|---|
| heightEmu | number | |
| widthEmu | number |
FontConfigurationinterfaceSource ↗
Public font source configuration sampled when an adapter mounts. It must be immutable for that editor lifetime; remount the adapter to replace bytes or substitutions atomically.
interface FontConfiguration| Member | Type | Summary |
|---|---|---|
| defaultFont | {
readonly family: string;
readonly sizeHalfPoints: number;
} | |
| epoch | number | |
| language? | string | |
| maxFontBytes | number | |
| sources | readonly FontSource[] | |
| substitutions? | readonly FontSourceSubstitution[] |
FontConfigurationBaseinterfaceSource ↗
The base of a composition: everything a FontConfiguration carries, all optional. Omitted fields take the documented defaults (epoch 0, maxFontBytes at the engine hard maximum, defaultFont Calibri at 11pt — Word's own default face and size).
interface FontConfigurationBase extends FontConfigurationFragment| Member | Type | Summary |
|---|---|---|
| defaultFont? | FontConfiguration['defaultFont'] | The face used when a run names no font. Defaults to Word's own: Calibri at 11pt. |
| epoch? | number | Identity of this configuration's byte set. The engine uses it to tell one resolved font set from another; leave it unset and the editor supplies the load sequence. |
| language? | string | BCP-47 tag passed to the shaper for language-sensitive shaping. |
| maxFontBytes? | number | Per-face byte ceiling. Defaults to the engine hard maximum; lower it to tighten intake. |
FontConfigurationFragmentinterfaceSource ↗
A partial font configuration one origin contributes: sources, substitutions, or both. loadDefaultFonts() (the substitute package) and loadFonts() (the fetch helper) both return this shape, so every origin composes through composeFontConfiguration the same way.
interface FontConfigurationFragment| Member | Type | Summary |
|---|---|---|
| sources? | readonly FontSource[] | |
| substitutions? | readonly FontSourceSubstitution[] |
FontDefinitioninterfaceSource ↗
A font the document names, and whether its bytes travel inside the package.
interface FontDefinition| Member | Type | Summary |
|---|---|---|
| embedded | boolean | |
| family | string |
FontFaceRequestinterfaceSource ↗
A concrete font face requested by authored document content.
interface FontFaceRequest| Member | Type | Summary |
|---|---|---|
| family | string | |
| style | 'normal' | 'italic' | |
| weight | number |
FontLoadFailureinterfaceSource ↗
One face that did not load, with whatever evidence the failure produced.
Non-fatal: [LoadFontsResult](LoadFontsResult) still carries every source that succeeded, and the affected family falls back to the engine's fixed measurement.
interface FontLoadFailure| Member | Type | Summary |
|---|---|---|
| actualHash? | string | |
| diagnostic? | string | |
| expectedHash? | string | |
| reason | FontLoadFailureReason | |
| request | FontFaceRequest | |
| status? | number | HTTP status for `httpError`; hashes for `hashMismatch`. |
| url | string |
FontMeasurementStateinterfaceSource ↗
Which measurer the current document's layout runs on, and whether shaped resolution is still in flight. Returned by [DocxEditorInstance.fontMeasurement](DocxEditorInstance.fontMeasurement).
interface FontMeasurementState| Member | Type | Summary |
|---|---|---|
| measurer | 'fixed' | 'shaped' | `fixed` estimates advance widths; `shaped` measures real font bytes with HarfBuzz. |
| producer? | string | The shaped measurer's identity (admitted face hashes); absent while fixed. |
| resolving | boolean | True while font resolution for the current document is still running. |
FontResolutionRequestinterfaceSource ↗
What the document turned out to need, handed to an on-demand resolver.
The families are the ones the file actually names — already name-validated and capped, so a resolver may treat them as a list to look up, never as URLs or paths to build.
interface FontResolutionRequest| Member | Type | Summary |
|---|---|---|
| defaultFamily | string | The face a run naming no font resolves to, so a resolver can cover it too. |
| families | readonly string[] | Families declared anywhere in the document (body, headers/footers, styles), deduped, sorted, and capped at [MAX_RESOLVER_FAMILIES](MAX_RESOLVER_FAMILIES). |
FontSourceinterfaceSource ↗
Immutable, byte-backed font face supplied to layout and browser paint.
interface FontSource| Member | Type | Summary |
|---|---|---|
| availability? | 'available' | 'forbidden' | |
| bytes | Uint8Array | |
| faceIndex | number | |
| hash | string | |
| id | string | |
| request | FontFaceRequest |
FontSourceSubstitutioninterfaceSource ↗
An explicit authored-font substitution. No implicit platform fallback is performed.
interface FontSourceSubstitution| Member | Type | Summary |
|---|---|---|
| from | FontFaceRequest | |
| to | FontFaceRequest |
FontUrlSourceinterfaceSource ↗
One URL to fetch and the face it claims to be.
interface FontUrlSource| Member | Type | Summary |
|---|---|---|
| faceIndex? | number | |
| family | string | |
| hash? | string | Expected `sha256:` content hash. When present, mismatching bytes are REFUSED — pin this for any URL not under the app's sole control. |
| style | 'normal' | 'italic' | |
| url | string | |
| weight | number |
HeaderFooterSetinterfaceSource ↗
A section's three header (or footer) variants, each a relationship id.
All optional: a variant a section does not declare inherits the previous section's, and one absent everywhere means the document simply has none.
interface HeaderFooterSet| Member | Type | Summary |
|---|---|---|
| default? | string | |
| even? | string | |
| first? | string |
HeaderFooterSlotArgsinterfaceSource ↗
Optional slot targeting shared by remove / link / unlink furniture commands.
interface HeaderFooterSlotArgs| Member | Type | Summary |
|---|---|---|
| evenPage? | boolean | |
| firstPage? | boolean | |
| position? | 'header' | 'footer' | |
| sectionIndex? | number | |
| variant? | FurnitureVariant | Prefer over `firstPage` / `evenPage` when selecting a furniture variant. |
HeaderFooterStateinterfaceSource ↗
Header/footer editing state: which region is being edited, if any.
interface HeaderFooterState| Member | Type | Summary |
|---|---|---|
| editing | 'header' | 'footer' | null | |
| evenAndOddHeaders? | boolean | Document `w:evenAndOddHeaders` — even-page furniture is distinct when true. |
| footerDistanceTwips? | number | Section footer distance from sheet edge, twips (`w:pgMar w:footer`). |
| headerDistanceTwips? | number | Section header distance from sheet edge, twips (`w:pgMar w:header`). |
| inherited? | boolean | Whether the resolved part is inherited from a preceding section ("Same as Previous") rather than declared on this section. |
| partName? | string | Package part name of the open story. |
| rId? | string | Relationship id of the open story (`EditorScope.rId`). |
| sectionIndex | number | |
| titlePage? | boolean | Section `w:titlePg` — first-page furniture is distinct when true. |
| variant? | FurnitureVariant | Furniture variant in effect on the page used to enter the scope. |
HyperlinkActivationinterfaceSource ↗
A click on a painted link, after native navigation was refused.
interface HyperlinkActivation| Member | Type | Summary |
|---|---|---|
| link | SurfaceHyperlink | |
| rect | {
readonly left: number;
readonly top: number;
readonly bottom: number;
readonly right: number;
} | The clicked line fragment's viewport rect, so a popover can be placed under it. |
HyperlinkChromeHandlersinterfaceSource ↗
The host chrome that answers the engine's hyperlink gestures.
A CLICK on an external link and Ctrl/Cmd+K both mean "the user wants the link UI", and the engine deliberately does not know what that looks like. Registered rather than passed at construction because the chrome mounts after the editor does, and it survives a document reload — the surface is rebuilt, the handlers are not.
interface HyperlinkChromeHandlers| Member | Type | Summary |
|---|---|---|
| onPopover? | (activation: HyperlinkActivation) => void | A plain click on an external or inert link: show the popover at `activation.rect`. |
| onRequest? | () => void | Ctrl/Cmd+K: open insert-or-edit for the selection. |
HyperlinkInfointerfaceSource ↗
The hyperlink under a position: where it points, how far it reaches, and what Word shows on hover.
href has already been through sanitizeHref — it comes from a file, so a javascript: or data: target is dropped at the parse boundary rather than here.
interface HyperlinkInfo| Member | Type | Summary |
|---|---|---|
| href | string | |
| range | DocRange | |
| tooltip? | string | `w:tooltip` on the `w:hyperlink` — the text Word shows on hover, and what the hyperlink dialog seeds its tooltip field with when editing an existing link. |
ImageCropPercentinterfaceSource ↗
Crop edge in UI percent (0–100).
interface ImageCropPercent| Member | Type | Summary |
|---|---|---|
| bottom | number | |
| left | number | |
| right | number | |
| top | number |
IndentFormattinginterfaceSource ↗
Indent at the selection, in twips.
Unlike every other field here, this does NOT go absent when the selection's paragraphs disagree. A ruler has to draw its handles somewhere, and Word draws them at the FIRST selected paragraph's values — Select All is the commonest indent gesture, and hiding the handles for it would be worse than showing one paragraph's truth. The values are therefore always the first touched paragraph's, and [mixed](mixed) records per field whether the rest agree.
firstLine is ONE SIGNED offset: negative is a hanging indent. OOXML spells it as two mutually exclusive attributes and this collapses them hanging-wins (§17.3.1.12), which is the model Word itself keeps.
Absent inside a table. The value would be correct there, but it is measured from the cell's content edge while a ruler is drawn against the page's margin, and the ruler does not know the cell.
interface IndentFormatting| Member | Type | Summary |
|---|---|---|
| firstLine | number | First-line offset from [left](left), signed. Negative is a hanging indent. |
| left | number | Left indent, signed. Negative pulls text into the margin, as Word allows. |
| mixed | {
readonly left: boolean;
readonly right: boolean;
readonly firstLine: boolean;
} | Per field, whether the selection's paragraphs disagree about it. |
| right | number | Right indent, signed. |
LoadFontsRequestinterfaceSource ↗
What to fetch, and under what limits.
Only sources is required. Each carries its own expected hash, so bytes are trusted by CONTENT rather than by origin — a swapped asset fails admission even from a trusted host.
interface LoadFontsRequest| Member | Type | Summary |
|---|---|---|
| cacheName? | string | Cache API bucket name; default `docx-editor-fonts`. |
| fetcher? | typeof fetch | Injectable for tests and CSP-constrained hosts; defaults to global `fetch`. |
| maxFontBytes? | number | Per-font byte ceiling; defaults to the engine hard maximum. |
| sources | readonly FontUrlSource[] |
LoadFontsResultinterfaceSource ↗
What one loadFonts call produced: the faces that arrived, plus the ones that did not.
A FontConfigurationFragment, so it composes straight into composeFontConfiguration alongside other font sources. Partial success is the normal case — compose it even with failures present.
interface LoadFontsResult extends FontConfigurationFragment| Member | Type | Summary |
|---|---|---|
| failures | readonly FontLoadFailure[] | |
| sources | readonly FontSource[] |
NotePropertiesSideinterfaceSource ↗
One note kind's resolved + authored properties for the caret section.
interface NotePropertiesSide| Member | Type | Summary |
|---|---|---|
| documentAuthored? | AuthoredNoteNumbering | |
| resolved | ResolvedNoteNumbering | |
| sectionAuthored? | AuthoredNoteNumbering |
NotePropertiesStateinterfaceSource ↗
Resolved and authored note properties for the caret section — properties dialog read-model.
interface NotePropertiesState| Member | Type | Summary |
|---|---|---|
| endnote | NotePropertiesSide | |
| footnote | NotePropertiesSide | |
| sectionIndex | number |
NumberingRefinterfaceSource ↗
A paragraph's list membership: which numbering.xml definition, and at which level.
interface NumberingRef| Member | Type | Summary |
|---|---|---|
| level | number | Zero-based. OOXML numbering has nine levels, 0 through 8. |
| numId | string |
PageMarginsinterfaceSource ↗
Page margins in twips.
interface PageMargins| Member | Type | Summary |
|---|---|---|
| bottomTwips | number | |
| leftTwips | number | |
| rightTwips | number | |
| topTwips | number |
PageSetupinterfaceSource ↗
Section page setup — size, orientation and margins, in twips — as getPageSetup() and snapshot().pageSetup report it and the setPageSetup command writes it. In a multi-section document this is the setup of the section the SELECTION is in, which is what a ruler or a dialog reflects — Word's behaviour.
interface PageSetup| Member | Type | Summary |
|---|---|---|
| gutterTwips? | number | Binding gutter (`w:gutter`), folded into the left margin by layout. |
| marginsTwips | {
readonly top: number;
readonly right: number;
readonly bottom: number;
readonly left: number;
} | |
| orientation | 'portrait' | 'landscape' | |
| pageHeightTwips | number | |
| pageWidthTwips | number |
ParagraphinterfaceSource ↗
One paragraph: its runs, the style it names, and its list membership.
interface Paragraph| Member | Type | Summary |
|---|---|---|
| kind | 'paragraph' | |
| numbering? | NumberingRef | |
| paraId? | string | `w14:paraId`. The stable handle `DocAnchor` addresses. |
| runs | readonly Run[] | |
| styleId? | string |
ParagraphSummaryinterfaceSource ↗
A paragraph reduced to what a listing needs: its stable handle, its text, and its style.
paraId is what a follow-up edit addresses, so a summary without one names a paragraph the file gave no w14:paraId and that a DocAnchor cannot reach.
interface ParagraphSummary| Member | Type | Summary |
|---|---|---|
| paraId? | string | |
| styleId? | string | |
| text | string |
PointinterfaceSource ↗
A position in points.
interface Point| Member | Type | Summary |
|---|---|---|
| x | number | |
| y | number |
RectinterfaceSource ↗
An axis-aligned rectangle in points, the unit layout works in throughout.
interface Rect| Member | Type | Summary |
|---|---|---|
| height | number | |
| width | number | |
| x | number | |
| y | number |
ResolvedNoteNumberinginterfaceSource ↗
Resolved note-numbering fields after document/section cascade.
interface ResolvedNoteNumbering| Member | Type | Summary |
|---|---|---|
| numFmt | string | |
| numRestart | string | |
| numStart | number | |
| pos | string |
ReviewActivationOptionsinterfaceSource ↗
How activating a review item places it in the viewport.
interface ReviewActivationOptions| Member | Type | Summary |
|---|---|---|
| reveal? | 'start' | 'center' | 'centerIfNeeded' | 'nearest' | false | Where the item lands, or `false` to select it without scrolling at all. |
ReviewCommentIteminterfaceSource ↗
One comment as a review card. A reply carries parentId; OOXML gives replies no separate element, so threads are reconstructed from that link.
interface ReviewCommentItem| Member | Type | Summary |
|---|---|---|
| comment | CommentRecord | |
| id | string | |
| kind | 'comment' | |
| orphaned | boolean | True when the file gave this comment no usable range. |
| parentId? | string | The comment this replies to, absent for a top-level comment. |
| parentRevisionId? | string | The REVISION this comment answers, when it covers exactly that change's characters. |
| range | ReviewRange | null | |
| replyIds | readonly string[] | Replies to this comment, in document order. Empty for a reply or a childless comment. |
| resolved | boolean |
ReviewCommentPlacementinterfaceSource ↗
A comment thread's card.
interface ReviewCommentPlacement extends ReviewItemPlacementBase| Member | Type | Summary |
|---|---|---|
| item | ReviewCommentItem | |
| kind | 'comment' | |
| parentId? | string | The comment this replies to, absent at the top of a thread. |
| parentRevisionId? | string | The REVISION this comment answers, absent unless it does. |
| resolved | boolean | Whether `w15:commentsEx` marks the thread done. |
ReviewCustomIteminterfaceSource ↗
A card contributed by a recognized custom node (defineCustomNode with a reviewCard hook), anchored at the node's range.
Informational, never resolvable: there is nothing to accept or reject, so the engine refuses those verbs on it. title and detail are HOST-authored (the definition's hook produced them), but attrs and text originate in a file an attacker controls — a surface renders every one of these as text, never markup.
interface ReviewCustomItem| Member | Type | Summary |
|---|---|---|
| attrs | Readonly<Record<string, string>> | Attrs decoded from the tag, after the definition's recognition hook. Untrusted input. |
| carded | boolean | Whether this node asked for a sidebar card. |
| data? | unknown | The payload the node's control binds to, after the definition validated it. |
| detail? | string | Card body, from the definition's `reviewCard` hook. |
| icon? | string | Glyph for this node in the collapsed rail, as an SVG path in a `0 -960 960 960` viewBox. |
| id | string | The SDT node's stable id in the canonical tree. |
| kind | 'custom' | |
| name | string | The definition's `name`. |
| range | ReviewRange | null | |
| tag | string | The raw `w:tag` the node was recognized from. Untrusted input. |
| text | string | The SDT's literal content text. Untrusted input. |
| title | string | Card title, from the definition's `reviewCard` hook. Empty when `carded` is false. |
ReviewCustomPlacementinterfaceSource ↗
A custom node's card (defineCustomNode with a reviewCard hook).
interface ReviewCustomPlacement extends ReviewItemPlacementBase| Member | Type | Summary |
|---|---|---|
| item | ReviewCustomItem | |
| kind | 'custom' |
ReviewItemPlacementBaseinterfaceSource ↗
What every review card carries, whatever kind of decision it represents.
Presentation-ready by design: author, initials, date and text are derived by the ENGINE, because deriving them means walking runs and reading w15:commentsEx. An adapter doing that walk would put document derivation in the host and would have to be written once per framework.
interface ReviewItemPlacementBase| Member | Type | Summary |
|---|---|---|
| activatable | boolean | Whether [Editor.setActiveReviewItem](Editor.setActiveReviewItem) would take this key. |
| anchorY | number | null | Document-space Y of the anchor, or null when the item has no resolvable range. |
| author | string | |
| date? | string | `@w:date`, absent when the file omits it — Word does when date stamping is off. |
| id | string | The engine's own id for the comment, the revision, or the custom node. |
| initials | string | Initials for an avatar: `@w:initials` when the file carries one, else from the name. |
| isActive | boolean | |
| key | string | Stable and unique per DECISION — a revision with three ranges is one entry. |
| pageIndex | number | null | |
| readOnly | boolean | True when the engine cannot resolve this kind structurally, so accept and reject must not be offered. A card offering a button the engine will refuse is worse than one that explains why it cannot. |
| replyIds | readonly string[] | Replies to this item, in document order. |
| text | string | The comment's body, the words the revision covers, or the custom card's detail. |
ReviewItemQueryinterfaceSource ↗
Narrows what getReviewItems returns.
Both fields exist to keep the review rail cheap: filtering revision kinds is how a host hides structural cards it has no UI for, and placement: false skips the layout pass entirely when only metadata is wanted.
interface ReviewItemQuery| Member | Type | Summary |
|---|---|---|
| excludeRevisionKinds? | readonly ReviewRevisionKind[] | |
| placement? | boolean | When false, skip layout geometry; metadata is unchanged and anchors are null. Default true. |
ReviewModelInputinterfaceSource ↗
What the review queue derivation reads: one story part plus its comment parts.
interface ReviewModelInput| Member | Type | Summary |
|---|---|---|
| commentsExtendedPart? | OoxmlPart | undefined | `word/commentsExtended.xml`, absent when the package has none. |
| commentsPart? | OoxmlPart | undefined | `word/comments.xml`, absent when the package has none. |
| customNodePayloads? | ReadonlyMap<string, {
readonly nodeId: string;
readonly label: string;
readonly data: string;
}> | undefined | |
| customNodes? | readonly unknown[] | undefined | Custom node definitions from the module registry, forwarded OPAQUELY. |
| furnitureParts? | readonly OoxmlPart[] | undefined | Header/footer story parts, in section order. Their revisions and comment anchors join the queue: a tracked change in a header is a pending decision like any other, and a queue that only walked the body silently hid it from the rail AND from Accept All. |
| reportCustomNodeDiagnostic? | ((diagnostic: unknown) => void) | undefined | Where a capability package reports a node it could not read. Supplied per editor, so a page with two of them keeps their diagnostics apart. |
| storyPart | OoxmlPart | The story the ranges live in — the main document, a header, a note. |
ReviewModuleContributioninterfaceSource ↗
What a review module contributes: the queue derivation, and the revision display modes the editor may enter beyond the free tier's final-state projection.
interface ReviewModuleContribution| Member | Type | Summary |
|---|---|---|
| collectReviewItems | CollectReviewItems | The review queue derivation. |
| displayModes | readonly RevisionDisplayMode[] | Display modes this module unlocks (the free engine renders `proposed` only). |
| revisionItemsOfParagraph | (part: OoxmlPart, paragraphId: string) => readonly ReviewRevisionItem[] | Revisions wholly inside one paragraph — for the conservative local review patch after a text-local body edit. |
ReviewPositioninterfaceSource ↗
A position in the model offset space of one story.
interface ReviewPosition| Member | Type | Summary |
|---|---|---|
| offset | number | |
| paragraphId | string |
ReviewRangeinterfaceSource ↗
Where an item is anchored: a range in one story.
interface ReviewRange| Member | Type | Summary |
|---|---|---|
| end | ReviewPosition | |
| partName | string | |
| start | ReviewPosition |
ReviewRevisionIteminterfaceSource ↗
One tracked change as a review card.
Keyed per DECISION rather than per site: a revision spanning three ranges is one card, because accepting it accepts all three.
interface ReviewRevisionItem| Member | Type | Summary |
|---|---|---|
| address | RevisionAddress | The payload `acceptRevision` / `rejectRevision` take. |
| addresses | readonly RevisionAddress[] | EVERY address this decision covers, `address` first. |
| author | string | |
| date? | string | |
| id | string | Stable across renders and unique per DECISION, not per site. |
| kind | 'revision' | |
| pairedWith? | string | The other half of a move, or the other side of a delete/insert replacement. |
| ranges | readonly ReviewRange[] | Every site this decision touches, in document order. |
| readOnly | boolean | True when the engine cannot resolve this kind, so accept and reject must not be offered. |
| replacedRangeCount? | number | How many leading `ranges` are the STRUCK half of a replacement. |
| replacedText | string | The words a replacement removes. Empty for every other kind. |
| replyIds | readonly string[] | Comments answering this change, in document order. |
| revisionKind | ReviewRevisionKind | |
| text | string | Text the revision covers, for the card summary. Empty for changes with no characters. |
ReviewRevisionPlacementinterfaceSource ↗
A tracked change's card.
interface ReviewRevisionPlacement extends ReviewItemPlacementBase| Member | Type | Summary |
|---|---|---|
| item | ReviewRevisionItem | |
| kind | 'revision' | |
| replacedText? | string | The words a REPLACEMENT removes, when [revisionKind](revisionKind) is `'replace'`. |
| revisionKind | ReviewRevisionKind | Which decision this is. |
RevisioninterfaceSource ↗
One tracked change.
Addressing needs BOTH id and part: @w:id is unique only within a part, so an id alone names two revisions in any package that has a header or a comments part.
interface Revision| Member | Type | Summary |
|---|---|---|
| author | string | |
| date? | string | OPTIONAL. `CT_TrackChange` requires `@w:id` and `@w:author` and makes `@w:date` optional, and producers that omit it are ordinary. Requiring it here forced either a fabricated date — a content change — or dropping the revision from the list. |
| id | number | Numeric, and unique only WITHIN a part. Pair with `part` to address one. |
| part | string | REQUIRED, and a canonical PART NAME rather than a three-value enum. |
| type | RevisionType |
RevisionAddressinterfaceSource ↗
How a tracked change is addressed: its numeric id plus the PART it lives in.
Both, always — @w:id is unique only within a part, so an id alone names two revisions in any package with a header or a comments part.
interface RevisionAddress| Member | Type | Summary |
|---|---|---|
| author | string | |
| date? | string | Absent when the file wrote no `@w:date`; part of the identity either way. |
| id | string |
RuninterfaceSource ↗
A stretch of text sharing one set of character properties.
interface Run| Member | Type | Summary |
|---|---|---|
| formatting? | RunFormatting | |
| revisionId? | number | Set when the run carries a tracked change. Unique only within its part. |
| text | string |
RunFormattinginterfaceSource ↗
Character formatting, and — at selection level — the paragraph properties a toolbar reads alongside it.
One type serves both roles so a toolbar reads alignment, style and script state from the same object as bold and italic. On a [Run](Run) the selection-level fields stay absent: a run has no alignment or paragraph style of its own.
interface RunFormatting| Member | Type | Summary |
|---|---|---|
| alignment? | 'left' | 'center' | 'right' | 'both' | Paragraph alignment at the selection. `both` is OOXML's spelling of justify. |
| bold? | boolean | |
| color? | ColorValue | |
| fontFamily? | string | |
| fontSizePt? | number | |
| highlight? | string | |
| indent? | IndentFormatting | The EFFECTIVE paragraph indent at the selection — cascade and numbering merge included, so a numbered item that authors no `w:ind` reports the indent its list definition gives it. Absent when nothing is loaded, or when the selection is inside a table (see [IndentFormatting](IndentFormatting)). |
| italic? | boolean | |
| lineSpacing? | {
readonly rule: 'multiple' | 'exact' | 'atLeast';
readonly value: number;
} | Line spacing at the selection, in the unit its rule implies — LINES for `multiple`, points for `exact` and `atLeast`. The same vocabulary `setLineSpacing` takes, so a control can show what it reads and send back what it shows. Absent when the selection's paragraphs disagree or state no line spacing. |
| spaceAfterPt? | number | |
| spaceBeforePt? | number | Space above and below the paragraph at the selection, in points. |
| strike? | boolean | |
| styleId? | string | Paragraph style id (`w:pStyle`) at the selection. |
| subscript? | boolean | |
| superscript? | boolean | |
| underline? | boolean |
SectioninterfaceSource ↗
One section: the page it lays out on, and the header/footer stories it declares.
interface Section| Member | Type | Summary |
|---|---|---|
| footers | HeaderFooterSet | |
| headers | HeaderFooterSet | |
| properties | SectionProperties |
SectionPropertiesinterfaceSource ↗
w:sectPr: the page a section lays out on. Twips throughout, as the file stores them.
interface SectionProperties| Member | Type | Summary |
|---|---|---|
| columns? | {
count: number;
gapTwips: number;
} | |
| margins | PageMargins | |
| pageSize | {
widthTwips: number;
heightTwips: number;
} | |
| titlePage? | boolean | `w:titlePg` — whether the section's first page takes the `first` header/footer variant. |
SelectedImageStateinterfaceSource ↗
Canonical selected-image read model shared by [EditorSnapshot.image](EditorSnapshot.image) and [Editor.getSelectedImage](Editor.getSelectedImage).
interface SelectedImageState| Member | Type | Summary |
|---|---|---|
| canChangeWrap | boolean | |
| canCrop | boolean | |
| canMove | boolean | |
| canResize | boolean | |
| crop | ImageCropPercent | Crop inset per edge in UI percent (0–100); OOXML stores permille (×1000). |
| description | string | |
| heightEmu | number | |
| hyperlink | string | null | |
| id | string | |
| intrinsic | Readonly<{
readonly pixelWidth: number;
readonly pixelHeight: number;
readonly dpiX: number;
readonly dpiY: number;
}> | null | |
| kind | DrawingKind | |
| locks | DrawingLocks | |
| name | string | |
| position | DrawingPositionInput | null | |
| resourceStatus | ImageResourceState['kind'] | |
| rotationDegrees | number | |
| title | string | |
| widthEmu | number | |
| wrap | ImageWrapTarget |
SemanticIdentityinterfaceSource ↗
Model-derived stable identity within a scope. Positions resolve through this index, not accumulated display-item lengths or editing-engine coordinates.
interface SemanticIdentity| Member | Type | Summary |
|---|---|---|
| blockId | string | |
| storyId | string |
SemanticPositioninterfaceSource ↗
A caret position in the model.
interface SemanticPosition| Member | Type | Summary |
|---|---|---|
| offset | number | |
| paragraphId | string |
SemanticSelectioninterfaceSource ↗
A selection as two semantic positions — never as DOM nodes.
anchor is where the selection started and head is where it currently ends, so head before anchor is an ordinary backwards selection rather than an error. Collapsed when the two are equal, which is what a caret is.
interface SemanticSelection| Member | Type | Summary |
|---|---|---|
| anchor | SemanticPosition | |
| head | SemanticPosition |
StyleDefinitioninterfaceSource ↗
One style: the ID content references, the name a reader sees, and its inheritance link.
interface StyleDefinition| Member | Type | Summary |
|---|---|---|
| basedOn? | string | `w:basedOn` — the style this one inherits from. Absent at the root of a chain. |
| id | string | |
| name | string |
StyleDefinitionsinterfaceSource ↗
styles.xml, split by the three style families that address separately.
Keyed by style ID rather than by the name a reader sees, because the ID is what a paragraph or run actually references.
interface StyleDefinitions| Member | Type | Summary |
|---|---|---|
| character | ReadonlyMap<string, StyleDefinition> | |
| paragraph | ReadonlyMap<string, StyleDefinition> | |
| table | ReadonlyMap<string, StyleDefinition> |
SurfaceHyperlinkinterfaceSource ↗
A hyperlink as the surface reports it: its identity, where it sits, and the SANITIZED target. href: null is an inert link — a refused scheme or a dangling relationship — which a UI shows and offers to edit but must never offer to open.
interface SurfaceHyperlink| Member | Type | Summary |
|---|---|---|
| anchor? | string | |
| authored | string | The authored target, for an editor to seed its input with. |
| end | number | |
| href | string | null | Sanitized projection: an absolute URL, `#anchor`, or null when inert. |
| id | string | Canonical node id of the `w:hyperlink`. |
| kind | 'external' | 'internal' | 'unresolved' | |
| paragraphId | string | |
| start | number | UTF-16 range of the link's display text within its paragraph. |
| text | string | |
| tooltip? | string |
TableinterfaceSource ↗
A table: its rows, and the table style they resolve through.
interface Table| Member | Type | Summary |
|---|---|---|
| kind | 'table' | |
| rows | readonly TableRow[] | |
| styleId? | string |
TableBorderSpecinterfaceSource ↗
Complete border spec for [EditorCommands.setTableBorders](EditorCommands.setTableBorders). Size is in eighths of a point.
interface TableBorderSpec| Member | Type | Summary |
|---|---|---|
| color | ColorValue | |
| size | number | |
| style | TableBorderStyle |
TableCellinterfaceSource ↗
One cell. Its content is ordinary blocks, so a cell may hold paragraphs, nested tables and content controls alike.
interface TableCell| Member | Type | Summary |
|---|---|---|
| colSpan? | number | `w:gridSpan`. Absent means 1. |
| content | readonly Block[] | |
| rowSpan? | number | Vertical merge span. Absent means 1. |
TableColumnDividerResizeTargetinterfaceSource ↗
Adjacent grid columns addressed by an internal divider resize gesture.
sourceRevision is captured from the store revision when the target is built. Commit MUST refuse when it does not equal the current store revision, even if an older layout remains published for geometry.
interface TableColumnDividerResizeTarget| Member | Type | Summary |
|---|---|---|
| isHeaderRepeat | boolean | |
| leftGridColumnId | string | |
| rightGridColumnId | string | |
| sourceRevision | number | |
| tableId | string |
TableColumnOccurrenceTargetinterfaceSource ↗
Explicit column occurrence for furniture/context commands.
interface TableColumnOccurrenceTarget| Member | Type | Summary |
|---|---|---|
| gridColumnId | string | |
| isHeaderRepeat | boolean | |
| sourceRevision | number | |
| tableId | string |
TableContextinterfaceSource ↗
Where the caret sits inside a table: the table's shape, and the cell holding it.
Null from the tableContext query when the selection is not in a table at all, which is how table-only chrome decides whether to render.
interface TableContext| Member | Type | Summary |
|---|---|---|
| columnIndex | number | Zero-based, within the row. |
| columns | number | |
| rowIndex | number | Zero-based, within the table. |
| rows | number |
TableRightEdgeResizeTargetinterfaceSource ↗
Last grid column and table width addressed by an outer-right-edge resize gesture.
sourceRevision is captured from the store revision when the target is built. Commit MUST refuse when it does not equal the current store revision, even if an older layout remains published for geometry.
interface TableRightEdgeResizeTarget| Member | Type | Summary |
|---|---|---|
| gridColumnId | string | |
| isHeaderRepeat | boolean | |
| sourceRevision | number | |
| tableId | string |
TableRowinterfaceSource ↗
One table row. Cell count may vary between rows: colSpan and vertical merges reshape it.
interface TableRow| Member | Type | Summary |
|---|---|---|
| cells | readonly TableCell[] |
TableRowOccurrenceTargetinterfaceSource ↗
Explicit row occurrence for furniture/context commands.
interface TableRowOccurrenceTarget| Member | Type | Summary |
|---|---|---|
| isHeaderRepeat | boolean | |
| rowId | string | |
| sourceRevision | number | |
| tableId | string |
TextMatchinterfaceSource ↗
One occurrence of a search query in the document.
Carries TWO addresses on purpose. blockId + start is the engine's own: stable across edits and independent of ordering. paragraphIndex + runIndex + runOffset is the positional one a find/replace UI needs to show and navigate results, and it is derived from the same walk rather than left to the caller to reconstruct — a caller guessing at run boundaries would send the selection to the wrong place.
A match can span runs when formatting changes mid-word; the run address is where it STARTS.
interface TextMatch| Member | Type | Summary |
|---|---|---|
| blockId | string | |
| contextAfter? | string | |
| contextBefore? | string | Paragraph text immediately before and after the match, bounded at the derivation boundary. A results list shows the match in its sentence — "…as described in this **Exhi**bit A" — and nothing else in the contract can reach paragraph text, so a caller would otherwise have to re-read the document to render one row. |
| length | number | |
| paragraphIndex | number | Ordinal among PARAGRAPHS in the body, skipping tables and other non-paragraph blocks. |
| runIndex | number | Index of the run the match starts in, and the offset within that run. |
| runOffset | number | |
| start | number | Character offset within the paragraph's concatenated run text. |
| text | string | The matched text as it appears in the document. |
ThemeinterfaceSource ↗
theme1.xml — what a [ColorValue](ColorValue) of kind theme resolves against.
interface Theme| Member | Type | Summary |
|---|---|---|
| colorScheme | ThemeColorScheme | |
| fontScheme? | Record<string, string> |
ToolbarCommandStateinterfaceSource ↗
Whether one control is enabled, and the engine's reason when it is not.
interface ToolbarCommandState| Member | Type | Summary |
|---|---|---|
| active | boolean | Whether the command is currently APPLIED at the selection, from `Editor.isActive` — derived in the engine for marks and alignment, honest-false elsewhere. |
| disabledReason | string | null | The engine's reason when disabled — surfaced as a tooltip, never invented. |
| enabled | boolean | |
| id | ChromeSlotId | |
| value? | string | What the control currently SHOWS, for the slots whose answer is a value rather than a pressed state — the editing-mode pill, and image wrap when it lands. |
ValidatedImageBytesHandleinterfaceSource ↗
Opaque handle — bytes are reachable only through [mintValidatedImageBytes](mintValidatedImageBytes).
interface ValidatedImageBytesHandle| Member | Type | Summary |
|---|---|---|
| contentId | string | |
| generation | number | |
| registryId | number | |
| resourceKey | string |
WatermarkinterfaceSource ↗
A watermark, which OOXML expresses as either text or an image — never both meaningfully.
interface Watermark| Member | Type | Summary |
|---|---|---|
| imageData? | Uint8Array | |
| text? | string |
Type aliases (53)
BlocktypeSource ↗
Anything that can sit at block level in a story. Discriminate on kind.
type Block = Paragraph | Table | ContentControl;CanResulttypeSource ↗
Whether a command would be accepted, and why not when it would not.
The reason is the ENGINE's own words, which is what lets disabled chrome explain itself instead of guessing — see toolbarCommandState.
type CanResult = {
ok: true;
} | {
ok: false;
code: ExecErrorCode;
reason: string;
};ChromeMenuEntrytypeSource ↗
One row of a chrome menu.
type ChromeMenuEntry = ChromeMenuItemEntry | ChromeMenuSubmenuEntry | ChromeMenuSeparatorEntry;ChromeMenuIdtypeSource ↗
Every menu id, as a literal union. Stable public API; renaming one is a breaking change, exactly like a group or slot id.
type ChromeMenuId = 'file' | 'format' | 'insert' | 'help';ChromeSlotIdtypeSource ↗
The public slot vocabulary: ${groupId}.${controlId} for every control that actually exists — text.bold, font.family, alignment.left. THE stable contract a host composes against and commandForSlot resolves; renaming a slot is a breaking change.
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';CollectReviewItemstypeSource ↗
Derives the review queue — every pending revision decision and comment thread — from one story part plus its comment parts. Implemented by the pro review module; the free engine has no implementation and reports an empty queue.
type CollectReviewItems = (input: ReviewModelInput) => readonly ReviewItem[];ColorValuetypeSource ↗
A colour as the FILE expresses it, not as a resolved RGB string.
A theme colour stays a theme reference — slot plus tint or shade — so that changing the theme repaints the document the way Word does. Flattening to hex at read time would freeze the resolved value and break that link. auto is Word's "let the renderer decide", usually black on white.
type ColorValue = {
readonly kind: 'hex';
readonly value: string;
} | {
readonly kind: 'theme';
readonly slot: string;
readonly tint?: number;
readonly shade?: number;
} | {
readonly kind: 'auto';
};ContainerReftypeSource ↗
Which STORY a location belongs to.
The body is one container; every header, footer and note is another. A path alone is ambiguous without it, because block index 0 exists in every story a document has.
type ContainerRef = {
part: 'body';
} | {
part: 'header' | 'footer';
rId: string;
} | {
part: 'footnote' | 'endnote';
noteId: number;
};ContentControlTypetypeSource ↗
Which kind of control a w:sdt is, and therefore what a value written into it must be.
type ContentControlType = 'richText' | 'plainText' | 'checkbox' | 'dropdown' | 'comboBox' | 'date' | 'picture' | 'repeatingSection';DocEdittypeSource ↗
One edit, as a discriminated union derived from [DocEdits](DocEdits).
Adding a key to DocEdits — including by declaration merging from a plugin — widens this automatically, so the union never drifts from the vocabulary it is built out of.
type DocEdit = {
[K in keyof DocEdits]: {
type: K;
} & DocEdits[K];
}[keyof DocEdits];DocQuerytypeSource ↗
One query, as a discriminated union derived from [DocQueries](DocQueries).
type DocQuery = {
[K in keyof DocQueries]: {
type: K;
} & DocQueries[K];
}[keyof DocQueries];DocTargettypeSource ↗
Anything an operation can be pointed at: a paragraph-relative [DocAnchor](DocAnchor), a structural [DocLocation](DocLocation), or a [DocRange](DocRange) spanning two of them.
type DocTarget = DocAnchor | DocLocation | DocRange;DocumentEditingModetypeSource ↗
How a keystroke reaches the document.
'suggesting' changes what an edit MEANS rather than whether it is allowed: typing writes w:ins and deleting writes w:del over the words it would have removed, so every change arrives as a proposal somebody else accepts or rejects.
type DocumentEditingMode = 'editing' | 'suggesting' | 'viewing';DocumentSourcetypeSource ↗
What createDocxEditor/load accept as a document: raw DOCX bytes, or an existing in-memory DocumentHandle (shared/handed off). The engine is byte-native (PackageModel is canonical); there is intentionally no structured-tree input, which would be lossy against the canonical package.
type DocumentSource = ArrayBuffer | Uint8Array | DocumentHandle;DrawingHorizontalReferenceFrametypeSource ↗
type DrawingHorizontalReferenceFrame = 'character' | 'column' | 'insideMargin' | 'leftMargin' | 'margin' | 'outsideMargin' | 'page' | 'rightMargin';DrawingKindtypeSource ↗
Whether a drawing sits in the text flow or is positioned against a frame.
The distinction that decides everything downstream: an inline drawing occupies a character position, while an anchored one has offsets relative to a page, margin or column.
type DrawingKind = 'inline' | 'anchored';DrawingVerticalReferenceFrametypeSource ↗
type DrawingVerticalReferenceFrame = 'bottomMargin' | 'insideMargin' | 'line' | 'margin' | 'outsideMargin' | 'page' | 'paragraph' | 'topMargin';EditorCommandtypeSource ↗
One command, as a discriminated union derived from [EditorCommands](EditorCommands).
This is what can and exec take. Widening EditorCommands widens it automatically.
type EditorCommand = {
[K in keyof EditorCommands]: {
type: K;
} & EditorCommands[K];
}[keyof EditorCommands];EditorCommandShapetypeSource ↗
In the editor a command targets the current selection unless told otherwise, and authoring is ambient — the author comes from DocxEditorConfig/the session, the way the Office JS API sources it from context — so the document layer's required target and author both become optional here.
type EditorCommandShape<T> = {
[K in keyof T]: Omit<T[K], 'target' | 'author'> & (T[K] extends {
target: infer G;
} ? {
target?: G;
} : unknown) & (T[K] extends {
author: infer A;
} ? {
author?: A;
} : unknown);
};EditorFontErrorCodetypeSource ↗
Why a font was not admitted.
Distinguished rather than collapsed because the responses differ: overLimit and malformed are the caller's own bytes, while forbidden and hashMismatch mean the source was not what it claimed and the load should not be retried.
type EditorFontErrorCode = 'initializationFailed' | 'missing' | 'forbidden' | 'overLimit' | 'malformed' | 'hashMismatch' | 'metadataMismatch' | 'fontFaceLoadFailed' | 'unsupportedFaceIndex' | 'missingFont' | 'hashInvalid' | 'fontMismatch' | 'unsupportedFace' | 'loadFailed';EditorPositiontypeSource ↗
A selection endpoint, in either vocabulary the engine resolves.
[DocAnchor](DocAnchor) addresses a paragraph by its w14:paraId, which is what an LLM or an automation script can name in a payload. [SemanticPosition](SemanticPosition) addresses it by the paragraph id the painted surface and the ops already use, with a UTF-16 offset inside it.
Neither subsumes the other. A paraId survives being written to a file and read back, so it is the one an out-of-process caller can hold; but it is OPTIONAL in the document, and ParagraphSummary.paraId says so — a paragraph the file gave no w14:paraId cannot be reached by a DocAnchor at all. The paragraph id reaches every paragraph.
type EditorPosition = DocAnchor | SemanticPosition;EditorQuerytypeSource ↗
One query, as a discriminated union derived from [EditorQueries](EditorQueries).
This is what query takes; [EditorQueryResults](EditorQueryResults) says what each answers.
type EditorQuery = {
[K in keyof EditorQueries]: {
type: K;
} & EditorQueries[K];
}[keyof EditorQueries];EditorScopetypeSource ↗
The editor is N+1 editing views: one body plus one per header/footer relationship, plus footnotes, text boxes, and other addressable regions. Commands must say which one they target, or they silently hit the wrong surface when a header is focused.
Intentionally open-ended: this set is expected to grow (notes, frames, and whatever regions later prove addressable), so treat it as non-exhaustive rather than a closed enum.
type EditorScope = {
kind: 'body';
} | {
kind: 'headerFooter';
rId: string;
}
/**
* A footnote/endnote region.
*
* `id` encodes kind + signed note id as `footnote:<id>` or `endnote:<id>`
* (e.g. `footnote:2`). Use `formatNoteScopeId` / `parseNoteScopeId` from the
* store package. Do not invent a parallel `{ noteKind, noteId }` scope arm.
*/
| {
kind: 'note';
id: string;
}
/** A text box or floating frame with its own content, addressed by id. */
| {
kind: 'frame';
id: string;
}
/** Read-only aggregate across every view. Valid for queries, not for writes. */
| {
kind: 'all';
};EditorSelectiontypeSource ↗
A selection, in one endpoint vocabulary or the other.
The two do NOT mix: a range is a pair of paraId anchors, or a semantic anchor/head pair, and can() refuses anything else with the engine's own reason. Spelled as two arms rather than { from: EditorPosition; to: EditorPosition } for exactly that reason — the looser shape would type a mixed pair the engine rejects at runtime.
type EditorSelection = SemanticSelection | {
from: DocAnchor;
to: DocAnchor;
};ExecErrorCodetypeSource ↗
Why a write was refused, as a value to branch on.
Deliberately finer-grained than a boolean: "no-op", "target not found" and "content control is locked" are different outcomes, and a caller retrying the first should not retry the third.
type ExecErrorCode = 'notFound' | 'ambiguous' | 'locked' | 'bound' | 'typeMismatch' | 'kindMismatch' | 'outOfBounds' | 'unsupported' | 'invalidArgs';ExecResulttypeSource ↗
Every write returns this rather than boolean.
A bare boolean cannot distinguish "no-op" from "target not found" from "content control is locked", and the editor layer already throws eight distinct ContentControl error classes that a boolean would flatten.
type ExecResult = {
ok: true;
changed: boolean;
} | {
ok: false;
code: ExecErrorCode;
reason: string;
target?: DocTarget;
};FontLoadFailureReasontypeSource ↗
Why one font did not load.
Distinguished rather than collapsed to "failed" because the responses differ: networkError and httpError are worth retrying, while hashMismatch and malformed mean the bytes were not what the source claimed and retrying will fetch the same wrong thing.
type FontLoadFailureReason = 'networkError' | 'httpError' | 'hashMismatch' | 'overLimit' | 'emptyResponse'
/** The declared face itself is unusable (empty family, out-of-range weight); nothing was fetched. */
| 'invalidRequest'
/** The bytes are not a font at all — most often an HTML error page served with 200. */
| 'malformed';FontResolvertypeSource ↗
Resolve fonts once the document's needs are known, instead of ahead of them.
Called once per load, AFTER the file is parsed and mounted, with the families it declares; whatever it returns composes exactly like a statically supplied fragment. Returning nothing is a valid answer — it means "I cover none of this", and the document stays on the fixed measurer.
A resolver that fetches makes opening a document perform network requests. That is a real change in posture and it must stay the APP's decision: the engine never supplies one, and the families here are file-derived, so a resolver must look them up in a set it shipped rather than interpolate them into a URL.
type FontResolver = (request: FontResolutionRequest) => FontConfiguration | FontConfigurationFragment | undefined | Promise<FontConfiguration | FontConfigurationFragment | undefined>;FurnitureVarianttypeSource ↗
Furniture variant selected by section title-page / even-and-odd flags.
type FurnitureVariant = 'default' | 'first' | 'even';ImageContexttypeSource ↗
The selected image and what may be done to it — the imageContext query's answer.
An alias of SelectedImageState, kept as its own name because it is the query's result type and chrome is written against it.
type ImageContext = SelectedImageState;ImageResourceStatetypeSource ↗
What is known about one embedded image: validated, refused, or still decoding.
Content type is a CLAIM. Signature sniffing, structural header validation and the decode port are authoritative, and bytes that fail them never enter public state.
type ImageResourceState = {
readonly kind: 'ready';
readonly partName: string;
readonly contentId: string;
readonly resourceKey: string;
readonly validatedHandle: ValidatedImageBytesHandle;
readonly mime: RenderableImageMime;
readonly pixelWidth: number;
readonly pixelHeight: number;
readonly dpiX: number;
readonly dpiY: number;
} | {
readonly kind: 'unrenderable';
readonly partName: string | null;
readonly mime: RenderableImageMime | PreservedImageMime | 'unknown';
readonly reason: 'unsupported-format' | 'non-picture-graphic' | 'signature-mismatch' | 'decode-failed' | 'resource-limit';
} | {
readonly kind: 'external';
readonly relationshipId: string;
readonly sinkSafe: boolean;
} | {
readonly kind: 'missing';
readonly relationshipId: string;
} | {
readonly kind: 'pending';
readonly resourceKey: string;
};ImageWrapTargettypeSource ↗
Nine Word wrap menu targets (inline plus eight floating modes).
type ImageWrapTarget = 'inline' | 'square' | 'squareLeft' | 'squareRight' | 'tight' | 'through' | 'topAndBottom' | 'behind' | 'inFront';InteractionAffinitytypeSource ↗
Bidi/grapheme affinity for a text caret or hit target.
type InteractionAffinity = 'upstream' | 'downstream';InteractionOutcometypeSource ↗
The result of one interaction attempt.
A rejection carries the ENGINE's own reason, which is what lets a caller surface why an interaction was refused instead of guessing.
type InteractionOutcome<T> = {
readonly ok: true;
readonly value: T;
} | {
readonly ok: false;
readonly code: InteractionOutcomeCode;
readonly reason: string;
};InteractionOutcomeCodetypeSource ↗
Typed rejection for pending, read-only, invalid, or unsupported interaction.
type InteractionOutcomeCode = 'pendingLayout' | 'pendingSelection' | 'readOnly' | 'invalidTarget' | 'unsupported';NoteKindtypeSource ↗
Footnote vs endnote — the public Editor vocabulary.
type NoteKind = 'footnote' | 'endnote';PreservedImageMimetypeSource ↗
Media kept in the package byte-for-byte that the painter cannot hand to an <img>. A decode port may rasterize it; without one it paints as a labelled placeholder.
type PreservedImageMime = 'image/tiff' | 'image/x-emf' | 'image/x-wmf';RenderableImageMimetypeSource ↗
Every mime the painter can hand to an <img>.
type RenderableImageMime = SupportedImageMime | VectorImageMime;ReviewItemtypeSource ↗
One pending decision in the review queue: a tracked change, a comment thread, or a pro custom-node card. Discriminate on kind.
type ReviewItem = ReviewRevisionItem | ReviewCommentItem | ReviewCustomItem;ReviewItemPlacementtypeSource ↗
A DISCRIMINATED union on [ReviewItemPlacementBase.kind](ReviewItemPlacementBase.kind): narrowing the kind narrows item and the kind-specific fields with it, so a consumer never writes the placement.kind === 'custom' && placement.item.kind === 'custom' double check.
type ReviewItemPlacement = ReviewCommentPlacement | ReviewRevisionPlacement | ReviewCustomPlacement;ReviewRevisionKindtypeSource ↗
What kind of decision a revision card represents.
Wider than the four content wrappers, because a reviewer has to be shown every pending decision, including the ones that decorate no characters. A card the surface cannot show is a change the reviewer never learns about — and acceptAllRevisions refuses if ANY revision in the document is one the engine cannot resolve, so an invisible one makes Accept All fail for a reason nothing on screen explains.
type ReviewRevisionKind = 'insert' | 'delete'
/**
* A deletion and an insertion that are one edit: text typed over a selection.
*
* Word shows these as a single `Replaced "x" with "y"` card, and resolving one half
* without the other is never what the reviewer meant — accepting the deletion alone
* leaves the replacement text unproposed, rejecting it alone leaves both.
*/
| 'replace' | 'moveFrom' | 'moveTo'
/** `w:rPrChange` / `w:pPrChange` — the words are unchanged, their formatting is not. */
| 'format'
/** `w:pPr/w:rPr/w:ins|w:del` — a paragraph split or merge. */
| 'paragraphMark'
/** A row, cell, section or grid revision. Supported row revisions are resolvable. */
| 'structural';RevisionDisplayModetypeSource ↗
Which revisions layout resolves before producing pages.
- all-markup shows both halves of every change. - proposed shows what the document becomes if every change is accepted. - original shows what it was before any of them.
The last two are specified as equal to accept-all and reject-all OUTPUT, which is what makes them testable, without either applying an op.
type RevisionDisplayMode = 'all-markup' | 'proposed' | 'original';RevisionTypetypeSource ↗
What kind of decision a revision represents.
Wider than insert/delete/format, and it has to be. w:moveFrom/w:moveTo are not a deletion and an insertion — resolving one half alone duplicates or loses the content; w:pPr/w:rPr/w:ins|w:del decorates no characters at all and merges paragraphs when resolved; a row or cell revision is structural. A reviewer shown only three kinds is a reviewer who never learns about the rest.
type RevisionType = 'insert' | 'delete'
/** A deletion and an insertion that are one edit: text typed over a selection. */
| 'replace' | 'moveFrom' | 'moveTo'
/** `w:rPrChange` / `w:pPrChange` — the words are unchanged, their formatting is not. */
| 'format'
/** `w:pPr/w:rPr/w:ins|w:del` — a paragraph split or merge. */
| 'paragraphMark'
/** A row, cell, section or grid revision. */
| 'structural';SemanticTargettypeSource ↗
A PM-free semantic caret, range endpoint, or atomic selection target.
type SemanticTarget = {
readonly kind: 'text';
readonly scope: ViewScope;
readonly identity: SemanticIdentity;
readonly graphemeOffset: number;
readonly affinity: InteractionAffinity;
} | {
readonly kind: 'atomic';
readonly scope: ViewScope;
readonly objectId: string;
};SupportedImageMimetypeSource ↗
Raster media the decode port measures and any authoring path may write.
BMP and WebP are here for the same reason the other three are: an <img> decodes them natively, so they need a signature and a structural header and nothing else. BMP is what older documents carry; WebP is what current Word writes.
type SupportedImageMime = 'image/png' | 'image/jpeg' | 'image/gif' | 'image/bmp' | 'image/webp';TableBorderEdgeTargettypeSource ↗
Concrete scopes that apply a complete border spec.
type TableBorderEdgeTarget = Exclude<TableBorderTarget, 'none'>;TableBorderStyletypeSource ↗
Allowlisted OOXML table border line styles.
Kept identical to store/table-border-style.ts; table-border-style-parity.test-d.ts fails if the contract and store vocabularies drift.
type TableBorderStyle = 'single' | 'dashed' | 'dotted' | 'double' | 'triple' | 'thick';TableBorderTargettypeSource ↗
Which cell edges a table border command targets.
type TableBorderTarget = 'all' | 'outside' | 'inside' | 'none' | 'top' | 'bottom' | 'left' | 'right';TableCellVerticalAlignmenttypeSource ↗
Vertical placement of content inside selected table cells.
type TableCellVerticalAlignment = 'top' | 'center' | 'bottom';ThemeColorSchemetypeSource ↗
Theme colour slots (accent1, dk1, lt2, …) to hex.
type ThemeColorScheme = Readonly<Record<string, string>>;UnsubscribetypeSource ↗
What every subscription returns. Calling it twice is safe.
type Unsubscribe = () => void;VectorImageMimetypeSource ↗
Vector media painted straight from validated bytes. An <img> renders SVG in the browser's secure static mode — no script, no external subresource loads — so there is no decode step and no raster buffer sized by a file-supplied number.
type VectorImageMime = 'image/svg+xml';ViewScopetypeSource ↗
A concrete editing view — every scope except the read-only all aggregate.
type ViewScope = Exclude<EditorScope, {
kind: 'all';
}>;Variables (3)
CHROME_GROUPSconstSource ↗
The complete chrome, in bar order. Literal-typed (as const) so the slot-id vocabulary below is derived from the data and cannot drift from it.
Taxonomy taste: ids are short, lowercaseCamel, and never repeat their group's name (alignment.left, not alignment.alignLeft; font.family, not font.fontFamily).
CHROME_GROUPS: readonly [{
readonly id: "history";
readonly labelKey: "formattingBar.groups.history";
readonly controls: readonly [{
readonly id: "undo";
readonly labelKey: "formattingBar.undoShortcut";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "redo";
readonly labelKey: "formattingBar.redoShortcut";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "zoom";
readonly labelKey: "formattingBar.groups.zoom";
readonly controls: readonly [{
readonly id: "level";
readonly shape: "stepper";
readonly valueText: "100%";
readonly labelKey: "formattingBar.groups.zoom";
readonly paths: null;
readonly valueKey: "zoom.zoomLevel";
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "styles";
readonly labelKey: "formattingBar.groups.styles";
readonly controls: readonly [{
readonly id: "style";
readonly shape: "dropdown";
readonly labelKey: "styles.selectAriaLabel";
readonly paths: null;
readonly valueKey: "styles.normalText";
readonly state: {
readonly kind: "value";
};
}];
}, {
readonly id: "font";
readonly labelKey: "formattingBar.groups.font";
readonly controls: readonly [{
readonly id: "family";
readonly shape: "dropdown";
readonly labelKey: "font.selectAriaLabel";
readonly paths: null;
readonly valueKey: "font.sansSerif";
readonly state: {
readonly kind: "value";
};
}, {
readonly id: "size";
readonly shape: "stepper";
readonly valueText: "11";
readonly labelKey: "fontSize.listLabel";
readonly paths: null;
readonly valueKey: "fontSize.label";
readonly state: {
readonly kind: "value";
};
}];
}, {
readonly id: "text";
readonly labelKey: "formattingBar.groups.textFormatting";
readonly controls: readonly [{
readonly id: "bold";
readonly labelKey: "formattingBar.boldShortcut";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "italic";
readonly labelKey: "formattingBar.italicShortcut";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "underline";
readonly labelKey: "formattingBar.underlineShortcut";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "strike";
readonly labelKey: "formattingBar.strikethrough";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "color";
readonly shape: "colorSplit";
readonly swatch: "#ff0000";
readonly labelKey: "formattingBar.fontColor";
readonly paths: readonly string[];
readonly state: {
readonly kind: "value";
};
}, {
readonly id: "highlight";
readonly shape: "colorSplit";
readonly swatch: "#ffff00";
readonly labelKey: "formattingBar.highlightColor";
readonly paths: readonly string[];
readonly state: {
readonly kind: "value";
};
}, {
readonly id: "link";
readonly labelKey: "formattingBar.insertLinkShortcut";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "script";
readonly labelKey: "formattingBar.groups.script";
readonly controls: readonly [{
readonly id: "super";
readonly labelKey: "formattingBar.superscript";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "sub";
readonly labelKey: "formattingBar.subscript";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "alignment";
readonly labelKey: "formattingBar.groups.alignment";
readonly controls: readonly [{
readonly id: "left";
readonly labelKey: "alignment.alignLeft";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "center";
readonly labelKey: "alignment.center";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "right";
readonly labelKey: "alignment.alignRight";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "justify";
readonly labelKey: "alignment.justify";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "list";
readonly labelKey: "formattingBar.groups.listFormatting";
readonly controls: readonly [{
readonly id: "bullet";
readonly labelKey: "lists.bulletList";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "numbered";
readonly labelKey: "lists.numberedList";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "outdent";
readonly labelKey: "lists.decreaseIndent";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "indent";
readonly labelKey: "lists.increaseIndent";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "lineSpacing";
readonly shape: "dropdown";
readonly labelKey: "lineSpacing.label";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "format";
readonly labelKey: "formattingBar.clearFormatting";
readonly controls: readonly [{
readonly id: "clear";
readonly labelKey: "formattingBar.clearFormatting";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "review";
readonly labelKey: "formattingBar.commentsAndChanges";
readonly controls: readonly [{
readonly id: "comments";
readonly shape: "icon";
readonly labelKey: "formattingBar.commentsAndChanges";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "editingMode";
readonly shape: "dropdown";
readonly labelKey: "editingMode.label";
readonly valueKey: "editingMode.editing";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "contentControl";
readonly labelKey: "contentControl.group";
readonly contextual: true;
readonly controls: readonly [{
readonly id: "showAll";
readonly labelKey: "contentControl.showAll";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "formFill";
readonly labelKey: "contentControl.formFill";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "inspector";
readonly labelKey: "contentControl.inspector";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "remove";
readonly labelKey: "contentControl.remove";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "image";
readonly labelKey: "formattingBar.groups.image";
readonly contextual: true;
readonly controls: readonly [{
readonly id: "insert";
readonly labelKey: "toolbar.image";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "properties";
readonly labelKey: "formattingBar.imagePropertiesShortcut";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "wrap";
readonly shape: "dropdown";
readonly labelKey: "formattingBar.imageWrap";
readonly paths: readonly string[];
readonly valueKey: "imageWrap.inline";
readonly state: {
readonly kind: "value";
};
}, {
readonly id: "altText";
readonly shape: "dropdown";
readonly labelKey: "formattingBar.altText";
readonly paths: null;
readonly valueKey: "imageProperties.altText";
readonly state: {
readonly kind: "value";
};
}];
}, {
readonly id: "table";
readonly labelKey: "formattingBar.groups.table";
readonly contextual: true;
readonly controls: readonly [{
readonly id: "insert";
readonly labelKey: "toolbar.table";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "borderTarget";
readonly shape: "dropdown";
readonly labelKey: "table.borders.tooltip";
readonly paths: readonly string[];
readonly state: {
readonly kind: "value";
};
}, {
readonly id: "borderColor";
readonly shape: "colorSplit";
readonly swatch: "#000000";
readonly labelKey: "table.borderColor";
readonly paths: readonly string[];
readonly state: {
readonly kind: "value";
};
}, {
readonly id: "borderStyle";
readonly shape: "dropdown";
readonly labelKey: "table.borders.styleAriaLabel";
readonly paths: readonly string[];
readonly state: {
readonly kind: "value";
};
}, {
readonly id: "borderWidth";
readonly shape: "dropdown";
readonly labelKey: "table.borderWidth";
readonly paths: readonly string[];
readonly state: {
readonly kind: "value";
};
}, {
readonly id: "cellFill";
readonly shape: "colorSplit";
readonly swatch: "#ffffff";
readonly labelKey: "table.cellFillColor";
readonly paths: readonly string[];
readonly state: {
readonly kind: "value";
};
}];
}, {
readonly id: "file";
readonly labelKey: "toolbar.file";
readonly contextual: true;
readonly controls: readonly [{
readonly id: "open";
readonly labelKey: "toolbar.open";
readonly paths: readonly string[];
readonly state: {
readonly kind: "load";
};
}, {
readonly id: "save";
readonly labelKey: "toolbar.saveShortcut";
readonly paths: readonly string[];
readonly state: {
readonly kind: "save";
};
}, {
readonly id: "pageSetup";
readonly labelKey: "toolbar.pageSetup";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}, {
readonly id: "insert";
readonly labelKey: "toolbar.insert";
readonly contextual: true;
readonly controls: readonly [{
readonly id: "footnote";
readonly labelKey: "toolbar.insertFootnote";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "endnote";
readonly labelKey: "toolbar.insertEndnote";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "pageNumber";
readonly labelKey: "headerFooter.insertPageNumber";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "totalPages";
readonly labelKey: "headerFooter.insertTotalPages";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "sectionPages";
readonly labelKey: "headerFooter.insertSectionPages";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "pageXofY";
readonly labelKey: "headerFooter.insertPageXofY";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "pageBreak";
readonly labelKey: "toolbar.pageBreak";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "sectionBreakNextPage";
readonly labelKey: "toolbar.sectionBreakNextPage";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "sectionBreakContinuous";
readonly labelKey: "toolbar.sectionBreakContinuous";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}, {
readonly id: "toc";
readonly labelKey: "toolbar.tableOfContents";
readonly paths: readonly string[];
readonly state: {
readonly kind: "command";
};
}];
}]CHROME_MENUSconstSource ↗
The menu bar the chrome shows above the toolbar, in bar order: File, Format, Insert, Help.
CHROME_MENUS: readonly ChromeMenu[]WORD_DEFAULT_FONTconstSource ↗
Word's document default when nothing else says otherwise: Calibri at 11pt.
WORD_DEFAULT_FONT: FontConfiguration['defaultFont']