@json-to-office/core-docx 2.6.0 → 2.7.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.
package/dist/index.js CHANGED
@@ -8455,11 +8455,167 @@ function emptyToUndefined(formatting) {
8455
8455
  }
8456
8456
 
8457
8457
  // src/blocks/index.ts
8458
- import { KEY_TAKEAWAYS_BUDGET } from "@json-to-office/shared-docx";
8458
+ import {
8459
+ COVER_BUDGET,
8460
+ KEY_TAKEAWAYS_BUDGET,
8461
+ RUNNING_HEAD_BUDGET,
8462
+ SECTION_OPENER_BUDGET
8463
+ } from "@json-to-office/shared-docx";
8459
8464
 
8460
- // src/blocks/keyTakeaways.ts
8465
+ // src/blocks/cover.ts
8466
+ init_widthUtils();
8467
+
8468
+ // src/blocks/recipe.ts
8461
8469
  var MIN_RULE_PT = 0.25;
8462
8470
  var MAX_RULE_PT = 12;
8471
+ function clampRule(weightPt) {
8472
+ return Math.min(MAX_RULE_PT, Math.max(MIN_RULE_PT, weightPt));
8473
+ }
8474
+ var FALLBACK_EYEBROW_FONT = {
8475
+ size: 9,
8476
+ bold: true,
8477
+ color: "accent",
8478
+ case: "upper"
8479
+ };
8480
+ function hasStyle(theme, role) {
8481
+ const styles = theme.styles;
8482
+ return styles?.[role] !== void 0;
8483
+ }
8484
+ function roleProps(theme, role, fallbackFont, color) {
8485
+ if (hasStyle(theme, role)) {
8486
+ return {
8487
+ themeStyle: role,
8488
+ ...color !== void 0 && { font: { color } }
8489
+ };
8490
+ }
8491
+ return { font: { ...fallbackFont, ...color !== void 0 && { color } } };
8492
+ }
8493
+
8494
+ // src/blocks/cover.ts
8495
+ var DROP_SHARE = 0.3;
8496
+ var DROP_SHARE_WITH_LOGO = 0.22;
8497
+ var DEFAULT_LOGO_WIDTH = "25%";
8498
+ var FALLBACK = {
8499
+ ruleWeightPt: 3,
8500
+ ruleColor: "accent",
8501
+ padPt: 12,
8502
+ metaFont: { size: 9, color: "textSecondary" }
8503
+ };
8504
+ function compileCover(props, theme) {
8505
+ const recipe = theme.chrome?.cover;
8506
+ const ruleWeightPt = recipe?.rule?.weightPt ?? FALLBACK.ruleWeightPt;
8507
+ const padPt = recipe?.padPt ?? FALLBACK.padPt;
8508
+ const heightPt = getAvailableHeightTwips(theme) / 20;
8509
+ const dropPt = Math.round(
8510
+ heightPt * (props.logo ? DROP_SHARE_WITH_LOGO : DROP_SHARE)
8511
+ );
8512
+ const children = [];
8513
+ const sourceMap = {};
8514
+ const emit = (child, slots) => {
8515
+ const index = children.push(child) - 1;
8516
+ sourceMap[`/children/${index}`] = "";
8517
+ for (const [emitted, authored] of Object.entries(slots)) {
8518
+ sourceMap[`/children/${index}${emitted}`] = authored;
8519
+ }
8520
+ };
8521
+ if (props.logo) {
8522
+ const { width, height, ...source } = props.logo;
8523
+ emit(
8524
+ {
8525
+ name: "image",
8526
+ props: {
8527
+ ...source,
8528
+ width: width ?? DEFAULT_LOGO_WIDTH,
8529
+ ...height !== void 0 && { height },
8530
+ alignment: theme.chrome?.logoSlot?.alignment ?? "left",
8531
+ spacing: { before: 0, after: 0 }
8532
+ }
8533
+ },
8534
+ { "/props": "/props/logo" }
8535
+ );
8536
+ }
8537
+ const drawsRule = ruleWeightPt > 0;
8538
+ if (drawsRule) {
8539
+ emit(
8540
+ {
8541
+ name: "divider",
8542
+ props: {
8543
+ thickness: clampRule(ruleWeightPt),
8544
+ color: recipe?.rule?.color ?? FALLBACK.ruleColor,
8545
+ spacing: { before: dropPt, after: padPt }
8546
+ }
8547
+ },
8548
+ {}
8549
+ );
8550
+ }
8551
+ let dropPending = !drawsRule;
8552
+ const before = () => {
8553
+ if (!dropPending) return {};
8554
+ dropPending = false;
8555
+ return { before: dropPt };
8556
+ };
8557
+ if (props.client) {
8558
+ emit(
8559
+ {
8560
+ name: "paragraph",
8561
+ props: {
8562
+ text: props.client,
8563
+ keepNext: true,
8564
+ spacing: { ...before(), after: 4 },
8565
+ ...roleProps(theme, "eyebrow", FALLBACK_EYEBROW_FONT)
8566
+ }
8567
+ },
8568
+ { "/props/text": "/props/client" }
8569
+ );
8570
+ }
8571
+ const titleRole = recipe?.type && hasStyle(theme, recipe.type) ? recipe.type : "title";
8572
+ emit(
8573
+ {
8574
+ name: "paragraph",
8575
+ props: {
8576
+ text: props.title,
8577
+ keepNext: true,
8578
+ ...dropPending && { spacing: before() },
8579
+ ...roleProps(theme, titleRole, { size: 26, bold: true }, recipe?.color)
8580
+ }
8581
+ },
8582
+ { "/props/text": "/props/title" }
8583
+ );
8584
+ if (props.subtitle) {
8585
+ emit(
8586
+ {
8587
+ name: "paragraph",
8588
+ props: {
8589
+ text: props.subtitle,
8590
+ keepNext: true,
8591
+ ...roleProps(theme, "subtitle", { size: 13, color: "textSecondary" })
8592
+ }
8593
+ },
8594
+ { "/props/text": "/props/subtitle" }
8595
+ );
8596
+ }
8597
+ const meta = [props.date, props.confidentiality].filter(
8598
+ (part) => typeof part === "string" && part !== ""
8599
+ );
8600
+ if (meta.length > 0) {
8601
+ emit(
8602
+ {
8603
+ name: "paragraph",
8604
+ props: {
8605
+ text: meta.join(" \xB7 "),
8606
+ spacing: { before: padPt, after: 0 },
8607
+ ...roleProps(theme, "label", FALLBACK.metaFont)
8608
+ }
8609
+ },
8610
+ {
8611
+ "/props/text": props.date ? "/props/date" : "/props/confidentiality"
8612
+ }
8613
+ );
8614
+ }
8615
+ return { children, sourceMap };
8616
+ }
8617
+
8618
+ // src/blocks/keyTakeaways.ts
8463
8619
  var KEY_TAKEAWAYS_DEFAULT_LABEL = "Key takeaways";
8464
8620
  var FALLBACK_RECIPE = {
8465
8621
  ruleWeightPt: 1.5,
@@ -8470,13 +8626,9 @@ var FALLBACK_RECIPE = {
8470
8626
  function compileKeyTakeaways(props, theme) {
8471
8627
  const recipe = theme.chrome?.keyTakeaways;
8472
8628
  const labelRole = recipe?.type ?? FALLBACK_RECIPE.type;
8473
- const labelStyle = theme.styles?.[labelRole];
8474
- const ruleWeightPt = Math.min(
8475
- MAX_RULE_PT,
8476
- Math.max(
8477
- MIN_RULE_PT,
8478
- recipe?.rule?.weightPt ?? FALLBACK_RECIPE.ruleWeightPt
8479
- )
8629
+ const labelStyle = hasStyle(theme, labelRole);
8630
+ const ruleWeightPt = clampRule(
8631
+ recipe?.rule?.weightPt ?? FALLBACK_RECIPE.ruleWeightPt
8480
8632
  );
8481
8633
  const ruleColor = recipe?.rule?.color ?? recipe?.color ?? FALLBACK_RECIPE.ruleColor;
8482
8634
  const padPt = recipe?.padPt ?? FALLBACK_RECIPE.padPt;
@@ -8531,10 +8683,195 @@ function compileKeyTakeaways(props, theme) {
8531
8683
  };
8532
8684
  }
8533
8685
 
8686
+ // src/blocks/runningHead.ts
8687
+ init_styles();
8688
+ init_widthUtils();
8689
+ var FALLBACK2 = {
8690
+ headFont: { size: 8, color: "textMuted", case: "upper" },
8691
+ footFont: { size: 8, color: "textMuted" },
8692
+ ruleWeightPt: 0.5,
8693
+ ruleColor: "border"
8694
+ };
8695
+ var PAGE_OF_TOTAL = "{PAGE} / {TOTAL_PAGES}";
8696
+ function sectionMeasureTwips(theme, page) {
8697
+ if (!page || page.size === void 0 && page.margins === void 0) {
8698
+ return getAvailableWidthTwips(theme);
8699
+ }
8700
+ const width = page.size ? getPageDimensions(page.size).width : getPageDimensions(theme.page.size).width;
8701
+ const margins = getDocumentMargins(theme);
8702
+ const left = page.margins?.left ?? margins.left ?? 1440;
8703
+ const right = page.margins?.right ?? margins.right ?? 1440;
8704
+ return Math.max(0, width - left - right);
8705
+ }
8706
+ function compileRunningHead(props, theme, scope) {
8707
+ const measure = sectionMeasureTwips(theme, scope.page);
8708
+ const head = theme.chrome?.runningHead;
8709
+ const foot = theme.chrome?.confidentialFooter;
8710
+ const slot = (name) => props[name] !== void 0 ? `${scope.block}/props/${name}` : void 0;
8711
+ const header = [];
8712
+ const headerMap = {};
8713
+ const title = props.title ?? scope.documentTitle ?? "";
8714
+ const tracker = scope.opener?.text ?? props.tracker ?? "";
8715
+ if (title !== "" || tracker !== "") {
8716
+ const both = title !== "" && tracker !== "";
8717
+ header.push({
8718
+ name: "paragraph",
8719
+ props: {
8720
+ text: both ? `${title} ${tracker}` : title || tracker,
8721
+ ...both ? { tabStops: [{ type: "right", position: measure }] } : { alignment: title !== "" ? "left" : head?.alignment ?? "right" },
8722
+ spacing: { before: 0, after: 0 },
8723
+ ...roleProps(
8724
+ theme,
8725
+ head?.type ?? "tracker",
8726
+ FALLBACK2.headFont,
8727
+ head?.color
8728
+ )
8729
+ }
8730
+ });
8731
+ headerMap["/0"] = scope.block;
8732
+ headerMap["/0/props/text"] = (tracker !== "" ? scope.opener?.slot ?? slot("tracker") : slot("title")) ?? scope.block;
8733
+ }
8734
+ const headRule = head?.rule?.weightPt ?? FALLBACK2.ruleWeightPt;
8735
+ if (headRule > 0) {
8736
+ header.push({
8737
+ name: "divider",
8738
+ props: {
8739
+ thickness: clampRule(headRule),
8740
+ color: head?.rule?.color ?? FALLBACK2.ruleColor,
8741
+ spacing: { before: 2, after: 0 }
8742
+ }
8743
+ });
8744
+ headerMap[`/${header.length - 1}`] = scope.block;
8745
+ }
8746
+ const footer = [];
8747
+ const footerMap = {};
8748
+ const footRule = foot?.rule?.weightPt ?? FALLBACK2.ruleWeightPt;
8749
+ if (footRule > 0) {
8750
+ footer.push({
8751
+ name: "divider",
8752
+ props: {
8753
+ thickness: clampRule(footRule),
8754
+ color: foot?.rule?.color ?? FALLBACK2.ruleColor,
8755
+ spacing: { before: 0, after: 4 }
8756
+ }
8757
+ });
8758
+ footerMap["/0"] = scope.block;
8759
+ }
8760
+ const parts = [
8761
+ props.confidentiality ?? "",
8762
+ props.pageNumbers === false ? "" : PAGE_OF_TOTAL,
8763
+ props.date ?? ""
8764
+ ];
8765
+ const present = parts.filter((part) => part !== "");
8766
+ if (present.length > 0) {
8767
+ const single = present.length === 1;
8768
+ const alignment2 = present[0] === PAGE_OF_TOTAL ? "center" : foot?.alignment ?? "left";
8769
+ footer.push({
8770
+ name: "paragraph",
8771
+ props: {
8772
+ text: single ? present[0] : parts.join(" ").replace(/\t+$/, ""),
8773
+ ...single ? { alignment: alignment2 } : {
8774
+ tabStops: [
8775
+ { type: "center", position: Math.round(measure / 2) },
8776
+ { type: "right", position: measure }
8777
+ ]
8778
+ },
8779
+ spacing: { before: 0, after: 0 },
8780
+ ...roleProps(
8781
+ theme,
8782
+ foot?.type ?? "footer",
8783
+ FALLBACK2.footFont,
8784
+ foot?.color
8785
+ )
8786
+ }
8787
+ });
8788
+ const index = footer.length - 1;
8789
+ footerMap[`/${index}`] = scope.block;
8790
+ footerMap[`/${index}/props/text`] = slot("confidentiality") ?? slot("date") ?? scope.block;
8791
+ }
8792
+ return {
8793
+ header: { children: header, sourceMap: headerMap },
8794
+ footer: { children: footer, sourceMap: footerMap }
8795
+ };
8796
+ }
8797
+
8798
+ // src/blocks/sectionOpener.ts
8799
+ function compileSectionOpener(props, theme) {
8800
+ const children = [];
8801
+ const sourceMap = {};
8802
+ const pageBreak = props.pageBreak === true;
8803
+ if (props.number !== void 0) {
8804
+ children.push({
8805
+ name: "paragraph",
8806
+ props: {
8807
+ text: String(props.number),
8808
+ keepNext: true,
8809
+ spacing: { after: 2 },
8810
+ ...pageBreak && { pageBreak: true },
8811
+ ...roleProps(theme, "eyebrow", FALLBACK_EYEBROW_FONT)
8812
+ }
8813
+ });
8814
+ sourceMap["/children/0"] = "";
8815
+ sourceMap["/children/0/props/text"] = "/props/number";
8816
+ }
8817
+ const index = children.length;
8818
+ children.push({
8819
+ name: "heading",
8820
+ props: {
8821
+ text: props.title,
8822
+ level: 1,
8823
+ ...pageBreak && index === 0 && { pageBreak: true }
8824
+ }
8825
+ });
8826
+ sourceMap[`/children/${index}`] = "";
8827
+ sourceMap[`/children/${index}/props/text`] = "/props/title";
8828
+ return { children, sourceMap };
8829
+ }
8830
+ function sectionTracker(section2) {
8831
+ if (!Array.isArray(section2.children)) return void 0;
8832
+ for (const [index, child] of section2.children.entries()) {
8833
+ if (typeof child !== "object" || child === null || child.name !== "section-opener" || child.enabled === false) {
8834
+ continue;
8835
+ }
8836
+ const props = child.props;
8837
+ if (!props) continue;
8838
+ if (typeof props.tracker === "string" && props.tracker !== "") {
8839
+ return { text: props.tracker, slot: `/children/${index}/props/tracker` };
8840
+ }
8841
+ if (typeof props.title === "string" && props.title !== "") {
8842
+ return { text: props.title, slot: `/children/${index}/props/title` };
8843
+ }
8844
+ }
8845
+ return void 0;
8846
+ }
8847
+
8534
8848
  // src/blocks/index.ts
8535
- var BLOCK_NAMES = ["key-takeaways"];
8849
+ var BLOCK_NAMES = [
8850
+ "key-takeaways",
8851
+ "cover",
8852
+ "section-opener",
8853
+ "running-head"
8854
+ ];
8855
+ function slotBudget(block2, props, pointer, slot, maxWords) {
8856
+ const value = props[slot];
8857
+ return typeof value === "string" ? [
8858
+ {
8859
+ block: block2,
8860
+ slot,
8861
+ path: `${pointer}/props/${slot}`,
8862
+ words: wordCount(value),
8863
+ maxWords
8864
+ }
8865
+ ] : [];
8866
+ }
8867
+ function budgetsOf(block2, budget) {
8868
+ return (props, pointer) => Object.entries(budget).flatMap(
8869
+ ([slot, { maxWords }]) => slotBudget(block2, props, pointer, slot, maxWords)
8870
+ );
8871
+ }
8536
8872
  var BLOCKS = {
8537
8873
  "key-takeaways": {
8874
+ kind: "flow",
8538
8875
  compile: (props, theme) => compileKeyTakeaways(props, theme),
8539
8876
  budgets: (props, pointer) => (Array.isArray(props.items) ? props.items : []).flatMap(
8540
8877
  (item, index) => typeof item === "string" ? [
@@ -8547,25 +8884,95 @@ var BLOCKS = {
8547
8884
  }
8548
8885
  ] : []
8549
8886
  )
8887
+ },
8888
+ cover: {
8889
+ kind: "flow",
8890
+ compile: (props, theme) => compileCover(props, theme),
8891
+ budgets: budgetsOf("cover", COVER_BUDGET)
8892
+ },
8893
+ "section-opener": {
8894
+ kind: "flow",
8895
+ compile: (props, theme) => compileSectionOpener(props, theme),
8896
+ budgets: budgetsOf("section-opener", SECTION_OPENER_BUDGET)
8897
+ },
8898
+ "running-head": {
8899
+ kind: "chrome",
8900
+ budgets: budgetsOf("running-head", RUNNING_HEAD_BUDGET)
8550
8901
  }
8551
8902
  };
8552
8903
  function isBlockName(name) {
8553
8904
  return BLOCK_NAMES.includes(name);
8554
8905
  }
8906
+ function isChromeBlockName(name) {
8907
+ return isBlockName(name) && BLOCKS[name].kind === "chrome";
8908
+ }
8555
8909
  function isRecord(value) {
8556
8910
  return typeof value === "object" && value !== null && !Array.isArray(value);
8557
8911
  }
8912
+ var SECTION_CHILD = /^\/children\/\d+\/children\/\d+$/;
8913
+ var SECTION = /^\/children\/(\d+)$/;
8914
+ function planChrome(document, theme) {
8915
+ const plans = /* @__PURE__ */ new Map();
8916
+ if (!isRecord(document) || document.name !== "docx" || !Array.isArray(document.children)) {
8917
+ return plans;
8918
+ }
8919
+ const metadata = isRecord(document.props) ? document.props.metadata : void 0;
8920
+ const documentTitle = isRecord(metadata) && typeof metadata.title === "string" ? metadata.title : void 0;
8921
+ let inForce;
8922
+ document.children.forEach((section2, index) => {
8923
+ if (!isRecord(section2) || section2.name !== "section" || section2.enabled === false) {
8924
+ return;
8925
+ }
8926
+ const sectionPointer = `/children/${index}`;
8927
+ const children = Array.isArray(section2.children) ? section2.children : [];
8928
+ children.forEach((child, childIndex) => {
8929
+ if (isRecord(child) && isChromeBlockName(child.name) && child.enabled !== false) {
8930
+ inForce = {
8931
+ block: `${sectionPointer}/children/${childIndex}`,
8932
+ props: isRecord(child.props) ? child.props : {}
8933
+ };
8934
+ }
8935
+ });
8936
+ if (!inForce) return;
8937
+ const opener = sectionTracker(section2);
8938
+ const sectionProps = isRecord(section2.props) ? section2.props : {};
8939
+ plans.set(
8940
+ index,
8941
+ compileRunningHead(inForce.props, theme, {
8942
+ block: inForce.block,
8943
+ documentTitle,
8944
+ ...opener && {
8945
+ opener: {
8946
+ text: opener.text,
8947
+ slot: `${sectionPointer}${opener.slot}`
8948
+ }
8949
+ },
8950
+ ...isRecord(sectionProps.page) && {
8951
+ page: sectionProps.page
8952
+ }
8953
+ })
8954
+ );
8955
+ });
8956
+ return plans;
8957
+ }
8558
8958
  function expandBlocks(document, theme) {
8559
8959
  const sourceMap = {};
8560
8960
  const blocks = [];
8961
+ const chrome = planChrome(document, theme);
8561
8962
  const walk2 = (node, pointer) => {
8562
8963
  if (Array.isArray(node)) {
8563
8964
  return node.map((child, index) => walk2(child, `${pointer}/${index}`));
8564
8965
  }
8565
8966
  if (!isRecord(node)) return node;
8566
- if (typeof node.name === "string" && isRecord(node.props)) {
8567
- if (node.enabled !== false && isBlockName(node.name)) {
8568
- const compiled = BLOCKS[node.name].compile(node.props, theme);
8967
+ if (typeof node.name === "string" && node.enabled !== false && isBlockName(node.name)) {
8968
+ const definition = BLOCKS[node.name];
8969
+ if (definition.kind === "chrome") {
8970
+ if (!SECTION_CHILD.test(pointer)) return node;
8971
+ blocks.push(pointer);
8972
+ return { ...node, children: [] };
8973
+ }
8974
+ if (isRecord(node.props)) {
8975
+ const compiled = definition.compile(node.props, theme);
8569
8976
  blocks.push(pointer);
8570
8977
  for (const [emitted, authored] of Object.entries(compiled.sourceMap)) {
8571
8978
  sourceMap[`${pointer}${emitted}`] = `${pointer}${authored}`;
@@ -8614,6 +9021,30 @@ function expandBlocks(document, theme) {
8614
9021
  if (Array.isArray(node.children)) {
8615
9022
  next.children = walk2(node.children, `${pointer}/children`);
8616
9023
  }
9024
+ const section2 = SECTION.exec(pointer);
9025
+ if (section2 && node.name === "section" && node.enabled !== false) {
9026
+ const plan = chrome.get(Number(section2[1]));
9027
+ if (plan) {
9028
+ const props = isRecord(next.props) ? { ...next.props } : {};
9029
+ let changed = false;
9030
+ for (const part of ["header", "footer"]) {
9031
+ const { children, sourceMap: partMap } = plan[part];
9032
+ if (props[part] !== void 0 || children.length === 0) continue;
9033
+ props[part] = children;
9034
+ changed = true;
9035
+ const base = `${pointer}/props/${part}`;
9036
+ sourceMap[base] = partMap["/0"] ?? pointer;
9037
+ for (const [emitted, authored] of Object.entries(partMap)) {
9038
+ sourceMap[`${base}${emitted}`] = authored;
9039
+ }
9040
+ }
9041
+ if (props.pageBreak === void 0) {
9042
+ props.pageBreak = true;
9043
+ changed = true;
9044
+ }
9045
+ if (changed) next.props = props;
9046
+ }
9047
+ }
8617
9048
  return next;
8618
9049
  };
8619
9050
  const expanded = walk2(document, "");
@@ -8955,33 +9386,47 @@ function compileChromeParagraph(component, scope) {
8955
9386
  const text = String(props.text ?? "");
8956
9387
  if (reportUnlowered(component, props, text, scope)) return [];
8957
9388
  const font = props.font ?? {};
8958
- const normal = getNormalStyle(ctx.theme);
9389
+ const named = chromeStyle(ctx.theme, props.themeStyle);
9390
+ const base = { ...getNormalStyle(ctx.theme), ...named };
9391
+ const styleId = named ? paragraphStyleId(props.themeStyle) ?? "Normal" : "Normal";
9392
+ if (styleId !== "Normal" && !ctx.styleIds.has(styleId)) {
9393
+ ctx.styleIds.add(styleId);
9394
+ }
8959
9395
  const chromeProps = {
8960
9396
  text,
8961
- ...props.alignment ? { alignment: props.alignment } : {},
9397
+ ...named ? { themeStyle: props.themeStyle } : {},
9398
+ ...props.alignment ? { alignment: props.alignment } : named?.alignment ? { alignment: named.alignment } : {},
8962
9399
  ...props.spacing ? { spacing: props.spacing } : {},
9400
+ ...props.indent ? { indent: props.indent } : {},
9401
+ ...props.tabStops ? { tabStops: props.tabStops } : {},
8963
9402
  ...props.boldColor ? { boldColor: props.boldColor } : {},
8964
9403
  font: {
8965
- family: font.family || resolveFontFamily(ctx.theme, normal.font) || getThemeFonts(ctx.theme).body.family,
8966
- size: font.size ?? normal.size ?? 11,
8967
- color: font.color || normal.color || "textPrimary",
8968
- bold: font.bold ?? false,
8969
- italic: font.italic ?? false,
9404
+ family: font.family || resolveFontFamily(ctx.theme, base.font) || getThemeFonts(ctx.theme).body.family,
9405
+ size: font.size ?? base.size ?? 11,
9406
+ color: font.color || base.color || "textPrimary",
9407
+ bold: font.bold ?? base.bold ?? false,
9408
+ italic: font.italic ?? base.italic ?? false,
8970
9409
  ...font.underline !== void 0 ? { underline: font.underline } : {},
8971
- ...font.fontWeight !== void 0 ? { fontWeight: font.fontWeight } : {},
8972
- ...font.case !== void 0 ? { case: font.case } : {},
9410
+ ...(font.fontWeight ?? base.fontWeight) !== void 0 ? { fontWeight: font.fontWeight ?? base.fontWeight } : {},
9411
+ ...(font.case ?? base.case) !== void 0 ? { case: font.case ?? base.case } : {},
9412
+ ...(font.characterSpacing ?? base.characterSpacing) !== void 0 ? { characterSpacing: font.characterSpacing ?? base.characterSpacing } : {},
8973
9413
  ...font.lineSpacing !== void 0 ? { lineSpacing: font.lineSpacing } : {}
8974
9414
  }
8975
9415
  };
8976
9416
  return [
8977
9417
  paragraphNode(scope, compileRuns(chromeProps, text, ctx, scope.path), {
8978
- styleId: "Normal",
9418
+ styleId,
8979
9419
  formatting: paragraphFormatting(chromeProps, ctx, {
8980
9420
  alwaysSpacing: true
8981
9421
  })
8982
9422
  })
8983
9423
  ];
8984
9424
  }
9425
+ function chromeStyle(theme, themeStyle) {
9426
+ if (typeof themeStyle !== "string" || !themeStyle) return void 0;
9427
+ const styles = getThemeStyles(theme);
9428
+ return styles[themeStyle] ?? styles[themeStyle.toLowerCase()];
9429
+ }
8985
9430
  function compileChromeImage(component, scope) {
8986
9431
  const { ctx, path: path4 } = scope;
8987
9432
  const props = component.props ?? {};
@@ -9081,8 +9526,8 @@ function compileComponent(component, scope) {
9081
9526
  }
9082
9527
  }
9083
9528
  function compileBlock(component, scope) {
9084
- const children = component.children ?? [];
9085
- if (children.length === 0) {
9529
+ const children = component.children;
9530
+ if (!Array.isArray(children)) {
9086
9531
  scope.ctx.unsupported.push({ name: component.name, path: scope.path });
9087
9532
  return [];
9088
9533
  }
@@ -14970,7 +15415,10 @@ export {
14970
15415
  analyzeDocxQuality,
14971
15416
  blockSlotBudgets,
14972
15417
  cleanComponentProps,
15418
+ compileCover,
14973
15419
  compileKeyTakeaways,
15420
+ compileRunningHead,
15421
+ compileSectionOpener,
14974
15422
  consultingTheme,
14975
15423
  createComponent,
14976
15424
  createDocumentGenerator,
@@ -15001,6 +15449,7 @@ export {
15001
15449
  getExampleNames,
15002
15450
  getVisualPrepassStats,
15003
15451
  hasNodeBuiltins,
15452
+ isChromeBlockName,
15004
15453
  isColumnsComponent,
15005
15454
  isDocxRendererId,
15006
15455
  isHeadingComponent,
@@ -15024,6 +15473,8 @@ export {
15024
15473
  resetVisualPrepassStats,
15025
15474
  resolveDocxQualityProfile,
15026
15475
  runExample,
15476
+ sectionMeasureTwips,
15477
+ sectionTracker,
15027
15478
  themes,
15028
15479
  toAuthoredPointer,
15029
15480
  validateComponentProps,