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