@forevka/wordcanvas 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist-lib/assets/{worker-BFAbWoje.js → worker-VdvO3cMW.js} +1198 -1182
  2. package/dist-lib/builder.js +5 -5
  3. package/dist-lib/{editorApp-CQn18PAu.js → editorApp-BGyP48-P.js} +37 -36
  4. package/dist-lib/{recalcToc-Dzz8cQho.js → engine-Chvebzwr.js} +525 -548
  5. package/dist-lib/export.js +8 -7
  6. package/dist-lib/generate-toc.js +7 -6
  7. package/dist-lib/import.js +2 -2
  8. package/dist-lib/{lists-DpmgbDyt.js → lists-BVCy5dMa.js} +2 -2
  9. package/dist-lib/{parse-CIuWi88O.js → parse-PD2rg4oO.js} +28 -28
  10. package/dist-lib/{pipeline-DQil8qUX.js → pipeline-r7GVSMFb.js} +60 -60
  11. package/dist-lib/query.js +977 -0
  12. package/dist-lib/recalc-docx.js +22 -21
  13. package/dist-lib/recalcToc-CAeOzLr3.js +37 -0
  14. package/dist-lib/{stylesheet-BeM16Mvj.js → stylesheet-IH4Hyc8o.js} +3 -3
  15. package/dist-lib/{toc-C-JErW1U.js → toc-B-TzD-Mr.js} +102 -86
  16. package/dist-lib/{webmcp-B9Q6w0Vl.js → webmcp-CDpzmTtU.js} +2 -2
  17. package/dist-lib/{wordcanvas-Cla5Ys8Y.js → wordcanvas-CIqBAV2w.js} +3 -3
  18. package/dist-lib/wordcanvas.js +1 -1
  19. package/dist-node/{chunk-JVSPB6WM.js → chunk-A53KB3BE.js} +2 -2
  20. package/dist-node/{chunk-HMBQQDXD.js → chunk-TLGEFCLV.js} +64 -1
  21. package/dist-node/chunk-TLGEFCLV.js.map +7 -0
  22. package/dist-node/{chunk-KZHUXFDE.js → chunk-VNDCELYX.js} +5 -45
  23. package/dist-node/chunk-VNDCELYX.js.map +7 -0
  24. package/dist-node/{engine-46GL2RKU.js → engine-QKH45ZHY.js} +5 -4
  25. package/dist-node/export.js +3 -3
  26. package/dist-node/generate-toc.js +3 -3
  27. package/dist-node/import.js +2 -2
  28. package/dist-node/recalc-docx.js +2 -2
  29. package/package.json +6 -2
  30. package/types/builder.d.ts +47 -2
  31. package/types/model.d.ts +34 -0
  32. package/types/query.d.ts +416 -0
  33. package/dist-node/chunk-HMBQQDXD.js.map +0 -7
  34. package/dist-node/chunk-KZHUXFDE.js.map +0 -7
  35. /package/dist-node/{chunk-JVSPB6WM.js.map → chunk-A53KB3BE.js.map} +0 -0
  36. /package/dist-node/{engine-46GL2RKU.js.map → engine-QKH45ZHY.js.map} +0 -0
@@ -5,11 +5,12 @@ const require = __createRequire(import.meta.url);
5
5
  const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
7
  import {
8
- createLayoutEngine,
8
+ createLayoutEngine
9
+ } from "./chunk-VNDCELYX.js";
10
+ import {
9
11
  effectiveSection,
10
12
  resolveSections
11
- } from "./chunk-KZHUXFDE.js";
12
- import "./chunk-HMBQQDXD.js";
13
+ } from "./chunk-TLGEFCLV.js";
13
14
  import "./chunk-K43IQCP2.js";
14
15
  import "./chunk-XSRSBST2.js";
15
16
  export {
@@ -17,4 +18,4 @@ export {
17
18
  effectiveSection,
18
19
  resolveSections
19
20
  };
20
- //# sourceMappingURL=engine-46GL2RKU.js.map
21
+ //# sourceMappingURL=engine-QKH45ZHY.js.map
@@ -45,7 +45,7 @@ import {
45
45
  } from "./chunk-5PUCGN47.js";
46
46
  import {
47
47
  createLayoutEngine
48
- } from "./chunk-KZHUXFDE.js";
48
+ } from "./chunk-VNDCELYX.js";
49
49
  import {
50
50
  DEFAULT_CHAR_STYLE,
51
51
  detectTocHeadings,
@@ -53,7 +53,7 @@ import {
53
53
  parseTocInstruction,
54
54
  styleType,
55
55
  textOfRuns
56
- } from "./chunk-HMBQQDXD.js";
56
+ } from "./chunk-TLGEFCLV.js";
57
57
  import {
58
58
  ARABIC_FONT_FAMILY,
59
59
  CJK_FONT_FAMILY,
@@ -24725,7 +24725,7 @@ async function renderPdf(doc, opts = {}) {
24725
24725
  }
24726
24726
  async function renderPdfInner(doc, opts, fontReg) {
24727
24727
  await installMeasureHost();
24728
- const { createLayoutEngine: createLayoutEngine2 } = await import("./engine-46GL2RKU.js");
24728
+ const { createLayoutEngine: createLayoutEngine2 } = await import("./engine-QKH45ZHY.js");
24729
24729
  const tree = createLayoutEngine2(fontReg, opts.cjk).layout(doc);
24730
24730
  const warnings = new WarningSink();
24731
24731
  const images = opts.images ?? {};
@@ -6,7 +6,7 @@ const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
7
  import {
8
8
  runImport
9
- } from "./chunk-JVSPB6WM.js";
9
+ } from "./chunk-A53KB3BE.js";
10
10
  import {
11
11
  el,
12
12
  escapeText,
@@ -28,14 +28,14 @@ import {
28
28
  } from "./chunk-5PUCGN47.js";
29
29
  import {
30
30
  createLayoutEngine
31
- } from "./chunk-KZHUXFDE.js";
31
+ } from "./chunk-VNDCELYX.js";
32
32
  import {
33
33
  detectTocHeadings,
34
34
  inRange,
35
35
  parseTocInstruction,
36
36
  textOfRuns,
37
37
  tocEntryStyle
38
- } from "./chunk-HMBQQDXD.js";
38
+ } from "./chunk-TLGEFCLV.js";
39
39
  import "./chunk-K43IQCP2.js";
40
40
  import "./chunk-XSRSBST2.js";
41
41
 
@@ -6,10 +6,10 @@ const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
7
  import {
8
8
  runImport
9
- } from "./chunk-JVSPB6WM.js";
9
+ } from "./chunk-A53KB3BE.js";
10
10
  import "./chunk-5I6FZZ5U.js";
11
11
  import "./chunk-5PUCGN47.js";
12
- import "./chunk-HMBQQDXD.js";
12
+ import "./chunk-TLGEFCLV.js";
13
13
  import "./chunk-XSRSBST2.js";
14
14
  export {
15
15
  runImport
@@ -18,8 +18,8 @@ import {
18
18
  } from "./chunk-5PUCGN47.js";
19
19
  import {
20
20
  createLayoutEngine
21
- } from "./chunk-KZHUXFDE.js";
22
- import "./chunk-HMBQQDXD.js";
21
+ } from "./chunk-VNDCELYX.js";
22
+ import "./chunk-TLGEFCLV.js";
23
23
  import "./chunk-K43IQCP2.js";
24
24
  import "./chunk-XSRSBST2.js";
25
25
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forevka/wordcanvas",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "Open-source embeddable Word-style document editor: canvas-rendered, with live collaboration, track changes & comments, and DOCX/PDF import & export. A lightweight alternative to Syncfusion, OnlyOffice, and DevExpress document editors. Self-contained, zero runtime dependencies.",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  ],
40
40
  "module": "./dist-lib/wordcanvas.js",
41
41
  "types": "./types/wordcanvas.d.ts",
42
- "//exports": "Dual-target, all compiled — no raw src ships. `.`/`./builder` are the browser editor (Vite → dist-lib). The headless pipelines (import/export/measure/recalc-docx/generate-toc) are isomorphic and exposed via conditional exports: the `node` condition resolves a self-contained, Node-targeted bundle (scripts/build-node.mjs → dist-node, with disk fonts + bundled pdfkit) for server/headless use; the `default` condition resolves the browser variant (Vite → dist-lib). Hand-written types/ keeps the published .d.ts self-contained (no @cw/shared import). The in-repo backend consumes the `node` build through this map (no tsconfig path aliases).",
42
+ "//exports": "Dual-target, all compiled — no raw src ships. `.`/`./builder`/`./query` are the browser editor (Vite → dist-lib); `./query` is the document query + edit + page API. The headless pipelines (import/export/measure/recalc-docx/generate-toc) are isomorphic and exposed via conditional exports: the `node` condition resolves a self-contained, Node-targeted bundle (scripts/build-node.mjs → dist-node, with disk fonts + bundled pdfkit) for server/headless use; the `default` condition resolves the browser variant (Vite → dist-lib). Hand-written types/ keeps the published .d.ts self-contained (no @cw/shared import). The in-repo backend consumes the `node` build through this map (no tsconfig path aliases).",
43
43
  "exports": {
44
44
  ".": {
45
45
  "types": "./types/wordcanvas.d.ts",
@@ -49,6 +49,10 @@
49
49
  "types": "./types/builder.d.ts",
50
50
  "import": "./dist-lib/builder.js"
51
51
  },
52
+ "./query": {
53
+ "types": "./types/query.d.ts",
54
+ "import": "./dist-lib/query.js"
55
+ },
52
56
  "./import": {
53
57
  "types": "./types/import.d.ts",
54
58
  "node": "./dist-node/import.js",
@@ -9,7 +9,7 @@
9
9
  // Works in the browser (live preview via WordCanvas.setDocument) and in Node
10
10
  // (server-side DOCX/PDF generation via the export subpath).
11
11
 
12
- import type { CellBorders, CellMargin, CharStyle, Document, NamedStyle, ParaBorders, ParaStyle, Stylesheet, TableCondOverrides, TableStyle, TabStop } from "./model";
12
+ import type { CellBorders, CellMargin, CharStyle, Document, NamedStyle, PageNumFmt, ParaBorders, ParaStyle, SdtProps, Stylesheet, TableCondOverrides, TableStyle, TabStop } from "./model";
13
13
 
14
14
  export type { Block, CharStyle, Document, NamedStyle, ParaStyle, Stylesheet, TableCondOverrides, TableStyle, TabStop } from "./model";
15
15
 
@@ -204,6 +204,48 @@ export declare class ParagraphBuilder<P extends StoryBuilder> {
204
204
  inlineEquation(latex: string, style?: Partial<CharStyle>): this;
205
205
  /** Append an inline equation from a presentation-MathML string. */
206
206
  inlineEquationMathml(mathml: string, style?: Partial<CharStyle>): this;
207
+ // ---- inline content controls (OOXML w:sdt) ----
208
+ /** Append an inline content control wrapping `text` with explicit properties. */
209
+ contentControl(props: SdtProps, text: string, style?: Partial<CharStyle>): this;
210
+ /** A rich-text content control. */
211
+ richTextControl(text: string, opts?: { alias?: string; tag?: string }): this;
212
+ /** A plain-text content control. */
213
+ plainTextControl(text: string, opts?: { alias?: string; tag?: string }): this;
214
+ /** A checkbox content control (☒/☐). */
215
+ checkbox(checked: boolean, opts?: { alias?: string; tag?: string }): this;
216
+ /** A drop-down content control (fixed list of `{ display, value }` items). */
217
+ dropDown(selected: string, items: { display: string; value: string }[], opts?: { alias?: string; tag?: string }): this;
218
+ /** A combo-box content control (list + free text). */
219
+ comboBox(selected: string, items: { display: string; value: string }[], opts?: { alias?: string; tag?: string }): this;
220
+ /** A date-picker content control. */
221
+ dateControl(text: string, dateFormat?: string, opts?: { alias?: string; tag?: string }): this;
222
+ // ---- inline fields (OOXML complex fields) ----
223
+ /** The current page number (PAGE field), resolved at layout. */
224
+ pageField(numFmt?: PageNumFmt): this;
225
+ /** The total page count (NUMPAGES field), resolved at layout. */
226
+ numPagesField(numFmt?: PageNumFmt): this;
227
+ /** A DATE field with a Word/.NET-style format (default "M/d/yyyy"). */
228
+ dateField(format?: string): this;
229
+ /** A TIME field with a Word/.NET-style format (default "h:mm AM/PM"). */
230
+ timeField(format?: string): this;
231
+ /** A custom (host-resolved) field: verbatim instruction + cached result text. */
232
+ customField(instruction: string, resultText: string): this;
233
+ /** A conditional (IF) field — branch text by comparing two operands. */
234
+ ifField(operandA: string, op: "=" | "<>" | "<" | "<=" | ">" | ">=", operandB: string, ifTrue: string, ifFalse: string): this;
235
+ /** A cross-reference to a bookmark (REF, or PAGEREF when `pageRef`). */
236
+ crossReference(bookmarkName: string, opts?: { kind?: "ref" | "pageRef" }): this;
237
+ // ---- bookmarks + notes ----
238
+ /** Append text and bookmark exactly that run's range. */
239
+ bookmark(name: string, text: string, style?: Partial<CharStyle>): this;
240
+ /** Append an auto-numbered footnote (single-paragraph body, or built via callback). */
241
+ footnote(text: string): this;
242
+ footnote(build: (s: StoryBuilder) => void): this;
243
+ /** Append an auto-numbered endnote (collected at the document end). */
244
+ endnote(text: string): this;
245
+ endnote(build: (s: StoryBuilder) => void): this;
246
+ /** Sub/superscript (measured smaller, baseline-shifted). */
247
+ superscript(on?: boolean): this;
248
+ subscript(on?: boolean): this;
207
249
  align(align: ParaStyle["align"]): this;
208
250
  spacing(opts: SpacingOptions): this;
209
251
  indent(opts: IndentOptions): this;
@@ -252,8 +294,11 @@ export declare class TableBuilder {
252
294
  }
253
295
 
254
296
  export declare class RowBuilder {
255
- cell(content: CellContent, opts?: CellOptions): this;
297
+ // The build (callback) overload is listed FIRST so a `(s) => …` arrow binds to it
298
+ // and `s` types as StoryBuilder — CellSpec's fields are all optional, so a function
299
+ // would otherwise match the `content: CellContent` overload and shadow the callback.
256
300
  cell(build: (s: StoryBuilder) => void, opts?: CellOptions): this;
301
+ cell(content: CellContent, opts?: CellOptions): this;
257
302
  }
258
303
 
259
304
  /** Root of the fluent builder. Produces the same plain-data Document the
package/types/model.d.ts CHANGED
@@ -323,11 +323,45 @@ export interface DocPosition {
323
323
  offset: number;
324
324
  }
325
325
 
326
+ export interface DocSelection {
327
+ anchor: DocPosition;
328
+ focus: DocPosition;
329
+ /** Preserved X column for Up/Down caret movement. */
330
+ goalX?: number;
331
+ }
332
+
326
333
  export interface BookmarkRange {
327
334
  start: DocPosition;
328
335
  end: DocPosition;
329
336
  }
330
337
 
338
+ /** OOXML page-number / list format (the field `\* <fmt>` switch). */
339
+ export type PageNumFmt = "arabic" | "roman" | "Roman" | "alpha" | "Alpha";
340
+ /** IF-field comparison operators. */
341
+ export type IfOp = "=" | "<>" | "<" | ">" | "<=" | ">=";
342
+
343
+ /** Typed, parsed form of a BUILT-IN field's definition (drives the field UI + the
344
+ * evaluator). TOC keeps its own path and is not here. */
345
+ export type FieldSpec =
346
+ | { type: "PAGE"; numFmt?: PageNumFmt }
347
+ | { type: "NUMPAGES"; numFmt?: PageNumFmt }
348
+ | { type: "DATE"; format: string }
349
+ | { type: "TIME"; format: string }
350
+ | { type: "IF"; operandA: string; op: IfOp; operandB: string; trueRuns: Run[]; falseRuns: Run[] };
351
+
352
+ /** A generic OOXML field tracked in the model (custom host-resolved + built-in).
353
+ * Its result is the blocks/runs carrying its `id` as `fieldId`. */
354
+ export interface FieldDef {
355
+ id: string;
356
+ /** Verbatim w:instrText, re-emitted on export. */
357
+ instruction: string;
358
+ /** Field keyword, uppercased (the first instruction token). */
359
+ name: string;
360
+ kind: "builtin" | "custom";
361
+ /** Parsed spec for built-ins the editor understands; absent for opaque fields. */
362
+ spec?: FieldSpec;
363
+ }
364
+
331
365
  export type SdtType = "richText" | "plainText" | "checkbox" | "dropDown" | "comboBox" | "date";
332
366
 
333
367
  export interface SdtProps {
@@ -0,0 +1,416 @@
1
+ // Public type surface for @forevka/wordcanvas/query — the document query + edit
2
+ // API (the rough analog of .NET's WordprocessingDocument access). Hand-written,
3
+ // self-contained (model types come from ./model, shared with wordcanvas.d.ts).
4
+ //
5
+ // import { findParagraphs, DocumentEditor, getPages } from "@forevka/wordcanvas/query";
6
+ // const ed = new DocumentEditor(doc);
7
+ // for (const m of findParagraphs(ed.doc, "DRAFT")) ed.setParagraphText(m.paragraph.id, "FINAL");
8
+
9
+ import type {
10
+ BandContainer,
11
+ Block,
12
+ BookmarkRange,
13
+ CharStyle,
14
+ Document,
15
+ DocPosition,
16
+ DocSelection,
17
+ FieldDef,
18
+ ImageBlock,
19
+ NamedStyle,
20
+ Paragraph,
21
+ ParaStyle,
22
+ Run,
23
+ SdtProps,
24
+ SectionProps,
25
+ TableBlock,
26
+ } from "./model";
27
+
28
+ export type {
29
+ BandContainer,
30
+ Block,
31
+ BookmarkRange,
32
+ CharStyle,
33
+ Document,
34
+ DocPosition,
35
+ DocSelection,
36
+ EquationBlock,
37
+ FieldDef,
38
+ FieldSpec,
39
+ ImageBlock,
40
+ NamedStyle,
41
+ Paragraph,
42
+ ParaStyle,
43
+ Run,
44
+ SdtProps,
45
+ SdtType,
46
+ SectionProps,
47
+ TableBlock,
48
+ } from "./model";
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // Traversal / query
52
+
53
+ /** A top-level story: the body or one of the six header/footer band stories.
54
+ * Note bodies report `"body"` and set `note` instead. */
55
+ export type Container = "body" | BandContainer;
56
+
57
+ /** A table cell coordinate. */
58
+ export interface CellRef {
59
+ tableId: string;
60
+ row: number;
61
+ col: number;
62
+ }
63
+
64
+ /** Where a visited block sits. `cell`/`note` are set when the block is nested
65
+ * below the top level of its story. */
66
+ export interface BlockContext {
67
+ container: Container;
68
+ /** Set when the block lives inside a table cell (innermost cell if nested). */
69
+ cell?: CellRef;
70
+ /** Full cell ancestry outer→inner, present only for a block nested ≥2 cells deep
71
+ * (a table within a cell); single-cell blocks keep the simple `{ cell }` shape. */
72
+ cellPath?: CellRef[];
73
+ /** Set when the block belongs to a footnote/endnote body. */
74
+ note?: { kind: "footnote" | "endnote"; id: string };
75
+ }
76
+
77
+ export type BlockVisitor = (block: Block, ctx: BlockContext) => void;
78
+
79
+ /** Where a visited run sits: its paragraph context plus the paragraph, run index,
80
+ * and full enclosing content-control chain (outer→inner). */
81
+ export interface RunContext extends BlockContext {
82
+ block: Paragraph;
83
+ runIndex: number;
84
+ sdtChain: string[];
85
+ }
86
+ export type RunVisitor = (run: Run, ctx: RunContext) => void;
87
+
88
+ /** Which stories `walk` descends into. All default to `true`. */
89
+ export interface WalkOptions {
90
+ bands?: boolean;
91
+ notes?: boolean;
92
+ cells?: boolean;
93
+ }
94
+
95
+ export interface ParagraphMatch {
96
+ paragraph: Paragraph;
97
+ /** The paragraph's concatenated run text (what was tested). */
98
+ text: string;
99
+ context: BlockContext;
100
+ }
101
+
102
+ export interface ResolvedSection {
103
+ index: number;
104
+ props: SectionProps;
105
+ startBlock: number;
106
+ endBlock: number;
107
+ breakType: "nextPage" | "evenPage" | "oddPage";
108
+ }
109
+
110
+ /** Visit every block, descending (by default) into table cells, header/footer
111
+ * bands, and note bodies. */
112
+ export declare function walk(doc: Document, visit: BlockVisitor, options?: WalkOptions): void;
113
+ /** Visit every run (paragraphs only) with its paragraph context + full sdt chain. */
114
+ export declare function walkRuns(doc: Document, visit: RunVisitor, options?: WalkOptions): void;
115
+ /** Plain text of a block (tables join cells with tabs, rows with newlines). */
116
+ export declare function textOf(block: Block): string;
117
+ export declare function getParagraphs(doc: Document, options?: WalkOptions): Paragraph[];
118
+ export declare function getTables(doc: Document, options?: WalkOptions): TableBlock[];
119
+ export declare function getImages(doc: Document, options?: WalkOptions): ImageBlock[];
120
+ /** Find paragraphs by substring or RegExp; each match carries its context. */
121
+ export declare function findParagraphs(doc: Document, pattern: string | RegExp, options?: WalkOptions): ParagraphMatch[];
122
+ export declare function getBlockById(doc: Document, id: string, options?: WalkOptions): Block | undefined;
123
+ export declare function getParagraphById(doc: Document, id: string, options?: WalkOptions): Paragraph | undefined;
124
+ export declare function getTableById(doc: Document, id: string, options?: WalkOptions): TableBlock | undefined;
125
+ export declare function getImageById(doc: Document, id: string, options?: WalkOptions): ImageBlock | undefined;
126
+ /** Enumerate sections (page geometry + the block range each covers). */
127
+ export declare function getSections(doc: Document): ResolvedSection[];
128
+ export declare function resolveSections(doc: Document): ResolvedSection[];
129
+
130
+ // ---------------------------------------------------------------------------
131
+ // Content controls (SDTs) — the primary templating surface. Membership is an
132
+ // ordered ancestry path, so controls nest; these expose the flat list (by
133
+ // id/tag/alias), the nesting tree, and the wrapped blocks/text.
134
+
135
+ /** A content control's id paired with its properties. */
136
+ export interface SdtMatch {
137
+ id: string;
138
+ props: SdtProps;
139
+ }
140
+
141
+ /** A content control as a node in the nesting tree. */
142
+ export interface SdtNode extends SdtMatch {
143
+ /** The control directly wrapping this one, or undefined for a top-level control. */
144
+ parentId?: string;
145
+ /** Direct child controls, in first-appearance order. */
146
+ childIds: string[];
147
+ /** Full ancestry outer→inner ending at this id (`[this]` for a root). */
148
+ path: string[];
149
+ /** Nesting depth: 0 for a root (== path.length - 1). */
150
+ depth: number;
151
+ }
152
+
153
+ /** A content control's properties by id, or undefined. */
154
+ export declare function getSdt(doc: Document, id: string): SdtProps | undefined;
155
+ /** Every content control, as `{ id, props }`, in `doc.sdts` insertion order. */
156
+ export declare function getSdts(doc: Document): SdtMatch[];
157
+ /** Controls whose machine-readable tag (w:tag) equals `tag` (a tag is not unique). */
158
+ export declare function getSdtsByTag(doc: Document, tag: string): SdtMatch[];
159
+ /** Controls whose title/alias (w:alias) equals `alias`. */
160
+ export declare function getSdtsByAlias(doc: Document, alias: string): SdtMatch[];
161
+ /** Every content control as a tree node (parent/child links, path, depth). */
162
+ export declare function getSdtNodes(doc: Document): SdtNode[];
163
+ /** The top-level controls — those not nested inside any other. */
164
+ export declare function getSdtRoots(doc: Document): SdtNode[];
165
+ /** The controls nested directly (one level) inside `id`. */
166
+ export declare function getSdtChildren(doc: Document, id: string): SdtNode[];
167
+ /** The controls wrapping `id`, outermost→innermost (excluding `id`). */
168
+ export declare function getSdtAncestors(doc: Document, id: string): SdtNode[];
169
+ /** Every control nested anywhere below `id` (depth-first, pre-order). */
170
+ export declare function getSdtDescendants(doc: Document, id: string): SdtNode[];
171
+ /** The blocks a block-level control wraps (their `sdtPath` includes `id`). */
172
+ export declare function getSdtBlocks(doc: Document, id: string, options?: WalkOptions): Block[];
173
+ /** The plain text a control encloses (block-level whole blocks + inline runs;
174
+ * nested controls' text included). Blocks join with newlines. */
175
+ export declare function sdtText(doc: Document, id: string, options?: WalkOptions): string;
176
+
177
+ /** A content control's value in the shape its `type` implies. `text` is always the
178
+ * enclosed text; `checked` is set for checkboxes; `selected` for dropDown/comboBox
179
+ * (the VALUE of the matching listItem, or the raw text for combo free entry). */
180
+ export interface SdtValue {
181
+ type: SdtProps["type"];
182
+ text: string;
183
+ checked?: boolean;
184
+ selected?: string;
185
+ }
186
+ /** Read a control's typed value, or undefined if it does not exist. */
187
+ export declare function getSdtValue(doc: Document, id: string): SdtValue | undefined;
188
+
189
+ // ---------------------------------------------------------------------------
190
+ // Fields / bookmarks / notes / lists / styles / block location
191
+
192
+ /** A field definition by id, or undefined. */
193
+ export declare function getField(doc: Document, id: string): FieldDef | undefined;
194
+ /** Every tracked field (custom + built-in), in document order. */
195
+ export declare function getFields(doc: Document): FieldDef[];
196
+ /** Fields whose keyword matches `name`, case-insensitively. */
197
+ export declare function getFieldsByName(doc: Document, name: string): FieldDef[];
198
+ /** The blocks forming a region field's result (their `fieldId` === id). */
199
+ export declare function getFieldBlocks(doc: Document, id: string, options?: WalkOptions): Block[];
200
+
201
+ export interface BookmarkEntry {
202
+ name: string;
203
+ range: BookmarkRange;
204
+ }
205
+ /** A bookmark's character range by name, or undefined. */
206
+ export declare function getBookmark(doc: Document, name: string): BookmarkRange | undefined;
207
+ /** Every bookmark as `{ name, range }`. */
208
+ export declare function getBookmarks(doc: Document): BookmarkEntry[];
209
+
210
+ export interface NoteStory {
211
+ id: string;
212
+ paragraphs: Paragraph[];
213
+ }
214
+ /** Footnote stories keyed by ref id. */
215
+ export declare function getFootnotes(doc: Document): NoteStory[];
216
+ /** Endnote stories keyed by ref id. */
217
+ export declare function getEndnotes(doc: Document): NoteStory[];
218
+
219
+ export interface ListItem {
220
+ paragraph: Paragraph;
221
+ /** 0-based list level (OOXML w:ilvl). */
222
+ level: number;
223
+ /** Resolved marker text ("1.", "a.", "•", …); "" for a markerless/unknown list. */
224
+ marker: string;
225
+ context: BlockContext;
226
+ }
227
+ /** Paragraphs bound to a list definition, in body reading order, each with its
228
+ * resolved marker (mirrors the layout engine's numbering pass, body-only). */
229
+ export declare function getListItems(doc: Document, listId: string): ListItem[];
230
+
231
+ /** Enumerate the stylesheet (Word's style gallery). */
232
+ export declare function getStyles(doc: Document): NamedStyle[];
233
+ /** A named style by id, or undefined. */
234
+ export declare function getStyleById(doc: Document, styleId: string): NamedStyle | undefined;
235
+
236
+ /** "Where is this block?" — the resolved container/cell/note context of a block by
237
+ * id, or undefined if no block carries the id. */
238
+ export declare function blockPath(doc: Document, id: string, options?: WalkOptions): BlockContext | undefined;
239
+
240
+ // ---------------------------------------------------------------------------
241
+ // Range / text addressing
242
+
243
+ /** The text a selection covers. A collapsed/single-block selection slices that
244
+ * block's text (any story); a multi-block selection is supported across top-level
245
+ * body blocks (joined by newlines), else "". Endpoints are ordered automatically. */
246
+ export declare function rangeText(doc: Document, selection: DocSelection): string;
247
+ /** The first `DocPosition` where `needle` appears in a paragraph's text (reading
248
+ * order), or undefined — target an edit without computing offsets by hand. */
249
+ export declare function positionOfText(doc: Document, needle: string, options?: WalkOptions): DocPosition | undefined;
250
+
251
+ // ---------------------------------------------------------------------------
252
+ // Edit facade
253
+
254
+ export interface InsertParagraphOptions {
255
+ position?: "before" | "after";
256
+ style?: ParaStyle;
257
+ runStyle?: CharStyle;
258
+ }
259
+
260
+ // ---------------------------------------------------------------------------
261
+ // Merge / append documents
262
+
263
+ /** How colliding named / table styles reconcile with the destination. */
264
+ export type StyleMergeMode = "useDestination" | "keepSource";
265
+ /** The section seam inserted between the destination and the appended source. */
266
+ export type MergeSectionBreak = "nextPage" | "evenPage" | "oddPage" | "continuous" | "none";
267
+
268
+ export interface MergeOptions {
269
+ styles?: StyleMergeMode;
270
+ sectionBreak?: MergeSectionBreak;
271
+ renameBookmarksOnCollision?: boolean;
272
+ }
273
+
274
+ /** old→new id per space, for every source id that changed or was repointed. */
275
+ export interface MergeIdMap {
276
+ blocks: Record<string, string>;
277
+ styles: Record<string, string>;
278
+ lists: Record<string, string>;
279
+ tableStyles: Record<string, string>;
280
+ sdts: Record<string, string>;
281
+ fields: Record<string, string>;
282
+ footnotes: Record<string, string>;
283
+ endnotes: Record<string, string>;
284
+ bookmarks: Record<string, string>;
285
+ }
286
+
287
+ export interface MergeWarning {
288
+ code: string;
289
+ detail?: string;
290
+ }
291
+
292
+ export interface MergeResult {
293
+ doc: Document;
294
+ idMap: MergeIdMap;
295
+ warnings: MergeWarning[];
296
+ }
297
+
298
+ /** Append `source` after `dest`, reconciling every id space. Pure — returns a new
299
+ * document; the inputs are not mutated. */
300
+ export declare function mergeDocuments(dest: Document, source: Document, opts?: MergeOptions): MergeResult;
301
+
302
+ /** Fold N documents left-to-right: mergeAll([a, b, c]) ≡ merge(merge(a, b), c). */
303
+ export declare function mergeAll(docs: Document[], opts?: MergeOptions): MergeResult;
304
+
305
+ /** Ergonomic, headless editing facade over the operation engine, with undo/redo.
306
+ * Every edit swaps `doc` for a new immutable value (structural sharing). */
307
+ export declare class DocumentEditor {
308
+ constructor(doc: Document);
309
+ get doc(): Document;
310
+ get canUndo(): boolean;
311
+ get canRedo(): boolean;
312
+ get lastInsertedId(): string | null;
313
+
314
+ setParagraphText(blockId: string, text: string, style?: CharStyle): this;
315
+ insertText(blockId: string, offset: number, text: string, style?: CharStyle): this;
316
+ deleteText(blockId: string, start: number, end: number): this;
317
+ replaceText(blockId: string, start: number, end: number, text: string, style?: CharStyle): this;
318
+ setParagraphStyle(blockId: string, patch: Partial<ParaStyle>): this;
319
+ removeBlock(blockId: string): this;
320
+ insertParagraph(refBlockId: string, text: string, options?: InsertParagraphOptions): this;
321
+
322
+ /** Merge a patch onto a content control's properties (the control must exist).
323
+ * The control `type` is not patchable — it is always preserved. */
324
+ setSdtProps(id: string, patch: Partial<Omit<SdtProps, "type">>): this;
325
+ /** Set a checkbox control's state (throws if `id` is not a checkbox). */
326
+ setCheckbox(id: string, checked: boolean): this;
327
+ /** Fill a single-paragraph content control's text (inline or block-level),
328
+ * preserving nesting and clearing any placeholder. */
329
+ setSdtText(id: string, text: string): this;
330
+ /** Select a value on a dropDown/comboBox control (by listItem value then display;
331
+ * comboBox allows free text). Throws for other control kinds. */
332
+ setSdtValue(id: string, value: string): this;
333
+ /** Remove a content control, unwrapping it (strip its id from member paths and
334
+ * delete its props; nested controls survive). `deleteContents` removes the
335
+ * wrapped content too. Block-level members outside the top-level body throw. */
336
+ removeSdt(id: string, options?: { deleteContents?: boolean }): this;
337
+
338
+ /** Find/replace across every paragraph as one undoable step. A string replaces
339
+ * all occurrences; a RegExp is applied per run. Matches spanning a style
340
+ * boundary are not replaced (run styling is always preserved). */
341
+ replaceAllText(pattern: string | RegExp, replacement: string): this;
342
+ /** Apply a named paragraph style by its human name (resolving to a styleId and
343
+ * baking the resolved formatting + setting the reference). Throws if unknown. */
344
+ setStyleByName(blockId: string, styleName: string): this;
345
+ /** Move a top-level body block to a new index among the body blocks (clamped),
346
+ * as one undoable step. Throws if it is not a top-level body block. */
347
+ moveBlock(blockId: string, toIndex: number): this;
348
+ /** Insert a row into a table at `rowIndex` (clamped); `cellTexts` fills cells
349
+ * left-to-right (padded/trimmed to the column count). Throws if unknown. */
350
+ insertTableRowAt(tableId: string, rowIndex: number, cellTexts?: string[]): this;
351
+ /** Delete the column whose first-row cell text equals `headerText`. Throws if the
352
+ * table or a matching header is not found. */
353
+ deleteColumnByHeader(tableId: string, headerText: string): this;
354
+
355
+ /** Append another document's content after this one (Word's "insert file at
356
+ * end"), reconciling every id space (see mergeDocuments) as ONE undoable step.
357
+ * Returns the merge's id map + warnings; the merged document becomes `doc`. */
358
+ append(source: Document, options?: MergeOptions): MergeResult;
359
+
360
+ /** Replace a block-level content control's entire content with another document
361
+ * (the templating primitive): reconciles every id space and preserves the control's
362
+ * ancestry (the source's own nested controls survive inside it). One undoable step.
363
+ * The control must be block-level at the top level of the body — an inline control,
364
+ * or one in a table cell / band / note, throws (use setSdtText for inline). */
365
+ replaceSdtContent(sdtId: string, source: Document, options?: MergeOptions): MergeResult;
366
+
367
+ /** Set (or clear, with `null`) a header/footer band on a specific section by index
368
+ * (see getSections). The final/body section stores bands on the document; a
369
+ * mid-document section on its break paragraph. Throws if the index is out of range. */
370
+ setSectionBand(sectionIndex: number, band: BandContainer, blocks: Block[] | null): this;
371
+ /** Set (or clear) a section's default footer band. See setSectionBand. */
372
+ setSectionFooter(sectionIndex: number, blocks: Block[] | null): this;
373
+ /** Set (or clear) a section's default header band. See setSectionBand. */
374
+ setSectionHeader(sectionIndex: number, blocks: Block[] | null): this;
375
+
376
+ undo(): boolean;
377
+ redo(): boolean;
378
+
379
+ find(pattern: string | RegExp): ParagraphMatch[];
380
+ getParagraph(blockId: string): Paragraph | undefined;
381
+ }
382
+
383
+ // ---------------------------------------------------------------------------
384
+ // Page query (layout-backed)
385
+
386
+ export interface PageInfo {
387
+ index: number;
388
+ number: number;
389
+ widthPx: number;
390
+ heightPx: number;
391
+ marginPx: { top: number; right: number; bottom: number; left: number };
392
+ contentTopPx: number;
393
+ contentBottomPx: number;
394
+ pageColorHex?: string;
395
+ blockIds: string[];
396
+ }
397
+
398
+ export interface GetPagesOptions {
399
+ fontRegistry?: unknown;
400
+ engineOptions?: {
401
+ cjkFallback?: string | null;
402
+ cjkLocale?: string;
403
+ arabicFallback?: string | null;
404
+ hebrewFallback?: string | null;
405
+ };
406
+ }
407
+
408
+ /** Lay the document out and return a serializable per-page map. Page numbers can
409
+ * shift after edits, so re-run after mutating. Requires text measurement
410
+ * (pretext) to be initialized, like rendering/export. */
411
+ export declare function getPages(doc: Document, options?: GetPagesOptions): PageInfo[];
412
+ /** The displayed page number a top-level block first appears on, or null. */
413
+ export declare function pageOfBlock(doc: Document, blockId: string, options?: GetPagesOptions): number | null;
414
+ /** Where a top-level block sits in a `getPages` map: its page `index` and 0-based
415
+ * `order` among that page's block ids, or null. Pure over the page map (no layout). */
416
+ export declare function indexOnPage(pages: PageInfo[], blockId: string): { index: number; order: number } | null;