@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.
- package/dist-lib/assets/{worker-BFAbWoje.js → worker-VdvO3cMW.js} +1198 -1182
- package/dist-lib/builder.js +5 -5
- package/dist-lib/{editorApp-CQn18PAu.js → editorApp-BGyP48-P.js} +37 -36
- package/dist-lib/{recalcToc-Dzz8cQho.js → engine-Chvebzwr.js} +525 -548
- package/dist-lib/export.js +8 -7
- package/dist-lib/generate-toc.js +7 -6
- package/dist-lib/import.js +2 -2
- package/dist-lib/{lists-DpmgbDyt.js → lists-BVCy5dMa.js} +2 -2
- package/dist-lib/{parse-CIuWi88O.js → parse-PD2rg4oO.js} +28 -28
- package/dist-lib/{pipeline-DQil8qUX.js → pipeline-r7GVSMFb.js} +60 -60
- package/dist-lib/query.js +977 -0
- package/dist-lib/recalc-docx.js +22 -21
- package/dist-lib/recalcToc-CAeOzLr3.js +37 -0
- package/dist-lib/{stylesheet-BeM16Mvj.js → stylesheet-IH4Hyc8o.js} +3 -3
- package/dist-lib/{toc-C-JErW1U.js → toc-B-TzD-Mr.js} +102 -86
- package/dist-lib/{webmcp-B9Q6w0Vl.js → webmcp-CDpzmTtU.js} +2 -2
- package/dist-lib/{wordcanvas-Cla5Ys8Y.js → wordcanvas-CIqBAV2w.js} +3 -3
- package/dist-lib/wordcanvas.js +1 -1
- package/dist-node/{chunk-JVSPB6WM.js → chunk-A53KB3BE.js} +2 -2
- package/dist-node/{chunk-HMBQQDXD.js → chunk-TLGEFCLV.js} +64 -1
- package/dist-node/chunk-TLGEFCLV.js.map +7 -0
- package/dist-node/{chunk-KZHUXFDE.js → chunk-VNDCELYX.js} +5 -45
- package/dist-node/chunk-VNDCELYX.js.map +7 -0
- package/dist-node/{engine-46GL2RKU.js → engine-QKH45ZHY.js} +5 -4
- package/dist-node/export.js +3 -3
- package/dist-node/generate-toc.js +3 -3
- package/dist-node/import.js +2 -2
- package/dist-node/recalc-docx.js +2 -2
- package/package.json +6 -2
- package/types/builder.d.ts +47 -2
- package/types/model.d.ts +34 -0
- package/types/query.d.ts +416 -0
- package/dist-node/chunk-HMBQQDXD.js.map +0 -7
- package/dist-node/chunk-KZHUXFDE.js.map +0 -7
- /package/dist-node/{chunk-JVSPB6WM.js.map → chunk-A53KB3BE.js.map} +0 -0
- /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-
|
|
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-
|
|
21
|
+
//# sourceMappingURL=engine-QKH45ZHY.js.map
|
package/dist-node/export.js
CHANGED
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
} from "./chunk-5PUCGN47.js";
|
|
46
46
|
import {
|
|
47
47
|
createLayoutEngine
|
|
48
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
38
|
+
} from "./chunk-TLGEFCLV.js";
|
|
39
39
|
import "./chunk-K43IQCP2.js";
|
|
40
40
|
import "./chunk-XSRSBST2.js";
|
|
41
41
|
|
package/dist-node/import.js
CHANGED
|
@@ -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-
|
|
9
|
+
} from "./chunk-A53KB3BE.js";
|
|
10
10
|
import "./chunk-5I6FZZ5U.js";
|
|
11
11
|
import "./chunk-5PUCGN47.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-TLGEFCLV.js";
|
|
13
13
|
import "./chunk-XSRSBST2.js";
|
|
14
14
|
export {
|
|
15
15
|
runImport
|
package/dist-node/recalc-docx.js
CHANGED
|
@@ -18,8 +18,8 @@ import {
|
|
|
18
18
|
} from "./chunk-5PUCGN47.js";
|
|
19
19
|
import {
|
|
20
20
|
createLayoutEngine
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import "./chunk-
|
|
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.
|
|
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",
|
package/types/builder.d.ts
CHANGED
|
@@ -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
|
-
|
|
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 {
|
package/types/query.d.ts
ADDED
|
@@ -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;
|