@json-to-office/core-docx 7.0.1 → 7.1.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.
@@ -2008,6 +2008,7 @@ var init_layoutUtils = __esm({
2008
2008
  if (themeConfig?.page) {
2009
2009
  const margins = themeConfig.page.margins || {};
2010
2010
  const dimensions = getPageDimensions(themeConfig.page.size);
2011
+ const gutter = margins.gutter;
2011
2012
  return {
2012
2013
  size: {
2013
2014
  width: dimensions.width,
@@ -2018,7 +2019,13 @@ var init_layoutUtils = __esm({
2018
2019
  top: margins.top ?? defaultMargins.top ?? 1440,
2019
2020
  right: margins.right ?? defaultMargins.right ?? 1440,
2020
2021
  bottom: margins.bottom ?? defaultMargins.bottom ?? 1440,
2021
- left: margins.left ?? defaultMargins.left ?? 1440
2022
+ left: margins.left ?? defaultMargins.left ?? 1440,
2023
+ // How far the running head and foot sit from the page edge. Left out,
2024
+ // each renderer writes its own default — docx.js 708, office-open 851
2025
+ // and 992 — in place of the distance the theme states.
2026
+ header: margins.header ?? defaultMargins.header ?? 720,
2027
+ footer: margins.footer ?? defaultMargins.footer ?? 720,
2028
+ ...gutter !== void 0 && { gutter }
2022
2029
  }
2023
2030
  };
2024
2031
  }
@@ -2034,50 +2041,15 @@ var init_layoutUtils = __esm({
2034
2041
  top: defaultMargins.top ?? 1440,
2035
2042
  right: defaultMargins.right ?? 1440,
2036
2043
  bottom: defaultMargins.bottom ?? 1440,
2037
- left: defaultMargins.left ?? 1440
2044
+ left: defaultMargins.left ?? 1440,
2045
+ header: defaultMargins.header ?? 720,
2046
+ footer: defaultMargins.footer ?? 720
2038
2047
  }
2039
2048
  };
2040
2049
  };
2041
2050
  }
2042
2051
  });
2043
2052
 
2044
- // src/utils/generationContext.ts
2045
- import { AsyncLocalStorage } from "async_hooks";
2046
- import { isAbsolute, resolve } from "path";
2047
- function runWithBaseDir(baseDir, callback) {
2048
- return baseDir === void 0 ? callback() : baseDirStorage.run(resolve(baseDir), callback);
2049
- }
2050
- function resolveFromBaseDir(filePath) {
2051
- const base = baseDirStorage.getStore();
2052
- if (!base || isAbsolute(filePath)) return filePath;
2053
- return resolve(base, filePath);
2054
- }
2055
- function runWithWarnings(warnings, callback) {
2056
- return warnings === void 0 ? callback() : warningsStorage.run(warnings, callback);
2057
- }
2058
- function reportWarning(component, code, message, context) {
2059
- const warnings = warningsStorage.getStore();
2060
- if (warnings) {
2061
- warnings.push({
2062
- component,
2063
- message,
2064
- severity: "warning",
2065
- context: { code, ...context }
2066
- });
2067
- return;
2068
- }
2069
- console.warn(`[json-to-docx] [${code}] ${message}`);
2070
- }
2071
- var generationDateStorage, baseDirStorage, warningsStorage;
2072
- var init_generationContext = __esm({
2073
- "src/utils/generationContext.ts"() {
2074
- "use strict";
2075
- generationDateStorage = new AsyncLocalStorage();
2076
- baseDirStorage = new AsyncLocalStorage();
2077
- warningsStorage = new AsyncLocalStorage();
2078
- }
2079
- });
2080
-
2081
2053
  // src/themes/json/parser.ts
2082
2054
  import { validateThemeJson } from "@json-to-office/shared-docx/validation/unified";
2083
2055
  var ThemeValidationError, ThemeParseError, ThemeParser;
@@ -2388,7 +2360,8 @@ function getAvailableWidthTwips(theme, themeName) {
2388
2360
  const width = page?.size?.width || 0;
2389
2361
  const left = page?.margin?.left || 0;
2390
2362
  const right = page?.margin?.right || 0;
2391
- return Math.max(0, width - left - right);
2363
+ const gutter = page?.margin?.gutter || 0;
2364
+ return Math.max(0, width - left - right - gutter);
2392
2365
  }
2393
2366
  function getPageWidthTwips(theme, themeName) {
2394
2367
  const page = getPageSetup(theme, themeName);
@@ -2423,6 +2396,13 @@ function resolveOffsetTwips(value, referenceTwips) {
2423
2396
  }
2424
2397
  return Math.round(referenceTwips * parseFloat(match[1]) / 100);
2425
2398
  }
2399
+ function splitTwips(count, totalTwips) {
2400
+ const edge = (index) => Math.round(totalTwips * index / count);
2401
+ return Array.from(
2402
+ { length: count },
2403
+ (_, index) => edge(index + 1) - edge(index)
2404
+ );
2405
+ }
2426
2406
  function relativeLengthToTwips(value, availableWidthTwips) {
2427
2407
  if (typeof value === "number") {
2428
2408
  return pointsToTwips(value);
@@ -2439,6 +2419,43 @@ var init_widthUtils = __esm({
2439
2419
  }
2440
2420
  });
2441
2421
 
2422
+ // src/utils/generationContext.ts
2423
+ import { AsyncLocalStorage } from "async_hooks";
2424
+ import { isAbsolute, resolve } from "path";
2425
+ function runWithBaseDir(baseDir, callback) {
2426
+ return baseDir === void 0 ? callback() : baseDirStorage.run(resolve(baseDir), callback);
2427
+ }
2428
+ function resolveFromBaseDir(filePath) {
2429
+ const base = baseDirStorage.getStore();
2430
+ if (!base || isAbsolute(filePath)) return filePath;
2431
+ return resolve(base, filePath);
2432
+ }
2433
+ function runWithWarnings(warnings, callback) {
2434
+ return warnings === void 0 ? callback() : warningsStorage.run(warnings, callback);
2435
+ }
2436
+ function reportWarning(component, code, message, context) {
2437
+ const warnings = warningsStorage.getStore();
2438
+ if (warnings) {
2439
+ warnings.push({
2440
+ component,
2441
+ message,
2442
+ severity: "warning",
2443
+ context: { code, ...context }
2444
+ });
2445
+ return;
2446
+ }
2447
+ console.warn(`[json-to-docx] [${code}] ${message}`);
2448
+ }
2449
+ var generationDateStorage, baseDirStorage, warningsStorage;
2450
+ var init_generationContext = __esm({
2451
+ "src/utils/generationContext.ts"() {
2452
+ "use strict";
2453
+ generationDateStorage = new AsyncLocalStorage();
2454
+ baseDirStorage = new AsyncLocalStorage();
2455
+ warningsStorage = new AsyncLocalStorage();
2456
+ }
2457
+ });
2458
+
2442
2459
  // src/utils/imageUtils.ts
2443
2460
  import { readFileSync } from "fs";
2444
2461
  import { availableParallelism } from "os";
@@ -2734,7 +2751,7 @@ var init_imageUtils = __esm({
2734
2751
  });
2735
2752
 
2736
2753
  // src/ir/types.ts
2737
- var TWIPS_PER_INCH, TWIPS_PER_POINT2, EMU_PER_INCH, EMU_PER_TWIP, DOCX_IR_SCHEMA_VERSION;
2754
+ var TWIPS_PER_INCH, TWIPS_PER_POINT2, EMU_PER_INCH, EMU_PER_TWIP, DOCX_IR_SCHEMA_VERSION, DOCX_IR_BORDER_STYLES;
2738
2755
  var init_types = __esm({
2739
2756
  "src/ir/types.ts"() {
2740
2757
  "use strict";
@@ -2743,6 +2760,35 @@ var init_types = __esm({
2743
2760
  EMU_PER_INCH = 914400;
2744
2761
  EMU_PER_TWIP = EMU_PER_INCH / TWIPS_PER_INCH;
2745
2762
  DOCX_IR_SCHEMA_VERSION = 1;
2763
+ DOCX_IR_BORDER_STYLES = [
2764
+ "single",
2765
+ "dashDotStroked",
2766
+ "dashed",
2767
+ "dashSmallGap",
2768
+ "dotDash",
2769
+ "dotDotDash",
2770
+ "dotted",
2771
+ "double",
2772
+ "doubleWave",
2773
+ "inset",
2774
+ "nil",
2775
+ "none",
2776
+ "outset",
2777
+ "thick",
2778
+ "thickThinLargeGap",
2779
+ "thickThinMediumGap",
2780
+ "thickThinSmallGap",
2781
+ "thinThickLargeGap",
2782
+ "thinThickMediumGap",
2783
+ "thinThickSmallGap",
2784
+ "thinThickThinLargeGap",
2785
+ "thinThickThinMediumGap",
2786
+ "thinThickThinSmallGap",
2787
+ "threeDEmboss",
2788
+ "threeDEngrave",
2789
+ "triple",
2790
+ "wave"
2791
+ ];
2746
2792
  }
2747
2793
  });
2748
2794
 
@@ -2802,7 +2848,6 @@ import {
2802
2848
  AlignmentType,
2803
2849
  BookmarkEnd,
2804
2850
  BookmarkStart,
2805
- BorderStyle,
2806
2851
  ColumnBreak,
2807
2852
  CommentRangeEnd,
2808
2853
  CommentRangeStart,
@@ -3248,7 +3293,8 @@ function emitTable(block2, resources = /* @__PURE__ */ new Map()) {
3248
3293
  },
3249
3294
  layout: block2.layout === "fixed" ? TableLayoutType.FIXED : TableLayoutType.AUTOFIT,
3250
3295
  // An empty grid is a table with nothing to say about its columns, which is
3251
- // not the same as one whose columns are all zero wide.
3296
+ // not the same as one whose columns are all zero wide. The compiler hands
3297
+ // over every grid in twips, the unit `columnWidths` takes.
3252
3298
  ...block2.columnGrid.values.length > 0 ? { columnWidths: block2.columnGrid.values } : {},
3253
3299
  ...block2.borders ? {
3254
3300
  borders: {
@@ -3342,7 +3388,10 @@ function emitTableCell(cell, resources) {
3342
3388
  function emitBorder(border3) {
3343
3389
  if (!border3) return void 0;
3344
3390
  return {
3345
- style: BORDER_STYLE[border3.style] ?? BorderStyle.SINGLE,
3391
+ // Already OOXML's word, and docx.js's `BorderStyle` values are exactly
3392
+ // those words. Mapping unknown ones to `single` here is what once hid an
3393
+ // authoring word the IR should never have carried.
3394
+ style: border3.style,
3346
3395
  size: border3.sizeEighthPoints ?? 0,
3347
3396
  color: border3.color?.hex ?? "000000",
3348
3397
  // Stated only when the IR states it, so every border that predates the
@@ -3351,7 +3400,7 @@ function emitBorder(border3) {
3351
3400
  ...border3.spacePoints !== void 0 ? { space: border3.spacePoints } : {}
3352
3401
  };
3353
3402
  }
3354
- var ALIGNMENT2, PAGE_FIELDS, isSequenceField, WRAP_TYPE, ThemedTableOfContents, VERTICAL_ALIGN, TABLE_ANCHOR, HORIZONTAL_POSITION, VERTICAL_POSITION, BORDER_STYLE;
3403
+ var ALIGNMENT2, PAGE_FIELDS, isSequenceField, WRAP_TYPE, ThemedTableOfContents, VERTICAL_ALIGN, TABLE_ANCHOR, HORIZONTAL_POSITION, VERTICAL_POSITION;
3355
3404
  var init_emit = __esm({
3356
3405
  "src/renderers/docxjs/emit.ts"() {
3357
3406
  "use strict";
@@ -3400,20 +3449,10 @@ var init_emit = __esm({
3400
3449
  inside: RelativeVerticalPosition.INSIDE,
3401
3450
  outside: RelativeVerticalPosition.OUTSIDE
3402
3451
  };
3403
- BORDER_STYLE = {
3404
- none: BorderStyle.NONE,
3405
- single: BorderStyle.SINGLE,
3406
- double: BorderStyle.DOUBLE,
3407
- dashed: BorderStyle.DASHED,
3408
- dotted: BorderStyle.DOTTED
3409
- };
3410
3452
  }
3411
3453
  });
3412
3454
 
3413
3455
  // src/renderers/docxjs/styles.ts
3414
- import {
3415
- BorderStyle as BorderStyle2
3416
- } from "docx";
3417
3456
  function runProperties(formatting) {
3418
3457
  const out = {};
3419
3458
  if (formatting.fontFamily !== void 0) out.font = formatting.fontFamily;
@@ -3422,7 +3461,7 @@ function runProperties(formatting) {
3422
3461
  }
3423
3462
  if (formatting.color) out.color = formatting.color.hex;
3424
3463
  if (formatting.bold !== void 0) out.bold = formatting.bold;
3425
- if (formatting.italic !== void 0) out.italic = formatting.italic;
3464
+ if (formatting.italic !== void 0) out.italics = formatting.italic;
3426
3465
  if (formatting.underline) {
3427
3466
  out.underline = {
3428
3467
  type: formatting.underline.type,
@@ -3434,7 +3473,9 @@ function runProperties(formatting) {
3434
3473
  if (formatting.subScript) out.subScript = true;
3435
3474
  if (formatting.smallCaps !== void 0) out.smallCaps = formatting.smallCaps;
3436
3475
  if (formatting.allCaps !== void 0) out.allCaps = formatting.allCaps;
3437
- if (formatting.highlight !== void 0) out.highlight = formatting.highlight;
3476
+ if (formatting.highlight !== void 0) {
3477
+ out.highlight = formatting.highlight;
3478
+ }
3438
3479
  if (formatting.characterSpacingTwentieths !== void 0) {
3439
3480
  out.characterSpacing = formatting.characterSpacingTwentieths;
3440
3481
  }
@@ -3448,7 +3489,10 @@ function runProperties(formatting) {
3448
3489
  }
3449
3490
  function border(value) {
3450
3491
  return {
3451
- style: BORDER_STYLE2[value.style] ?? BorderStyle2.SINGLE,
3492
+ // OOXML's word, which is what docx.js's `BorderStyle` values are. A theme
3493
+ // may state any of them; mapping the unlisted ones to `single` drew a
3494
+ // `wave` or `triple` rule as a plain line here and as asked on office-open.
3495
+ style: value.style,
3452
3496
  ...value.sizeEighthPoints !== void 0 ? { size: value.sizeEighthPoints } : {},
3453
3497
  ...value.color ? { color: value.color.hex } : {},
3454
3498
  ...value.spacePoints !== void 0 ? { space: value.spacePoints } : {}
@@ -3561,19 +3605,10 @@ function emitStyles(styles) {
3561
3605
  }
3562
3606
  };
3563
3607
  }
3564
- var BORDER_STYLE2;
3565
3608
  var init_styles2 = __esm({
3566
3609
  "src/renderers/docxjs/styles.ts"() {
3567
3610
  "use strict";
3568
3611
  init_emit();
3569
- BORDER_STYLE2 = {
3570
- none: BorderStyle2.NONE,
3571
- single: BorderStyle2.SINGLE,
3572
- double: BorderStyle2.DOUBLE,
3573
- dashed: BorderStyle2.DASHED,
3574
- dotted: BorderStyle2.DOTTED,
3575
- thick: BorderStyle2.THICK
3576
- };
3577
3612
  }
3578
3613
  });
3579
3614
 
@@ -3752,7 +3787,7 @@ import {
3752
3787
  Header,
3753
3788
  ImageRun,
3754
3789
  Packer,
3755
- LineRuleType as LineRuleType2,
3790
+ LineRuleType,
3756
3791
  Paragraph as Paragraph2
3757
3792
  } from "docx";
3758
3793
  function createDocxJsRenderer() {
@@ -4039,7 +4074,7 @@ function lastBlockIsFrame(section2) {
4039
4074
  function anchorParagraph(anchor) {
4040
4075
  return new Paragraph2({
4041
4076
  children: anchor ? [anchor] : [],
4042
- spacing: { before: 0, after: 0, line: 20, lineRule: LineRuleType2.EXACT }
4077
+ spacing: { before: 0, after: 0, line: 20, lineRule: LineRuleType.EXACT }
4043
4078
  });
4044
4079
  }
4045
4080
  function coreProperties(ir) {
@@ -4232,10 +4267,17 @@ function runProperties2(formatting) {
4232
4267
  if (formatting.fontFamily) out.font = formatting.fontFamily;
4233
4268
  if (formatting.sizeHalfPoints !== void 0) {
4234
4269
  out.size = formatting.sizeHalfPoints / 2;
4270
+ if (formatting.sizeHalfPoints) out.sizeComplexScript = out.size;
4235
4271
  }
4236
4272
  if (formatting.color) out.color = formatting.color.hex;
4237
- if (formatting.bold !== void 0) out.bold = formatting.bold;
4238
- if (formatting.italic !== void 0) out.italic = formatting.italic;
4273
+ if (formatting.bold !== void 0) {
4274
+ out.bold = formatting.bold;
4275
+ out.boldComplexScript = formatting.bold;
4276
+ }
4277
+ if (formatting.italic !== void 0) {
4278
+ out.italic = formatting.italic;
4279
+ out.italicComplexScript = formatting.italic;
4280
+ }
4239
4281
  if (formatting.underline) {
4240
4282
  out.underline = {
4241
4283
  type: formatting.underline.type,
@@ -4791,10 +4833,9 @@ function table(value, ctx) {
4791
4833
  },
4792
4834
  layout: value.layout,
4793
4835
  // An empty grid is a table with nothing to say about its columns, which is
4794
- // not the same as one whose columns are all zero wide.
4795
- ...value.columnGrid.values.length > 0 ? {
4796
- columnWidths: value.columnGrid.unit === "twips" ? value.columnGrid.values.map(Math.floor) : value.columnGrid.values
4797
- } : {},
4836
+ // not the same as one whose columns are all zero wide. The compiler hands
4837
+ // over every grid in twips; floored for the same reason as the width.
4838
+ ...value.columnGrid.values.length > 0 ? { columnWidths: value.columnGrid.values.map(Math.floor) } : {},
4798
4839
  ...value.alignment ? { alignment: alignment(value.alignment) } : {},
4799
4840
  ...value.borders ? { borders: borders2(value.borders) } : {},
4800
4841
  ...value.cellMargins ? { margins: cellMargins(value.cellMargins) } : {},
@@ -4928,7 +4969,13 @@ function section(value, ctx, closesDocument = false) {
4928
4969
  }))
4929
4970
  } : {}
4930
4971
  }
4931
- } : {}
4972
+ } : {},
4973
+ // No document grid, as the IR states none. Left to the backend, every
4974
+ // section gets the one Word's Chinese template sets — a 15.6pt line grid
4975
+ // (`w:type="lines"`, pitch 312) — and every line is laid out on it here
4976
+ // but at its own height on docx.js, which writes no grid type. A field
4977
+ // the backend is not given takes that default, so all three are stated.
4978
+ grid: { type: "default", linePitch: 360, charSpace: 0 }
4932
4979
  },
4933
4980
  children: sectionChildren2(value, ctx, closesDocument),
4934
4981
  ...value.headers ? { headers: headerFooterSet(value.headers, ctx) } : {},
@@ -5013,12 +5060,11 @@ function builtIn2(style) {
5013
5060
  };
5014
5061
  }
5015
5062
  function emitStyles2(styles) {
5016
- const documentDefaults = {
5017
- ...Object.keys(styles.defaults.run).length > 0 ? { run: runProperties2(styles.defaults.run) } : {},
5018
- ...Object.keys(styles.defaults.paragraph).length > 0 ? { paragraph: paragraphProperties2(styles.defaults.paragraph) } : {}
5019
- };
5020
5063
  const defaults = {
5021
- ...Object.keys(documentDefaults).length > 0 ? { document: documentDefaults } : {}
5064
+ document: {
5065
+ run: Object.keys(styles.defaults.run).length > 0 ? runProperties2(styles.defaults.run) : null,
5066
+ paragraph: Object.keys(styles.defaults.paragraph).length > 0 ? paragraphProperties2(styles.defaults.paragraph) : null
5067
+ }
5022
5068
  };
5023
5069
  for (const slot of [
5024
5070
  "footnoteText",
@@ -5047,7 +5093,7 @@ function emitStyles2(styles) {
5047
5093
  run: runProperties2(style.run)
5048
5094
  }))
5049
5095
  } : {},
5050
- ...Object.keys(defaults).length > 0 ? { default: defaults } : {}
5096
+ default: defaults
5051
5097
  };
5052
5098
  }
5053
5099
  var init_styles3 = __esm({
@@ -6280,7 +6326,7 @@ import {
6280
6326
 
6281
6327
  // src/components/highcharts.ts
6282
6328
  init_colorUtils();
6283
- init_layoutUtils();
6329
+ init_widthUtils();
6284
6330
  import {
6285
6331
  chartFamilyResolver,
6286
6332
  remoteExportNotice,
@@ -6391,8 +6437,7 @@ function placedWidthPt(config, theme) {
6391
6437
  const chart = config.options.chart;
6392
6438
  if (typeof width === "number") return width * POINTS_PER_PIXEL;
6393
6439
  if (typeof width === "string") {
6394
- const page = getPageSetup(theme);
6395
- const contentWidthPt = (page.size.width - page.margin.left - page.margin.right) * POINTS_PER_TWIP;
6440
+ const contentWidthPt = getAvailableWidthTwips(theme) * POINTS_PER_TWIP;
6396
6441
  return parseFloat(width) / 100 * contentWidthPt;
6397
6442
  }
6398
6443
  if (typeof height === "number" && chart.height > 0) {
@@ -7156,6 +7201,7 @@ function resolveColors(entries, at, deps) {
7156
7201
 
7157
7202
  // src/styles/themeToStyles.ts
7158
7203
  init_themes();
7204
+ init_types();
7159
7205
  init_colorUtils();
7160
7206
  init_styleHelpers();
7161
7207
  import {
@@ -7322,10 +7368,13 @@ function convertParagraphProperties(merged, styleProps, theme) {
7322
7368
  }
7323
7369
  };
7324
7370
  }
7371
+ function themeBorderStyle(style) {
7372
+ return DOCX_IR_BORDER_STYLES.includes(style) ? style : "single";
7373
+ }
7325
7374
  function convertBorders(borders3, theme) {
7326
7375
  if (!borders3) return void 0;
7327
7376
  const mapSide = (side) => side ? {
7328
- style: side.style,
7377
+ style: themeBorderStyle(side.style),
7329
7378
  sizeEighthPoints: side.size,
7330
7379
  color: { hex: resolveColor(side.color, theme) },
7331
7380
  ...side.space !== void 0 ? { spacePoints: side.space } : {}
@@ -8512,7 +8561,11 @@ function resolveTableModel(source, theme, themeName, options = {}) {
8512
8561
  });
8513
8562
  adjudicateInteriorEdges([...hasHeader ? [header] : [], ...rows]);
8514
8563
  return {
8515
- ...resolveWidths(source, columns, theme, themeName),
8564
+ ...resolveWidths(
8565
+ source,
8566
+ columns,
8567
+ options.measureTwips ?? getAvailableWidthTwips(theme, themeName)
8568
+ ),
8516
8569
  ...hasHeader ? { header } : {},
8517
8570
  rows,
8518
8571
  repeatHeader: source.repeatHeaderOnPageBreak ?? true
@@ -8566,22 +8619,24 @@ function adjudicateInteriorEdges(rows) {
8566
8619
  });
8567
8620
  });
8568
8621
  }
8569
- function resolveWidths(source, columns, theme, themeName) {
8622
+ function resolveWidths(source, columns, measureTwips) {
8570
8623
  const hasExplicitWidths = columns.some((col) => col.width !== void 0);
8571
8624
  if (!hasExplicitWidths) {
8572
- const share = 100 / columns.length;
8625
+ const percent = source.width ?? 100;
8573
8626
  return {
8574
- columnGrid: { unit: "percent", values: columns.map(() => share) },
8575
- width: { size: source.width ?? 100, unit: "percent" }
8627
+ columnGrid: {
8628
+ unit: "twips",
8629
+ values: splitTwips(columns.length, measureTwips * percent / 100)
8630
+ },
8631
+ width: { size: percent, unit: "percent" }
8576
8632
  };
8577
8633
  }
8578
- const available = getAvailableWidthTwips(theme, themeName);
8579
8634
  const stated = columns.map(
8580
- (col) => col.width !== void 0 ? relativeLengthToTwips(col.width, available) : void 0
8635
+ (col) => col.width !== void 0 ? relativeLengthToTwips(col.width, measureTwips) : void 0
8581
8636
  );
8582
8637
  const totalStated = stated.reduce((sum, w) => sum + (w ?? 0), 0);
8583
8638
  const unstatedCount = columns.filter((col) => col.width === void 0).length;
8584
- const remaining = Math.max(0, available - totalStated);
8639
+ const remaining = Math.max(0, measureTwips - totalStated);
8585
8640
  const shareOfRemainder = unstatedCount > 0 ? remaining / unstatedCount : pointsToTwips(72);
8586
8641
  const values = stated.map((w) => w || shareOfRemainder);
8587
8642
  return {
@@ -8590,7 +8645,7 @@ function resolveWidths(source, columns, theme, themeName) {
8590
8645
  size: values.reduce((sum, w) => sum + w, 0),
8591
8646
  unit: "twips"
8592
8647
  },
8593
- ...totalStated > available ? { overflow: { totalTwips: totalStated, availableTwips: available } } : {}
8648
+ ...totalStated > measureTwips ? { overflow: { totalTwips: totalStated, availableTwips: measureTwips } } : {}
8594
8649
  };
8595
8650
  }
8596
8651
 
@@ -9306,6 +9361,36 @@ function emptyToUndefined(formatting) {
9306
9361
 
9307
9362
  // src/ir/compiler.ts
9308
9363
  init_types();
9364
+
9365
+ // src/ir/measure.ts
9366
+ var DEFAULT_COLUMN_SPACE_TWIPS = 720;
9367
+ function textWidthTwips(page) {
9368
+ const { leftTwips, rightTwips, gutterTwips = 0 } = page.margins;
9369
+ return Math.max(0, page.widthTwips - leftTwips - rightTwips - gutterTwips);
9370
+ }
9371
+ function sectionMeasureTwips(properties) {
9372
+ const textWidth = textWidthTwips(properties.page);
9373
+ const columns = properties.columns;
9374
+ if (!columns || columns.count <= 1) return textWidth;
9375
+ if (columns.equalWidth !== true && columns.widths?.length) {
9376
+ return Math.min(...columns.widths.map((column) => column.widthTwips));
9377
+ }
9378
+ const space = columns.spaceTwips ?? DEFAULT_COLUMN_SPACE_TWIPS;
9379
+ return Math.max(0, (textWidth - space * (columns.count - 1)) / columns.count);
9380
+ }
9381
+ function cellMeasureTwips(widthTwips, margins) {
9382
+ return Math.max(
9383
+ 0,
9384
+ widthTwips - (margins?.leftTwips ?? 0) - (margins?.rightTwips ?? 0)
9385
+ );
9386
+ }
9387
+ function tableWidthTwips(width, measureTwips) {
9388
+ if (width.kind === "twips") return width.value;
9389
+ if (width.kind === "percent") return measureTwips * width.value / 100;
9390
+ return measureTwips;
9391
+ }
9392
+
9393
+ // src/ir/compiler.ts
9309
9394
  init_units();
9310
9395
  var CONTENT_BOOKMARK_ID_BASE = 2e6;
9311
9396
  var SINGLE_LINE_TWIPS = 240;
@@ -9506,6 +9591,42 @@ function compileSectionBody(section2, index, ordinal, chrome, ctx) {
9506
9591
  if (column && column.count > 1) {
9507
9592
  ctx.features.require("columns", `${path3}.properties.columns`);
9508
9593
  }
9594
+ const properties = {
9595
+ page: {
9596
+ widthTwips: page.size.width,
9597
+ heightTwips: page.size.height,
9598
+ orientation: page.size.width > page.size.height ? "landscape" : "portrait",
9599
+ ...page.size.code !== void 0 ? { code: page.size.code } : {},
9600
+ margins: {
9601
+ topTwips: page.margin.top,
9602
+ bottomTwips: page.margin.bottom,
9603
+ leftTwips: page.margin.left,
9604
+ rightTwips: page.margin.right,
9605
+ ...page.margin.header !== void 0 ? { headerTwips: page.margin.header } : {},
9606
+ ...page.margin.footer !== void 0 ? { footerTwips: page.margin.footer } : {},
9607
+ ...page.margin.gutter !== void 0 ? { gutterTwips: page.margin.gutter } : {}
9608
+ }
9609
+ },
9610
+ // A chunk that starts on a new page says so; the rest continue the flow.
9611
+ // The layout stage already decided which, so it is carried rather than
9612
+ // re-derived from `breakBefore`: a section can be continuous without the
9613
+ // two agreeing.
9614
+ ...section2.properties.type ? { type: sectionType(section2.properties.type) } : {},
9615
+ ...column ? {
9616
+ columns: {
9617
+ count: column.count,
9618
+ ...column.space !== void 0 ? { spaceTwips: column.space } : {},
9619
+ ...column.equalWidth !== void 0 ? { equalWidth: column.equalWidth } : {},
9620
+ ...column.widths ? {
9621
+ widths: column.widths.map((c) => ({
9622
+ widthTwips: c.width,
9623
+ ...c.space !== void 0 ? { spaceTwips: c.space } : {}
9624
+ }))
9625
+ } : {}
9626
+ }
9627
+ } : {}
9628
+ };
9629
+ const measureTwips = sectionMeasureTwips(properties);
9509
9630
  const children = [];
9510
9631
  const sectionBookmarkName = section2.belongsToUserSection && ordinal.ordinal !== void 0 ? `_Section_${ordinal.ordinal}` : void 0;
9511
9632
  section2.components.forEach((component, i) => {
@@ -9515,6 +9636,7 @@ function compileSectionBody(section2, index, ordinal, chrome, ctx) {
9515
9636
  ctx,
9516
9637
  path: `${path3}.children[${i}]`,
9517
9638
  id: blockId(index, [i]),
9639
+ measureTwips,
9518
9640
  ...sectionBookmarkName ? { sectionBookmarkName } : {}
9519
9641
  })
9520
9642
  );
@@ -9527,41 +9649,7 @@ function compileSectionBody(section2, index, ordinal, chrome, ctx) {
9527
9649
  id: `s${index}`,
9528
9650
  path: path3,
9529
9651
  children,
9530
- properties: {
9531
- page: {
9532
- widthTwips: page.size.width,
9533
- heightTwips: page.size.height,
9534
- orientation: page.size.width > page.size.height ? "landscape" : "portrait",
9535
- ...page.size.code !== void 0 ? { code: page.size.code } : {},
9536
- margins: {
9537
- topTwips: page.margin.top,
9538
- bottomTwips: page.margin.bottom,
9539
- leftTwips: page.margin.left,
9540
- rightTwips: page.margin.right,
9541
- ...page.margin.header !== void 0 ? { headerTwips: page.margin.header } : {},
9542
- ...page.margin.footer !== void 0 ? { footerTwips: page.margin.footer } : {},
9543
- ...page.margin.gutter !== void 0 ? { gutterTwips: page.margin.gutter } : {}
9544
- }
9545
- },
9546
- // A chunk that starts on a new page says so; the rest continue the flow.
9547
- // The layout stage already decided which, so it is carried rather than
9548
- // re-derived from `breakBefore`: a section can be continuous without the
9549
- // two agreeing.
9550
- ...section2.properties.type ? { type: sectionType(section2.properties.type) } : {},
9551
- ...column ? {
9552
- columns: {
9553
- count: column.count,
9554
- ...column.space !== void 0 ? { spaceTwips: column.space } : {},
9555
- ...column.equalWidth !== void 0 ? { equalWidth: column.equalWidth } : {},
9556
- ...column.widths ? {
9557
- widths: column.widths.map((c) => ({
9558
- widthTwips: c.width,
9559
- ...c.space !== void 0 ? { spaceTwips: c.space } : {}
9560
- }))
9561
- } : {}
9562
- }
9563
- } : {}
9564
- }
9652
+ properties
9565
9653
  };
9566
9654
  if (ordinal.ordinal !== void 0) {
9567
9655
  compiled.bookmark = {
@@ -9572,9 +9660,22 @@ function compileSectionBody(section2, index, ordinal, chrome, ctx) {
9572
9660
  };
9573
9661
  ctx.features.require("bookmarks", `${path3}.bookmark`);
9574
9662
  }
9575
- const headers = compilePart(chrome.header, "header", index, ctx);
9663
+ const chromeMeasureTwips = textWidthTwips(properties.page);
9664
+ const headers = compilePart(
9665
+ chrome.header,
9666
+ "header",
9667
+ index,
9668
+ chromeMeasureTwips,
9669
+ ctx
9670
+ );
9576
9671
  if (headers) compiled.headers = { default: headers };
9577
- const footers = compilePart(chrome.footer, "footer", index, ctx);
9672
+ const footers = compilePart(
9673
+ chrome.footer,
9674
+ "footer",
9675
+ index,
9676
+ chromeMeasureTwips,
9677
+ ctx
9678
+ );
9578
9679
  if (footers) compiled.footers = { default: footers };
9579
9680
  if (headers || footers) {
9580
9681
  ctx.features.require("headers-footers", `${path3}.headers`);
@@ -9593,7 +9694,7 @@ function sectionType(value) {
9593
9694
  return void 0;
9594
9695
  }
9595
9696
  }
9596
- function compilePart(part, kind, sectionIndex, ctx) {
9697
+ function compilePart(part, kind, sectionIndex, measureTwips, ctx) {
9597
9698
  if (!part) return void 0;
9598
9699
  const id = `${kind}:s${sectionIndex}:default`;
9599
9700
  const children = [];
@@ -9604,7 +9705,8 @@ function compilePart(part, kind, sectionIndex, ctx) {
9604
9705
  const scope = {
9605
9706
  ctx,
9606
9707
  path: `sections[${sectionIndex}].${kind}s.default.children[${i}]`,
9607
- id: headerFooterBlockId(id, [i])
9708
+ id: headerFooterBlockId(id, [i]),
9709
+ measureTwips
9608
9710
  };
9609
9711
  children.push(
9610
9712
  ...component.name === "paragraph" ? compileChromeParagraph(component, scope) : component.name === "image" ? compileChromeImage(component, scope) : compileComponent(component, scope)
@@ -9680,9 +9782,7 @@ function compileChromeImage(component, scope) {
9680
9782
  if (mediaType === "svg") ctx.features.require("svg-images", path3);
9681
9783
  const page = getPageSetup(ctx.theme);
9682
9784
  const pageWidthPx = Math.round(twipsToPixels(page.size.width));
9683
- const contentWidthPx = Math.round(
9684
- twipsToPixels(page.size.width - page.margin.left - page.margin.right)
9685
- );
9785
+ const contentWidthPx = Math.round(twipsToPixels(scope.measureTwips));
9686
9786
  const pageHeightPx = Math.round(twipsToPixels(page.size.height));
9687
9787
  const contentHeightPx = Math.round(
9688
9788
  twipsToPixels(page.size.height - page.margin.top - page.margin.bottom)
@@ -9890,7 +9990,7 @@ function compileColumns(component, scope) {
9890
9990
  const props = component.props ?? {};
9891
9991
  const configs = columnConfigs(props.columns);
9892
9992
  if (configs.length === 0) return [];
9893
- const available = getAvailableWidthTwips(ctx.theme, ctx.themeName);
9993
+ const available = scope.measureTwips;
9894
9994
  const { widths, gaps } = columnMetrics(configs, props.gap, available);
9895
9995
  const stated = widths.map(
9896
9996
  (width, index) => width + gaps[index] / 2 + (index > 0 ? gaps[index - 1] / 2 : 0)
@@ -9919,11 +10019,18 @@ function compileColumns(component, scope) {
9919
10019
  rows: [
9920
10020
  {
9921
10021
  cells: configs.map((_, index) => {
10022
+ const margins = {
10023
+ topTwips: 0,
10024
+ rightTwips: gaps[index] / 2,
10025
+ bottomTwips: 0,
10026
+ leftTwips: index > 0 ? gaps[index - 1] / 2 : 0
10027
+ };
9922
10028
  const blocks = contents[index].flatMap(
9923
10029
  (child, childIndex) => compileComponent(child, {
9924
10030
  ...scope,
9925
10031
  path: `${path3}.children[${index}][${childIndex}]`,
9926
- id: `${scope.id}:c${index}:${childIndex}`
10032
+ id: `${scope.id}:c${index}:${childIndex}`,
10033
+ measureTwips: cellMeasureTwips(cells[index], margins)
9927
10034
  })
9928
10035
  );
9929
10036
  return {
@@ -9938,12 +10045,7 @@ function compileColumns(component, scope) {
9938
10045
  }
9939
10046
  ],
9940
10047
  widthTwips: cells[index],
9941
- margins: {
9942
- topTwips: 0,
9943
- rightTwips: gaps[index] / 2,
9944
- bottomTwips: 0,
9945
- leftTwips: index > 0 ? gaps[index - 1] / 2 : 0
9946
- },
10048
+ margins,
9947
10049
  verticalAlign: "top",
9948
10050
  borders: {
9949
10051
  top: NO_BORDERS.top,
@@ -10000,6 +10102,16 @@ var DEFAULT_TEXT_BOX_WIDTH_TWIPS = 5e3;
10000
10102
  function compileTextBox(component, scope) {
10001
10103
  const { ctx, path: path3 } = scope;
10002
10104
  const props = component.props ?? {};
10105
+ const style = props.style;
10106
+ const padding = style?.padding;
10107
+ const width = textBoxWidth(props);
10108
+ const widthTwips = Math.round(tableWidthTwips(width, scope.measureTwips));
10109
+ const margins = {
10110
+ topTwips: padding?.top ? pointsToTwips2(padding.top) : 0,
10111
+ rightTwips: padding?.right ? pointsToTwips2(padding.right) : 0,
10112
+ bottomTwips: padding?.bottom ? pointsToTwips2(padding.bottom) : 0,
10113
+ leftTwips: padding?.left ? pointsToTwips2(padding.left) : 0
10114
+ };
10003
10115
  const children = [];
10004
10116
  const contents = component.children ?? [];
10005
10117
  contents.forEach((child, index) => {
@@ -10007,12 +10119,12 @@ function compileTextBox(component, scope) {
10007
10119
  ...compileComponent(child, {
10008
10120
  ...scope,
10009
10121
  path: `${path3}.children[${index}]`,
10010
- id: `${scope.id}:c${index}`
10122
+ id: `${scope.id}:c${index}`,
10123
+ // What the box holds is set against the box less its padding.
10124
+ measureTwips: cellMeasureTwips(widthTwips, margins)
10011
10125
  })
10012
10126
  );
10013
10127
  });
10014
- const style = props.style;
10015
- const padding = style?.padding;
10016
10128
  if (props.renderAs === "shape") {
10017
10129
  const shape = compileShape2(props, children, scope);
10018
10130
  if (shape) return shape;
@@ -10024,9 +10136,11 @@ function compileTextBox(component, scope) {
10024
10136
  kind: "table",
10025
10137
  id: scope.id,
10026
10138
  path: path3,
10027
- // No grid: one cell, whose width the table itself decides.
10028
- columnGrid: { unit: "twips", values: [] },
10029
- width: textBoxWidth(props),
10139
+ // One cell, as wide as the box. Left out, the grid would be each
10140
+ // backend's 100-twip placeholder, which a reader that takes the grid as
10141
+ // the column widths draws.
10142
+ columnGrid: { unit: "twips", values: [widthTwips] },
10143
+ width,
10030
10144
  layout: "fixed",
10031
10145
  // The container is invisible; whatever border the author asked for is
10032
10146
  // drawn by the cell inside it.
@@ -10046,12 +10160,7 @@ function compileTextBox(component, scope) {
10046
10160
  children: []
10047
10161
  }
10048
10162
  ],
10049
- margins: {
10050
- topTwips: padding?.top ? pointsToTwips2(padding.top) : 0,
10051
- rightTwips: padding?.right ? pointsToTwips2(padding.right) : 0,
10052
- bottomTwips: padding?.bottom ? pointsToTwips2(padding.bottom) : 0,
10053
- leftTwips: padding?.left ? pointsToTwips2(padding.left) : 0
10054
- },
10163
+ margins,
10055
10164
  ...style?.shading?.fill ? {
10056
10165
  shading: {
10057
10166
  fill: irColor(
@@ -10070,8 +10179,11 @@ function compileTextBox(component, scope) {
10070
10179
  var EMU_PER_PIXEL = 9525;
10071
10180
  function compileShape2(props, children, scope) {
10072
10181
  const { ctx, path: path3 } = scope;
10073
- const width = shapeSize(props.width, "width", ctx);
10074
- const height = shapeSize(props.height, "height", ctx);
10182
+ const width = shapeSize(props.width, scope.measureTwips);
10183
+ const height = shapeSize(
10184
+ props.height,
10185
+ getAvailableHeightTwips(ctx.theme, ctx.themeName)
10186
+ );
10075
10187
  if (width.pixels === void 0 || height.pixels === void 0) {
10076
10188
  warnOnce(
10077
10189
  ctx,
@@ -10102,7 +10214,7 @@ function compileShape2(props, children, scope) {
10102
10214
  warnOnce(
10103
10215
  ctx,
10104
10216
  "text-box",
10105
- '[core-docx] text-box renderAs "shape" resolves percentage sizes at generation time, against the current page content box; the shape will not reflow if the page size changes.'
10217
+ '[core-docx] text-box renderAs "shape" resolves percentage sizes at generation time \u2014 a width against what holds it, a height against the page \u2014 so the shape will not reflow if either changes.'
10106
10218
  );
10107
10219
  }
10108
10220
  if (outline.ignoredSides.length > 0) {
@@ -10147,7 +10259,7 @@ function compileShape2(props, children, scope) {
10147
10259
  }
10148
10260
  ];
10149
10261
  }
10150
- function shapeSize(value, axis, ctx) {
10262
+ function shapeSize(value, referenceTwips) {
10151
10263
  if (typeof value === "number") {
10152
10264
  return { pixels: Math.round(value), resolvedPercentage: false };
10153
10265
  }
@@ -10156,9 +10268,8 @@ function shapeSize(value, axis, ctx) {
10156
10268
  if (!Number.isFinite(fraction) || fraction <= 0) {
10157
10269
  return { resolvedPercentage: false };
10158
10270
  }
10159
- const availableTwips = axis === "width" ? getAvailableWidthTwips(ctx.theme, ctx.themeName) : getAvailableHeightTwips(ctx.theme, ctx.themeName);
10160
10271
  return {
10161
- pixels: Math.round(availableTwips * fraction / TWIPS_PER_PIXEL),
10272
+ pixels: Math.round(referenceTwips * fraction / TWIPS_PER_PIXEL),
10162
10273
  resolvedPercentage: true
10163
10274
  };
10164
10275
  }
@@ -10233,10 +10344,20 @@ function textBoxWidth(props) {
10233
10344
  value: typeof raw === "number" ? raw * TWIPS_PER_PIXEL : DEFAULT_TEXT_BOX_WIDTH_TWIPS
10234
10345
  };
10235
10346
  }
10347
+ function borderLineStyle(authored) {
10348
+ switch (authored) {
10349
+ case "dashed":
10350
+ case "dotted":
10351
+ case "double":
10352
+ return authored;
10353
+ default:
10354
+ return "single";
10355
+ }
10356
+ }
10236
10357
  function compileBorders(border3, ctx) {
10237
10358
  if (!border3) return void 0;
10238
10359
  const side = (value) => value ? {
10239
- style: String(value.style ?? "single"),
10360
+ style: value.style === "none" ? "none" : borderLineStyle(value.style),
10240
10361
  // Points to eighths of a point, never thinner than the hairline a
10241
10362
  // reader can actually see.
10242
10363
  sizeEighthPoints: value.width !== void 0 ? Math.max(1, Math.round(value.width * 8)) : 1,
@@ -10340,12 +10461,6 @@ function compileToc(component, scope) {
10340
10461
  var DEFAULT_DIVIDER_SPACING_PT = 6;
10341
10462
  var DEFAULT_DIVIDER_THICKNESS_PT = 1;
10342
10463
  var DIVIDER_LINE_TWIPS = 20;
10343
- var DIVIDER_BORDER_STYLE = {
10344
- solid: "single",
10345
- dashed: "dashed",
10346
- dotted: "dotted",
10347
- double: "double"
10348
- };
10349
10464
  function compileDivider(component, scope) {
10350
10465
  const { ctx, path: path3 } = scope;
10351
10466
  const props = component.props ?? {};
@@ -10374,10 +10489,10 @@ function compileDivider(component, scope) {
10374
10489
  lineTwips: DIVIDER_LINE_TWIPS,
10375
10490
  lineRule: "exact"
10376
10491
  },
10377
- ...dividerIndent(props, ctx, path3),
10492
+ ...dividerIndent(props, scope),
10378
10493
  borders: {
10379
10494
  bottom: {
10380
- style: DIVIDER_BORDER_STYLE[String(props.style)] ?? "single",
10495
+ style: borderLineStyle(props.style),
10381
10496
  sizeEighthPoints: pointsToEighthPoints(thicknessPt),
10382
10497
  color: irColor(
10383
10498
  resolveColor(String(props.color ?? "border"), ctx.theme)
@@ -10391,14 +10506,10 @@ function compileDivider(component, scope) {
10391
10506
  }
10392
10507
  ];
10393
10508
  }
10394
- function dividerIndent(props, ctx, path3) {
10509
+ function dividerIndent(props, scope) {
10510
+ const { ctx, path: path3, measureTwips } = scope;
10395
10511
  const width = props.width;
10396
10512
  if (width === void 0) return {};
10397
- const page = getPageSetup(ctx.theme);
10398
- const measureTwips = Math.max(
10399
- 0,
10400
- page.size.width - page.margin.left - page.margin.right
10401
- );
10402
10513
  let usedTwips;
10403
10514
  if (typeof width === "number" && Number.isFinite(width)) {
10404
10515
  usedTwips = pointsToTwips2(width);
@@ -10554,7 +10665,7 @@ function compileList(component, scope, referencePrefix = "list", explicitLevels)
10554
10665
  }
10555
10666
  blocks.push(
10556
10667
  paragraphNode(
10557
- { ctx, path: itemPath, id: `${scope.id}:i${index}` },
10668
+ { ...scope, path: itemPath, id: `${scope.id}:i${index}` },
10558
10669
  revision === void 0 ? parseInline(text, {
10559
10670
  base,
10560
10671
  hyperlinks: true,
@@ -11201,7 +11312,7 @@ function compileVisual(component, scope) {
11201
11312
  );
11202
11313
  if (!group) return [];
11203
11314
  const size = visualPlacementPixels(props, group.canvas, {
11204
- widthPx: Math.round(twipsToPixels(getAvailableWidthTwips(ctx.theme))),
11315
+ widthPx: Math.round(twipsToPixels(scope.measureTwips)),
11205
11316
  heightPx: Math.round(twipsToPixels(getAvailableHeightTwips(ctx.theme)))
11206
11317
  });
11207
11318
  const drawing = {
@@ -11316,7 +11427,7 @@ function compileImage2(component, scope) {
11316
11427
  `Alt text is not written to the document: the DOCX pipeline has never emitted \`wp:docPr\` descriptions, so the image at ${path3} will have none. The text is preserved in the IR.`
11317
11428
  );
11318
11429
  }
11319
- const size = imagePixelSize(props, loaded, ctx);
11430
+ const size = imagePixelSize(props, loaded, scope);
11320
11431
  const resourceId = declareResource(loaded, mediaType, ctx);
11321
11432
  const image = {
11322
11433
  kind: "image",
@@ -11426,8 +11537,7 @@ function compileChart(component, scope) {
11426
11537
  return [];
11427
11538
  }
11428
11539
  });
11429
- const page = getPageSetup(ctx.theme);
11430
- const contentWidthInches = (page.size.width - page.margin.left - page.margin.right) / 1440;
11540
+ const contentWidthInches = scope.measureTwips / 1440;
11431
11541
  const widthInches = typeof props.width === "number" ? props.width : contentWidthInches;
11432
11542
  const heightInches = typeof props.height === "number" ? props.height : DEFAULT_CHART_HEIGHT_INCHES;
11433
11543
  const chart = {
@@ -11527,12 +11637,13 @@ function wrapType(value) {
11527
11637
  return "square";
11528
11638
  }
11529
11639
  }
11530
- function imagePixelSize(props, loaded, ctx) {
11640
+ function imagePixelSize(props, loaded, scope) {
11641
+ const { ctx } = scope;
11531
11642
  const widthRef = props.widthRelativeTo === "page" ? "page" : "content";
11532
11643
  const heightRef = props.heightRelativeTo === "page" ? "page" : "content";
11533
11644
  const availableWidthPx = Math.round(
11534
11645
  twipsToPixels(
11535
- widthRef === "page" ? getPageWidthTwips(ctx.theme) : getAvailableWidthTwips(ctx.theme)
11646
+ widthRef === "page" ? getPageWidthTwips(ctx.theme) : scope.measureTwips
11536
11647
  )
11537
11648
  );
11538
11649
  const availableHeightPx = Math.round(
@@ -11719,7 +11830,10 @@ function compileTable(component, scope) {
11719
11830
  source,
11720
11831
  ctx.theme,
11721
11832
  ctx.themeName,
11722
- { onWarning: (code, message) => warnOnce(ctx, "table", message, code) }
11833
+ {
11834
+ onWarning: (code, message) => warnOnce(ctx, "table", message, code),
11835
+ measureTwips: scope.measureTwips
11836
+ }
11723
11837
  );
11724
11838
  if (model.overflow) {
11725
11839
  warnOnce(
@@ -11737,6 +11851,7 @@ function compileTable(component, scope) {
11737
11851
  ...model.header ? [
11738
11852
  compileTableRow(
11739
11853
  model.header,
11854
+ model.columnGrid.values,
11740
11855
  style.headerParagraph,
11741
11856
  style.tableHeader,
11742
11857
  {
@@ -11749,13 +11864,19 @@ function compileTable(component, scope) {
11749
11864
  )
11750
11865
  ] : [],
11751
11866
  ...model.rows.map(
11752
- (row, index) => compileTableRow(row, style.cellParagraph, style.tableCell, {
11753
- ctx,
11754
- path: `${path3}.rows[${index}]`,
11755
- id: `${scope.id}:r${index}`,
11756
- ...row.tableHeader !== void 0 ? { isHeader: row.tableHeader } : {},
11757
- ...row.cantSplit !== void 0 ? { cantSplit: row.cantSplit } : {}
11758
- })
11867
+ (row, index) => compileTableRow(
11868
+ row,
11869
+ model.columnGrid.values,
11870
+ style.cellParagraph,
11871
+ style.tableCell,
11872
+ {
11873
+ ctx,
11874
+ path: `${path3}.rows[${index}]`,
11875
+ id: `${scope.id}:r${index}`,
11876
+ ...row.tableHeader !== void 0 ? { isHeader: row.tableHeader } : {},
11877
+ ...row.cantSplit !== void 0 ? { cantSplit: row.cantSplit } : {}
11878
+ }
11879
+ )
11759
11880
  )
11760
11881
  ];
11761
11882
  ctx.features.require("tables", path3);
@@ -11833,7 +11954,7 @@ function tableBlocker(model, path3) {
11833
11954
  }
11834
11955
  return void 0;
11835
11956
  }
11836
- function compileTableRow(row, spacing, baseStyle, scope) {
11957
+ function compileTableRow(row, columnTwips, spacing, baseStyle, scope) {
11837
11958
  const { ctx } = scope;
11838
11959
  const rowRevision = row.revision;
11839
11960
  const rowMark = rowRevision ? {
@@ -11853,6 +11974,7 @@ function compileTableRow(row, spacing, baseStyle, scope) {
11853
11974
  cells: row.cells.map(
11854
11975
  (cell, colIndex) => compileTableCell(
11855
11976
  cell,
11977
+ columnTwips[colIndex] ?? 0,
11856
11978
  spacing,
11857
11979
  baseStyle,
11858
11980
  row.keepNext,
@@ -11874,7 +11996,17 @@ function compileTableRow(row, spacing, baseStyle, scope) {
11874
11996
  ...scope.cantSplit !== void 0 ? { cantSplit: scope.cantSplit } : {}
11875
11997
  };
11876
11998
  }
11877
- function compileTableCell(cell, spacing, baseStyle, keepNext, scope, rowRevision, markRevision) {
11999
+ function compileTableCell(cell, columnTwips, spacing, baseStyle, keepNext, partScope, rowRevision, markRevision) {
12000
+ const margins = !cell.missing && cell.padding ? {
12001
+ topTwips: pointsToTwips2(cell.padding.top),
12002
+ bottomTwips: pointsToTwips2(cell.padding.bottom),
12003
+ leftTwips: pointsToTwips2(cell.padding.left),
12004
+ rightTwips: pointsToTwips2(cell.padding.right)
12005
+ } : void 0;
12006
+ const scope = {
12007
+ ...partScope,
12008
+ measureTwips: cellMeasureTwips(columnTwips, margins)
12009
+ };
11878
12010
  const cellLine = compileLineSpacing(cell.font?.lineSpacing);
11879
12011
  const paragraph2 = {
11880
12012
  kind: "paragraph",
@@ -11903,14 +12035,7 @@ function compileTableCell(cell, spacing, baseStyle, keepNext, scope, rowRevision
11903
12035
  ...cell.missing ? {} : {
11904
12036
  verticalAlign: verticalAlign(cell.verticalAlignment),
11905
12037
  ...cell.backgroundColor !== void 0 && cell.backgroundColor !== "transparent" ? { shading: { fill: { hex: cell.backgroundColor } } } : {},
11906
- ...cell.padding ? {
11907
- margins: {
11908
- topTwips: pointsToTwips2(cell.padding.top),
11909
- bottomTwips: pointsToTwips2(cell.padding.bottom),
11910
- leftTwips: pointsToTwips2(cell.padding.left),
11911
- rightTwips: pointsToTwips2(cell.padding.right)
11912
- }
11913
- } : {}
12038
+ ...margins ? { margins } : {}
11914
12039
  },
11915
12040
  borders: {
11916
12041
  top: compileTableBorder(cell.borders.top),
@@ -12933,9 +13058,10 @@ function docxBlockContext(document, theme, path3, sources) {
12933
13058
  page.size ?? theme.page.size
12934
13059
  );
12935
13060
  const overrides = isBlockRecord(page.margins) ? page.margins : {};
13061
+ const gutter = "gutter" in margins ? margins.gutter : 0;
12936
13062
  const width = Object.keys(page).length ? Math.max(
12937
13063
  0,
12938
- dimensions.width - Number(overrides.left ?? margins.left ?? 1440) - Number(overrides.right ?? margins.right ?? 1440)
13064
+ dimensions.width - Number(overrides.left ?? margins.left ?? 1440) - Number(overrides.right ?? margins.right ?? 1440) - Number(overrides.gutter ?? gutter ?? 0)
12939
13065
  ) : getAvailableWidthTwips(theme);
12940
13066
  const height = Object.keys(page).length ? Math.max(
12941
13067
  0,
@@ -13492,7 +13618,7 @@ function pageBox(theme, themeName, pageOverride) {
13492
13618
  return {
13493
13619
  availableWidthTwips: Math.max(
13494
13620
  0,
13495
- page.size.width - page.margin.left - page.margin.right
13621
+ page.size.width - page.margin.left - page.margin.right - (page.margin.gutter ?? 0)
13496
13622
  ),
13497
13623
  pageBottomTwips: page.size.height
13498
13624
  };