@json-to-office/core-docx 1.3.0 → 1.4.0

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 +1 @@
1
- {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/ir/compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAKhE,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAuC3D,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAuC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAEL,KAAK,MAAM,EAmCZ,MAAM,SAAS,CAAC;AAiBjB,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,QAAQ,EAAE,SAAS,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;IACrD,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B;;;;OAIG;IACH,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACrC;AAsFD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,UAAU,EAClB,QAAQ,GAAE,iBAAiB,EAAO,EAClC,MAAM,GAAE,cAA0B,EAClC,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,iBAAiB,CAmGnB"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/ir/compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAKhE,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AA6C3D,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAuC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAEL,KAAK,MAAM,EAoCZ,MAAM,SAAS,CAAC;AAiBjB,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,QAAQ,EAAE,SAAS,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;IACrD,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B;;;;OAIG;IACH,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACrC;AA8FD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,UAAU,EAClB,QAAQ,GAAE,iBAAiB,EAAO,EAClC,MAAM,GAAE,cAA0B,EAClC,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,iBAAiB,CAgHnB"}
@@ -355,8 +355,7 @@ var init_minimal_docx_theme = __esm({
355
355
  },
356
356
  list: {
357
357
  format: "bullet",
358
- bullet: "\u2022",
359
- indent: 3
358
+ bullet: "\u2022"
360
359
  },
361
360
  image: {
362
361
  alignment: "left"
@@ -480,8 +479,7 @@ var init_corporate_docx_theme = __esm({
480
479
  },
481
480
  list: {
482
481
  format: "bullet",
483
- bullet: "\u2022",
484
- indent: 3
482
+ bullet: "\u2022"
485
483
  },
486
484
  statistic: {
487
485
  alignment: "center"
@@ -594,8 +592,7 @@ var init_modern_docx_theme = __esm({
594
592
  },
595
593
  list: {
596
594
  format: "bullet",
597
- bullet: "\u2013",
598
- indent: 3
595
+ bullet: "\u2013"
599
596
  },
600
597
  image: {
601
598
  alignment: "center"
@@ -719,8 +716,7 @@ var init_apex_docx_theme = __esm({
719
716
  },
720
717
  list: {
721
718
  format: "bullet",
722
- bullet: "\u2022",
723
- indent: 3
719
+ bullet: "\u2022"
724
720
  },
725
721
  image: {
726
722
  alignment: "center"
@@ -852,8 +848,7 @@ var init_devportal_docx_theme = __esm({
852
848
  },
853
849
  list: {
854
850
  format: "bullet",
855
- bullet: "\u2013",
856
- indent: 3
851
+ bullet: "\u2013"
857
852
  },
858
853
  image: {
859
854
  alignment: "center"
@@ -2751,99 +2746,6 @@ var init_styles2 = __esm({
2751
2746
  }
2752
2747
  });
2753
2748
 
2754
- // src/ir/features.ts
2755
- var DOCX_FEATURES, ALL_DOCX_FEATURES;
2756
- var init_features = __esm({
2757
- "src/ir/features.ts"() {
2758
- "use strict";
2759
- DOCX_FEATURES = [
2760
- /** Paragraphs and text runs — the floor of the format. */
2761
- "paragraphs",
2762
- /** Named paragraph and character styles in `styles.xml`. */
2763
- "styles",
2764
- /** Numbering definitions and numbered paragraphs. */
2765
- "numbering",
2766
- /** Multiple sections with their own page setup. */
2767
- "sections",
2768
- /** Multi-column section layout. */
2769
- "columns",
2770
- /** Header and footer parts, including first/even variants. */
2771
- "headers-footers",
2772
- "tables",
2773
- /** Merged table cells — column span or vertical merge. */
2774
- "table-merged-cells",
2775
- /** A table positioned out of the text flow. */
2776
- "floating-tables",
2777
- /** Inline images. */
2778
- "images",
2779
- /** Anchored images with text wrapping. */
2780
- "floating-images",
2781
- /** SVG images with a raster fallback. */
2782
- "svg-images",
2783
- /** A paragraph positioned as a floating frame. */
2784
- "text-frames",
2785
- /** Native shape text boxes. */
2786
- "text-boxes",
2787
- /**
2788
- * A DrawingML group: shapes, text boxes and pictures sharing one child
2789
- * coordinate space, drawn as a single anchored or inline object.
2790
- *
2791
- * Separate from `text-boxes` because a lone `wps:wsp` run is a far smaller
2792
- * ask than `wpg:wgp` with child transforms, preset geometry and grouped
2793
- * pictures — a backend can plausibly have the first and not the second.
2794
- */
2795
- "drawing-groups",
2796
- /**
2797
- * A native chart part: a `c:chartSpace` with its own embedded workbook.
2798
- *
2799
- * Separate from `images` because a chart is not a picture with extra data —
2800
- * it is its own part, its own relationship and its own workbook, and a
2801
- * backend either writes all three or writes none. docx.js has no chart
2802
- * primitive at all, which is what turns a `chart` component sent to that
2803
- * backend into a named capability error rather than a document missing a
2804
- * figure.
2805
- */
2806
- "charts",
2807
- /** A table-of-contents field. */
2808
- "toc",
2809
- /** TOC entries baked in so an unrefreshed reader still shows them. */
2810
- "cached-toc",
2811
- /** Arbitrary Word fields, e.g. PAGE, NUMPAGES, REF. */
2812
- "fields",
2813
- /** Field results cached for readers that never refresh. */
2814
- "cached-fields",
2815
- "hyperlinks",
2816
- "bookmarks",
2817
- /** Links and REF fields that target a bookmark. */
2818
- "cross-references",
2819
- "comments",
2820
- /** Threaded and resolvable comments. */
2821
- "comment-threads",
2822
- "footnotes",
2823
- "endnotes",
2824
- /** Inserted and deleted content. */
2825
- "revisions",
2826
- /** Page, column and line breaks. */
2827
- "breaks",
2828
- /** Paragraph and table shading. */
2829
- "shading",
2830
- /** Paragraph, table and page borders. */
2831
- "borders",
2832
- /** Tab stops. */
2833
- "tab-stops",
2834
- /** Per-run proofing language and no-proof. */
2835
- "proofing-language",
2836
- /** Custom document properties. */
2837
- "custom-properties",
2838
- /** Right-to-left paragraph direction. */
2839
- "rtl"
2840
- ];
2841
- ALL_DOCX_FEATURES = new Set(
2842
- DOCX_FEATURES
2843
- );
2844
- }
2845
- });
2846
-
2847
2749
  // src/utils/packageDocument.ts
2848
2750
  import AdmZip from "adm-zip";
2849
2751
  function resolveGenerationDate(options) {
@@ -3251,37 +3153,47 @@ function coreProperties(ir) {
3251
3153
  ...metadata.custom?.length ? { customProperties: metadata.custom } : {}
3252
3154
  };
3253
3155
  }
3254
- var DOCXJS_RENDERER_ID, NOT_YET_EMITTED, DOCXJS_CAPABILITIES;
3156
+ var DOCXJS_RENDERER_ID, DOCXJS_CAPABILITIES;
3255
3157
  var init_docxjs = __esm({
3256
3158
  "src/renderers/docxjs/index.ts"() {
3257
3159
  "use strict";
3258
3160
  init_styles2();
3259
3161
  init_imageUtils();
3260
- init_features();
3261
3162
  init_packageDocument();
3262
3163
  init_fixFloatingImageIds();
3263
3164
  init_emit();
3264
3165
  init_units();
3265
3166
  DOCXJS_RENDERER_ID = "docxjs";
3266
- NOT_YET_EMITTED = /* @__PURE__ */ new Set([
3267
- "table-merged-cells",
3268
- "cached-fields",
3269
- "shading",
3270
- "borders",
3271
- "rtl",
3272
- // `drawing-groups` is the one exclusion that is a real backend gap rather
3273
- // than a slice boundary: docx.js has no `wpg:wgp`. Leaving it out is what
3274
- // turns a native `visual` sent to this backend into a named capability
3275
- // error instead of a document with the graphic missing.
3276
- "drawing-groups",
3277
- // `charts` is the second real backend gap: docx.js has no chart primitive at
3278
- // all, so a `chart` component sent here becomes a named capability error
3279
- // rather than a document missing a figure.
3280
- "charts"
3167
+ DOCXJS_CAPABILITIES = /* @__PURE__ */ new Set([
3168
+ "paragraphs",
3169
+ "styles",
3170
+ "numbering",
3171
+ "sections",
3172
+ "columns",
3173
+ "headers-footers",
3174
+ "tables",
3175
+ "floating-tables",
3176
+ "images",
3177
+ "floating-images",
3178
+ "svg-images",
3179
+ "text-frames",
3180
+ "text-boxes",
3181
+ "toc",
3182
+ "cached-toc",
3183
+ "fields",
3184
+ "hyperlinks",
3185
+ "bookmarks",
3186
+ "cross-references",
3187
+ "comments",
3188
+ "comment-threads",
3189
+ "footnotes",
3190
+ "endnotes",
3191
+ "revisions",
3192
+ "breaks",
3193
+ "tab-stops",
3194
+ "proofing-language",
3195
+ "custom-properties"
3281
3196
  ]);
3282
- DOCXJS_CAPABILITIES = new Set(
3283
- [...ALL_DOCX_FEATURES].filter((feature) => !NOT_YET_EMITTED.has(feature))
3284
- );
3285
3197
  }
3286
3198
  });
3287
3199
 
@@ -4539,11 +4451,10 @@ function coreProperties2(ir) {
4539
4451
  ...metadata.custom?.length ? { customProperties: metadata.custom } : {}
4540
4452
  };
4541
4453
  }
4542
- var OFFICE_OPEN_DOCX_RENDERER_ID, OFFICE_OPEN_DOCX, UNSUPPORTED, OFFICE_OPEN_CAPABILITIES;
4454
+ var OFFICE_OPEN_DOCX_RENDERER_ID, OFFICE_OPEN_DOCX, OFFICE_OPEN_CAPABILITIES;
4543
4455
  var init_office_open = __esm({
4544
4456
  "src/renderers/office-open/index.ts"() {
4545
4457
  "use strict";
4546
- init_features();
4547
4458
  init_chartParts();
4548
4459
  init_imageUtils();
4549
4460
  init_packageDocument();
@@ -4551,17 +4462,37 @@ var init_office_open = __esm({
4551
4462
  init_styles3();
4552
4463
  OFFICE_OPEN_DOCX_RENDERER_ID = "office-open";
4553
4464
  OFFICE_OPEN_DOCX = "@office-open/docx";
4554
- UNSUPPORTED = /* @__PURE__ */ new Set([
4555
- "cached-fields",
4556
- "comment-threads",
4557
- "table-merged-cells",
4558
- "shading",
4559
- "borders",
4560
- "rtl"
4465
+ OFFICE_OPEN_CAPABILITIES = /* @__PURE__ */ new Set([
4466
+ "paragraphs",
4467
+ "styles",
4468
+ "numbering",
4469
+ "sections",
4470
+ "columns",
4471
+ "headers-footers",
4472
+ "tables",
4473
+ "floating-tables",
4474
+ "images",
4475
+ "floating-images",
4476
+ "svg-images",
4477
+ "text-frames",
4478
+ "text-boxes",
4479
+ "drawing-groups",
4480
+ "charts",
4481
+ "toc",
4482
+ "cached-toc",
4483
+ "fields",
4484
+ "hyperlinks",
4485
+ "bookmarks",
4486
+ "cross-references",
4487
+ "comments",
4488
+ "footnotes",
4489
+ "endnotes",
4490
+ "revisions",
4491
+ "breaks",
4492
+ "tab-stops",
4493
+ "proofing-language",
4494
+ "custom-properties"
4561
4495
  ]);
4562
- OFFICE_OPEN_CAPABILITIES = new Set(
4563
- [...ALL_DOCX_FEATURES].filter((feature) => !UNSUPPORTED.has(feature))
4564
- );
4565
4496
  }
4566
4497
  });
4567
4498
 
@@ -6192,6 +6123,13 @@ init_themes();
6192
6123
  init_colorUtils();
6193
6124
  init_styleHelpers();
6194
6125
  var RIGHT_MARGIN_TAB_TWIPS = 9026 * 2;
6126
+ var STATISTIC_NUMBER_STYLE_ID = "StatisticNumber";
6127
+ var STATISTIC_DESCRIPTION_STYLE_ID = "StatisticDescription";
6128
+ var STATISTIC_SIZE_POINTS = {
6129
+ small: 20,
6130
+ medium: 28,
6131
+ large: 40
6132
+ };
6195
6133
  function isValidStyleName(name) {
6196
6134
  return [
6197
6135
  "normal",
@@ -6830,6 +6768,67 @@ function createDocumentStyles(themeNameOrObject = "minimal", language) {
6830
6768
  }
6831
6769
  };
6832
6770
  }
6771
+ function createStatisticStyles(theme) {
6772
+ const definitions = [
6773
+ {
6774
+ id: STATISTIC_NUMBER_STYLE_ID,
6775
+ name: "Statistic Number",
6776
+ font: "heading",
6777
+ sizePoints: STATISTIC_SIZE_POINTS.medium,
6778
+ color: theme.colors.primary,
6779
+ bold: true,
6780
+ // Space above separates the figure from whatever preceded it; none below,
6781
+ // because the description is the other half of the same block.
6782
+ spacing: { before: 12, after: 0 },
6783
+ next: STATISTIC_DESCRIPTION_STYLE_ID,
6784
+ // The figure and its caption are one unit; a page break between them
6785
+ // reads as a number with no label.
6786
+ keepNext: true
6787
+ },
6788
+ {
6789
+ id: STATISTIC_DESCRIPTION_STYLE_ID,
6790
+ name: "Statistic Description",
6791
+ font: "body",
6792
+ sizePoints: 10,
6793
+ color: theme.colors.textMuted,
6794
+ bold: false,
6795
+ spacing: { before: 0, after: 12 },
6796
+ next: "Normal",
6797
+ keepNext: false
6798
+ }
6799
+ ];
6800
+ return definitions.filter(
6801
+ (definition) => !(theme.styles && Object.prototype.hasOwnProperty.call(theme.styles, definition.id))
6802
+ ).map((definition) => {
6803
+ const fontProps = resolveFontProperties(theme, definition.font);
6804
+ return {
6805
+ id: definition.id,
6806
+ name: definition.name,
6807
+ basedOn: "Normal",
6808
+ next: definition.next,
6809
+ quickFormat: true,
6810
+ run: {
6811
+ fontFamily: fontProps.family || "Arial",
6812
+ // Pinned, not inherited: the whole point of the style is that the
6813
+ // figure is not body text, so a theme's body size must not decide it.
6814
+ sizeHalfPoints: definition.sizePoints * 2,
6815
+ color: { hex: resolveColor(definition.color, theme) },
6816
+ bold: definition.bold
6817
+ },
6818
+ paragraph: {
6819
+ spacing: {
6820
+ ...resolveSpacing(definition.spacing),
6821
+ ...irLineSpacing(fontProps.lineSpacing)
6822
+ },
6823
+ // Centred, matching the compiler's own alignment default — a KPI
6824
+ // reads as a block, and an author who wants otherwise says so on the
6825
+ // component, which overrides this on the paragraph.
6826
+ alignment: convertAlignment("center"),
6827
+ keepNext: definition.keepNext
6828
+ }
6829
+ };
6830
+ });
6831
+ }
6833
6832
 
6834
6833
  // src/ir/compiler.ts
6835
6834
  init_styleHelpers();
@@ -8140,6 +8139,7 @@ function compileDocument(structure, layout, warnings = [], images = /* @__PURE__
8140
8139
  resourcesByHash: /* @__PURE__ */ new Map(),
8141
8140
  nextBookmarkId: CONTENT_BOOKMARK_ID_BASE + 1,
8142
8141
  bookmarkNames: /* @__PURE__ */ new Set(),
8142
+ usesStatistic: false,
8143
8143
  styleIds: /* @__PURE__ */ new Set([
8144
8144
  ...styles.paragraph.map((s) => s.id),
8145
8145
  ...styles.character.map((s) => s.id)
@@ -8188,7 +8188,17 @@ function compileDocument(structure, layout, warnings = [], images = /* @__PURE__
8188
8188
  trackRevisions: structure.trackRevisions === true,
8189
8189
  ...noProofWords(structure.theme) ? { noProofWords: noProofWords(structure.theme) } : {}
8190
8190
  },
8191
- styles,
8191
+ // The statistic styles are appended rather than built with the rest: a
8192
+ // document that uses no statistic must keep the exact style set it had
8193
+ // before the component had styles, or every recorded golden moves for a
8194
+ // component the document does not contain.
8195
+ styles: ctx.usesStatistic ? {
8196
+ ...styles,
8197
+ paragraph: [
8198
+ ...styles.paragraph,
8199
+ ...createStatisticStyles(structure.theme)
8200
+ ]
8201
+ } : styles,
8192
8202
  numbering: ctx.numbering,
8193
8203
  resources: ctx.resources,
8194
8204
  sections,
@@ -8203,6 +8213,21 @@ function compileDocument(structure, layout, warnings = [], images = /* @__PURE__
8203
8213
  unsupported: ctx.unsupported
8204
8214
  };
8205
8215
  }
8216
+ var AFTER_TABLE_TWIPS = 120;
8217
+ var BODY_STYLE_IDS = /* @__PURE__ */ new Set([void 0, "Normal"]);
8218
+ function separateFromTables(blocks) {
8219
+ for (let i = 1; i < blocks.length; i += 1) {
8220
+ const block2 = blocks[i];
8221
+ if (blocks[i - 1].kind !== "table") continue;
8222
+ if (block2.kind !== "paragraph") continue;
8223
+ if (!BODY_STYLE_IDS.has(block2.styleId)) continue;
8224
+ if (block2.formatting?.spacing?.beforeTwips !== void 0) continue;
8225
+ block2.formatting = {
8226
+ ...block2.formatting,
8227
+ spacing: { ...block2.formatting?.spacing, beforeTwips: AFTER_TABLE_TWIPS }
8228
+ };
8229
+ }
8230
+ }
8206
8231
  function collectOutline(layout, warnings) {
8207
8232
  try {
8208
8233
  return collectDocumentOutline(layout.sections);
@@ -8279,6 +8304,7 @@ function compileSection(section2, index, ordinal, chrome, ctx) {
8279
8304
  })
8280
8305
  );
8281
8306
  });
8307
+ separateFromTables(children);
8282
8308
  const compiled = {
8283
8309
  id: `s${index}`,
8284
8310
  path: path3,
@@ -9049,35 +9075,83 @@ function compileToc(component, scope) {
9049
9075
  });
9050
9076
  return blocks;
9051
9077
  }
9078
+ var TREND_GLYPHS = {
9079
+ up: "\u25B2",
9080
+ down: "\u25BC",
9081
+ neutral: "\u2013"
9082
+ };
9052
9083
  function compileStatistic(component, scope) {
9053
- const { path: path3 } = scope;
9084
+ const { ctx, path: path3 } = scope;
9054
9085
  const props = component.props ?? {};
9055
9086
  const alignment2 = compileAlignment(props.alignment) ?? "center";
9087
+ ctx.usesStatistic = true;
9056
9088
  const spacing = props.spacing ? {
9057
9089
  ...props.spacing.before !== void 0 ? { beforeTwips: props.spacing.before } : {},
9058
9090
  ...props.spacing.after !== void 0 ? { afterTwips: props.spacing.after } : {}
9059
9091
  } : void 0;
9060
- const line = (text, styleId, suffix, formatting) => {
9061
- const value = normalizeUnicodeText(String(text ?? ""));
9062
- return {
9063
- kind: "paragraph",
9064
- id: `${scope.id}:${suffix}`,
9065
- path: `${path3}.${suffix}`,
9066
- styleId,
9067
- formatting,
9068
- // Nothing to say is not the same as saying nothing: an empty statistic
9069
- // line is a styled blank paragraph, with no run inside it at all.
9070
- children: value ? [{ kind: "text", text: value }] : []
9071
- };
9072
- };
9092
+ if (props.format !== void 0) {
9093
+ warnOnce(
9094
+ ctx,
9095
+ "statistic",
9096
+ 'statistic "format" is not implemented and was ignored \u2014 format the value yourself and pass the result as "number".',
9097
+ "W_STATISTIC_FORMAT_IGNORED"
9098
+ );
9099
+ }
9100
+ const text = (value) => normalizeUnicodeText(String(value ?? ""));
9101
+ const numberPoints = STATISTIC_SIZE_POINTS[String(props.size)] ?? STATISTIC_SIZE_POINTS.medium;
9102
+ const resized = numberPoints !== STATISTIC_SIZE_POINTS.medium;
9103
+ const suffixHalfPoints = Math.max(12, Math.round(numberPoints));
9104
+ const numberRuns = [];
9105
+ const numberText = text(props.number);
9106
+ if (numberText) {
9107
+ numberRuns.push({
9108
+ kind: "text",
9109
+ text: numberText,
9110
+ ...resized ? { formatting: { sizeHalfPoints: numberPoints * 2 } } : {}
9111
+ });
9112
+ }
9113
+ const unitText = text(props.unit);
9114
+ if (unitText) {
9115
+ numberRuns.push({
9116
+ kind: "text",
9117
+ text: unitText,
9118
+ formatting: { sizeHalfPoints: suffixHalfPoints }
9119
+ });
9120
+ }
9121
+ const glyph = typeof props.trend === "string" ? TREND_GLYPHS[props.trend] : void 0;
9122
+ const trendValue = text(props.trendValue);
9123
+ if (glyph || trendValue) {
9124
+ numberRuns.push({
9125
+ kind: "text",
9126
+ text: `${numberRuns.length > 0 ? " " : ""}${[glyph, trendValue].filter(Boolean).join(" ")}`,
9127
+ formatting: {
9128
+ sizeHalfPoints: suffixHalfPoints,
9129
+ color: irColor(resolveColor(ctx.theme.colors.textMuted, ctx.theme))
9130
+ }
9131
+ });
9132
+ }
9133
+ const line = (children, styleId, suffix, formatting) => ({
9134
+ kind: "paragraph",
9135
+ id: `${scope.id}:${suffix}`,
9136
+ path: `${path3}.${suffix}`,
9137
+ styleId,
9138
+ formatting,
9139
+ // Nothing to say is not the same as saying nothing: an empty statistic
9140
+ // line is a styled blank paragraph, with no run inside it at all.
9141
+ children
9142
+ });
9143
+ const descriptionText = text(props.description);
9073
9144
  return [
9074
- line(props.number, "StatisticNumber", "number", {
9145
+ line(numberRuns, STATISTIC_NUMBER_STYLE_ID, "number", {
9075
9146
  alignment: alignment2,
9076
9147
  ...spacing ? { spacing } : {}
9077
9148
  }),
9078
- line(props.description, "StatisticDescription", "description", {
9079
- alignment: alignment2
9080
- })
9149
+ line(
9150
+ descriptionText ? [{ kind: "text", text: descriptionText }] : [],
9151
+ STATISTIC_DESCRIPTION_STYLE_ID,
9152
+ "description",
9153
+ { alignment: alignment2 }
9154
+ )
9081
9155
  ];
9082
9156
  }
9083
9157
  function compileList(component, scope, referencePrefix = "list", explicitLevels) {
@@ -9150,12 +9224,12 @@ function compileList(component, scope, referencePrefix = "list", explicitLevels)
9150
9224
  }
9151
9225
  function itemSpacing(spacing, index, count) {
9152
9226
  const out = {};
9153
- if (index === 0 && spacing?.before) {
9227
+ if (index === 0 && spacing?.before !== void 0) {
9154
9228
  out.beforeTwips = pointsToTwips2(spacing.before);
9155
9229
  }
9156
- if (index === count - 1 && spacing?.after) {
9230
+ if (index === count - 1 && spacing?.after !== void 0) {
9157
9231
  out.afterTwips = pointsToTwips2(spacing.after);
9158
- } else if (spacing?.item) {
9232
+ } else if (spacing?.item !== void 0) {
9159
9233
  out.afterTwips = pointsToTwips2(spacing.item);
9160
9234
  }
9161
9235
  return out;
@@ -10626,7 +10700,9 @@ function warnOnce(ctx, component, message, code) {
10626
10700
  }
10627
10701
 
10628
10702
  // src/renderers/registry.ts
10629
- import { RendererRegistry } from "@json-to-office/shared/rendering";
10703
+ import {
10704
+ RendererRegistry
10705
+ } from "@json-to-office/shared/rendering";
10630
10706
 
10631
10707
  // src/renderers/types.ts
10632
10708
  import {