@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.
Files changed (47) hide show
  1. package/README.md +48 -1
  2. package/dist-lib/assets/{worker-BsOsK39A.js → worker-D8rUOKfg.js} +9603 -9451
  3. package/dist-lib/assets/worker-wXuuyshQ.js +2258 -0
  4. package/dist-lib/{blockFactory-Bcy0U40y.js → blockFactory-CUI4Rqiq.js} +50 -42
  5. package/dist-lib/{browser-5Sv4CuNy.js → browser-DkKxreJM.js} +404 -383
  6. package/dist-lib/builder.js +364 -109
  7. package/dist-lib/editorApp-DLXMmtu5.js +8023 -0
  8. package/dist-lib/export.js +3820 -3768
  9. package/dist-lib/generate-toc.js +4 -4
  10. package/dist-lib/import.js +4 -1538
  11. package/dist-lib/{lists-BegzmTmD.js → lists-Sc5I40JO.js} +2 -2
  12. package/dist-lib/pipeline-CbxmCE84.js +1705 -0
  13. package/dist-lib/recalc-docx.js +2 -2
  14. package/dist-lib/recalcToc-g1hFKSNs.js +3935 -0
  15. package/dist-lib/toc-B6VpkJge.js +213 -0
  16. package/dist-lib/{webmcp-B7Gvd58E.js → webmcp-6WxRNKCc.js} +2 -2
  17. package/dist-lib/{wordcanvas-BAxBeErX.js → wordcanvas-CFqpDK0k.js} +1 -1
  18. package/dist-lib/wordcanvas.js +1 -1
  19. package/dist-node/{chunk-GXFDF7UY.js → chunk-22JHAERT.js} +95 -23
  20. package/dist-node/chunk-22JHAERT.js.map +7 -0
  21. package/dist-node/{chunk-2RCPB7UZ.js → chunk-6AJJMHKY.js} +1 -1
  22. package/dist-node/chunk-6AJJMHKY.js.map +7 -0
  23. package/dist-node/{chunk-XDUDPPJW.js → chunk-CDN6WU2P.js} +89 -26
  24. package/dist-node/chunk-CDN6WU2P.js.map +7 -0
  25. package/dist-node/{chunk-TBSXA2I4.js → chunk-EGSAVPCC.js} +1 -1
  26. package/dist-node/chunk-EGSAVPCC.js.map +7 -0
  27. package/dist-node/{chunk-IJLL6IFJ.js → chunk-RNB336F3.js} +116 -5
  28. package/dist-node/{chunk-IJLL6IFJ.js.map → chunk-RNB336F3.js.map} +2 -2
  29. package/dist-node/{engine-FRCX7PXF.js → engine-5FGDJD2H.js} +3 -3
  30. package/dist-node/export.js +92 -31
  31. package/dist-node/export.js.map +2 -2
  32. package/dist-node/generate-toc.js +5 -5
  33. package/dist-node/import.js +3 -3
  34. package/dist-node/recalc-docx.js +4 -4
  35. package/dist-node/recalc-docx.js.map +1 -1
  36. package/package.json +1 -1
  37. package/types/model.d.ts +231 -225
  38. package/types/recalc-docx.d.ts +27 -27
  39. package/dist-lib/assets/worker-BbFAIxdy.js +0 -2163
  40. package/dist-lib/editorApp-DvjFPHiy.js +0 -7582
  41. package/dist-lib/recalcToc-uaLWt59L.js +0 -3835
  42. package/dist-lib/toc-CZel_Kk3.js +0 -127
  43. package/dist-node/chunk-2RCPB7UZ.js.map +0 -7
  44. package/dist-node/chunk-GXFDF7UY.js.map +0 -7
  45. package/dist-node/chunk-TBSXA2I4.js.map +0 -7
  46. package/dist-node/chunk-XDUDPPJW.js.map +0 -7
  47. /package/dist-node/{engine-FRCX7PXF.js.map → engine-5FGDJD2H.js.map} +0 -0
@@ -1,18 +1,19 @@
1
- import { d as P, B as u } from "./blockFactory-Bcy0U40y.js";
2
- import { d as p, D as k, a as w } from "./lists-BegzmTmD.js";
3
- import { B as x } from "./browser-5Sv4CuNy.js";
4
- import { runImport as S } from "./import.js";
5
- function B(s) {
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 < s.length; i += 32768)
8
- t += String.fromCharCode(...s.subarray(i, i + 32768));
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 m(s, t) {
12
- const e = s instanceof ArrayBuffer ? new Uint8Array(s) : s;
13
- return `data:${t};base64,${B(e)}`;
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 v {
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
- const i = this.ctx.run(t, { ...this.charPatch, ...e });
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 g = { spaceAfterPx: 0, lineHeight: 1.35 };
127
- class L {
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 C(this.ctx);
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
- if (this.tableRows.length === 0 && (this.ctx.warn("table-empty", "A table was built with no rows — a single empty cell was inserted."), this.row([""])), this.opts.headerRow) {
149
- for (const e of this.tableRows[0].cells)
150
- for (const i of e.blocks)
151
- if (i.kind === "paragraph") for (const r of i.runs) r.style.bold = !0;
152
- }
153
- const t = { kind: "table", id: this.ctx.ids.next(), revision: 0, rows: this.tableRows };
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 e = this.fractions.reduce((i, r) => i + r, 0);
156
- e > 0 && (t.colFractions = this.fractions.map((i) => i / e));
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 t;
313
+ return i;
159
314
  }
160
315
  }
161
- class C {
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 r;
323
+ let s;
169
324
  if (typeof t == "function")
170
- t(new f(this.ctx, i)), r = e ?? {};
325
+ t(new f(this.ctx, i)), s = e ?? {};
171
326
  else {
172
- r = typeof t == "string" ? { ...e, text: t } : { ...t, ...e };
173
- const a = { ...g };
174
- r.align !== void 0 && (a.align = r.align), i.push(this.ctx.paragraph([this.ctx.run(r.text ?? "", r.style ?? {})], a));
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([], g));
177
- const n = { id: this.ctx.ids.next(), blocks: i };
178
- return r.colSpan !== void 0 && r.colSpan > 1 && (n.colSpan = r.colSpan), r.rowSpan !== void 0 && r.rowSpan > 1 && (n.rowSpan = r.rowSpan), r.shading !== void 0 && (n.shading = r.shading), r.borders !== void 0 && (n.borders = r.borders), r.margin !== void 0 && (n.margin = r.margin), this.cells.push(n), this;
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 pageBreak(). Only paragraphs carry
189
- * pageBreakBefore, so a break before a table/image lands on an injected
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
- this.pendingPageBreak && (t.kind === "paragraph" ? t.style.pageBreakBefore = !0 : this.blocks.push(this.ctx.paragraph([], { pageBreakBefore: !0 })), this.pendingPageBreak = !1), this.blocks.push(t);
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 ?? {})] : [], r = this.ctx.paragraph(i);
198
- return this.push(r), new v(this, this.ctx, r);
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 L(this.ctx, e);
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 : m(t.data, t.mime);
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", r = this.ctx.doc.lists ??= {};
216
- let n = e.listId;
217
- n !== void 0 ? r[n] || (this.ctx.warn(
218
- `list-missing:${n}`,
219
- `List definition "${n}" is not in the document — a default ${i} definition was registered under that id.`
220
- ), r[n] = { ...p(i === "number" ? "decimal" : "bullet"), id: n }) : (n = i === "number" ? k : w, r[n] || (r[n] = p(i === "number" ? "decimal" : "bullet")));
221
- for (const a of t) {
222
- const o = typeof a == "string" ? { text: a } : a, h = Math.max(0, Math.min(8, o.level ?? e.level ?? 0));
223
- this.push(this.ctx.paragraph([this.ctx.run(o.text, o.style ?? {})], { list: { listId: n, level: h } }));
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 A(s, t) {
244
- const e = s instanceof Uint8Array ? s : new Uint8Array(s), i = S(e, void 0, { collectMediaBytes: !0 }), r = i.doc, n = new Map(i.media.map((a) => [a.src, m(a.bytes, a.mime)]));
245
- if (n.size > 0) {
246
- const a = (o) => {
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 = n.get(h.src);
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 y of l.cells) a(y.blocks);
437
+ for (const l of h.rows) for (const u of l.cells) n(u.blocks);
253
438
  };
254
- a(r.blocks);
255
- for (const o of x) a(r.section[o]);
439
+ n(s.blocks);
440
+ for (const o of w) n(s.section[o]);
256
441
  }
257
- return t || (r.blocks = [], delete r.footnotes, H(r)), { doc: r, warnings: i.warnings };
442
+ return t || (s.blocks = [], delete s.footnotes, $(s)), { doc: s, warnings: i.warnings };
258
443
  }
259
- function H(s) {
260
- const t = /* @__PURE__ */ new Set(), e = /* @__PURE__ */ new Set(), i = (r) => {
261
- for (const n of r ?? [])
262
- if (t.add(n.id), n.kind === "paragraph")
263
- for (const a of n.runs) a.style.sdtId && e.add(a.style.sdtId);
264
- else if (n.kind === "table")
265
- for (const a of n.rows) for (const o of a.cells) i(o.blocks);
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(s.blocks);
268
- for (const r of x) i(s.section[r]);
269
- if (s.bookmarks) {
270
- for (const [r, n] of Object.entries(s.bookmarks))
271
- (!t.has(n.start.blockId) || !t.has(n.end.blockId)) && delete s.bookmarks[r];
272
- Object.keys(s.bookmarks).length === 0 && delete s.bookmarks;
273
- }
274
- if (s.sdts) {
275
- for (const r of Object.keys(s.sdts))
276
- e.has(r) || delete s.sdts[r];
277
- Object.keys(s.sdts).length === 0 && delete s.sdts;
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 R = (s) => s * 96, U = (s) => s * 96 / 2.54, E = (s) => s * 96 / 72, F = (s) => s / 15, I = {
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
- }, c = 96;
287
- function b(s) {
288
- return typeof s == "string" ? I[s] : s;
471
+ }, p = 96;
472
+ function g(a) {
473
+ return typeof a == "string" ? z[a] : a;
289
474
  }
290
- class d extends f {
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 = b(t.pageSize ?? "Letter"), i = {
478
+ const e = g(t.pageSize ?? "Letter"), i = {
294
479
  section: {
295
480
  pageWidthPx: e.pageWidthPx,
296
481
  pageHeightPx: e.pageHeightPx,
297
- marginPx: { top: c, right: c, bottom: c, left: c, ...t.margins }
482
+ marginPx: { top: p, right: p, bottom: p, left: p, ...t.margins }
298
483
  },
299
484
  blocks: [],
300
- stylesheet: t.stylesheet ?? P()
485
+ stylesheet: t.stylesheet ?? v()
301
486
  };
302
- return new d(new u(i, t.idSeed));
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: r } = A(t, e.keepBody ?? !1), n = new d(new u(i, e.idSeed));
309
- for (const a of r) n.ctx.warn(a.code, a.message);
310
- return n;
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 r = i.variant ?? "default", n = r === "default" ? t : `${t}${r === "first" ? "First" : "Even"}`, a = [];
331
- return e(new f(this.ctx, a)), a.length === 0 && a.push(this.ctx.paragraph([])), this.ctx.doc.section[n] = a, this;
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 = b(t.pageSize);
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", [r, n] = [e.pageWidthPx, e.pageHeightPx];
342
- i !== r > n && (e.pageWidthPx = n, e.pageHeightPx = r);
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((r) => r.id === t.id);
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
- const t = structuredClone(this.ctx.doc);
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
- d as DocumentBuilder,
362
- I as PAGE_SIZES,
363
- v as ParagraphBuilder,
364
- C as RowBuilder,
616
+ b as DocumentBuilder,
617
+ z as PAGE_SIZES,
618
+ O as ParagraphBuilder,
619
+ U as RowBuilder,
365
620
  f as StoryBuilder,
366
- L as TableBuilder,
367
- m as bytesToDataUrl,
368
- U as cm,
369
- R as inches,
370
- E as pt,
371
- F as twips
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
  };