wordinweb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +137 -0
- package/README.md +19 -0
- package/dist/index.d.ts +1985 -0
- package/dist/index.js +23301 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1985 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal, fast XML parser producing a lightweight element tree.
|
|
5
|
+
*
|
|
6
|
+
* OOXML parts are machine-generated, namespace-prefixed, well-formed XML with
|
|
7
|
+
* no DTDs. This parser handles exactly that subset: elements, attributes,
|
|
8
|
+
* text, CDATA, comments, processing instructions, and the built-in + numeric
|
|
9
|
+
* character entities. Namespace prefixes are kept verbatim (`w:p`), and
|
|
10
|
+
* lookups match on either the full name or the local name, which is robust
|
|
11
|
+
* for every mainstream producer (Word, LibreOffice, Google Docs export).
|
|
12
|
+
*/
|
|
13
|
+
interface XmlElement {
|
|
14
|
+
name: string;
|
|
15
|
+
attrs: Record<string, string>;
|
|
16
|
+
children: XmlElement[];
|
|
17
|
+
/** Concatenated character data directly inside this element. */
|
|
18
|
+
text: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Typed document model produced by the parser and consumed by the layout
|
|
23
|
+
* engine. All lengths are CSS px (see units.ts) unless a field name says
|
|
24
|
+
* otherwise. Property bags are Partial-style: `undefined` means "not set at
|
|
25
|
+
* this level" so the style-inheritance merge can distinguish absence from an
|
|
26
|
+
* explicit value.
|
|
27
|
+
*
|
|
28
|
+
* Model nodes keep `src` references to the XML elements they were parsed
|
|
29
|
+
* from: the XML tree is the source of truth for editing — commands mutate it
|
|
30
|
+
* and the model is re-derived, which preserves round-trip fidelity for
|
|
31
|
+
* everything untouched.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
type BorderStyle = "none" | "single" | "double" | "dotted" | "dashed" | "thick" | "wave" | "dotDash" | "dotDotDash" | "triple";
|
|
35
|
+
interface Border {
|
|
36
|
+
style: BorderStyle;
|
|
37
|
+
/** Stroke width in px. */
|
|
38
|
+
width: number;
|
|
39
|
+
/** CSS color. */
|
|
40
|
+
color: string;
|
|
41
|
+
/** Gap between border and content in px (w:space, points in OOXML). */
|
|
42
|
+
space: number;
|
|
43
|
+
/** Declared stroke width in px BEFORE the 0.75px paint floor (w:sz/8 pt).
|
|
44
|
+
* Word's LAYOUT math (table row border share) uses this true width — a
|
|
45
|
+
* sz-4 rule contributes 0.5pt, not the floored 0.5625pt (phase23 p66:
|
|
46
|
+
* 45 rows drift 2.5px down without it). */
|
|
47
|
+
rawWidth?: number;
|
|
48
|
+
}
|
|
49
|
+
interface ParagraphBorders {
|
|
50
|
+
top?: Border;
|
|
51
|
+
bottom?: Border;
|
|
52
|
+
left?: Border;
|
|
53
|
+
right?: Border;
|
|
54
|
+
/** Drawn between consecutive paragraphs that both specify it. */
|
|
55
|
+
between?: Border;
|
|
56
|
+
}
|
|
57
|
+
type LineSpacingRule = "auto" | "atLeast" | "exact";
|
|
58
|
+
interface LineSpacing {
|
|
59
|
+
rule: LineSpacingRule;
|
|
60
|
+
/**
|
|
61
|
+
* For "auto": multiple of single line height (240ths in OOXML, stored here
|
|
62
|
+
* as the multiplier, e.g. 1.15). For atLeast/exact: px.
|
|
63
|
+
*/
|
|
64
|
+
value: number;
|
|
65
|
+
}
|
|
66
|
+
type Alignment = "left" | "center" | "right" | "justify";
|
|
67
|
+
interface TabStop {
|
|
68
|
+
/** px from the left text edge */
|
|
69
|
+
pos: number;
|
|
70
|
+
align: "left" | "center" | "right" | "decimal" | "bar";
|
|
71
|
+
leader: "none" | "dot" | "hyphen" | "underscore" | "middleDot";
|
|
72
|
+
/** w:val="clear": removes the inherited stop at this pos when tab lists
|
|
73
|
+
* merge down the style chain (never a live stop itself). */
|
|
74
|
+
clear?: boolean;
|
|
75
|
+
}
|
|
76
|
+
interface RunProps {
|
|
77
|
+
bold?: boolean;
|
|
78
|
+
italic?: boolean;
|
|
79
|
+
underline?: string;
|
|
80
|
+
strike?: boolean;
|
|
81
|
+
doubleStrike?: boolean;
|
|
82
|
+
/** Resolved primary font family name (ascii/hAnsi, theme-resolved). */
|
|
83
|
+
font?: string;
|
|
84
|
+
/** East Asian font (rFonts w:eastAsia): used for CJK codepoints. */
|
|
85
|
+
fontEastAsia?: string;
|
|
86
|
+
/** hAnsi font (rFonts w:hAnsi, theme-resolved): Word uses this channel for
|
|
87
|
+
* non-ASCII, non-CJK, non-complex characters (curly quotes, ≤, dashes). A
|
|
88
|
+
* run that declares only w:ascii leaves it inherited from the style chain. */
|
|
89
|
+
fontHAnsi?: string;
|
|
90
|
+
/** Complex-script font (rFonts w:cs): used for RTL/complex runs. */
|
|
91
|
+
fontComplex?: string;
|
|
92
|
+
/** w:rtl — this run's text is right-to-left (Arabic/Hebrew). */
|
|
93
|
+
rtl?: boolean;
|
|
94
|
+
/** Font size in px. */
|
|
95
|
+
size?: number;
|
|
96
|
+
/** CSS color; "auto" resolved to inherit/black by renderer. */
|
|
97
|
+
color?: string;
|
|
98
|
+
highlight?: string;
|
|
99
|
+
/** Character shading fill (w:shd). */
|
|
100
|
+
shading?: string;
|
|
101
|
+
/** Run border (w:bdr): a box painted around the run. Word merges adjacent
|
|
102
|
+
* runs with identical borders into one box; a run wrapping across lines
|
|
103
|
+
* closes the box on every line segment. */
|
|
104
|
+
border?: Border;
|
|
105
|
+
verticalAlign?: "baseline" | "superscript" | "subscript";
|
|
106
|
+
caps?: boolean;
|
|
107
|
+
smallCaps?: boolean;
|
|
108
|
+
/** Letter spacing px (w:spacing, twips in OOXML). */
|
|
109
|
+
letterSpacing?: number;
|
|
110
|
+
/** w:w horizontal character scaling as a fraction (1.5 = 150%). */
|
|
111
|
+
textScale?: number;
|
|
112
|
+
/** w:fitText target width in px: the run's advances scale so its text
|
|
113
|
+
* occupies exactly this width (resolved to textScale at layout time). */
|
|
114
|
+
fitText?: number;
|
|
115
|
+
/** w:position baseline shift in px, positive = raised. */
|
|
116
|
+
raise?: number;
|
|
117
|
+
/** w:outline — hollow stroked glyphs. */
|
|
118
|
+
outline?: boolean;
|
|
119
|
+
/** w:emboss / w:imprint — Word triple-draws offset copies. */
|
|
120
|
+
emboss?: boolean;
|
|
121
|
+
imprint?: boolean;
|
|
122
|
+
vanish?: boolean;
|
|
123
|
+
/** Character style id (w:rStyle). */
|
|
124
|
+
styleId?: string;
|
|
125
|
+
lang?: string;
|
|
126
|
+
}
|
|
127
|
+
interface NumberingRef {
|
|
128
|
+
numId: number;
|
|
129
|
+
ilvl: number;
|
|
130
|
+
}
|
|
131
|
+
interface ParaProps {
|
|
132
|
+
styleId?: string;
|
|
133
|
+
alignment?: Alignment;
|
|
134
|
+
/** The exact OOXML w:jc value when it is a "justify" flavor whose behavior
|
|
135
|
+
* differs from plain "both": `distribute` also stretches the LAST line, and
|
|
136
|
+
* the Arabic `*Kashida` levels elongate glyphs (kashida) so lines pack fewer
|
|
137
|
+
* words and — at medium/high — wrap to more lines. Absent for plain "both".
|
|
138
|
+
* `alignment` stays "justify" for all of these. */
|
|
139
|
+
justifyKind?: "distribute" | "lowKashida" | "mediumKashida" | "highKashida";
|
|
140
|
+
/** w:bidi — right-to-left paragraph: lines assemble RTL and default
|
|
141
|
+
* alignment flips to the right edge. */
|
|
142
|
+
bidi?: boolean;
|
|
143
|
+
/** px */
|
|
144
|
+
indentLeft?: number;
|
|
145
|
+
indentRight?: number;
|
|
146
|
+
/** Positive px; mutually exclusive with hanging in effect. */
|
|
147
|
+
indentFirstLine?: number;
|
|
148
|
+
/** Positive px hanging indent. */
|
|
149
|
+
indentHanging?: number;
|
|
150
|
+
spacingBefore?: number;
|
|
151
|
+
spacingAfter?: number;
|
|
152
|
+
/** w:beforeAutospacing/afterAutospacing: HTML-style automatic paragraph
|
|
153
|
+
* spacing — Word ignores the literal before/after and inserts one blank
|
|
154
|
+
* line's worth of space. */
|
|
155
|
+
beforeAutospacing?: boolean;
|
|
156
|
+
afterAutospacing?: boolean;
|
|
157
|
+
/** Word's default when absent is auto/1.0 via docDefaults. */
|
|
158
|
+
lineSpacing?: LineSpacing;
|
|
159
|
+
/** w:snapToGrid: whether this paragraph's lines use the section docGrid. */
|
|
160
|
+
snapToGrid?: boolean;
|
|
161
|
+
contextualSpacing?: boolean;
|
|
162
|
+
keepNext?: boolean;
|
|
163
|
+
/** w:framePr w:dropCap: the paragraph is a drop-cap letter frame. */
|
|
164
|
+
dropCap?: {
|
|
165
|
+
mode: "drop" | "margin";
|
|
166
|
+
lines: number;
|
|
167
|
+
hSpace: number;
|
|
168
|
+
pageAnchored?: boolean;
|
|
169
|
+
};
|
|
170
|
+
/** w:framePr positioned text frame (absolute-positioned paragraph the body
|
|
171
|
+
* text wraps around). Geometry in px. Individual attributes are optional so a
|
|
172
|
+
* framePr merges attribute-by-attribute across the style cascade (a direct
|
|
173
|
+
* framePr that sets only h/x/y keeps the style framePr's width/anchor — IEEE
|
|
174
|
+
* authors); the engine normalizes defaults at layout time. */
|
|
175
|
+
frame?: {
|
|
176
|
+
w?: number;
|
|
177
|
+
h?: number;
|
|
178
|
+
hRule?: "auto" | "atLeast" | "exact";
|
|
179
|
+
x?: number;
|
|
180
|
+
y?: number;
|
|
181
|
+
hAnchor?: "page" | "margin" | "text" | "column";
|
|
182
|
+
vAnchor?: "page" | "margin" | "text" | "paragraph";
|
|
183
|
+
xAlign?: "left" | "center" | "right" | "inside" | "outside";
|
|
184
|
+
yAlign?: "top" | "center" | "bottom" | "inside" | "outside" | "inline";
|
|
185
|
+
wrap?: "around" | "auto" | "notBeside" | "through" | "tight" | "none";
|
|
186
|
+
/** w:hSpace / w:vSpace: horizontal/vertical margin around the frame (px). */
|
|
187
|
+
hSpace?: number;
|
|
188
|
+
vSpace?: number;
|
|
189
|
+
};
|
|
190
|
+
keepLines?: boolean;
|
|
191
|
+
pageBreakBefore?: boolean;
|
|
192
|
+
widowControl?: boolean;
|
|
193
|
+
borders?: ParagraphBorders;
|
|
194
|
+
/** Paragraph shading fill as CSS color. */
|
|
195
|
+
shading?: string;
|
|
196
|
+
numbering?: NumberingRef | null;
|
|
197
|
+
/** A numPr that carries ilvl but no numId (Heading3 basedOn Heading2)
|
|
198
|
+
* overrides only the list LEVEL, keeping the inherited numId; the style
|
|
199
|
+
* chain applies it to `numbering` on merge. */
|
|
200
|
+
numberingLevelOverride?: number;
|
|
201
|
+
tabs?: TabStop[];
|
|
202
|
+
outlineLevel?: number;
|
|
203
|
+
/** Run props declared on pPr/rPr — apply to the paragraph mark & numbering label. */
|
|
204
|
+
markRunProps?: RunProps;
|
|
205
|
+
/**
|
|
206
|
+
* styleId of the enclosing table (set on cell paragraphs at parse time).
|
|
207
|
+
* A table style's own pPr layers between docDefaults and the paragraph
|
|
208
|
+
* style, e.g. TableGrid's `spacing after=0 line=240` overrides docDefaults'
|
|
209
|
+
* `after=200 line=276` so list cells lay out compactly.
|
|
210
|
+
*/
|
|
211
|
+
tableStyleId?: string;
|
|
212
|
+
/**
|
|
213
|
+
* Grid position of the enclosing cell plus the table's tblLook (set on cell
|
|
214
|
+
* paragraphs at parse time, like tableStyleId). Lets run/paragraph
|
|
215
|
+
* resolution layer the applicable w:tblStylePr conditional formats (e.g.
|
|
216
|
+
* firstRow bold + white) between the table style's own rPr and the
|
|
217
|
+
* paragraph style chain.
|
|
218
|
+
*/
|
|
219
|
+
tableCellCond?: {
|
|
220
|
+
look?: TableLook;
|
|
221
|
+
rowIdx: number;
|
|
222
|
+
nRows: number;
|
|
223
|
+
colStart: number;
|
|
224
|
+
colSpan: number;
|
|
225
|
+
nCols: number;
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
interface TextContent {
|
|
229
|
+
kind: "text";
|
|
230
|
+
text: string;
|
|
231
|
+
/** Source w:t element inside the run, when this text came verbatim from one. */
|
|
232
|
+
srcT?: XmlElement;
|
|
233
|
+
/** When this text is the glyph of a modern checkbox content control, the
|
|
234
|
+
* source `w14:checkbox` element (in the enclosing w:sdt's sdtPr). Its
|
|
235
|
+
* presence makes the glyph a click-to-toggle target rather than plain text. */
|
|
236
|
+
checkbox?: XmlElement;
|
|
237
|
+
}
|
|
238
|
+
interface BreakContent {
|
|
239
|
+
kind: "break";
|
|
240
|
+
breakType: "line" | "page" | "column";
|
|
241
|
+
}
|
|
242
|
+
interface TabContent {
|
|
243
|
+
kind: "tab";
|
|
244
|
+
}
|
|
245
|
+
interface PTabContent {
|
|
246
|
+
kind: "ptab";
|
|
247
|
+
/** Absolute-position tab: jump to left/center/right of the base. */
|
|
248
|
+
alignment: "left" | "center" | "right";
|
|
249
|
+
relativeTo: "margin" | "indent";
|
|
250
|
+
}
|
|
251
|
+
interface ImageContent {
|
|
252
|
+
kind: "image";
|
|
253
|
+
/** Part path of the image inside the package. */
|
|
254
|
+
part: string;
|
|
255
|
+
width: number;
|
|
256
|
+
height: number;
|
|
257
|
+
/** True when the drawing is floating (wp:anchor); v1 lays it out inline. */
|
|
258
|
+
anchored?: boolean;
|
|
259
|
+
/** a:srcRect crop, fractions of the source bitmap. */
|
|
260
|
+
crop?: {
|
|
261
|
+
l: number;
|
|
262
|
+
t: number;
|
|
263
|
+
r: number;
|
|
264
|
+
b: number;
|
|
265
|
+
};
|
|
266
|
+
/** a:xfrm rotation, degrees clockwise. */
|
|
267
|
+
rotation?: number;
|
|
268
|
+
/** a:ln picture outline (Word draws it just outside the image). */
|
|
269
|
+
border?: {
|
|
270
|
+
color: string;
|
|
271
|
+
width: number;
|
|
272
|
+
};
|
|
273
|
+
/** Source w:drawing (or pict) element, for resize/move editing. */
|
|
274
|
+
srcDrawing?: XmlElement;
|
|
275
|
+
}
|
|
276
|
+
/** OMML equation node (subset: runs, scripts, fractions, radicals). */
|
|
277
|
+
type MathNode = {
|
|
278
|
+
t: "run";
|
|
279
|
+
text: string;
|
|
280
|
+
normal?: boolean;
|
|
281
|
+
/** m:func function name (cos, log, …): Word kerns a thin space on
|
|
282
|
+
* both sides of the name. */
|
|
283
|
+
fname?: boolean;
|
|
284
|
+
} | {
|
|
285
|
+
t: "sup" | "sub";
|
|
286
|
+
base: MathNode[];
|
|
287
|
+
script: MathNode[];
|
|
288
|
+
} | {
|
|
289
|
+
t: "frac";
|
|
290
|
+
num: MathNode[];
|
|
291
|
+
den: MathNode[];
|
|
292
|
+
bar?: boolean;
|
|
293
|
+
}
|
|
294
|
+
/** Radical; deg is the optional m:deg index (∛), absent when m:degHide. */
|
|
295
|
+
| {
|
|
296
|
+
t: "rad";
|
|
297
|
+
e: MathNode[];
|
|
298
|
+
deg?: MathNode[];
|
|
299
|
+
}
|
|
300
|
+
/** n-ary operator (sum/integral); chr defaults to the integral sign. */
|
|
301
|
+
| {
|
|
302
|
+
t: "nary";
|
|
303
|
+
chr: string;
|
|
304
|
+
sub: MathNode[];
|
|
305
|
+
sup: MathNode[];
|
|
306
|
+
e: MathNode[];
|
|
307
|
+
}
|
|
308
|
+
/** Delimiters grown to the content height; beg/end default to parens.
|
|
309
|
+
* An empty beg/end string means that side has no delimiter (cases "{"). */
|
|
310
|
+
| {
|
|
311
|
+
t: "dlm";
|
|
312
|
+
beg: string;
|
|
313
|
+
end: string;
|
|
314
|
+
e: MathNode[][];
|
|
315
|
+
}
|
|
316
|
+
/** Matrix: rows x cells. */
|
|
317
|
+
| {
|
|
318
|
+
t: "mat";
|
|
319
|
+
rows: MathNode[][][];
|
|
320
|
+
}
|
|
321
|
+
/** m:eqArr equation array (cases/piecewise rows). */
|
|
322
|
+
| {
|
|
323
|
+
t: "eqarr";
|
|
324
|
+
rows: MathNode[][];
|
|
325
|
+
}
|
|
326
|
+
/** m:acc combining accent (hat/bar/vector) over the base. */
|
|
327
|
+
| {
|
|
328
|
+
t: "acc";
|
|
329
|
+
chr: string;
|
|
330
|
+
e: MathNode[];
|
|
331
|
+
}
|
|
332
|
+
/** m:groupChr horizontal group character (over/under brace). */
|
|
333
|
+
| {
|
|
334
|
+
t: "grp";
|
|
335
|
+
chr: string;
|
|
336
|
+
pos: "top" | "bot";
|
|
337
|
+
vertJc: "top" | "bot";
|
|
338
|
+
e: MathNode[];
|
|
339
|
+
}
|
|
340
|
+
/** m:limLow / m:limUpp limit stacked under/over a text operator. */
|
|
341
|
+
| {
|
|
342
|
+
t: "lim";
|
|
343
|
+
pos: "low" | "upp";
|
|
344
|
+
e: MathNode[];
|
|
345
|
+
lim: MathNode[];
|
|
346
|
+
};
|
|
347
|
+
interface MathContent {
|
|
348
|
+
kind: "math";
|
|
349
|
+
nodes: MathNode[];
|
|
350
|
+
/** Source m:oMath element (math editing). */
|
|
351
|
+
src?: XmlElement;
|
|
352
|
+
/** Display equation (wrapped in m:oMathPara): centered on its own line with
|
|
353
|
+
* display-style layout - larger n-ary operators with limits stacked
|
|
354
|
+
* above/below, and full-size fraction numerators/denominators. */
|
|
355
|
+
display?: boolean;
|
|
356
|
+
/** m:oMathParaPr/m:jc - display-equation justification. Absent: the
|
|
357
|
+
* document default (settings m:mathPr/m:defJc, itself "centerGroup" when
|
|
358
|
+
* unset). */
|
|
359
|
+
jc?: "left" | "right" | "center" | "centerGroup";
|
|
360
|
+
}
|
|
361
|
+
interface FieldContent {
|
|
362
|
+
kind: "field";
|
|
363
|
+
/** Raw field instruction, e.g. ` PAGE \\* MERGEFORMAT `. */
|
|
364
|
+
instruction: string;
|
|
365
|
+
/** Last cached result text from the file, used for unsupported fields. */
|
|
366
|
+
cachedResult: string;
|
|
367
|
+
/** When this field is a legacy FORMCHECKBOX, the source `w:checkBox` element
|
|
368
|
+
* (in the fldChar begin's w:ffData). Its presence makes the rendered ballot
|
|
369
|
+
* box a click-to-toggle target; the glyph derives from its w:checked child. */
|
|
370
|
+
checkbox?: XmlElement;
|
|
371
|
+
}
|
|
372
|
+
/** What an anchored shape's coordinates are measured from. "char" (relH=
|
|
373
|
+
* "character") measures from the anchor run's pen position; "line" (relV=
|
|
374
|
+
* "line") from the top of the line holding the anchor — both resolved from
|
|
375
|
+
* the anchor paragraph's first-pass layout. */
|
|
376
|
+
type AnchorRel = "page" | "margin" | "text" | "column" | "char" | "line";
|
|
377
|
+
interface ShapeLine {
|
|
378
|
+
type: "line";
|
|
379
|
+
x1: number;
|
|
380
|
+
y1: number;
|
|
381
|
+
x2: number;
|
|
382
|
+
y2: number;
|
|
383
|
+
color: string;
|
|
384
|
+
/** Stroke weight px. */
|
|
385
|
+
weight: number;
|
|
386
|
+
hRel: AnchorRel;
|
|
387
|
+
vRel: AnchorRel;
|
|
388
|
+
}
|
|
389
|
+
interface ShapeTextbox {
|
|
390
|
+
type: "textbox";
|
|
391
|
+
x: number;
|
|
392
|
+
y: number;
|
|
393
|
+
width: number;
|
|
394
|
+
height: number;
|
|
395
|
+
hRel: AnchorRel;
|
|
396
|
+
vRel: AnchorRel;
|
|
397
|
+
blocks: Block[];
|
|
398
|
+
/** Background fill (CSS color) painted behind the text. */
|
|
399
|
+
fill?: string;
|
|
400
|
+
/** Outline. */
|
|
401
|
+
stroke?: {
|
|
402
|
+
color: string;
|
|
403
|
+
weight: number;
|
|
404
|
+
};
|
|
405
|
+
/** Alignment-based positioning (mso-position-horizontal/vertical). */
|
|
406
|
+
hAlign?: "left" | "center" | "right";
|
|
407
|
+
vAlign?: "top" | "center" | "bottom";
|
|
408
|
+
/** Percent-of-base geometry, 0..1 (mso-*-percent / wp14 pct offsets).
|
|
409
|
+
* Bases: pctWidthRel/pctHeightRel say page vs margin. */
|
|
410
|
+
pctX?: number;
|
|
411
|
+
pctY?: number;
|
|
412
|
+
pctWidth?: number;
|
|
413
|
+
pctHeight?: number;
|
|
414
|
+
pctWidthRel?: "page" | "margin";
|
|
415
|
+
pctHeightRel?: "page" | "margin";
|
|
416
|
+
/** Vertical anchoring of the text INSIDE the box (v-text-anchor). */
|
|
417
|
+
textAnchor?: "top" | "middle" | "bottom";
|
|
418
|
+
/** How body text flows around a DrawingML textbox (wp:wrap*). */
|
|
419
|
+
wrap?: WrapMode;
|
|
420
|
+
/** behindDoc: paint under the body text, never displace it. */
|
|
421
|
+
behind?: boolean;
|
|
422
|
+
/** wp:anchor @allowOverlap="0": Word shifts this shape clear of earlier
|
|
423
|
+
* overlapping floats rather than letting them overlap. Default true. */
|
|
424
|
+
allowOverlap?: boolean;
|
|
425
|
+
/** Wrap distances px (wp:anchor distT/B/L/R). */
|
|
426
|
+
dist?: {
|
|
427
|
+
t: number;
|
|
428
|
+
b: number;
|
|
429
|
+
l: number;
|
|
430
|
+
r: number;
|
|
431
|
+
};
|
|
432
|
+
/** a:xfrm rotation, degrees clockwise (rotates the whole box). */
|
|
433
|
+
rotation?: number;
|
|
434
|
+
/** Text insets px (bodyPr lIns/tIns/rIns/bIns); default 9.6/4.8. For
|
|
435
|
+
* non-rect preset geometries these INCLUDE the geometry's text-rectangle
|
|
436
|
+
* insets (ellipse: inscribed rect; diamond: middle-half rect). */
|
|
437
|
+
insets?: {
|
|
438
|
+
l: number;
|
|
439
|
+
t: number;
|
|
440
|
+
r: number;
|
|
441
|
+
b: number;
|
|
442
|
+
};
|
|
443
|
+
/** Non-rect preset geometry: paint this outline (in a viewW x viewH space
|
|
444
|
+
* scaled to the shape box) instead of a rectangle. */
|
|
445
|
+
geom?: {
|
|
446
|
+
d: string;
|
|
447
|
+
viewW: number;
|
|
448
|
+
viewH: number;
|
|
449
|
+
};
|
|
450
|
+
/** bodyPr a:noAutofit: the box does NOT grow with its text — Word hides
|
|
451
|
+
* whole lines that stick out past the shape bottom (phase23 p12 ovals:
|
|
452
|
+
* "Was 0 / B" visible, the wrapped tail rows hidden). */
|
|
453
|
+
clipText?: boolean;
|
|
454
|
+
/** bodyPr a:spAutoFit: the box grows in height to exactly fit its laid text
|
|
455
|
+
* plus the top/bottom insets (the stored cy is only Word's last cached
|
|
456
|
+
* value). Width is fixed. */
|
|
457
|
+
autofitHeight?: boolean;
|
|
458
|
+
/** Linked text-box chain id (wps:txbx/@id or wps:linkedTxbx/@id): boxes with
|
|
459
|
+
* the same id form one story. The seq-0 box (wps:txbx) holds the content;
|
|
460
|
+
* later boxes (wps:linkedTxbx, chainSeq>0) are empty sinks that continue the
|
|
461
|
+
* overflow. */
|
|
462
|
+
chainId?: string;
|
|
463
|
+
/** Position in the linked chain (0 = the content box). */
|
|
464
|
+
chainSeq?: number;
|
|
465
|
+
/** Source w:drawing element, attached at parse time so the shape's fill can
|
|
466
|
+
* be an interactive hit target (select the shape instead of the body text
|
|
467
|
+
* behind it). */
|
|
468
|
+
srcDrawing?: XmlElement;
|
|
469
|
+
/** bodyPr a:prstTxWarp preset name (textArchUp, textWave1, textChevron,
|
|
470
|
+
* textCirclePour, …): the shape's text is bent onto the preset's envelope
|
|
471
|
+
* rather than flowed as ordinary lines. "textNoShape" (no warp) is dropped. */
|
|
472
|
+
warp?: string;
|
|
473
|
+
}
|
|
474
|
+
/** WordArt (VML v:textpath, e.g. a "CONFIDENTIAL" watermark): text scaled to
|
|
475
|
+
* fill a box, optionally rotated, painted semi-transparent behind the body. */
|
|
476
|
+
interface ShapeWordArt {
|
|
477
|
+
type: "wordart";
|
|
478
|
+
text: string;
|
|
479
|
+
fontFamily: string;
|
|
480
|
+
bold?: boolean;
|
|
481
|
+
italic?: boolean;
|
|
482
|
+
/** CSS fill color. */
|
|
483
|
+
fill: string;
|
|
484
|
+
/** 0..1 alpha. */
|
|
485
|
+
opacity: number;
|
|
486
|
+
x: number;
|
|
487
|
+
y: number;
|
|
488
|
+
width: number;
|
|
489
|
+
height: number;
|
|
490
|
+
hRel: AnchorRel;
|
|
491
|
+
vRel: AnchorRel;
|
|
492
|
+
hAlign?: "left" | "center" | "right";
|
|
493
|
+
vAlign?: "top" | "center" | "bottom";
|
|
494
|
+
/** Clockwise degrees. */
|
|
495
|
+
rotation: number;
|
|
496
|
+
behind?: boolean;
|
|
497
|
+
/** The v:textpath font-size (px). Only used when the text is NOT fit to the
|
|
498
|
+
* shape (see noFit). */
|
|
499
|
+
fontSize?: number;
|
|
500
|
+
/** The referenced v:shapetype has a malformed text-guide path (missing
|
|
501
|
+
* coordinates), so Word cannot compute the fitshape scale and falls back to
|
|
502
|
+
* drawing the string at its nominal font-size — a near-invisible mark rather
|
|
503
|
+
* than a box-filling watermark. Render at fontSize, unstretched, to match. */
|
|
504
|
+
noFit?: boolean;
|
|
505
|
+
/** Source VML shape element (v:shape / v:rect) for interactive editing:
|
|
506
|
+
* the v:textpath string, fill/opacity, and rotation live under it. */
|
|
507
|
+
src?: XmlElement;
|
|
508
|
+
}
|
|
509
|
+
interface ShapeArt {
|
|
510
|
+
type: "art";
|
|
511
|
+
srcDrawing?: XmlElement;
|
|
512
|
+
x: number;
|
|
513
|
+
y: number;
|
|
514
|
+
/** Percent-of-page offsets (wp14:pctPos*Offset), 0..1. */
|
|
515
|
+
pctX?: number;
|
|
516
|
+
pctY?: number;
|
|
517
|
+
width: number;
|
|
518
|
+
height: number;
|
|
519
|
+
hRel: AnchorRel;
|
|
520
|
+
vRel: AnchorRel;
|
|
521
|
+
hAlign?: "left" | "center" | "right";
|
|
522
|
+
behind?: boolean;
|
|
523
|
+
lines: DrawingLine[];
|
|
524
|
+
images: DrawingImage[];
|
|
525
|
+
paths: DrawingPath[];
|
|
526
|
+
/** Positioned text bodies inside the group (wps textboxes, dsp:sp txBody). */
|
|
527
|
+
texts?: DrawingTextShape[];
|
|
528
|
+
}
|
|
529
|
+
/** How text interacts with a floating image. */
|
|
530
|
+
type WrapMode = "square" | "topAndBottom" | "none";
|
|
531
|
+
interface ShapeImage {
|
|
532
|
+
type: "image";
|
|
533
|
+
part: string;
|
|
534
|
+
/** Offset from the anchor origin, px. */
|
|
535
|
+
x: number;
|
|
536
|
+
y: number;
|
|
537
|
+
width: number;
|
|
538
|
+
height: number;
|
|
539
|
+
hRel: AnchorRel;
|
|
540
|
+
vRel: AnchorRel;
|
|
541
|
+
/** Horizontal alignment when the file uses wp:align instead of an offset. */
|
|
542
|
+
hAlign?: "left" | "center" | "right";
|
|
543
|
+
/** Vertical alignment keyword (VML mso-position-vertical; watermarks center). */
|
|
544
|
+
vAlign?: "top" | "center" | "bottom";
|
|
545
|
+
wrap: WrapMode;
|
|
546
|
+
/** behindDoc anchors render under the text and never displace it. */
|
|
547
|
+
behind?: boolean;
|
|
548
|
+
/** Wrap distances px (wp:anchor distT/B/L/R); text clears the image by these. */
|
|
549
|
+
dist?: {
|
|
550
|
+
t: number;
|
|
551
|
+
b: number;
|
|
552
|
+
l: number;
|
|
553
|
+
r: number;
|
|
554
|
+
};
|
|
555
|
+
crop?: {
|
|
556
|
+
l: number;
|
|
557
|
+
t: number;
|
|
558
|
+
r: number;
|
|
559
|
+
b: number;
|
|
560
|
+
};
|
|
561
|
+
rotation?: number;
|
|
562
|
+
/** Watermark "washout" recolor (VML v:imagedata gain/blacklevel, 0..1). */
|
|
563
|
+
washout?: {
|
|
564
|
+
gain: number;
|
|
565
|
+
blacklevel: number;
|
|
566
|
+
};
|
|
567
|
+
/** Source w:drawing element (editing). */
|
|
568
|
+
srcDrawing?: XmlElement;
|
|
569
|
+
}
|
|
570
|
+
type Shape = ShapeLine | ShapeTextbox | ShapeImage | ShapeArt | ShapeWordArt;
|
|
571
|
+
/**
|
|
572
|
+
* Floating/anchored object: does not occupy inline space; positioned against
|
|
573
|
+
* page/margin/paragraph during layout. (How classic pleading paper draws its
|
|
574
|
+
* margin line numbers and vertical rules.)
|
|
575
|
+
*/
|
|
576
|
+
interface AnchorContent {
|
|
577
|
+
kind: "anchor";
|
|
578
|
+
shape: Shape;
|
|
579
|
+
}
|
|
580
|
+
/** A stroked segment inside a composite drawing, px relative to its box. */
|
|
581
|
+
interface DrawingLine {
|
|
582
|
+
x1: number;
|
|
583
|
+
y1: number;
|
|
584
|
+
x2: number;
|
|
585
|
+
y2: number;
|
|
586
|
+
color: string;
|
|
587
|
+
weight: number;
|
|
588
|
+
}
|
|
589
|
+
interface DrawingImage {
|
|
590
|
+
part: string;
|
|
591
|
+
x: number;
|
|
592
|
+
y: number;
|
|
593
|
+
width: number;
|
|
594
|
+
height: number;
|
|
595
|
+
crop?: {
|
|
596
|
+
l: number;
|
|
597
|
+
t: number;
|
|
598
|
+
r: number;
|
|
599
|
+
b: number;
|
|
600
|
+
};
|
|
601
|
+
rotation?: number;
|
|
602
|
+
/** a:ln picture outline (Word draws it just outside the image). */
|
|
603
|
+
border?: {
|
|
604
|
+
color: string;
|
|
605
|
+
width: number;
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Composite inline drawing (DrawingML groups): vector lines + placed images
|
|
610
|
+
* inside a width×height box that flows like an image.
|
|
611
|
+
*/
|
|
612
|
+
interface DrawingContent {
|
|
613
|
+
kind: "drawing";
|
|
614
|
+
width: number;
|
|
615
|
+
height: number;
|
|
616
|
+
lines: DrawingLine[];
|
|
617
|
+
images: DrawingImage[];
|
|
618
|
+
/** Freeform vector shapes (a:custGeom), as SVG path data. */
|
|
619
|
+
paths?: DrawingPath[];
|
|
620
|
+
/** An INLINE wps text box (wp:inline wps:txbx): a fixed-extent box that
|
|
621
|
+
* flows in the text (occupying its width x height like an inline image) and
|
|
622
|
+
* carries a fill/border + its own block content. Distinct from the floating
|
|
623
|
+
* ShapeTextbox, which is absolutely placed via a wp:anchor. */
|
|
624
|
+
textbox?: {
|
|
625
|
+
blocks: Block[];
|
|
626
|
+
fill?: string;
|
|
627
|
+
stroke?: {
|
|
628
|
+
color: string;
|
|
629
|
+
weight: number;
|
|
630
|
+
};
|
|
631
|
+
insets?: {
|
|
632
|
+
l: number;
|
|
633
|
+
t: number;
|
|
634
|
+
r: number;
|
|
635
|
+
b: number;
|
|
636
|
+
};
|
|
637
|
+
textAnchor?: "top" | "middle" | "bottom";
|
|
638
|
+
};
|
|
639
|
+
/** Source w:drawing element (select/move as a group). */
|
|
640
|
+
srcDrawing?: XmlElement;
|
|
641
|
+
/** Positioned text bodies inside the drawing (multi-textbox groups and
|
|
642
|
+
* SmartArt cached-drawing shapes). Painted above lines/paths. */
|
|
643
|
+
texts?: DrawingTextShape[];
|
|
644
|
+
}
|
|
645
|
+
/** A text body positioned inside a composite drawing (a wps textbox in a
|
|
646
|
+
* group, or a SmartArt dsp:sp txBody), px relative to the drawing's box. */
|
|
647
|
+
interface DrawingTextShape {
|
|
648
|
+
x: number;
|
|
649
|
+
y: number;
|
|
650
|
+
width: number;
|
|
651
|
+
height: number;
|
|
652
|
+
blocks: Block[];
|
|
653
|
+
/** Background fill painted behind the text box. */
|
|
654
|
+
fill?: string;
|
|
655
|
+
/** Outline. */
|
|
656
|
+
stroke?: {
|
|
657
|
+
color: string;
|
|
658
|
+
weight: number;
|
|
659
|
+
};
|
|
660
|
+
/** Text insets px (bodyPr lIns/tIns/rIns/bIns). */
|
|
661
|
+
insets: {
|
|
662
|
+
l: number;
|
|
663
|
+
t: number;
|
|
664
|
+
r: number;
|
|
665
|
+
b: number;
|
|
666
|
+
};
|
|
667
|
+
/** Vertical anchoring of the text inside the box (bodyPr anchor). */
|
|
668
|
+
textAnchor?: "top" | "middle" | "bottom";
|
|
669
|
+
}
|
|
670
|
+
interface DrawingPath {
|
|
671
|
+
/** Position/size inside the drawing, px. */
|
|
672
|
+
x: number;
|
|
673
|
+
y: number;
|
|
674
|
+
width: number;
|
|
675
|
+
height: number;
|
|
676
|
+
/** SVG path in the `viewW x viewH` source coordinate space. */
|
|
677
|
+
d: string;
|
|
678
|
+
viewW: number;
|
|
679
|
+
viewH: number;
|
|
680
|
+
fill?: string;
|
|
681
|
+
stroke?: {
|
|
682
|
+
color: string;
|
|
683
|
+
width: number;
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Footnote/endnote reference mark. In body text (w:footnoteReference /
|
|
688
|
+
* w:endnoteReference) `id` points into the notes part. Inside a note body,
|
|
689
|
+
* w:footnoteRef / w:endnoteRef render the note's own mark: `self` is true and
|
|
690
|
+
* `id` is meaningless.
|
|
691
|
+
*/
|
|
692
|
+
interface NoteRefContent {
|
|
693
|
+
kind: "noteRef";
|
|
694
|
+
noteType: "footnote" | "endnote";
|
|
695
|
+
id: number;
|
|
696
|
+
self?: boolean;
|
|
697
|
+
}
|
|
698
|
+
/** w:ruby — an East-Asian ruby (furigana) cluster: an annotation run (w:rt)
|
|
699
|
+
* riding above a base run (w:rubyBase). Both sides render as their own runs;
|
|
700
|
+
* the annotation is centered over the base and raised above its baseline. */
|
|
701
|
+
interface RubyContent {
|
|
702
|
+
kind: "ruby";
|
|
703
|
+
base: Run;
|
|
704
|
+
rt: Run;
|
|
705
|
+
/** w:rubyPr/w:hpsRaise — annotation baseline raise above the base baseline,
|
|
706
|
+
* half-points. */
|
|
707
|
+
hpsRaise?: number;
|
|
708
|
+
/** w:rubyPr/w:rubyAlign — how the annotation distributes over the base. */
|
|
709
|
+
align?: "center" | "distributeLetter" | "distributeSpace" | "left" | "right" | "rightVertical";
|
|
710
|
+
}
|
|
711
|
+
type RunContent = MathContent | TextContent | BreakContent | TabContent | PTabContent | ImageContent | FieldContent | AnchorContent | DrawingContent | NoteRefContent | RubyContent;
|
|
712
|
+
interface Run {
|
|
713
|
+
type: "run";
|
|
714
|
+
props: RunProps;
|
|
715
|
+
content: RunContent[];
|
|
716
|
+
/** Source w:r element. */
|
|
717
|
+
src?: XmlElement;
|
|
718
|
+
/** Element whose children array contains src (w:p, w:hyperlink, …). */
|
|
719
|
+
srcParent?: XmlElement;
|
|
720
|
+
}
|
|
721
|
+
interface Hyperlink {
|
|
722
|
+
type: "hyperlink";
|
|
723
|
+
href?: string;
|
|
724
|
+
anchor?: string;
|
|
725
|
+
runs: Run[];
|
|
726
|
+
}
|
|
727
|
+
type ParaChild = Run | Hyperlink;
|
|
728
|
+
interface Paragraph {
|
|
729
|
+
type: "paragraph";
|
|
730
|
+
props: ParaProps;
|
|
731
|
+
children: ParaChild[];
|
|
732
|
+
/** Section break attached to this paragraph's pPr (ends a section). */
|
|
733
|
+
sectionBreak?: SectionProps;
|
|
734
|
+
/** w:bookmarkStart names in this paragraph (PAGEREF targets). */
|
|
735
|
+
bookmarks?: string[];
|
|
736
|
+
/** Final revision view: the paragraph mark AND all content are tracked
|
|
737
|
+
* deletions — the paragraph does not exist (no line, no numbering). */
|
|
738
|
+
revisionHidden?: boolean;
|
|
739
|
+
/** Source w:p element. */
|
|
740
|
+
src?: XmlElement;
|
|
741
|
+
}
|
|
742
|
+
interface TableCellProps {
|
|
743
|
+
/** Preferred width px (from tcW when dxa). */
|
|
744
|
+
width?: number;
|
|
745
|
+
gridSpan: number;
|
|
746
|
+
vMerge?: "restart" | "continue";
|
|
747
|
+
borders?: {
|
|
748
|
+
top?: Border;
|
|
749
|
+
bottom?: Border;
|
|
750
|
+
left?: Border;
|
|
751
|
+
right?: Border;
|
|
752
|
+
tl2br?: Border;
|
|
753
|
+
tr2bl?: Border;
|
|
754
|
+
};
|
|
755
|
+
shading?: string;
|
|
756
|
+
/** Cell margins px. */
|
|
757
|
+
margins?: {
|
|
758
|
+
top?: number;
|
|
759
|
+
right?: number;
|
|
760
|
+
bottom?: number;
|
|
761
|
+
left?: number;
|
|
762
|
+
};
|
|
763
|
+
verticalAlign?: "top" | "center" | "bottom";
|
|
764
|
+
textDirection?: "btLr" | "tbRl";
|
|
765
|
+
}
|
|
766
|
+
interface TableCell {
|
|
767
|
+
props: TableCellProps;
|
|
768
|
+
blocks: Block[];
|
|
769
|
+
}
|
|
770
|
+
interface TableRowProps {
|
|
771
|
+
/** px; undefined = auto */
|
|
772
|
+
height?: number;
|
|
773
|
+
heightRule?: "auto" | "atLeast" | "exact";
|
|
774
|
+
cantSplit?: boolean;
|
|
775
|
+
/** Repeat as header row on each page. */
|
|
776
|
+
tblHeader?: boolean;
|
|
777
|
+
}
|
|
778
|
+
interface TableRow {
|
|
779
|
+
props: TableRowProps;
|
|
780
|
+
cells: TableCell[];
|
|
781
|
+
}
|
|
782
|
+
interface TableProps {
|
|
783
|
+
styleId?: string;
|
|
784
|
+
/** px table indent from left margin. */
|
|
785
|
+
indent?: number;
|
|
786
|
+
alignment?: Alignment;
|
|
787
|
+
/** w:bidiVisual — RTL table: column order reverses and the table hugs the
|
|
788
|
+
* right margin. */
|
|
789
|
+
bidiVisual?: boolean;
|
|
790
|
+
borders?: {
|
|
791
|
+
top?: Border;
|
|
792
|
+
bottom?: Border;
|
|
793
|
+
left?: Border;
|
|
794
|
+
right?: Border;
|
|
795
|
+
insideH?: Border;
|
|
796
|
+
insideV?: Border;
|
|
797
|
+
};
|
|
798
|
+
/** Default cell margins px. */
|
|
799
|
+
cellMargins?: {
|
|
800
|
+
top?: number;
|
|
801
|
+
right?: number;
|
|
802
|
+
bottom?: number;
|
|
803
|
+
left?: number;
|
|
804
|
+
};
|
|
805
|
+
/** w:tblCellSpacing px — old-style separated cell borders: every cell gets
|
|
806
|
+
* its own border box inset by this much from the grid slot on all sides
|
|
807
|
+
* (adjacent cells end up 2x apart), and the table outline is a separate box
|
|
808
|
+
* around everything. */
|
|
809
|
+
cellSpacing?: number;
|
|
810
|
+
/** w:tblpPr — floating table: absolutely positioned against page/margin/
|
|
811
|
+
* column, painted over an opaque white sheet, with body text (including
|
|
812
|
+
* text EARLIER in the flow on the same page) wrapping square around it. */
|
|
813
|
+
floating?: {
|
|
814
|
+
hAnchor: "page" | "margin" | "text";
|
|
815
|
+
vAnchor: "page" | "margin" | "text";
|
|
816
|
+
/** tblpX/tblpY px (absent when an alignment keyword is used). */
|
|
817
|
+
x?: number;
|
|
818
|
+
y?: number;
|
|
819
|
+
xAlign?: "left" | "center" | "right";
|
|
820
|
+
yAlign?: "top" | "center" | "bottom";
|
|
821
|
+
/** Wrap distances px (leftFromText, …). */
|
|
822
|
+
dist: {
|
|
823
|
+
l: number;
|
|
824
|
+
r: number;
|
|
825
|
+
t: number;
|
|
826
|
+
b: number;
|
|
827
|
+
};
|
|
828
|
+
/** w:tblOverlap "never": shift clear of earlier floating tables. */
|
|
829
|
+
allowOverlap: boolean;
|
|
830
|
+
};
|
|
831
|
+
/** Preferred total width px (tblW dxa) or undefined for auto. */
|
|
832
|
+
width?: number;
|
|
833
|
+
/** Preferred total width as a fraction of available width (tblW pct). */
|
|
834
|
+
widthPct?: number;
|
|
835
|
+
layout?: "fixed" | "autofit";
|
|
836
|
+
/** w:tblLook flags controlling which conditional formats apply. */
|
|
837
|
+
tblLook?: TableLook;
|
|
838
|
+
}
|
|
839
|
+
/** w:tblLook flags controlling which conditional table-style formats apply. */
|
|
840
|
+
interface TableLook {
|
|
841
|
+
firstRow: boolean;
|
|
842
|
+
lastRow: boolean;
|
|
843
|
+
firstColumn: boolean;
|
|
844
|
+
lastColumn: boolean;
|
|
845
|
+
noHBand: boolean;
|
|
846
|
+
noVBand: boolean;
|
|
847
|
+
}
|
|
848
|
+
interface Table {
|
|
849
|
+
type: "table";
|
|
850
|
+
props: TableProps;
|
|
851
|
+
/** Column grid widths px (tblGrid). */
|
|
852
|
+
grid: number[];
|
|
853
|
+
rows: TableRow[];
|
|
854
|
+
/** Source w:tbl element. */
|
|
855
|
+
src?: XmlElement;
|
|
856
|
+
}
|
|
857
|
+
type Block = Paragraph | Table;
|
|
858
|
+
interface HeaderFooterRefs {
|
|
859
|
+
default?: string;
|
|
860
|
+
first?: string;
|
|
861
|
+
even?: string;
|
|
862
|
+
}
|
|
863
|
+
interface ColumnSpec {
|
|
864
|
+
count: number;
|
|
865
|
+
/** Space between columns px. */
|
|
866
|
+
space: number;
|
|
867
|
+
/** Explicit widths px when equalWidth=false. */
|
|
868
|
+
widths?: number[];
|
|
869
|
+
/** Per-column trailing space px (w:col w:space), when explicit w:col
|
|
870
|
+
* entries are present. spaces[i] separates column i from column i+1. */
|
|
871
|
+
spaces?: number[];
|
|
872
|
+
/** w:cols w:sep: paint a vertical rule centered in each inter-column gap. */
|
|
873
|
+
sep?: boolean;
|
|
874
|
+
}
|
|
875
|
+
interface SectionProps {
|
|
876
|
+
pageWidth: number;
|
|
877
|
+
pageHeight: number;
|
|
878
|
+
marginTop: number;
|
|
879
|
+
marginRight: number;
|
|
880
|
+
marginBottom: number;
|
|
881
|
+
marginLeft: number;
|
|
882
|
+
/** Distance of header top from page top, px (w:headerReference distance). */
|
|
883
|
+
headerDistance: number;
|
|
884
|
+
footerDistance: number;
|
|
885
|
+
gutter: number;
|
|
886
|
+
headerRefs: HeaderFooterRefs;
|
|
887
|
+
footerRefs: HeaderFooterRefs;
|
|
888
|
+
/** Different first-page header/footer enabled. */
|
|
889
|
+
titlePage: boolean;
|
|
890
|
+
/** Page numbering restart value, if set. */
|
|
891
|
+
pageNumberStart?: number;
|
|
892
|
+
pageNumberFormat?: string;
|
|
893
|
+
columns: ColumnSpec;
|
|
894
|
+
/** w:docGrid type=lines/linesAndChars: minimum single-line height (px) that
|
|
895
|
+
* the line-spacing multiplier is applied over. Word snaps every line's font
|
|
896
|
+
* height up to this grid pitch (CJK documents). */
|
|
897
|
+
docGridLinePitch?: number;
|
|
898
|
+
/** Present w:docGrid type; omitted w:type means "default". */
|
|
899
|
+
docGridType?: "default" | "lines" | "linesAndChars" | "snapToChars";
|
|
900
|
+
/** w:docGrid type="charsAndLines": a combined char+line grid that (in compat
|
|
901
|
+
* 15) keeps natural East-Asian line pitch. Drives the CJK line-height
|
|
902
|
+
* correction during measurement. */
|
|
903
|
+
docGridCharGrid?: boolean;
|
|
904
|
+
type?: "nextPage" | "continuous" | "evenPage" | "oddPage" | "nextColumn";
|
|
905
|
+
/** Vertical alignment of page content. */
|
|
906
|
+
vAlign?: "top" | "center" | "both" | "bottom";
|
|
907
|
+
/** w:pgBorders. Offsets (border.space, px) measure from text or page edge. */
|
|
908
|
+
pageBorders?: {
|
|
909
|
+
top?: Border;
|
|
910
|
+
bottom?: Border;
|
|
911
|
+
left?: Border;
|
|
912
|
+
right?: Border;
|
|
913
|
+
offsetFrom: "text" | "page";
|
|
914
|
+
};
|
|
915
|
+
/** w:lnNumType: margin line numbering. distance px from the text edge. */
|
|
916
|
+
lineNumbering?: {
|
|
917
|
+
countBy: number;
|
|
918
|
+
start: number;
|
|
919
|
+
distance: number;
|
|
920
|
+
restart: "continuous" | "newPage" | "newSection";
|
|
921
|
+
};
|
|
922
|
+
/** Footnote/endnote mark numbering (w:footnotePr / w:endnotePr). */
|
|
923
|
+
footnoteNumFmt?: string;
|
|
924
|
+
footnoteNumStart?: number;
|
|
925
|
+
endnoteNumFmt?: string;
|
|
926
|
+
endnoteNumStart?: number;
|
|
927
|
+
/** w:textDirection tbRl: the whole section flows as East-Asian vertical
|
|
928
|
+
* writing — lines run top-to-bottom, progressing right-to-left. */
|
|
929
|
+
textDirection?: "tbRl";
|
|
930
|
+
}
|
|
931
|
+
interface Section {
|
|
932
|
+
props: SectionProps;
|
|
933
|
+
blocks: Block[];
|
|
934
|
+
}
|
|
935
|
+
/** A review comment from word/comments.xml. */
|
|
936
|
+
interface DocComment {
|
|
937
|
+
id: string;
|
|
938
|
+
author: string;
|
|
939
|
+
initials?: string;
|
|
940
|
+
/** ISO timestamp from w:date, verbatim. */
|
|
941
|
+
date?: string;
|
|
942
|
+
/** Plain text of the comment body (paragraphs joined with newlines). */
|
|
943
|
+
text: string;
|
|
944
|
+
/** w14:paraId of the comment's last body paragraph (threading key). */
|
|
945
|
+
paraId?: string;
|
|
946
|
+
/** Parent comment id when this comment is a reply (commentsExtended). */
|
|
947
|
+
parentId?: string;
|
|
948
|
+
}
|
|
949
|
+
interface HeaderFooter {
|
|
950
|
+
blocks: Block[];
|
|
951
|
+
}
|
|
952
|
+
/** One w:tblStylePr conditional-formatting block (firstRow, band1Horz, …). */
|
|
953
|
+
interface TableCondFormat {
|
|
954
|
+
/** Cell shading fill as CSS color. */
|
|
955
|
+
shd?: string;
|
|
956
|
+
/** Conditional cell borders. */
|
|
957
|
+
borders?: {
|
|
958
|
+
top?: Border;
|
|
959
|
+
bottom?: Border;
|
|
960
|
+
left?: Border;
|
|
961
|
+
right?: Border;
|
|
962
|
+
insideH?: Border;
|
|
963
|
+
insideV?: Border;
|
|
964
|
+
};
|
|
965
|
+
/** Conditional run bold (firstRow/firstCol headers). */
|
|
966
|
+
bold?: boolean;
|
|
967
|
+
/** Full conditional run props (w:tblStylePr > w:rPr). */
|
|
968
|
+
rPr?: RunProps;
|
|
969
|
+
}
|
|
970
|
+
type TableCondType = "wholeTable" | "band1Vert" | "band2Vert" | "band1Horz" | "band2Horz" | "firstRow" | "lastRow" | "firstCol" | "lastCol" | "nwCell" | "neCell" | "swCell" | "seCell";
|
|
971
|
+
interface Style {
|
|
972
|
+
id: string;
|
|
973
|
+
type: "paragraph" | "character" | "table" | "numbering";
|
|
974
|
+
name?: string;
|
|
975
|
+
basedOn?: string;
|
|
976
|
+
isDefault?: boolean;
|
|
977
|
+
pPr?: ParaProps;
|
|
978
|
+
rPr?: RunProps;
|
|
979
|
+
tblPr?: TableProps;
|
|
980
|
+
/** w:tblStylePr conditional formats, by type (table styles only). */
|
|
981
|
+
condFormats?: Map<TableCondType, TableCondFormat>;
|
|
982
|
+
/** w:tblStyleRowBandSize / ColBandSize (default 1). */
|
|
983
|
+
rowBandSize?: number;
|
|
984
|
+
colBandSize?: number;
|
|
985
|
+
}
|
|
986
|
+
interface Styles {
|
|
987
|
+
byId: Map<string, Style>;
|
|
988
|
+
defaultParagraphStyle?: string;
|
|
989
|
+
defaultRPr: RunProps;
|
|
990
|
+
defaultPPr: ParaProps;
|
|
991
|
+
}
|
|
992
|
+
interface NumberingLevel {
|
|
993
|
+
ilvl: number;
|
|
994
|
+
start: number;
|
|
995
|
+
format: string;
|
|
996
|
+
/** Template like "%1." */
|
|
997
|
+
text: string;
|
|
998
|
+
alignment: Alignment;
|
|
999
|
+
/** Paragraph props contributed by the level (indents). */
|
|
1000
|
+
pPr?: ParaProps;
|
|
1001
|
+
rPr?: RunProps;
|
|
1002
|
+
suffix: "tab" | "space" | "nothing";
|
|
1003
|
+
restartAfter?: number;
|
|
1004
|
+
}
|
|
1005
|
+
interface AbstractNum {
|
|
1006
|
+
id: number;
|
|
1007
|
+
levels: Map<number, NumberingLevel>;
|
|
1008
|
+
numStyleLink?: string;
|
|
1009
|
+
}
|
|
1010
|
+
interface NumInstance {
|
|
1011
|
+
numId: number;
|
|
1012
|
+
abstractNumId: number;
|
|
1013
|
+
overrides: Map<number, {
|
|
1014
|
+
startOverride?: number;
|
|
1015
|
+
level?: NumberingLevel;
|
|
1016
|
+
}>;
|
|
1017
|
+
}
|
|
1018
|
+
interface Numbering {
|
|
1019
|
+
abstract: Map<number, AbstractNum>;
|
|
1020
|
+
instances: Map<number, NumInstance>;
|
|
1021
|
+
}
|
|
1022
|
+
interface Theme {
|
|
1023
|
+
majorFont: string;
|
|
1024
|
+
minorFont: string;
|
|
1025
|
+
majorBidiFont?: string;
|
|
1026
|
+
minorBidiFont?: string;
|
|
1027
|
+
/** East Asian faces from theme <a:ea> (fontScheme major/minorFont). Word's
|
|
1028
|
+
* eastAsiaTheme="minor/majorEastAsia" resolves through these, NOT the Latin
|
|
1029
|
+
* minor/major font — routing a CJK run's theme reference to the Latin face
|
|
1030
|
+
* (Calibri) leaves East Asian text in a glyphless Latin font. */
|
|
1031
|
+
majorEastAsiaFont?: string;
|
|
1032
|
+
minorEastAsiaFont?: string;
|
|
1033
|
+
colors: Map<string, string>;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/** A read-only view over the OPC (zip) package inside a .docx file. */
|
|
1037
|
+
declare class Package {
|
|
1038
|
+
private files;
|
|
1039
|
+
constructor(data: Uint8Array);
|
|
1040
|
+
static from(data: ArrayBuffer | Uint8Array): Package;
|
|
1041
|
+
has(name: string): boolean;
|
|
1042
|
+
binary(name: string): Uint8Array | undefined;
|
|
1043
|
+
text(name: string): string | undefined;
|
|
1044
|
+
names(): string[];
|
|
1045
|
+
/** Raw entry map (shared, do not mutate) — used for write-back. */
|
|
1046
|
+
raw(): Record<string, Uint8Array>;
|
|
1047
|
+
/** OPC part names never start with '/' inside the zip; tolerate both. */
|
|
1048
|
+
private normalize;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
interface Relationship {
|
|
1052
|
+
id: string;
|
|
1053
|
+
type: string;
|
|
1054
|
+
target: string;
|
|
1055
|
+
external: boolean;
|
|
1056
|
+
}
|
|
1057
|
+
type Relationships = Map<string, Relationship>;
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* A fully parsed .docx: sections of blocks, styles, numbering, theme, and
|
|
1061
|
+
* header/footer parts, with helpers to resolve effective formatting.
|
|
1062
|
+
*/
|
|
1063
|
+
declare class DocxDocument {
|
|
1064
|
+
/** Changes whenever refresh() rebuilds the parsed model. Plain in-place text
|
|
1065
|
+
* edits can keep this stable so incremental layout reuses model-only caches. */
|
|
1066
|
+
private _modelVersion;
|
|
1067
|
+
get modelVersion(): number;
|
|
1068
|
+
readonly pkg: Package;
|
|
1069
|
+
readonly theme: Theme;
|
|
1070
|
+
styles: Styles;
|
|
1071
|
+
numbering: Numbering;
|
|
1072
|
+
sections: Section[];
|
|
1073
|
+
/** Header/footer parts keyed by relationship id from document.xml.rels. */
|
|
1074
|
+
readonly headers: Map<string, HeaderFooter>;
|
|
1075
|
+
readonly footers: Map<string, HeaderFooter>;
|
|
1076
|
+
/** Note content by note id (render-only; sources stripped). */
|
|
1077
|
+
readonly footnotes: Map<number, Block[]>;
|
|
1078
|
+
readonly endnotes: Map<number, Block[]>;
|
|
1079
|
+
/** `_Ref` cross-reference bookmark ranges (name → captured runs). REF
|
|
1080
|
+
* fields re-render the referenced text from these — Word recomputes REF on
|
|
1081
|
+
* open, so the cached field result in the file is stale. */
|
|
1082
|
+
refBookmarks: Map<string, Run[]>;
|
|
1083
|
+
readonly documentRels: Relationships;
|
|
1084
|
+
/** settings.xml w:evenAndOddHeaders — enables the "even" header/footer variants. */
|
|
1085
|
+
readonly evenAndOddHeaders: boolean;
|
|
1086
|
+
/** settings.xml w:mirrorMargins — facing-page (book fold) margins: even
|
|
1087
|
+
* (verso) pages swap the left/right margins and place the gutter on the
|
|
1088
|
+
* inside (right) edge so the binding margin stays on the inner side of
|
|
1089
|
+
* each spread. */
|
|
1090
|
+
readonly mirrorMargins: boolean;
|
|
1091
|
+
/** settings.xml w:defaultTabStop in px (Word default 0.5"). */
|
|
1092
|
+
readonly defaultTabStop: number;
|
|
1093
|
+
/** settings.xml w:compat compatibilityMode (12=Word2007, 14=Word2010,
|
|
1094
|
+
* 15=Word2013+). Word 2013 (mode 15) introduced suppressing a paragraph's
|
|
1095
|
+
* space-before when it lands at the top of a page; mode 14 and earlier keep
|
|
1096
|
+
* it (nccih: a Heading1/2 after a page break sits at margin + its before).
|
|
1097
|
+
* Absent → treated as current (15). */
|
|
1098
|
+
readonly compatibilityMode: number;
|
|
1099
|
+
/** settings.xml m:mathPr/m:defJc — default justification for display
|
|
1100
|
+
* equations whose m:oMathParaPr carries no explicit m:jc (Word default:
|
|
1101
|
+
* centerGroup — the rows of a broken equation left-align to each other and
|
|
1102
|
+
* the group is centered in the column). */
|
|
1103
|
+
readonly mathDefJc: "left" | "right" | "center" | "centerGroup";
|
|
1104
|
+
/** settings.xml m:mathPr/m:wrapIndent in px (Word default 1440tw = 1"):
|
|
1105
|
+
* indent of auto-wrapped display-equation continuation rows from the
|
|
1106
|
+
* equation group's left edge (dense p13: the "+Dc(...)" continuations sit
|
|
1107
|
+
* exactly 72pt right of the explicit rows). */
|
|
1108
|
+
readonly mathWrapIndent: number;
|
|
1109
|
+
/** Review comments from word/comments.xml (empty when the part is absent).
|
|
1110
|
+
* Re-derived from the retained comments XML on every refresh(). */
|
|
1111
|
+
comments: DocComment[];
|
|
1112
|
+
/** Retained comments.xml tree (editing + save round-trip), when present. */
|
|
1113
|
+
private commentsPart;
|
|
1114
|
+
private commentsRoot;
|
|
1115
|
+
/** Retained commentsExtended.xml tree (comment threading), when present. */
|
|
1116
|
+
private commentsExtPart;
|
|
1117
|
+
private commentsExtRoot;
|
|
1118
|
+
private commentsExtDirty;
|
|
1119
|
+
/** Conditional table formats per table style id, keyed by the Styles object
|
|
1120
|
+
* so re-parsing styles.xml (edits) naturally invalidates the cache. */
|
|
1121
|
+
private tableCondCache;
|
|
1122
|
+
/** Retained styles.xml tree (built-in style injection + save). */
|
|
1123
|
+
private stylesPart;
|
|
1124
|
+
private stylesRoot;
|
|
1125
|
+
/** Retained numbering.xml tree (list creation + save round-trip). */
|
|
1126
|
+
private numberingPart;
|
|
1127
|
+
private numberingRoot;
|
|
1128
|
+
private numberingDirty;
|
|
1129
|
+
/** Retained footnotes.xml tree (footnote insertion + save round-trip). */
|
|
1130
|
+
private footnotesPart;
|
|
1131
|
+
private footnotesRoot;
|
|
1132
|
+
private footnotesDirty;
|
|
1133
|
+
private footnotesRels;
|
|
1134
|
+
/** Serialize retained optional parts only once actually mutated, keeping
|
|
1135
|
+
* untouched parts byte-identical through save(). */
|
|
1136
|
+
private stylesDirty;
|
|
1137
|
+
private commentsDirty;
|
|
1138
|
+
/** Retained XML roots — source of truth for editing and save(). */
|
|
1139
|
+
private readonly docPart;
|
|
1140
|
+
/** Parsed document.xml root (read-only outside the class; the layout engine
|
|
1141
|
+
* scans it for incremental-reuse eligibility, tests walk it). */
|
|
1142
|
+
readonly docRoot: XmlElement;
|
|
1143
|
+
private readonly hfParts;
|
|
1144
|
+
private readonly ctxBase;
|
|
1145
|
+
/** Tracked-changes display mode; refresh() re-derives after changes. */
|
|
1146
|
+
revisionView: "final" | "markup";
|
|
1147
|
+
private readonly relsPath;
|
|
1148
|
+
private relsRoot;
|
|
1149
|
+
private contentTypesRoot;
|
|
1150
|
+
private nextDocPrId;
|
|
1151
|
+
/** Transient layout state: set by the engine while laying out a docGrid
|
|
1152
|
+
* type="charsAndLines" section so line measurement can give East-Asian
|
|
1153
|
+
* glyphs their true (uninflated) grid line height. Off outside such a
|
|
1154
|
+
* section. Safe as document-scoped mutable state because layout is
|
|
1155
|
+
* single-threaded and sequential per section. */
|
|
1156
|
+
charGridEa: boolean;
|
|
1157
|
+
private constructor();
|
|
1158
|
+
/**
|
|
1159
|
+
* Re-derive the document model from the retained XML trees. Called after
|
|
1160
|
+
* edit commands mutate the XML.
|
|
1161
|
+
*/
|
|
1162
|
+
/** Switch tracked-changes display and re-derive the model. */
|
|
1163
|
+
setRevisionView(view: "final" | "markup"): void;
|
|
1164
|
+
/** Invalidated on refresh; see layoutGlobalSig. */
|
|
1165
|
+
private _layoutGlobalSig;
|
|
1166
|
+
/** Signature of everything OUTSIDE a paragraph's own XML that affects how it
|
|
1167
|
+
* breaks into lines: style + numbering definitions, doc-level layout scalars,
|
|
1168
|
+
* and the tracked-changes view mode. The line-break cache (layout/inline.ts)
|
|
1169
|
+
* combines this with a paragraph's own content signature so a style/numbering/
|
|
1170
|
+
* settings edit invalidates cached breaks even though the paragraph XML is
|
|
1171
|
+
* unchanged. Memoized until the next refresh() (styles/numbering trees are
|
|
1172
|
+
* stable across a plain text edit). */
|
|
1173
|
+
layoutGlobalSig(): string;
|
|
1174
|
+
refresh(): void;
|
|
1175
|
+
private deriveComments;
|
|
1176
|
+
/** Retained comments tree for edit commands (null when the doc has none). */
|
|
1177
|
+
/**
|
|
1178
|
+
* Retained comments tree. With create=true, a missing comments.xml part is
|
|
1179
|
+
* created and registered (content type + document relationship) so newly
|
|
1180
|
+
* added comments serialize and round-trip through Word.
|
|
1181
|
+
*/
|
|
1182
|
+
commentsTree(create?: boolean): XmlElement | null;
|
|
1183
|
+
/**
|
|
1184
|
+
* Make sure a paragraph style is usable: Word ships built-in definitions
|
|
1185
|
+
* for Heading 1-6/Title even when a file doesn't declare them, so applying
|
|
1186
|
+
* one to such a file must inject a standard definition (otherwise the
|
|
1187
|
+
* paragraph would reference an undefined style and render as Normal).
|
|
1188
|
+
*/
|
|
1189
|
+
ensureParagraphStyle(styleId: string): boolean;
|
|
1190
|
+
/**
|
|
1191
|
+
* Retained numbering tree. With create=true, a missing numbering.xml part
|
|
1192
|
+
* is created and registered (content type + document relationship) so list
|
|
1193
|
+
* definitions added by editing serialize and round-trip.
|
|
1194
|
+
*/
|
|
1195
|
+
numberingTree(create?: boolean): XmlElement | null;
|
|
1196
|
+
markNumberingChanged(): void;
|
|
1197
|
+
/**
|
|
1198
|
+
* Retained footnotes tree. With create=true, a missing footnotes.xml part
|
|
1199
|
+
* is created and registered (with Word's required separator footnotes) so
|
|
1200
|
+
* inserted footnotes serialize and round-trip.
|
|
1201
|
+
*/
|
|
1202
|
+
footnotesTree(create?: boolean): XmlElement | null;
|
|
1203
|
+
/**
|
|
1204
|
+
* Create an empty header/footer part (with a default-type reference in
|
|
1205
|
+
* every sectPr) when the document has none - Word does this implicitly the
|
|
1206
|
+
* first time you edit the header area. Returns the part's root.
|
|
1207
|
+
*/
|
|
1208
|
+
ensureHfPart(kind: "header" | "footer"): XmlElement;
|
|
1209
|
+
markFootnotesChanged(): void;
|
|
1210
|
+
/** Called by comment edit commands after mutating the comments tree. */
|
|
1211
|
+
markCommentsChanged(): void;
|
|
1212
|
+
/**
|
|
1213
|
+
* Retained commentsExtended tree (threading). With create=true, a missing
|
|
1214
|
+
* part is created and registered (content type + document relationship) so
|
|
1215
|
+
* Word picks up reply threading.
|
|
1216
|
+
*/
|
|
1217
|
+
commentsExtendedTree(create?: boolean): XmlElement | null;
|
|
1218
|
+
markCommentsExtendedChanged(): void;
|
|
1219
|
+
/**
|
|
1220
|
+
* The w:t elements covered by each comment's range, in document order.
|
|
1221
|
+
* Point comments (a bare commentReference with no range) anchor to the
|
|
1222
|
+
* nearest preceding w:t.
|
|
1223
|
+
*/
|
|
1224
|
+
commentAnchors(): Map<string, XmlElement[]>;
|
|
1225
|
+
/** The mutable XML roots (document body, header/footer parts, comments).
|
|
1226
|
+
* The comments root is last so history snapshot indices stay stable. */
|
|
1227
|
+
/** Flag the footnotes part dirty when `t` lives inside it, so save()
|
|
1228
|
+
* re-serializes footnotes.xml. Called by the editor after a text edit; a
|
|
1229
|
+
* no-op for body/header/footer targets. */
|
|
1230
|
+
markDirtyIfFootnote(t: XmlElement): void;
|
|
1231
|
+
editableRoots(): XmlElement[];
|
|
1232
|
+
/**
|
|
1233
|
+
* Find the parent element of `target` in any modeled XML tree (document
|
|
1234
|
+
* body, headers, footers). Linear scan — documents are small and this only
|
|
1235
|
+
* runs on structural edits (Enter, paragraph merge).
|
|
1236
|
+
*/
|
|
1237
|
+
/** XML roots that can carry tracked changes: body, headers/footers, footnotes. */
|
|
1238
|
+
revisionRoots(): XmlElement[];
|
|
1239
|
+
findParentOf(target: XmlElement): XmlElement | undefined;
|
|
1240
|
+
/**
|
|
1241
|
+
* Serialize the (possibly edited) document back to .docx bytes. Only the
|
|
1242
|
+
* XML parts we model are re-serialized; every other part round-trips
|
|
1243
|
+
* byte-for-byte.
|
|
1244
|
+
*/
|
|
1245
|
+
save(): Uint8Array;
|
|
1246
|
+
/** Fresh unique docPr id for inserted drawings. */
|
|
1247
|
+
nextDrawingId(): number;
|
|
1248
|
+
/** Next unused revision id (w:id on w:ins/w:del). Seeded once past the
|
|
1249
|
+
* highest id already present in any editable root so a document that
|
|
1250
|
+
* already has tracked changes never collides. */
|
|
1251
|
+
private revIdCounter;
|
|
1252
|
+
nextRevisionId(): number;
|
|
1253
|
+
/**
|
|
1254
|
+
* Add image bytes as a new media part + relationship (+ content-type
|
|
1255
|
+
* default). Returns the relationship id for use in a w:drawing.
|
|
1256
|
+
*/
|
|
1257
|
+
private ensureRelsRoot;
|
|
1258
|
+
/** Register an external hyperlink relationship and return its rId. */
|
|
1259
|
+
addHyperlinkRel(url: string): string;
|
|
1260
|
+
/** Retarget an existing external relationship (hyperlink href edit). */
|
|
1261
|
+
setRelTarget(relId: string, url: string): boolean;
|
|
1262
|
+
addImageResource(bytes: Uint8Array, ext: string): string;
|
|
1263
|
+
static load(data: ArrayBuffer | Uint8Array): DocxDocument;
|
|
1264
|
+
media(part: string): Uint8Array | undefined;
|
|
1265
|
+
/** Effective paragraph properties: docDefaults → table style → style chain → direct. */
|
|
1266
|
+
effectiveParaProps(para: Paragraph): ParaProps;
|
|
1267
|
+
/**
|
|
1268
|
+
* Run props contributed by the enclosing table style's conditional
|
|
1269
|
+
* w:tblStylePr blocks for this paragraph's cell (undefined when the
|
|
1270
|
+
* paragraph isn't in a styled table cell or nothing applies).
|
|
1271
|
+
*/
|
|
1272
|
+
private tableCondRPr;
|
|
1273
|
+
/** Effective run properties for a run inside a paragraph. */
|
|
1274
|
+
effectiveRunProps(para: Paragraph, runProps: RunProps): RunProps;
|
|
1275
|
+
numberingLevel(numId: number, ilvl: number): NumberingLevel | undefined;
|
|
1276
|
+
numberingInstance(numId: number): NumInstance | undefined;
|
|
1277
|
+
private findDocumentPart;
|
|
1278
|
+
private readXmlOptional;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/** Maps a rendered text item back to its source XML for editing. */
|
|
1282
|
+
interface TextSource {
|
|
1283
|
+
run: Run;
|
|
1284
|
+
/** Source w:t; null when the text is synthetic (fields, symbols). */
|
|
1285
|
+
t: XmlElement | null;
|
|
1286
|
+
/** Char offset of this item's first character within t's text. */
|
|
1287
|
+
offset: number;
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Layout output: pages of absolutely positioned primitives (px, page-relative).
|
|
1291
|
+
* The renderer maps these 1:1 to DOM/canvas/SVG — no further layout happens
|
|
1292
|
+
* downstream, which is what guarantees pagination fidelity.
|
|
1293
|
+
*/
|
|
1294
|
+
interface FontSpec {
|
|
1295
|
+
family: string;
|
|
1296
|
+
size: number;
|
|
1297
|
+
bold: boolean;
|
|
1298
|
+
italic: boolean;
|
|
1299
|
+
/** Optional PAINT-only family tried before `family` in the CSS stack, without
|
|
1300
|
+
* affecting metrics or width lookups (keyed by `family`). Used for CJK: the
|
|
1301
|
+
* line-pitch profile stays keyed by the macOS substitute face while the real
|
|
1302
|
+
* Windows glyphs (MS Mincho, Microsoft JhengHei, …) paint when available. */
|
|
1303
|
+
paintFamily?: string;
|
|
1304
|
+
/** PAINT-only vertical nudge (CSS px, positive = down) applied to the glyphs
|
|
1305
|
+
* without touching layout metrics or advances. Used when a substitute face
|
|
1306
|
+
* (Latha for Word's Tamil Vijaya) sits on a different baseline than the face
|
|
1307
|
+
* Word rasterized; the shift lands the glyphs on Word's baseline. */
|
|
1308
|
+
paintDY?: number;
|
|
1309
|
+
}
|
|
1310
|
+
interface PathItem {
|
|
1311
|
+
kind: "path";
|
|
1312
|
+
x: number;
|
|
1313
|
+
y: number;
|
|
1314
|
+
width: number;
|
|
1315
|
+
height: number;
|
|
1316
|
+
/** SVG path data in a `viewW x viewH` coordinate space. */
|
|
1317
|
+
d: string;
|
|
1318
|
+
viewW: number;
|
|
1319
|
+
viewH: number;
|
|
1320
|
+
fill?: string;
|
|
1321
|
+
stroke?: {
|
|
1322
|
+
color: string;
|
|
1323
|
+
width: number;
|
|
1324
|
+
};
|
|
1325
|
+
/** Paint under / over the body text (anchored-shape layering). */
|
|
1326
|
+
behind?: boolean;
|
|
1327
|
+
front?: boolean;
|
|
1328
|
+
}
|
|
1329
|
+
interface TextItem {
|
|
1330
|
+
kind: "text";
|
|
1331
|
+
x: number;
|
|
1332
|
+
/** Baseline y. */
|
|
1333
|
+
baseline: number;
|
|
1334
|
+
width: number;
|
|
1335
|
+
text: string;
|
|
1336
|
+
props: RunProps;
|
|
1337
|
+
font: FontSpec;
|
|
1338
|
+
/** Footnote/endnote id referenced by this run (registration happens when
|
|
1339
|
+
* the item lands on a real page - split table rows carry it across). */
|
|
1340
|
+
noteId?: number;
|
|
1341
|
+
/** Vertical stretch for tall delimiter glyphs (Word's glyph variants). */
|
|
1342
|
+
mathScaleY?: number;
|
|
1343
|
+
/** Horizontal stretch for wide brace glyphs (Word's over/under brace
|
|
1344
|
+
* variants), applied about the glyph box's horizontal center. */
|
|
1345
|
+
mathScaleX?: number;
|
|
1346
|
+
/** Stretch anchor above the baseline, px. */
|
|
1347
|
+
mathScaleAnchor?: number;
|
|
1348
|
+
/** Line box for selection/highlight backgrounds. */
|
|
1349
|
+
lineTop: number;
|
|
1350
|
+
lineHeight: number;
|
|
1351
|
+
/** Exact glyph box for baseline-shifted runs (superscript/subscript):
|
|
1352
|
+
* the renderer anchors these instead of bottoming on the line box. */
|
|
1353
|
+
glyphTop?: number;
|
|
1354
|
+
glyphBoxH?: number;
|
|
1355
|
+
/** Small-caps reduced segment: the base run font that must supply the
|
|
1356
|
+
* strut so the painted baseline matches neighboring full-size spans (the
|
|
1357
|
+
* renderer sizes the outer span with this font and shrinks the text via
|
|
1358
|
+
* a baseline-aligned inner span). */
|
|
1359
|
+
strutFont?: FontSpec;
|
|
1360
|
+
/** PAGEREF bookmark name: the final pass rewrites this item's text with
|
|
1361
|
+
* the bookmark's page number (Word recomputes PAGEREF on open; the docx
|
|
1362
|
+
* cached result is stale in real TOCs). */
|
|
1363
|
+
pageRef?: string;
|
|
1364
|
+
/** Source m:oMath element when this text is a piece of an equation. */
|
|
1365
|
+
mathSrc?: XmlElement;
|
|
1366
|
+
href?: string;
|
|
1367
|
+
/** Present for editable text (absent on numbering labels etc.). */
|
|
1368
|
+
src?: TextSource;
|
|
1369
|
+
/** Rotate about a point (px, relative to this item's top-left). */
|
|
1370
|
+
rotate?: {
|
|
1371
|
+
deg: number;
|
|
1372
|
+
ox: number;
|
|
1373
|
+
oy: number;
|
|
1374
|
+
};
|
|
1375
|
+
/** Paint under the body text (behindDoc textbox content). */
|
|
1376
|
+
behind?: boolean;
|
|
1377
|
+
/** Paint over the body text (non-behindDoc anchored shape content: Word
|
|
1378
|
+
* layers in-front shapes above the text layer). */
|
|
1379
|
+
front?: boolean;
|
|
1380
|
+
/** Right-to-left run: renderer sets direction:rtl so the browser shapes and
|
|
1381
|
+
* orders the (Arabic/Hebrew) glyphs within the span box. */
|
|
1382
|
+
rtl?: boolean;
|
|
1383
|
+
/** Ordinal of the source paragraph within its cell/frame. Set only for
|
|
1384
|
+
* widow-controlled paragraphs; row splitting uses it to scope Word's
|
|
1385
|
+
* widow/orphan rules to the paragraph straddling the cut. */
|
|
1386
|
+
paraSeq?: number;
|
|
1387
|
+
/** Editor-only: maximum caret x for this item — a trailing hanging space
|
|
1388
|
+
* confined to its table cell pins the caret at the cell's content edge
|
|
1389
|
+
* (Word behavior) while the span keeps its true hanging layout x. */
|
|
1390
|
+
caretClampX?: number;
|
|
1391
|
+
}
|
|
1392
|
+
interface RectItem {
|
|
1393
|
+
kind: "rect";
|
|
1394
|
+
x: number;
|
|
1395
|
+
y: number;
|
|
1396
|
+
width: number;
|
|
1397
|
+
height: number;
|
|
1398
|
+
fill: string;
|
|
1399
|
+
/** Semantic paint provenance used by render-layer comparison. */
|
|
1400
|
+
role?: "table-fill";
|
|
1401
|
+
/** Rotate about a point (px, relative to this item's top-left). */
|
|
1402
|
+
rotate?: {
|
|
1403
|
+
deg: number;
|
|
1404
|
+
ox: number;
|
|
1405
|
+
oy: number;
|
|
1406
|
+
};
|
|
1407
|
+
behind?: boolean;
|
|
1408
|
+
/** Paint over the body text (non-behindDoc anchored shape fill). */
|
|
1409
|
+
front?: boolean;
|
|
1410
|
+
}
|
|
1411
|
+
interface LineEdgeItem {
|
|
1412
|
+
kind: "edge";
|
|
1413
|
+
x1: number;
|
|
1414
|
+
y1: number;
|
|
1415
|
+
x2: number;
|
|
1416
|
+
y2: number;
|
|
1417
|
+
border: Border;
|
|
1418
|
+
/** Semantic paint provenance used by render-layer comparison. */
|
|
1419
|
+
role?: "table-rule";
|
|
1420
|
+
/** Rotate about a point (px, relative to this item's top-left). */
|
|
1421
|
+
rotate?: {
|
|
1422
|
+
deg: number;
|
|
1423
|
+
ox: number;
|
|
1424
|
+
oy: number;
|
|
1425
|
+
};
|
|
1426
|
+
/** Paint over the body text (non-behindDoc anchored shape border). */
|
|
1427
|
+
front?: boolean;
|
|
1428
|
+
}
|
|
1429
|
+
interface ImageItem {
|
|
1430
|
+
kind: "image";
|
|
1431
|
+
x: number;
|
|
1432
|
+
y: number;
|
|
1433
|
+
width: number;
|
|
1434
|
+
height: number;
|
|
1435
|
+
/** Package part path; renderer resolves bytes via DocxDocument.media(). */
|
|
1436
|
+
part: string;
|
|
1437
|
+
/** a:srcRect crop (fractions) and a:xfrm rotation (degrees). */
|
|
1438
|
+
crop?: {
|
|
1439
|
+
l: number;
|
|
1440
|
+
t: number;
|
|
1441
|
+
r: number;
|
|
1442
|
+
b: number;
|
|
1443
|
+
};
|
|
1444
|
+
rotation?: number;
|
|
1445
|
+
/** Picture-watermark "washout" (VML v:imagedata gain/blacklevel, 0..1
|
|
1446
|
+
* fractions). Per-channel linear recolor, measured against Word's PDF of
|
|
1447
|
+
* probe2-picture-watermark (gain 0.3, blacklevel 0.35: source 32 -> 215,
|
|
1448
|
+
* 74 -> 227, 135 -> 246, 210 -> clamped 255):
|
|
1449
|
+
* out = in * gain + 255 * (blacklevel * (1 + gain) + (1 - gain) / 2) */
|
|
1450
|
+
washout?: {
|
|
1451
|
+
gain: number;
|
|
1452
|
+
blacklevel: number;
|
|
1453
|
+
};
|
|
1454
|
+
/** a:ln picture outline, drawn just outside the image (Word hairline). */
|
|
1455
|
+
border?: {
|
|
1456
|
+
color: string;
|
|
1457
|
+
width: number;
|
|
1458
|
+
};
|
|
1459
|
+
/** behindDoc: paint under the text layer. */
|
|
1460
|
+
behind?: boolean;
|
|
1461
|
+
/** wrapNone + !behindDoc ("in front of text"): paint ABOVE the text layer
|
|
1462
|
+
* (Word's z-order; without this, later-emitted text spans cover the image
|
|
1463
|
+
* and it neither shows in front nor receives clicks/drags). */
|
|
1464
|
+
front?: boolean;
|
|
1465
|
+
/** Source w:drawing element (for interactive resize/move). */
|
|
1466
|
+
src?: XmlElement;
|
|
1467
|
+
}
|
|
1468
|
+
/** Interactive resize zone over a table boundary (column or row). */
|
|
1469
|
+
interface DrawingHitItem {
|
|
1470
|
+
kind: "drawingHit";
|
|
1471
|
+
x: number;
|
|
1472
|
+
y: number;
|
|
1473
|
+
width: number;
|
|
1474
|
+
height: number;
|
|
1475
|
+
/** Source w:drawing element (select/move the whole drawing). */
|
|
1476
|
+
src: XmlElement;
|
|
1477
|
+
/** Anchored drawings drag by offset; inline ones re-anchor into text. */
|
|
1478
|
+
anchored: boolean;
|
|
1479
|
+
/** A shape fill hit that sits UNDER the shape's own text spans (same z): a
|
|
1480
|
+
* click on bare fill selects the shape, but clicks on the text glyphs still
|
|
1481
|
+
* reach the text for editing. Such hits select only (never drag-move). */
|
|
1482
|
+
belowText?: boolean;
|
|
1483
|
+
}
|
|
1484
|
+
interface GripItem {
|
|
1485
|
+
kind: "grip";
|
|
1486
|
+
/** "col": vertical zone at x spanning y1..y2. "row": horizontal zone at y1
|
|
1487
|
+
* spanning x..x2. */
|
|
1488
|
+
axis: "col" | "row";
|
|
1489
|
+
x: number;
|
|
1490
|
+
y1: number;
|
|
1491
|
+
y2: number;
|
|
1492
|
+
/** Right edge for row grips. */
|
|
1493
|
+
x2?: number;
|
|
1494
|
+
/** Source w:tbl element. */
|
|
1495
|
+
tbl: XmlElement;
|
|
1496
|
+
/** col: boundary 1..n (n = right edge). row: row index above the boundary. */
|
|
1497
|
+
boundary: number;
|
|
1498
|
+
/** Laid-out height of the row above (row grips), px. */
|
|
1499
|
+
rowHeightPx?: number;
|
|
1500
|
+
/** Rendered column widths px (col grips) — resize works in this space. */
|
|
1501
|
+
renderedWidths?: number[];
|
|
1502
|
+
}
|
|
1503
|
+
/** WordArt/watermark text scaled to fill a box, rotated about its center. */
|
|
1504
|
+
interface WordArtItem {
|
|
1505
|
+
kind: "wordart";
|
|
1506
|
+
/** Box top-left, px. */
|
|
1507
|
+
x: number;
|
|
1508
|
+
y: number;
|
|
1509
|
+
width: number;
|
|
1510
|
+
height: number;
|
|
1511
|
+
text: string;
|
|
1512
|
+
fontFamily: string;
|
|
1513
|
+
bold?: boolean;
|
|
1514
|
+
italic?: boolean;
|
|
1515
|
+
fill: string;
|
|
1516
|
+
opacity: number;
|
|
1517
|
+
/** Clockwise degrees. */
|
|
1518
|
+
rotation: number;
|
|
1519
|
+
behind?: boolean;
|
|
1520
|
+
/** v:textpath font-size (px), used only when noFit is set. */
|
|
1521
|
+
fontSize?: number;
|
|
1522
|
+
/** Malformed shapetype guide path: render at nominal fontSize, unstretched
|
|
1523
|
+
* (Word can't fitshape, so it draws a near-invisible mark). */
|
|
1524
|
+
noFit?: boolean;
|
|
1525
|
+
/** Source VML shape element (v:shape / v:rect), for interactive select/edit. */
|
|
1526
|
+
src?: XmlElement;
|
|
1527
|
+
}
|
|
1528
|
+
/** DrawingML a:prstTxWarp text: the shape's single text line bent onto a
|
|
1529
|
+
* preset envelope (arch/wave/chevron/circle-pour), filling the shape box. */
|
|
1530
|
+
interface WarpTextItem {
|
|
1531
|
+
kind: "warptext";
|
|
1532
|
+
/** Shape box top-left, px. */
|
|
1533
|
+
x: number;
|
|
1534
|
+
y: number;
|
|
1535
|
+
width: number;
|
|
1536
|
+
height: number;
|
|
1537
|
+
text: string;
|
|
1538
|
+
fontFamily: string;
|
|
1539
|
+
/** Run font size px (the text's natural size; presets that don't fill the
|
|
1540
|
+
* box — textArchUp — ride the text at this size). */
|
|
1541
|
+
fontSize: number;
|
|
1542
|
+
bold?: boolean;
|
|
1543
|
+
italic?: boolean;
|
|
1544
|
+
/** CSS text color. */
|
|
1545
|
+
fill: string;
|
|
1546
|
+
/** Preset name (textArchUp, textWave1, textChevron, textCirclePour, …). */
|
|
1547
|
+
warp: string;
|
|
1548
|
+
behind?: boolean;
|
|
1549
|
+
front?: boolean;
|
|
1550
|
+
}
|
|
1551
|
+
type PageItem = TextItem | PathItem | RectItem | LineEdgeItem | ImageItem | DrawingHitItem | GripItem | WordArtItem | WarpTextItem;
|
|
1552
|
+
interface LaidOutPage {
|
|
1553
|
+
width: number;
|
|
1554
|
+
height: number;
|
|
1555
|
+
/** 1-based physical index. */
|
|
1556
|
+
index: number;
|
|
1557
|
+
/** Display page number after pgNumType.start is applied. */
|
|
1558
|
+
number: number;
|
|
1559
|
+
items: PageItem[];
|
|
1560
|
+
/** Body box (for header/footer editing chrome). */
|
|
1561
|
+
bodyTop: number;
|
|
1562
|
+
bodyBottom: number;
|
|
1563
|
+
/** Items from this index on belong to the header/footer parts. */
|
|
1564
|
+
hfStart: number;
|
|
1565
|
+
}
|
|
1566
|
+
interface LayoutResult {
|
|
1567
|
+
pages: LaidOutPage[];
|
|
1568
|
+
totalPages: number;
|
|
1569
|
+
/** Opaque incremental-reuse state (engine-internal); pass a previous result
|
|
1570
|
+
* back as LayoutOptions.prev to enable incremental relayout. Not part of the
|
|
1571
|
+
* rendered output and ignored by the equivalence harness. */
|
|
1572
|
+
_incr?: unknown;
|
|
1573
|
+
/** Opaque page state used to refresh headers/footers without repaginating
|
|
1574
|
+
* the body when their measured geometry is unchanged. */
|
|
1575
|
+
_hf?: unknown;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
interface FontMetrics {
|
|
1579
|
+
/** px above baseline (raw font ascent - anchors CSS glyph boxes). */
|
|
1580
|
+
ascent: number;
|
|
1581
|
+
/** px below baseline, raw (positive - anchors CSS glyph boxes). */
|
|
1582
|
+
descent: number;
|
|
1583
|
+
/** Natural single-spaced line height px (what Word calls single spacing). */
|
|
1584
|
+
lineHeight: number;
|
|
1585
|
+
/** Word's below-baseline share of lineHeight (quantized); use for
|
|
1586
|
+
* baseline placement. Falls back to `descent` when absent. */
|
|
1587
|
+
lineDescent?: number;
|
|
1588
|
+
}
|
|
1589
|
+
interface TextMeasurer {
|
|
1590
|
+
width(text: string, font: FontSpec, letterSpacing?: number): number;
|
|
1591
|
+
metrics(font: FontSpec): FontMetrics;
|
|
1592
|
+
/** The browser's own font box (fontBoundingBoxAscent/Descent) for the
|
|
1593
|
+
* resolved first face of this font's CSS stack, when the host can know it.
|
|
1594
|
+
* Used to anchor paint-routed CJK spans: the DOM renderer centers glyphs
|
|
1595
|
+
* by the browser strut, which differs from the engine's calibrated line
|
|
1596
|
+
* profile (Hiragino/PingFang) whenever the real Windows face paints. */
|
|
1597
|
+
paintBox?(font: FontSpec): {
|
|
1598
|
+
ascent: number;
|
|
1599
|
+
descent: number;
|
|
1600
|
+
} | undefined;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
interface LayoutOptions {
|
|
1604
|
+
measurer?: TextMeasurer;
|
|
1605
|
+
/** Previous layout result (from an earlier layoutDocument call on the same
|
|
1606
|
+
* document). Enables incremental relayout: pages whose input blocks and
|
|
1607
|
+
* lead-in state are unchanged are reused instead of re-laid. The engine falls
|
|
1608
|
+
* back to a full layout whenever it cannot prove reuse is byte-identical. */
|
|
1609
|
+
prev?: LayoutResult;
|
|
1610
|
+
/** The top-level block XML element (w:p / w:tbl) the editor mutated IN PLACE
|
|
1611
|
+
* since `prev` — the paragraph the caret sits in for a single-character
|
|
1612
|
+
* type/delete. Lets the incremental scan skip re-hashing every block: it
|
|
1613
|
+
* re-hashes only the hinted block and its two neighbours and reuses prev's
|
|
1614
|
+
* per-block signatures for the rest. Purely an optimisation — the fast path
|
|
1615
|
+
* is gated on block-count parity and neighbour-signature checks, so a stale,
|
|
1616
|
+
* structural, or wrong hint falls through to the full block scan. Absent for
|
|
1617
|
+
* multi-block edits (paste, paragraph split/merge, undo/redo, structural ops),
|
|
1618
|
+
* which take the full scan. */
|
|
1619
|
+
dirtyHint?: XmlElement;
|
|
1620
|
+
}
|
|
1621
|
+
declare function layoutDocument(doc: DocxDocument, options?: LayoutOptions): LayoutResult;
|
|
1622
|
+
|
|
1623
|
+
interface RenderOptions {
|
|
1624
|
+
/** Zoom factor (1 = 100%). */
|
|
1625
|
+
zoom?: number;
|
|
1626
|
+
/** Gap between pages, px. */
|
|
1627
|
+
pageGap?: number;
|
|
1628
|
+
/** Page drop shadow / chrome. */
|
|
1629
|
+
pageShadow?: boolean;
|
|
1630
|
+
/** Materialize interactive affordances (table resize grips). */
|
|
1631
|
+
interactive?: boolean;
|
|
1632
|
+
/** Keep only nearby page contents mounted. Page shells always remain so
|
|
1633
|
+
* scroll geometry is unchanged. Intended for long interactive documents. */
|
|
1634
|
+
virtualize?: boolean;
|
|
1635
|
+
/** Called after the mounted page window changes so editor chrome can be
|
|
1636
|
+
* restored on newly-mounted pages. */
|
|
1637
|
+
onViewportChange?: () => void;
|
|
1638
|
+
/** Show review comments (highlight + margin balloons). Default true. */
|
|
1639
|
+
comments?: boolean;
|
|
1640
|
+
/** Called when the user deletes a comment from its balloon. The balloon
|
|
1641
|
+
* shows a delete button only when this is provided. */
|
|
1642
|
+
onDeleteComment?: (id: string) => void;
|
|
1643
|
+
/** Called when the user submits a reply from a balloon's reply box. The
|
|
1644
|
+
* reply box only renders when this is provided. */
|
|
1645
|
+
onReplyComment?: (id: string, text: string) => void;
|
|
1646
|
+
}
|
|
1647
|
+
interface TextBinding {
|
|
1648
|
+
el: HTMLElement;
|
|
1649
|
+
item: TextItem;
|
|
1650
|
+
}
|
|
1651
|
+
interface GripBinding {
|
|
1652
|
+
el: HTMLElement;
|
|
1653
|
+
item: GripItem;
|
|
1654
|
+
}
|
|
1655
|
+
interface ImageBinding {
|
|
1656
|
+
el: HTMLElement;
|
|
1657
|
+
item: ImageItem;
|
|
1658
|
+
}
|
|
1659
|
+
interface DrawingBinding {
|
|
1660
|
+
el: HTMLElement;
|
|
1661
|
+
item: DrawingHitItem;
|
|
1662
|
+
}
|
|
1663
|
+
interface WordArtBinding {
|
|
1664
|
+
el: HTMLElement;
|
|
1665
|
+
item: WordArtItem;
|
|
1666
|
+
}
|
|
1667
|
+
interface RenderHandle {
|
|
1668
|
+
/** Root element containing all pages. */
|
|
1669
|
+
root: HTMLElement;
|
|
1670
|
+
/** Rendered text elements in paint order, for selection mapping. */
|
|
1671
|
+
bindings: TextBinding[];
|
|
1672
|
+
/** Mounted text bindings indexed by their retained source w:t element. */
|
|
1673
|
+
bindingsByText: Map<XmlElement, TextBinding[]>;
|
|
1674
|
+
/** Table resize grips (only when options.interactive). */
|
|
1675
|
+
grips: GripBinding[];
|
|
1676
|
+
/** Rendered images, for interactive select/resize/move. */
|
|
1677
|
+
images: ImageBinding[];
|
|
1678
|
+
/** Transparent hit targets over vector drawings/icons (select/move). */
|
|
1679
|
+
drawings: DrawingBinding[];
|
|
1680
|
+
/** WordArt / text watermarks, for interactive select/edit. */
|
|
1681
|
+
wordarts: WordArtBinding[];
|
|
1682
|
+
/** Revoke object URLs etc. */
|
|
1683
|
+
destroy: () => void;
|
|
1684
|
+
/** Temporarily mount every page, returning a function that restores the
|
|
1685
|
+
* viewport window. Used by the synchronous print-clone path. */
|
|
1686
|
+
materializeAll?: () => () => void;
|
|
1687
|
+
/** Recompute the mounted page window after an external scroll/resize. */
|
|
1688
|
+
updateViewport?: () => void;
|
|
1689
|
+
/** Per-page render records, retained so the next render can reuse the DOM of
|
|
1690
|
+
* pages whose layout is unchanged (see renderToDom's `prev` parameter). */
|
|
1691
|
+
_pages?: PageRender[];
|
|
1692
|
+
/** Whether this render drew the comments overlay. Comment highlights live
|
|
1693
|
+
* INSIDE page surfaces, so the next render must sweep them out of any page
|
|
1694
|
+
* DOM it adopts before re-running the overlay. */
|
|
1695
|
+
_hadComments?: boolean;
|
|
1696
|
+
/** Zoom this render painted at — adoption is only valid at the same zoom. */
|
|
1697
|
+
_zoom?: number;
|
|
1698
|
+
/** Whether this handle keeps only a viewport-sized page window mounted. */
|
|
1699
|
+
_virtualized?: boolean;
|
|
1700
|
+
/** Parsed-model generation whose source bindings this handle owns. */
|
|
1701
|
+
_modelVersion?: number;
|
|
1702
|
+
/** Remove viewport listeners before this handle is replaced. */
|
|
1703
|
+
_stopVirtualizer?: () => void;
|
|
1704
|
+
}
|
|
1705
|
+
/** One page's DOM element plus the editor bindings it owns and the object URLs
|
|
1706
|
+
* it created. Retained on the handle so an incremental re-render can adopt an
|
|
1707
|
+
* unchanged page wholesale instead of tearing it down and rebuilding it. */
|
|
1708
|
+
interface PageRender {
|
|
1709
|
+
el: HTMLElement;
|
|
1710
|
+
page: LaidOutPage;
|
|
1711
|
+
bindings: TextBinding[];
|
|
1712
|
+
grips: GripBinding[];
|
|
1713
|
+
images: ImageBinding[];
|
|
1714
|
+
drawings: DrawingBinding[];
|
|
1715
|
+
wordarts: WordArtBinding[];
|
|
1716
|
+
urls: string[];
|
|
1717
|
+
mounted: boolean;
|
|
1718
|
+
}
|
|
1719
|
+
declare function renderToDom(doc: DocxDocument, layout: LayoutResult, container: HTMLElement, options?: RenderOptions, prev?: RenderHandle): RenderHandle;
|
|
1720
|
+
/**
|
|
1721
|
+
* Print the rendered pages (browser print -> paper or PDF): clones the page
|
|
1722
|
+
* DOM into a hidden same-origin iframe sized to the document's page, strips
|
|
1723
|
+
* screen chrome (shadows, gaps), and invokes the print dialog.
|
|
1724
|
+
*/
|
|
1725
|
+
declare function printPages(root: HTMLElement, pageWidthPx: number, pageHeightPx: number): void;
|
|
1726
|
+
|
|
1727
|
+
interface RunFormatPatch {
|
|
1728
|
+
bold?: boolean;
|
|
1729
|
+
italic?: boolean;
|
|
1730
|
+
underline?: boolean;
|
|
1731
|
+
strike?: boolean;
|
|
1732
|
+
/** "#RRGGBB"; null removes the direct color. */
|
|
1733
|
+
color?: string | null;
|
|
1734
|
+
/** Word highlight name ("yellow", "cyan", …); null removes. */
|
|
1735
|
+
highlight?: string | null;
|
|
1736
|
+
/** Font size in points. */
|
|
1737
|
+
fontSizePt?: number;
|
|
1738
|
+
fontFamily?: string;
|
|
1739
|
+
/** Superscript/subscript; null returns the run to the baseline. */
|
|
1740
|
+
verticalAlign?: "superscript" | "subscript" | null;
|
|
1741
|
+
/** Remove all direct character formatting (and character style). */
|
|
1742
|
+
clear?: boolean;
|
|
1743
|
+
}
|
|
1744
|
+
interface SelectionFormat {
|
|
1745
|
+
bold: boolean;
|
|
1746
|
+
italic: boolean;
|
|
1747
|
+
underline: boolean;
|
|
1748
|
+
strike: boolean;
|
|
1749
|
+
/** Common font size in points, if uniform. */
|
|
1750
|
+
fontSizePt?: number;
|
|
1751
|
+
color?: string;
|
|
1752
|
+
highlight?: string;
|
|
1753
|
+
fontFamily?: string;
|
|
1754
|
+
verticalAlign?: "superscript" | "subscript";
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
type ParagraphAlignment = "left" | "center" | "right" | "justify";
|
|
1758
|
+
interface PageLayoutPatch {
|
|
1759
|
+
/** Margins in inches. */
|
|
1760
|
+
margins?: {
|
|
1761
|
+
top?: number;
|
|
1762
|
+
right?: number;
|
|
1763
|
+
bottom?: number;
|
|
1764
|
+
left?: number;
|
|
1765
|
+
};
|
|
1766
|
+
/** Page size in inches (before orientation). */
|
|
1767
|
+
size?: {
|
|
1768
|
+
width: number;
|
|
1769
|
+
height: number;
|
|
1770
|
+
};
|
|
1771
|
+
orientation?: "portrait" | "landscape";
|
|
1772
|
+
/** Equal-width text columns (1 removes w:cols). */
|
|
1773
|
+
columns?: number;
|
|
1774
|
+
/** Box page border (null removes). sz in eighth-points, color hex. */
|
|
1775
|
+
pageBorders?: {
|
|
1776
|
+
sz?: number;
|
|
1777
|
+
color?: string;
|
|
1778
|
+
offsetFrom?: "text" | "page";
|
|
1779
|
+
} | null;
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* Table manipulation: add/remove rows and columns relative to the cell
|
|
1784
|
+
* containing the caret. Mutates source XML; callers checkpoint + relayout.
|
|
1785
|
+
*
|
|
1786
|
+
* v1 scope: column operations refuse tables using gridSpan (merged cells)
|
|
1787
|
+
* rather than corrupt them.
|
|
1788
|
+
*/
|
|
1789
|
+
type TableOp = "rowAbove" | "rowBelow" | "deleteRow" | "colLeft" | "colRight" | "deleteCol" | "deleteTable" | "mergeRight" | "mergeDown" | "splitCell" | {
|
|
1790
|
+
kind: "cellShading";
|
|
1791
|
+
fill: string | null;
|
|
1792
|
+
} | {
|
|
1793
|
+
kind: "cellVAlign";
|
|
1794
|
+
v: "top" | "center" | "bottom";
|
|
1795
|
+
};
|
|
1796
|
+
|
|
1797
|
+
interface LineNumberingPatch {
|
|
1798
|
+
/** Turn margin line numbering on/off for the target section(s). */
|
|
1799
|
+
enabled: boolean;
|
|
1800
|
+
/** Number every Nth line (1/5/10). Default 1 when first enabled. */
|
|
1801
|
+
countBy?: number;
|
|
1802
|
+
/** When the count resets. Default newPage when first enabled. */
|
|
1803
|
+
restart?: "continuous" | "newPage" | "newSection";
|
|
1804
|
+
/** First line number. Default 1. */
|
|
1805
|
+
start?: number;
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
interface MissingFont {
|
|
1809
|
+
/** The face the document asked for (first name in the item's stack). */
|
|
1810
|
+
family: string;
|
|
1811
|
+
/** A short sample of text that will render in a substitute. */
|
|
1812
|
+
sample: string;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
/** Toolbar control groups a host can disable via the `features` prop. */
|
|
1816
|
+
type ToolbarFeature = "history" | "styles" | "font" | "size" | "format" | "color" | "highlight" | "alignment" | "indent" | "spacing" | "link" | "lists" | "table" | "image" | "comment" | "footnote" | "layout" | "download";
|
|
1817
|
+
declare function DocxToolbar({ api, onSave, features, className, style, }: {
|
|
1818
|
+
api: DocxViewApi | null;
|
|
1819
|
+
onSave?: (bytes: Uint8Array) => void;
|
|
1820
|
+
/** Per-group overrides; every group defaults to enabled. */
|
|
1821
|
+
features?: Partial<Record<ToolbarFeature, boolean>>;
|
|
1822
|
+
/** Extra class on the toolbar root (e.g. a scope for CSS-variable overrides). */
|
|
1823
|
+
className?: string;
|
|
1824
|
+
/** Inline overrides merged onto the toolbar root; wins over the defaults. */
|
|
1825
|
+
style?: React.CSSProperties;
|
|
1826
|
+
}): react.JSX.Element;
|
|
1827
|
+
|
|
1828
|
+
interface DocxViewApi {
|
|
1829
|
+
/** Apply character formatting to the current browser selection. */
|
|
1830
|
+
applyFormat(patch: RunFormatPatch): void;
|
|
1831
|
+
/** Create a review comment on the current selection. False if no selection. */
|
|
1832
|
+
addComment(text: string): boolean;
|
|
1833
|
+
/** Insert a footnote at the caret. False without a caret. */
|
|
1834
|
+
addFootnote(text: string): boolean;
|
|
1835
|
+
/** Insert a dynamic page-number field at the caret (body, header or footer). */
|
|
1836
|
+
insertPageNumber(kind?: "page" | "pageOfTotal"): boolean;
|
|
1837
|
+
undo(): void;
|
|
1838
|
+
redo(): void;
|
|
1839
|
+
canUndo(): boolean;
|
|
1840
|
+
canRedo(): boolean;
|
|
1841
|
+
/** Insert a rows×cols table at the caret's paragraph. */
|
|
1842
|
+
insertTable(rows: number, cols: number): void;
|
|
1843
|
+
/** Row/column/table operations on the table containing the caret. */
|
|
1844
|
+
tableOp(op: TableOp): void;
|
|
1845
|
+
/** Insert an image file at the caret (inline, natural size clamped to column). */
|
|
1846
|
+
insertImage(file: Blob): Promise<void>;
|
|
1847
|
+
/** Align the paragraph(s) under the caret or selection. */
|
|
1848
|
+
setAlignment(align: ParagraphAlignment): void;
|
|
1849
|
+
/** Apply a named paragraph style (null clears back to Normal). */
|
|
1850
|
+
setParagraphStyle(styleId: string | null): void;
|
|
1851
|
+
/** Toggle bulleted/numbered list on the paragraph(s) under the selection. */
|
|
1852
|
+
toggleList(kind: "bullet" | "number"): void;
|
|
1853
|
+
/** Current list kind at the caret ("bullet" | "number" | null). */
|
|
1854
|
+
getListType(): "bullet" | "number" | null;
|
|
1855
|
+
/** Link the selection to a URL; null removes the link at the caret. */
|
|
1856
|
+
setLink(url: string | null): void;
|
|
1857
|
+
/** URL of the hyperlink at the caret/selection, or null. */
|
|
1858
|
+
getLinkAt(): string | null;
|
|
1859
|
+
/** Step paragraph indent by half an inch (Word's indent buttons). */
|
|
1860
|
+
adjustIndent(direction: 1 | -1): void;
|
|
1861
|
+
/** Line spacing multiple and/or space before/after (points). */
|
|
1862
|
+
setParagraphSpacing(patch: {
|
|
1863
|
+
lineMultiple?: number;
|
|
1864
|
+
beforePt?: number | null;
|
|
1865
|
+
afterPt?: number | null;
|
|
1866
|
+
}): void;
|
|
1867
|
+
/** Remove direct character formatting from the selection. */
|
|
1868
|
+
clearFormatting(): void;
|
|
1869
|
+
/** Change the selection's case. */
|
|
1870
|
+
changeCase(mode: "upper" | "lower" | "title"): void;
|
|
1871
|
+
/** Find matches for a query; selects the first and returns the count. */
|
|
1872
|
+
find(query: string, opts?: {
|
|
1873
|
+
matchCase?: boolean;
|
|
1874
|
+
}): number;
|
|
1875
|
+
/** Select the next/previous match; returns 1-based index or 0. */
|
|
1876
|
+
findStep(delta: 1 | -1): number;
|
|
1877
|
+
/** Replace the current match; returns remaining match count. */
|
|
1878
|
+
replaceCurrent(replacement: string): number;
|
|
1879
|
+
/** Replace every match; returns how many were replaced. */
|
|
1880
|
+
replaceAll(query: string, replacement: string): number;
|
|
1881
|
+
/** Paragraph styles for the style menu (declared + Word built-ins). */
|
|
1882
|
+
listParagraphStyles(): {
|
|
1883
|
+
id: string;
|
|
1884
|
+
name: string;
|
|
1885
|
+
}[];
|
|
1886
|
+
/** pStyle id of the caret paragraph (null = Normal). */
|
|
1887
|
+
getParagraphStyleId(): string | null;
|
|
1888
|
+
/** Change margins / page size / orientation (inches). */
|
|
1889
|
+
setPageLayout(patch: PageLayoutPatch, scope?: "document" | "section"): void;
|
|
1890
|
+
/** Insert a page/column break or a section break at the caret. */
|
|
1891
|
+
insertBreak(kind: "page" | "column" | "sectionNextPage" | "sectionContinuous"): boolean;
|
|
1892
|
+
/** Toggle/configure margin line numbers (Word's Layout > Line Numbers).
|
|
1893
|
+
* scope "section" targets the caret's section; "document" every section. */
|
|
1894
|
+
setLineNumbering(patch: LineNumberingPatch, scope?: "document" | "section"): void;
|
|
1895
|
+
/** Current line-numbering settings for the caret's section, or null (off). */
|
|
1896
|
+
getLineNumbering(): {
|
|
1897
|
+
countBy: number;
|
|
1898
|
+
restart: "continuous" | "newPage" | "newSection";
|
|
1899
|
+
start: number;
|
|
1900
|
+
} | null;
|
|
1901
|
+
/** Leave header/footer editing mode. */
|
|
1902
|
+
closeHeaderFooter(): void;
|
|
1903
|
+
/** Effective formatting of the current selection (toolbar state), or null. */
|
|
1904
|
+
getSelectionFormat(): SelectionFormat | null;
|
|
1905
|
+
/** Print the rendered pages (browser print dialog / save as PDF). */
|
|
1906
|
+
print(): void;
|
|
1907
|
+
/** Serialize the (edited) document back to .docx bytes. */
|
|
1908
|
+
save(): Uint8Array;
|
|
1909
|
+
/** Page count after the latest layout. */
|
|
1910
|
+
pageCount(): number;
|
|
1911
|
+
/**
|
|
1912
|
+
* Suggesting mode: when on, edits record as OOXML tracked changes (w:ins /
|
|
1913
|
+
* w:del) instead of mutating text directly, and the view switches to markup
|
|
1914
|
+
* so the suggestion shows live. `author` stamps the revision (defaults to the
|
|
1915
|
+
* commentAuthor prop). Turning it off restores the prior revision view.
|
|
1916
|
+
*/
|
|
1917
|
+
setSuggesting(on: boolean, author?: string): void;
|
|
1918
|
+
isSuggesting(): boolean;
|
|
1919
|
+
/** Accept the tracked change at the caret (keep insertion / apply deletion). */
|
|
1920
|
+
acceptRevisionAtCaret(): boolean;
|
|
1921
|
+
/** Reject the tracked change at the caret (drop insertion / restore deletion). */
|
|
1922
|
+
rejectRevisionAtCaret(): boolean;
|
|
1923
|
+
/** How many tracked changes (suggestions) the document currently holds. */
|
|
1924
|
+
revisionCount(): number;
|
|
1925
|
+
/** Accept every tracked change (one undo step). Returns how many applied. */
|
|
1926
|
+
acceptAllRevisions(): number;
|
|
1927
|
+
/** Reject every tracked change (one undo step). Returns how many applied. */
|
|
1928
|
+
rejectAllRevisions(): number;
|
|
1929
|
+
document: DocxDocument;
|
|
1930
|
+
}
|
|
1931
|
+
interface DocxViewProps {
|
|
1932
|
+
/** The document: raw bytes, a File/Blob, or a URL to fetch. */
|
|
1933
|
+
source: ArrayBuffer | Uint8Array | Blob | string;
|
|
1934
|
+
/** Zoom factor, 1 = 100%. */
|
|
1935
|
+
zoom?: number;
|
|
1936
|
+
/**
|
|
1937
|
+
* Fit-to-width (Google-Docs mobile behavior): when the page is wider than the
|
|
1938
|
+
* viewport, auto-scale down so it fits with a small gutter and never scrolls
|
|
1939
|
+
* horizontally. The computed scale drives the real `zoom` (crisp text, not a
|
|
1940
|
+
* blurry transform) and is capped at `zoom`, so a wide desktop viewport is
|
|
1941
|
+
* unchanged. Recomputed on container resize. Default true.
|
|
1942
|
+
*/
|
|
1943
|
+
fitWidth?: boolean;
|
|
1944
|
+
/**
|
|
1945
|
+
* Container width (px) at or below which the chrome switches to its compact
|
|
1946
|
+
* phone/tablet treatment — the comment rail collapses to tap-to-open cards so
|
|
1947
|
+
* balloons never force horizontal scroll. Default 820.
|
|
1948
|
+
*/
|
|
1949
|
+
narrowWidth?: number;
|
|
1950
|
+
/**
|
|
1951
|
+
* Enable editing commands (selection-based formatting, save-back).
|
|
1952
|
+
* Default false: pure render-only viewer.
|
|
1953
|
+
*/
|
|
1954
|
+
editable?: boolean;
|
|
1955
|
+
className?: string;
|
|
1956
|
+
style?: React.CSSProperties;
|
|
1957
|
+
onLoad?: (info: {
|
|
1958
|
+
pageCount: number;
|
|
1959
|
+
document: DocxDocument;
|
|
1960
|
+
}) => void;
|
|
1961
|
+
/** Fires when the document is ready; the api is only usable while mounted. */
|
|
1962
|
+
onReady?: (api: DocxViewApi) => void;
|
|
1963
|
+
onError?: (error: Error) => void;
|
|
1964
|
+
/** Author name stamped on comment replies (default "You"). */
|
|
1965
|
+
commentAuthor?: string;
|
|
1966
|
+
/** Render review comments (range highlights + margin balloons). Default true. */
|
|
1967
|
+
showComments?: boolean;
|
|
1968
|
+
/** Tracked-changes display: "final" (default) or "markup". */
|
|
1969
|
+
revisions?: "final" | "markup";
|
|
1970
|
+
/** Fires after render with document-requested font faces the browser cannot
|
|
1971
|
+
* render (unavailable, or lacking the document's script) — the page is
|
|
1972
|
+
* silently substituting and may differ from Word. Empty array = all good. */
|
|
1973
|
+
onMissingFonts?: (missing: MissingFont[]) => void;
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* High-fidelity paginated DOCX viewer (and, with `editable`, editor).
|
|
1977
|
+
*
|
|
1978
|
+
* ```tsx
|
|
1979
|
+
* <DocxView source="/report.docx" /> // render-only
|
|
1980
|
+
* <DocxView source="/report.docx" editable onReady={setApi} /> // editing
|
|
1981
|
+
* ```
|
|
1982
|
+
*/
|
|
1983
|
+
declare function DocxView({ source, zoom, fitWidth, narrowWidth, editable, className, style, onLoad, onReady, onError, commentAuthor, showComments, revisions, onMissingFonts, }: DocxViewProps): react.JSX.Element;
|
|
1984
|
+
|
|
1985
|
+
export { DocxDocument, DocxToolbar, DocxView, type DocxViewApi, type DocxViewProps, type LineNumberingPatch, type PageLayoutPatch, type ParagraphAlignment, type RunFormatPatch, type SelectionFormat, layoutDocument, printPages, renderToDom };
|