@office-open/docx 0.9.2 → 0.9.4

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.
@@ -1,4 +1,4 @@
1
- import { TargetModeType, convertEmuToPixels, convertPixelsToEmu, convertToEmu, convertToTwip, convertUniversalMeasureToEmu, decimalNumber, eighthPointMeasureValue, hexColorValue, hpsMeasureValue, measurementOrPercentValue, pointMeasureValue, signedTwipsMeasureValue, toUint8Array, twipsMeasureValue, uCharHexNumber, uniqueId, uniqueNumericIdCreator, xsdVerticalMergeRev } from "@office-open/core";
1
+ import { TargetModeType, ThemeColor, convertEmuToPixels, convertPixelsToEmu, convertToEmu, convertToTwip, convertUniversalMeasureToEmu, decimalNumber, eighthPointMeasureValue, hexColorValue, hpsMeasureValue, measurementOrPercentValue, pointMeasureValue, signedTwipsMeasureValue, toUint8Array, twipsMeasureValue, uCharHexNumber, uniqueId, uniqueNumericIdCreator, xsdVerticalMergeRev } from "@office-open/core";
2
2
  import { attr, attrBool, attrNum, children, element, escapeXml, findChild, findDeep, textOf } from "@office-open/xml";
3
3
  import { calculateEffectExtent, createEffectDag, createScene3D, createShape3D, customGeometryDesc, effectListDesc, extractBlipFillMedia, fillDesc, outlineDesc, scene3DDesc, shape3DDesc, transform2DDesc } from "@office-open/core/drawingml";
4
4
  import { chartSpaceDesc } from "@office-open/core/chart";
@@ -243,6 +243,234 @@ const createBodyProperties = (options = {}) => {
243
243
  return element("wps:bodyPr", attrs, children.length > 0 ? children : void 0);
244
244
  };
245
245
  //#endregion
246
+ //#region src/parts/paragraph/run/form-field.ts
247
+ /**
248
+ * Form field module for WordprocessingML documents.
249
+ *
250
+ * Form fields allow creating interactive controls (checkboxes, dropdown lists,
251
+ * text inputs) within a document. Each form field is wrapped in a field code
252
+ * region delimited by fldChar elements (begin/separate/end), with ffData
253
+ * attached to the begin fldChar.
254
+ *
255
+ * Reference: ISO/IEC 29500-4, wml.xsd, CT_FFData, CT_FFCheckBox, CT_FFDDList, CT_FFTextInput
256
+ *
257
+ * @module
258
+ */
259
+ /**
260
+ * Text input field type (ST_FFTextType).
261
+ *
262
+ * ## XSD Schema
263
+ * ```xml
264
+ * <xsd:simpleType name="ST_FFTextType">
265
+ * <xsd:restriction base="xsd:string">
266
+ * <xsd:enumeration value="regular"/>
267
+ * <xsd:enumeration value="number"/>
268
+ * <xsd:enumeration value="date"/>
269
+ * <xsd:enumeration value="currentTime"/>
270
+ * <xsd:enumeration value="currentDate"/>
271
+ * <xsd:enumeration value="calculated"/>
272
+ * </xsd:restriction>
273
+ * </xsd:simpleType>
274
+ * ```
275
+ */
276
+ const FormFieldTextType = {
277
+ /** Regular text input */
278
+ REGULAR: "regular",
279
+ /** Numeric input */
280
+ NUMBER: "number",
281
+ /** Date input */
282
+ DATE: "date",
283
+ /** Current time */
284
+ CURRENT_TIME: "currentTime",
285
+ /** Current date */
286
+ CURRENT_DATE: "currentDate",
287
+ /** Calculated value */
288
+ CALCULATED: "calculated"
289
+ };
290
+ /** Build a w:val-style element with a single attribute. */
291
+ const valElement = (name, val) => `<${name} w:val="${val}"/>`;
292
+ /**
293
+ * Creates a help or status text element.
294
+ */
295
+ const createFormFieldText = (name, options) => `<${name} w:type="${options.type}" w:val="${options.value}"/>`;
296
+ /**
297
+ * Creates a checkbox form field element (w:checkBox).
298
+ */
299
+ const createCheckBox = (options) => {
300
+ const children = [];
301
+ if (options.size !== void 0) children.push(valElement("w:size", options.size));
302
+ else if (options.sizeAuto !== void 0) children.push(`<w:sizeAuto/>`);
303
+ const defaultVal = options.default ?? options.checked;
304
+ if (defaultVal !== void 0) children.push(defaultVal ? `<w:default/>` : `<w:default w:val="0"/>`);
305
+ if (options.checked !== void 0) children.push(options.checked ? `<w:checked/>` : `<w:checked w:val="0"/>`);
306
+ return element("w:checkBox", void 0, children);
307
+ };
308
+ /**
309
+ * Creates a dropdown list form field element (w:ddList).
310
+ */
311
+ const createDropDownList = (options) => {
312
+ const children = [];
313
+ if (options.result !== void 0) children.push(valElement("w:result", options.result));
314
+ if (options.default !== void 0) children.push(valElement("w:default", options.default));
315
+ for (const entry of options.entries) children.push(valElement("w:listEntry", entry));
316
+ return element("w:ddList", void 0, children);
317
+ };
318
+ /**
319
+ * Creates a text input form field element (w:textInput).
320
+ */
321
+ const createTextInput = (options) => {
322
+ const children = [];
323
+ if (options.type !== void 0) children.push(valElement("w:type", options.type));
324
+ if (options.default !== void 0) children.push(valElement("w:default", options.default));
325
+ if (options.maxLength !== void 0) children.push(valElement("w:maxLength", options.maxLength));
326
+ if (options.format !== void 0) children.push(valElement("w:format", options.format));
327
+ return element("w:textInput", void 0, children);
328
+ };
329
+ /**
330
+ * Creates a form field data element (w:ffData).
331
+ *
332
+ * This element contains the definition for an interactive form field
333
+ * (checkbox, dropdown list, or text input) within a document.
334
+ *
335
+ * ## XSD Schema
336
+ * ```xml
337
+ * <xsd:complexType name="CT_FFData">
338
+ * <xsd:choice maxOccurs="unbounded">
339
+ * <xsd:element name="name" type="CT_FFName"/>
340
+ * <xsd:element name="label" type="CT_DecimalNumber"/>
341
+ * <xsd:element name="tabIndex" type="CT_UnsignedDecimalNumber"/>
342
+ * <xsd:element name="enabled" type="CT_OnOff"/>
343
+ * <xsd:element name="calcOnExit" type="CT_OnOff"/>
344
+ * <xsd:element name="entryMacro" type="CT_MacroName"/>
345
+ * <xsd:element name="exitMacro" type="CT_MacroName"/>
346
+ * <xsd:element name="helpText" type="CT_FFHelpText"/>
347
+ * <xsd:element name="statusText" type="CT_FFStatusText"/>
348
+ * <xsd:choice>
349
+ * <xsd:element name="checkBox" type="CT_FFCheckBox"/>
350
+ * <xsd:element name="ddList" type="CT_FFDDList"/>
351
+ * <xsd:element name="textInput" type="CT_FFTextInput"/>
352
+ * </xsd:choice>
353
+ * </xsd:choice>
354
+ * </xsd:complexType>
355
+ * ```
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * // Checkbox
360
+ * createFormFieldData({
361
+ * name: "Check1",
362
+ * checkBox: { checked: true, sizeAuto: true },
363
+ * });
364
+ *
365
+ * // Dropdown
366
+ * createFormFieldData({
367
+ * name: "DropDown1",
368
+ * dropDownList: { entries: ["Option A", "Option B", "Option C"], result: 0 },
369
+ * });
370
+ *
371
+ * // Text input
372
+ * createFormFieldData({
373
+ * name: "Text1",
374
+ * textInput: { type: "regular", default: "Enter text here" },
375
+ * });
376
+ * ```
377
+ */
378
+ const createFormFieldData = (options) => {
379
+ const children = [];
380
+ if (options.name !== void 0) children.push(valElement("w:name", options.name));
381
+ if (options.label !== void 0) children.push(valElement("w:label", options.label));
382
+ if (options.tabIndex !== void 0) children.push(valElement("w:tabIndex", options.tabIndex));
383
+ const enabled = options.enabled ?? true;
384
+ children.push(enabled ? `<w:enabled/>` : `<w:enabled w:val="0"/>`);
385
+ const calcOnExit = options.calcOnExit ?? false;
386
+ children.push(calcOnExit ? `<w:calcOnExit/>` : `<w:calcOnExit w:val="0"/>`);
387
+ if (options.entryMacro !== void 0) children.push(valElement("w:entryMacro", options.entryMacro));
388
+ if (options.exitMacro !== void 0) children.push(valElement("w:exitMacro", options.exitMacro));
389
+ if (options.helpText) children.push(createFormFieldText("w:helpText", options.helpText));
390
+ if (options.statusText) children.push(createFormFieldText("w:statusText", options.statusText));
391
+ if (options.checkBox) children.push(createCheckBox(options.checkBox));
392
+ else if (options.dropDownList) children.push(createDropDownList(options.dropDownList));
393
+ else if (options.textInput) children.push(createTextInput(options.textInput));
394
+ return element("w:ffData", void 0, children);
395
+ };
396
+ /**
397
+ * Parse a w:ffData element back into FormFieldOptions.
398
+ *
399
+ * Inverse of {@link createFormFieldData}. Reads the common form-field metadata
400
+ * (name, label, tabIndex, enabled, calcOnExit) and exactly one of
401
+ * checkBox / dropDownList / textInput.
402
+ */
403
+ function parseFormFieldData(el) {
404
+ const opts = {};
405
+ const name = findChild(el, "w:name");
406
+ if (name) opts.name = attr(name, "w:val");
407
+ const label = findChild(el, "w:label");
408
+ if (label) {
409
+ const v = attrNum(label, "w:val");
410
+ if (v !== void 0) opts.label = v;
411
+ }
412
+ const tabIndex = findChild(el, "w:tabIndex");
413
+ if (tabIndex) {
414
+ const v = attrNum(tabIndex, "w:val");
415
+ if (v !== void 0) opts.tabIndex = v;
416
+ }
417
+ const enabled = findChild(el, "w:enabled");
418
+ if (enabled) opts.enabled = attrBool(enabled, "w:val") ?? true;
419
+ const calcOnExit = findChild(el, "w:calcOnExit");
420
+ if (calcOnExit) opts.calcOnExit = attrBool(calcOnExit, "w:val") ?? true;
421
+ const checkBox = findChild(el, "w:checkBox");
422
+ if (checkBox) {
423
+ const cb = {};
424
+ if (findChild(checkBox, "w:sizeAuto")) cb.sizeAuto = true;
425
+ const size = findChild(checkBox, "w:size");
426
+ if (size) {
427
+ const v = attrNum(size, "w:val");
428
+ if (v !== void 0) cb.size = v;
429
+ }
430
+ const def = findChild(checkBox, "w:default");
431
+ if (def) cb.default = attrBool(def, "w:val") ?? true;
432
+ const checked = findChild(checkBox, "w:checked");
433
+ if (checked) cb.checked = attrBool(checked, "w:val") ?? true;
434
+ opts.checkBox = cb;
435
+ } else {
436
+ const ddList = findChild(el, "w:ddList");
437
+ if (ddList) {
438
+ const entries = [];
439
+ for (const li of children(ddList, "w:listEntry")) entries.push(attr(li, "w:val") ?? "");
440
+ const ddl = { entries };
441
+ const result = findChild(ddList, "w:result");
442
+ if (result) {
443
+ const v = attrNum(result, "w:val");
444
+ if (v !== void 0) ddl.result = v;
445
+ }
446
+ const def = findChild(ddList, "w:default");
447
+ if (def) {
448
+ const v = attrNum(def, "w:val");
449
+ if (v !== void 0) ddl.default = v;
450
+ }
451
+ opts.dropDownList = ddl;
452
+ } else {
453
+ const textInput = findChild(el, "w:textInput");
454
+ if (textInput) {
455
+ const ti = {};
456
+ const type = findChild(textInput, "w:type");
457
+ if (type) ti.type = attr(type, "w:val");
458
+ const def = findChild(textInput, "w:default");
459
+ if (def) ti.default = attr(def, "w:val");
460
+ const maxLength = findChild(textInput, "w:maxLength");
461
+ if (maxLength) {
462
+ const v = attrNum(maxLength, "w:val");
463
+ if (v !== void 0) ti.maxLength = v;
464
+ }
465
+ const format = findChild(textInput, "w:format");
466
+ if (format) ti.format = attr(format, "w:val");
467
+ opts.textInput = ti;
468
+ }
469
+ }
470
+ }
471
+ return opts;
472
+ }
473
+ //#endregion
246
474
  //#region src/parts/table/table-cell/table-cell-components.ts
247
475
  /**
248
476
  * Vertical merge types for table cells.
@@ -1031,40 +1259,76 @@ function parseImageRun(el, ctx) {
1031
1259
  }
1032
1260
  if (anchor && !inline) {
1033
1261
  const floating = {};
1262
+ const margins = {};
1263
+ const distT = attrNum(anchor, "distT");
1264
+ if (distT !== void 0) margins.top = distT;
1265
+ const distB = attrNum(anchor, "distB");
1266
+ if (distB !== void 0) margins.bottom = distB;
1267
+ const distL = attrNum(anchor, "distL");
1268
+ if (distL !== void 0) margins.left = distL;
1269
+ const distR = attrNum(anchor, "distR");
1270
+ if (distR !== void 0) margins.right = distR;
1271
+ if (Object.keys(margins).length > 0) floating.margins = margins;
1034
1272
  const posH = findChild(anchor, "wp:positionH");
1035
1273
  if (posH) {
1036
- const align = findChild(posH, "wp:align");
1037
- const posOffset = findChild(posH, "wp:posOffset");
1038
- if (align) floating.horizontalPosition = { align: textOf(align) };
1039
- else if (posOffset) {
1040
- const val = Number(textOf(posOffset));
1041
- if (!isNaN(val)) floating.horizontalPosition = { offset: val };
1042
- }
1274
+ const hp = readPosition(posH);
1275
+ if (hp) floating.horizontalPosition = hp;
1043
1276
  }
1044
1277
  const posV = findChild(anchor, "wp:positionV");
1045
1278
  if (posV) {
1046
- const align = findChild(posV, "wp:align");
1047
- const posOffset = findChild(posV, "wp:posOffset");
1048
- if (align) floating.verticalPosition = { align: textOf(align) };
1049
- else if (posOffset) {
1050
- const val = Number(textOf(posOffset));
1051
- if (!isNaN(val)) floating.verticalPosition = { offset: val };
1052
- }
1053
- }
1054
- for (const wrapType of [
1055
- "wrapSquare",
1056
- "wrapTight",
1057
- "wrapTopAndBottom",
1058
- "wrapNone"
1059
- ]) if (findChild(anchor, `wp:${wrapType}`)) {
1060
- floating.wrap = wrapType;
1061
- break;
1279
+ const vp = readPosition(posV);
1280
+ if (vp) floating.verticalPosition = vp;
1062
1281
  }
1063
- if (attrBool(anchor, "behindDoc")) floating.behindDocument = true;
1282
+ const wrap = readWrap(anchor);
1283
+ if (wrap) floating.wrap = wrap;
1284
+ const allowOverlap = attrBool(anchor, "allowOverlap");
1285
+ if (allowOverlap !== void 0) floating.allowOverlap = allowOverlap;
1286
+ const behindDoc = attrBool(anchor, "behindDoc");
1287
+ if (behindDoc !== void 0) floating.behindDocument = behindDoc;
1288
+ const locked = attrBool(anchor, "locked");
1289
+ if (locked !== void 0) floating.lockAnchor = locked;
1290
+ const layoutInCell = attrBool(anchor, "layoutInCell");
1291
+ if (layoutInCell !== void 0) floating.layoutInCell = layoutInCell;
1292
+ const relativeHeight = attrNum(anchor, "relativeHeight");
1293
+ if (relativeHeight !== void 0) floating.zIndex = relativeHeight;
1064
1294
  if (Object.keys(floating).length > 0) imageOpts.floating = floating;
1065
1295
  }
1066
1296
  return { image: imageOpts };
1067
1297
  }
1298
+ /** Map wp:positionH/V children + relativeFrom into a position-options object. */
1299
+ function readPosition(posEl) {
1300
+ const relative = attr(posEl, "relativeFrom");
1301
+ const alignEl = findChild(posEl, "wp:align");
1302
+ const posOffset = findChild(posEl, "wp:posOffset");
1303
+ const result = {};
1304
+ if (relative) result.relative = relative;
1305
+ if (alignEl) {
1306
+ const a = textOf(alignEl);
1307
+ if (a) result.align = a;
1308
+ } else if (posOffset) {
1309
+ const val = Number(textOf(posOffset));
1310
+ if (!isNaN(val)) result.offset = val;
1311
+ }
1312
+ return Object.keys(result).length > 0 ? result : void 0;
1313
+ }
1314
+ /** Map the wp:anchor wrap child element into a TextWrapping ({ type, side? }). */
1315
+ function readWrap(anchor) {
1316
+ const WRAP_TYPE = [
1317
+ ["wrapNone", TextWrappingType.NONE],
1318
+ ["wrapSquare", TextWrappingType.SQUARE],
1319
+ ["wrapTight", TextWrappingType.TIGHT],
1320
+ ["wrapTopAndBottom", TextWrappingType.TOP_AND_BOTTOM],
1321
+ ["wrapThrough", TextWrappingType.THROUGH]
1322
+ ];
1323
+ for (const [name, type] of WRAP_TYPE) {
1324
+ const el = findChild(anchor, `wp:${name}`);
1325
+ if (!el) continue;
1326
+ const wrap = { type };
1327
+ const side = attr(el, "wrapText");
1328
+ if (side) wrap.side = side;
1329
+ return wrap;
1330
+ }
1331
+ }
1068
1332
  function getDrawingExtent(el) {
1069
1333
  const inline = findDeep(el, "wp:inline")[0];
1070
1334
  const anchor = inline ? void 0 : findDeep(el, "wp:anchor")[0];
@@ -2027,6 +2291,95 @@ function parseMathArg(parent, childName) {
2027
2291
  return parseMathChildren(container);
2028
2292
  }
2029
2293
  //#endregion
2294
+ //#region src/parts/paragraph/run/field.ts
2295
+ /**
2296
+ * Field module for WordprocessingML documents.
2297
+ *
2298
+ * This module provides support for complex fields, which are regions of text
2299
+ * that can contain dynamic content such as page numbers, dates, or mail merge fields.
2300
+ * Fields are delimited by field character elements (begin, separate, end).
2301
+ *
2302
+ * Reference: http://officeopenxml.com/WPrun.php
2303
+ *
2304
+ * @module
2305
+ */
2306
+ /**
2307
+ * Field character types that delimit field regions.
2308
+ *
2309
+ * @internal
2310
+ */
2311
+ const FieldCharacterType = {
2312
+ BEGIN: "begin",
2313
+ END: "end",
2314
+ SEPARATE: "separate"
2315
+ };
2316
+ /**
2317
+ * Creates a field character element.
2318
+ *
2319
+ * ## XSD Schema
2320
+ * ```xml
2321
+ * <xsd:complexType name="CT_FldChar">
2322
+ * <xsd:sequence>
2323
+ * <xsd:element name="fldData" type="CT_Text" minOccurs="0"/>
2324
+ * <xsd:element name="ffData" type="CT_FFData" minOccurs="0"/>
2325
+ * <xsd:element name="numberingChange" type="CT_TrackChangeNumbering" minOccurs="0"/>
2326
+ * </xsd:sequence>
2327
+ * <xsd:attribute name="fldCharType" type="ST_FldCharType" use="required"/>
2328
+ * <xsd:attribute name="fldLock" type="s:ST_OnOff"/>
2329
+ * <xsd:attribute name="dirty" type="s:ST_OnOff"/>
2330
+ * </xsd:complexType>
2331
+ * ```
2332
+ * @internal
2333
+ */
2334
+ const createFieldChar = (type, dirty, ffData, fldData, fieldLock) => {
2335
+ const children = [];
2336
+ if (fldData !== void 0) children.push(element("w:fldData", { "xml:space": "preserve" }, [fldData]));
2337
+ if (ffData) children.push(ffData);
2338
+ return element("w:fldChar", {
2339
+ "w:dirty": dirty,
2340
+ "w:fldLock": fieldLock,
2341
+ "w:fldCharType": type
2342
+ }, children.length > 0 ? children : void 0);
2343
+ };
2344
+ /**
2345
+ * Creates the beginning of a complex field.
2346
+ *
2347
+ * The Begin element marks the start of a field. A field consists of a begin character,
2348
+ * field instructions, an optional separate character, field result, and an end character.
2349
+ *
2350
+ * For form fields, pass `formField` to embed `w:ffData` within the begin `w:fldChar`.
2351
+ *
2352
+ * @param dirty - Whether the field should be recalculated
2353
+ * @param formField - Optional form field data to embed in the begin character
2354
+ *
2355
+ * @example
2356
+ * ```typescript
2357
+ * // Simple field begin
2358
+ * createBegin();
2359
+ *
2360
+ * // Form field (checkbox)
2361
+ * createBegin(false, {
2362
+ * name: "Check1",
2363
+ * checkBox: { checked: true, sizeAuto: true },
2364
+ * });
2365
+ * ```
2366
+ */
2367
+ const createBegin = (dirty, formField, fieldLock) => createFieldChar(FieldCharacterType.BEGIN, dirty, formField ? createFormFieldData(formField) : void 0, void 0, fieldLock);
2368
+ /**
2369
+ * Creates the separator between field code and field result in a complex field.
2370
+ *
2371
+ * The Separate element divides the field code (instructions) from the field result
2372
+ * (the computed value).
2373
+ */
2374
+ const createSeparate = (dirty) => createFieldChar(FieldCharacterType.SEPARATE, dirty);
2375
+ /**
2376
+ * Creates the end of a complex field.
2377
+ *
2378
+ * The End element marks the end of a field. Every field that begins with a Begin
2379
+ * element must be terminated with an End element.
2380
+ */
2381
+ const createEnd = (dirty) => createFieldChar(FieldCharacterType.END, dirty);
2382
+ //#endregion
2030
2383
  //#region src/parts/paragraph/stringify.ts
2031
2384
  /**
2032
2385
  * Direct XML string builders for paragraph and run properties.
@@ -2466,10 +2819,27 @@ function stringifyChildDispatch(child, ctx) {
2466
2819
  if ("bookmarkEnd" in child) return `<w:bookmarkEnd w:id="${child.bookmarkEnd}"/>`;
2467
2820
  if ("symbolRun" in child) {
2468
2821
  const opts = child.symbolRun;
2469
- return stringifyRunInline({
2470
- ...opts,
2471
- children: [`<w:sym w:char="${opts.char}" w:font="${opts.symbolfont ?? "Wingdings"}"/>`]
2472
- }, ctx);
2822
+ return `<w:r>${stringifyRunProperties(opts) ?? ""}<w:sym w:char="${opts.char}" w:font="${opts.symbolfont ?? "Wingdings"}"/></w:r>`;
2823
+ }
2824
+ if ("formField" in child) {
2825
+ const ff = child.formField;
2826
+ let result = "";
2827
+ let instrCode = "";
2828
+ let symbolFont = false;
2829
+ if (ff.checkBox) {
2830
+ result = ff.checkBox.checked ? "☒" : "☐";
2831
+ instrCode = "FORMCHECKBOX";
2832
+ symbolFont = true;
2833
+ } else if (ff.dropDownList) {
2834
+ const idx = ff.dropDownList.result ?? ff.dropDownList.default;
2835
+ result = idx !== void 0 ? ff.dropDownList.entries[idx] ?? "" : "";
2836
+ instrCode = "FORMDROPDOWN";
2837
+ } else if (ff.textInput) {
2838
+ result = ff.textInput.value ?? ff.textInput.default ?? "";
2839
+ instrCode = "FORMTEXT";
2840
+ }
2841
+ const rPr = symbolFont ? "<w:rPr><w:rFonts w:ascii=\"MS Gothic\" w:hAnsi=\"MS Gothic\"/></w:rPr>" : "";
2842
+ return `<w:r>${createBegin(false, ff)}</w:r><w:r><w:instrText xml:space="preserve"> ${instrCode} </w:instrText></w:r><w:r>${createSeparate()}</w:r><w:r>${rPr}<w:t xml:space="preserve">${escapeXml(result)}</w:t></w:r><w:r>${createEnd()}</w:r>`;
2473
2843
  }
2474
2844
  if ("image" in child) {
2475
2845
  const opts = child.image;
@@ -2698,6 +3068,11 @@ function stringifyChildDispatch(child, ctx) {
2698
3068
  if (sf.cachedValue !== void 0) return `<w:fldSimple w:instr="${escapeXml(sf.instruction)}"><w:r><w:t>${escapeXml(sf.cachedValue)}</w:t></w:r></w:fldSimple>`;
2699
3069
  return `<w:fldSimple w:instr="${escapeXml(sf.instruction)}"/>`;
2700
3070
  }
3071
+ if ("complexField" in child) {
3072
+ const cf = child.complexField;
3073
+ const resultXml = cf.result !== void 0 ? `<w:r><w:fldChar w:fldCharType="separate"/></w:r><w:r><w:t xml:space="preserve">${escapeXml(cf.result)}</w:t></w:r>` : "";
3074
+ return `<w:r><w:fldChar w:fldCharType="begin"/></w:r><w:r><w:instrText xml:space="preserve">${escapeXml(cf.instruction)}</w:instrText></w:r>` + resultXml + "<w:r><w:fldChar w:fldCharType=\"end\"/></w:r>";
3075
+ }
2701
3076
  if ("seqIdentifier" in child) {
2702
3077
  const id = child.seqIdentifier;
2703
3078
  return `<w:r><w:fldChar w:fldCharType="begin"/><w:instrText xml:space="preserve"> SEQ ${escapeXml(id)} </w:instrText><w:fldChar w:fldCharType="separate"/><w:fldChar w:fldCharType="end"/></w:r>`;
@@ -2844,20 +3219,15 @@ function cellMarginStr(tag, opts) {
2844
3219
  const inner = cellMarginChildrenStr(opts);
2845
3220
  return inner ? `<${tag}>${inner}</${tag}>` : void 0;
2846
3221
  }
2847
- const DEFAULT_BORDER = {
2848
- color: "auto",
2849
- size: 4,
2850
- style: BorderStyle.SINGLE
2851
- };
2852
3222
  function tableBordersStr(opts) {
2853
3223
  const parts = [];
2854
- parts.push(borderStr("w:top", opts.top ?? DEFAULT_BORDER));
2855
- parts.push(borderStr("w:left", opts.left ?? DEFAULT_BORDER));
2856
- parts.push(borderStr("w:bottom", opts.bottom ?? DEFAULT_BORDER));
2857
- parts.push(borderStr("w:right", opts.right ?? DEFAULT_BORDER));
2858
- parts.push(borderStr("w:insideH", opts.insideHorizontal ?? DEFAULT_BORDER));
2859
- parts.push(borderStr("w:insideV", opts.insideVertical ?? DEFAULT_BORDER));
2860
- return `<w:tblBorders>${parts.join("")}</w:tblBorders>`;
3224
+ if (opts.top) parts.push(borderStr("w:top", opts.top));
3225
+ if (opts.left) parts.push(borderStr("w:left", opts.left));
3226
+ if (opts.bottom) parts.push(borderStr("w:bottom", opts.bottom));
3227
+ if (opts.right) parts.push(borderStr("w:right", opts.right));
3228
+ if (opts.insideHorizontal) parts.push(borderStr("w:insideH", opts.insideHorizontal));
3229
+ if (opts.insideVertical) parts.push(borderStr("w:insideV", opts.insideVertical));
3230
+ return parts.length > 0 ? `<w:tblBorders>${parts.join("")}</w:tblBorders>` : void 0;
2861
3231
  }
2862
3232
  function cellBordersStr(opts) {
2863
3233
  const parts = [];
@@ -2942,7 +3312,10 @@ function stringifyTablePropertiesInner(options) {
2942
3312
  if (options.width) parts.push(tableWidthStr("w:tblW", options.width));
2943
3313
  if (options.alignment) parts.push(`<w:jc w:val="${options.alignment}"/>`);
2944
3314
  if (options.indent) parts.push(tableWidthStr("w:tblInd", options.indent));
2945
- if (options.borders) parts.push(tableBordersStr(options.borders));
3315
+ if (options.borders) {
3316
+ const bs = tableBordersStr(options.borders);
3317
+ if (bs) parts.push(bs);
3318
+ }
2946
3319
  if (options.shading) parts.push(shadingStr(options.shading));
2947
3320
  if (options.layout) parts.push(`<w:tblLayout w:type="${options.layout}"/>`);
2948
3321
  if (options.cellMargin) {
@@ -3066,7 +3439,10 @@ function stringifyTablePropertyExceptions(options) {
3066
3439
  if (options.alignment) parts.push(`<w:jc w:val="${options.alignment}"/>`);
3067
3440
  if (options.cellSpacing) parts.push(cellSpacingStr(options.cellSpacing));
3068
3441
  if (options.indent) parts.push(tableWidthStr("w:tblInd", options.indent));
3069
- if (options.borders) parts.push(tableBordersStr(options.borders));
3442
+ if (options.borders) {
3443
+ const bs = tableBordersStr(options.borders);
3444
+ if (bs) parts.push(bs);
3445
+ }
3070
3446
  if (options.shading) parts.push(shadingStr(options.shading));
3071
3447
  if (options.layout) parts.push(`<w:tblLayout w:type="${options.layout}"/>`);
3072
3448
  if (options.cellMargin) {
@@ -3088,6 +3464,27 @@ function stringifyTablePropertyExceptions(options) {
3088
3464
  }
3089
3465
  //#endregion
3090
3466
  //#region src/parts/table/descriptor.ts
3467
+ /**
3468
+ * Table (w:tbl) descriptor for DOCX.
3469
+ *
3470
+ * Stringifies pure JSON TableOptions into XML using direct string
3471
+ * concatenation — zero IXmlableObject, zero xml(), zero BaseXmlComponent.
3472
+ *
3473
+ * @module
3474
+ */
3475
+ const BORDER_STYLES = Object.values(BorderStyle);
3476
+ const THEME_COLORS = Object.values(ThemeColor);
3477
+ /** Parse track-change attributes (id/author/date) from w:ins/w:del/w:cellIns/w:cellDel. */
3478
+ function parseChangeAttrs(el) {
3479
+ const change = {};
3480
+ const id = attrNum(el, "w:id");
3481
+ if (id !== void 0) change.id = id;
3482
+ const author = attr(el, "w:author");
3483
+ if (author) change.author = author;
3484
+ const date = attr(el, "w:date");
3485
+ if (date) change.date = date;
3486
+ return change;
3487
+ }
3091
3488
  function buildTableGridXml(widths, revision) {
3092
3489
  const cols = widths.map((w) => `<w:gridCol w:w="${w}"/>`).join("");
3093
3490
  if (revision) {
@@ -3186,9 +3583,9 @@ const tableDesc = {
3186
3583
  kind: "custom",
3187
3584
  stringify(opts, ctx) {
3188
3585
  const parts = [];
3189
- const tblPr = stringifyTableProperties({
3586
+ const tblPrOpts = {
3190
3587
  alignment: opts.alignment,
3191
- borders: opts.borders ?? {},
3588
+ borders: opts.borders,
3192
3589
  caption: opts.caption,
3193
3590
  cellMargin: opts.margins,
3194
3591
  cellSpacing: opts.cellSpacing,
@@ -3202,9 +3599,10 @@ const tableDesc = {
3202
3599
  styleRowBandSize: opts.styleRowBandSize,
3203
3600
  tableLook: opts.tableLook,
3204
3601
  visuallyRightToLeft: opts.visuallyRightToLeft,
3205
- width: opts.width ?? { size: 100 }
3206
- });
3207
- if (tblPr) parts.push(tblPr);
3602
+ width: opts.width,
3603
+ includeIfEmpty: true
3604
+ };
3605
+ parts.push(stringifyTableProperties(tblPrOpts));
3208
3606
  const columnWidths = opts.columnWidths ?? Array(Math.max(...opts.rows.map((r) => r.cells.length))).fill(100);
3209
3607
  parts.push(buildTableGridXml(columnWidths, opts.columnWidthsRevision));
3210
3608
  const extraCells = computeVerticalMergeCells(opts.rows);
@@ -3254,28 +3652,38 @@ function parseTablePropertiesEl(el) {
3254
3652
  }
3255
3653
  const tblBorders = findChild(el, "w:tblBorders");
3256
3654
  if (tblBorders) {
3655
+ const SIDE_KEYS = [
3656
+ ["top", "top"],
3657
+ ["left", "left"],
3658
+ ["bottom", "bottom"],
3659
+ ["right", "right"],
3660
+ ["insideH", "insideHorizontal"],
3661
+ ["insideV", "insideVertical"]
3662
+ ];
3257
3663
  const borders = {};
3258
- for (const side of [
3259
- "top",
3260
- "bottom",
3261
- "left",
3262
- "right",
3263
- "insideH",
3264
- "insideV"
3265
- ]) {
3266
- const sideEl = findChild(tblBorders, `w:${side}`);
3267
- if (sideEl) {
3268
- const b = {};
3269
- const val = attr(sideEl, "w:val");
3270
- if (val) b.style = val;
3271
- const color = attr(sideEl, "w:color");
3272
- if (color) b.color = color;
3273
- const sz = attrNum(sideEl, "w:sz");
3274
- if (sz !== void 0) b.size = sz;
3275
- const space = attrNum(sideEl, "w:space");
3276
- if (space !== void 0) b.space = space;
3277
- borders[side] = b;
3278
- }
3664
+ for (const [xmlSide, key] of SIDE_KEYS) {
3665
+ const sideEl = findChild(tblBorders, `w:${xmlSide}`);
3666
+ if (!sideEl) continue;
3667
+ const style = attr(sideEl, "w:val");
3668
+ if (!style || !BORDER_STYLES.includes(style)) continue;
3669
+ const sideOpts = { style };
3670
+ const color = attr(sideEl, "w:color");
3671
+ if (color) sideOpts.color = color;
3672
+ const size = attrNum(sideEl, "w:sz");
3673
+ if (size !== void 0) sideOpts.size = size;
3674
+ const space = attrNum(sideEl, "w:space");
3675
+ if (space !== void 0) sideOpts.space = space;
3676
+ const themeColor = attr(sideEl, "w:themeColor");
3677
+ if (themeColor && THEME_COLORS.includes(themeColor)) sideOpts.themeColor = themeColor;
3678
+ const themeTint = attr(sideEl, "w:themeTint");
3679
+ if (themeTint) sideOpts.themeTint = themeTint;
3680
+ const themeShade = attr(sideEl, "w:themeShade");
3681
+ if (themeShade) sideOpts.themeShade = themeShade;
3682
+ const shadow = attrBool(sideEl, "w:shadow");
3683
+ if (shadow !== void 0) sideOpts.shadow = shadow;
3684
+ const frame = attrBool(sideEl, "w:frame");
3685
+ if (frame !== void 0) sideOpts.frame = frame;
3686
+ borders[key] = sideOpts;
3279
3687
  }
3280
3688
  if (Object.keys(borders).length > 0) opts.borders = borders;
3281
3689
  }
@@ -3350,6 +3758,45 @@ function parseTablePropertiesEl(el) {
3350
3758
  ...type ? { type } : {}
3351
3759
  };
3352
3760
  }
3761
+ const bidiVisual = findChild(el, "w:bidiVisual");
3762
+ if (bidiVisual) opts.visuallyRightToLeft = attrBool(bidiVisual, "w:val") ?? true;
3763
+ const tblStyleRowBandSize = findChild(el, "w:tblStyleRowBandSize");
3764
+ if (tblStyleRowBandSize) {
3765
+ const val = attrNum(tblStyleRowBandSize, "w:val");
3766
+ if (val !== void 0) opts.styleRowBandSize = val;
3767
+ }
3768
+ const tblStyleColBandSize = findChild(el, "w:tblStyleColBandSize");
3769
+ if (tblStyleColBandSize) {
3770
+ const val = attrNum(tblStyleColBandSize, "w:val");
3771
+ if (val !== void 0) opts.styleColBandSize = val;
3772
+ }
3773
+ const tblCaption = findChild(el, "w:tblCaption");
3774
+ if (tblCaption) {
3775
+ const val = attr(tblCaption, "w:val");
3776
+ if (val) opts.caption = val;
3777
+ }
3778
+ const tblCellSpacing = findChild(el, "w:tblCellSpacing");
3779
+ if (tblCellSpacing) {
3780
+ const type = attr(tblCellSpacing, "w:type");
3781
+ const w = attrNum(tblCellSpacing, "w:w");
3782
+ if (w !== void 0) opts.cellSpacing = {
3783
+ value: w,
3784
+ ...type ? { type } : {}
3785
+ };
3786
+ }
3787
+ const tblPrChange = findChild(el, "w:tblPrChange");
3788
+ if (tblPrChange) {
3789
+ const rev = {};
3790
+ const author = attr(tblPrChange, "w:author");
3791
+ if (author) rev.author = author;
3792
+ const date = attr(tblPrChange, "w:date");
3793
+ if (date) rev.date = date;
3794
+ const id = attrNum(tblPrChange, "w:id");
3795
+ if (id !== void 0) rev.id = id;
3796
+ const innerTblPr = findChild(tblPrChange, "w:tblPr");
3797
+ if (innerTblPr) Object.assign(rev, parseTablePropertiesEl(innerTblPr));
3798
+ if (Object.keys(rev).length > 0) opts.revision = rev;
3799
+ }
3353
3800
  return opts;
3354
3801
  }
3355
3802
  function parseColumnWidthsEl(el) {
@@ -3373,10 +3820,105 @@ function parseTableRowPropertiesEl(el) {
3373
3820
  rule: rule ?? "atLeast"
3374
3821
  };
3375
3822
  }
3823
+ const cnfStyle = findChild(el, "w:cnfStyle");
3824
+ if (cnfStyle) {
3825
+ const val = attr(cnfStyle, "w:val");
3826
+ if (val) {
3827
+ const cnf = { val };
3828
+ const changed = attrBool(cnfStyle, "w:changed");
3829
+ if (changed !== void 0) cnf.changed = changed;
3830
+ opts.cnfStyle = cnf;
3831
+ }
3832
+ }
3833
+ const divId = findChild(el, "w:divId");
3834
+ if (divId) {
3835
+ const val = attrNum(divId, "w:val");
3836
+ if (val !== void 0) opts.divId = val;
3837
+ }
3838
+ const gridBefore = findChild(el, "w:gridBefore");
3839
+ if (gridBefore) {
3840
+ const val = attrNum(gridBefore, "w:val");
3841
+ if (val !== void 0) opts.gridBefore = val;
3842
+ }
3843
+ const gridAfter = findChild(el, "w:gridAfter");
3844
+ if (gridAfter) {
3845
+ const val = attrNum(gridAfter, "w:val");
3846
+ if (val !== void 0) opts.gridAfter = val;
3847
+ }
3848
+ const wBefore = findChild(el, "w:wBefore");
3849
+ if (wBefore) {
3850
+ const rawSize = attr(wBefore, "w:w");
3851
+ const type = attr(wBefore, "w:type");
3852
+ const size = type === "pct" ? rawSize : attrNum(wBefore, "w:w");
3853
+ if (size !== void 0) opts.widthBefore = {
3854
+ size,
3855
+ ...type ? { type } : {}
3856
+ };
3857
+ }
3858
+ const wAfter = findChild(el, "w:wAfter");
3859
+ if (wAfter) {
3860
+ const rawSize = attr(wAfter, "w:w");
3861
+ const type = attr(wAfter, "w:type");
3862
+ const size = type === "pct" ? rawSize : attrNum(wAfter, "w:w");
3863
+ if (size !== void 0) opts.widthAfter = {
3864
+ size,
3865
+ ...type ? { type } : {}
3866
+ };
3867
+ }
3868
+ const jc = findChild(el, "w:jc");
3869
+ if (jc) {
3870
+ const val = attr(jc, "w:val");
3871
+ if (val) opts.rowAlignment = val;
3872
+ }
3873
+ const hidden = findChild(el, "w:hidden");
3874
+ if (hidden) opts.hidden = attrBool(hidden, "w:val") ?? true;
3875
+ const tblCellSpacing = findChild(el, "w:tblCellSpacing");
3876
+ if (tblCellSpacing) {
3877
+ const type = attr(tblCellSpacing, "w:type");
3878
+ const w = attrNum(tblCellSpacing, "w:w");
3879
+ if (w !== void 0) opts.cellSpacing = {
3880
+ value: w,
3881
+ ...type ? { type } : {}
3882
+ };
3883
+ }
3884
+ const ins = findChild(el, "w:ins");
3885
+ if (ins) opts.insertion = parseChangeAttrs(ins);
3886
+ const del = findChild(el, "w:del");
3887
+ if (del) opts.deletion = parseChangeAttrs(del);
3888
+ const trPrChange = findChild(el, "w:trPrChange");
3889
+ if (trPrChange) {
3890
+ const rev = {};
3891
+ const author = attr(trPrChange, "w:author");
3892
+ if (author) rev.author = author;
3893
+ const date = attr(trPrChange, "w:date");
3894
+ if (date) rev.date = date;
3895
+ const id = attrNum(trPrChange, "w:id");
3896
+ if (id !== void 0) rev.id = id;
3897
+ const innerTrPr = findChild(trPrChange, "w:trPr");
3898
+ if (innerTrPr) Object.assign(rev, parseTableRowPropertiesEl(innerTrPr));
3899
+ if (Object.keys(rev).length > 0) opts.revision = rev;
3900
+ }
3376
3901
  const tblHeader = findChild(el, "w:tblHeader");
3377
3902
  if (tblHeader) opts.tableHeader = attrBool(tblHeader, "w:val") ?? true;
3378
3903
  const cantSplit = findChild(el, "w:cantSplit");
3379
3904
  if (cantSplit) opts.cantSplit = attrBool(cantSplit, "w:val") ?? true;
3905
+ const tblLook = findChild(el, "w:tblLook");
3906
+ if (tblLook) {
3907
+ const look = {};
3908
+ const firstRow = attrBool(tblLook, "w:firstRow");
3909
+ if (firstRow !== void 0) look.firstRow = firstRow;
3910
+ const lastRow = attrBool(tblLook, "w:lastRow");
3911
+ if (lastRow !== void 0) look.lastRow = lastRow;
3912
+ const firstColumn = attrBool(tblLook, "w:firstColumn");
3913
+ if (firstColumn !== void 0) look.firstColumn = firstColumn;
3914
+ const lastColumn = attrBool(tblLook, "w:lastColumn");
3915
+ if (lastColumn !== void 0) look.lastColumn = lastColumn;
3916
+ const noHBand = attrBool(tblLook, "w:noHBand");
3917
+ if (noHBand !== void 0) look.noHBand = noHBand;
3918
+ const noVBand = attrBool(tblLook, "w:noVBand");
3919
+ if (noVBand !== void 0) look.noVBand = noVBand;
3920
+ if (Object.keys(look).length > 0) opts.tableLook = look;
3921
+ }
3380
3922
  return opts;
3381
3923
  }
3382
3924
  function parseTableCellPropertiesEl(el) {
@@ -3416,13 +3958,17 @@ function parseTableCellPropertiesEl(el) {
3416
3958
  const tcBorders = findChild(el, "w:tcBorders");
3417
3959
  if (tcBorders) {
3418
3960
  const borders = {};
3419
- for (const side of [
3420
- "top",
3421
- "bottom",
3422
- "left",
3423
- "right"
3961
+ for (const [xmlSide, key] of [
3962
+ ["top", "top"],
3963
+ ["start", "start"],
3964
+ ["left", "left"],
3965
+ ["bottom", "bottom"],
3966
+ ["end", "end"],
3967
+ ["right", "right"],
3968
+ ["tl2br", "topLeftToBottomRight"],
3969
+ ["tr2bl", "topRightToBottomLeft"]
3424
3970
  ]) {
3425
- const sideEl = findChild(tcBorders, `w:${side}`);
3971
+ const sideEl = findChild(tcBorders, `w:${xmlSide}`);
3426
3972
  if (sideEl) {
3427
3973
  const b = {};
3428
3974
  const val = attr(sideEl, "w:val");
@@ -3431,12 +3977,13 @@ function parseTableCellPropertiesEl(el) {
3431
3977
  if (color) b.color = color;
3432
3978
  const sz = attrNum(sideEl, "w:sz");
3433
3979
  if (sz !== void 0) b.size = sz;
3434
- borders[side] = b;
3980
+ borders[key] = b;
3435
3981
  }
3436
3982
  }
3437
3983
  if (Object.keys(borders).length > 0) opts.borders = borders;
3438
3984
  }
3439
- if (findChild(el, "w:noWrap")) opts.noWrap = true;
3985
+ const noWrap = findChild(el, "w:noWrap");
3986
+ if (noWrap) opts.noWrap = attrBool(noWrap, "w:val") ?? true;
3440
3987
  const tcMar = findChild(el, "w:tcMar");
3441
3988
  if (tcMar) {
3442
3989
  const margins = {};
@@ -3465,6 +4012,48 @@ function parseTableCellPropertiesEl(el) {
3465
4012
  const val = attr(textDirection, "w:val");
3466
4013
  if (val) opts.textDirection = val;
3467
4014
  }
4015
+ const hMerge = findChild(el, "w:hMerge");
4016
+ if (hMerge) opts.horizontalMerge = attr(hMerge, "w:val") === "restart" ? "restart" : "continue";
4017
+ const tcFitText = findChild(el, "w:tcFitText");
4018
+ if (tcFitText) opts.fitText = attrBool(tcFitText, "w:val") ?? true;
4019
+ const hideMark = findChild(el, "w:hideMark");
4020
+ if (hideMark) opts.hideMark = attrBool(hideMark, "w:val") ?? true;
4021
+ const headersEl = findChild(el, "w:headers");
4022
+ if (headersEl) {
4023
+ const headerVals = [];
4024
+ for (const h of headersEl.elements ?? []) {
4025
+ if (h.name !== "w:header") continue;
4026
+ const val = attr(h, "w:val");
4027
+ if (val) headerVals.push(val);
4028
+ }
4029
+ if (headerVals.length > 0) opts.headers = headerVals;
4030
+ }
4031
+ const cellIns = findChild(el, "w:cellIns");
4032
+ if (cellIns) opts.insertion = parseChangeAttrs(cellIns);
4033
+ const cellDel = findChild(el, "w:cellDel");
4034
+ if (cellDel) opts.deletion = parseChangeAttrs(cellDel);
4035
+ const tcPrChange = findChild(el, "w:tcPrChange");
4036
+ if (tcPrChange) {
4037
+ const rev = {};
4038
+ const author = attr(tcPrChange, "w:author");
4039
+ if (author) rev.author = author;
4040
+ const date = attr(tcPrChange, "w:date");
4041
+ if (date) rev.date = date;
4042
+ const id = attrNum(tcPrChange, "w:id");
4043
+ if (id !== void 0) rev.id = id;
4044
+ const innerTcPr = findChild(tcPrChange, "w:tcPr");
4045
+ if (innerTcPr) Object.assign(rev, parseTableCellPropertiesEl(innerTcPr));
4046
+ if (Object.keys(rev).length > 0) opts.revision = rev;
4047
+ }
4048
+ const cellMerge = findChild(el, "w:cellMerge");
4049
+ if (cellMerge) {
4050
+ const cm = parseChangeAttrs(cellMerge);
4051
+ const vMerge = attr(cellMerge, "w:vMerge");
4052
+ if (vMerge) cm.verticalMerge = xsdVerticalMergeRev.from(vMerge);
4053
+ const vMergeOrig = attr(cellMerge, "w:vMergeOrig");
4054
+ if (vMergeOrig) cm.verticalMergeOriginal = xsdVerticalMergeRev.from(vMergeOrig);
4055
+ if (Object.keys(cm).length > 0) opts.cellMerge = cm;
4056
+ }
3468
4057
  return opts;
3469
4058
  }
3470
4059
  function parseTableCellEl(el, ctx) {
@@ -3487,6 +4076,15 @@ function parseTableRowEl(el, ctx) {
3487
4076
  const opts = {};
3488
4077
  const trPr = findChild(el, "w:trPr");
3489
4078
  if (trPr) Object.assign(opts, parseTableRowPropertiesEl(trPr));
4079
+ for (const [attrName, optKey] of [
4080
+ ["w:rsidRPr", "rsidRPr"],
4081
+ ["w:rsidR", "rsidR"],
4082
+ ["w:rsidDel", "rsidDel"],
4083
+ ["w:rsidTr", "rsidTr"]
4084
+ ]) {
4085
+ const val = attr(el, attrName);
4086
+ if (val) opts[optKey] = val;
4087
+ }
3490
4088
  const childCells = [];
3491
4089
  for (const child of el.elements ?? []) if (child.name === "w:tc") childCells.push(parseTableCellEl(child, ctx));
3492
4090
  opts.cells = childCells;
@@ -4068,6 +4666,10 @@ const createHeaderFooterReference = (type, options) => `<${type} r:id="rId${opti
4068
4666
  *
4069
4667
  * @module
4070
4668
  */
4669
+ /** Valid page-number @w:fmt values (ST_NumberFormat). */
4670
+ const PAGE_NUMBER_FORMATS = Object.values(NumberFormat);
4671
+ /** Valid page-number @w:chapSep values (ST_ChapterSep). */
4672
+ const PAGE_NUMBER_SEPARATORS = Object.values(PageNumberSeparator);
4071
4673
  function stringifyBorderXml(tag, opts) {
4072
4674
  const attrs = [];
4073
4675
  if (opts.style !== void 0) attrs.push(`w:val="${opts.style}"`);
@@ -4182,14 +4784,14 @@ function stringifySectionPropertiesInner(opts) {
4182
4784
  const parts = [];
4183
4785
  appendHeaderFooterRefs(parts, "w:headerReference", opts.headerWrapperGroup);
4184
4786
  appendHeaderFooterRefs(parts, "w:footerReference", opts.footerWrapperGroup);
4185
- const { size: { width = sectionPageSizeDefaults.WIDTH, height = sectionPageSizeDefaults.HEIGHT, orientation = sectionPageSizeDefaults.ORIENTATION } = {}, margin: { top = sectionMarginDefaults.TOP, right = sectionMarginDefaults.RIGHT, bottom = sectionMarginDefaults.BOTTOM, left = sectionMarginDefaults.LEFT, header = sectionMarginDefaults.HEADER, footer = sectionMarginDefaults.FOOTER, gutter = sectionMarginDefaults.GUTTER } = {}, pageNumbers = {}, borders, textDirection } = opts.page ?? {};
4787
+ const { size: { width = sectionPageSizeDefaults.WIDTH, height = sectionPageSizeDefaults.HEIGHT, orientation = sectionPageSizeDefaults.ORIENTATION, code } = {}, margin: { top = sectionMarginDefaults.TOP, right = sectionMarginDefaults.RIGHT, bottom = sectionMarginDefaults.BOTTOM, left = sectionMarginDefaults.LEFT, header = sectionMarginDefaults.HEADER, footer = sectionMarginDefaults.FOOTER, gutter = sectionMarginDefaults.GUTTER } = {}, pageNumbers = {}, borders, textDirection } = opts.page ?? {};
4186
4788
  const { linePitch = 312, charSpace = 0, type: gridType = "lines" } = opts.grid ?? {};
4187
4789
  if (opts.footnotePr) parts.push(footnotePrXml("w:footnotePr", opts.footnotePr));
4188
4790
  if (opts.endnotePr) parts.push(footnotePrXml("w:endnotePr", opts.endnotePr));
4189
4791
  if (opts.type) parts.push(sectionTypeXml(opts.type));
4190
4792
  const pgW = orientation === "landscape" ? convertToTwip(height) : width;
4191
4793
  const pgH = orientation === "landscape" ? convertToTwip(width) : height;
4192
- parts.push(pageSizeXml(pgW, pgH, orientation));
4794
+ parts.push(pageSizeXml(pgW, pgH, orientation, code));
4193
4795
  parts.push(pageMarginXml(top, right, bottom, left, header, footer, gutter));
4194
4796
  if (borders) parts.push(pageBordersXml(borders));
4195
4797
  if (opts.lineNumbers) parts.push(lineNumberXml(opts.lineNumbers));
@@ -4271,6 +4873,8 @@ function parseSectionPropertiesEl(el) {
4271
4873
  if (h !== void 0) size.height = h;
4272
4874
  }
4273
4875
  if (orient) size.orientation = orient;
4876
+ const code = attrNum(pgSz, "w:code");
4877
+ if (code !== void 0) size.code = code;
4274
4878
  if (Object.keys(size).length > 0) page.size = size;
4275
4879
  const pgMar = findChild(el, "w:pgMar");
4276
4880
  if (pgMar) {
@@ -4295,7 +4899,11 @@ function parseSectionPropertiesEl(el) {
4295
4899
  const start = attrNum(pgNumType, "w:start");
4296
4900
  if (start !== void 0) pageNumbers.start = start;
4297
4901
  const fmt = attr(pgNumType, "w:fmt");
4298
- if (fmt) pageNumbers.formatType = fmt;
4902
+ if (fmt && PAGE_NUMBER_FORMATS.includes(fmt)) pageNumbers.formatType = fmt;
4903
+ const chapSep = attr(pgNumType, "w:chapSep");
4904
+ if (chapSep && PAGE_NUMBER_SEPARATORS.includes(chapSep)) pageNumbers.separator = chapSep;
4905
+ const chapStyle = attrNum(pgNumType, "w:chapStyle");
4906
+ if (chapStyle !== void 0) pageNumbers.chapStyle = chapStyle;
4299
4907
  if (Object.keys(pageNumbers).length > 0) page.pageNumbers = pageNumbers;
4300
4908
  }
4301
4909
  if (Object.keys(page).length > 0) opts.page = page;
@@ -4307,7 +4915,21 @@ function parseSectionPropertiesEl(el) {
4307
4915
  if (count !== void 0) column.count = count;
4308
4916
  const space = attrNum(cols, "w:space");
4309
4917
  if (space !== void 0) column.space = space;
4310
- if (attrBool(cols, "w:sep")) column.separator = true;
4918
+ const separate = attrBool(cols, "w:sep");
4919
+ if (separate !== void 0) column.separate = separate;
4920
+ const equalWidth = attrBool(cols, "w:equalWidth");
4921
+ if (equalWidth !== void 0) column.equalWidth = equalWidth;
4922
+ const colChildren = [];
4923
+ for (const colEl of cols.elements ?? []) {
4924
+ if (colEl.name !== "w:col") continue;
4925
+ const width = attrNum(colEl, "w:w");
4926
+ if (width === void 0) continue;
4927
+ const colAttr = { width };
4928
+ const colSpace = attrNum(colEl, "w:space");
4929
+ if (colSpace !== void 0) colAttr.space = colSpace;
4930
+ colChildren.push(colAttr);
4931
+ }
4932
+ if (colChildren.length > 0) column.children = colChildren;
4311
4933
  if (Object.keys(column).length > 0) opts.column = column;
4312
4934
  }
4313
4935
  const type = findChild(el, "w:type");
@@ -4459,6 +5081,6 @@ function parseNotePropertiesEl(el) {
4459
5081
  return opts;
4460
5082
  }
4461
5083
  //#endregion
4462
- export { TextHorzOverflowType as $, stringifyParagraphProperties as A, HorizontalPositionAlign as B, createPageSize as C, stringifyChildDispatch as D, tableDesc as E, parseDrawingRun as F, createWrapTight as G, SpaceType as H, createVerticalPosition as I, WidthType as J, TextWrappingSide as K, createHorizontalPosition as L, parseMathChildren as M, drawingDesc as N, stringifyParagraphInline as O, resetDrawingIdGen as P, TextBodyWrappingType as Q, HorizontalPositionRelativeFrom as R, PageOrientation as S, setTableParseChild as T, VerticalPositionAlign as U, NumberFormat as V, createWrapThrough as W, TextDirection as X, BorderStyle as Y, VerticalMergeType as Z, DocumentGridType as _, HeaderFooterType as a, Media as at, sectionPageSizeDefaults as b, createSectionType as c, createPageMargin as d, TextVertOverflowType as et, PageBorderDisplay as f, createPageNumberType as g, PageNumberSeparator as h, HeaderFooterReferenceType as i, WORKAROUND2 as it, stringifyRunProperties as j, stringifyRunInline as k, LineNumberRestartFormat as l, PageBorderZOrder as m, sectionPropertiesDesc as n, VerticalAnchor as nt, createHeaderFooterReference as o, createTransformation as ot, PageBorderOffsetFrom as p, TextWrappingType as q, stringifySectionPropertiesXml as r, createBodyProperties as rt, SectionType as s, parseSectionPropertiesEl as t, TextVerticalType as tt, createLineNumberType as u, createDocumentGrid as v, DocumentAttributeNamespaces as w, PageTextDirectionType as x, sectionMarginDefaults as y, VerticalPositionRelativeFrom as z };
5084
+ export { FormFieldTextType as $, stringifyParagraphProperties as A, VerticalPositionRelativeFrom as B, createPageSize as C, stringifyChildDispatch as D, tableDesc as E, resetDrawingIdGen as F, createWrapThrough as G, NumberFormat as H, parseDrawingRun as I, TextWrappingType as J, createWrapTight as K, createVerticalPosition as L, stringifyRunPropertiesInner as M, parseMathChildren as N, stringifyParagraphInline as O, drawingDesc as P, VerticalMergeType as Q, createHorizontalPosition as R, PageOrientation as S, setTableParseChild as T, SpaceType as U, HorizontalPositionAlign as V, VerticalPositionAlign as W, BorderStyle as X, WidthType as Y, TextDirection as Z, DocumentGridType as _, HeaderFooterType as a, TextVerticalType as at, sectionPageSizeDefaults as b, createSectionType as c, WORKAROUND2 as ct, createPageMargin as d, createFormFieldData as et, PageBorderDisplay as f, createPageNumberType as g, PageNumberSeparator as h, HeaderFooterReferenceType as i, TextVertOverflowType as it, stringifyRunProperties as j, stringifyRunInline as k, LineNumberRestartFormat as l, Media as lt, PageBorderZOrder as m, sectionPropertiesDesc as n, TextBodyWrappingType as nt, createHeaderFooterReference as o, VerticalAnchor as ot, PageBorderOffsetFrom as p, TextWrappingSide as q, stringifySectionPropertiesXml as r, TextHorzOverflowType as rt, SectionType as s, createBodyProperties as st, parseSectionPropertiesEl as t, parseFormFieldData as tt, createLineNumberType as u, createTransformation as ut, createDocumentGrid as v, DocumentAttributeNamespaces as w, PageTextDirectionType as x, sectionMarginDefaults as y, HorizontalPositionRelativeFrom as z };
4463
5085
 
4464
- //# sourceMappingURL=document-CeM-U6J3.mjs.map
5086
+ //# sourceMappingURL=document-B_uvEH8b.mjs.map