@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.
Files changed (66) hide show
  1. package/README.md +48 -1
  2. package/dist-lib/assets/{worker-BsOsK39A.js → worker-4HYrkNrG.js} +12276 -11981
  3. package/dist-lib/assets/worker-CJpwUzKh.js +2403 -0
  4. package/dist-lib/blockFactory-B_CLnkUh.js +106 -0
  5. package/dist-lib/browser-p_rkUcqE.js +1339 -0
  6. package/dist-lib/builder.js +365 -109
  7. package/dist-lib/editorApp-mTD0YNv-.js +9863 -0
  8. package/dist-lib/export.js +4670 -4567
  9. package/dist-lib/generate-toc.js +5 -5
  10. package/dist-lib/import.js +4 -1538
  11. package/dist-lib/{lists-BegzmTmD.js → lists-Sc5I40JO.js} +2 -2
  12. package/dist-lib/measure.js +2 -2
  13. package/dist-lib/{measureHost-CMiJKdlk.js → measureHost-B2aKX7lF.js} +1 -1
  14. package/dist-lib/metrics-BUMIC9Mv.js +164 -0
  15. package/dist-lib/pipeline-DD0nxAYM.js +1850 -0
  16. package/dist-lib/recalc-docx.js +2 -2
  17. package/dist-lib/recalcToc-CFCGCgij.js +3985 -0
  18. package/dist-lib/styleProps-DhqDEfvc.js +149 -0
  19. package/dist-lib/stylesheet-B6oczA-L.js +141 -0
  20. package/dist-lib/toc-Dj57zdz-.js +213 -0
  21. package/dist-lib/{webmcp-B7Gvd58E.js → webmcp-CXghUon_.js} +2 -2
  22. package/dist-lib/{wordcanvas-BAxBeErX.js → wordcanvas-D5DI9ZR1.js} +49 -23
  23. package/dist-lib/wordcanvas.js +1 -1
  24. package/dist-node/{chunk-GXFDF7UY.js → chunk-57L5XMCL.js} +327 -59
  25. package/dist-node/chunk-57L5XMCL.js.map +7 -0
  26. package/dist-node/{chunk-TBSXA2I4.js → chunk-EGSAVPCC.js} +1 -1
  27. package/dist-node/chunk-EGSAVPCC.js.map +7 -0
  28. package/dist-node/{chunk-4PDVRJF6.js → chunk-EMY2P524.js} +32 -2
  29. package/dist-node/chunk-EMY2P524.js.map +7 -0
  30. package/dist-node/{chunk-2RCPB7UZ.js → chunk-KJV7GJ3H.js} +1 -1
  31. package/dist-node/chunk-KJV7GJ3H.js.map +7 -0
  32. package/dist-node/{chunk-XDUDPPJW.js → chunk-PIMVQULL.js} +93 -24
  33. package/dist-node/chunk-PIMVQULL.js.map +7 -0
  34. package/dist-node/{chunk-BRAPV465.js → chunk-SA26UVIJ.js} +2 -2
  35. package/dist-node/{chunk-IJLL6IFJ.js → chunk-T3253N22.js} +202 -13
  36. package/dist-node/{chunk-IJLL6IFJ.js.map → chunk-T3253N22.js.map} +2 -2
  37. package/dist-node/{chunk-4ICCHZX4.js → chunk-U27EBKBG.js} +37 -1
  38. package/dist-node/chunk-U27EBKBG.js.map +7 -0
  39. package/dist-node/{engine-FRCX7PXF.js → engine-5F7DUU4W.js} +4 -4
  40. package/dist-node/export.js +178 -52
  41. package/dist-node/export.js.map +2 -2
  42. package/dist-node/generate-toc.js +7 -7
  43. package/dist-node/import.js +3 -3
  44. package/dist-node/measure.js +2 -2
  45. package/dist-node/recalc-docx.js +5 -5
  46. package/dist-node/recalc-docx.js.map +1 -1
  47. package/package.json +1 -1
  48. package/types/model.d.ts +277 -225
  49. package/types/recalc-docx.d.ts +27 -27
  50. package/types/wordcanvas.d.ts +212 -157
  51. package/dist-lib/assets/worker-BbFAIxdy.js +0 -2163
  52. package/dist-lib/blockFactory-Bcy0U40y.js +0 -178
  53. package/dist-lib/browser-5Sv4CuNy.js +0 -1284
  54. package/dist-lib/editorApp-DvjFPHiy.js +0 -7582
  55. package/dist-lib/metrics-CkAo4zh8.js +0 -143
  56. package/dist-lib/recalcToc-uaLWt59L.js +0 -3835
  57. package/dist-lib/styleProps-Db5pEkG8.js +0 -127
  58. package/dist-lib/toc-CZel_Kk3.js +0 -127
  59. package/dist-node/chunk-2RCPB7UZ.js.map +0 -7
  60. package/dist-node/chunk-4ICCHZX4.js.map +0 -7
  61. package/dist-node/chunk-4PDVRJF6.js.map +0 -7
  62. package/dist-node/chunk-GXFDF7UY.js.map +0 -7
  63. package/dist-node/chunk-TBSXA2I4.js.map +0 -7
  64. package/dist-node/chunk-XDUDPPJW.js.map +0 -7
  65. /package/dist-node/{chunk-BRAPV465.js.map → chunk-SA26UVIJ.js.map} +0 -0
  66. /package/dist-node/{engine-FRCX7PXF.js.map → engine-5F7DUU4W.js.map} +0 -0
@@ -1,18 +1,20 @@
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, 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 < s.length; i += 32768)
8
- t += String.fromCharCode(...s.subarray(i, i + 32768));
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 m(s, t) {
12
- const e = s instanceof ArrayBuffer ? new Uint8Array(s) : s;
13
- return `data:${t};base64,${B(e)}`;
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 v {
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
- 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;
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 g = { spaceAfterPx: 0, lineHeight: 1.35 };
127
- class L {
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 C(this.ctx);
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
- 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 };
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 e = this.fractions.reduce((i, r) => i + r, 0);
156
- e > 0 && (t.colFractions = this.fractions.map((i) => i / e));
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 t;
314
+ return i;
159
315
  }
160
316
  }
161
- class C {
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 r;
324
+ let s;
169
325
  if (typeof t == "function")
170
- t(new f(this.ctx, i)), r = e ?? {};
326
+ t(new f(this.ctx, i)), s = e ?? {};
171
327
  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));
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([], 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;
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 pageBreak(). Only paragraphs carry
189
- * pageBreakBefore, so a break before a table/image lands on an injected
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
- this.pendingPageBreak && (t.kind === "paragraph" ? t.style.pageBreakBefore = !0 : this.blocks.push(this.ctx.paragraph([], { pageBreakBefore: !0 })), this.pendingPageBreak = !1), this.blocks.push(t);
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 ?? {})] : [], r = this.ctx.paragraph(i);
198
- return this.push(r), new v(this, this.ctx, r);
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 L(this.ctx, e);
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 : m(t.data, t.mime);
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", 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 } }));
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 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) => {
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 = n.get(h.src);
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 y of l.cells) a(y.blocks);
438
+ for (const l of h.rows) for (const u of l.cells) n(u.blocks);
253
439
  };
254
- a(r.blocks);
255
- for (const o of x) a(r.section[o]);
440
+ n(s.blocks);
441
+ for (const o of w) n(s.section[o]);
256
442
  }
257
- return t || (r.blocks = [], delete r.footnotes, H(r)), { doc: r, warnings: i.warnings };
443
+ return t || (s.blocks = [], delete s.footnotes, $(s)), { doc: s, warnings: i.warnings };
258
444
  }
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);
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(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;
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 R = (s) => s * 96, U = (s) => s * 96 / 2.54, E = (s) => s * 96 / 72, F = (s) => s / 15, I = {
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
- }, c = 96;
287
- function b(s) {
288
- return typeof s == "string" ? I[s] : s;
472
+ }, p = 96;
473
+ function g(a) {
474
+ return typeof a == "string" ? z[a] : a;
289
475
  }
290
- class d extends f {
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 = b(t.pageSize ?? "Letter"), i = {
479
+ const e = g(t.pageSize ?? "Letter"), i = {
294
480
  section: {
295
481
  pageWidthPx: e.pageWidthPx,
296
482
  pageHeightPx: e.pageHeightPx,
297
- marginPx: { top: c, right: c, bottom: c, left: c, ...t.margins }
483
+ marginPx: { top: p, right: p, bottom: p, left: p, ...t.margins }
298
484
  },
299
485
  blocks: [],
300
- stylesheet: t.stylesheet ?? P()
486
+ stylesheet: t.stylesheet ?? v()
301
487
  };
302
- return new d(new u(i, t.idSeed));
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: 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;
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 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;
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 = b(t.pageSize);
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", [r, n] = [e.pageWidthPx, e.pageHeightPx];
342
- i !== r > n && (e.pageWidthPx = n, e.pageHeightPx = r);
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((r) => r.id === t.id);
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
- const t = structuredClone(this.ctx.doc);
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
- d as DocumentBuilder,
362
- I as PAGE_SIZES,
363
- v as ParagraphBuilder,
364
- C as RowBuilder,
617
+ b as DocumentBuilder,
618
+ z as PAGE_SIZES,
619
+ O as ParagraphBuilder,
620
+ U as RowBuilder,
365
621
  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
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
  };