@forevka/wordcanvas 0.7.0 → 0.7.2
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/README.md +48 -1
- package/dist-lib/assets/{worker-BsOsK39A.js → worker-4HYrkNrG.js} +12276 -11981
- package/dist-lib/assets/worker-CJpwUzKh.js +2403 -0
- package/dist-lib/blockFactory-B_CLnkUh.js +106 -0
- package/dist-lib/browser-p_rkUcqE.js +1339 -0
- package/dist-lib/builder.js +365 -109
- package/dist-lib/editorApp-mTD0YNv-.js +9863 -0
- package/dist-lib/export.js +4670 -4567
- package/dist-lib/generate-toc.js +5 -5
- package/dist-lib/import.js +4 -1538
- package/dist-lib/{lists-BegzmTmD.js → lists-Sc5I40JO.js} +2 -2
- package/dist-lib/measure.js +2 -2
- package/dist-lib/{measureHost-CMiJKdlk.js → measureHost-B2aKX7lF.js} +1 -1
- package/dist-lib/metrics-BUMIC9Mv.js +164 -0
- package/dist-lib/pipeline-DD0nxAYM.js +1850 -0
- package/dist-lib/recalc-docx.js +2 -2
- package/dist-lib/recalcToc-CFCGCgij.js +3985 -0
- package/dist-lib/styleProps-DhqDEfvc.js +149 -0
- package/dist-lib/stylesheet-B6oczA-L.js +141 -0
- package/dist-lib/toc-Dj57zdz-.js +213 -0
- package/dist-lib/{webmcp-B7Gvd58E.js → webmcp-CXghUon_.js} +2 -2
- package/dist-lib/{wordcanvas-BAxBeErX.js → wordcanvas-D5DI9ZR1.js} +49 -23
- package/dist-lib/wordcanvas.js +1 -1
- package/dist-node/{chunk-GXFDF7UY.js → chunk-57L5XMCL.js} +327 -59
- package/dist-node/chunk-57L5XMCL.js.map +7 -0
- package/dist-node/{chunk-TBSXA2I4.js → chunk-EGSAVPCC.js} +1 -1
- package/dist-node/chunk-EGSAVPCC.js.map +7 -0
- package/dist-node/{chunk-4PDVRJF6.js → chunk-EMY2P524.js} +32 -2
- package/dist-node/chunk-EMY2P524.js.map +7 -0
- package/dist-node/{chunk-2RCPB7UZ.js → chunk-KJV7GJ3H.js} +1 -1
- package/dist-node/chunk-KJV7GJ3H.js.map +7 -0
- package/dist-node/{chunk-XDUDPPJW.js → chunk-PIMVQULL.js} +93 -24
- package/dist-node/chunk-PIMVQULL.js.map +7 -0
- package/dist-node/{chunk-BRAPV465.js → chunk-SA26UVIJ.js} +2 -2
- package/dist-node/{chunk-IJLL6IFJ.js → chunk-T3253N22.js} +202 -13
- package/dist-node/{chunk-IJLL6IFJ.js.map → chunk-T3253N22.js.map} +2 -2
- package/dist-node/{chunk-4ICCHZX4.js → chunk-U27EBKBG.js} +37 -1
- package/dist-node/chunk-U27EBKBG.js.map +7 -0
- package/dist-node/{engine-FRCX7PXF.js → engine-5F7DUU4W.js} +4 -4
- package/dist-node/export.js +178 -52
- package/dist-node/export.js.map +2 -2
- package/dist-node/generate-toc.js +7 -7
- package/dist-node/import.js +3 -3
- package/dist-node/measure.js +2 -2
- package/dist-node/recalc-docx.js +5 -5
- package/dist-node/recalc-docx.js.map +1 -1
- package/package.json +1 -1
- package/types/model.d.ts +277 -225
- package/types/recalc-docx.d.ts +27 -27
- package/types/wordcanvas.d.ts +212 -157
- package/dist-lib/assets/worker-BbFAIxdy.js +0 -2163
- package/dist-lib/blockFactory-Bcy0U40y.js +0 -178
- package/dist-lib/browser-5Sv4CuNy.js +0 -1284
- package/dist-lib/editorApp-DvjFPHiy.js +0 -7582
- package/dist-lib/metrics-CkAo4zh8.js +0 -143
- package/dist-lib/recalcToc-uaLWt59L.js +0 -3835
- package/dist-lib/styleProps-Db5pEkG8.js +0 -127
- package/dist-lib/toc-CZel_Kk3.js +0 -127
- package/dist-node/chunk-2RCPB7UZ.js.map +0 -7
- package/dist-node/chunk-4ICCHZX4.js.map +0 -7
- package/dist-node/chunk-4PDVRJF6.js.map +0 -7
- package/dist-node/chunk-GXFDF7UY.js.map +0 -7
- package/dist-node/chunk-TBSXA2I4.js.map +0 -7
- package/dist-node/chunk-XDUDPPJW.js.map +0 -7
- /package/dist-node/{chunk-BRAPV465.js.map → chunk-SA26UVIJ.js.map} +0 -0
- /package/dist-node/{engine-FRCX7PXF.js.map → engine-5F7DUU4W.js.map} +0 -0
package/dist-lib/builder.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import { d as
|
|
2
|
-
import { d as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { d as v, s as B } from "./stylesheet-B6oczA-L.js";
|
|
2
|
+
import { d as k, D as C, a as R, b as I, n as F, m as A } from "./lists-Sc5I40JO.js";
|
|
3
|
+
import { b as L, g as D } from "./toc-Dj57zdz-.js";
|
|
4
|
+
import { B as y } from "./blockFactory-B_CLnkUh.js";
|
|
5
|
+
import { t as x, B as w } from "./browser-p_rkUcqE.js";
|
|
6
|
+
import { b as E, e as T, r as H } from "./pipeline-DD0nxAYM.js";
|
|
7
|
+
function N(a) {
|
|
6
8
|
let t = "";
|
|
7
|
-
for (let i = 0; i <
|
|
8
|
-
t += String.fromCharCode(...
|
|
9
|
+
for (let i = 0; i < a.length; i += 32768)
|
|
10
|
+
t += String.fromCharCode(...a.subarray(i, i + 32768));
|
|
9
11
|
return btoa(t);
|
|
10
12
|
}
|
|
11
|
-
function
|
|
12
|
-
const e =
|
|
13
|
-
return `data:${t};base64,${
|
|
13
|
+
function S(a, t) {
|
|
14
|
+
const e = a instanceof ArrayBuffer ? new Uint8Array(a) : a;
|
|
15
|
+
return `data:${t};base64,${N(e)}`;
|
|
14
16
|
}
|
|
15
|
-
class
|
|
17
|
+
class O {
|
|
16
18
|
constructor(t, e, i) {
|
|
17
19
|
this.parent = t, this.ctx = e, this.para = i;
|
|
18
20
|
}
|
|
@@ -29,10 +31,14 @@ class v {
|
|
|
29
31
|
for (const i of this.para.runs) Object.assign(i.style, e.char);
|
|
30
32
|
return Object.assign(this.charPatch, e.char), this;
|
|
31
33
|
}
|
|
34
|
+
/** Append a run, swapping out the empty placeholder a textless paragraph holds.
|
|
35
|
+
* Shared by text() and every inline-content emitter (field/sdt/footnote/…). */
|
|
36
|
+
pushRun(t) {
|
|
37
|
+
return this.para.runs.length === 1 && this.para.runs[0].text === "" ? this.para.runs[0] = t : this.para.runs.push(t), this;
|
|
38
|
+
}
|
|
32
39
|
/** Append a run. Inherits the scope's accrued char formatting; `style` wins. */
|
|
33
40
|
text(t, e) {
|
|
34
|
-
|
|
35
|
-
return this.para.runs.length === 1 && this.para.runs[0].text === "" ? this.para.runs[0] = i : this.para.runs.push(i), this;
|
|
41
|
+
return this.pushRun(this.ctx.run(t, { ...this.charPatch, ...e }));
|
|
36
42
|
}
|
|
37
43
|
applyChar(t) {
|
|
38
44
|
Object.assign(this.charPatch, t);
|
|
@@ -67,6 +73,123 @@ class v {
|
|
|
67
73
|
link(t) {
|
|
68
74
|
return this.applyChar({ link: t });
|
|
69
75
|
}
|
|
76
|
+
/** Remove a char property from the scope default AND every existing run (the
|
|
77
|
+
* exactOptional-safe way to toggle an optional CharStyle field off). */
|
|
78
|
+
clearChar(t) {
|
|
79
|
+
delete this.charPatch[t];
|
|
80
|
+
for (const e of this.para.runs) delete e.style[t];
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
superscript(t = !0) {
|
|
84
|
+
return t ? this.applyChar({ verticalAlign: "super" }) : this.clearChar("verticalAlign");
|
|
85
|
+
}
|
|
86
|
+
subscript(t = !0) {
|
|
87
|
+
return t ? this.applyChar({ verticalAlign: "sub" }) : this.clearChar("verticalAlign");
|
|
88
|
+
}
|
|
89
|
+
letterSpacing(t) {
|
|
90
|
+
return this.applyChar({ letterSpacingPx: t });
|
|
91
|
+
}
|
|
92
|
+
/** Hidden text — kept in the model + .docx, never laid out/painted. */
|
|
93
|
+
hidden(t = !0) {
|
|
94
|
+
return t ? this.applyChar({ hidden: !0 }) : this.clearChar("hidden");
|
|
95
|
+
}
|
|
96
|
+
// ---- inline fields -------------------------------------------------------
|
|
97
|
+
/** Register a built-in field def and append its (fieldId-tagged) result run.
|
|
98
|
+
* PAGE/NUMPAGES emit a live `{page}`/`{pages}` token; DATE/TIME/IF materialize
|
|
99
|
+
* via the shared evaluator so the builder agrees with the editor. */
|
|
100
|
+
emitField(t, e) {
|
|
101
|
+
const i = this.ctx.doc.fields ??= {}, s = this.ctx.ids.next();
|
|
102
|
+
i[s] = { id: s, instruction: E(t), name: t.type, kind: "builtin", spec: t };
|
|
103
|
+
const r = T(t, this.ctx.charDefault, { now: e?.now ?? /* @__PURE__ */ new Date() }), n = r.kind === "token" ? r.token : r.runs.map((o) => o.text).join("");
|
|
104
|
+
return this.pushRun(this.ctx.run(n, { ...this.charPatch, ...e?.style, fieldId: s }));
|
|
105
|
+
}
|
|
106
|
+
/** Insert any built-in field from its typed spec. */
|
|
107
|
+
field(t, e) {
|
|
108
|
+
return this.emitField(t, e);
|
|
109
|
+
}
|
|
110
|
+
pageField(t) {
|
|
111
|
+
return this.emitField(t ? { type: "PAGE", numFmt: t } : { type: "PAGE" });
|
|
112
|
+
}
|
|
113
|
+
numPagesField(t) {
|
|
114
|
+
return this.emitField(t ? { type: "NUMPAGES", numFmt: t } : { type: "NUMPAGES" });
|
|
115
|
+
}
|
|
116
|
+
dateField(t = "M/d/yyyy", e) {
|
|
117
|
+
return this.emitField({ type: "DATE", format: t }, e);
|
|
118
|
+
}
|
|
119
|
+
timeField(t = "h:mm AM/PM", e) {
|
|
120
|
+
return this.emitField({ type: "TIME", format: t }, e);
|
|
121
|
+
}
|
|
122
|
+
/** Conditional field. Branch results are plain text (matching the editor's
|
|
123
|
+
* field constructor — rich branch content stays raw-model only). */
|
|
124
|
+
ifField(t, e, i, s, r) {
|
|
125
|
+
return this.emitField({
|
|
126
|
+
type: "IF",
|
|
127
|
+
operandA: t,
|
|
128
|
+
op: e,
|
|
129
|
+
operandB: i,
|
|
130
|
+
trueRuns: [this.ctx.run(s)],
|
|
131
|
+
falseRuns: [this.ctx.run(r)]
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/** A non-built-in (host-resolved) field: verbatim instruction + cached result.
|
|
135
|
+
* The escape hatch for PAGEREF/REF/SEQ/STYLEREF/etc. (see crossReference). */
|
|
136
|
+
customField(t, e, i) {
|
|
137
|
+
const s = this.ctx.doc.fields ??= {}, r = this.ctx.ids.next(), n = i?.name ?? t.trim().split(/\s+/)[0]?.toUpperCase() ?? "FIELD";
|
|
138
|
+
return s[r] = { id: r, instruction: t, name: n, kind: "custom" }, this.pushRun(this.ctx.run(e, { ...this.charPatch, ...i?.style, fieldId: r }));
|
|
139
|
+
}
|
|
140
|
+
/** A cross-reference to a bookmark, as a REF/PAGEREF field over customField. */
|
|
141
|
+
crossReference(t, e) {
|
|
142
|
+
const i = e?.kind ?? "ref", s = i === "pageRef" ? ` PAGEREF ${t} \\h ` : ` REF ${t} \\h `, r = e?.resultText ?? (i === "pageRef" ? "1" : t);
|
|
143
|
+
return this.customField(s, r, { name: i === "pageRef" ? "PAGEREF" : "REF" });
|
|
144
|
+
}
|
|
145
|
+
// ---- inline content controls (SDT) ---------------------------------------
|
|
146
|
+
emitSdt(t, e, i) {
|
|
147
|
+
const s = this.ctx.doc.sdts ??= {}, r = this.ctx.ids.next();
|
|
148
|
+
return s[r] = t, this.pushRun(this.ctx.run(e, { ...this.charPatch, ...i, sdtId: r }));
|
|
149
|
+
}
|
|
150
|
+
/** Insert any content control from its props. */
|
|
151
|
+
contentControl(t, e, i) {
|
|
152
|
+
return this.emitSdt(t, e, i);
|
|
153
|
+
}
|
|
154
|
+
richTextControl(t, e) {
|
|
155
|
+
return this.emitSdt({ type: "richText", ...e }, t);
|
|
156
|
+
}
|
|
157
|
+
plainTextControl(t, e) {
|
|
158
|
+
return this.emitSdt({ type: "plainText", ...e }, t);
|
|
159
|
+
}
|
|
160
|
+
checkbox(t, e) {
|
|
161
|
+
return this.emitSdt({ type: "checkbox", checked: t, ...e }, t ? "☒" : "☐");
|
|
162
|
+
}
|
|
163
|
+
dropDown(t, e, i) {
|
|
164
|
+
return this.emitSdt({ type: "dropDown", listItems: e, ...i }, t);
|
|
165
|
+
}
|
|
166
|
+
comboBox(t, e, i) {
|
|
167
|
+
return this.emitSdt({ type: "comboBox", listItems: e, ...i }, t);
|
|
168
|
+
}
|
|
169
|
+
dateControl(t, e = "M/d/yyyy", i) {
|
|
170
|
+
return this.emitSdt({ type: "date", dateFormat: e, ...i }, t);
|
|
171
|
+
}
|
|
172
|
+
// ---- footnotes + bookmarks -----------------------------------------------
|
|
173
|
+
/** Append an auto-numbered footnote reference; the note body is a string (one
|
|
174
|
+
* paragraph) or a StoryBuilder callback (rich, multi-paragraph). */
|
|
175
|
+
footnote(t) {
|
|
176
|
+
const e = this.ctx.doc.footnotes ??= {}, i = this.ctx.nextFootnoteNumber(), s = this.ctx.ids.next();
|
|
177
|
+
let r;
|
|
178
|
+
if (typeof t == "string")
|
|
179
|
+
r = [this.ctx.paragraph([this.ctx.run(t, { fontSizePx: 12 })], { spaceAfterPx: 0 })];
|
|
180
|
+
else {
|
|
181
|
+
const n = [];
|
|
182
|
+
t(new f(this.ctx, n)), r = n.filter((o) => o.kind === "paragraph"), r.length < n.length && this.ctx.warn("footnote-non-paragraph", "Footnote bodies hold paragraphs only — non-paragraph blocks were dropped."), r.length === 0 && (r = [this.ctx.paragraph([])]);
|
|
183
|
+
}
|
|
184
|
+
return e[s] = r, this.pushRun(this.ctx.run(String(i), { footnoteRef: s, verticalAlign: "super", fontSizePx: 11 }));
|
|
185
|
+
}
|
|
186
|
+
/** Append `text` and bookmark exactly that run's range in this paragraph. */
|
|
187
|
+
bookmark(t, e, i) {
|
|
188
|
+
const s = this.ctx.doc.bookmarks ??= {}, r = x(this.para.runs).length;
|
|
189
|
+
this.pushRun(this.ctx.run(e, { ...this.charPatch, ...i }));
|
|
190
|
+
const n = x(this.para.runs).length;
|
|
191
|
+
return s[t] = { start: { blockId: this.para.id, offset: r }, end: { blockId: this.para.id, offset: n } }, this;
|
|
192
|
+
}
|
|
70
193
|
align(t) {
|
|
71
194
|
return this.para.style.align = t, this;
|
|
72
195
|
}
|
|
@@ -106,6 +229,12 @@ class v {
|
|
|
106
229
|
pageBreak() {
|
|
107
230
|
return this.parent.pageBreak();
|
|
108
231
|
}
|
|
232
|
+
columnBreak() {
|
|
233
|
+
return this.parent.columnBreak();
|
|
234
|
+
}
|
|
235
|
+
bookmarkRange(t, e) {
|
|
236
|
+
return this.parent.bookmarkRange(t, e);
|
|
237
|
+
}
|
|
109
238
|
// ---- document-level delegators (only when the parent is the root builder) -
|
|
110
239
|
header(t, e) {
|
|
111
240
|
return this.parent.header(t, e);
|
|
@@ -122,16 +251,31 @@ class v {
|
|
|
122
251
|
build() {
|
|
123
252
|
return this.parent.build();
|
|
124
253
|
}
|
|
254
|
+
tableOfContents(t) {
|
|
255
|
+
return this.parent.tableOfContents(t);
|
|
256
|
+
}
|
|
257
|
+
sectionBreak(t) {
|
|
258
|
+
return this.parent.sectionBreak(t);
|
|
259
|
+
}
|
|
260
|
+
defaultStyle(t) {
|
|
261
|
+
return this.parent.defaultStyle(t);
|
|
262
|
+
}
|
|
263
|
+
listDefinition(t, e) {
|
|
264
|
+
return this.parent.listDefinition(t, e);
|
|
265
|
+
}
|
|
266
|
+
tableStylePreset(t, e) {
|
|
267
|
+
return this.parent.tableStylePreset(t, e);
|
|
268
|
+
}
|
|
125
269
|
}
|
|
126
|
-
const
|
|
127
|
-
class
|
|
270
|
+
const P = { spaceAfterPx: 0, lineHeight: 1.35 };
|
|
271
|
+
class W {
|
|
128
272
|
constructor(t, e = {}) {
|
|
129
273
|
this.ctx = t, this.opts = e, this.fractions = e.colFractions;
|
|
130
274
|
}
|
|
131
275
|
tableRows = [];
|
|
132
276
|
fractions;
|
|
133
277
|
row(t) {
|
|
134
|
-
const e = new
|
|
278
|
+
const e = new U(this.ctx);
|
|
135
279
|
if (typeof t == "function") t(e);
|
|
136
280
|
else for (const i of t) e.cell(i);
|
|
137
281
|
return this.tableRows.push({ cells: e.cells }), this;
|
|
@@ -145,82 +289,104 @@ class L {
|
|
|
145
289
|
}
|
|
146
290
|
/** Materialize the TableBlock (called by the owning scope's .table()). */
|
|
147
291
|
toBlock() {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
292
|
+
this.tableRows.length === 0 && (this.ctx.warn("table-empty", "A table was built with no rows — a single empty cell was inserted."), this.row([""]));
|
|
293
|
+
const t = this.opts.style ? this.ctx.tableStyle(this.opts.style) : void 0, e = this.opts.headerRow ?? t?.headerRow ?? !1;
|
|
294
|
+
this.tableRows.forEach((s, r) => {
|
|
295
|
+
const n = e && r === 0;
|
|
296
|
+
for (const o of s.cells) {
|
|
297
|
+
if (n) {
|
|
298
|
+
const h = { bold: !0, ...t?.headerChar };
|
|
299
|
+
for (const l of o.blocks)
|
|
300
|
+
if (l.kind === "paragraph") for (const u of l.runs) Object.assign(u.style, h);
|
|
301
|
+
}
|
|
302
|
+
if (o.shading === void 0) {
|
|
303
|
+
const h = n ? t?.headerShading : (r % 2 === 1 ? t?.stripeShading : void 0) ?? t?.shading;
|
|
304
|
+
h !== void 0 && (o.shading = h);
|
|
305
|
+
}
|
|
306
|
+
o.borders === void 0 && t?.borders && (o.borders = t.borders);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
const i = { kind: "table", id: this.ctx.ids.next(), revision: 0, rows: this.tableRows };
|
|
154
310
|
if (this.fractions && this.fractions.length > 0) {
|
|
155
|
-
const
|
|
156
|
-
|
|
311
|
+
const s = this.fractions.reduce((r, n) => r + n, 0);
|
|
312
|
+
s > 0 && (i.colFractions = this.fractions.map((r) => r / s));
|
|
157
313
|
}
|
|
158
|
-
return
|
|
314
|
+
return i;
|
|
159
315
|
}
|
|
160
316
|
}
|
|
161
|
-
class
|
|
317
|
+
class U {
|
|
162
318
|
constructor(t) {
|
|
163
319
|
this.ctx = t;
|
|
164
320
|
}
|
|
165
321
|
cells = [];
|
|
166
322
|
cell(t, e) {
|
|
167
323
|
const i = [];
|
|
168
|
-
let
|
|
324
|
+
let s;
|
|
169
325
|
if (typeof t == "function")
|
|
170
|
-
t(new f(this.ctx, i)),
|
|
326
|
+
t(new f(this.ctx, i)), s = e ?? {};
|
|
171
327
|
else {
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
328
|
+
s = typeof t == "string" ? { ...e, text: t } : { ...t, ...e };
|
|
329
|
+
const n = { ...P };
|
|
330
|
+
s.align !== void 0 && (n.align = s.align), i.push(this.ctx.paragraph([this.ctx.run(s.text ?? "", s.style ?? {})], n));
|
|
175
331
|
}
|
|
176
|
-
i.length === 0 && i.push(this.ctx.paragraph([],
|
|
177
|
-
const
|
|
178
|
-
return
|
|
332
|
+
i.length === 0 && i.push(this.ctx.paragraph([], P));
|
|
333
|
+
const r = { id: this.ctx.ids.next(), blocks: i };
|
|
334
|
+
return s.colSpan !== void 0 && s.colSpan > 1 && (r.colSpan = s.colSpan), s.rowSpan !== void 0 && s.rowSpan > 1 && (r.rowSpan = s.rowSpan), s.shading !== void 0 && (r.shading = s.shading), s.borders !== void 0 && (r.borders = s.borders), s.margin !== void 0 && (r.margin = s.margin), this.cells.push(r), this;
|
|
179
335
|
}
|
|
180
336
|
}
|
|
181
337
|
class f {
|
|
182
338
|
ctx;
|
|
183
339
|
blocks;
|
|
184
340
|
pendingPageBreak = !1;
|
|
341
|
+
pendingColumnBreak = !1;
|
|
185
342
|
constructor(t, e) {
|
|
186
343
|
this.ctx = t, this.blocks = e;
|
|
187
344
|
}
|
|
188
|
-
/** Append a block, honoring a pending
|
|
189
|
-
*
|
|
345
|
+
/** Append a block, honoring a pending page/column break(). Only paragraphs
|
|
346
|
+
* carry the break flag, so a break before a table/image lands on an injected
|
|
190
347
|
* empty paragraph (same trick as the docx import mapper). */
|
|
191
348
|
push(t) {
|
|
192
|
-
|
|
349
|
+
if (this.pendingPageBreak || this.pendingColumnBreak) {
|
|
350
|
+
if (t.kind === "paragraph")
|
|
351
|
+
this.pendingPageBreak && (t.style.pageBreakBefore = !0), this.pendingColumnBreak && (t.style.columnBreakBefore = !0);
|
|
352
|
+
else {
|
|
353
|
+
const e = {};
|
|
354
|
+
this.pendingPageBreak && (e.pageBreakBefore = !0), this.pendingColumnBreak && (e.columnBreakBefore = !0), this.blocks.push(this.ctx.paragraph([], e));
|
|
355
|
+
}
|
|
356
|
+
this.pendingPageBreak = !1, this.pendingColumnBreak = !1;
|
|
357
|
+
}
|
|
358
|
+
this.blocks.push(t);
|
|
193
359
|
}
|
|
194
360
|
/** Start a paragraph. The returned scope styles THIS paragraph and delegates
|
|
195
361
|
* block-starting calls back here, so the chain continues seamlessly. */
|
|
196
362
|
paragraph(t, e) {
|
|
197
|
-
const i = t !== void 0 ? [this.ctx.run(t, e ?? {})] : [],
|
|
198
|
-
return this.push(
|
|
363
|
+
const i = t !== void 0 ? [this.ctx.run(t, e ?? {})] : [], s = this.ctx.paragraph(i);
|
|
364
|
+
return this.push(s), new O(this, this.ctx, s);
|
|
199
365
|
}
|
|
200
366
|
table(t, e) {
|
|
201
|
-
const i = new
|
|
367
|
+
const i = new W(this.ctx, e);
|
|
202
368
|
return typeof t == "function" ? t(i) : i.rows(t), this.push(i.toBlock()), this;
|
|
203
369
|
}
|
|
204
370
|
/** Insert an image from a URL (https:/data:) or raw bytes (inlined as data:). */
|
|
205
371
|
image(t, e) {
|
|
206
372
|
if (!Number.isFinite(e?.widthPx) || !Number.isFinite(e?.heightPx) || e.widthPx <= 0 || e.heightPx <= 0)
|
|
207
373
|
throw new TypeError("image() requires positive widthPx and heightPx (no DOM to auto-measure in Node).");
|
|
208
|
-
const i = typeof t == "string" ? t :
|
|
374
|
+
const i = typeof t == "string" ? t : S(t.data, t.mime);
|
|
209
375
|
return this.push(this.ctx.image(i, e.widthPx, e.heightPx, e.align ?? "left", e.wrap)), this;
|
|
210
376
|
}
|
|
211
377
|
/** One paragraph per item, marked as list members. Definitions resolve to the
|
|
212
378
|
* template's (via listId), or the editor-default bullet/number definitions
|
|
213
379
|
* registered on demand. */
|
|
214
380
|
list(t, e = {}) {
|
|
215
|
-
const i = e.kind ?? "bullet",
|
|
216
|
-
let
|
|
217
|
-
|
|
218
|
-
`list-missing:${
|
|
219
|
-
`List definition "${
|
|
220
|
-
), r
|
|
221
|
-
for (const
|
|
222
|
-
const o = typeof
|
|
223
|
-
this.push(this.ctx.paragraph([this.ctx.run(o.text, o.style ?? {})], { list: { listId:
|
|
381
|
+
const i = e.kind ?? "bullet", s = this.ctx.doc.lists ??= {};
|
|
382
|
+
let r = e.listId;
|
|
383
|
+
r !== void 0 ? s[r] || (this.ctx.warn(
|
|
384
|
+
`list-missing:${r}`,
|
|
385
|
+
`List definition "${r}" is not in the document — a default ${i} definition was registered under that id.`
|
|
386
|
+
), s[r] = { ...k(i === "number" ? "decimal" : "bullet"), id: r }) : (r = i === "number" ? C : R, s[r] || (s[r] = k(i === "number" ? "decimal" : "bullet")));
|
|
387
|
+
for (const n of t) {
|
|
388
|
+
const o = typeof n == "string" ? { text: n } : n, h = Math.max(0, Math.min(8, o.level ?? e.level ?? 0));
|
|
389
|
+
this.push(this.ctx.paragraph([this.ctx.run(o.text, o.style ?? {})], { list: { listId: r, level: h } }));
|
|
224
390
|
}
|
|
225
391
|
return this;
|
|
226
392
|
}
|
|
@@ -234,81 +400,104 @@ class f {
|
|
|
234
400
|
pageBreak() {
|
|
235
401
|
return this.pendingPageBreak = !0, this;
|
|
236
402
|
}
|
|
403
|
+
/** The NEXT block starts a new newspaper column (Ctrl+Shift+Enter). A trailing
|
|
404
|
+
* column break with no following block is a no-op, matching Word. */
|
|
405
|
+
columnBreak() {
|
|
406
|
+
return this.pendingColumnBreak = !0, this;
|
|
407
|
+
}
|
|
408
|
+
/** Bookmark everything the callback appends to this story (multi-paragraph
|
|
409
|
+
* span). For a precise inline span use ParagraphBuilder.bookmark(name, text). */
|
|
410
|
+
bookmarkRange(t, e) {
|
|
411
|
+
const i = this.blocks.length;
|
|
412
|
+
e(this);
|
|
413
|
+
const s = this.blocks.slice(i).filter((h) => h.kind === "paragraph");
|
|
414
|
+
if (s.length === 0)
|
|
415
|
+
return this.ctx.warn(`bookmark-empty:${t}`, `bookmarkRange("${t}") wrapped no paragraphs — no bookmark was recorded.`), this;
|
|
416
|
+
const r = s[0], n = s[s.length - 1], o = this.ctx.doc.bookmarks ??= {};
|
|
417
|
+
return o[t] = {
|
|
418
|
+
start: { blockId: r.id, offset: 0 },
|
|
419
|
+
end: { blockId: n.id, offset: x(n.runs).length }
|
|
420
|
+
}, this;
|
|
421
|
+
}
|
|
237
422
|
/** A trailing pageBreak() with no following block still needs to exist —
|
|
238
|
-
* materialize it as an empty page-broken paragraph (called by build()).
|
|
423
|
+
* materialize it as an empty page-broken paragraph (called by build()). A
|
|
424
|
+
* pending column break alone is dropped (Word ignores a trailing one). */
|
|
239
425
|
flushPendingPageBreak() {
|
|
240
|
-
this.pendingPageBreak && (this.blocks.push(this.ctx.paragraph([], { pageBreakBefore: !0 })), this.pendingPageBreak = !1);
|
|
426
|
+
this.pendingPageBreak && (this.blocks.push(this.ctx.paragraph([], { pageBreakBefore: !0 })), this.pendingPageBreak = !1, this.pendingColumnBreak = !1);
|
|
241
427
|
}
|
|
242
428
|
}
|
|
243
|
-
function
|
|
244
|
-
const e =
|
|
245
|
-
if (
|
|
246
|
-
const
|
|
429
|
+
function M(a, t) {
|
|
430
|
+
const e = a instanceof Uint8Array ? a : new Uint8Array(a), i = H(e, void 0, { collectMediaBytes: !0 }), s = i.doc, r = new Map(i.media.map((n) => [n.src, S(n.bytes, n.mime)]));
|
|
431
|
+
if (r.size > 0) {
|
|
432
|
+
const n = (o) => {
|
|
247
433
|
for (const h of o ?? [])
|
|
248
434
|
if (h.kind === "image") {
|
|
249
|
-
const l =
|
|
435
|
+
const l = r.get(h.src);
|
|
250
436
|
l && (h.src = l);
|
|
251
437
|
} else if (h.kind === "table")
|
|
252
|
-
for (const l of h.rows) for (const
|
|
438
|
+
for (const l of h.rows) for (const u of l.cells) n(u.blocks);
|
|
253
439
|
};
|
|
254
|
-
|
|
255
|
-
for (const o of
|
|
440
|
+
n(s.blocks);
|
|
441
|
+
for (const o of w) n(s.section[o]);
|
|
256
442
|
}
|
|
257
|
-
return t || (
|
|
443
|
+
return t || (s.blocks = [], delete s.footnotes, $(s)), { doc: s, warnings: i.warnings };
|
|
258
444
|
}
|
|
259
|
-
function
|
|
260
|
-
const t = /* @__PURE__ */ new Set(), e = /* @__PURE__ */ new Set(), i = (
|
|
261
|
-
for (const
|
|
262
|
-
if (t.add(
|
|
263
|
-
for (const
|
|
264
|
-
else if (
|
|
265
|
-
for (const
|
|
445
|
+
function $(a) {
|
|
446
|
+
const t = /* @__PURE__ */ new Set(), e = /* @__PURE__ */ new Set(), i = (s) => {
|
|
447
|
+
for (const r of s ?? [])
|
|
448
|
+
if (t.add(r.id), r.kind === "paragraph")
|
|
449
|
+
for (const n of r.runs) n.style.sdtId && e.add(n.style.sdtId);
|
|
450
|
+
else if (r.kind === "table")
|
|
451
|
+
for (const n of r.rows) for (const o of n.cells) i(o.blocks);
|
|
266
452
|
};
|
|
267
|
-
i(
|
|
268
|
-
for (const
|
|
269
|
-
if (
|
|
270
|
-
for (const [
|
|
271
|
-
(!t.has(
|
|
272
|
-
Object.keys(
|
|
273
|
-
}
|
|
274
|
-
if (
|
|
275
|
-
for (const
|
|
276
|
-
e.has(
|
|
277
|
-
Object.keys(
|
|
453
|
+
i(a.blocks);
|
|
454
|
+
for (const s of w) i(a.section[s]);
|
|
455
|
+
if (a.bookmarks) {
|
|
456
|
+
for (const [s, r] of Object.entries(a.bookmarks))
|
|
457
|
+
(!t.has(r.start.blockId) || !t.has(r.end.blockId)) && delete a.bookmarks[s];
|
|
458
|
+
Object.keys(a.bookmarks).length === 0 && delete a.bookmarks;
|
|
459
|
+
}
|
|
460
|
+
if (a.sdts) {
|
|
461
|
+
for (const s of Object.keys(a.sdts))
|
|
462
|
+
e.has(s) || delete a.sdts[s];
|
|
463
|
+
Object.keys(a.sdts).length === 0 && delete a.sdts;
|
|
278
464
|
}
|
|
279
465
|
}
|
|
280
|
-
const
|
|
466
|
+
const J = (a) => a * 96, Q = (a) => a * 96 / 2.54, V = (a) => a * 96 / 72, X = (a) => a / 15, z = {
|
|
281
467
|
Letter: { pageWidthPx: 816, pageHeightPx: 1056 },
|
|
282
468
|
Legal: { pageWidthPx: 816, pageHeightPx: 1344 },
|
|
283
469
|
A4: { pageWidthPx: 794, pageHeightPx: 1123 },
|
|
284
470
|
A3: { pageWidthPx: 1123, pageHeightPx: 1587 },
|
|
285
471
|
Tabloid: { pageWidthPx: 1056, pageHeightPx: 1632 }
|
|
286
|
-
},
|
|
287
|
-
function
|
|
288
|
-
return typeof
|
|
472
|
+
}, p = 96;
|
|
473
|
+
function g(a) {
|
|
474
|
+
return typeof a == "string" ? z[a] : a;
|
|
289
475
|
}
|
|
290
|
-
class
|
|
476
|
+
class b extends f {
|
|
291
477
|
/** Start from a blank document (default stylesheet, US Letter, 1in margins). */
|
|
292
478
|
static create(t = {}) {
|
|
293
|
-
const e =
|
|
479
|
+
const e = g(t.pageSize ?? "Letter"), i = {
|
|
294
480
|
section: {
|
|
295
481
|
pageWidthPx: e.pageWidthPx,
|
|
296
482
|
pageHeightPx: e.pageHeightPx,
|
|
297
|
-
marginPx: { top:
|
|
483
|
+
marginPx: { top: p, right: p, bottom: p, left: p, ...t.margins }
|
|
298
484
|
},
|
|
299
485
|
blocks: [],
|
|
300
|
-
stylesheet: t.stylesheet ??
|
|
486
|
+
stylesheet: t.stylesheet ?? v()
|
|
301
487
|
};
|
|
302
|
-
return new
|
|
488
|
+
return new b(new y(i, t.idSeed));
|
|
303
489
|
}
|
|
304
490
|
/** Start from a .docx template: its stylesheet, list definitions, page setup,
|
|
305
491
|
* and header/footer bands carry over (body content is discarded unless
|
|
306
492
|
* keepBody). Import warnings surface on `builder.warnings`. */
|
|
307
493
|
static async fromTemplate(t, e = {}) {
|
|
308
|
-
const { doc: i, warnings:
|
|
309
|
-
for (const
|
|
310
|
-
return
|
|
494
|
+
const { doc: i, warnings: s } = M(t, e.keepBody ?? !1), r = new b(new y(i, e.idSeed));
|
|
495
|
+
for (const n of s) r.ctx.warn(n.code, n.message);
|
|
496
|
+
return r;
|
|
311
497
|
}
|
|
498
|
+
/** Set when .tableOfContents() ran — build() splices entries at the anchor. */
|
|
499
|
+
tocRequested = !1;
|
|
500
|
+
tocOpts = {};
|
|
312
501
|
constructor(t) {
|
|
313
502
|
super(t, t.doc.blocks);
|
|
314
503
|
}
|
|
@@ -327,46 +516,113 @@ class d extends f {
|
|
|
327
516
|
return this.band("footer", t, e);
|
|
328
517
|
}
|
|
329
518
|
band(t, e, i) {
|
|
330
|
-
const
|
|
331
|
-
return e(new f(this.ctx,
|
|
519
|
+
const s = i.variant ?? "default", r = s === "default" ? t : `${t}${s === "first" ? "First" : "Even"}`, n = [];
|
|
520
|
+
return e(new f(this.ctx, n)), n.length === 0 && n.push(this.ctx.paragraph([])), this.ctx.doc.section[r] = n, this;
|
|
332
521
|
}
|
|
333
522
|
/** Merge page geometry onto the section (template values are the base). */
|
|
334
523
|
pageSetup(t) {
|
|
335
524
|
const e = this.ctx.doc.section;
|
|
336
525
|
if (t.pageSize !== void 0) {
|
|
337
|
-
const i =
|
|
526
|
+
const i = g(t.pageSize);
|
|
338
527
|
e.pageWidthPx = i.pageWidthPx, e.pageHeightPx = i.pageHeightPx;
|
|
339
528
|
}
|
|
340
529
|
if (t.orientation !== void 0) {
|
|
341
|
-
const i = t.orientation === "landscape", [
|
|
342
|
-
i !==
|
|
530
|
+
const i = t.orientation === "landscape", [s, r] = [e.pageWidthPx, e.pageHeightPx];
|
|
531
|
+
i !== s > r && (e.pageWidthPx = r, e.pageHeightPx = s);
|
|
343
532
|
}
|
|
344
533
|
return t.margins !== void 0 && (e.marginPx = { ...e.marginPx, ...t.margins }), t.columns !== void 0 && (e.columns = { count: t.columns.count, gapPx: t.columns.gapPx ?? 48 }), t.headerDistancePx !== void 0 && (e.headerDistancePx = t.headerDistancePx), t.footerDistancePx !== void 0 && (e.footerDistancePx = t.footerDistancePx), t.pageNumberStart !== void 0 && (e.pageNumberStart = t.pageNumberStart), this;
|
|
345
534
|
}
|
|
346
535
|
/** Register (or override) a named style. Register BEFORE applying it —
|
|
347
536
|
* withStyle() resolves at call time, not at build(). */
|
|
348
537
|
style(t) {
|
|
349
|
-
const e = this.ctx.stylesheet(), i = e.styles.findIndex((
|
|
538
|
+
const e = this.ctx.stylesheet(), i = e.styles.findIndex((s) => s.id === t.id);
|
|
350
539
|
return i >= 0 ? e.styles[i] = t : e.styles.push(t), this;
|
|
351
540
|
}
|
|
541
|
+
/** Make `id` the document's default style and refresh the run/paragraph
|
|
542
|
+
* defaults from it. Call EARLY — only content added afterwards inherits it. */
|
|
543
|
+
defaultStyle(t) {
|
|
544
|
+
const e = this.ctx.stylesheet();
|
|
545
|
+
return B(e, t) ? (e.defaultStyleId = t, this.ctx.refreshDefaults(), this) : (this.ctx.warn(`style-missing:${t}`, `.defaultStyle("${t}") — no such style in the stylesheet; default unchanged.`), this);
|
|
546
|
+
}
|
|
547
|
+
/** Register a custom list definition; reference it via .list(items,{listId:id}). */
|
|
548
|
+
listDefinition(t, e) {
|
|
549
|
+
const i = this.ctx.doc.lists ??= {};
|
|
550
|
+
return "levels" in e ? i[t] = { id: t, levels: e.levels } : e.kind === "bullet" ? i[t] = I(t, e.char) : e.kind === "number" ? i[t] = F(t, e.format, e.suffix ?? ".") : i[t] = { ...A(), id: t }, this;
|
|
551
|
+
}
|
|
552
|
+
/** Register (or override) a builder-only table-style preset — reusable cell
|
|
553
|
+
* formatting applied via .table(rows, { style: name }). Resolved to concrete
|
|
554
|
+
* cell properties at build time; nothing style-id-like enters the model. */
|
|
555
|
+
tableStylePreset(t, e) {
|
|
556
|
+
return this.ctx.tableStyles.set(t, e), this;
|
|
557
|
+
}
|
|
558
|
+
/** Insert a table of contents, built from the document's headings at build()
|
|
559
|
+
* time (so headings added AFTER this call are still included). Pushes a
|
|
560
|
+
* placeholder anchor now; build() replaces it with the entries. */
|
|
561
|
+
tableOfContents(t = {}) {
|
|
562
|
+
this.tocRequested = !0, this.tocOpts = t;
|
|
563
|
+
const e = {
|
|
564
|
+
useOutlineLevels: !0,
|
|
565
|
+
hyperlinks: t.hyperlink ?? !0,
|
|
566
|
+
hideInWeb: !0,
|
|
567
|
+
outlineRange: { from: 1, to: t.maxLevel ?? 3 }
|
|
568
|
+
};
|
|
569
|
+
this.ctx.doc.tocInstruction = L(e);
|
|
570
|
+
const i = this.ctx.paragraph([]);
|
|
571
|
+
return this.push(i), this.ctx.doc.tocAnchorBlockId = i.id, this;
|
|
572
|
+
}
|
|
573
|
+
/** End the current section and start a new one on the next page, with the
|
|
574
|
+
* given per-section overrides (page size/orientation/margins, newspaper
|
|
575
|
+
* columns, page-number restart, and its own header/footer bands). */
|
|
576
|
+
sectionBreak(t = {}) {
|
|
577
|
+
const e = this.compileSectionPatch(t), i = this.ctx.doc.blocks, s = i[i.length - 1];
|
|
578
|
+
return s && s.kind === "paragraph" ? s.style.sectionBreak = { type: "nextPage", props: e } : i.push(this.ctx.paragraph([], { sectionBreak: { type: "nextPage", props: e } })), this;
|
|
579
|
+
}
|
|
580
|
+
compileSectionPatch(t) {
|
|
581
|
+
const e = {}, i = this.ctx.doc.section;
|
|
582
|
+
if (t.pageSize !== void 0 || t.orientation !== void 0) {
|
|
583
|
+
let d = i.pageWidthPx, c = i.pageHeightPx;
|
|
584
|
+
if (t.pageSize !== void 0) {
|
|
585
|
+
const m = g(t.pageSize);
|
|
586
|
+
d = m.pageWidthPx, c = m.pageHeightPx;
|
|
587
|
+
}
|
|
588
|
+
t.orientation !== void 0 && t.orientation === "landscape" != d > c && ([d, c] = [c, d]), e.pageWidthPx = d, e.pageHeightPx = c;
|
|
589
|
+
}
|
|
590
|
+
t.margins !== void 0 && (e.marginPx = { ...i.marginPx, ...t.margins }), t.columns !== void 0 && (e.columns = t.columns === null ? null : { count: t.columns.count, gapPx: t.columns.gapPx ?? 48 }), t.pageNumberStart !== void 0 && (e.pageNumberStart = t.pageNumberStart);
|
|
591
|
+
const s = (d) => {
|
|
592
|
+
if (!d) return;
|
|
593
|
+
const c = [];
|
|
594
|
+
return d(new f(this.ctx, c)), c.length === 0 && c.push(this.ctx.paragraph([])), c;
|
|
595
|
+
}, r = s(t.header);
|
|
596
|
+
r && (e.header = r);
|
|
597
|
+
const n = s(t.footer);
|
|
598
|
+
n && (e.footer = n);
|
|
599
|
+
const o = s(t.headerFirst);
|
|
600
|
+
o && (e.headerFirst = o);
|
|
601
|
+
const h = s(t.footerFirst);
|
|
602
|
+
h && (e.footerFirst = h);
|
|
603
|
+
const l = s(t.headerEven);
|
|
604
|
+
l && (e.headerEven = l);
|
|
605
|
+
const u = s(t.footerEven);
|
|
606
|
+
return u && (e.footerEven = u), e;
|
|
607
|
+
}
|
|
352
608
|
/** Snapshot the document: deep clone, guaranteed at least one paragraph.
|
|
353
609
|
* The builder remains usable (and unaffected by mutations of the result). */
|
|
354
610
|
build() {
|
|
355
611
|
this.flushPendingPageBreak();
|
|
356
|
-
|
|
357
|
-
return t.blocks.length === 0 && t.blocks.push(this.ctx.paragraph([])), t;
|
|
612
|
+
let t = structuredClone(this.ctx.doc);
|
|
613
|
+
return this.tocRequested && t.tocAnchorBlockId !== void 0 && (t = D(t, this.tocOpts).doc), t.blocks.length === 0 && t.blocks.push(this.ctx.paragraph([])), t;
|
|
358
614
|
}
|
|
359
615
|
}
|
|
360
616
|
export {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
617
|
+
b as DocumentBuilder,
|
|
618
|
+
z as PAGE_SIZES,
|
|
619
|
+
O as ParagraphBuilder,
|
|
620
|
+
U as RowBuilder,
|
|
365
621
|
f as StoryBuilder,
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
622
|
+
W as TableBuilder,
|
|
623
|
+
S as bytesToDataUrl,
|
|
624
|
+
Q as cm,
|
|
625
|
+
J as inches,
|
|
626
|
+
V as pt,
|
|
627
|
+
X as twips
|
|
372
628
|
};
|