@shbernal/ts-pptx 4.0.1 → 4.2.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.
Files changed (139) hide show
  1. package/README.md +147 -114
  2. package/dist/anim-presets-Qbgh8uut.js +55 -0
  3. package/dist/anim-presets-Qbgh8uut.js.map +1 -0
  4. package/dist/{autopage-odPz7zZO.js → autopage-DqZ37VpL.js} +11 -12
  5. package/dist/autopage-DqZ37VpL.js.map +1 -0
  6. package/dist/{binary-string-CKVAYI3M.js → binary-string-Ba8VM3b9.js} +3 -4
  7. package/dist/binary-string-Ba8VM3b9.js.map +1 -0
  8. package/dist/{body-insets-Dw_BeWD_.js → body-insets-BDHymJvz.js} +7 -9
  9. package/dist/body-insets-BDHymJvz.js.map +1 -0
  10. package/dist/browser.d.ts +24 -16
  11. package/dist/browser.d.ts.map +1 -1
  12. package/dist/browser.js +19 -19
  13. package/dist/browser.js.map +1 -1
  14. package/dist/{image-size-CvN2iCA4.js → chart-metadata-CwiTTcJq.js} +634 -537
  15. package/dist/chart-metadata-CwiTTcJq.js.map +1 -0
  16. package/dist/{clip-Bl01BPcN.d.ts → clip-ISfCMtWA.d.ts} +6 -10
  17. package/dist/clip-ISfCMtWA.d.ts.map +1 -0
  18. package/dist/{notes-Dh12JAbn.js → comments-CKIZYRbZ.js} +530 -401
  19. package/dist/comments-CKIZYRbZ.js.map +1 -0
  20. package/dist/{diagnostics-D8ot4Ei7.d.ts → diagnostics-MoA4MBq5.d.ts} +55 -53
  21. package/dist/diagnostics-MoA4MBq5.d.ts.map +1 -0
  22. package/dist/{embedded-fonts-DarT9aoa.d.ts → embedded-fonts-U7HIIhPO.d.ts} +4 -6
  23. package/dist/embedded-fonts-U7HIIhPO.d.ts.map +1 -0
  24. package/dist/{entry-compose-DCnvBZz2.d.ts → entry-compose-CiakSt-f.d.ts} +62 -81
  25. package/dist/entry-compose-CiakSt-f.d.ts.map +1 -0
  26. package/dist/{errors-C4oENPcu.js → entry-errors-JMthgJ2g.js} +45 -29
  27. package/dist/entry-errors-JMthgJ2g.js.map +1 -0
  28. package/dist/{table-cell-margins-EVg0EwxT.js → enums-BP9wsb9Q.js} +44 -47
  29. package/dist/enums-BP9wsb9Q.js.map +1 -0
  30. package/dist/{enums-BUKTUB6V.d.ts → enums-PcXr3o3J.d.ts} +13 -14
  31. package/dist/{enums-BUKTUB6V.d.ts.map → enums-PcXr3o3J.d.ts.map} +1 -1
  32. package/dist/families.d.ts +24 -26
  33. package/dist/families.d.ts.map +1 -1
  34. package/dist/families.js +3 -4
  35. package/dist/{fit-Cb7naFj6.js → fit-Bpmzep6O.js} +64 -56
  36. package/dist/fit-Bpmzep6O.js.map +1 -0
  37. package/dist/{font-metrics-v5fn7s7e.d.ts → font-metrics-DTppw4t3.d.ts} +62 -38
  38. package/dist/font-metrics-DTppw4t3.d.ts.map +1 -0
  39. package/dist/{grid-DikTjFey.js → grid-DUIMxjfl.js} +23 -26
  40. package/dist/grid-DUIMxjfl.js.map +1 -0
  41. package/dist/{html-dom-Iuog2wdK.js → html-dom-LZCgntnJ.js} +46 -47
  42. package/dist/html-dom-LZCgntnJ.js.map +1 -0
  43. package/dist/html.d.ts +53 -9
  44. package/dist/html.d.ts.map +1 -1
  45. package/dist/html.js +12 -13
  46. package/dist/html.js.map +1 -1
  47. package/dist/index.d.ts +21 -13
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +15 -15
  50. package/dist/index.js.map +1 -1
  51. package/dist/inspect.d.ts +16 -18
  52. package/dist/inspect.d.ts.map +1 -1
  53. package/dist/inspect.js +18 -19
  54. package/dist/inspect.js.map +1 -1
  55. package/dist/{text-anchor-CrYXAfUu.js → lock-attrs-CSQnFDHP.js} +62 -12
  56. package/dist/lock-attrs-CSQnFDHP.js.map +1 -0
  57. package/dist/math.d.ts +2 -4
  58. package/dist/math.d.ts.map +1 -1
  59. package/dist/math.js +12 -13
  60. package/dist/math.js.map +1 -1
  61. package/dist/measure.d.ts +23 -12
  62. package/dist/measure.d.ts.map +1 -1
  63. package/dist/measure.js +3 -3
  64. package/dist/node.d.ts +21 -13
  65. package/dist/node.d.ts.map +1 -1
  66. package/dist/node.js +12 -12
  67. package/dist/node.js.map +1 -1
  68. package/dist/{options-internal-WqgMf720.js → options-internal-BWgmLPdx.js} +4 -5
  69. package/dist/options-internal-BWgmLPdx.js.map +1 -0
  70. package/dist/{package-J49Ck6S2.d.ts → package-CANBWuSm.d.ts} +9 -13
  71. package/dist/package-CANBWuSm.d.ts.map +1 -0
  72. package/dist/{playbtn-CUqQdoDf.js → playbtn-BQZFJir9.js} +4 -5
  73. package/dist/playbtn-BQZFJir9.js.map +1 -0
  74. package/dist/{pres-C6qgOFAa.d.ts → pres-BkEkUAEM.d.ts} +410 -237
  75. package/dist/pres-BkEkUAEM.d.ts.map +1 -0
  76. package/dist/{presentation-DGYlAWhl.js → presentation-4Ggq0_Xa.js} +470 -315
  77. package/dist/presentation-4Ggq0_Xa.js.map +1 -0
  78. package/dist/{presentation-types-8jLQHI4M.d.ts → presentation-types-BgnZR-0a.d.ts} +1119 -468
  79. package/dist/presentation-types-BgnZR-0a.d.ts.map +1 -0
  80. package/dist/read.d.ts +18 -13
  81. package/dist/read.d.ts.map +1 -1
  82. package/dist/read.js +4 -4
  83. package/dist/script.d.ts +116 -65
  84. package/dist/script.d.ts.map +1 -1
  85. package/dist/script.js +2700 -780
  86. package/dist/script.js.map +1 -1
  87. package/dist/{shapes-re0KyQk_.js → shapes-CAPOjU0Q.js} +1564 -491
  88. package/dist/shapes-CAPOjU0Q.js.map +1 -0
  89. package/dist/{slide-Dx2ZeVZ6.d.ts → slide-BmT4kMoO.d.ts} +102 -89
  90. package/dist/slide-BmT4kMoO.d.ts.map +1 -0
  91. package/dist/{slide-size-BalTjFuv.js → slide-size-SkScz1ig.js} +2 -3
  92. package/dist/{slide-size-BalTjFuv.js.map → slide-size-SkScz1ig.js.map} +1 -1
  93. package/dist/{table-dom-BTDP3lEP.js → table-dom-BYga4FYY.js} +4 -5
  94. package/dist/{table-dom-BTDP3lEP.js.map → table-dom-BYga4FYY.js.map} +1 -1
  95. package/dist/{text-sN64Otf_.js → text-CU08xJGs.js} +393 -344
  96. package/dist/text-CU08xJGs.js.map +1 -0
  97. package/dist/{transition-speed-kUEWDWTx.js → transition-speed-CNJ0fSpQ.js} +2 -3
  98. package/dist/{transition-speed-kUEWDWTx.js.map → transition-speed-CNJ0fSpQ.js.map} +1 -1
  99. package/dist/{units-internal-XJlf-hOl.js → units-internal-BR3a4cIi.js} +34 -32
  100. package/dist/units-internal-BR3a4cIi.js.map +1 -0
  101. package/dist/{zip-CKd8ihcf.js → zip-7JTh61LX.js} +8 -10
  102. package/dist/zip-7JTh61LX.js.map +1 -0
  103. package/dist/{zip-C0leZZMj.d.ts → zip-uUjs9Cqx.d.ts} +4 -6
  104. package/dist/zip-uUjs9Cqx.d.ts.map +1 -0
  105. package/dist/zip.d.ts +3 -3
  106. package/dist/zip.js +3 -3
  107. package/dist/{zoom-DPUHh85d.js → zoom-CSSeOwM8.js} +1204 -620
  108. package/dist/zoom-CSSeOwM8.js.map +1 -0
  109. package/package.json +27 -28
  110. package/skills/{ts-pptx-upstream → pptx-ts-upstream}/SKILL.md +37 -84
  111. package/dist/autopage-odPz7zZO.js.map +0 -1
  112. package/dist/binary-string-CKVAYI3M.js.map +0 -1
  113. package/dist/body-insets-Dw_BeWD_.js.map +0 -1
  114. package/dist/clip-Bl01BPcN.d.ts.map +0 -1
  115. package/dist/diagnostics-D8ot4Ei7.d.ts.map +0 -1
  116. package/dist/embedded-fonts-DarT9aoa.d.ts.map +0 -1
  117. package/dist/entry-compose-DCnvBZz2.d.ts.map +0 -1
  118. package/dist/errors-C4oENPcu.js.map +0 -1
  119. package/dist/fit-Cb7naFj6.js.map +0 -1
  120. package/dist/font-metrics-v5fn7s7e.d.ts.map +0 -1
  121. package/dist/grid-DikTjFey.js.map +0 -1
  122. package/dist/html-dom-Iuog2wdK.js.map +0 -1
  123. package/dist/image-size-CvN2iCA4.js.map +0 -1
  124. package/dist/notes-Dh12JAbn.js.map +0 -1
  125. package/dist/options-internal-WqgMf720.js.map +0 -1
  126. package/dist/package-J49Ck6S2.d.ts.map +0 -1
  127. package/dist/playbtn-CUqQdoDf.js.map +0 -1
  128. package/dist/pres-C6qgOFAa.d.ts.map +0 -1
  129. package/dist/presentation-DGYlAWhl.js.map +0 -1
  130. package/dist/presentation-types-8jLQHI4M.d.ts.map +0 -1
  131. package/dist/shapes-re0KyQk_.js.map +0 -1
  132. package/dist/slide-Dx2ZeVZ6.d.ts.map +0 -1
  133. package/dist/table-cell-margins-EVg0EwxT.js.map +0 -1
  134. package/dist/text-anchor-CrYXAfUu.js.map +0 -1
  135. package/dist/text-sN64Otf_.js.map +0 -1
  136. package/dist/units-internal-XJlf-hOl.js.map +0 -1
  137. package/dist/zip-C0leZZMj.d.ts.map +0 -1
  138. package/dist/zip-CKd8ihcf.js.map +0 -1
  139. package/dist/zoom-DPUHh85d.js.map +0 -1
@@ -1,15 +1,15 @@
1
- import { l as warn, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError, u as warnOnce } from "./errors-C4oENPcu.js";
2
- import { A as DEF_CELL_BORDER, B as DEF_TEXT_SHADOW, C as usableTableWidthEmu, D as AXIS_ID_VALUE_PRIMARY, E as AXIS_ID_SERIES_PRIMARY, H as LETTERS, K as PIECHART_COLORS, L as DEF_SHAPE_SHADOW, M as DEF_CHART_GRIDLINE, N as DEF_FONT_COLOR, O as AXIS_ID_VALUE_SECONDARY, S as transparencyToAlpha, T as AXIS_ID_CATEGORY_SECONDARY, _ as resolveCellMarginsInches, b as resolveTableColWidthsEmu, c as inch2Emu, d as marginToEmu, g as ptsToEmuLenient, j as DEF_CHART_BORDER, k as BARCHART_COLORS, l as lineWidthToEmu, n as clampRangedInput, o as fractionToFixedPercent, p as percentToFixedPercent, r as convertAngleUnits, s as getSmartParseNumber, u as mapStated, v as resolveInsetsEmu, w as AXIS_ID_CATEGORY_PRIMARY, x as resolveTableRowHeightEmu, y as resolveSlideMarginsInches } from "./units-internal-XJlf-hOl.js";
3
- import { E as coordToEmu, F as EMU_PER_INCH, I as EMU_PER_POINT, M as pixelsToEmu, _ as isChartType, a as ChartType, b as FIXED_PCT_PER_PERCENT, g as isChartExType, h as connectorPresetFor, m as asChartType, s as PlaceholderType, v as ANGLE_UNITS_PER_DEGREE, w as PERCENT_SCALE } from "./table-cell-margins-EVg0EwxT.js";
4
- import { $ as TICK_MARKS, $t as THEME_REL, A as GROUPINGS, At as NOTES_MASTER_CONTENT_TYPE, B as RADAR_STYLE_ALIAS_NAMES, C as CROSS_BETWEEN, D as ERROR_BAR_DIRECTIONS, Ft as OFFICE_DOCUMENT_REL, G as TEXT_HORZ_OVERFLOW, Ht as RELATIONSHIPS_CONTENT_TYPE, It as OFFICE_REL, K as TEXT_SHAPE_TYPES, L as PRESET_MATERIALS, Lt as PACKAGE_REL, M as LIGHT_RIGS, Mt as NOTES_SLIDE_CONTENT_TYPE, N as LIGHT_RIG_DIRECTIONS, O as ERROR_BAR_TYPES, P as LINE_DATA_SYMBOLS, Pt as OD_CONTENT, Q as TICK_LABEL_POSITIONS, Qt as THEME_CONTENT_TYPE, R as RADAR_STYLES, T as DISPLAY_BLANKS_AS, Tt as MODEL3D_REL, X as TEXT_VERTICAL, _ as BAR_3D_SHAPES, _t as CORE_PROPS_REL, an as PML_ROOT_NS, b as BEVEL_PRESETS, bt as EXTENDED_PROPS_CONTENT_TYPE, ct as CHART_CONTENT_TYPE, d as xsdBool, dt as CHART_STYLE_REL, et as TIME_UNITS, f as xsdBoolIfTrue, ft as COMMENTS_CONTENT_TYPE, g as AXIS_ORIENTATIONS, gt as CORE_PROPS_CONTENT_TYPE, in as OOXML_NS, it as CHARTEX_CONTENT_TYPE, j as LEGEND_POSITIONS, k as ERROR_BAR_VALUE_TYPES, l as checkEnumOrWarn, ln as hasBase64Header, mt as COMMENT_AUTHORS_CONTENT_TYPE, n as getImageSizeFromBase64, on as TABLE_GRAPHIC_DATA_URI, ot as CHART_COLOR_STYLE_CONTENT_TYPE, rn as XLSX_CONTENT_TYPE, st as CHART_COLOR_STYLE_REL, t as fitSrcRectPercents, un as svgMarkupToDataUri, ut as CHART_STYLE_CONTENT_TYPE, v as BAR_DIRECTIONS, x as BUILT_IN_UNITS, xt as EXTENDED_PROPS_REL, y as BAR_GROUPINGS, z as RADAR_STYLE_ALIASES } from "./image-size-CvN2iCA4.js";
5
- import { c as imageExtensionForSource, s as imageContentType, t as TEXT_ANCHOR_BY_VALIGN } from "./text-anchor-CrYXAfUu.js";
6
- import { $ as noStrokeLine, A as graphicFrameEl, B as genXmlParagraphProperties, D as cNvPrEl, E as FALLBACK_PICTURE_LOCKS, F as assertKnownPreset, Ft as nextMediaTarget, H as renderTextParagraphsXml, I as genXmlCustGeom, It as preencodedPath, J as createHyperlinkRels, L as genXmlPresetGeom, Lt as validateObjectName, M as previewPicBody, Mt as getUuid, O as cNvPrHyperlink, Ot as XML_DECL, P as xfrmEl, Q as createLineCap, R as prstGeomRect, St as voidEl, U as clampFontSizeSz, V as groupRunsIntoLines, X as validateHyperlink, Y as registerHyperlinkRel, Z as borderLine, _t as namedColorOr, a as makeXmlNotesSlideRel, b as relsPath, bt as elOrVoid, ct as rejectEmptyFill, d as relationshipsEl, dt as genXmlImageCropRect, et as resolveBorderDash, ft as createShadowEffectLst, g as commentPath, gt as isColorValue, ht as createColorElement, i as makeXmlNotesSlide, it as withLineDefaults, j as grpXfrmEl, jt as getNewRelId, k as genXmlShapeLine, kt as bracedGuid, lt as resolveFillKind, mt as alphaEl, n as makeXmlNotesMaster, nt as strokeDash, ot as genXmlColorSelection, p as NOTES_MASTER_PATH, pt as normalizeShadowOptions, r as makeXmlNotesMasterRel, rt as strokePaint, st as genXmlPatternFill, t as buildNotesSlideRels, tt as resolveDash, u as relationshipEl, ut as STRETCH_FILL_RECT, v as notesSlidePath, vt as rejectEmptyColor, xt as raw, y as overrideName, yt as el, z as genXmlNormAutofit } from "./notes-Dh12JAbn.js";
7
- import { n as setOrClear, t as pickDefined } from "./options-internal-WqgMf720.js";
8
- import { a as CELL_INHERITED_KEYS, i as computeTableLayout, n as measureText, r as requireBoxHeight } from "./fit-Cb7naFj6.js";
9
- import { r as PPTX_CONTENT_TYPE, t as ZipWriter } from "./zip-CKd8ihcf.js";
10
- import { a as resolveSpan, n as tableColCount, o as tableHasHyperlink, r as walkTableGrid, s as withCheckedSpans } from "./grid-DikTjFey.js";
11
- import { t as getSlidesForTableRows } from "./autopage-odPz7zZO.js";
12
- //#region src/gen/define/image-rel.ts
1
+ import { d as warnOnce, n as InternalError, r as InvalidOptionError, s as UnsupportedFeatureError, u as warn } from "./entry-errors-JMthgJ2g.js";
2
+ import { A as DEF_CELL_BORDER, B as DEF_TEXT_SHADOW, C as usableTableWidthEmu, D as AXIS_ID_VALUE_PRIMARY, E as AXIS_ID_SERIES_PRIMARY, H as LETTERS, K as PIECHART_COLORS, L as DEF_SHAPE_SHADOW, M as DEF_CHART_GRIDLINE, N as DEF_FONT_COLOR, O as AXIS_ID_VALUE_SECONDARY, S as transparencyToAlpha, T as AXIS_ID_CATEGORY_SECONDARY, Z as ST_GUID, _ as resolveCellMarginsInches, b as resolveTableColWidthsEmu, d as marginToEmu, g as ptsToEmuLenient, j as DEF_CHART_BORDER, k as BARCHART_COLORS, l as lineWidthToEmu, n as clampRangedInput, o as fractionToFixedPercent, p as percentToFixedPercent, r as convertAngleUnits, s as getSmartParseNumber, u as mapStated, v as resolveInsetsEmu, w as AXIS_ID_CATEGORY_PRIMARY, x as resolveTableRowHeightEmu, y as resolveSlideMarginsInches } from "./units-internal-BR3a4cIi.js";
3
+ import { E as coordToEmu, F as EMU_PER_INCH, I as EMU_PER_POINT, M as pixelsToEmu, b as FIXED_PCT_PER_PERCENT, g as isChartType, h as isChartExType, i as ChartType, m as connectorPresetFor, o as PlaceholderType, p as asChartType, v as ANGLE_UNITS_PER_DEGREE, w as PERCENT_SCALE } from "./enums-BP9wsb9Q.js";
4
+ import { $t as TICK_LABEL_POSITIONS, At as LEGEND_POSITIONS, B as NOTES_SLIDE_CONTENT_TYPE, Bt as RADAR_STYLE_ALIASES, Dt as ERROR_BAR_TYPES, Et as ERROR_BAR_DIRECTIONS, G as PACKAGE_REL, H as OD_CONTENT, It as PLACEHOLDER_TYPES, Kt as TEXT_HORZ_OVERFLOW, M as IMAGE_REL, Mt as LIGHT_RIG_DIRECTIONS, N as MODEL3D_REL, Nt as LINE_DATA_SYMBOLS, O as EXTENDED_PROPS_CONTENT_TYPE, Ot as ERROR_BAR_VALUE_TYPES, R as NOTES_MASTER_CONTENT_TYPE, Rt as PRESET_MATERIALS, S as COMMENT_AUTHORS_CONTENT_TYPE, St as CROSS_BETWEEN, T as CORE_PROPS_REL, U as OFFICE_DOCUMENT_REL, Vt as RADAR_STYLE_ALIAS_NAMES, W as OFFICE_REL, X as RELATIONSHIPS_CONTENT_TYPE, Zt as TEXT_VERTICAL, _t as BAR_DIRECTIONS, an as checkEnumOrWarn, b as COMMENTS_CONTENT_TYPE, bt as BUILT_IN_UNITS, cn as xsdBoolIfTrue, dt as XLSX_CONTENT_TYPE, en as TICK_MARKS, f as CHARTEX_CONTENT_TYPE, ft as OOXML_NS, g as CHART_CONTENT_TYPE, gt as BAR_3D_SHAPES, h as CHART_COLOR_STYLE_REL, hn as svgMarkupToDataUri, ht as AXIS_ORIENTATIONS, i as getImageSizeFromBase64, jt as LIGHT_RIGS, k as EXTENDED_PROPS_REL, kt as GROUPINGS, m as CHART_COLOR_STYLE_CONTENT_TYPE, mn as hasBase64Header, mt as TABLE_GRAPHIC_DATA_URI, n as CHART_METADATA_NS, ot as THEME_CONTENT_TYPE, pn as decodeBase64ToBytes, qt as TEXT_SHAPE_TYPES, r as fitSrcRectPercents, sn as xsdBool, st as THEME_REL, t as CHART_METADATA_EXT_URI, tn as TIME_UNITS, v as CHART_STYLE_CONTENT_TYPE, vt as BAR_GROUPINGS, w as CORE_PROPS_CONTENT_TYPE, wt as DISPLAY_BLANKS_AS, y as CHART_STYLE_REL, yt as BEVEL_PRESETS, zt as RADAR_STYLES } from "./chart-metadata-CwiTTcJq.js";
5
+ import { a as TEXT_ANCHOR_BY_VALIGN, d as imageContentType, f as imageExtensionForSource, i as SHAPE_LOCK_ATTRS, r as PICTURE_LOCK_ATTRS, t as GRAPHIC_FRAME_LOCK_ATTRS } from "./lock-attrs-CSQnFDHP.js";
6
+ import { A as cNvPrEl, At as namedColorOr, B as genXmlCustGeom, Bt as getUuid, C as relsPath, Ct as resolveFillKind, Dt as alphaEl, Et as genXmlImageCropRect, F as previewPicBody, Ft as voidEl, G as groupRunsIntoLines, Gt as validateObjectName, H as prstGeomRect, I as slideTextColor, It as XML_DECL, J as clampFontSizeSz, K as renderTextParagraphsXml, Lt as bracedGuid, M as genXmlShapeLine, Mt as el, N as graphicFrameEl, Nt as elOrVoid, Ot as createColorElement, P as grpXfrmEl, Pt as raw, R as xfrmEl, S as overrideName, St as rejectEmptyFill, Tt as STRETCH_FILL_RECT, U as genXmlNormAutofit, Ut as nextMediaTarget, V as genXmlPresetGeom, W as genXmlParagraphProperties, Wt as preencodedPath, a as makeXmlNotesMaster, at as createLineCap, bt as genXmlColorSelection, c as makeXmlNotesSlideRel, ct as resolveDash, dt as withLineDefaults, ft as createShadowEffectLst, g as NOTES_MASTER_PATH, i as buildNotesSlideRels, it as borderLine, j as cNvPrHyperlink, jt as rejectEmptyColor, k as FALLBACK_PICTURE_LOCKS, kt as isColorValue, lt as strokeDash, m as relationshipsEl, n as makeXmlComments, nt as registerHyperlinkRel, o as makeXmlNotesMasterRel, ot as noStrokeLine, p as relationshipEl, pt as normalizeShadowOptions, r as resolveCommentAuthors, rt as validateHyperlink, s as makeXmlNotesSlide, st as resolveBorderDash, t as makeXmlCommentAuthors, tt as createHyperlinkRels, ut as strokePaint, x as notesSlidePath, xt as genXmlPatternFill, y as commentPath, z as assertKnownPreset, zt as getNewRelId } from "./comments-CKIZYRbZ.js";
7
+ import { n as setOrClear, t as pickDefined } from "./options-internal-BWgmLPdx.js";
8
+ import { a as CELL_INHERITED_KEYS, i as computeTableLayout, n as measureText, r as requireBoxHeight } from "./fit-Bpmzep6O.js";
9
+ import { r as PPTX_CONTENT_TYPE, t as ZipWriter } from "./zip-7JTh61LX.js";
10
+ import { a as cellHasHyperlink, n as tableColCount, o as resolveSpan, r as walkTableGrid, s as withCheckedSpans } from "./grid-DUIMxjfl.js";
11
+ import { t as getSlidesForTableRows } from "./autopage-DqZ37VpL.js";
12
+ // src/gen/define/image-rel.ts
13
13
  /**
14
14
  * Resolve a caller's `{ path, data }` to the source an image media rel is registered from, or say
15
15
  * why there is none.
@@ -69,7 +69,7 @@ function pushMediaRel(target, source) {
69
69
  /**
70
70
  * Push an image media rel onto `target`, reusing an identical source's package part.
71
71
  *
72
- * Three definers need it — an image *fill* on a shape or text box (`registerImageFillMedia`), an
72
+ * Three definers need it: an image *fill* on a shape or text box (`registerImageFillMedia`), an
73
73
  * `addImage()` raster (`addImageDefinition`), and the cached preview raster a Zoom tile, an OLE
74
74
  * object or a 3D model is drawn from (`registerPreviewImage`). See {@link MediaRelSource.dedupe} for the match.
75
75
  * @param target - slide (or layout/master) the rel is registered on
@@ -81,8 +81,8 @@ function registerImageMediaRel(target, source, relId) {
81
81
  kind: "image",
82
82
  extn: source.extn,
83
83
  type: imageContentType(source.extn),
84
- path: source.path || "",
85
- data: source.data || "",
84
+ path: source.path,
85
+ data: source.data,
86
86
  rId: relId,
87
87
  dedupe: true
88
88
  });
@@ -140,17 +140,16 @@ function registerSvgImageRels(target, source, pinned) {
140
140
  svgRid
141
141
  };
142
142
  }
143
- //#endregion
144
- //#region src/gen/define/object-name.ts
143
+ // src/gen/define/object-name.ts
145
144
  /**
146
- * Take the next slide-wide index for `type`'s default Selection Pane name — 0-based here, and
145
+ * Take the next slide-wide index for `type`'s default Selection Pane name: 0-based here, and
147
146
  * offset to the 1-based name by {@link resolveObjectName}.
148
147
  *
149
148
  * Default names used to be derived by counting the matching objects already in
150
149
  * `target._slideObjects`. `buildGroupObject` splices group children back out of that array, so the
151
150
  * count never advanced past them and a later top-level object reused a grouped child's name. This
152
151
  * counter is immune to the splice: every object of a kind consumes an index when it is added,
153
- * whether it stays top-level or moves into a group — at any nesting depth, since `target` stays the
152
+ * whether it stays top-level or moves into a group, at any nesting depth, since `target` stays the
154
153
  * slide all the way down.
155
154
  *
156
155
  * Shapes and text boxes deliberately share the `text` bucket (both are `_type === text`), which is
@@ -169,7 +168,7 @@ function nextObjectNameIdx(target, type) {
169
168
  }
170
169
  /**
171
170
  * The Selection Pane name an object takes: the caller's, validated and kept as they wrote it, or the
172
- * next default for its kind — `Shape 1`, `Image 1`, `Group 1`, `Slide Zoom 1`, …
171
+ * next default for its kind: `Shape 1`, `Image 1`, `Group 1`, `Slide Zoom 1`, …
173
172
  *
174
173
  * The name is stored raw and escaped once, when `cNvPrOpen` writes it. It used to be escaped here,
175
174
  * so any path that handed a stored name back in as a supplied one escaped it a second time: a layout
@@ -177,7 +176,7 @@ function nextObjectNameIdx(target, type) {
177
176
  *
178
177
  * Eleven definers wrote this out, and the index base they appended used to disagree: six counted
179
178
  * from 0 (`Shape 0`, `Text 0`, `Image 0`, `Connector 0`, `Media 0`, `Table 0`), four from 1
180
- * (`Group 1`, `Object 1`, `3D Model 1`, and the zoom tiles), and `addChart` neither — it derived
179
+ * (`Group 1`, `Object 1`, `3D Model 1`, and the zoom tiles), and `addChart` neither: it derived
181
180
  * `Chart 0` by counting the chart objects already on the slide, which is the numbering this
182
181
  * counter exists to replace ({@link nextObjectNameIdx}).
183
182
  *
@@ -187,15 +186,15 @@ function nextObjectNameIdx(target, type) {
187
186
  * name outside this counter is the slide-number placeholder, which the slide emitter writes as
188
187
  * `Slide Number Placeholder 0`.
189
188
  *
190
- * The index is taken unconditionally — including when the caller supplied a name — so an object's
189
+ * The index is taken unconditionally, including when the caller supplied a name, so an object's
191
190
  * index is its ordinal among its kind. See {@link nextObjectNameIdx}.
192
191
  *
193
192
  * @param target - slide (or master) the object is being added to
194
193
  * @param type - the object's `_type`, which selects the counter bucket
195
194
  * @param spec - `label` opens the default name, `kind` names the API in a validation warning, and
196
195
  * `supplied` is the caller's own name when they gave one. `fallback` replaces the `label N`
197
- * default for a kind that has a better one to offer — a placeholder is named after the
198
- * placeholder it fills — and is used as given, since it is the library's own string rather than
196
+ * default for a kind that has a better one to offer (a placeholder is named after the
197
+ * placeholder it fills) and is used as given, since it is the library's own string rather than
199
198
  * the caller's and has nothing to validate.
200
199
  */
201
200
  function resolveObjectName(target, type, spec) {
@@ -203,8 +202,7 @@ function resolveObjectName(target, type, spec) {
203
202
  if (spec.supplied) return validateObjectName(spec.supplied, spec.kind);
204
203
  return spec.fallback ?? `${spec.label} ${idx + 1}`;
205
204
  }
206
- //#endregion
207
- //#region src/families/shared.ts
205
+ // src/families/shared.ts
208
206
  /** Which family supplies each slide method, as data, so a program can name a family it never linked. */
209
207
  const SLIDE_METHOD_FAMILIES = Object.freeze({
210
208
  addAnimation: "animations",
@@ -233,7 +231,7 @@ const PRESENTATION_METHOD_FAMILIES = Object.freeze({
233
231
  tableToSlides: "table"
234
232
  });
235
233
  /**
236
- * Which family supplies each child descriptor, as data — the counterpart to
234
+ * Which family supplies each child descriptor, as data. It is the counterpart to
237
235
  * {@link SLIDE_METHOD_FAMILIES}, and for the same reason: a descriptor key that reaches a
238
236
  * presentation composed without its family has to be able to name the family it is missing.
239
237
  *
@@ -300,18 +298,17 @@ function requirePresentationAuthor(authors, method) {
300
298
  if (!author) familyMethodUnavailable(`pptx.${method}`, PRESENTATION_METHOD_FAMILIES[method]);
301
299
  return author;
302
300
  }
303
- //#endregion
304
- //#region src/gen/define/group.ts
301
+ // src/gen/define/group.ts
305
302
  /**
306
303
  * Dispatch a key-tagged child-object descriptor (`{ text }`, `{ image }`, `{ shape }`, …) to the
307
304
  * family that recognizes it. Shared by `createSlideMaster` (slide master `objects`) and
308
305
  * `addGroupDefinition` (group children) so the descriptor mapping lives in one place.
309
306
  *
310
307
  * The mapping is handed in rather than spelled here. It used to be an `if` chain naming four
311
- * `add*Definition` functions, which put the chart definer — and every plot module under it — in the
308
+ * `add*Definition` functions, which put the chart definer (and every plot module under it) in the
312
309
  * graph of any program that can define a slide master, which is all of them.
313
310
  *
314
- * `placeholder` is intentionally not handled here — it is master-specific and needs the object's
311
+ * `placeholder` is intentionally not handled here: it is master-specific and needs the object's
315
312
  * index for `_placeholderIdx`, so `createSlideMaster` handles that case itself.
316
313
  * @param target - slide (or master) the object is appended to
317
314
  * @param object - the child descriptor
@@ -331,7 +328,7 @@ function addChildDefinition(target, object, children) {
331
328
  * Warn about a child descriptor {@link addChildDefinition} did not author, from `call`.
332
329
  *
333
330
  * Two conditions arrive here and they have different fixes, so they get different codes. A key
334
- * {@link CHILD_DESCRIPTOR_FAMILIES} claims is valid and typed and was simply left uncomposed —
331
+ * {@link CHILD_DESCRIPTOR_FAMILIES} claims is valid and typed and was simply left uncomposed:
335
332
  * the family that would have drawn it is not in this presentation's list, so the message names it
336
333
  * the way `familyMethodUnavailable` names the family behind a missing method. Any other key is a
337
334
  * typo, which is all this walk used to be able to say, because before the split a descriptor that
@@ -352,7 +349,7 @@ function warnUnauthoredChild(object, call) {
352
349
  * group itself to the slide. Nested `group` children recurse, so a group can contain other groups.
353
350
  *
354
351
  * An identity child coordinate space is kept at every depth (emitted in `gen/slide/object.ts` as
355
- * `chOff/chExt == off/ext`), so children — including descendants of nested groups — keep their
352
+ * `chOff/chExt == off/ext`), so children, including descendants of nested groups, keep their
356
353
  * slide-absolute coordinates and grouping is visually a no-op while making the objects one
357
354
  * selectable PowerPoint group. Charts, media, tables, and placeholders are not supported as group
358
355
  * children yet; each is skipped with a warning. When `opts.x/y/w/h` are omitted the group's bounds
@@ -390,7 +387,7 @@ function buildGroupObject(target, children, opts, childAuthors) {
390
387
  * Wrap already-built child render-objects in a group (`<p:grpSp>`) render-object, without appending
391
388
  * the group anywhere. Shared by `buildGroupObject` (children built from descriptors) and
392
389
  * `groupObjectsDefinition` (children lifted off the slide) so both entry points name and frame a
393
- * group identically — including the all-or-nothing frame, which is left to `gen/slide/object.ts` to resolve:
390
+ * group identically, including the all-or-nothing frame, which is left to `gen/slide/object.ts` to resolve:
394
391
  * passing `x/y/w/h` through unset is what makes the bounds auto-compute to the children's bounding
395
392
  * box, so neither caller needs bounds math of its own.
396
393
  *
@@ -437,7 +434,7 @@ function addGroupDefinition(target, children, opts, childAuthors) {
437
434
  }
438
435
  /**
439
436
  * Object kinds `groupObjects()` accepts. Text (which shapes and text boxes both are), images,
440
- * connectors, and groups — the last so consumers can build nested logical groups out of groups they
437
+ * connectors, and groups; the last so consumers can build nested logical groups out of groups they
441
438
  * already made. Charts, media, tables, and placeholders are excluded for the same reason
442
439
  * `addGroup()` excludes them (rels/id/transform work pending); a placeholder is excluded on top of
443
440
  * that because grouping it would sever the layout inheritance that makes it a placeholder.
@@ -450,8 +447,8 @@ const GROUPABLE_TYPES = [
450
447
  ];
451
448
  /**
452
449
  * Whether `groupObjects()` would accept this object, given only what it is. The remaining reasons a
453
- * call can still fail are about the *selection* rather than the object — an unresolved, duplicated
454
- * or ambiguous name — so a consumer cannot decide those from one object either way.
450
+ * call can still fail are about the *selection* rather than the object (an unresolved, duplicated
451
+ * or ambiguous name), so a consumer cannot decide those from one object either way.
455
452
  *
456
453
  * Exported because `Slide.objects` reports it as `canGroup`, and a consumer that had to re-state the
457
454
  * rule would be pinning a copy of the list above: it would keep refusing the day grouping learns a
@@ -478,14 +475,14 @@ function findNameInGroups(objects, name) {
478
475
  * renderers: the objects already exist, so replaying their descriptors just to group them would mean
479
476
  * every renderer exposing its internals.
480
477
  *
481
- * Grouping is visually a no-op — children keep their slide-absolute geometry, their ids, their rels,
478
+ * Grouping is visually a no-op: children keep their slide-absolute geometry, their ids, their rels,
482
479
  * and their relative z-order, exactly as with `addGroup()`. Two ordering rules make that true:
483
480
  * children are ordered by their existing slide z-order (**not** by the order they are named, which
484
481
  * would silently restack the slide), and the group itself takes the topmost member's former slot, so
485
482
  * it lands where the selection's top edge already was.
486
483
  *
487
484
  * Every failure here throws rather than warns. An unmatched name is not a degenerate deck the author
488
- * might still want — it means the intended object is silently still loose on the slide, which is the
485
+ * might still want. It means the intended object is silently still loose on the slide, which is the
489
486
  * footgun the group was meant to remove.
490
487
  * @param target - slide holding the objects
491
488
  * @param objectNames - `objectName`s of the top-level objects to group
@@ -505,12 +502,12 @@ function groupObjectsDefinition(target, objectNames, opts) {
505
502
  const [obj, ambiguous] = matches;
506
503
  if (!obj) {
507
504
  const hint = findNameInGroups(target._slideObjects, name) ? "it is already inside a group (an object can only belong to one group)" : "no top-level object on this slide has that objectName";
508
- throw new InvalidOptionError("group/unresolved-object-name", `groupObjects(): cannot group "${name}" — ${hint}.`);
505
+ throw new InvalidOptionError("group/unresolved-object-name", `groupObjects(): cannot group "${name}": ${hint}.`);
509
506
  }
510
- if (ambiguous) throw new InvalidOptionError("group/ambiguous-object-name", `groupObjects(): objectName "${name}" is ambiguous — ${matches.length} objects on this slide share it. Give them unique objectNames.`);
507
+ if (ambiguous) throw new InvalidOptionError("group/ambiguous-object-name", `groupObjects(): objectName "${name}" is ambiguous: ${matches.length} objects on this slide share it. Give them unique objectNames.`);
511
508
  if (!isGroupableObject(obj)) {
512
509
  const kind = obj.options?.placeholder ? "placeholder" : obj._type;
513
- throw new UnsupportedFeatureError("group/kind-not-groupable", `groupObjects(): cannot group "${name}" — grouping a ${String(kind)} is not supported yet.`);
510
+ throw new UnsupportedFeatureError("group/kind-not-groupable", `groupObjects(): cannot group "${name}": grouping a ${String(kind)} is not supported yet.`);
514
511
  }
515
512
  members.push(obj);
516
513
  });
@@ -522,8 +519,7 @@ function groupObjectsDefinition(target, objectNames, opts) {
522
519
  regrouped.splice(insertAt, 0, makeGroupObject(target, children, opts));
523
520
  target._slideObjects.splice(0, target._slideObjects.length, ...regrouped);
524
521
  }
525
- //#endregion
526
- //#region src/gen/slide/shape-ids.ts
522
+ // src/gen/slide/shape-ids.ts
527
523
  /**
528
524
  * The four `SlideObjectType` members that live in `_slideObjects` without drawing anything on the
529
525
  * slide: speaker notes belong to the notes part, a table cell is rendered by its owning table, a
@@ -573,9 +569,9 @@ function shapeIdCount(obj) {
573
569
  * map names a shape that exists.
574
570
  *
575
571
  * This **mirrors** the allocation in `slideObjectToXml`, which hands out ids as it walks the tree.
576
- * A reference that must name an id *before* the walk reaches it — a connector's `<a:stCxn>`, an
577
- * animation's `<p:spTgt spid>` — cannot wait for that, so it resolves through this map instead.
578
- * The two must stay in step: `test/regression/shape/group-shapes.test.js` parses the emitted `cNvPr` ids
572
+ * A reference that must name an id *before* the walk reaches it (a connector's `<a:stCxn>`, an
573
+ * animation's `<p:spTgt spid>`) cannot wait for that, so it resolves through this map instead.
574
+ * The two must stay in step: `test/regression/shape/group-shapes.test.ts` parses the emitted `cNvPr` ids
579
575
  * back out and asserts each reference points at the shape it names, so drift fails there.
580
576
  * @param slideObjects - the slide's top-level objects
581
577
  * @returns each object's `<p:cNvPr>` id, keyed by object identity, in id order
@@ -623,10 +619,9 @@ function resolveObjectNameToId(shapeIds, objectName) {
623
619
  for (const [obj, id] of shapeIds) if (obj.options?.objectName === objectName) return id;
624
620
  return null;
625
621
  }
626
- //#endregion
627
- //#region src/gen/drawingml/text-body.ts
622
+ // src/gen/drawingml/text-body.ts
628
623
  /**
629
- * ts-pptx: DrawingML text body
624
+ * pptx-ts: DrawingML text body
630
625
  *
631
626
  * The container layer over `text-run.ts`: body properties (`<a:bodyPr>`), the
632
627
  * full `<p:txBody>`/`<a:txBody>` builder (`genXmlTextBody`), the native-equation
@@ -640,7 +635,7 @@ const PLACEHOLDER_TYPE_MAP = PlaceholderType;
640
635
  */
641
636
  function genXmlBodyProperties(slideObject) {
642
637
  if (slideObject._type === "tablecell") return voidEl("a:bodyPr");
643
- if (!slideObject || slideObject._type !== "text" && slideObject._type !== "placeholder") return el("a:bodyPr", {
638
+ if (slideObject._type !== "text" && slideObject._type !== "placeholder") return el("a:bodyPr", {
644
639
  wrap: "square",
645
640
  rtlCol: "0"
646
641
  });
@@ -679,12 +674,12 @@ function genXmlBodyProperties(slideObject) {
679
674
  * nothing usable.
680
675
  *
681
676
  * `null` means "no answer here", not "omit the attribute": each call site then applies its own
682
- * default — the text definer's is `ctr`, while a table cell and the slide-number placeholder
677
+ * default. The text definer's is `ctr`, while a table cell and the slide-number placeholder
683
678
  * leave the attribute off and inherit.
684
679
  *
685
680
  * `ST_TextAnchoringType` is an enumeration, so a string outside it makes PowerPoint report the
686
- * package as needing repair. Typed callers are unaffected — `VAlign` is
687
- * `'top' | 'middle' | 'bottom'` — and a JavaScript caller passing something else now gets a
681
+ * package as needing repair. Typed callers are unaffected (`VAlign` is
682
+ * `'top' | 'middle' | 'bottom'`), and a JavaScript caller passing something else now gets a
688
683
  * diagnostic instead of an attribute the schema rejects.
689
684
  * @param valign - the caller's `valign`, in any of the spellings above
690
685
  */
@@ -704,6 +699,7 @@ function objectHasMath(slideObj) {
704
699
  /**
705
700
  * Generate the XML for text and its options (bold, bullet, etc) including text runs (word-level formatting)
706
701
  * @param {SlideObject|TableCellInternal} slideObj - slideObj or tableCell
702
+ * @param slideColor - the colour a run marked `_slideColor` is written in: the slide's, else black
707
703
  * @note PPT text lines [lines followed by line-breaks] are created using <p>-aragraph's
708
704
  * @note Bullets are a paragragh-level formatting device
709
705
  * @template
@@ -723,18 +719,18 @@ function objectHasMath(slideObj) {
723
719
  * </p:txBody>
724
720
  * @returns XML containing the param object's text and formatting
725
721
  */
726
- function genXmlTextBody(slideObj) {
722
+ function genXmlTextBody(slideObj, slideColor = DEF_FONT_COLOR) {
727
723
  const opts = slideObj.options || {};
728
724
  let tmpTextObjects = [];
729
725
  const arrTextObjects = [];
730
726
  let strSlideXml = "";
731
727
  strSlideXml += genXmlBodyProperties(slideObj);
732
728
  if (opts.h === 0 && opts.line && opts.align) strSlideXml += el("a:lstStyle", null, raw(voidEl("a:lvl1pPr", { algn: "l" })));
733
- else if (slideObj._type === "placeholder") strSlideXml += el("a:lstStyle", null, raw(genXmlParagraphProperties(slideObj, true)));
729
+ else if (slideObj._type === "placeholder" && !slideObj._seeded) strSlideXml += el("a:lstStyle", null, raw(genXmlParagraphProperties(slideObj, true)));
734
730
  else strSlideXml += voidEl("a:lstStyle");
735
731
  if (typeof slideObj.text === "string" || typeof slideObj.text === "number") tmpTextObjects.push({
736
732
  text: slideObj.text.toString(),
737
- options: opts || {}
733
+ options: opts
738
734
  });
739
735
  else if (Array.isArray(slideObj.text)) tmpTextObjects = slideObj.text.map((item) => {
740
736
  const projected = {};
@@ -746,8 +742,8 @@ function genXmlTextBody(slideObj) {
746
742
  });
747
743
  tmpTextObjects.forEach((itext, idx) => {
748
744
  if (!itext.text) itext.text = "";
749
- itext.options = itext.options || opts || {};
750
- if (idx === 0 && itext.options && !itext.options.bullet && opts.bullet) itext.options.bullet = opts.bullet;
745
+ itext.options = itext.options || opts;
746
+ if (idx === 0 && !itext.options.bullet && opts.bullet) itext.options.bullet = opts.bullet;
751
747
  if (typeof itext.text === "string" || typeof itext.text === "number") itext.text = itext.text.toString().replace(/\r*\n/g, "\r\n");
752
748
  if (itext.text.includes("\r\n") && itext.text.match(/\n$/g) === null) {
753
749
  const lines = itext.text.split("\r\n");
@@ -762,35 +758,38 @@ function genXmlTextBody(slideObj) {
762
758
  });
763
759
  } else arrTextObjects.push({
764
760
  ...itext,
765
- options: itext.options ?? {}
761
+ options: itext.options
766
762
  });
767
763
  });
768
764
  const arrLines = groupRunsIntoLines(arrTextObjects, opts);
769
- strSlideXml += renderTextParagraphsXml(arrLines, slideObj, opts);
765
+ strSlideXml += renderTextParagraphsXml(arrLines, slideObj, opts, slideColor);
770
766
  if (!strSlideXml.includes("<a:p>")) strSlideXml += el("a:p", null, raw(voidEl("a:endParaRPr")));
771
767
  return el(slideObj._type === "tablecell" ? "a:txBody" : "p:txBody", null, raw(strSlideXml));
772
768
  }
773
769
  /**
774
770
  * Generate an XML Placeholder
775
771
  * @param {SlideObject} placeholderObj
772
+ * @param binding - the `type` and `idx` the slide object states itself, each winning over
773
+ * `placeholderObj`'s; with one, a `p:ph` is written even when `placeholderObj` is `null`
774
+ * @param definition - `placeholderObj` is the layout or master placeholder being written, not the
775
+ * one a slide object fills
776
776
  * @returns XML
777
777
  */
778
- function genXmlPlaceholder(placeholderObj) {
779
- if (!placeholderObj) return "";
780
- const placeholderIdx = placeholderObj.options?._placeholderIdx ? placeholderObj.options._placeholderIdx : "";
781
- const placeholderTyp = placeholderObj.options?._placeholderType ? placeholderObj.options._placeholderType : "";
782
- const placeholderType = PLACEHOLDER_TYPE_MAP[placeholderTyp] ? PLACEHOLDER_TYPE_MAP[placeholderTyp].toString() : Object.values(PlaceholderType).includes(placeholderTyp) ? placeholderTyp : "";
783
- const isPlaceholderDef = placeholderObj._type === "placeholder";
778
+ function genXmlPlaceholder(placeholderObj, binding, definition = false) {
779
+ if (!placeholderObj && !binding) return "";
780
+ const placeholderIdx = binding?.idx ?? (placeholderObj?.options?._placeholderIdx || "");
781
+ const placeholderTyp = placeholderObj?.options?._placeholderType ? placeholderObj.options._placeholderType : "";
782
+ const placeholderType = binding?.type ?? (PLACEHOLDER_TYPE_MAP[placeholderTyp] ? PLACEHOLDER_TYPE_MAP[placeholderTyp].toString() : Object.values(PlaceholderType).includes(placeholderTyp) || placeholderObj?._type === "placeholder" && PLACEHOLDER_TYPES.includes(placeholderTyp) ? placeholderTyp : "");
783
+ const hasCustomPrompt = definition && placeholderObj?._type === "placeholder" && (placeholderObj.text ?? []).some((run) => typeof run.text === "string" && run.text.length > 0);
784
784
  return `<p:ph
785
- ${placeholderIdx ? " idx=\"" + placeholderIdx.toString() + "\"" : ""}
785
+ ${placeholderIdx !== "" ? " idx=\"" + placeholderIdx.toString() + "\"" : ""}
786
786
  ${placeholderType ? ` type="${placeholderType}"` : ""}
787
- ${isPlaceholderDef && placeholderObj.text && placeholderObj.text.length > 0 ? " hasCustomPrompt=\"1\"" : ""}
787
+ ${hasCustomPrompt ? " hasCustomPrompt=\"1\"" : ""}
788
788
  />`;
789
789
  }
790
- //#endregion
791
- //#region src/gen/define/frame.ts
790
+ // src/gen/define/frame.ts
792
791
  /**
793
- * ts-pptx: an authored object's frame
792
+ * pptx-ts: an authored object's frame
794
793
  *
795
794
  * Every definer used to spell its own default for an omitted `x`/`y`/`w`/`h`, and they disagreed
796
795
  * on what "omitted" meant. A shape tested `x || (x === 0 ? 0 : 1)`, media `|| 2`, an image `|| 1`
@@ -847,19 +846,43 @@ function resolveAuthoredFrame(given, defaults, api, zeroExtentAllowed = false) {
847
846
  }
848
847
  return frame;
849
848
  }
850
- //#endregion
851
- //#region src/gen/define/layout-placeholder.ts
849
+ // src/gen/define/layout-placeholder.ts
850
+ /** The layout placeholder name a `placeholder` option states: the string, or a binding's `name`. */
851
+ function layoutPlaceholderName(option) {
852
+ return typeof option === "object" && option !== null ? option.name : option;
853
+ }
852
854
  /**
853
- * The layout placeholder named `name`: the first `placeholder` object on the layout whose
854
- * `placeholder` option is `name`.
855
+ * The binding a `placeholder` option states its `p:ph` with, or `undefined` when it states neither
856
+ * `type` nor `idx` and so binds by name alone, exactly as the string does.
857
+ */
858
+ function statedPlaceholderBinding(option) {
859
+ if (typeof option !== "object" || option === null) return void 0;
860
+ return option.type !== void 0 || option.idx !== void 0 ? option : void 0;
861
+ }
862
+ /**
863
+ * Throw on a binding whose `idx` or `type` has no `p:ph` spelling, so a bad value fails where it
864
+ * was written rather than dropping out of the slide XML.
865
+ * @param option - the slide object's `placeholder` option
866
+ * @param label - the option's owner, as an error message names it (`addText`, `addImage`)
867
+ */
868
+ function checkPlaceholderBinding(option, label) {
869
+ if (typeof option !== "object" || option === null) return;
870
+ const { idx, type } = option;
871
+ if (idx !== void 0 && !(Number.isInteger(idx) && idx >= 0 && idx <= 4294967295)) throw new InvalidOptionError("placeholder/invalid-idx", `${label} placeholder.idx must be an integer from 0 to 4294967295 (got ${String(idx)}).`);
872
+ if (type !== void 0 && !PLACEHOLDER_TYPES.includes(type)) throw new InvalidOptionError("placeholder/invalid-type", `${label} placeholder.type must be one of ${PLACEHOLDER_TYPES.join(", ")} (got ${String(type)}).`);
873
+ }
874
+ /**
875
+ * The layout placeholder a `placeholder` option names: the first `placeholder` object on the
876
+ * layout whose `placeholder` option is that name.
855
877
  *
856
878
  * Only placeholder objects qualify. A layout text box can carry a `placeholder` option too, but it is
857
879
  * not a placeholder a slide can bind a `<p:ph>` to or inherit from.
858
880
  * @param layout - the slide's layout, if it has one
859
- * @param name - the placeholder name the slide object states, if any
881
+ * @param option - the slide object's `placeholder` option, if any
860
882
  * @returns the layout placeholder, or `null` when there is none
861
883
  */
862
- function findLayoutPlaceholder(layout, name) {
884
+ function findLayoutPlaceholder(layout, option) {
885
+ const name = layoutPlaceholderName(option);
863
886
  if (!layout?._slideObjects || !name) return null;
864
887
  return layout._slideObjects.find((obj) => obj._type === "placeholder" && obj.options?.placeholder === name) ?? null;
865
888
  }
@@ -871,11 +894,11 @@ function findLayoutPlaceholder(layout, name) {
871
894
  * treated a `null` axis as unstated and the table did not, so `x: null` put an image at the
872
895
  * placeholder's left edge and a table at the default half inch.
873
896
  * @param layout - the slide's layout, if it has one
874
- * @param name - the placeholder name the slide object states, if any
897
+ * @param option - the slide object's `placeholder` option, if any
875
898
  * @returns the placeholder's axes, each absent when it states none or there is no such placeholder
876
899
  */
877
- function placeholderFrame(layout, name) {
878
- const options = findLayoutPlaceholder(layout, name)?.options;
900
+ function placeholderFrame(layout, option) {
901
+ const options = findLayoutPlaceholder(layout, option)?.options;
879
902
  return options ? {
880
903
  x: options.x,
881
904
  y: options.y,
@@ -883,8 +906,7 @@ function placeholderFrame(layout, name) {
883
906
  h: options.h
884
907
  } : {};
885
908
  }
886
- //#endregion
887
- //#region src/gen/define/image.ts
909
+ // src/gen/define/image.ts
888
910
  /** DPI PowerPoint assumes when sizing an inserted raster image (natural pixels / 96 == inches) */
889
911
  const IMAGE_NATURAL_DPI = 96;
890
912
  /**
@@ -931,7 +953,7 @@ function registerImageFillMedia(target, fill) {
931
953
  * Normalize an `addImage()` call into a slide image object and register its media relationships.
932
954
  *
933
955
  * Resolves the image source (path or base64 `data:`), allocates the drawing relationship id(s)
934
- * — SVG needs a second rId for its PNG rasterization fallback — appends the bytes to
956
+ * (SVG needs a second rId for its PNG rasterization fallback), appends the bytes to
935
957
  * `target._relsMedia` (deduping identical sources), and inherits any omitted x/y/w/h from a
936
958
  * matching layout picture placeholder. The resulting `SlideObject` is pushed onto the slide;
937
959
  * `gen/slide/objects/image.ts` later emits the `<p:pic>`.
@@ -940,6 +962,7 @@ function registerImageFillMedia(target, fill) {
940
962
  */
941
963
  function addImageDefinition(target, opt) {
942
964
  const newObject = { _type: "image" };
965
+ checkPlaceholderBinding(opt.placeholder, "addImage");
943
966
  const placeholder = placeholderFrame(target._slideLayout, opt.placeholder);
944
967
  const givenX = opt.x ?? placeholder.x;
945
968
  const givenY = opt.y ?? placeholder.y;
@@ -963,7 +986,6 @@ function addImageDefinition(target, opt) {
963
986
  supplied: opt.objectName
964
987
  });
965
988
  const strImgExtn = source.extn;
966
- newObject._type = "image";
967
989
  newObject.image = strImagePath || preencodedPath("png");
968
990
  let defWidth = givenW;
969
991
  let defHeight = givenH;
@@ -1046,10 +1068,9 @@ function addImageDefinition(target, opt) {
1046
1068
  }
1047
1069
  target._slideObjects.push(newObject);
1048
1070
  }
1049
- //#endregion
1050
- //#region src/gen/define/text.ts
1071
+ // src/gen/define/text.ts
1051
1072
  /**
1052
- * ts-pptx: Text Definition
1073
+ * pptx-ts: Text Definition
1053
1074
  *
1054
1075
  * `addTextDefinition` cleans shape / run options (color, bullets, placeholder inheritance, body
1055
1076
  * properties, columns, align / valign), registers hyperlink + picture-bullet + image-fill rels,
@@ -1064,6 +1085,7 @@ function addImageDefinition(target, opt) {
1064
1085
  * @param {boolean} isPlaceholder whether this a placeholder object
1065
1086
  */
1066
1087
  function addTextDefinition(target, text, opts, isPlaceholder) {
1088
+ checkPlaceholderBinding(opts.placeholder, "addText");
1067
1089
  const owned = /* @__PURE__ */ new Map();
1068
1090
  /**
1069
1091
  * The keys the CALLER wrote on each owned copy, recorded before any default reaches it.
@@ -1100,20 +1122,23 @@ function addTextDefinition(target, text, opts, isPlaceholder) {
1100
1122
  if (!(Boolean(itemOpts.placeholder ?? objectOptions.placeholder) || isPlaceholder)) {
1101
1123
  rejectEmptyColor(itemOpts.color, "color");
1102
1124
  rejectEmptyColor(objectOptions.color, "color");
1103
- setOrClear(itemOpts, "color", itemOpts.color || objectOptions.color || target.color || (itemOpts.hyperlink || objectOptions.hyperlink ? void 0 : "000000"));
1125
+ const linked = Boolean(itemOpts.hyperlink || objectOptions.hyperlink);
1126
+ const shapeColor = linked && !authoredKeys.get(objectOptions)?.has("color") ? void 0 : objectOptions.color;
1127
+ const color = itemOpts.color || shapeColor || void 0;
1128
+ setOrClear(itemOpts, "color", color);
1129
+ setOrClear(itemOpts, "_slideColor", color === void 0 && !linked ? true : void 0);
1104
1130
  }
1105
- if (itemOpts.placeholder || isPlaceholder) itemOpts.bullet = itemOpts.bullet || false;
1106
- if (itemOpts.placeholder && target._slideLayout && target._slideLayout._slideObjects) {
1107
- const placeHold = findLayoutPlaceholder(target._slideLayout, itemOpts.placeholder);
1108
- if (placeHold?.options) {
1109
- const stated = authoredKeys.get(itemOpts) ?? /* @__PURE__ */ new Set();
1110
- const inherited = {};
1111
- for (const [key, value] of Object.entries(placeholderOptionsForSlide(placeHold.options))) if (value !== void 0 && !stated.has(key)) inherited[key] = value;
1112
- itemOpts = {
1113
- ...itemOpts,
1114
- ...inherited
1115
- };
1116
- }
1131
+ if (isPlaceholder) itemOpts.bullet = itemOpts.bullet ?? "inherit";
1132
+ else if (itemOpts.placeholder) itemOpts.bullet = itemOpts.bullet || false;
1133
+ const placeHold = findLayoutPlaceholder(target._slideLayout, itemOpts.placeholder);
1134
+ if (placeHold?.options) {
1135
+ const stated = authoredKeys.get(itemOpts) ?? /* @__PURE__ */ new Set();
1136
+ const inherited = {};
1137
+ for (const [key, value] of Object.entries(placeholderOptionsForSlide(placeHold.options))) if (value !== void 0 && !stated.has(key)) inherited[key] = value;
1138
+ itemOpts = {
1139
+ ...itemOpts,
1140
+ ...inherited
1141
+ };
1117
1142
  }
1118
1143
  itemOpts.line = itemOpts.line || {};
1119
1144
  if (itemOpts.shape === "line" && typeof itemOpts.line === "object") itemOpts.line = withLineDefaults(itemOpts.line, "line.color");
@@ -1137,7 +1162,6 @@ function addTextDefinition(target, text, opts, isPlaceholder) {
1137
1162
  if (typeof itemOpts.columnSpacing !== "number" || !Number.isFinite(itemOpts.columnSpacing) || itemOpts.columnSpacing < 0) warn("text/invalid-column-spacing", "text `columnSpacing` must be a number >= 0 (ignoring value)");
1138
1163
  else itemOpts._bodyProp.spcCol = ptsToEmuLenient(itemOpts.columnSpacing);
1139
1164
  }
1140
- if (typeof itemOpts.underline === "boolean" && itemOpts.underline === true) itemOpts.underline = { style: "sng" };
1141
1165
  }
1142
1166
  {
1143
1167
  const align = (itemOpts.align || "").toLowerCase();
@@ -1153,17 +1177,19 @@ function addTextDefinition(target, text, opts, isPlaceholder) {
1153
1177
  }
1154
1178
  newObject.options = cleanOpts(objectOptions);
1155
1179
  if (newObject.shape !== "line") Object.assign(newObject.options, resolveAuthoredFrame(newObject.options, { h: .3 }, "addText"));
1156
- const placeholderName = isPlaceholder ? String(newObject.options.placeholder || newObject.options._placeholderType || `Placeholder ${newObject.options._placeholderIdx ?? target._slideObjects.length}`) : void 0;
1180
+ const placeholderName = isPlaceholder ? String(layoutPlaceholderName(newObject.options.placeholder) || newObject.options._placeholderType || `Placeholder ${newObject.options._placeholderIdx ?? target._slideObjects.length}`) : void 0;
1157
1181
  newObject.options.objectName = resolveObjectName(target, newObject._type, {
1158
1182
  label: "Text",
1159
1183
  kind: "text",
1160
1184
  supplied: newObject.options.objectName,
1161
1185
  ...placeholderName === void 0 ? {} : { fallback: placeholderName }
1162
1186
  });
1163
- if (!isPlaceholder && newObject.options.placeholder && !newObject.options._placeholderType) newObject.options._placeholderType = newObject.options.placeholder;
1164
- textObjects.forEach((item) => item.options = cleanOpts(item.options || {}));
1187
+ const placeholder = newObject.options.placeholder;
1188
+ const fallbackType = statedPlaceholderBinding(placeholder) ? void 0 : layoutPlaceholderName(placeholder);
1189
+ if (!isPlaceholder && fallbackType && !newObject.options._placeholderType) newObject.options._placeholderType = fallbackType;
1190
+ textObjects.forEach((item) => item.options = cleanOpts(item.options));
1165
1191
  createHyperlinkRels(target, newObject);
1166
- createBulletImageRels(target, newObject.options, textObjects);
1192
+ createBulletImageRels(target, [newObject.options, ...textObjects.map((item) => item.options)]);
1167
1193
  if (typeof newObject.options.fill === "object" && resolveFillKind(newObject.options.fill) === "image") registerImageFillMedia(target, newObject.options.fill);
1168
1194
  target._slideObjects.push(newObject);
1169
1195
  }
@@ -1198,22 +1224,33 @@ function placeholderOptionsForSlide(options) {
1198
1224
  return copy;
1199
1225
  }
1200
1226
  /**
1201
- * Register slide media relationships for any picture bullets (`bullet.image`) used by a text object.
1202
- * Picture bullets render as `<a:buBlip><a:blip r:embed="rId.."/></a:buBlip>`, so the bullet image
1203
- * needs the same media-rel + package-part plumbing as `addImage()`. The assigned `rId` is stored on
1204
- * the bullet options object (`_rId`) so XML generation can reference it.
1227
+ * Register slide media relationships for any picture bullets (`bullet.image`) the given option bags
1228
+ * use. Picture bullets render as `<a:buBlip><a:blip r:embed="rId.."/></a:buBlip>`, so the bullet
1229
+ * image needs the same media-rel + package-part plumbing as `addImage()`. The assigned `rId` is
1230
+ * stored on the bullet (`_rId`) so XML generation can reference it.
1231
+ *
1232
+ * The bullet each bag holds is replaced by a copy before anything is stamped on it. The bags are
1233
+ * the definer's own, but the bullet inside one is the caller's object, and an id stamped there
1234
+ * travelled with it: reused in another deck, it was written as an `r:embed` that deck never
1235
+ * declared (#83). One copy per bullet object, so a bullet shared between the shape and its runs
1236
+ * stays one object and registers once.
1205
1237
  * @param {PresSlideInternal} target - slide receiving the rels
1206
- * @param objectOptions - shape-level text options (bullet may live here)
1207
- * @param {TextProps[]} textObjects - per-paragraph text options (bullet may live here too)
1208
- */
1209
- function createBulletImageRels(target, objectOptions, textObjects) {
1210
- const bulletObjs = [];
1211
- const collect = (opts) => {
1212
- if (opts && typeof opts.bullet === "object" && opts.bullet) bulletObjs.push(opts.bullet);
1213
- };
1214
- collect(objectOptions);
1215
- textObjects.forEach((item) => collect(item.options));
1216
- bulletObjs.forEach((bullet) => {
1238
+ * @param bags - the shape-level, table-level, per-paragraph or per-cell options a bullet may live on
1239
+ */
1240
+ function createBulletImageRels(target, bags) {
1241
+ const copies = /* @__PURE__ */ new Map();
1242
+ for (const opts of bags) {
1243
+ if (!opts || typeof opts.bullet !== "object" || !opts.bullet) continue;
1244
+ const source = opts.bullet;
1245
+ if (!source.image) continue;
1246
+ let copy = copies.get(source);
1247
+ if (!copy) {
1248
+ copy = { ...source };
1249
+ copies.set(source, copy);
1250
+ }
1251
+ opts.bullet = copy;
1252
+ }
1253
+ copies.forEach((bullet) => {
1217
1254
  const img = bullet.image;
1218
1255
  if (!img || !img.path && !img.data) return;
1219
1256
  const source = resolveImageSource(img);
@@ -1248,8 +1285,7 @@ function createBulletImageRels(target, objectOptions, textObjects) {
1248
1285
  }
1249
1286
  });
1250
1287
  }
1251
- //#endregion
1252
- //#region src/gen/define/object-options.ts
1288
+ // src/gen/define/object-options.ts
1253
1289
  /**
1254
1290
  * The options an object's slide record carries: its frame, its Selection Pane name, and its alt
1255
1291
  * text and lock flags when the caller stated them.
@@ -1286,8 +1322,7 @@ function framedObjectOptions(target, type, opt, spec) {
1286
1322
  function requirePayloadSource(opt, code, api) {
1287
1323
  if (!opt.path && !opt.data) throw new InvalidOptionError(code, `${api}(): either \`data\` or \`path\` are required!`);
1288
1324
  }
1289
- //#endregion
1290
- //#region src/gen/define/media.ts
1325
+ // src/gen/define/media.ts
1291
1326
  /**
1292
1327
  * One media item costs three consecutive slide rels, allocated together by {@link addMedia}:
1293
1328
  * the ECMA `audio`/`video` rel (the id kept on the object as `mediaRid`), the MS-2007 `media`
@@ -1304,7 +1339,7 @@ const msMediaRid = (mediaRid) => mediaRid + 1;
1304
1339
  const previewRid = (mediaRid) => mediaRid + 2;
1305
1340
  /**
1306
1341
  * Check that a media item's three rels really did come out consecutive. The ids come from
1307
- * three separate `getNewRelId` calls, so nothing but call order makes them so — and every
1342
+ * three separate `getNewRelId` calls, so nothing but call order makes them so, and every
1308
1343
  * reader of the triple assumes it.
1309
1344
  */
1310
1345
  function assertConsecutiveMediaRids(base, second, third) {
@@ -1326,6 +1361,7 @@ function addMediaDefinition(target, opt) {
1326
1361
  if (strData && !hasBase64Header(strData)) throw new InvalidOptionError("media/missing-base64-header", "addMedia(): `data` value lacks a base64 header! Ex: 'video/mpeg;base64,NMP[...]')");
1327
1362
  else if (strCover && !hasBase64Header(strCover)) throw new InvalidOptionError("media/cover-missing-base64-header", "addMedia(): `cover` value lacks a base64 header! Ex: 'data:image/png;base64,iV[...]')");
1328
1363
  if (strType === "online" && !strLink) throw new InvalidOptionError("media/online-missing-link", "addMedia(): online videos require `link` value");
1364
+ if (strType !== "online" && strLink) warn("media/option-not-supported", `addMedia(): \`link\` is read only for \`type: 'online'\`; embedded ${strType} has nowhere to write it, so it was ignored.`);
1329
1365
  const options = framedObjectOptions(target, "media", opt, {
1330
1366
  label: "Media",
1331
1367
  kind: "media",
@@ -1411,8 +1447,7 @@ function addMediaDefinition(target, opt) {
1411
1447
  assertConsecutiveMediaRids(mediaRid, msRid, coverRid);
1412
1448
  target._slideObjects.push(slideData);
1413
1449
  }
1414
- //#endregion
1415
- //#region src/gen/oxml/alternate-content.ts
1450
+ // src/gen/oxml/alternate-content.ts
1416
1451
  /**
1417
1452
  * An `mc:AlternateContent` envelope: a Choice for consumers that understand one namespace, and an
1418
1453
  * optional Fallback for everyone else.
@@ -1435,50 +1470,7 @@ function alternateContentEl(opts) {
1435
1470
  Requires: prefix
1436
1471
  }, raw(opts.choice))), ...opts.fallback === void 0 ? [] : [raw(el("mc:Fallback", null, raw(opts.fallback)))]]);
1437
1472
  }
1438
- //#endregion
1439
- //#region src/gen/drawingml/locks.ts
1440
- const SHAPE_LOCK_ATTRS = [
1441
- "noGrp",
1442
- "noSelect",
1443
- "noRot",
1444
- "noChangeAspect",
1445
- "noMove",
1446
- "noResize",
1447
- "noEditPoints",
1448
- "noAdjustHandles",
1449
- "noChangeArrowheads",
1450
- "noChangeShapeType",
1451
- "noTextEdit"
1452
- ];
1453
- const PICTURE_LOCK_ATTRS = [
1454
- "noGrp",
1455
- "noSelect",
1456
- "noRot",
1457
- "noChangeAspect",
1458
- "noMove",
1459
- "noResize",
1460
- "noEditPoints",
1461
- "noAdjustHandles",
1462
- "noChangeArrowheads",
1463
- "noChangeShapeType",
1464
- "noCrop"
1465
- ];
1466
- const GRAPHIC_FRAME_LOCK_ATTRS = [
1467
- "noGrp",
1468
- "noDrilldown",
1469
- "noSelect",
1470
- "noChangeAspect",
1471
- "noMove",
1472
- "noResize"
1473
- ];
1474
- const GROUP_SHAPE_LOCK_ATTRS = [
1475
- "noGrp",
1476
- "noSelect",
1477
- "noRot",
1478
- "noChangeAspect",
1479
- "noMove",
1480
- "noResize"
1481
- ];
1473
+ // src/gen/drawingml/locks.ts
1482
1474
  /**
1483
1475
  * Serialize an object-lock element (`a:spLocks` / `a:picLocks` / `a:graphicFrameLocks`).
1484
1476
  * Only flags set to `true` AND valid for this element type are emitted; a flag set on an
@@ -1496,8 +1488,7 @@ function genXmlObjectLock(tag, allowed, locks, objectName) {
1496
1488
  const set = allowed.filter((name) => lockMap[name] === true);
1497
1489
  return set.length > 0 ? voidEl(tag, Object.fromEntries(set.map((name) => [name, "1"]))) : "";
1498
1490
  }
1499
- //#endregion
1500
- //#region src/gen/slide/objects/image-extent.ts
1491
+ // src/gen/slide/objects/image-extent.ts
1501
1492
  /**
1502
1493
  * An image's natural size in pixels, measured from its embedded media.
1503
1494
  *
@@ -1508,7 +1499,7 @@ function genXmlObjectLock(tag, allowed, locks, objectName) {
1508
1499
  * @returns the natural size, or `null` when the media is not loaded or cannot be measured
1509
1500
  */
1510
1501
  function imageNaturalSize(obj, slide) {
1511
- const relData = (slide._relsMedia || []).find((rel) => rel.rId === obj.imageRid)?.data;
1502
+ const relData = slide._relsMedia.find((rel) => rel.rId === obj.imageRid)?.data;
1512
1503
  return typeof relData === "string" ? getImageSizeFromBase64(relData) : null;
1513
1504
  }
1514
1505
  /**
@@ -1552,14 +1543,13 @@ function resolveImageExtent(obj, slide, frame) {
1552
1543
  drawnH: sizing.h ? getSmartParseNumber(sizing.h, "Y", slide._presLayout) : frameH
1553
1544
  };
1554
1545
  }
1555
- //#endregion
1556
- //#region src/gen/oxml/fmt-scheme.ts
1546
+ // src/gen/oxml/fmt-scheme.ts
1557
1547
  /**
1558
- * ts-pptx: the `<a:fmtScheme>` block, shared by the two themes this library writes.
1548
+ * pptx-ts: the `<a:fmtScheme>` block, shared by the two themes this library writes.
1559
1549
  *
1560
1550
  * The fill/line/effect/background style matrices that shape style indices (`<p:style>`) point
1561
- * at. Fixed Office boilerplate: no caller data reaches it, so — unlike the `<a:clrScheme>` and
1562
- * `<a:fontScheme>` blocks beside it in `gen/pres/theme.ts` — there is no escaping risk to remove
1551
+ * at. Fixed Office boilerplate: no caller data reaches it, so, unlike the `<a:clrScheme>` and
1552
+ * `<a:fontScheme>` blocks beside it in `gen/pres/theme.ts`, there is no escaping risk to remove
1563
1553
  * by rebuilding it node by node, and it stays a raw literal rather than ~90 nested `el()` calls
1564
1554
  * written for uniformity alone.
1565
1555
  *
@@ -1570,8 +1560,7 @@ function resolveImageExtent(obj, slide, frame) {
1570
1560
  * @raw-xml-asset
1571
1561
  */
1572
1562
  const FMT_SCHEME_XML = "<a:fmtScheme name=\"Office\"><a:fillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"110000\"/><a:satMod val=\"105000\"/><a:tint val=\"67000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"105000\"/><a:satMod val=\"103000\"/><a:tint val=\"73000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"105000\"/><a:satMod val=\"109000\"/><a:tint val=\"81000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:satMod val=\"103000\"/><a:lumMod val=\"102000\"/><a:tint val=\"94000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:satMod val=\"110000\"/><a:lumMod val=\"100000\"/><a:shade val=\"100000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"99000\"/><a:satMod val=\"120000\"/><a:shade val=\"78000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln><a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln><a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad=\"57150\" dist=\"19050\" dir=\"5400000\" algn=\"ctr\" rotWithShape=\"0\"><a:srgbClr val=\"000000\"><a:alpha val=\"63000\"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:solidFill><a:schemeClr val=\"phClr\"><a:tint val=\"95000\"/><a:satMod val=\"170000\"/></a:schemeClr></a:solidFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"93000\"/><a:satMod val=\"150000\"/><a:shade val=\"98000\"/><a:lumMod val=\"102000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:tint val=\"98000\"/><a:satMod val=\"130000\"/><a:shade val=\"90000\"/><a:lumMod val=\"103000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"63000\"/><a:satMod val=\"120000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill></a:bgFillStyleLst></a:fmtScheme>";
1573
- //#endregion
1574
- //#region src/gen/chart/part-names.ts
1563
+ // src/gen/chart/part-names.ts
1575
1564
  /**
1576
1565
  * The names for the chart with package-wide id `globalId`.
1577
1566
  * @param globalId - the chart's id, unique across every chart part in the package
@@ -1588,10 +1577,9 @@ function chartPartNames(globalId, isChartEx) {
1588
1577
  workbookName: `Microsoft_Excel_Worksheet${globalId}.xlsx`
1589
1578
  };
1590
1579
  }
1591
- //#endregion
1592
- //#region src/gen/opc/core.ts
1580
+ // src/gen/opc/core.ts
1593
1581
  /**
1594
- * ts-pptx: `docProps/core.xml`
1582
+ * pptx-ts: `docProps/core.xml`
1595
1583
  *
1596
1584
  * Emit the core-properties part (title/subject/creator/revision and the
1597
1585
  * created/modified timestamps).
@@ -1611,7 +1599,7 @@ const CORE_PROPS_NS = {
1611
1599
  "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance"
1612
1600
  };
1613
1601
  /**
1614
- * Now, as `dcterms:W3CDTF` without milliseconds — the precision Office writes.
1602
+ * Now, as `dcterms:W3CDTF` without milliseconds, the precision Office writes.
1615
1603
  *
1616
1604
  * Call it **once** per part and reuse the value for `created` and `modified`: two calls make a
1617
1605
  * part whose two timestamps can disagree by a millisecond depending on when the build crossed a
@@ -1654,10 +1642,23 @@ function makeXmlCore(title, subject, author, revision) {
1654
1642
  closePrefix: "\n "
1655
1643
  });
1656
1644
  }
1657
- //#endregion
1658
- //#region src/families/group.ts
1645
+ // src/gen/pres/table-styles.ts
1646
+ /** The style PowerPoint applies to a new table, which the part names as its default. */
1647
+ const DEFAULT_TABLE_STYLE = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}";
1648
+ /**
1649
+ * Create `ppt/tableStyles.xml`
1650
+ * @param definitions - the `a:tblStyle` elements the part carries, in order
1651
+ * @return {string} XML
1652
+ */
1653
+ function makeXmlTableStyles(definitions) {
1654
+ return XML_DECL + "\r\n" + elOrVoid("a:tblStyleLst", {
1655
+ "xmlns:a": OOXML_NS.a,
1656
+ def: DEFAULT_TABLE_STYLE
1657
+ }, definitions.join(""));
1658
+ }
1659
+ // src/families/group.ts
1659
1660
  /**
1660
- * ts-pptx: the group construct family
1661
+ * pptx-ts: the group construct family
1661
1662
  *
1662
1663
  * Both ways to make a `<p:grpSp>`: from child descriptors (`addGroup`) and from objects already on
1663
1664
  * the slide (`groupObjects`). The group *renderer* is not here -- it recurses back into the shape
@@ -1674,10 +1675,9 @@ const groupFamily = {
1674
1675
  }
1675
1676
  }
1676
1677
  };
1677
- //#endregion
1678
- //#region src/gen/drawingml/image.ts
1678
+ // src/gen/drawingml/image.ts
1679
1679
  /**
1680
- * ts-pptx: DrawingML image sizing & cropping
1680
+ * pptx-ts: DrawingML image sizing & cropping
1681
1681
  *
1682
1682
  * Build the `<a:srcRect>` (+ `<a:stretch>`) blipFill children for the image
1683
1683
  * sizing modes (`cover` / `contain` / `crop` / `stretch`), for the implicit
@@ -1711,12 +1711,12 @@ const ImageSizingXml = {
1711
1711
  const b = imgSize.h - (boxDim.y + boxDim.h);
1712
1712
  if (l < 0 || r < 0 || t < 0 || b < 0) {
1713
1713
  const over = [
1714
- l < 0 && `x (${l < 0 ? -l : 0} past left edge)`,
1714
+ l < 0 && `x (${-l} past left edge)`,
1715
1715
  r < 0 && `x+w (${-r} past right edge)`,
1716
1716
  t < 0 && `y (${-t} past top edge)`,
1717
1717
  b < 0 && `y+h (${-b} past bottom edge)`
1718
1718
  ].filter(Boolean).join(", ");
1719
- throw new InvalidOptionError("image/crop-window-overflows", `addImage sizing.type 'crop': crop window overflows image bounds — ${over}. Ensure x≥0, y≥0, x+w≤w, y+h≤h.`);
1719
+ throw new InvalidOptionError("image/crop-window-overflows", `addImage sizing.type 'crop': crop window overflows image bounds: ${over}. Ensure x≥0, y≥0, x+w≤w, y+h≤h.`);
1720
1720
  }
1721
1721
  const lPerc = Math.round(PERCENT_SCALE * (l / imgSize.w));
1722
1722
  const rPerc = Math.round(PERCENT_SCALE * (r / imgSize.w));
@@ -1732,12 +1732,12 @@ const ImageSizingXml = {
1732
1732
  };
1733
1733
  /**
1734
1734
  * The blipFill children for a vector source the caller gave no `sizing` for: letterbox it to its
1735
- * own aspect ratio inside its frame, the way `sizing: 'contain'` would — an SVG carries an
1735
+ * own aspect ratio inside its frame, the way `sizing: 'contain'` would. An SVG carries an
1736
1736
  * intrinsic ratio, and stretching a glyph into a box that disagrees with it is never the intent.
1737
1737
  *
1738
1738
  * Returns `null` when the two ratios already agree, which is the overwhelmingly common case (a
1739
1739
  * square icon in a square box). The caller then emits the plain `<a:stretch>` it always did, so
1740
- * this default costs nothing — neither bytes nor a behaviour change — until it actually differs.
1740
+ * this default costs nothing (neither bytes nor a behaviour change) until it actually differs.
1741
1741
  * @param imgSize - the vector's intrinsic size (viewBox or width/height)
1742
1742
  * @param boxDim - the picture's displayed frame
1743
1743
  * @returns the `<a:srcRect>` + `<a:stretch>` children, or `null` if no letterboxing is needed
@@ -1758,10 +1758,9 @@ function genXmlImageCrop(crop, objectName) {
1758
1758
  const where = objectName ? ` for image "${objectName}"` : "";
1759
1759
  return genXmlImageCropRect(crop, "addImage", where) + STRETCH;
1760
1760
  }
1761
- //#endregion
1762
- //#region src/gen/slide/objects/image.ts
1761
+ // src/gen/slide/objects/image.ts
1763
1762
  /**
1764
- * ts-pptx: image slide-object serialization
1763
+ * pptx-ts: image slide-object serialization
1765
1764
  *
1766
1765
  * Emits an `image` slide object as a `<p:pic>`: the blip and its image effects (transparency,
1767
1766
  * duotone, colour change, grayscale, bi-level), the crop or `sizing` source rectangle, the
@@ -1779,7 +1778,7 @@ function renderImageObject(ctx) {
1779
1778
  let drawnH = frameH;
1780
1779
  const { sizing, rounding } = itemOpts;
1781
1780
  let strSlideXml = "";
1782
- const mediaRel = (slide._relsMedia || []).find((rel) => rel.rId === slideItemObj.imageRid);
1781
+ const mediaRel = slide._relsMedia.find((rel) => rel.rId === slideItemObj.imageRid);
1783
1782
  const naturalSize = () => imageNaturalSize(slideItemObj, slide);
1784
1783
  const imgOpts = itemOpts;
1785
1784
  const imgLink = slideItemObj.hyperlink;
@@ -1790,7 +1789,7 @@ function renderImageObject(ctx) {
1790
1789
  noChangeAspect: true,
1791
1790
  ...imgOpts.objectLock
1792
1791
  }, imgOpts.objectName)), { openPrefix: " " });
1793
- strSlideXml += el("p:nvPr", null, raw(genXmlPlaceholder(placeholderObj)), { openPrefix: " " });
1792
+ strSlideXml += el("p:nvPr", null, raw(genXmlPlaceholder(placeholderObj, statedPlaceholderBinding(itemOpts.placeholder))), { openPrefix: " " });
1794
1793
  strSlideXml += " </p:nvPicPr>";
1795
1794
  const blipEffects = (alphaPrefix) => [
1796
1795
  mapStated(imgOpts.transparency, (transparency) => raw(voidEl("a:alphaModFix", { amt: transparencyToAlpha(transparency) }, { openPrefix: alphaPrefix }))) ?? null,
@@ -1865,8 +1864,7 @@ function renderImageObject(ctx) {
1865
1864
  strSlideXml += "</p:pic>";
1866
1865
  return strSlideXml;
1867
1866
  }
1868
- //#endregion
1869
- //#region src/families/image.ts
1867
+ // src/families/image.ts
1870
1868
  const imageFamily = {
1871
1869
  name: "image",
1872
1870
  authors: { addImage(slide, options) {
@@ -1877,8 +1875,7 @@ const imageFamily = {
1877
1875
  } },
1878
1876
  renderers: { ["image"]: renderImageObject }
1879
1877
  };
1880
- //#endregion
1881
- //#region src/package/parts/notes.ts
1878
+ // src/package/parts/notes.ts
1882
1879
  const notesContributor = {
1883
1880
  order: 10,
1884
1881
  parts: {
@@ -1907,8 +1904,7 @@ const notesContributor = {
1907
1904
  }
1908
1905
  }
1909
1906
  };
1910
- //#endregion
1911
- //#region src/gen/define/notes.ts
1907
+ // src/gen/define/notes.ts
1912
1908
  /**
1913
1909
  * Adds Notes to a slide.
1914
1910
  * @param {PresSlideInternal} `target` slide object
@@ -1926,10 +1922,9 @@ function addNotesDefinition(target, notes) {
1926
1922
  text: runs
1927
1923
  });
1928
1924
  }
1929
- //#endregion
1930
- //#region src/families/notes.ts
1925
+ // src/families/notes.ts
1931
1926
  /**
1932
- * ts-pptx: the speaker-notes construct family
1927
+ * pptx-ts: the speaker-notes construct family
1933
1928
  *
1934
1929
  * `addNotes` and the notes-slide parts it puts in the package. Cheap, and a deck without speaker
1935
1930
  * notes is a poor default, so every tier carries it -- which is a reason to compose it, not a
@@ -1942,8 +1937,7 @@ const notesFamily = {
1942
1937
  } },
1943
1938
  parts: notesContributor
1944
1939
  };
1945
- //#endregion
1946
- //#region src/gen/define/shape.ts
1940
+ // src/gen/define/shape.ts
1947
1941
  /**
1948
1942
  * Map of common friendly shape names users pass as bare strings to their
1949
1943
  * valid OOXML preset values. PowerPoint can't parse the friendly spellings
@@ -1989,8 +1983,7 @@ function addShapeDefinition(target, shapeName, opts) {
1989
1983
  if (typeof options.fill === "object" && resolveFillKind(options.fill) === "image") registerImageFillMedia(target, options.fill);
1990
1984
  target._slideObjects.push(newObject);
1991
1985
  }
1992
- //#endregion
1993
- //#region src/families/shape.ts
1986
+ // src/families/shape.ts
1994
1987
  const shapeFamily = {
1995
1988
  name: "shape",
1996
1989
  authors: { addShape(slide, shapeName, options) {
@@ -2011,8 +2004,7 @@ const shapeFamily = {
2011
2004
  }
2012
2005
  }
2013
2006
  };
2014
- //#endregion
2015
- //#region src/gen/slide/objects/text.ts
2007
+ // src/gen/slide/objects/text.ts
2016
2008
  /**
2017
2009
  * Render a `text` / `placeholder` slide object to its `<p:sp>` XML.
2018
2010
  */
@@ -2024,10 +2016,11 @@ function renderTextObject(ctx) {
2024
2016
  strSlideXml += "<p:nvSpPr>" + cNvPrEl(shapeId, txtOpts.objectName, txtOpts.altText || "", cNvPrHyperlink(txtOpts.hyperlink));
2025
2017
  {
2026
2018
  const spLockXml = genXmlObjectLock("a:spLocks", SHAPE_LOCK_ATTRS, txtOpts.objectLock, txtOpts.objectName);
2027
- const cNvSpPrAttrs = { txBox: xsdBoolIfTrue(txtOpts?.isTextBox) };
2019
+ const cNvSpPrAttrs = { txBox: xsdBoolIfTrue(txtOpts.isTextBox) };
2028
2020
  strSlideXml += elOrVoid("p:cNvSpPr", cNvSpPrAttrs, spLockXml);
2029
2021
  }
2030
- strSlideXml += el("p:nvPr", null, raw(genXmlPlaceholder(slideItemObj._type === "placeholder" || placeholderObj == null && itemOpts?._placeholderType ? slideItemObj : placeholderObj)));
2022
+ const isPlaceholderDef = slideItemObj._type === "placeholder";
2023
+ strSlideXml += el("p:nvPr", null, raw(genXmlPlaceholder(isPlaceholderDef || placeholderObj == null && itemOpts._placeholderType ? slideItemObj : placeholderObj, statedPlaceholderBinding(itemOpts.placeholder), isPlaceholderDef)));
2031
2024
  strSlideXml += "</p:nvSpPr><p:spPr>";
2032
2025
  strSlideXml += xfrmEl("a:xfrm", {
2033
2026
  x,
@@ -2042,7 +2035,7 @@ function renderTextObject(ctx) {
2042
2035
  if (itemOpts.line) strSlideXml += genXmlShapeLine(itemOpts.line);
2043
2036
  if (itemOpts.shadow && itemOpts.shadow.type !== "none") strSlideXml += createShadowEffectLst(itemOpts.shadow, DEF_TEXT_SHADOW);
2044
2037
  strSlideXml += "</p:spPr>";
2045
- strSlideXml += genXmlTextBody(slideItemObj);
2038
+ strSlideXml += genXmlTextBody(slideItemObj, slideTextColor(slide));
2046
2039
  strSlideXml += "</p:sp>";
2047
2040
  if (objectHasMath(slideItemObj)) return alternateContentEl({
2048
2041
  requires: {
@@ -2053,8 +2046,7 @@ function renderTextObject(ctx) {
2053
2046
  });
2054
2047
  return strSlideXml;
2055
2048
  }
2056
- //#endregion
2057
- //#region src/families/text.ts
2049
+ // src/families/text.ts
2058
2050
  /**
2059
2051
  * Refuse a `text` that is none of the forms the signature takes. A single run object,
2060
2052
  * `{ text: 'x' }`, is the one a caller reaches for, and it failed inside the definer with a
@@ -2081,16 +2073,14 @@ const textFamily = {
2081
2073
  ["text"]: renderTextObject
2082
2074
  }
2083
2075
  };
2084
- //#endregion
2085
- //#region src/families/animations.ts
2076
+ // src/families/animations.ts
2086
2077
  const animationsFamily = {
2087
2078
  name: "animations",
2088
2079
  authors: { addAnimation(slide, options) {
2089
2080
  slide._animations.push(options);
2090
2081
  } }
2091
2082
  };
2092
- //#endregion
2093
- //#region src/gen/chart/chart-kind.ts
2083
+ // src/gen/chart/chart-kind.ts
2094
2084
  /** Both bubble variants (`<c:bubbleChart>`), which differ only by `<c:bubble3D>`. */
2095
2085
  function isBubbleChart(type) {
2096
2086
  return type === "bubble" || type === "bubble3D";
@@ -2160,16 +2150,15 @@ const STOCK_STYLE_SPEC = {
2160
2150
  upDownBars: true
2161
2151
  }
2162
2152
  };
2163
- //#endregion
2164
- //#region src/gen/chart/data-refs.ts
2153
+ // src/gen/chart/data-refs.ts
2165
2154
  /**
2166
- * ts-pptx: Chart Series-Data ↔ Worksheet-Cell Mapping
2155
+ * pptx-ts: Chart Series-Data ↔ Worksheet-Cell Mapping
2167
2156
  *
2168
2157
  * The tiny pure helpers that both chart package parts share: the empty-array-safe
2169
2158
  * accessors over the normalized (internal) chart-series arrays, and the builders that
2170
2159
  * turn a (column, row) into an absolute reference into the chart's embedded `Sheet1`.
2171
2160
  * The embedded-workbook builder ({@link ../chart/embed-xlsx}) writes the cells; the
2172
- * chart-XML builder ({@link ../chart/chart-xml}) points `<c:f>` formulas back at them —
2161
+ * chart-XML builder ({@link ../chart/chart-xml}) points `<c:f>` formulas back at them,
2173
2162
  * so this mapping lives in one place to keep column letters and `$`-anchoring from
2174
2163
  * drifting between the two sides.
2175
2164
  */
@@ -2328,10 +2317,9 @@ function worksheetLayout(rel) {
2328
2317
  * @param count - how many categories the series carries
2329
2318
  */
2330
2319
  const categoryRange = (sheet, count) => sheetRangeRef(sheet.labelCols, 2, sheet.labelCols, count + 1);
2331
- //#endregion
2332
- //#region src/gen/chart/chart-stroke.ts
2320
+ // src/gen/chart/chart-stroke.ts
2333
2321
  /**
2334
- * ts-pptx: folding a chart's older stroke spellings onto {@link StrokeProps}.
2322
+ * pptx-ts: folding a chart's older stroke spellings onto {@link StrokeProps}.
2335
2323
  *
2336
2324
  * A stroke is one concept, and the chart option bag used to spell it three ways that the rest
2337
2325
  * of the library did not: `size` for the width, `style` for the dash, and a separate
@@ -2419,7 +2407,7 @@ function axisLineStroke(opts, axis) {
2419
2407
  * @param option - the option path to name in a diagnostic, as the caller spells it
2420
2408
  */
2421
2409
  function scrubGridLine(glOpts, option = "chart.gridLine") {
2422
- if (!glOpts || gridLineSuppressed(glOpts)) return;
2410
+ if (gridLineSuppressed(glOpts)) return;
2423
2411
  const width = glOpts.width ?? glOpts.size;
2424
2412
  if (width !== void 0 && (!Number.isFinite(Number(width)) || width <= 0)) {
2425
2413
  warn("chart/invalid-grid-line-size", `${option}.width must be greater than 0.`);
@@ -2443,8 +2431,7 @@ function scrubGridLine(glOpts, option = "chart.gridLine") {
2443
2431
  delete glOpts.cap;
2444
2432
  }
2445
2433
  }
2446
- //#endregion
2447
- //#region src/gen/chart/chart-parts.ts
2434
+ // src/gen/chart/chart-parts.ts
2448
2435
  /**
2449
2436
  * The six `c:show*` flags every `<c:dLbls>` carries, in schema order, as `XmlChild`s for the
2450
2437
  * parent's child list. Eight `<c:dLbls>` builders across five modules wrote all six out by
@@ -2470,15 +2457,15 @@ function dLblShowFlags(flags) {
2470
2457
  * The data-label run properties, in the attribute order the scatter and custom-label paths
2471
2458
  * emit: `sz, b, i, u, strike`.
2472
2459
  *
2473
- * There is a second ordering in this file — `b, i, strike, sz, u`, used by
2474
- * {@link chartDataLabels} and by the bubble plot — and the two are **deliberately not
2460
+ * There is a second ordering in this file, `b, i, strike, sz, u`, used by
2461
+ * {@link chartDataLabels} and by the bubble plot, and the two are **deliberately not
2475
2462
  * merged**. Attribute order carries no meaning in XML, so either is correct and a reader is
2476
2463
  * right to want one; but merging them moves bytes in a refactor whose whole claim is that it
2477
2464
  * does not, and the byte-identity gate is what makes that claim checkable. Unifying the
2478
2465
  * spelling is a decision to take on its own, with its own re-baseline.
2479
2466
  *
2480
2467
  * `over` layers a series' own `seriesOptions` entry on top with `??`, leaving the chart-level
2481
- * reading below it exactly as it was — a series that states nothing produces the same bytes.
2468
+ * reading below it exactly as it was: a series that states nothing produces the same bytes.
2482
2469
  * @param opts - the chart's normalized options
2483
2470
  * @param over - this series' `seriesOptions` entry, whose stated fields win over the chart's
2484
2471
  */
@@ -2550,7 +2537,7 @@ function labelRun(opts, text, over) {
2550
2537
  * The `<c:txPr>` a data-label block wraps its run properties in: an empty `<a:bodyPr>`, an empty
2551
2538
  * `<a:lstStyle>`, then one `<a:p>` carrying the `<a:pPr>` the caller built.
2552
2539
  *
2553
- * Five sites spelled this out byte-identically — the shared `<c:dLbls>` builder, the bubble,
2540
+ * Five sites spelled this out byte-identically: the shared `<c:dLbls>` builder, the bubble,
2554
2541
  * category-axis and pie plots, and the pie's plot-level block. The axis one in `chart-axes.ts`
2555
2542
  * is deliberately NOT this: it carries a rotation on the `bodyPr` and an `<a:endParaRPr>` after
2556
2543
  * the `<a:pPr>`.
@@ -2598,7 +2585,7 @@ function c15LeaderLinesExt(val) {
2598
2585
  * This and {@link labelFontAttrs} read the same five options and read them the same way:
2599
2586
  * `over?.X ?? opts.X ?? DEFAULT`. Attribute order is the only difference left between them.
2600
2587
  *
2601
- * They disagreed on the operator once — `??` here against `||` there — and which one a chart
2588
+ * They disagreed on the operator once (`??` here against `||` there), and which one a chart
2602
2589
  * reached was decided by its type and its label format, so `dataLabelFontSize: 0` had three
2603
2590
  * answers: a bar warned and clamped, a pie dropped the value with no diagnostic at all, and an
2604
2591
  * `XY` scatter, which reaches both builders, emitted `sz="100"` on one label block and
@@ -2628,7 +2615,7 @@ function dataLabelDefRPr(opts, over) {
2628
2615
  * This replaces two copies of a loop that wrote `opts[opt] = undefined` back onto the options
2629
2616
  * bag from inside an XML builder. Nothing downstream was corrupted (`ChartOptsInternal` is a
2630
2617
  * copy `gen/define/chart.ts` already made, guarded by
2631
- * `test/regression/chart/chart-input-immutability.test.js`), but it meant calling the same axis
2618
+ * `test/regression/chart/chart-input-immutability.test.ts`), but it meant calling the same axis
2632
2619
  * builder twice gave a different answer the second time, and it put validation somewhere nobody
2633
2620
  * would look for it.
2634
2621
  *
@@ -2653,7 +2640,7 @@ function validTimeUnit(value, optionName) {
2653
2640
  * `undefined` when the caller's value is not one.
2654
2641
  *
2655
2642
  * `catAxisLabelFrequency` and `serAxisLabelFrequency` were typed as free-form strings and
2656
- * emitted verbatim, so `'every other'` reached `<c:tickLblSkip val="every other"/>` — and the
2643
+ * emitted verbatim, so `'every other'` reached `<c:tickLblSkip val="every other"/>`, and the
2657
2644
  * type also rejected the natural `2`. Same shape as {@link validTimeUnit} beside it: warn and
2658
2645
  * emit nothing rather than write a value outside the attribute's own type.
2659
2646
  * @param value - the caller's value, a number or a numeric string
@@ -2673,7 +2660,7 @@ function positiveIntAttr(value, optionName) {
2673
2660
  * for a rule, and `defaultRule` when the caller stated neither.
2674
2661
  *
2675
2662
  * The two axis builders each spelled this decision out, and both opened it with
2676
- * `typeof value === 'number'` — the one numeric guard in the file that `NaN` passes, since every
2663
+ * `typeof value === 'number'`, the one numeric guard in the file that `NaN` passes, since every
2677
2664
  * other numeric axis option is guarded by truthiness. `{ valAxisCrossesAt: NaN }` therefore
2678
2665
  * emitted `<c:crossesAt val="NaN"/>`, and `ST_Double` has no such value.
2679
2666
  * @param value - the caller's `*AxisCrossesAt`: a position, a `ST_Crosses` rule, or nothing
@@ -2719,9 +2706,8 @@ function resolveChartPalette(opts) {
2719
2706
  * Every palette lookup in this directory goes through here so that a deck with more series or
2720
2707
  * data points than the palette has entries still emits the same bytes on every build.
2721
2708
  */
2722
- function paletteColor(palette, idx, fallback = "000000") {
2723
- if (palette.length === 0) return fallback;
2724
- return palette[idx % palette.length] ?? fallback;
2709
+ function paletteColor(palette, idx) {
2710
+ return palette[idx % palette.length] ?? "000000";
2725
2711
  }
2726
2712
  const DEF_GRIDLINE_COLOR = DEF_CHART_GRIDLINE.color ?? "888888";
2727
2713
  /**
@@ -2740,12 +2726,12 @@ function seriesDash(opts, serIndex) {
2740
2726
  /**
2741
2727
  * Fill fragment for a `chartColors`-derived series/line/marker colour.
2742
2728
  *
2743
- * A `'transparent'` entry means "no fill" — an invisible series, connecting line, or marker
2744
- * stroke — and maps to `<a:noFill/>`. Any real colour goes through the normal solid-fill path.
2729
+ * A `'transparent'` entry means "no fill" (an invisible series, connecting line, or marker
2730
+ * stroke) and maps to `<a:noFill/>`. Any real colour goes through the normal solid-fill path.
2745
2731
  * The series and marker *fill* paths already special-case `'transparent'`; without this the
2746
2732
  * *stroke* paths (`<a:ln>` on the series line and marker border) would instead pass the literal
2747
2733
  * `'transparent'` through colour validation, warn "not a valid scheme color or hex RGB", and
2748
- * render as black — leaving a stray black line/border where a transparent series was requested.
2734
+ * render as black, leaving a stray black line/border where a transparent series was requested.
2749
2735
  */
2750
2736
  function chartColorLineFill(color) {
2751
2737
  return color === "transparent" ? voidEl("a:noFill") : genXmlColorSelection(color);
@@ -2756,7 +2742,7 @@ function chartColorLineFill(color) {
2756
2742
  * otherwise.
2757
2743
  *
2758
2744
  * Read against {@link chartColorLineFill}, which is the same decision for a *stroke* and stops
2759
- * one step earlier — a stroke has no opacity option to fold in. Three plot builders (bubble,
2745
+ * one step earlier: a stroke has no opacity option to fold in. Three plot builders (bubble,
2760
2746
  * scatter, and the whole category-axis family) each carried this expression verbatim, down to
2761
2747
  * the diagnostic code and the option name in its message, which is what made the `transparent`
2762
2748
  * arm easy to add to one and forget in another.
@@ -2771,7 +2757,7 @@ function seriesFill(opts, serColor) {
2771
2757
  return el("a:solidFill", null, raw(createColorElement(serColor, alpha)));
2772
2758
  }
2773
2759
  /**
2774
- * One plotted series' stroke: a width, this series' dash, the palette colour and a round join —
2760
+ * One plotted series' stroke (a width, this series' dash, the palette colour and a round join),
2775
2761
  * or `<a:noFill/>` when the caller asked for no line at all.
2776
2762
  *
2777
2763
  * Three plot builders had this, differing only in whether a per-series `lineSize` could override
@@ -2852,7 +2838,7 @@ function serMarker(opts, markerColor, seriesColor) {
2852
2838
  * its element: `<a:latin>` covers Latin/ASCII, `<a:ea>` covers East Asian, and
2853
2839
  * `<a:cs>` covers complex scripts. Emitting `<a:latin>` alone leaves East Asian
2854
2840
  * (e.g. Chinese) and complex-script glyphs falling back to the theme font, so a
2855
- * user-specified font never takes effect for that text — most visibly on
2841
+ * user-specified font never takes effect for that text, most visibly on
2856
2842
  * PowerPoint for Mac. Stamping the same typeface onto all three classes is what
2857
2843
  * choosing a font in PowerPoint's UI does.
2858
2844
  * @param {string} typeface - font face name
@@ -2886,7 +2872,7 @@ function genXmlTitle(opts, chartX, chartY) {
2886
2872
  const runChildren = genXmlColorSelection(namedColorOr(opts.color, DEF_FONT_COLOR, "chart text color")) + createChartTextFonts(opts.fontFace ?? "Arial");
2887
2873
  /**
2888
2874
  * Fold a slide-relative offset into the fraction-of-chart value `c:x`/`c:y` want, or
2889
- * `undefined` when it does not read as a finite number — `ST_Double` has no `NaN`, and
2875
+ * `undefined` when it does not read as a finite number: `ST_Double` has no `NaN`, and
2890
2876
  * omitting the axis is what CT_ManualLayout already means by "leave this one automatic".
2891
2877
  */
2892
2878
  const edgeFraction = (offset) => {
@@ -2900,7 +2886,7 @@ function genXmlTitle(opts, chartX, chartY) {
2900
2886
  * The chart's own offset along one axis, in inches, to fold into the caller's `titlePos`.
2901
2887
  *
2902
2888
  * Resolved here rather than by the caller so the warning fires only where the value is
2903
- * actually used — a chart with `showTitle` and no `titlePos` folds nothing and says nothing.
2889
+ * actually used. A chart with `showTitle` and no `titlePos` folds nothing and says nothing.
2904
2890
  */
2905
2891
  const chartOffset = (value, axis) => {
2906
2892
  const inches = chartCoordInches(value);
@@ -3033,7 +3019,7 @@ function chartDataLabels(opts, leaderLines) {
3033
3019
  });
3034
3020
  }
3035
3021
  /**
3036
- * An `<a:solidFill>` of the theme text colour dimmed towards the background — the grey the chart
3022
+ * An `<a:solidFill>` of the theme text colour dimmed towards the background: the grey the chart
3037
3023
  * furniture (stock hi-low lines and up/down bars, the data-table grid) is drawn in.
3038
3024
  * `lumMod`/`lumOff` are the two halves of one dimming: how much of the luminance survives, and
3039
3025
  * how much white is mixed back in.
@@ -3061,7 +3047,7 @@ function dimmedTextLine(lumMod, lumOff) {
3061
3047
  * gaps and are skipped silently (a sparse, idx-keyed cache is valid).
3062
3048
  *
3063
3049
  * **PowerPoint is the only oracle for this.** `<c:v>` is `s:ST_Xstring` in the schema, not
3064
- * `xsd:double` — nothing above is a schema violation, and the OpenXmlValidator reports every one
3050
+ * `xsd:double`. Nothing above is a schema violation, and the OpenXmlValidator reports every one
3065
3051
  * of those three packages clean. An *empty* `<c:v>` is the case that shows why the distinction is
3066
3052
  * worth stating rather than reasoning about: it looks equally invalid and it is not, opening
3067
3053
  * cleanly and reading back as an empty point. See `pieValues` in
@@ -3197,7 +3183,7 @@ function makeCustomDLblXml(idx, text, opts) {
3197
3183
  ]);
3198
3184
  }
3199
3185
  /**
3200
- * The `<a:ln>` a chart-level `dataBorder` paints around every data point — the bubble, the
3186
+ * The `<a:ln>` a chart-level `dataBorder` paints around every data point: the bubble, the
3201
3187
  * pie slice, the bar.
3202
3188
  *
3203
3189
  * A near-sibling of {@link createChartBorderLine} rather than the same thing, and the three
@@ -3225,7 +3211,7 @@ function createDataBorderLine(dataBorder, cap) {
3225
3211
  * caller asked for none. See {@link createDataBorderLine} for why the two are separate.
3226
3212
  *
3227
3213
  * `type: 'dash'` here means the `dash` preset, not the `sysDash` a table border's `type`
3228
- * resolves to — a chart border has no `dashType` of its own to name a preset with, so the
3214
+ * resolves to. A chart border has no `dashType` of its own to name a preset with, so the
3229
3215
  * three-way switch is the whole vocabulary and it picks the plain one.
3230
3216
  * @param border - the chart's `border` (`type`, `color`, `width`, `transparency`)
3231
3217
  */
@@ -3264,7 +3250,7 @@ function makeSeriesDataPointsXml(chartType, obj, opts, varyColors) {
3264
3250
  let xml = "";
3265
3251
  dataValues(obj).forEach((value, index) => {
3266
3252
  const ptStyle = pointStyles?.[index];
3267
- const arrColors = varyColors ? value < 0 ? opts.invertedColors || opts.chartColors || BARCHART_COLORS : varyColors : null;
3253
+ const arrColors = varyColors ? value !== null && value < 0 ? opts.invertedColors || opts.chartColors || BARCHART_COLORS : varyColors : null;
3268
3254
  const fillColor = ptStyle?.fill || (arrColors ? paletteColor(arrColors, index) : null);
3269
3255
  const pattern = ptStyle?.pattern;
3270
3256
  const border = ptStyle?.border;
@@ -3383,8 +3369,8 @@ function xySeriesRefs(chartType, obj, data, opts, sheet, valFmtCode) {
3383
3369
  * A `<c:cat>` category reference: the `<c:f>` formula plus the `<c:numCache>`/`<c:strCache>` that
3384
3370
  * mirrors the label cells it points at.
3385
3371
  *
3386
- * `kind` picks the cache: `'num'` for numeric categories — dates, which need a `<c:formatCode>` so
3387
- * PowerPoint renders them as dates rather than serial numbers — and `'str'` for text ones. Stock
3372
+ * `kind` picks the cache: `'num'` for numeric categories (dates, which need a `<c:formatCode>` so
3373
+ * PowerPoint renders them as dates rather than serial numbers) and `'str'` for text ones. Stock
3388
3374
  * and cat-axis each carried both arms of that choice, and surface carried the string one, five
3389
3375
  * copies of the same `<c:f>` + `<c:ptCount>` + `<c:pt idx>` loop.
3390
3376
  *
@@ -3393,11 +3379,12 @@ function xySeriesRefs(chartType, obj, data, opts, sheet, valFmtCode) {
3393
3379
  * different spelling.
3394
3380
  * @param kind - `num` for a numeric (date) category cache, `str` for a text one
3395
3381
  * @param ref - the `<c:f>` formula
3396
- * @param labels - the category labels, in order; escaped on the way into `<c:v>`
3382
+ * @param labels - the category labels, in order; escaped on the way into `<c:v>`. A blank one has no
3383
+ * point in a numeric cache, whose `<c:v>` must hold a number, as {@link numCachePt} leaves a gap.
3397
3384
  * @param formatCode - the cached `<c:formatCode>`; numeric caches only
3398
3385
  */
3399
3386
  function catRefBlock(kind, ref, labels, formatCode) {
3400
- const points = labels.map((label, idx) => el("c:pt", { idx }, raw(el("c:v", null, label)))).join("");
3387
+ const points = labels.map((label, idx) => kind === "num" && String(label ?? "").trim() === "" ? "" : el("c:pt", { idx }, raw(el("c:v", null, label)))).join("");
3401
3388
  const cache = el(`c:${kind}Cache`, null, [formatCode === void 0 ? null : raw(el("c:formatCode", null, formatCode)), raw(voidEl("c:ptCount", { val: labels.length }) + points)]);
3402
3389
  return el(`c:${kind}Ref`, null, [raw(el("c:f", null, ref)), raw(cache)]);
3403
3390
  }
@@ -3406,13 +3393,13 @@ function catRefBlock(kind, ref, labels, formatCode) {
3406
3393
  * it points at.
3407
3394
  *
3408
3395
  * Scatter and bubble each carried their own copy of this twice over, four near-identical
3409
- * twelve-line blocks, and bubble's per-point sizes were a fifth — the same block under a third
3396
+ * twelve-line blocks, and bubble's per-point sizes were a fifth: the same block under a third
3410
3397
  * wrapping tag with a constant format code. `values` is the exact point list to cache, so the
3411
3398
  * caller decides what a gap is: the Y series is emitted against the X series' length (a caller
3412
- * may supply fewer Y values than X — a timeline with only the first few months filled in), and
3399
+ * may supply fewer Y values than X, e.g. a timeline with only the first few months filled in), and
3413
3400
  * the shorter array's tail arrives here as `undefined`, which {@link numCachePt} skips.
3414
3401
  *
3415
- * `ptCount` is the length of the cached *range* — the number of cells `ref` spans — which is not
3402
+ * `ptCount` is the length of the cached *range* (the number of cells `ref` spans), which is not
3416
3403
  * always `values.length`. A category chart caches one column against the chart's category count
3417
3404
  * and may hold fewer values than that, so it states the count explicitly; scatter and bubble pad
3418
3405
  * their arrays to the range instead and let the default stand. Both spellings mean the same
@@ -3427,9 +3414,9 @@ function catRefBlock(kind, ref, labels, formatCode) {
3427
3414
  * @param ref - the `<c:f>` formula, from {@link sheetRangeRef} or written inline
3428
3415
  * @param formatCode - the cached `<c:formatCode>`
3429
3416
  * @param values - the points to cache, in order; `null`/`undefined` entries are gaps
3430
- * @param ptCount - cells spanned by `ref`; defaults to `values.length`
3417
+ * @param ptCount - cells spanned by `ref`
3431
3418
  */
3432
- function numRefBlock(tag, ref, formatCode, values, ptCount = values.length) {
3419
+ function numRefBlock(tag, ref, formatCode, values, ptCount) {
3433
3420
  const numCache = el("c:numCache", null, [
3434
3421
  raw(el("c:formatCode", null, formatCode)),
3435
3422
  raw(voidEl("c:ptCount", { val: ptCount })),
@@ -3438,10 +3425,9 @@ function numRefBlock(tag, ref, formatCode, values, ptCount = values.length) {
3438
3425
  const numRef = el("c:numRef", null, [raw(el("c:f", null, ref)), raw(numCache)]);
3439
3426
  return el(tag, null, raw(numRef));
3440
3427
  }
3441
- //#endregion
3442
- //#region src/gen/chart/chart-axes.ts
3428
+ // src/gen/chart/chart-axes.ts
3443
3429
  /**
3444
- * ts-pptx: Chart Axis Assembly
3430
+ * pptx-ts: Chart Axis Assembly
3445
3431
  *
3446
3432
  * Builds the `<c:catAx>` / `<c:valAx>` / `<c:serAx>` elements. The three share a
3447
3433
  * structure -- scaling, delete flag, tick marks, label position, text properties,
@@ -3613,20 +3599,39 @@ function makeCatAxis(opts, axisId, valAxisId) {
3613
3599
  ]);
3614
3600
  }
3615
3601
  /**
3602
+ * A value-axis bound as the axis can carry it: `undefined` when the axis is logarithmic and the
3603
+ * bound is not above 0, with a warning, so the axis scales itself instead.
3604
+ *
3605
+ * PowerPoint refuses a whole deck (0x80070570) over one chart whose `<c:logBase>` sits beside a
3606
+ * `<c:min val="0"/>`: a log axis has no 0 to start from. The check is here rather than in
3607
+ * `addChartDefinition` because a `valAxes[i]` entry is spread over the chart's options at emit
3608
+ * time, so a log base and a bound can each come from a different bag.
3609
+ * @param opts - the axis's options, overrides already applied
3610
+ * @param key - which bound
3611
+ */
3612
+ function logAxisBound(opts, key) {
3613
+ const bound = opts[key];
3614
+ if (bound == null) return void 0;
3615
+ if (opts.valAxisLogScaleBase && bound <= 0) {
3616
+ warn("chart/option-out-of-range", `"${key}" must be above 0 on a logarithmic axis; ignoring ${bound} so the axis scales itself.`);
3617
+ return;
3618
+ }
3619
+ return bound;
3620
+ }
3621
+ /**
3616
3622
  * Create Value Axis (Used by `bar3D`)
3617
3623
  * @param {ChartOptsInternal} opts - chart options
3618
3624
  * @param {string} valAxisId - value
3619
3625
  * @return {string} XML
3620
3626
  */
3621
3627
  function makeValAxis(opts, valAxisId) {
3622
- let axisPos = valAxisId === "2094734552" ? opts.barDir === "col" ? "l" : "b" : opts.barDir !== "col" ? "r" : "t";
3623
- if (valAxisId === "2094734553") axisPos = "r";
3628
+ const axisPos = valAxisId === "2094734552" ? opts.barDir === "col" ? "l" : "b" : "r";
3624
3629
  const crossAxId = valAxisId === "2094734552" ? AXIS_ID_CATEGORY_PRIMARY : AXIS_ID_CATEGORY_SECONDARY;
3625
3630
  const scaling = el("c:scaling", null, [
3626
3631
  opts.valAxisLogScaleBase ? raw(voidEl("c:logBase", { val: opts.valAxisLogScaleBase })) : null,
3627
3632
  raw(voidEl("c:orientation", { val: opts.valAxisOrientation || "minMax" })),
3628
- opts.valAxisMaxVal != null ? raw(voidEl("c:max", { val: opts.valAxisMaxVal })) : null,
3629
- opts.valAxisMinVal != null ? raw(voidEl("c:min", { val: opts.valAxisMinVal })) : null
3633
+ logAxisBound(opts, "valAxisMaxVal") != null ? raw(voidEl("c:max", { val: opts.valAxisMaxVal })) : null,
3634
+ logAxisBound(opts, "valAxisMinVal") != null ? raw(voidEl("c:min", { val: opts.valAxisMinVal })) : null
3630
3635
  ]);
3631
3636
  const ticks = isScatterChart(opts._type) ? voidEl("c:majorTickMark", { val: "none" }) + voidEl("c:minorTickMark", { val: "none" }) + voidEl("c:tickLblPos", { val: "nextTo" }) : voidEl("c:majorTickMark", { val: opts.valAxisMajorTickMark || "out" }) + voidEl("c:minorTickMark", { val: opts.valAxisMinorTickMark || "none" }) + voidEl("c:tickLblPos", { val: opts.valAxisLabelPos || (opts.barDir === "col" ? "nextTo" : "low") });
3632
3637
  const txPr = axisTextProps(axisLabelDefRPr({
@@ -3637,7 +3642,7 @@ function makeValAxis(opts, valAxisId) {
3637
3642
  color: opts.valAxisLabelColor,
3638
3643
  fontFace: opts.valAxisLabelFontFace
3639
3644
  }), chartLang(opts), mapStated(opts.valAxisLabelRotate, (d) => convertAngleUnits(d, "valAxisLabelRotate")));
3640
- const crosses = axisCrossing(opts.catAxisCrossesAt, axisPos === "r" || axisPos === "t" ? "max" : "autoZero", "catAxisCrossesAt");
3645
+ const crosses = axisCrossing(opts.catAxisCrossesAt, axisPos === "r" ? "max" : "autoZero", "catAxisCrossesAt");
3641
3646
  const crossBetween = opts.valAxisCrossBetween || (isScatterChart(opts._type) || !!(Array.isArray(opts._type) && opts._type.some((type) => asChartType(type.type) === "area")) ? "midCat" : "between");
3642
3647
  return el("c:valAx", null, [
3643
3648
  raw(voidEl("c:axId", { val: valAxisId })),
@@ -3715,10 +3720,9 @@ function makeSerAxis(opts, axisId, valAxisId) {
3715
3720
  serLabelSkip !== void 0 ? raw(voidEl("c:tickLblSkip", { val: serLabelSkip })) : null
3716
3721
  ]);
3717
3722
  }
3718
- //#endregion
3719
- //#region src/gen/chart/plot-cat-axis.ts
3723
+ // src/gen/chart/plot-cat-axis.ts
3720
3724
  /**
3721
- * ts-pptx: Category-Axis Plot Assembly
3725
+ * pptx-ts: Category-Axis Plot Assembly
3722
3726
  *
3723
3727
  * Emits the `<c:areaChart>` / `<c:barChart>` / `<c:bar3DChart>` / `<c:lineChart>` /
3724
3728
  * `<c:radarChart>` plot elements. These five chart types share one builder because they
@@ -3809,19 +3813,9 @@ const makeCatAxisPlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode
3809
3813
  chartType === "bar3D" ? raw(voidEl("c:axId", { val: AXIS_ID_SERIES_PRIMARY })) : null
3810
3814
  ]);
3811
3815
  };
3812
- //#endregion
3813
- //#region src/gen/chart/plot-scatter.ts
3816
+ // src/gen/chart/plot-scatter.ts
3814
3817
  /**
3815
- * ts-pptx: Scatter Plot Assembly
3816
- *
3817
- * Emits the `<c:scatterChart>` plot element. Scatter is the one family whose first data
3818
- * row supplies X *values* rather than categories, so each `<c:ser>` carries an
3819
- * `<c:xVal>`/`<c:yVal>` pair instead of `<c:cat>`/`<c:val>` -- which is why it does not
3820
- * share the category-axis builder. Reached through {@link ./chart-xml}'s `makeChartType`
3821
- * dispatch.
3822
- */
3823
- /**
3824
- * The `<c:spPr>` a scatter data label carries: no fill, no outline, no effects — the label is
3818
+ * The `<c:spPr>` a scatter data label carries: no fill, no outline, no effects. The label is
3825
3819
  * text on the plot rather than a box. Both label builders in this file spelled it out.
3826
3820
  */
3827
3821
  const TRANSPARENT_LABEL_SPPR = el("c:spPr", null, [
@@ -3835,7 +3829,7 @@ const TRANSPARENT_LABEL_SPPR = el("c:spPr", null, [
3835
3829
  *
3836
3830
  * Each `<a:fld>` id is minted per build. A field id has to be unique, which is a property a
3837
3831
  * derived id would have to reproduce without an oracle for how far that uniqueness has to
3838
- * reach — so the ids stay random and the *comparison* gives: `NORMALIZERS` in
3832
+ * reach. So the ids stay random and the *comparison* gives: `NORMALIZERS` in
3839
3833
  * `scripts/pptx-parts.mjs` erases exactly these two field types before the byte-identity gate
3840
3834
  * diffs a part. Do not "fix" the nondeterminism here.
3841
3835
  */
@@ -3919,7 +3913,6 @@ function scatterSerShapeProps(opts, serColor, serIndex, lineSize) {
3919
3913
  * Plot an XY scatter chart into `<c:scatterChart>` (paired X/Y numeric series).
3920
3914
  */
3921
3915
  const makeScatterPlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode, sheet) => {
3922
- const scatterVaryColors = data.length === 1 && opts.chartColors !== BARCHART_COLORS ? opts.chartColors || BARCHART_COLORS : null;
3923
3916
  const sers = data.slice(1).map((obj) => {
3924
3917
  const { idx, over, color: serColor, xVal, yVal } = xySeriesRefs(chartType, obj, data, opts, sheet, valFmtCode);
3925
3918
  let labels = "";
@@ -3935,7 +3928,7 @@ const makeScatterPlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode
3935
3928
  raw(seriesNameRef(obj, sheet)),
3936
3929
  raw(scatterSerShapeProps(opts, serColor, idx, over?.lineSize)),
3937
3930
  raw(serMarker(opts, serColor, serColor)),
3938
- raw(makeSeriesDataPointsXml(chartType, obj, opts, scatterVaryColors)),
3931
+ raw(makeSeriesDataPointsXml(chartType, obj, opts, null)),
3939
3932
  raw(labels),
3940
3933
  raw(makeChartErrorBarsXml(chartType, obj.errorBars, obj)),
3941
3934
  raw(xVal + yVal),
@@ -3951,15 +3944,14 @@ const makeScatterPlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode
3951
3944
  raw(voidEl("c:axId", { val: valAxisId }))
3952
3945
  ]);
3953
3946
  };
3954
- //#endregion
3955
- //#region src/gen/chart/plot-bubble.ts
3947
+ // src/gen/chart/plot-bubble.ts
3956
3948
  /**
3957
3949
  * Fill + outline + shadow for one bubble series, from the palette colour and the line options.
3958
3950
  *
3959
3951
  * Both the stroke fill and the cap read the same way as in `plot-scatter.ts` and
3960
3952
  * `plot-cat-axis.ts`, which this used to differ from on both counts with nothing saying why.
3961
3953
  * The colour went through `genXmlColorSelection` directly, so a `'transparent'` palette entry
3962
- * reached colour validation, warned, and painted the bubble outline black — the exact hole
3954
+ * reached colour validation, warned, and painted the bubble outline black: the exact hole
3963
3955
  * `chartColorLineFill` exists to close. The cap was hardcoded `flat`, so `lineCap` was accepted
3964
3956
  * and silently dropped for bubble charts alone; it is visible here, because a bubble outline
3965
3957
  * carries `lineDash` and a cap shapes the end of every dash.
@@ -4012,8 +4004,7 @@ const makeBubblePlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode,
4012
4004
  raw(voidEl("c:axId", { val: valAxisId }))
4013
4005
  ]);
4014
4006
  };
4015
- //#endregion
4016
- //#region src/gen/chart/plot-pie.ts
4007
+ // src/gen/chart/plot-pie.ts
4017
4008
  /** One `<c:dPt>`: the slice's own fill, its border override, and the shared shadow. */
4018
4009
  function pieDataPoint(idx, ptStyle, opts, fallbackColor) {
4019
4010
  const border = ptStyle?.border ? createChartBorderLine(ptStyle.border) : opts.dataBorder ? createDataBorderLine(opts.dataBorder, "flat") : "";
@@ -4093,8 +4084,8 @@ function pieCategories(labels, sheet) {
4093
4084
  * (`SeriesCollection(1).Values` reads `Empty` at that index in both), and export to a
4094
4085
  * byte-identical PNG. A sensitivity check confirms the cache is what paints: perturbing a
4095
4086
  * *neighbouring* cached value moves both the read-back and the pixels.
4096
- * - `<c:v>Infinity</c:v>` was not. PowerPoint refuses the package with 0x80070570 — the
4097
- * corrupt-file error — and so does `NaN` or `INF` in that position. A pie was therefore the one
4087
+ * - `<c:v>Infinity</c:v>` was not. PowerPoint refuses the package with 0x80070570 (the
4088
+ * corrupt-file error), and so does `NaN` or `INF` in that position. A pie was therefore the one
4098
4089
  * family where a non-finite value reached the deck instead of being warned about and dropped.
4099
4090
  */
4100
4091
  function pieValues(obj, count, valFmtCode, sheet) {
@@ -4156,10 +4147,9 @@ function makePiePlot(chartType, data, opts, valFmtCode, sheet) {
4156
4147
  chartType === "doughnut" ? raw(voidEl("c:holeSize", { val: opts.holeSize ?? 50 })) : null
4157
4148
  ]);
4158
4149
  }
4159
- //#endregion
4160
- //#region src/gen/chart/plot-stock.ts
4150
+ // src/gen/chart/plot-stock.ts
4161
4151
  /**
4162
- * ts-pptx: Stock (High-Low-Close) Plot Assembly
4152
+ * pptx-ts: Stock (High-Low-Close) Plot Assembly
4163
4153
  *
4164
4154
  * Emits the classic `<c:stockChart>` element (plus, for the volume styles, a leading
4165
4155
  * `<c:barChart>` volume series on a secondary axis pair). A stock chart is a fixed-order
@@ -4215,7 +4205,7 @@ const makeStockPlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode,
4215
4205
  raw(voidEl("c:idx", { val: volumeIdx })),
4216
4206
  raw(voidEl("c:order", { val: volumeIdx })),
4217
4207
  raw(seriesNameRef(volumeSeries, sheet)),
4218
- raw(el("c:spPr", null, raw(genXmlColorSelection(namedColorOr(opts.seriesOptions?.[volumeIdx]?.color, chartColors[0] ?? "4472C4", "seriesOptions color"))))),
4208
+ raw(el("c:spPr", null, raw(genXmlColorSelection(namedColorOr(opts.seriesOptions?.[volumeIdx]?.color, paletteColor(chartColors, 0), "seriesOptions color"))))),
4219
4209
  raw(voidEl("c:invertIfNegative", { val: 0 })),
4220
4210
  raw(catValRefs(volumeSeries, opts, valFmtCode, sheet, { multiLevel: false }))
4221
4211
  ]);
@@ -4232,7 +4222,7 @@ const makeStockPlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode,
4232
4222
  }
4233
4223
  const sers = stockSeries.map((obj, pos) => {
4234
4224
  const idx = seriesIdx(obj, chartType);
4235
- return makeStockLineSer(idx, obj, opts, valFmtCode, !spec.upDownBars && pos === stockSeries.length - 1 ? namedColorOr(opts.seriesOptions?.[idx]?.color, paletteColor(chartColors, idx, "ED7D31"), "seriesOptions color") : null, sheet);
4225
+ return makeStockLineSer(idx, obj, opts, valFmtCode, !spec.upDownBars && pos === stockSeries.length - 1 ? namedColorOr(opts.seriesOptions?.[idx]?.color, paletteColor(chartColors, idx), "seriesOptions color") : null, sheet);
4236
4226
  }).join("");
4237
4227
  const hiLowLines = el("c:hiLowLines", null, raw(el("c:spPr", null, [raw(dimmedTextLine(75e3, 25e3)), raw(voidEl("a:effectLst"))])));
4238
4228
  const upDownBars = spec.upDownBars ? el("c:upDownBars", null, [
@@ -4260,15 +4250,14 @@ const makeStockPlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode,
4260
4250
  ]);
4261
4251
  return strXml;
4262
4252
  };
4263
- //#endregion
4264
- //#region src/gen/chart/plot-surface.ts
4253
+ // src/gen/chart/plot-surface.ts
4265
4254
  /**
4266
- * ts-pptx: Surface Plot Assembly
4255
+ * pptx-ts: Surface Plot Assembly
4267
4256
  *
4268
4257
  * Emits the classic `<c:surface3DChart>` (a 3-D surface) or `<c:surfaceChart>` (a 2-D
4269
4258
  * contour / top view), selected by the `surface3D` option; `wireframe` toggles the
4270
4259
  * mesh-only look. A surface chart interpolates a colored sheet over the category (X) and
4271
- * series (Z) axes with the value as height (Y), so — like `bar3D` — it needs all three
4260
+ * series (Z) axes with the value as height (Y), so, like `bar3D`, it needs all three
4272
4261
  * axes and a `<c:view3D>` + floor/side/back walls (emitted by the surface branch of
4273
4262
  * `makeChartHeaderXml`). Reached through {@link ./chart-xml}'s `makeChartType` dispatch.
4274
4263
  */
@@ -4299,7 +4288,7 @@ function makeSurfaceSer(chartType, obj, opts, valFmtCode, seriesColor, sheet) {
4299
4288
  const makeSurfacePlot = (chartType, data, opts, valAxisId, catAxisId, valFmtCode, sheet) => {
4300
4289
  const tag = isSurface3D(opts) ? "surface3DChart" : "surfaceChart";
4301
4290
  const chartColors = resolveChartPalette(opts);
4302
- const sers = data.map((obj, idx) => makeSurfaceSer(chartType, obj, opts, valFmtCode, paletteColor(chartColors, idx, "4472C4"), sheet)).join("");
4291
+ const sers = data.map((obj, idx) => makeSurfaceSer(chartType, obj, opts, valFmtCode, paletteColor(chartColors, idx), sheet)).join("");
4303
4292
  return el(`c:${tag}`, null, [
4304
4293
  raw(voidEl("c:wireframe", { val: xsdBool(opts.surfaceWireframe) })),
4305
4294
  raw(sers),
@@ -4333,10 +4322,9 @@ function makeSurfaceScene(opts) {
4333
4322
  ];
4334
4323
  return el("c:view3D", null, scene) + el("c:floor", null, raw(wall)) + el("c:sideWall", null, raw(wall)) + el("c:backWall", null, raw(wall));
4335
4324
  }
4336
- //#endregion
4337
- //#region src/gen/chart/chart-xml.ts
4325
+ // src/gen/chart/chart-xml.ts
4338
4326
  /**
4339
- * ts-pptx: Chart DrawingML Assembly
4327
+ * pptx-ts: Chart DrawingML Assembly
4340
4328
  *
4341
4329
  * Builds a chart's `ppt/charts/chartN.xml` -- the `<c:chartSpace>` DrawingML that
4342
4330
  * PowerPoint renders. `makeXmlCharts` assembles the top-level envelope (header, plot
@@ -4359,8 +4347,8 @@ const CHART_SPACE_NS = {
4359
4347
  /**
4360
4348
  * Whether a chart-area/plot-area `fill` says anything the fill dispatch can act on.
4361
4349
  *
4362
- * `c:spPr` is `a:CT_ShapeProperties` — the same optional `EG_FillProperties` group the
4363
- * shape path writes into — so gradient, pattern and an omitted fill child are all legal
4350
+ * `c:spPr` is `a:CT_ShapeProperties`, the same optional `EG_FillProperties` group the
4351
+ * shape path writes into, so gradient, pattern and an omitted fill child are all legal
4364
4352
  * here. The gate used to be `fill?.color`, which meant every spelling carrying no colour
4365
4353
  * (`gradient`, `pattern`, `image`, `inherit`) fell to the no-fill arm and did nothing.
4366
4354
  *
@@ -4374,7 +4362,7 @@ const CHART_SPACE_NS = {
4374
4362
  * matches the shape path: only `line` infers its type from a bare `gradient`, fills have
4375
4363
  * always wanted `type: 'gradient'` spelled out.
4376
4364
  *
4377
- * A bare {@link Color} string is stated — it is the solid-colour shorthand every other fill
4365
+ * A bare {@link Color} string is stated: it is the solid-colour shorthand every other fill
4378
4366
  * site takes. This one used to be the exception: the string reached here having already been
4379
4367
  * spread into `{0:'F',1:'F',…}` by `copyChartOptions`, so it named neither `color` nor `type`
4380
4368
  * and a chart area asked for `fill: 'FF0000'` came out `<a:noFill/>`.
@@ -4389,7 +4377,7 @@ function isStatedFill(fill) {
4389
4377
  * The override bag carries a third state the rest of the generator does not: a *present*
4390
4378
  * `undefined`, meaning "this subchart's own value was rejected, so emit nothing here", as against
4391
4379
  * an absent key, which inherits the chart-level value (see {@link ChartOptsOverrides}). The spread
4392
- * is what applies that distinction — and once it has, the keys still holding `undefined` have said
4380
+ * is what applies that distinction, and once it has, the keys still holding `undefined` have said
4393
4381
  * everything they had to say, so they are dropped. What the plot builders receive is an ordinary
4394
4382
  * options bag with one spelling of absent.
4395
4383
  * @param chartOptions - the chart-level options, already normalized
@@ -4419,7 +4407,7 @@ function makeChartHeaderXml(rel) {
4419
4407
  titleUnderline: rel.opts.titleUnderline,
4420
4408
  titlePos: rel.opts.titlePos,
4421
4409
  titleRotate: rel.opts.titleRotate
4422
- }, rel.opts.x, rel.opts.y) + voidEl("c:autoTitleDeleted", { val: 0 }) : voidEl("c:autoTitleDeleted", { val: 1 });
4410
+ }, rel.opts.x ?? void 0, rel.opts.y ?? void 0) + voidEl("c:autoTitleDeleted", { val: 0 }) : voidEl("c:autoTitleDeleted", { val: 1 });
4423
4411
  if (rel.opts._type === "bar3D") return title + el("c:view3D", null, [
4424
4412
  raw(voidEl("c:rotX", { val: rel.opts.v3DRotX })),
4425
4413
  raw(voidEl("c:rotY", { val: rel.opts.v3DRotY })),
@@ -4532,26 +4520,31 @@ function makeChartAxesXml(rel, plan) {
4532
4520
  const valOverride = (idx) => rel.opts.valAxes?.[idx];
4533
4521
  const overrideCount = rel.opts.valAxes?.length ?? 0;
4534
4522
  if (overrideCount > 2) warn("chart/option-not-supported", `"valAxes" and "catAxes" have ${overrideCount} entries, but a chart has one primary and one secondary axis of each kind; the entries past the second are ignored.`);
4523
+ const crossing = (key, entry) => entry?.[key] === void 0 ? {} : { [key]: entry[key] };
4535
4524
  strXml += makeCatAxis({
4536
4525
  ...rel.opts,
4537
4526
  ...catOverride(0),
4527
+ ...crossing("valAxisCrossesAt", valOverride(0)),
4538
4528
  ...comboCatAxisType(false)
4539
4529
  }, AXIS_ID_CATEGORY_PRIMARY, AXIS_ID_VALUE_PRIMARY);
4540
4530
  strXml += makeValAxis({
4541
4531
  ...rel.opts,
4542
- ...valOverride(0)
4532
+ ...valOverride(0),
4533
+ ...crossing("catAxisCrossesAt", catOverride(0))
4543
4534
  }, AXIS_ID_VALUE_PRIMARY);
4544
4535
  if (rel.opts._type === "bar3D" || rel.opts._type === "surface") strXml += makeSerAxis(rel.opts, AXIS_ID_SERIES_PRIMARY, AXIS_ID_VALUE_PRIMARY);
4545
4536
  if (plan.secondary) {
4546
4537
  strXml += makeValAxis({
4547
4538
  ...rel.opts,
4548
4539
  ...plan.secondaryVal ? {} : { valAxisHidden: true },
4549
- ...valOverride(1)
4540
+ ...valOverride(1),
4541
+ ...crossing("catAxisCrossesAt", catOverride(1))
4550
4542
  }, AXIS_ID_VALUE_SECONDARY);
4551
4543
  strXml += makeCatAxis({
4552
4544
  ...rel.opts,
4553
4545
  ...plan.secondaryCat ? {} : { catAxisHidden: true },
4554
4546
  ...catOverride(1),
4547
+ ...crossing("valAxisCrossesAt", valOverride(1)),
4555
4548
  ...comboCatAxisType(true)
4556
4549
  }, AXIS_ID_CATEGORY_SECONDARY, AXIS_ID_VALUE_SECONDARY);
4557
4550
  }
@@ -4564,7 +4557,7 @@ function makeChartAxesXml(rel, plan) {
4564
4557
  *
4565
4558
  * The lightest of the four `BorderProps` strokes: paint only, with neither the `a:prstDash`
4566
4559
  * nor the `a:round` its siblings write. It also branches on the border being *absent* rather
4567
- * than on `type: 'none'` — the caller here has an optional border where
4560
+ * than on `type: 'none'`: the caller here has an optional border where
4568
4561
  * `createChartBorderLine` (`gen/chart/chart-parts.ts`) has a resolved one.
4569
4562
  */
4570
4563
  function chartShapeProps(fill, border) {
@@ -4680,7 +4673,7 @@ function makeLegendXml(rel) {
4680
4673
  for (const type of legendOrder(rel.opts, rel.opts._type)) {
4681
4674
  const seriesCount = isXyChart(asChartType(type.type)) ? Math.max(0, type.data.length - 1) : type.data.length;
4682
4675
  for (let i = 0; i < seriesCount; i++, position++) {
4683
- if (type.options?.showLegend !== false) continue;
4676
+ if (type.options.showLegend !== false) continue;
4684
4677
  entries += el("c:legendEntry", null, [raw(voidEl("c:idx", { val: position })), raw(voidEl("c:delete", { val: 1 }))]);
4685
4678
  }
4686
4679
  }
@@ -4733,9 +4726,10 @@ function makeXmlCharts(rel) {
4733
4726
  const secondary = plotsOnSecondaryAxes(options);
4734
4727
  const valAxisId = secondary ? AXIS_ID_VALUE_SECONDARY : AXIS_ID_VALUE_PRIMARY;
4735
4728
  const catAxisId = secondary ? AXIS_ID_CATEGORY_SECONDARY : AXIS_ID_CATEGORY_PRIMARY;
4736
- plots += makeChartType(asChartType(type.type), type.data, options, valAxisId, catAxisId, sheet);
4729
+ const plotOptions = withAxisValueFormat(options, rel.opts.valAxes?.[secondary ? 1 : 0], type.options.valLabelFormatCode);
4730
+ plots += makeChartType(asChartType(type.type), type.data, plotOptions, valAxisId, catAxisId, sheet);
4737
4731
  }
4738
- else if (rel.opts._type) plots = makeChartType(rel.opts._type, rel.data, rel.opts, AXIS_ID_VALUE_PRIMARY, AXIS_ID_CATEGORY_PRIMARY, sheet);
4732
+ else if (rel.opts._type) plots = makeChartType(rel.opts._type, rel.data, withAxisValueFormat(rel.opts, rel.opts.valAxes?.[0], void 0), AXIS_ID_VALUE_PRIMARY, AXIS_ID_CATEGORY_PRIMARY, sheet);
4739
4733
  const axes = makeChartAxesXml(rel, plan);
4740
4734
  const plotArea = el("c:plotArea", null, [
4741
4735
  raw(makePlotAreaLayoutXml(rel)),
@@ -4762,14 +4756,6 @@ function makeXmlCharts(rel) {
4762
4756
  ]);
4763
4757
  }
4764
4758
  /**
4765
- * Stable ts-pptx vendor GUID identifying the chart-metadata extension on `c:chartSpace/c:extLst`.
4766
- * Custom data rides under this URI in a foreign namespace so PowerPoint preserves it (the extLst
4767
- * mechanism) instead of stripping/repairing it as it would an unrecognised sibling element.
4768
- */
4769
- const CHART_METADATA_EXT_URI = "{094A432E-1F6C-499B-95B8-B57DC9536949}";
4770
- /** Foreign namespace for the chart-metadata extension payload. */
4771
- const CHART_METADATA_NS = "http://ts-pptx.com/schema/chart/metadata";
4772
- /**
4773
4759
  * Create the chart-space extension-list XML carrying custom `metadata` key/value annotations.
4774
4760
  * Emits nothing when metadata is absent or contains no valid entries. Keys must be non-empty
4775
4761
  * strings and values must be strings; invalid entries are dropped with a warning rather than
@@ -4785,7 +4771,7 @@ function genXmlChartMetadata(metadata) {
4785
4771
  }
4786
4772
  let items = "";
4787
4773
  for (const [key, value] of Object.entries(metadata)) {
4788
- if (typeof key !== "string" || key.length === 0) {
4774
+ if (key.length === 0) {
4789
4775
  warn("chart/invalid-metadata-key", `chart metadata key "${String(key)}" is not a non-empty string; entry skipped.`);
4790
4776
  continue;
4791
4777
  }
@@ -4802,6 +4788,22 @@ function genXmlChartMetadata(metadata) {
4802
4788
  return el("c:extLst", null, raw(el("c:ext", { uri: CHART_METADATA_EXT_URI }, raw(el("pgm:metadata", { "xmlns:pgm": CHART_METADATA_NS }, raw(items))))));
4803
4789
  }
4804
4790
  /**
4791
+ * A plot's options with the value format its series caches take: a subchart's own
4792
+ * `valLabelFormatCode`, else the one stated on the `valAxes` entry for the axis it plots on, else
4793
+ * the chart's. The entry's format was spread over that axis' builder only, which never reads it, so
4794
+ * the caches kept the chart's (#142).
4795
+ * @param opts - the plot's resolved options
4796
+ * @param axis - the `valAxes` entry for the value axis the plot is on
4797
+ * @param own - the format the subchart states itself
4798
+ */
4799
+ function withAxisValueFormat(opts, axis, own) {
4800
+ const format = own ?? axis?.valLabelFormatCode;
4801
+ return format === void 0 ? opts : {
4802
+ ...opts,
4803
+ valLabelFormatCode: format
4804
+ };
4805
+ }
4806
+ /**
4805
4807
  * Create XML string for any given chart type.
4806
4808
  * Dispatches to a per-family plot helper; resolves the effective value number format first.
4807
4809
  * @param {ChartType} chartType chart type name
@@ -4828,11 +4830,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId, sheet) {
4828
4830
  case "surface": return makeSurfacePlot(chartType, data, opts, valAxisId, catAxisId, valFmtCode, sheet);
4829
4831
  case "doughnut":
4830
4832
  case "pie": return makePiePlot(chartType, data, opts, valFmtCode, sheet);
4831
- default: throw new InternalError("chart/type-not-routed", `makeChartType: "${String(chartType)}" has no <c:...Chart> plot — the chartEx catalog is built by makeXmlChartEx, and a newly added classic type needs an arm here`, { detail: { chartType } });
4833
+ default: throw new InternalError("chart/type-not-routed", `makeChartType: "${String(chartType)}" has no <c:...Chart> plot: the chartEx catalog is built by makeXmlChartEx, and a newly added classic type needs an arm here`, { detail: { chartType } });
4832
4834
  }
4833
4835
  }
4834
- //#endregion
4835
- //#region src/gen/chart/chartex-data.ts
4836
+ // src/gen/chart/chartex-data.ts
4836
4837
  /**
4837
4838
  * The numeric-dimension tag PowerPoint expects varies by layout. The flat layouts (waterfall,
4838
4839
  * funnel, histogram, pareto, boxWhisker) use `type="val"`; the hierarchical treemap/sunburst use
@@ -4852,7 +4853,7 @@ function valueDimType(type) {
4852
4853
  * `<cx:externalData r:id="rId1">` points at the embedded workbook (same `rId1` the chart part's
4853
4854
  * `.rels` maps to the `.xlsx`).
4854
4855
  *
4855
- * Category labels are `string[][]` — one inner array per hierarchy level (leaf first). A flat chart
4856
+ * Category labels are `string[][]`: one inner array per hierarchy level (leaf first). A flat chart
4856
4857
  * has a single level; treemap/sunburst carry several. Each level becomes one `<cx:lvl>`, emitted
4857
4858
  * leaf-first to match PowerPoint. The workbook ({@link ./embed-xlsx}) lays the levels out in
4858
4859
  * columns A..N (outermost in A, leaf in the last label column) with the value series in the next
@@ -4901,7 +4902,7 @@ function makeChartExData(rel, sheet) {
4901
4902
  return el("cx:chartData", null, [raw(externalData), raw(data)]);
4902
4903
  }
4903
4904
  /**
4904
- * The `Sheet1` cell holding the series name (the numeric dimension's header) — column immediately
4905
+ * The `Sheet1` cell holding the series name (the numeric dimension's header): the column immediately
4905
4906
  * after all label columns, row 1. A category-less histogram lands on `$A$1`; a flat chart on
4906
4907
  * `$B$1`; a 3-level treemap on `$D$1`.
4907
4908
  * @param {WorksheetLayout} sheet - the chart's worksheet layout
@@ -4910,12 +4911,11 @@ function makeChartExData(rel, sheet) {
4910
4911
  function chartExSeriesNameRef(sheet) {
4911
4912
  return sheetCellRef(sheet.valueColumn(0), 1);
4912
4913
  }
4913
- //#endregion
4914
- //#region src/gen/chart/chartex-xml.ts
4914
+ // src/gen/chart/chartex-xml.ts
4915
4915
  /**
4916
- * ts-pptx: chartEx (`cx:`) Chart Assembly
4916
+ * pptx-ts: chartEx (`cx:`) Chart Assembly
4917
4917
  *
4918
- * Builds a chartEx chart part `ppt/charts/chartEx{N}.xml` — the `<cx:chartSpace>` for the
4918
+ * Builds a chartEx chart part `ppt/charts/chartEx{N}.xml`: the `<cx:chartSpace>` for the
4919
4919
  * Office-2016 chart family (currently `waterfall`, `funnel`, `treemap`, `sunburst`, `histogram`,
4920
4920
  * `pareto`, `boxWhisker`, `regionMap`).
4921
4921
  * This is the chartEx analogue of
@@ -4932,7 +4932,7 @@ function chartExSeriesNameRef(sheet) {
4932
4932
  */
4933
4933
  /**
4934
4934
  * Map a chartEx {@link ChartType} to its `<cx:series layoutId>` token (the CT_SeriesLayout value
4935
- * PowerPoint keys the chart geometry on). Throws on anything it does not own — see the `default`
4935
+ * PowerPoint keys the chart geometry on). Throws on anything it does not own; see the `default`
4936
4936
  * arm for which members those are and why reaching it is a routing bug.
4937
4937
  */
4938
4938
  function chartExLayoutId(type) {
@@ -4944,13 +4944,13 @@ function chartExLayoutId(type) {
4944
4944
  case "histogram": return "clusteredColumn";
4945
4945
  case "boxWhisker": return "boxWhisker";
4946
4946
  case "regionMap": return "regionMap";
4947
- default: throw new InternalError("chart/type-not-routed", `chartExLayoutId: "${String(type)}" has no <cx:series> layoutId — classic chart types belong to makeXmlCharts, pareto is built by makeParetoSeries, and a newly added chartEx type needs an arm here`, { detail: { chartType: type } });
4947
+ default: throw new InternalError("chart/type-not-routed", `chartExLayoutId: "${String(type)}" has no <cx:series> layoutId: classic chart types belong to makeXmlCharts, pareto is built by makeParetoSeries, and a newly added chartEx type needs an arm here`, { detail: { chartType: type } });
4948
4948
  }
4949
4949
  }
4950
4950
  /**
4951
4951
  * A deterministic `uniqueId` GUID for a `<cx:series>`, derived from the chart's package-global id.
4952
4952
  * PowerPoint stamps a random GUID here; deriving it keeps output byte-stable (the project pins
4953
- * chart determinism — the package-wide id this derives from is assigned at write time in
4953
+ * chart determinism; the package-wide id this derives from is assigned at write time in
4954
4954
  * `package/assemble.ts`, STEP 2). `seriesIdx`
4955
4955
  * distinguishes multiple series within one chart (pareto emits two), varying the 4th GUID group so
4956
4956
  * every series still gets a distinct id.
@@ -4965,10 +4965,10 @@ function chartExLegendPos(pos) {
4965
4965
  /**
4966
4966
  * The `<cx:axisId>` binding on a `<cx:series>` (which value/category axis the series plots against).
4967
4967
  *
4968
- * NOTE — a schema-vs-PowerPoint divergence (the exact mirror of the histogram `binCount` gotcha):
4968
+ * NOTE: a schema-vs-PowerPoint divergence (the exact mirror of the histogram `binCount` gotcha):
4969
4969
  * the OpenXML SDK models `cx:axisId` as an `OpenXmlLeafTextElement`, so the OOXML validator only
4970
4970
  * accepts the text-content form `<cx:axisId>1</cx:axisId>` and flags the `val` attribute as
4971
- * undeclared. But PowerPoint desktop REFUSES to open a deck using the text form (0x80070570) — it
4971
+ * undeclared. But PowerPoint desktop REFUSES to open a deck using the text form (0x80070570). It
4972
4972
  * writes and requires the ATTRIBUTE form `<cx:axisId val="1"/>` (matching the classic `c:axId`).
4973
4973
  * PowerPoint is the authoritative oracle here, so the attribute form is emitted; the resulting
4974
4974
  * validator complaint on `cx:axisId/@val` is expected and whitelisted in the schema-case test.
@@ -4978,20 +4978,20 @@ function makeChartExAxisId(id) {
4978
4978
  }
4979
4979
  /**
4980
4980
  * Build the histogram `<cx:binning>` element from the caller's `binning` opt. PowerPoint bins the
4981
- * raw observations automatically; the only control wired here is `intervalClosed` — whether each
4981
+ * raw observations automatically; the only control wired here is `intervalClosed`: whether each
4982
4982
  * bin interval is right-closed (`"r"`, PowerPoint's default) or left-closed (`"l"`).
4983
4983
  *
4984
4984
  * NOTE: explicit bin geometry (`binCount`/`binSize` child elements, `underflow`/`overflow`
4985
4985
  * attributes) is intentionally NOT emitted. Although `<cx:binCount>`/`<cx:binSize>` pass OOXML
4986
4986
  * schema validation (they are declared children of `cx:binning` in the OpenXML SDK), PowerPoint
4987
- * desktop refuses to open a deck that contains them (0x80004005) — so shipping them would corrupt
4987
+ * desktop refuses to open a deck that contains them (0x80004005), so shipping them would corrupt
4988
4988
  * the file. They stay deferred until their real requirements are pinned down against PowerPoint.
4989
4989
  */
4990
4990
  function makeChartExBinning(binning) {
4991
4991
  return voidEl("cx:binning", { intervalClosed: binning?.intervalClosed === "l" ? "l" : "r" });
4992
4992
  }
4993
4993
  /**
4994
- * Build the box-and-whisker `<cx:layoutPr>` body — a `<cx:visibility>` toggle set plus a
4994
+ * Build the box-and-whisker `<cx:layoutPr>` body: a `<cx:visibility>` toggle set plus a
4995
4995
  * `<cx:statistics>` quartile-method choice, in that document order (what PowerPoint itself emits).
4996
4996
  * All flags default to PowerPoint's own defaults: exclusive quartiles, mean marker on, outlier
4997
4997
  * points on, the mean-line and the full non-outlier scatter off. Booleans map to the `0`/`1`
@@ -5009,16 +5009,16 @@ function makeBoxWhiskerLayoutPr(stats) {
5009
5009
  return el("cx:layoutPr", null, [raw(visibility), raw(statistics)]);
5010
5010
  }
5011
5011
  /**
5012
- * Build the region-map `<cx:layoutPr>` body — a single `<cx:geography>` hint telling PowerPoint how
5012
+ * Build the region-map `<cx:layoutPr>` body: a single `<cx:geography>` hint telling PowerPoint how
5013
5013
  * to interpret the category labels as geographic region names. `cultureLanguage`/`cultureRegion`
5014
5014
  * (both schema-REQUIRED) resolve ambiguous names (e.g. "Georgia" the country vs. the US state);
5015
5015
  * `attribution` is Bing's fixed acknowledgement string.
5016
5016
  *
5017
- * NOTE — PowerPoint itself also nests a `<cx:geoCache>` here holding a base64 binary blob: its
5017
+ * NOTE: PowerPoint itself also nests a `<cx:geoCache>` here holding a base64 binary blob: its
5018
5018
  * cached Bing geometry for the resolved regions. That blob is produced by an online Bing lookup and
5019
5019
  * cannot be reproduced offline, so it is intentionally OMITTED. PowerPoint re-resolves the geography
5020
5020
  * from the region names when the deck is opened (verified over COM: the deck opens and reads back as
5021
- * a regionMap either way) — this is why a region map is documented as best-effort/write-only and
5021
+ * a regionMap either way). This is why a region map is documented as best-effort/write-only and
5022
5022
  * renders blank if the names don't match PowerPoint's geography database.
5023
5023
  */
5024
5024
  function makeGeographyLayoutPr(geo) {
@@ -5045,7 +5045,7 @@ function makeChartExDataLabels(rel) {
5045
5045
  }))) : "";
5046
5046
  }
5047
5047
  /**
5048
- * Build the pareto `<cx:series>` PAIR — pareto is the first chartEx layout that emits more than one
5048
+ * Build the pareto `<cx:series>` PAIR; pareto is the first chartEx layout that emits more than one
5049
5049
  * series. Series 0 is a `clusteredColumn` bound to value axis 1 whose `<cx:aggregation/>` tells
5050
5050
  * PowerPoint to sum the values per category, sort the bars descending, and drive the cumulative
5051
5051
  * line. Series 1 is the `paretoLine` itself: it carries `ownerIdx="0"` (it derives its data from
@@ -5073,7 +5073,7 @@ function makeChartExSeries(rel, sheet) {
5073
5073
  const type = opts._type;
5074
5074
  if (type === "pareto") return makeParetoSeries(rel, sheet);
5075
5075
  let layoutPr = "";
5076
- if (type === "waterfall" && Array.isArray(opts.subtotals) && opts.subtotals.length > 0) {
5076
+ if (type === "waterfall" && opts.subtotals) {
5077
5077
  const idxs = opts.subtotals.map((idx) => voidEl("cx:idx", { val: idx })).join("");
5078
5078
  layoutPr = el("cx:layoutPr", null, raw(el("cx:subtotals", null, raw(idxs))));
5079
5079
  } else if (type === "treemap") layoutPr = el("cx:layoutPr", null, raw(voidEl("cx:parentLabelLayout", { val: "overlapping" })));
@@ -5120,8 +5120,8 @@ const CHARTEX_CAT_GAP_WIDTH = {
5120
5120
  /**
5121
5121
  * Build the `<cx:axis>` list for a layout, matched to what PowerPoint itself emits for each.
5122
5122
  *
5123
- * Four of the five axis-bearing layouts are the same pair — a category axis (id 0) and a
5124
- * gridlined value axis (id 1) — differing only in gap width, so they are a table rather than
5123
+ * Four of the five axis-bearing layouts are the same pair, a category axis (id 0) and a
5124
+ * gridlined value axis (id 1), differing only in gap width, so they are a table rather than
5125
5125
  * four arms. The two that are not: the **funnel** has a SINGLE category axis, which PowerPoint
5126
5126
  * numbers id 1, with no value axis and no gridlines (its bars run horizontally off one
5127
5127
  * category scale); and the **pareto** adds a third axis for its cumulative line.
@@ -5186,21 +5186,20 @@ function makeXmlChartEx(rel) {
5186
5186
  "xmlns:r": OOXML_NS.r
5187
5187
  }, [raw(makeChartExData(rel, sheet)), raw(chart)]);
5188
5188
  }
5189
- //#endregion
5190
- //#region src/gen/chart/chartex-style.ts
5189
+ // src/gen/chart/chartex-style.ts
5191
5190
  /**
5192
- * ts-pptx: chartEx (cx:) Style + Color Parts
5191
+ * pptx-ts: chartEx (cx:) Style + Color Parts
5193
5192
  *
5194
5193
  * Every chartEx chart part (`chartEx{N}.xml`) MUST be accompanied by a chart-style part
5195
5194
  * (`style{N}.xml`, `cs:chartStyle`) and a chart-color-style part (`colors{N}.xml`,
5196
5195
  * `cs:colorStyle`), linked from the chartEx part's `.rels` via the MS `chartStyle` /
5197
5196
  * `chartColorStyle` relationship types. This is NOT optional: PowerPoint reports a chartEx deck
5198
- * that lacks them as corrupt (0x80070570) — a failure the OOXML schema validator does not catch,
5197
+ * that lacks them as corrupt (0x80070570), a failure the OOXML schema validator does not catch,
5199
5198
  * found via the desktop COM smoke (`pnpm run test:com`).
5200
5199
  *
5201
5200
  * The two payloads below are PowerPoint's own generic, chart-type-agnostic defaults (the same
5202
5201
  * boilerplate Office writes for any new chartEx chart), captured verbatim and shipped as a static
5203
- * template — analogous to the default theme/worksheet boilerplate the library already embeds. They
5202
+ * template, analogous to the default theme/worksheet boilerplate the library already embeds. They
5204
5203
  * reference theme scheme colors, so they adapt to the deck theme without per-chart customization.
5205
5204
  */
5206
5205
  /**
@@ -5221,18 +5220,17 @@ function makeChartExColorsXml() {
5221
5220
  function makeChartExStyleXml() {
5222
5221
  return XML_DECL + CHARTEX_STYLE_BODY;
5223
5222
  }
5224
- //#endregion
5225
- //#region src/gen/chart/embed-xlsx.ts
5223
+ // src/gen/chart/embed-xlsx.ts
5226
5224
  /**
5227
- * ts-pptx: Chart Embedded-Workbook Generation
5225
+ * pptx-ts: Chart Embedded-Workbook Generation
5228
5226
  *
5229
- * Builds the embedded `.xlsx` workbook that backs a chart's cached data — the data
5227
+ * Builds the embedded `.xlsx` workbook that backs a chart's cached data: the data
5230
5228
  * source PowerPoint opens when a user edits the chart. `createExcelWorksheet` writes
5231
5229
  * the workbook plus the chart part + its `.rels` into the presentation package;
5232
5230
  * `buildEmbeddedWorksheet` and `chartPartBodies` are also used by slide extraction
5233
- * (`TsPptx.extractSlides`), whose chart relationships `appendSlides` rebuilds itself against the
5231
+ * (`PptxTs.extractSlides`), whose chart relationships `appendSlides` rebuilds itself against the
5234
5232
  * parts it reserves. Everything here is a pure string/bytes
5235
- * builder — no I/O beyond the passed-in ZipWriter, no mutation of the presentation model.
5233
+ * builder: no I/O beyond the passed-in ZipWriter, no mutation of the presentation model.
5236
5234
  *
5237
5235
  * The chart's `chart.xml` DrawingML lives in `./chart-xml.ts`; the series↔worksheet-cell
5238
5236
  * mapping the two sides share lives in `./data-refs.ts`.
@@ -5262,10 +5260,10 @@ const XLSX_STYLES_XML = "<styleSheet xmlns=\"http://schemas.openxmlformats.org/s
5262
5260
  const XLSX_THEME_XML = "<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office Theme\"><a:themeElements><a:clrScheme name=\"Office\"><a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1><a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1><a:dk2><a:srgbClr val=\"44546A\"/></a:dk2><a:lt2><a:srgbClr val=\"E7E6E6\"/></a:lt2><a:accent1><a:srgbClr val=\"4472C4\"/></a:accent1><a:accent2><a:srgbClr val=\"ED7D31\"/></a:accent2><a:accent3><a:srgbClr val=\"A5A5A5\"/></a:accent3><a:accent4><a:srgbClr val=\"FFC000\"/></a:accent4><a:accent5><a:srgbClr val=\"5B9BD5\"/></a:accent5><a:accent6><a:srgbClr val=\"70AD47\"/></a:accent6><a:hlink><a:srgbClr val=\"0563C1\"/></a:hlink><a:folHlink><a:srgbClr val=\"954F72\"/></a:folHlink></a:clrScheme><a:fontScheme name=\"Office\"><a:majorFont><a:latin typeface=\"Calibri Light\" panose=\"020F0302020204030204\"/><a:ea typeface=\"\"/><a:cs typeface=\"\"/><a:font script=\"Jpan\" typeface=\"Yu Gothic Light\"/><a:font script=\"Hang\" typeface=\"맑은 고딕\"/><a:font script=\"Hans\" typeface=\"DengXian Light\"/><a:font script=\"Hant\" typeface=\"新細明體\"/><a:font script=\"Arab\" typeface=\"Times New Roman\"/><a:font script=\"Hebr\" typeface=\"Times New Roman\"/><a:font script=\"Thai\" typeface=\"Tahoma\"/><a:font script=\"Ethi\" typeface=\"Nyala\"/><a:font script=\"Beng\" typeface=\"Vrinda\"/><a:font script=\"Gujr\" typeface=\"Shruti\"/><a:font script=\"Khmr\" typeface=\"MoolBoran\"/><a:font script=\"Knda\" typeface=\"Tunga\"/><a:font script=\"Guru\" typeface=\"Raavi\"/><a:font script=\"Cans\" typeface=\"Euphemia\"/><a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/><a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/><a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/><a:font script=\"Thaa\" typeface=\"MV Boli\"/><a:font script=\"Deva\" typeface=\"Mangal\"/><a:font script=\"Telu\" typeface=\"Gautami\"/><a:font script=\"Taml\" typeface=\"Latha\"/><a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/><a:font script=\"Orya\" typeface=\"Kalinga\"/><a:font script=\"Mlym\" typeface=\"Kartika\"/><a:font script=\"Laoo\" typeface=\"DokChampa\"/><a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/><a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/><a:font script=\"Viet\" typeface=\"Times New Roman\"/><a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/><a:font script=\"Geor\" typeface=\"Sylfaen\"/></a:majorFont><a:minorFont><a:latin typeface=\"Calibri\" panose=\"020F0502020204030204\"/><a:ea typeface=\"\"/><a:cs typeface=\"\"/><a:font script=\"Jpan\" typeface=\"Yu Gothic\"/><a:font script=\"Hang\" typeface=\"맑은 고딕\"/><a:font script=\"Hans\" typeface=\"DengXian\"/><a:font script=\"Hant\" typeface=\"新細明體\"/><a:font script=\"Arab\" typeface=\"Arial\"/><a:font script=\"Hebr\" typeface=\"Arial\"/><a:font script=\"Thai\" typeface=\"Tahoma\"/><a:font script=\"Ethi\" typeface=\"Nyala\"/><a:font script=\"Beng\" typeface=\"Vrinda\"/><a:font script=\"Gujr\" typeface=\"Shruti\"/><a:font script=\"Khmr\" typeface=\"DaunPenh\"/><a:font script=\"Knda\" typeface=\"Tunga\"/><a:font script=\"Guru\" typeface=\"Raavi\"/><a:font script=\"Cans\" typeface=\"Euphemia\"/><a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/><a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/><a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/><a:font script=\"Thaa\" typeface=\"MV Boli\"/><a:font script=\"Deva\" typeface=\"Mangal\"/><a:font script=\"Telu\" typeface=\"Gautami\"/><a:font script=\"Taml\" typeface=\"Latha\"/><a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/><a:font script=\"Orya\" typeface=\"Kalinga\"/><a:font script=\"Mlym\" typeface=\"Kartika\"/><a:font script=\"Laoo\" typeface=\"DokChampa\"/><a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/><a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/><a:font script=\"Viet\" typeface=\"Arial\"/><a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/><a:font script=\"Geor\" typeface=\"Sylfaen\"/></a:minorFont></a:fontScheme>" + FMT_SCHEME_XML + "</a:themeElements><a:objectDefaults/><a:extraClrSchemeLst/><a:extLst><a:ext uri=\"{05A4C25C-085E-4340-85A3-A5531E510DB2}\"><thm15:themeFamily xmlns:thm15=\"http://schemas.microsoft.com/office/thememl/2012/main\" name=\"Office Theme\" id=\"{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}\" vid=\"{4A3C46E8-61CC-4603-A589-7422A47A8E4A}\"/></a:ext></a:extLst></a:theme>";
5263
5261
  /**
5264
5262
  * Build the chart's embedded Excel workbook as a standalone OPC package and
5265
- * return its bytes — the data source PowerPoint opens when a user edits the
5263
+ * return its bytes: the data source PowerPoint opens when a user edits the
5266
5264
  * chart's data. Pure (no zip side effects), so both the package write path
5267
5265
  * ({@link createExcelWorksheet}) and the read-side injection path
5268
- * (`TsPptx.extractSlides`) can reuse it.
5266
+ * (`PptxTs.extractSlides`) can reuse it.
5269
5267
  * @param {SlideRelChart} chartObject - chart object
5270
5268
  * @return {Uint8Array} the embedded `.xlsx` package bytes
5271
5269
  */
@@ -5324,13 +5322,7 @@ function buildEmbeddedWorksheet(chartObject) {
5324
5322
  raw(el("HyperlinksChanged", null, "false")),
5325
5323
  raw(el("AppVersion", null, "16.0300"))
5326
5324
  ]) + "\n");
5327
- const now = coreTimestamp();
5328
- zipExcel.add("docProps/core.xml", XML_DECL + el("cp:coreProperties", CORE_PROPS_NS, [
5329
- raw(el("dc:creator", null, "TsPptx")),
5330
- raw(el("cp:lastModifiedBy", null, "TsPptx")),
5331
- raw(el("dcterms:created", { "xsi:type": "dcterms:W3CDTF" }, now)),
5332
- raw(el("dcterms:modified", { "xsi:type": "dcterms:W3CDTF" }, now))
5333
- ]));
5325
+ zipExcel.add("docProps/core.xml", XML_DECL + el("cp:coreProperties", CORE_PROPS_NS, [raw(el("dc:creator", null, "pptx-ts")), raw(el("cp:lastModifiedBy", null, "pptx-ts"))]));
5334
5326
  zipExcel.add("xl/_rels/workbook.xml.rels", XML_DECL + relationshipsEl([
5335
5327
  relationshipEl("rId3", OFFICE_REL + "styles", "styles.xml"),
5336
5328
  relationshipEl("rId2", THEME_REL, "theme/theme1.xml"),
@@ -5468,7 +5460,7 @@ function buildXlsxSheet(data, layout) {
5468
5460
  * reached this sheet (`?? ''` at the call sites) and which Excel reads back as an empty cell.
5469
5461
  * A **non-finite** number is the same thing: `<v>Infinity</v>` (or `NaN`, or `INF`) is not a
5470
5462
  * number Excel will parse, and it refuses the whole workbook with 0x3EC rather than skipping
5471
- * the cell — a failure PowerPoint hides, because it does not parse the embedding on open. It
5463
+ * the cell. PowerPoint hides that failure, because it does not parse the embedding on open. It
5472
5464
  * surfaces on "Edit Data", by which point the chart's own cache is already clean: `numCachePt`
5473
5465
  * (`./chart-parts.ts`) and the chartEx numeric dimension (`./chartex-data.ts`) both drop a
5474
5466
  * non-finite point, with a `chart/non-finite-value` warning, before it reaches the chart part.
@@ -5532,14 +5524,17 @@ function buildXlsxSheet(data, layout) {
5532
5524
  ]) + "\n";
5533
5525
  }
5534
5526
  /**
5535
- * Build the standalone `.rels` for a classic chart part: a single `rId1` relationship to the
5536
- * chart's embedded workbook (`Target`). Package write path only: `appendSlides` builds a chart's
5537
- * relationships through the package model instead.
5527
+ * Build the standalone `.rels` for a classic chart part: an `rId1` relationship to the chart's
5528
+ * embedded workbook (`Target`), then one per picture an area fill paints. A media `Target` is
5529
+ * `../media/…` from `ppt/slides/` and from `ppt/charts/` alike, so the slide's reads the same here.
5530
+ * Package write path only: `appendSlides` builds a chart's relationships through the package model
5531
+ * instead.
5538
5532
  * @param {string} embeddingTarget - the workbook target, relative to the chart part
5533
+ * @param media - the chart's pictures, {@link SlideRelChart.media}
5539
5534
  * @return {string} the chart part's `.rels` XML
5540
5535
  */
5541
- function buildChartRelsXml(embeddingTarget) {
5542
- return XML_DECL + relationshipsEl([relationshipEl("rId1", PACKAGE_REL, embeddingTarget)]);
5536
+ function buildChartRelsXml(embeddingTarget, media) {
5537
+ return XML_DECL + relationshipsEl([relationshipEl("rId1", PACKAGE_REL, embeddingTarget), ...(media ?? []).map((picture) => relationshipEl(`rId${picture.rId}`, IMAGE_REL, picture.rel.Target))]);
5543
5538
  }
5544
5539
  /**
5545
5540
  * Build the `.rels` for a chartEx chart part: the embedded workbook (rId1, via `<cx:externalData>`)
@@ -5592,12 +5587,11 @@ async function createExcelWorksheet(chartObject, zip) {
5592
5587
  zip.add(`ppt/charts/${names.colorsName}`, bodies.chartEx.colorsXml);
5593
5588
  zip.add(`ppt/charts/${names.styleName}`, bodies.chartEx.styleXml);
5594
5589
  zip.add("ppt/charts/_rels/" + chartObject.fileName + ".rels", buildChartExRelsXml(embeddingTarget, names.colorsName, names.styleName));
5595
- } else zip.add("ppt/charts/_rels/" + chartObject.fileName + ".rels", buildChartRelsXml(embeddingTarget));
5590
+ } else zip.add("ppt/charts/_rels/" + chartObject.fileName + ".rels", buildChartRelsXml(embeddingTarget, chartObject.media));
5596
5591
  zip.add(`ppt/charts/${chartObject.fileName}`, bodies.chartXml);
5597
5592
  return "";
5598
5593
  }
5599
- //#endregion
5600
- //#region src/gen/extract-charts.ts
5594
+ // src/gen/extract-charts.ts
5601
5595
  /**
5602
5596
  * Charts: the chart part XML plus its embedded workbook bytes. The chart part's own `.rels`
5603
5597
  * (workbook reference) is rebuilt on injection.
@@ -5609,14 +5603,23 @@ async function createExcelWorksheet(chartObject, zip) {
5609
5603
  * the classic-or-chartEx choice for the package writer too.
5610
5604
  */
5611
5605
  function chartsOf(slide) {
5612
- return (slide._relsChart || []).map((rel) => ({
5606
+ return slide._relsChart.map((rel) => ({
5613
5607
  rId: rel.rId,
5614
5608
  embeddingBytes: buildEmbeddedWorksheet(rel),
5615
- ...chartPartBodies(rel)
5609
+ ...chartPartBodies(rel),
5610
+ pictures: (rel.media ?? []).flatMap((picture) => {
5611
+ const bytes = decodeBase64ToBytes(picture.rel.data);
5612
+ const extn = (picture.rel.extn || "png").toLowerCase();
5613
+ return bytes ? [{
5614
+ rId: picture.rId,
5615
+ bytes,
5616
+ extn,
5617
+ contentType: imageContentType(extn)
5618
+ }] : [];
5619
+ })
5616
5620
  }));
5617
5621
  }
5618
- //#endregion
5619
- //#region src/package/parts/chart.ts
5622
+ // src/package/parts/chart.ts
5620
5623
  /** The embedded workbook every chart carries; one Default covers all of them. */
5621
5624
  const XLSX_DEFAULT = {
5622
5625
  extension: "xlsx",
@@ -5655,7 +5658,7 @@ function chartOverrides(rel, leadingSpace = false) {
5655
5658
  const chartContributor = {
5656
5659
  order: 30,
5657
5660
  parts: { fromTargetRels(target, zip) {
5658
- return (target._relsChart || []).map((rel) => createExcelWorksheet(rel, zip));
5661
+ return target._relsChart.map((rel) => createExcelWorksheet(rel, zip));
5659
5662
  } },
5660
5663
  contentTypes: {
5661
5664
  defaults(pres) {
@@ -5663,23 +5666,22 @@ const chartContributor = {
5663
5666
  ...pres.slides,
5664
5667
  ...pres.slideLayouts,
5665
5668
  pres.masterSlide
5666
- ].some((target) => (target?._relsChart || []).length > 0) ? [XLSX_DEFAULT] : [];
5669
+ ].some((target) => target._relsChart.length > 0) ? [XLSX_DEFAULT] : [];
5667
5670
  },
5668
5671
  perSlide(slide) {
5669
5672
  return slide._relsChart.flatMap((rel) => chartOverrides(rel));
5670
5673
  },
5671
5674
  perLayout(layout) {
5672
- return (layout._relsChart || []).flatMap((rel) => chartOverrides(rel, true));
5675
+ return layout._relsChart.flatMap((rel) => chartOverrides(rel, true));
5673
5676
  },
5674
5677
  trailing(pres) {
5675
- return (pres.masterSlide?._relsChart || []).flatMap((rel) => chartOverrides(rel, true));
5678
+ return pres.masterSlide._relsChart.flatMap((rel) => chartOverrides(rel, true));
5676
5679
  }
5677
5680
  }
5678
5681
  };
5679
- //#endregion
5680
- //#region src/gen/slide/objects/chart.ts
5682
+ // src/gen/slide/objects/chart.ts
5681
5683
  /**
5682
- * ts-pptx: chart slide-object serialization
5684
+ * pptx-ts: chart slide-object serialization
5683
5685
  *
5684
5686
  * Emits a `chart` slide object as the `<p:graphicFrame>` that references the chart part.
5685
5687
  * Classic charts emit that frame bare; chartEx charts wrap it in `<mc:AlternateContent>` with a
@@ -5735,8 +5737,8 @@ function renderChartObject(ctx) {
5735
5737
  const graphicFrame = graphicFrameEl({
5736
5738
  nvGraphicFramePr: el("p:nvGraphicFramePr", null, [
5737
5739
  raw(cNvPrEl(shapeId, itemOpts.objectName, itemOpts.altText || "", void 0, { openPrefix: " " })),
5738
- raw(voidEl("p:cNvGraphicFramePr", null, { openPrefix: " " })),
5739
- raw(el("p:nvPr", null, raw(genXmlPlaceholder(placeholderObj)), { openPrefix: " " }))
5740
+ raw(elOrVoid("p:cNvGraphicFramePr", null, genXmlObjectLock("a:graphicFrameLocks", GRAPHIC_FRAME_LOCK_ATTRS, itemOpts.objectLock, itemOpts.objectName), { openPrefix: " " })),
5741
+ raw(el("p:nvPr", null, raw(genXmlPlaceholder(placeholderObj, statedPlaceholderBinding(itemOpts.placeholder))), { openPrefix: " " }))
5740
5742
  ], {
5741
5743
  openPrefix: " ",
5742
5744
  closePrefix: " "
@@ -5772,7 +5774,7 @@ function renderChartObject(ctx) {
5772
5774
  /**
5773
5775
  * Build the `<mc:Fallback>` placeholder shape shown when a chartEx chart cannot be rendered
5774
5776
  * (any consumer older than PowerPoint 2016 / Microsoft 365). A light-grey rectangle at the chart's
5775
- * position carrying a short explanatory note — enough that the slide reads sensibly rather than
5777
+ * position carrying a short explanatory note, enough that the slide reads sensibly rather than
5776
5778
  * showing a void where the chart would be.
5777
5779
  */
5778
5780
  function renderChartExFallback(shapeId, itemOpts, x, y, cx, cy) {
@@ -5800,10 +5802,9 @@ function renderChartExFallback(shapeId, itemOpts, x, y, cx, cy) {
5800
5802
  ]))
5801
5803
  ]);
5802
5804
  }
5803
- //#endregion
5804
- //#region src/gen/define/chart.ts
5805
+ // src/gen/define/chart.ts
5805
5806
  /**
5806
- * ts-pptx: Chart Definition
5807
+ * pptx-ts: Chart Definition
5807
5808
  *
5808
5809
  * `addChartDefinition` normalizes `addChart()` options onto the slide model and registers the
5809
5810
  * chart part rel; the `normalize*` / `clamp*` helpers apply the schema-valid defaults and range
@@ -5902,8 +5903,8 @@ function reportMismatchedSeries(options, data) {
5902
5903
  * object is shared across two charts.
5903
5904
  *
5904
5905
  * Nested objects are copied wherever a normalizer writes into them. `structuredClone` is
5905
- * deliberately not used: it would deep-copy the `ChartMulti[]` on `_type` — breaking the series
5906
- * identity the combo emit path depends on — and throws on a stray function in an untyped
5906
+ * deliberately not used: it would deep-copy the `ChartMulti[]` on `_type`, breaking the series
5907
+ * identity the combo emit path depends on, and throws on a stray function in an untyped
5907
5908
  * caller's option bag.
5908
5909
  * @param opts - caller-supplied chart options
5909
5910
  */
@@ -5930,7 +5931,7 @@ function copyChartOptions(opts) {
5930
5931
  * A border width the emitter can use: a positive, finite number of points.
5931
5932
  *
5932
5933
  * `0` counts as "not stated" here and takes the default, which is what the truthiness test
5933
- * this replaces already did. What it adds is `Infinity` and a negative — neither is a width,
5934
+ * this replaces already did. What it adds is `Infinity` and a negative. Neither is a width,
5934
5935
  * and a negative one reached `a:ln/@w` as a negative attribute.
5935
5936
  */
5936
5937
  function isUsableBorderWidth(width) {
@@ -6142,6 +6143,70 @@ function normalizeAxisOptions(axis, prefix) {
6142
6143
  }
6143
6144
  if (axis.valAxisLogScaleBase != null) axis.valAxisLogScaleBase = clampRangedInput(axis.valAxisLogScaleBase, 2, 1e3, "chart/option-out-of-range", `${prefix}valAxisLogScaleBase`, "chart/option-non-finite");
6144
6145
  }
6146
+ /** `YYYY-MM-DD`, optionally with a `THH:MM` or `THH:MM:SS` time (a space works as well as `T`). */
6147
+ const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2}))?)?$/;
6148
+ /** Days from the spreadsheet epoch (serial 0, 1899-12-30) to the Unix epoch. */
6149
+ const SERIAL_UNIX_EPOCH = 25569;
6150
+ /** 1900-03-01: earlier serials are skewed by the spreadsheet's phantom 1900-02-29. */
6151
+ const FIRST_SAFE_SERIAL = 61;
6152
+ /**
6153
+ * A category label as the date serial a `<c:numCache>` point holds, or `null` when it is not one.
6154
+ *
6155
+ * A number passes, written plainly (`'1e3'` is 1000): it already is a serial. An ISO date or date-time becomes its serial, read
6156
+ * as calendar time, so `'2026-01-01'` is 46023 in every time zone. A date that does not exist, such
6157
+ * as `'2026-02-30'`, or one before 1900-03-01 is not converted.
6158
+ * @param label - one category label, not blank
6159
+ */
6160
+ function dateCategorySerial(label) {
6161
+ const number = Number(label);
6162
+ if (Number.isFinite(number)) return String(number);
6163
+ const m = ISO_DATE.exec(label.trim());
6164
+ if (!m) return null;
6165
+ const [y, mo, d, h, mi, s] = m.slice(1).map((group) => Number(group ?? 0));
6166
+ if (y === void 0 || mo === void 0 || d === void 0 || h === void 0 || mi === void 0 || s === void 0) return null;
6167
+ const ms = Date.UTC(y, mo - 1, d, h, mi, s);
6168
+ const date = new Date(ms);
6169
+ if (date.getUTCMonth() !== mo - 1 || date.getUTCDate() !== d || h > 23 || mi > 59 || s > 59) return null;
6170
+ const serial = ms / 864e5 + SERIAL_UNIX_EPOCH;
6171
+ return serial >= FIRST_SAFE_SERIAL ? String(serial) : null;
6172
+ }
6173
+ /**
6174
+ * Turn the leaf category labels into date serials when `catLabelFormatCode` makes them dates, or drop
6175
+ * the format code, warning, when one of them is not a date.
6176
+ *
6177
+ * A format code makes the categories a `<c:numRef>` under a `<c:dateAx>`, and its cache was written
6178
+ * from the labels as given. PowerPoint refuses the whole deck (0x80070570) over one `<c:numCache>`
6179
+ * point that is not a number, so `labels: ['2026-01-01', …]` broke the deck it was in. Blank labels
6180
+ * stay blank. Only the leaf level is cached, so it is the only level converted.
6181
+ *
6182
+ * The series' label arrays are replaced, never written through: the outer array is this model's own,
6183
+ * but the inner ones are the caller's.
6184
+ * @param options - the chart's options, `catLabelFormatCode` deleted when the labels are not dates
6185
+ * @param series - every series, a combo's across all its subcharts
6186
+ */
6187
+ function normalizeDateCategories(options, series) {
6188
+ if (!options.catLabelFormatCode) return;
6189
+ const type = options._type;
6190
+ if (!(Array.isArray(type) || !(isXyChart(type) || type === "pie" || type === "doughnut" || isChartExType(type)))) return;
6191
+ const converted = /* @__PURE__ */ new Map();
6192
+ for (const item of series) {
6193
+ const [leaf, ...outer] = item.labels ?? [];
6194
+ if (!leaf) continue;
6195
+ const serials = [];
6196
+ for (const label of leaf) {
6197
+ const text = label == null ? "" : String(label);
6198
+ const serial = text.trim() === "" ? text : dateCategorySerial(text);
6199
+ if (serial === null) {
6200
+ warn("chart/invalid-option-value", `"catLabelFormatCode" needs category labels that are dates (a serial number or YYYY-MM-DD); "${text}" is neither, so the categories stay text.`);
6201
+ delete options.catLabelFormatCode;
6202
+ return;
6203
+ }
6204
+ serials.push(serial);
6205
+ }
6206
+ converted.set(item, [serials, ...outer]);
6207
+ }
6208
+ for (const [item, labels] of converted) item.labels = labels;
6209
+ }
6145
6210
  /**
6146
6211
  * Drop each `x`/`y`/`w`/`h` of a manual layout that is not a fraction of the chart, warning, so that
6147
6212
  * axis stays automatic. Shared by the plot area's `layout` and `legendLayout`; the legend's used to
@@ -6502,6 +6567,77 @@ function normalizeComboSubchartOptions(subOptions, chartOptions, subType, caller
6502
6567
  return result;
6503
6568
  }
6504
6569
  /**
6570
+ * The `TextBaseProps` keys `ChartOpts` takes through `ChartPropsTitle` and the chart writer reads
6571
+ * none of: every one but `lang`. The chart's text is styled through its own spellings
6572
+ * (`titleBold`, `legendFontSize`, `dataLabelColor`, …).
6573
+ */
6574
+ const UNREAD_TEXT_BASE_KEYS = [
6575
+ "align",
6576
+ "bold",
6577
+ "breakLine",
6578
+ "bullet",
6579
+ "caps",
6580
+ "color",
6581
+ "fontFace",
6582
+ "fontFaceEA",
6583
+ "fontSize",
6584
+ "highlight",
6585
+ "italic",
6586
+ "paraIndent",
6587
+ "paraMarginLeft",
6588
+ "softBreakBefore",
6589
+ "tabStops",
6590
+ "textDirection",
6591
+ "textWarp",
6592
+ "transparency",
6593
+ "underline",
6594
+ "valign"
6595
+ ];
6596
+ /**
6597
+ * Name the `TextBaseProps` keys a chart was given, which write nothing (#138). A chart written with
6598
+ * `bold` or `fontFace` was byte-identical to one written without, and nothing said so; autocomplete
6599
+ * offers them on `addChart`.
6600
+ * @param options - the chart's options as the caller stated them
6601
+ */
6602
+ function reportTextBaseKeys(options) {
6603
+ const stated = UNREAD_TEXT_BASE_KEYS.filter((key) => options[key] !== void 0);
6604
+ if (stated.length === 0) return;
6605
+ warn("chart/option-not-supported", `addChart: ${stated.map((key) => `"${key}"`).join(", ")} ${stated.length === 1 ? "has" : "have"} no effect on a chart, whose text is styled through its own options (titleBold, legendFontSize, dataLabelColor, catAxisLabelFontFace, …).`);
6606
+ }
6607
+ /**
6608
+ * Register a chart or plot area's picture fill, so the chart part can reference it.
6609
+ *
6610
+ * The fill wrote nothing and warned that its `image.data` was missing, because a picture fill needs
6611
+ * a media relationship and nothing gave the chart part one (#139). The picture is registered on the
6612
+ * slide, marked {@link SlideRelMedia.chartOwned}, so it is loaded, deduped and written like any other
6613
+ * picture, and the chart part declares it from `rId2` on: its `rId1` is the embedded workbook. The
6614
+ * fill each area keeps is a copy carrying that chart-part id.
6615
+ * @param target - the slide, layout or master the chart is on
6616
+ * @param options - the chart's normalized options, whose `chartArea` and `plotArea` are its own copies
6617
+ * @returns the pictures the chart part references, in relationship-id order
6618
+ */
6619
+ function registerAreaPictures(target, options) {
6620
+ const media = [];
6621
+ for (const area of [options.chartArea, options.plotArea]) {
6622
+ const fill = area?.fill;
6623
+ if (!area || !fill || typeof fill !== "object" || resolveFillKind(fill) !== "image") continue;
6624
+ const own = { ...fill };
6625
+ const before = target._relsMedia.length;
6626
+ registerImageFillMedia(target, own);
6627
+ const rel = target._relsMedia[before];
6628
+ if (rel && own.type === "image") {
6629
+ rel.chartOwned = true;
6630
+ own._imgRid = media.length + 2;
6631
+ media.push({
6632
+ rId: own._imgRid,
6633
+ rel
6634
+ });
6635
+ }
6636
+ area.fill = own;
6637
+ }
6638
+ return media;
6639
+ }
6640
+ /**
6505
6641
  * Generate the chart based on input data.
6506
6642
  * OOXML Chart Spec: ISO/IEC 29500-1:2016(E)
6507
6643
  *
@@ -6527,6 +6663,14 @@ function normalizeComboSubchartOptions(subOptions, chartOptions, subType, caller
6527
6663
  * }
6528
6664
  */
6529
6665
  function addChartDefinition(target, type, data, opt) {
6666
+ const [only] = Array.isArray(type) && type.length === 1 ? type : [];
6667
+ if (only && isChartType(only.type) && isBubbleChart(asChartType(only.type))) {
6668
+ const chartOpts = !Array.isArray(data) && data && typeof data === "object" ? data : opt;
6669
+ return addChartDefinition(target, only.type, only.data, {
6670
+ ...chartOpts,
6671
+ ...only.options
6672
+ });
6673
+ }
6530
6674
  const chartId = target._relsChart.length + 1;
6531
6675
  const resultObject = { _type: "chart" };
6532
6676
  let tmpOpt;
@@ -6539,7 +6683,8 @@ function addChartDefinition(target, type, data, opt) {
6539
6683
  tmpData = tmpData.concat(seriesData);
6540
6684
  return {
6541
6685
  ...obj,
6542
- data: seriesData
6686
+ data: seriesData,
6687
+ options: obj.options ?? {}
6543
6688
  };
6544
6689
  });
6545
6690
  tmpOpt = !Array.isArray(data) && data && typeof data === "object" ? data : opt;
@@ -6552,8 +6697,16 @@ function addChartDefinition(target, type, data, opt) {
6552
6697
  for (const name of tmpTypes ? tmpTypes.map((sub) => sub.type) : [type]) if (!isChartType(name)) throw new InvalidOptionError("chart/unknown-type", `addChart: "${String(name)}" is not a chart type. Valid types are: ${Object.values(ChartType).join(", ")}.`, { detail: { type: name } });
6553
6698
  if (tmpTypes?.some((sub) => isBubbleChart(asChartType(sub.type)))) throw new InvalidOptionError("chart/bubble-in-combo", "addChart: a bubble chart cannot be combined with other chart types; PowerPoint refuses the deck. Add it as a chart of its own.", { detail: { types: tmpTypes.map((sub) => sub.type) } });
6554
6699
  if (!tmpTypes && isChartExType(type)) reportChartExOptions(options, asChartType(type));
6700
+ reportTextBaseKeys(options);
6555
6701
  options._type = tmpTypes ?? asChartType(type);
6556
- Object.assign(options, resolveAuthoredFrame(options, {
6702
+ checkPlaceholderBinding(options.placeholder, "addChart");
6703
+ const placeholder = placeholderFrame(target._slideLayout, options.placeholder);
6704
+ Object.assign(options, resolveAuthoredFrame({
6705
+ x: options.x ?? placeholder.x,
6706
+ y: options.y ?? placeholder.y,
6707
+ w: options.w ?? placeholder.w,
6708
+ h: options.h ?? placeholder.h
6709
+ }, {
6557
6710
  x: 1,
6558
6711
  y: 1,
6559
6712
  w: "50%",
@@ -6572,6 +6725,7 @@ function addChartDefinition(target, type, data, opt) {
6572
6725
  normalizeAxisOptions(options, "");
6573
6726
  options.catAxes?.forEach((axis, idx) => normalizeAxisOptions(axis, `catAxes[${idx}].`));
6574
6727
  options.valAxes?.forEach((axis, idx) => normalizeAxisOptions(axis, `valAxes[${idx}].`));
6728
+ normalizeDateCategories(options, tmpData);
6575
6729
  const scatterGrid = {
6576
6730
  color: "D9D9D9",
6577
6731
  width: 1
@@ -6603,10 +6757,10 @@ function addChartDefinition(target, type, data, opt) {
6603
6757
  if (tmpData.length !== expected) warn("chart/stock-series-count", `stock chart style "${options.stockStyle}" expects ${expected} data series (got ${tmpData.length}); the chart may not render as intended.`);
6604
6758
  }
6605
6759
  reportMismatchedSeries(options, tmpData);
6606
- resultObject._type = "chart";
6607
6760
  resultObject.options = options;
6608
- resultObject.chartRid = getNewRelId(target);
6609
6761
  const isChartEx = isChartExType(options._type);
6762
+ const media = isChartEx ? [] : registerAreaPictures(target, options);
6763
+ resultObject.chartRid = getNewRelId(target);
6610
6764
  const { fileName, target: chartTarget } = chartPartNames(chartId, isChartEx);
6611
6765
  target._relsChart.push({
6612
6766
  rId: getNewRelId(target),
@@ -6616,15 +6770,15 @@ function addChartDefinition(target, type, data, opt) {
6616
6770
  globalId: chartId,
6617
6771
  isChartEx,
6618
6772
  fileName,
6619
- Target: chartTarget
6773
+ Target: chartTarget,
6774
+ ...media.length > 0 ? { media } : {}
6620
6775
  });
6621
6776
  target._slideObjects.push(resultObject);
6622
6777
  return resultObject;
6623
6778
  }
6624
- //#endregion
6625
- //#region src/families/chart.ts
6779
+ // src/families/chart.ts
6626
6780
  /**
6627
- * ts-pptx: the chart construct family
6781
+ * pptx-ts: the chart construct family
6628
6782
  *
6629
6783
  * The expensive one: `addChart` reaches every plot module, axis and sidecar builder under
6630
6784
  * `gen/chart/`, which is what a program that never draws a chart is paying for when a slide method
@@ -6660,97 +6814,7 @@ const chartFamily = {
6660
6814
  parts: chartContributor,
6661
6815
  extract: { charts: chartsOf }
6662
6816
  };
6663
- //#endregion
6664
- //#region src/gen/slide/comments.ts
6665
- /**
6666
- * ts-pptx: comment parts
6667
- *
6668
- * Resolve every slide's comments into a deck-wide author registry with per-author
6669
- * numbering, then emit the presentation-level `commentAuthors.xml` and each
6670
- * slide's `comments/commentN.xml` part.
6671
- */
6672
- /**
6673
- * Walk every slide's comments and build the deck-wide author registry + per-comment numbering.
6674
- *
6675
- * Legacy comments number each comment with a *per-author* 1-based `idx`; an author's `lastIdx` is the
6676
- * highest `idx` it used. Authors are keyed by `name`+`initials` and assigned ids in first-appearance
6677
- * order (slide order, then insertion order). `clrIdx` mirrors `id` (one colour slot per author).
6678
- * @param {PresSlideInternal[]} slides - all presentation slides
6679
- * @return {ResolvedComments} the author list and per-comment metadata
6680
- */
6681
- function resolveCommentAuthors(slides) {
6682
- const byKey = /* @__PURE__ */ new Map();
6683
- const authors = [];
6684
- const perAuthorCount = /* @__PURE__ */ new Map();
6685
- const meta = /* @__PURE__ */ new Map();
6686
- (slides || []).forEach((slide) => {
6687
- (slide._comments || []).forEach((comment) => {
6688
- const key = comment.author + "\0" + comment.initials;
6689
- let author = byKey.get(key);
6690
- if (!author) {
6691
- author = {
6692
- id: authors.length,
6693
- name: comment.author,
6694
- initials: comment.initials,
6695
- lastIdx: 0,
6696
- clrIdx: authors.length
6697
- };
6698
- byKey.set(key, author);
6699
- authors.push(author);
6700
- perAuthorCount.set(author.id, 0);
6701
- }
6702
- const idx = (perAuthorCount.get(author.id) ?? 0) + 1;
6703
- perAuthorCount.set(author.id, idx);
6704
- author.lastIdx = idx;
6705
- meta.set(comment, {
6706
- authorId: author.id,
6707
- idx
6708
- });
6709
- });
6710
- });
6711
- return {
6712
- authors,
6713
- meta
6714
- };
6715
- }
6716
- /**
6717
- * Creates the presentation-level `ppt/commentAuthors.xml` part (`<p:cmAuthorLst>`).
6718
- * @param {ResolvedCommentAuthor[]} authors - resolved deck-wide author registry
6719
- * @return {string} XML
6720
- */
6721
- function makeXmlCommentAuthors(authors) {
6722
- const cmAuthors = authors.map((author) => voidEl("p:cmAuthor", {
6723
- id: author.id,
6724
- name: author.name,
6725
- initials: author.initials,
6726
- lastIdx: author.lastIdx,
6727
- clrIdx: author.clrIdx
6728
- })).join("");
6729
- return XML_DECL + "\r\n" + el("p:cmAuthorLst", { ...PML_ROOT_NS }, raw(cmAuthors));
6730
- }
6731
- /**
6732
- * Creates a per-slide comments part `ppt/comments/comment{N}.xml` (`<p:cmLst>`).
6733
- * @param {PresSlideInternal} slide - the slide whose comments are serialized
6734
- * @param {Map} meta - per-comment `authorId`/`idx` from {@link resolveCommentAuthors}
6735
- * @return {string} XML
6736
- */
6737
- function makeXmlComments(slide, meta) {
6738
- const cms = (slide._comments || []).map((comment) => {
6739
- const m = meta.get(comment);
6740
- if (!m) return "";
6741
- return el("p:cm", {
6742
- authorId: m.authorId,
6743
- dt: comment.date || null,
6744
- idx: m.idx
6745
- }, [raw(voidEl("p:pos", {
6746
- x: Math.round(inch2Emu(comment.x)),
6747
- y: Math.round(inch2Emu(comment.y))
6748
- })), raw(el("p:text", null, comment.text))]);
6749
- }).join("");
6750
- return XML_DECL + "\r\n" + el("p:cmLst", { ...PML_ROOT_NS }, raw(cms));
6751
- }
6752
- //#endregion
6753
- //#region src/package/parts/comments.ts
6817
+ // src/package/parts/comments.ts
6754
6818
  const COMMENT_AUTHORS_PATH = "ppt/commentAuthors.xml";
6755
6819
  const commentsContributor = {
6756
6820
  order: 20,
@@ -6759,13 +6823,13 @@ const commentsContributor = {
6759
6823
  if (resolved.authors.length === 0) return;
6760
6824
  zip.add(COMMENT_AUTHORS_PATH, makeXmlCommentAuthors(resolved.authors));
6761
6825
  pres.slides.forEach((slide, idx) => {
6762
- if ((slide._comments || []).length > 0) zip.add(commentPath(idx + 1), makeXmlComments(slide, resolved.meta));
6826
+ if (slide._comments.length > 0) zip.add(commentPath(idx + 1), makeXmlComments(slide._comments, resolved.meta));
6763
6827
  });
6764
6828
  } },
6765
6829
  contentTypes: { trailing(pres) {
6766
6830
  const entries = [];
6767
6831
  pres.slides.forEach((slide, idx) => {
6768
- if ((slide._comments || []).length > 0) entries.push({
6832
+ if (slide._comments.length > 0) entries.push({
6769
6833
  partName: overrideName(commentPath(idx + 1)),
6770
6834
  contentType: COMMENTS_CONTENT_TYPE
6771
6835
  });
@@ -6777,10 +6841,9 @@ const commentsContributor = {
6777
6841
  return entries;
6778
6842
  } }
6779
6843
  };
6780
- //#endregion
6781
- //#region src/gen/define/comment.ts
6844
+ // src/gen/define/comment.ts
6782
6845
  /**
6783
- * ts-pptx: Comment Definition
6846
+ * pptx-ts: Comment Definition
6784
6847
  *
6785
6848
  * Validates `addComment()` author / text / position and stashes a review comment on the slide
6786
6849
  * (`_comments`); the `<p:cm>` XML is emitted later by `gen/slide/comments.ts`.
@@ -6819,7 +6882,6 @@ function addCommentDefinition(target, opts) {
6819
6882
  let date;
6820
6883
  if (opts.date instanceof Date) date = opts.date.toISOString();
6821
6884
  else if (typeof opts.date === "string" && opts.date) date = opts.date;
6822
- if (!target._comments) target._comments = [];
6823
6885
  target._comments.push(date === void 0 ? {
6824
6886
  author,
6825
6887
  initials,
@@ -6835,10 +6897,9 @@ function addCommentDefinition(target, opts) {
6835
6897
  date
6836
6898
  });
6837
6899
  }
6838
- //#endregion
6839
- //#region src/families/comments.ts
6900
+ // src/families/comments.ts
6840
6901
  /**
6841
- * ts-pptx: the comments construct family
6902
+ * pptx-ts: the comments construct family
6842
6903
  *
6843
6904
  * Legacy PowerPoint review comments: the marker on the slide, the per-slide comment part, and the
6844
6905
  * deck-wide author list.
@@ -6850,10 +6911,9 @@ const commentsFamily = {
6850
6911
  } },
6851
6912
  parts: commentsContributor
6852
6913
  };
6853
- //#endregion
6854
- //#region src/gen/slide/objects/connector.ts
6914
+ // src/gen/slide/objects/connector.ts
6855
6915
  /**
6856
- * ts-pptx: connector slide-object serialization
6916
+ * pptx-ts: connector slide-object serialization
6857
6917
  *
6858
6918
  * Emits a `connector` slide object as a `<p:cxnSp>`. The start/end shape bindings resolve a
6859
6919
  * caller-supplied `objectName` to the target's slide-wide `<p:cNvPr>` id; an unresolved name
@@ -6901,10 +6961,9 @@ function renderConnectorObject(ctx) {
6901
6961
  strSlideXml += "</p:spPr></p:cxnSp>";
6902
6962
  return strSlideXml;
6903
6963
  }
6904
- //#endregion
6905
- //#region src/gen/define/connector.ts
6964
+ // src/gen/define/connector.ts
6906
6965
  /**
6907
- * ts-pptx: Connector Definition
6966
+ * pptx-ts: Connector Definition
6908
6967
  *
6909
6968
  * `addConnectorDefinition` converts two endpoints to a flip-oriented bounding box, resolves the
6910
6969
  * connector preset + adjust guides, and optionally binds start / end shapes. Emitted later as
@@ -6994,8 +7053,7 @@ function addConnectorDefinition(target, opts) {
6994
7053
  };
6995
7054
  target._slideObjects.push(newObject);
6996
7055
  }
6997
- //#endregion
6998
- //#region src/families/connector.ts
7056
+ // src/families/connector.ts
6999
7057
  const connectorFamily = {
7000
7058
  name: "connector",
7001
7059
  authors: { addConnector(slide, options) {
@@ -7003,10 +7061,9 @@ const connectorFamily = {
7003
7061
  } },
7004
7062
  renderers: { ["connector"]: renderConnectorObject }
7005
7063
  };
7006
- //#endregion
7007
- //#region src/families/measure.ts
7064
+ // src/families/measure.ts
7008
7065
  /**
7009
- * ts-pptx: the measurement construct family
7066
+ * pptx-ts: the measurement construct family
7010
7067
  *
7011
7068
  * The three presentation methods that measure without authoring anything: `measureText`,
7012
7069
  * `overflowsBox` and `tableLayout`. They measure through `measure/fit.ts` and
@@ -7039,14 +7096,13 @@ const measureFamily = {
7039
7096
  }
7040
7097
  }
7041
7098
  };
7042
- //#endregion
7043
- //#region src/gen/slide/objects/media.ts
7099
+ // src/gen/slide/objects/media.ts
7044
7100
  /**
7045
- * ts-pptx: media (audio / video / online video) slide-object serialization
7101
+ * pptx-ts: media (audio / video / online video) slide-object serialization
7046
7102
  *
7047
7103
  * Emits a `media` slide object as a `<p:pic>` carrying the required preview image. The online
7048
- * and embedded forms differ in exactly two tokens — the EG_Media choice element and whether the
7049
- * paired `<p14:media>` rel binds by `r:link` or `r:embed` — so they share one body.
7104
+ * and embedded forms differ in exactly two tokens (the EG_Media choice element and whether the
7105
+ * paired `<p14:media>` rel binds by `r:link` or `r:embed`), so they share one body.
7050
7106
  */
7051
7107
  /**
7052
7108
  * Render a `media` (audio/video/online) slide object to its `<p:pic>` XML.
@@ -7095,8 +7151,7 @@ function renderMediaObject(ctx) {
7095
7151
  }))
7096
7152
  ]);
7097
7153
  }
7098
- //#endregion
7099
- //#region src/families/media.ts
7154
+ // src/families/media.ts
7100
7155
  const mediaFamily = {
7101
7156
  name: "media",
7102
7157
  authors: { addMedia(slide, options) {
@@ -7104,15 +7159,14 @@ const mediaFamily = {
7104
7159
  } },
7105
7160
  renderers: { ["media"]: renderMediaObject }
7106
7161
  };
7107
- //#endregion
7108
- //#region src/gen/slide/objects/model3d.ts
7162
+ // src/gen/slide/objects/model3d.ts
7109
7163
  /** The `am3d` namespace, doubling as `a:graphicData@uri` and the `mc:Choice Requires` token's URI. */
7110
7164
  const AM3D_NS = "http://schemas.microsoft.com/office/drawing/2017/model3d";
7111
7165
  /** Denominator of every `am3d` rational element (`@n`/`@d`). */
7112
7166
  const RATIO_DEN = 1e6;
7113
7167
  /**
7114
- * `am3d:raster@rName`/`@rVer` — the renderer that produced the cached preview. PowerPoint stamps
7115
- * its own renderer here; ts-pptx did not rasterize anything, but the attributes are what PowerPoint
7168
+ * `am3d:raster@rName`/`@rVer`: the renderer that produced the cached preview. PowerPoint stamps
7169
+ * its own renderer here; pptx-ts did not rasterize anything, but the attributes are what PowerPoint
7116
7170
  * writes and the element is where the preview blip lives, so they are reproduced verbatim.
7117
7171
  */
7118
7172
  const RASTER = {
@@ -7124,7 +7178,7 @@ const RASTER = {
7124
7178
  * gave different values); the cube's is emitted, matching the fixed default camera.
7125
7179
  */
7126
7180
  const OBJ_VIEWPORT_SZ = 3338805;
7127
- /** The three point lights PowerPoint writes for every inserted model — key, fill and rim. */
7181
+ /** The three point lights PowerPoint writes for every inserted model: key, fill and rim. */
7128
7182
  const PT_LIGHTS = [
7129
7183
  {
7130
7184
  clr: {
@@ -7166,7 +7220,7 @@ const PT_LIGHTS = [
7166
7220
  }
7167
7221
  }
7168
7222
  ];
7169
- /** `am3d:ambientLight` — neutral 50% scRGB at half illuminance, constant like the point lights. */
7223
+ /** `am3d:ambientLight`: neutral 50% scRGB at half illuminance, constant like the point lights. */
7170
7224
  const AMBIENT = {
7171
7225
  clr: {
7172
7226
  r: 5e4,
@@ -7175,7 +7229,7 @@ const AMBIENT = {
7175
7229
  },
7176
7230
  illuminanceN: 5e5
7177
7231
  };
7178
- /** `<am3d:clr><a:scrgbClr …/></am3d:clr>` — the colour wrapper both light kinds share. */
7232
+ /** `<am3d:clr><a:scrgbClr …/></am3d:clr>`: the colour wrapper both light kinds share. */
7179
7233
  function lightColor(clr) {
7180
7234
  return el("am3d:clr", null, raw(voidEl("a:scrgbClr", clr)));
7181
7235
  }
@@ -7190,7 +7244,7 @@ function cameraEl(model) {
7190
7244
  }
7191
7245
  /**
7192
7246
  * The `am3d:trans` block: model-unit scale plus an identity placement. Only `meterPerModelUnit`
7193
- * varies — `preTrans`/`scale`/`rot`/`postTrans` are the identity PowerPoint writes for a model
7247
+ * varies; `preTrans`/`scale`/`rot`/`postTrans` are the identity PowerPoint writes for a model
7194
7248
  * inserted without any subsequent 3D manipulation, and `am3d:rot` is emitted attribute-less.
7195
7249
  */
7196
7250
  function transEl(model) {
@@ -7235,7 +7289,7 @@ function lightsXml() {
7235
7289
  raw(voidEl("am3d:pos", light.pos))
7236
7290
  ])).join("");
7237
7291
  }
7238
- /** The `mc:Fallback` picture — the cached preview, drawn by everything that is not PowerPoint 2019+. */
7292
+ /** The `mc:Fallback` picture: the cached preview, drawn by everything that is not PowerPoint 2019+. */
7239
7293
  function fallbackPic(picId, objectName, altText, model, xf) {
7240
7294
  return el("p:pic", null, [raw(el("p:nvPicPr", null, [
7241
7295
  raw(cNvPrEl(picId, objectName, altText)),
@@ -7255,7 +7309,7 @@ function renderModel3dObject(ctx) {
7255
7309
  const { obj: slideItemObj, shapeId, frame: { x, y, cx, cy } } = ctx;
7256
7310
  const model = slideItemObj.model3d;
7257
7311
  if (!model) return "";
7258
- const opts = slideItemObj.options || {};
7312
+ const opts = ctx.itemOpts;
7259
7313
  const altText = opts.altText || "";
7260
7314
  const spPr = el("am3d:spPr", null, [raw(xfrmEl("a:xfrm", {
7261
7315
  x: 0,
@@ -7301,12 +7355,11 @@ function renderModel3dObject(ctx) {
7301
7355
  })
7302
7356
  });
7303
7357
  }
7304
- //#endregion
7305
- //#region src/gen/define/preview-image.ts
7358
+ // src/gen/define/preview-image.ts
7306
7359
  /**
7307
- * ts-pptx: preview/cover image registration.
7360
+ * pptx-ts: preview/cover image registration.
7308
7361
  *
7309
- * Several objects are drawn from a cached raster the library cannot render itself — a Zoom tile's
7362
+ * Several objects are drawn from a cached raster the library cannot render itself: a Zoom tile's
7310
7363
  * thumbnail of its target slide, an OLE object's picture of the embedded document, a 3D model's
7311
7364
  * preview. Each registers that raster as an ordinary slide image rel and references it by rId.
7312
7365
  * Shared here so the definers agree on the placeholder fallback and on extension sniffing; the rel itself goes through
@@ -7335,8 +7388,7 @@ function registerPreviewImage(target, cover, label) {
7335
7388
  registerImageMediaRel(target, source, rId);
7336
7389
  return rId;
7337
7390
  }
7338
- //#endregion
7339
- //#region src/gen/define/model3d.ts
7391
+ // src/gen/define/model3d.ts
7340
7392
  /** OPC content type for a glTF binary, as PowerPoint spells it in `[Content_Types].xml`. */
7341
7393
  const GLB_CONTENT_TYPE = "model/gltf.binary";
7342
7394
  /** Fixed-point denominator for `am3d` linear values: `am3d:up@dy="36000000"` is the unit vector. */
@@ -7345,7 +7397,7 @@ const AM3D_UNIT = 36e6;
7345
7397
  const AM3D_RATIO_DEN = 1e6;
7346
7398
  /**
7347
7399
  * The camera PowerPoint wrote for the 2×2×2 cube fixture, in caller units (metres / degrees).
7348
- * `z` is `sqrt(3)/2 / sin(22.5°)` — the bounding sphere of a 1-metre cube framed at a 45° fov.
7400
+ * `z` is `sqrt(3)/2 / sin(22.5°)`: the bounding sphere of a 1-metre cube framed at a 45° fov.
7349
7401
  */
7350
7402
  const DEFAULT_CAMERA = {
7351
7403
  pos: {
@@ -7387,7 +7439,8 @@ function resolveCamera(camera, meterPerModelUnit) {
7387
7439
  if (!Number.isFinite(fovDeg) || fovDeg <= 0 || fovDeg >= 180) throw new InvalidOptionError("model3d/invalid-fov", `addModel3d(): camera.fov must be greater than 0 and less than 180 degrees, got ${String(fovDeg)}.`);
7388
7440
  const scale = meterPerModelUnit ?? DEFAULT_METER_PER_MODEL_UNIT;
7389
7441
  if (!Number.isFinite(scale) || scale <= 0) throw new InvalidOptionError("model3d/invalid-scale", `addModel3d(): meterPerModelUnit must be a finite number greater than 0, got ${String(scale)}.`);
7390
- if (Math.round(scale * AM3D_RATIO_DEN) === 0) throw new InvalidOptionError("model3d/invalid-scale", `addModel3d(): meterPerModelUnit ${String(scale)} rounds to 0 at the six decimal places the file stores; use at least 0.0000005.`);
7442
+ const meterPerModelUnitN = Math.round(scale * AM3D_RATIO_DEN);
7443
+ if (meterPerModelUnitN === 0) throw new InvalidOptionError("model3d/invalid-scale", `addModel3d(): meterPerModelUnit ${String(scale)} rounds to 0 at the six decimal places the file stores; use at least 0.0000005.`);
7391
7444
  const up = toAm3dUnits(camera?.up, DEFAULT_CAMERA.up, "up");
7392
7445
  return {
7393
7446
  pos: toAm3dUnits(camera?.pos, DEFAULT_CAMERA.pos, "pos"),
@@ -7398,7 +7451,7 @@ function resolveCamera(camera, meterPerModelUnit) {
7398
7451
  dz: up.z
7399
7452
  },
7400
7453
  fov: Math.round(fovDeg * ANGLE_UNITS_PER_DEGREE),
7401
- meterPerModelUnitN: Math.round(scale * AM3D_RATIO_DEN)
7454
+ meterPerModelUnitN
7402
7455
  };
7403
7456
  }
7404
7457
  /**
@@ -7444,8 +7497,7 @@ function addModel3dDefinition(target, opt) {
7444
7497
  };
7445
7498
  target._slideObjects.push(slideData);
7446
7499
  }
7447
- //#endregion
7448
- //#region src/families/model3d.ts
7500
+ // src/families/model3d.ts
7449
7501
  const model3dFamily = {
7450
7502
  name: "model3d",
7451
7503
  authors: { addModel3d(slide, options) {
@@ -7453,12 +7505,11 @@ const model3dFamily = {
7453
7505
  } },
7454
7506
  renderers: { ["model3d"]: renderModel3dObject }
7455
7507
  };
7456
- //#endregion
7457
- //#region src/gen/slide/objects/ole.ts
7508
+ // src/gen/slide/objects/ole.ts
7458
7509
  /**
7459
- * ts-pptx: OLE-object slide-object serialization
7510
+ * pptx-ts: OLE-object slide-object serialization
7460
7511
  */
7461
- /** VML namespace — declared by an OLE object's `mc:Choice Requires="v"` (no VML content is emitted). */
7512
+ /** VML namespace, declared by an OLE object's `mc:Choice Requires="v"` (no VML content is emitted). */
7462
7513
  const VML_NS = "urn:schemas-microsoft-com:vml";
7463
7514
  /** graphicData URI for an embedded OLE object (`<p:oleObj>`). */
7464
7515
  const OLE_NS = "http://schemas.openxmlformats.org/presentationml/2006/ole";
@@ -7470,14 +7521,14 @@ const OLE_NS = "http://schemas.openxmlformats.org/presentationml/2006/ole";
7470
7521
  * PowerPoint renders by drawing the live embedded document); the `mc:Fallback` repeats it with a
7471
7522
  * `<p:pic>` preview so every other consumer shows the cached picture.
7472
7523
  *
7473
- * Note `mc:Choice Requires="v"` only *declares* the VML namespace — modern PowerPoint writes no
7524
+ * Note `mc:Choice Requires="v"` only *declares* the VML namespace. Modern PowerPoint writes no
7474
7525
  * `spid` and no `vmlDrawing` part, so neither is emitted here.
7475
7526
  */
7476
7527
  function renderOleObject(ctx) {
7477
7528
  const { obj: slideItemObj, shapeId, frame: { x, y, cx, cy } } = ctx;
7478
7529
  const ole = slideItemObj.ole;
7479
7530
  if (!ole) return "";
7480
- const opts = slideItemObj.options || {};
7531
+ const opts = ctx.itemOpts;
7481
7532
  const oleAttrs = {
7482
7533
  name: ole.name,
7483
7534
  showAsIcon: xsdBoolIfTrue(ole.showAsIcon),
@@ -7528,9 +7579,8 @@ function renderOleObject(ctx) {
7528
7579
  payload: alternateContent
7529
7580
  });
7530
7581
  }
7531
- //#endregion
7532
- //#region src/gen/define/ole.ts
7533
- /** Rel type for a generic OLE-server blob — a compound-file `.bin` (ECMA-376 Part 1 §15.2.10). */
7582
+ // src/gen/define/ole.ts
7583
+ /** Rel type for a generic OLE-server blob: a compound-file `.bin` (ECMA-376 Part 1 §15.2.10). */
7534
7584
  const OLE_OBJECT_REL = OFFICE_REL + "oleObject";
7535
7585
  /**
7536
7586
  * Embeddable payload formats, keyed by file extension. The six Office extensions are OPC packages
@@ -7589,7 +7639,7 @@ const EXTN_BY_CONTENT_TYPE = new Map(Object.entries(OLE_FORMATS).map(([extn, fmt
7589
7639
  /**
7590
7640
  * Resolve the embedded part's extension from whatever the caller gave us, in decreasing order of
7591
7641
  * explicitness: `extn`, the `data:` URI's MIME, the `path`'s extension, then the `progId`. Anything
7592
- * unrecognized becomes `bin`, the generic OLE blob — which is what PowerPoint itself writes for a
7642
+ * unrecognized becomes `bin`, the generic OLE blob, which is what PowerPoint itself writes for a
7593
7643
  * shell-packaged payload, so an unknown extension never leaks into `[Content_Types].xml`.
7594
7644
  */
7595
7645
  function resolvePartExtn(opt) {
@@ -7668,8 +7718,7 @@ function addOleObjectDefinition(target, opt) {
7668
7718
  };
7669
7719
  target._slideObjects.push(slideData);
7670
7720
  }
7671
- //#endregion
7672
- //#region src/families/ole.ts
7721
+ // src/families/ole.ts
7673
7722
  const oleFamily = {
7674
7723
  name: "ole",
7675
7724
  authors: { addOleObject(slide, options) {
@@ -7677,11 +7726,10 @@ const oleFamily = {
7677
7726
  } },
7678
7727
  renderers: { ["oleObject"]: renderOleObject }
7679
7728
  };
7680
- //#endregion
7681
- //#region src/gen/drawingml/table-border.ts
7729
+ // src/gen/drawingml/table-border.ts
7682
7730
  /**
7683
- * One `<a:lnX>` border element. Every side of a table cell — the four edges and the two
7684
- * diagonals — is a `CT_LineProperties`, so they differ only in element name.
7731
+ * One `<a:lnX>` border element. Every side of a table cell (the four edges and the two
7732
+ * diagonals) is a `CT_LineProperties`, so they differ only in element name.
7685
7733
  * @param {string} name - the element's local name (`lnL`, `lnTlToBr`, …)
7686
7734
  * @param {BorderProps} border - the resolved border for that side
7687
7735
  * @return {string} the border element XML
@@ -7765,8 +7813,7 @@ function genTableCellBorderXml(cellBorder, diagonal) {
7765
7813
  if (diagonal?.blToTr) strXml += genBorderLine("lnBlToTr", diagonal.blToTr);
7766
7814
  return strXml;
7767
7815
  }
7768
- //#endregion
7769
- //#region src/gen/drawingml/table-cell3d.ts
7816
+ // src/gen/drawingml/table-cell3d.ts
7770
7817
  /**
7771
7818
  * Vet one enumerated value before it reaches the XML, reporting and dropping anything outside
7772
7819
  * its `ST_` union. See `ooxml/check-enum.ts` for why the write path drops rather than throws.
@@ -7811,8 +7858,7 @@ function genTableCell3DXml(cell3D) {
7811
7858
  if (cell3D.lightRig && !lightRig) warnOnce("table/invalid-cell3d", "table cell: cell3D `lightRig` needs both `rig` and `dir` (both are required by CT_LightRig); the light rig is dropped and the bevel takes the renderer default.", { received: cell3D.lightRig });
7812
7859
  return el("a:cell3D", { prstMaterial: resolveEnum(cell3D.material, PRESET_MATERIALS, "material") }, [raw(bevel), lightRig ? raw(lightRig) : null]);
7813
7860
  }
7814
- //#endregion
7815
- //#region src/gen/slide/objects/table.ts
7861
+ // src/gen/slide/objects/table.ts
7816
7862
  /**
7817
7863
  * Validate a cell's `horzOverflow` before it reaches the XML, reporting and dropping anything
7818
7864
  * outside `ST_TextHorzOverflowType`. `undefined` (the common case) emits nothing.
@@ -7826,7 +7872,7 @@ function resolveHorzOverflow(value) {
7826
7872
  * The perimeter is decided per **grid position**, not per authored cell, which is what makes
7827
7873
  * merges work: a colspan's origin sits at the left of its span and its covered `_hmerge`
7828
7874
  * cells sit to the right, so a span straddling the last column gets that column's rule on the
7829
- * covered cell — exactly where PowerPoint defines a merged region's outer edge. A cell in the
7875
+ * covered cell, exactly where PowerPoint defines a merged region's outer edge. A cell in the
7830
7876
  * table's interior touches no edge and comes back untouched.
7831
7877
  *
7832
7878
  * Returns the input array (not a copy) when nothing applies, so the common no-perimeter path
@@ -7970,7 +8016,7 @@ function buildMergeGrid(rows, numCols) {
7970
8016
  * Render a `table` slide object to its `<p:graphicFrame>` XML (merge-grid, row/col spans, per-cell styling).
7971
8017
  */
7972
8018
  function renderTableObject(ctx) {
7973
- const { obj: slideItemObj, shapeId, frame: { x, y, cx, cy }, placeholder: placeholderObj, itemOpts } = ctx;
8019
+ const { obj: slideItemObj, shapeId, slide, frame: { x, y, cx, cy }, placeholder: placeholderObj, itemOpts } = ctx;
7974
8020
  let tblInner = "";
7975
8021
  const arrTabRows = withCheckedSpans(slideItemObj.arrTabRows ?? []);
7976
8022
  const objTabOpts = itemOpts;
@@ -7981,7 +8027,7 @@ function renderTableObject(ctx) {
7981
8027
  noGrp: true,
7982
8028
  ...itemOpts.objectLock
7983
8029
  }, itemOpts.objectName)))),
7984
- raw(el("p:nvPr", null, [raw(genXmlPlaceholder(placeholderObj)), raw(el("p:extLst", null, raw(el("p:ext", { uri: "{D42A27DB-BD31-4B8C-83A1-F6EECF244321}" }, raw(voidEl("p14:modId", {
8030
+ raw(el("p:nvPr", null, [raw(genXmlPlaceholder(placeholderObj, statedPlaceholderBinding(itemOpts.placeholder))), raw(el("p:extLst", null, raw(el("p:ext", { uri: "{D42A27DB-BD31-4B8C-83A1-F6EECF244321}" }, raw(voidEl("p14:modId", {
7985
8031
  "xmlns:p14": OOXML_NS.p14,
7986
8032
  val: "1579011935"
7987
8033
  }))))))], { openPrefix: " " }))
@@ -8049,6 +8095,10 @@ function renderTableObject(ctx) {
8049
8095
  return;
8050
8096
  }
8051
8097
  const cellOpts = inheritTableOptions(cell.options, objTabOpts);
8098
+ if (cellOpts.color === void 0 && itemOpts._slideColor && !cellHasHyperlink(cell)) {
8099
+ const color = objTabOpts.tableStyle ? "color" in slide && slide.color || void 0 : slideTextColor(slide);
8100
+ if (color) cellOpts.color = color;
8101
+ }
8052
8102
  const cellValign = resolveTextAnchor(cellOpts.valign);
8053
8103
  const cellTextDir = cellOpts.textDirection && cellOpts.textDirection !== "horz" ? cellOpts.textDirection : null;
8054
8104
  rejectEmptyColor(cellOpts.fill, "cell fill");
@@ -8091,14 +8141,13 @@ function renderTableObject(ctx) {
8091
8141
  }
8092
8142
  });
8093
8143
  }
8094
- //#endregion
8095
- //#region src/gen/define/table.ts
8144
+ // src/gen/define/table.ts
8096
8145
  /**
8097
- * ts-pptx: Table Definition
8146
+ * pptx-ts: Table Definition
8098
8147
  *
8099
8148
  * `addTableDefinition` applies the `headerRow` / `columns` sugar, normalizes rows into
8100
- * fully-resolved `TableCellInternal`s (incl. 4-side borders), computes width, and — when `autoPage` is
8101
- * set — shreds the table across overflow slides via `getSlidesForTableRows`.
8149
+ * fully-resolved `TableCellInternal`s (incl. 4-side borders), computes width, and (when `autoPage` is
8150
+ * set) shreds the table across overflow slides via `getSlidesForTableRows`.
8102
8151
  */
8103
8152
  /**
8104
8153
  * Expand a cell/table border into the 4-side tuple the rest of the pipeline expects.
@@ -8162,13 +8211,12 @@ function applyTableHeaderColumnSugar(tableRows, opt) {
8162
8211
  const hdr = opt.headerRow && typeof opt.headerRow === "object" ? opt.headerRow : void 0;
8163
8212
  const cols = Array.isArray(opt.columns) && opt.columns.length ? opt.columns : void 0;
8164
8213
  let srcRows = tableRows;
8165
- if ((hdr || cols) && Array.isArray(tableRows[0])) {
8214
+ if (hdr || cols) {
8166
8215
  if (hdr && opt.hasHeader === void 0) opt.hasHeader = true;
8167
8216
  const gridRows = tableRows;
8168
8217
  const gridCols = gridRows.map(() => []);
8169
8218
  if (cols) for (const placement of walkTableGrid(gridRows, tableColCount(gridRows))) gridCols[placement.row]?.push(placement.col);
8170
8219
  srcRows = tableRows.map((row, rowIdx) => {
8171
- if (!Array.isArray(row)) return row;
8172
8220
  if (!cols && rowIdx !== 0) return row;
8173
8221
  return row.map((cell, cellIdx) => {
8174
8222
  const cellObj = typeof cell === "string" || typeof cell === "number" ? {
@@ -8192,6 +8240,38 @@ function applyTableHeaderColumnSugar(tableRows, opt) {
8192
8240
  return srcRows;
8193
8241
  }
8194
8242
  /**
8243
+ * Report and drop `textWarp` from the table and its cells, once per call.
8244
+ *
8245
+ * `TableCellProps` takes it from `TextBaseProps`, and a cell's `a:bodyPr` was written empty whatever
8246
+ * it said (#84). PowerPoint has nowhere to put it: setting `TextFrame2.WarpFormat` on a cell throws
8247
+ * "The specified value is out of range" over COM, and a saved cell carries an empty `a:bodyPr`.
8248
+ * (`fit` is different: `'shrink'` is baked into the runs by the measured-fit pass.)
8249
+ * @param rows - the normalized rows, whose option bags are this module's own copies
8250
+ * @param opt - the table's options, also this module's own
8251
+ */
8252
+ function dropCellTextWarp(rows, opt) {
8253
+ let stated = false;
8254
+ for (const bag of [opt, ...rows.flatMap((row) => row.map((cell) => cell.options ?? {}))]) {
8255
+ if (bag.textWarp === void 0) continue;
8256
+ stated = true;
8257
+ delete bag.textWarp;
8258
+ }
8259
+ if (stated) warn("table/option-not-supported", "addTable: `textWarp` has no effect in a table cell, which PowerPoint does not warp; it was ignored.");
8260
+ }
8261
+ /**
8262
+ * A text shadow normalized the way `addText` normalizes one, on a bag this module already owns.
8263
+ * The run emitter reads `_alpha`, which only {@link normalizeShadowOptions} derives from
8264
+ * `transparency` or an RGBA colour; skipped, a cell's shadow painted at the default alpha
8265
+ * whatever the caller asked for.
8266
+ */
8267
+ function withRunShadow(bag) {
8268
+ if (bag.shadow === void 0) return bag;
8269
+ const shadow = normalizeShadowOptions(bag.shadow);
8270
+ if (shadow) bag.shadow = shadow;
8271
+ else delete bag.shadow;
8272
+ return bag;
8273
+ }
8274
+ /**
8195
8275
  * Transform loosely-typed table rows (strings / numbers / TableCellInternal) into a grid of
8196
8276
  * well-formed TableCellInternal objects with fully-resolved 4-side cell borders.
8197
8277
  *
@@ -8202,8 +8282,8 @@ function normalizeTableRows(srcRows, opt) {
8202
8282
  const arrRows = [];
8203
8283
  srcRows.forEach((row) => {
8204
8284
  const newRow = [];
8205
- if (Array.isArray(row)) row.forEach((cell) => {
8206
- const newCellOptions = typeof cell === "object" && cell.options ? { ...cell.options } : {};
8285
+ row.forEach((cell) => {
8286
+ const newCellOptions = withRunShadow(typeof cell === "object" && cell.options ? { ...cell.options } : {});
8207
8287
  const newCell = {
8208
8288
  _type: "tablecell",
8209
8289
  text: "",
@@ -8214,9 +8294,9 @@ function normalizeTableRows(srcRows, opt) {
8214
8294
  if (typeof cell.text === "string" || typeof cell.text === "number") newCell.text = cell.text.toString();
8215
8295
  else if (Array.isArray(cell.text)) newCell.text = cell.text.map((run) => run.options ? {
8216
8296
  ...run,
8217
- options: { ...run.options }
8297
+ options: withRunShadow({ ...run.options })
8218
8298
  } : { ...run });
8219
- else if (cell.text) newCell.text = cell.text;
8299
+ else newCell.text = cell.text;
8220
8300
  }
8221
8301
  if (newCellOptions.border != null && typeof newCellOptions.border !== "object") {
8222
8302
  warn("table/invalid-border", "addTable cell `border` option must be an object. Ex: `{border: {type:'none'}}`");
@@ -8260,7 +8340,7 @@ function normalizeTableRows(srcRows, opt) {
8260
8340
  * Resolve `autoPageHeaderRows` to a usable count of header rows.
8261
8341
  *
8262
8342
  * It is a count, so it has to be a whole number, at least one, and no larger than the table
8263
- * itself — a header taller than the table repeats every row onto every continuation slide and
8343
+ * itself: a header taller than the table repeats every row onto every continuation slide and
8264
8344
  * leaves no room for body content. Anything else falls back to `1` and reports
8265
8345
  * `table/invalid-header-row-count`.
8266
8346
  *
@@ -8286,16 +8366,16 @@ function resolveHeaderRowCount(value, rowCount) {
8286
8366
  *
8287
8367
  * Three fill sources are walked, which between them cover every way a picture reaches a table:
8288
8368
  * the resolved cells (per-cell `options.fill`, plus `headerRow` and `columns[i]`, both baked
8289
- * onto cells by the sugar step above), the table-level `fill`, which is *not* baked —
8290
- * `gen/slide/objects/table.ts` copies it onto each cell at emit time — and `tableFill`, which
8369
+ * onto cells by the sugar step above), the table-level `fill`, which is *not* baked
8370
+ * (`gen/slide/objects/table.ts` copies it onto each cell at emit time), and `tableFill`, which
8291
8371
  * lands on `a:tblPr` itself and so needs its own relationship for the same reason.
8292
8372
  *
8293
8373
  * Keyed on fill **object identity**, not on the image source. The sugar spreads its options
8294
8374
  * shallowly, so one `headerRow` fill object is shared by every cell it styles; registering
8295
8375
  * per cell would mint a redundant relationship each time and let the later call overwrite
8296
8376
  * the `_imgRid` the first one stashed. Two cells given separately-authored fills for the
8297
- * same file still get one relationship each — matching how two shapes sharing an image
8298
- * behave — while the bytes are deduped into a single media part downstream.
8377
+ * same file still get one relationship each (matching how two shapes sharing an image
8378
+ * behave), while the bytes are deduped into a single media part downstream.
8299
8379
  *
8300
8380
  * Must run only after auto-paging has shredded the rows across slides, for the same reason
8301
8381
  * `createHyperlinkRels` does: `target` has to be the slide the cell actually lands on, or
@@ -8340,6 +8420,7 @@ function addTableDefinition(target, tableRows, options) {
8340
8420
  kind: "table",
8341
8421
  supplied: opt.objectName
8342
8422
  });
8423
+ checkPlaceholderBinding(opt.placeholder, "addTable");
8343
8424
  if (opt.placeholder) {
8344
8425
  const placeholder = placeholderFrame(slideLayout, opt.placeholder);
8345
8426
  const x = opt.x ?? placeholder.x;
@@ -8357,18 +8438,21 @@ function addTableDefinition(target, tableRows, options) {
8357
8438
  if (idx === 0 || Array.isArray(row)) return;
8358
8439
  throw new InvalidOptionError("table/rows-not-nested", `addTable: 'rows' should be an array of cells! Row ${idx} is ${JSON.stringify(row)}`);
8359
8440
  });
8441
+ if (opt.tableStyle !== void 0 && !ST_GUID.test(opt.tableStyle)) throw new InvalidOptionError("table/invalid-style-id", `addTable: \`tableStyle\` ${JSON.stringify(opt.tableStyle)} is not a style GUID. Use a \`TableStyle\` member, or a GUID in braces such as '{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}'.`);
8360
8442
  const srcRows = applyTableHeaderColumnSugar(withCheckedSpans(tableRows), opt);
8361
8443
  if (opt.border != null && typeof opt.border !== "object") {
8362
8444
  warn("table/invalid-border", "addTable `border` option must be an object. Ex: `{border: {type:'none'}}`");
8363
8445
  delete opt.border;
8364
8446
  }
8365
8447
  const arrRows = normalizeTableRows(srcRows, opt);
8448
+ dropCellTextWarp(arrRows, opt);
8366
8449
  if (opt.x === void 0 || opt.x === null) opt.x = .5;
8367
8450
  if (opt.y === void 0 || opt.y === null) opt.y = .5;
8368
8451
  opt.fontSize = opt.fontSize || 12;
8369
8452
  opt.margin = resolveCellMarginsInches(opt.margin);
8370
- if (!tableHasHyperlink(arrRows)) {
8371
- if (!opt.color) opt.color = DEF_FONT_COLOR;
8453
+ if (!opt.color) {
8454
+ delete opt.color;
8455
+ opt._slideColor = true;
8372
8456
  }
8373
8457
  if (Array.isArray(opt.border)) opt.border = [
8374
8458
  0,
@@ -8389,7 +8473,8 @@ function addTableDefinition(target, tableRows, options) {
8389
8473
  opt.autoPage = typeof opt.autoPage === "boolean" ? opt.autoPage : false;
8390
8474
  opt.autoPagePlaceholder = typeof opt.autoPagePlaceholder === "boolean" ? opt.autoPagePlaceholder : false;
8391
8475
  opt.autoPageRepeatHeader = typeof opt.autoPageRepeatHeader === "boolean" ? opt.autoPageRepeatHeader : false;
8392
- opt.autoPageHeaderRows = resolveHeaderRowCount(opt.autoPageHeaderRows, tableRows.length);
8476
+ const headerRowCount = resolveHeaderRowCount(opt.autoPageHeaderRows, tableRows.length);
8477
+ opt.autoPageHeaderRows = headerRowCount;
8393
8478
  const lineWeight = Number(opt.autoPageLineWeight);
8394
8479
  opt.autoPageLineWeight = typeof opt.autoPageLineWeight !== "undefined" && Number.isFinite(lineWeight) ? lineWeight : 0;
8395
8480
  if (opt.autoPageLineWeight) {
@@ -8435,8 +8520,8 @@ function addTableDefinition(target, tableRows, options) {
8435
8520
  delete opt.colW;
8436
8521
  };
8437
8522
  if (typeof opt.colW === "string" || typeof opt.colW === "number") spreadUniformColW(opt.colW);
8438
- else if (opt.colW && Array.isArray(opt.colW) && opt.colW.length === 1 && firstRowColCnt > 1) spreadUniformColW(opt.colW[0]);
8439
- else if (opt.colW && Array.isArray(opt.colW) && opt.colW.length !== firstRowColCnt) {
8523
+ else if (Array.isArray(opt.colW) && opt.colW.length === 1 && firstRowColCnt > 1) spreadUniformColW(opt.colW[0]);
8524
+ else if (Array.isArray(opt.colW) && opt.colW.length !== firstRowColCnt) {
8440
8525
  warn("table/col-width-count-mismatch", "addTable: mismatch: (colW.length != data.length) Therefore, defaulting to evenly distributed col widths.");
8441
8526
  delete opt.colW;
8442
8527
  }
@@ -8455,9 +8540,10 @@ function addTableDefinition(target, tableRows, options) {
8455
8540
  }
8456
8541
  }
8457
8542
  const newAutoPagedSlides = [];
8458
- if (opt && !opt.autoPage) {
8543
+ if (!opt.autoPage) {
8459
8544
  createHyperlinkRels(target, arrRows, "addTable");
8460
8545
  registerTableImageFills(target, arrRows, opt);
8546
+ createBulletImageRels(target, [opt, ...arrRows.flatMap((row) => row.flatMap((cell) => [cell.options, ...Array.isArray(cell.text) ? cell.text.map((run) => run.options) : []]))]);
8461
8547
  const { columns: _columns, ...tableObjectOptions } = opt;
8462
8548
  target._slideObjects.push({
8463
8549
  _type: "table",
@@ -8465,8 +8551,8 @@ function addTableDefinition(target, tableRows, options) {
8465
8551
  options: tableObjectOptions
8466
8552
  });
8467
8553
  } else {
8468
- if (opt.autoPageRepeatHeader) opt._arrObjTabHeadRows = arrRows.filter((_row, idx) => idx < (opt.autoPageHeaderRows || 1));
8469
- const sourcePlaceholders = opt.autoPagePlaceholder && Array.isArray(target._slideObjects) ? target._slideObjects.filter((obj) => obj._type !== "table" && obj.options?.placeholder) : [];
8554
+ if (opt.autoPageRepeatHeader) opt._arrObjTabHeadRows = arrRows.filter((_row, idx) => idx < headerRowCount);
8555
+ const sourcePlaceholders = opt.autoPagePlaceholder ? target._slideObjects.filter((obj) => obj._type !== "table" && obj.options?.placeholder) : [];
8470
8556
  getSlidesForTableRows(arrRows, opt, presLayout, slideLayout).forEach((slide, idx) => {
8471
8557
  let newSlide = target.getSlide(target._slideNum + idx);
8472
8558
  if (!newSlide) {
@@ -8489,18 +8575,519 @@ function addTableDefinition(target, tableRows, options) {
8489
8575
  }
8490
8576
  return newAutoPagedSlides;
8491
8577
  }
8492
- //#endregion
8493
- //#region src/families/table.ts
8578
+ // src/gen/pres/builtin-table-styles.ts
8579
+ /**
8580
+ * pptx-ts: the built-in table style definitions
8581
+ *
8582
+ * GENERATED by `scripts/gen-builtin-table-styles.mjs` from `test/read/fixtures/table-styles-builtin.pptx`.
8583
+ * Do not edit by hand: re-run the script.
8584
+ *
8585
+ * PowerPoint's own `a:tblStyle` markup for the 74 built-in [MS-OE376] table styles, which it
8586
+ * writes into `ppt/tableStyles.xml` for every style a deck uses. Each body is a template whose
8587
+ * `$0`/`$1` slots take the scheme colour that varies across a family's accent variants; see the
8588
+ * script's header for why.
8589
+ */
8590
+ /**
8591
+ * Style bodies, the children of `a:tblStyle`, with `$0`/`$1` where a family's accent goes.
8592
+ * @raw-xml-asset Captured verbatim from PowerPoint; not built here, so not a migration target.
8593
+ */
8594
+ const BODIES = [
8595
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:left><a:right><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:insideH><a:insideV><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band2H><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:band2V><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2V><a:lastCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:top><a:ln w=\"38100\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"38100\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow>",
8596
+ "<a:tblBg><a:fillRef idx=\"2\"><a:schemeClr val=\"$0\"/></a:fillRef><a:effectRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:effectRef></a:tblBg><a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:left><a:right><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:right><a:top><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:top><a:bottom><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:bottom><a:insideH><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:insideH><a:insideV><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:alpha val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band2H><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2H><a:band1V><a:tcStyle><a:tcBdr><a:top><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:top><a:bottom><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:bottom></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:alpha val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:band2V><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"2\"><a:schemeClr val=\"$0\"/></a:lnRef></a:left><a:right><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:right><a:top><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:top><a:bottom><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:bottom><a:insideH><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:left><a:right><a:lnRef idx=\"2\"><a:schemeClr val=\"$0\"/></a:lnRef></a:right><a:top><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:top><a:bottom><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:bottom><a:insideH><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:left><a:right><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:right><a:top><a:lnRef idx=\"2\"><a:schemeClr val=\"$0\"/></a:lnRef></a:top><a:bottom><a:lnRef idx=\"2\"><a:schemeClr val=\"$0\"/></a:lnRef></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:left><a:right><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:right><a:top><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:top><a:bottom><a:lnRef idx=\"2\"><a:schemeClr val=\"lt1\"/></a:lnRef></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow>",
8597
+ "<a:tblBg><a:fillRef idx=\"3\"><a:schemeClr val=\"$0\"/></a:fillRef><a:effectRef idx=\"3\"><a:schemeClr val=\"$0\"/></a:effectRef></a:tblBg><a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"><a:tint val=\"50000\"/></a:schemeClr></a:lnRef></a:left><a:right><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"><a:tint val=\"50000\"/></a:schemeClr></a:lnRef></a:right><a:top><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"><a:tint val=\"50000\"/></a:schemeClr></a:lnRef></a:top><a:bottom><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"><a:tint val=\"50000\"/></a:schemeClr></a:lnRef></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"lt1\"><a:alpha val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"lt1\"><a:alpha val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"2\"><a:schemeClr val=\"lt1\"/></a:lnRef></a:left></a:tcBdr></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:right><a:lnRef idx=\"2\"><a:schemeClr val=\"lt1\"/></a:lnRef></a:right></a:tcBdr></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:lnRef idx=\"2\"><a:schemeClr val=\"lt1\"/></a:lnRef></a:top></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:lastRow><a:seCell><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:top><a:ln><a:noFill/></a:ln></a:top></a:tcBdr></a:tcStyle></a:seCell><a:swCell><a:tcStyle><a:tcBdr><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln><a:noFill/></a:ln></a:top></a:tcBdr></a:tcStyle></a:swCell><a:firstRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:bottom><a:lnRef idx=\"3\"><a:schemeClr val=\"lt1\"/></a:lnRef></a:bottom></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:firstRow><a:neCell><a:tcStyle><a:tcBdr><a:bottom><a:ln><a:noFill/></a:ln></a:bottom></a:tcBdr></a:tcStyle></a:neCell>",
8598
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"tx1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:alpha val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band2H><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:alpha val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:firstRow>",
8599
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"tx1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:left><a:right><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:right><a:top><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:top><a:bottom><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr><a:top><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:top><a:bottom><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:bottom></a:tcBdr></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:left><a:right><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:right></a:tcBdr></a:tcStyle></a:band1V><a:band2V><a:tcStyle><a:tcBdr><a:left><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:left><a:right><a:lnRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:lnRef></a:right></a:tcBdr></a:tcStyle></a:band2V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"50800\" cmpd=\"dbl\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top></a:tcBdr></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"bg1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fillRef idx=\"1\"><a:schemeClr val=\"$0\"/></a:fillRef></a:tcStyle></a:firstRow>",
8600
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"tx1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:left><a:right><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:insideH><a:insideV><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:alpha val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:alpha val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"50800\" cmpd=\"dbl\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:firstRow>",
8601
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:left><a:right><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"50800\" cmpd=\"dbl\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow>",
8602
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"50800\" cmpd=\"dbl\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:seCell><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/></a:tcStyle></a:seCell><a:swCell><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/></a:tcStyle></a:swCell><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow>",
8603
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:left><a:right><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:insideH><a:insideV><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:firstRow>",
8604
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln><a:noFill/></a:ln></a:top><a:bottom><a:ln><a:noFill/></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"/></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:shade val=\"60000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:shade val=\"60000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:left><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:left></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:shade val=\"60000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:right><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:right></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:shade val=\"60000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:shade val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:seCell><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left></a:tcBdr></a:tcStyle></a:seCell><a:swCell><a:tcStyle><a:tcBdr><a:right><a:ln><a:noFill/></a:ln></a:right></a:tcBdr></a:tcStyle></a:swCell><a:firstRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow><a:neCell><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left></a:tcBdr></a:tcStyle></a:neCell><a:nwCell><a:tcStyle><a:tcBdr><a:right><a:ln><a:noFill/></a:ln></a:right></a:tcBdr></a:tcStyle></a:nwCell>",
8605
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln><a:noFill/></a:ln></a:top><a:bottom><a:ln><a:noFill/></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"50800\" cmpd=\"dbl\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"$0\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"$1\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow>",
8606
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"tx1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln><a:noFill/></a:ln></a:top><a:bottom><a:ln><a:noFill/></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl>",
8607
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"tx1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:left><a:right><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:insideH><a:insideV><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl>",
8608
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"/><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"50800\" cmpd=\"dbl\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:seCell><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/></a:tcStyle></a:seCell><a:swCell><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/></a:tcStyle></a:swCell><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow>",
8609
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln><a:noFill/></a:ln></a:top><a:bottom><a:ln><a:noFill/></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:left><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:left></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"60000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:right><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:right></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"60000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"60000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:seCell><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left></a:tcBdr></a:tcStyle></a:seCell><a:swCell><a:tcStyle><a:tcBdr><a:right><a:ln><a:noFill/></a:ln></a:right></a:tcBdr></a:tcStyle></a:swCell><a:firstRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"25400\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow><a:neCell><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left></a:tcBdr></a:tcStyle></a:neCell><a:nwCell><a:tcStyle><a:tcBdr><a:right><a:ln><a:noFill/></a:ln></a:right></a:tcBdr></a:tcStyle></a:nwCell>",
8610
+ "<a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln><a:noFill/></a:ln></a:top><a:bottom><a:ln><a:noFill/></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:lastCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr/></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"/><a:tcStyle><a:tcBdr><a:top><a:ln w=\"50800\" cmpd=\"dbl\"><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow>"
8611
+ ];
8612
+ /** `[styleId, styleName, body index, ...slot values]`, in the order PowerPoint wrote them. */
8613
+ const STYLES = [
8614
+ [
8615
+ "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}",
8616
+ "Medium Style 2 - Accent 1",
8617
+ 0,
8618
+ "accent1"
8619
+ ],
8620
+ [
8621
+ "{2D5ABB26-0587-4C30-8999-92F81FD0307C}",
8622
+ "No Style, No Grid",
8623
+ 11
8624
+ ],
8625
+ [
8626
+ "{5940675A-B579-460E-94D1-54222C63F5DA}",
8627
+ "No Style, Table Grid",
8628
+ 12
8629
+ ],
8630
+ [
8631
+ "{3C2FFA5D-87B4-456A-9821-1D502468CF0F}",
8632
+ "Themed Style 1 - Accent 1",
8633
+ 1,
8634
+ "accent1"
8635
+ ],
8636
+ [
8637
+ "{284E427A-3D55-4303-BF80-6455036E1DE7}",
8638
+ "Themed Style 1 - Accent 2",
8639
+ 1,
8640
+ "accent2"
8641
+ ],
8642
+ [
8643
+ "{69C7853C-536D-4A76-A0AE-DD22124D55A5}",
8644
+ "Themed Style 1 - Accent 3",
8645
+ 1,
8646
+ "accent3"
8647
+ ],
8648
+ [
8649
+ "{775DCB02-9BB8-47FD-8907-85C794F793BA}",
8650
+ "Themed Style 1 - Accent 4",
8651
+ 1,
8652
+ "accent4"
8653
+ ],
8654
+ [
8655
+ "{35758FB7-9AC5-4552-8A53-C91805E547FA}",
8656
+ "Themed Style 1 - Accent 5",
8657
+ 1,
8658
+ "accent5"
8659
+ ],
8660
+ [
8661
+ "{08FB837D-C827-4EFA-A057-4D05807E0F7C}",
8662
+ "Themed Style 1 - Accent 6",
8663
+ 1,
8664
+ "accent6"
8665
+ ],
8666
+ [
8667
+ "{D113A9D2-9D6B-4929-AA2D-F23B5EE8CBE7}",
8668
+ "Themed Style 2 - Accent 1",
8669
+ 2,
8670
+ "accent1"
8671
+ ],
8672
+ [
8673
+ "{18603FDC-E32A-4AB5-989C-0864C3EAD2B8}",
8674
+ "Themed Style 2 - Accent 2",
8675
+ 2,
8676
+ "accent2"
8677
+ ],
8678
+ [
8679
+ "{306799F8-075E-4A3A-A7F6-7FBC6576F1A4}",
8680
+ "Themed Style 2 - Accent 3",
8681
+ 2,
8682
+ "accent3"
8683
+ ],
8684
+ [
8685
+ "{E269D01E-BC32-4049-B463-5C60D7B0CCD2}",
8686
+ "Themed Style 2 - Accent 4",
8687
+ 2,
8688
+ "accent4"
8689
+ ],
8690
+ [
8691
+ "{327F97BB-C833-4FB7-BDE5-3F7075034690}",
8692
+ "Themed Style 2 - Accent 5",
8693
+ 2,
8694
+ "accent5"
8695
+ ],
8696
+ [
8697
+ "{638B1855-1B75-4FBE-930C-398BA8C253C6}",
8698
+ "Themed Style 2 - Accent 6",
8699
+ 2,
8700
+ "accent6"
8701
+ ],
8702
+ [
8703
+ "{9D7B26C5-4107-4FEC-AEDC-1716B250A1EF}",
8704
+ "Light Style 1",
8705
+ 3,
8706
+ "tx1"
8707
+ ],
8708
+ [
8709
+ "{3B4B98B0-60AC-42C2-AFA5-B58CD77FA1E5}",
8710
+ "Light Style 1 - Accent 1",
8711
+ 3,
8712
+ "accent1"
8713
+ ],
8714
+ [
8715
+ "{0E3FDE45-AF77-4B5C-9715-49D594BDF05E}",
8716
+ "Light Style 1 - Accent 2",
8717
+ 3,
8718
+ "accent2"
8719
+ ],
8720
+ [
8721
+ "{C083E6E3-FA7D-4D7B-A595-EF9225AFEA82}",
8722
+ "Light Style 1 - Accent 3",
8723
+ 3,
8724
+ "accent3"
8725
+ ],
8726
+ [
8727
+ "{D27102A9-8310-4765-A935-A1911B00CA55}",
8728
+ "Light Style 1 - Accent 4",
8729
+ 3,
8730
+ "accent4"
8731
+ ],
8732
+ [
8733
+ "{5FD0F851-EC5A-4D38-B0AD-8093EC10F338}",
8734
+ "Light Style 1 - Accent 5",
8735
+ 3,
8736
+ "accent5"
8737
+ ],
8738
+ [
8739
+ "{68D230F3-CF80-4859-8CE7-A43EE81993B5}",
8740
+ "Light Style 1 - Accent 6",
8741
+ 3,
8742
+ "accent6"
8743
+ ],
8744
+ [
8745
+ "{7E9639D4-E3E2-4D34-9284-5A2195B3D0D7}",
8746
+ "Light Style 2",
8747
+ 4,
8748
+ "tx1"
8749
+ ],
8750
+ [
8751
+ "{69012ECD-51FC-41F1-AA8D-1B2483CD663E}",
8752
+ "Light Style 2 - Accent 1",
8753
+ 4,
8754
+ "accent1"
8755
+ ],
8756
+ [
8757
+ "{72833802-FEF1-4C79-8D5D-14CF1EAF98D9}",
8758
+ "Light Style 2 - Accent 2",
8759
+ 4,
8760
+ "accent2"
8761
+ ],
8762
+ [
8763
+ "{F2DE63D5-997A-4646-A377-4702673A728D}",
8764
+ "Light Style 2 - Accent 3",
8765
+ 4,
8766
+ "accent3"
8767
+ ],
8768
+ [
8769
+ "{17292A2E-F333-43FB-9621-5CBBE7FDCDCB}",
8770
+ "Light Style 2 - Accent 4",
8771
+ 4,
8772
+ "accent4"
8773
+ ],
8774
+ [
8775
+ "{5A111915-BE36-4E01-A7E5-04B1672EAD32}",
8776
+ "Light Style 2 - Accent 5",
8777
+ 4,
8778
+ "accent5"
8779
+ ],
8780
+ [
8781
+ "{912C8C85-51F0-491E-9774-3900AFEF0FD7}",
8782
+ "Light Style 2 - Accent 6",
8783
+ 4,
8784
+ "accent6"
8785
+ ],
8786
+ [
8787
+ "{616DA210-FB5B-4158-B5E0-FEB733F419BA}",
8788
+ "Light Style 3",
8789
+ 5,
8790
+ "tx1"
8791
+ ],
8792
+ [
8793
+ "{BC89EF96-8CEA-46FF-86C4-4CE0E7609802}",
8794
+ "Light Style 3 - Accent 1",
8795
+ 5,
8796
+ "accent1"
8797
+ ],
8798
+ [
8799
+ "{5DA37D80-6434-44D0-A028-1B22A696006F}",
8800
+ "Light Style 3 - Accent 2",
8801
+ 5,
8802
+ "accent2"
8803
+ ],
8804
+ [
8805
+ "{8799B23B-EC83-4686-B30A-512413B5E67A}",
8806
+ "Light Style 3 - Accent 3",
8807
+ 5,
8808
+ "accent3"
8809
+ ],
8810
+ [
8811
+ "{ED083AE6-46FA-4A59-8FB0-9F97EB10719F}",
8812
+ "Light Style 3 - Accent 4",
8813
+ 5,
8814
+ "accent4"
8815
+ ],
8816
+ [
8817
+ "{BDBED569-4797-4DF1-A0F4-6AAB3CD982D8}",
8818
+ "Light Style 3 - Accent 5",
8819
+ 5,
8820
+ "accent5"
8821
+ ],
8822
+ [
8823
+ "{E8B1032C-EA38-4F05-BA0D-38AFFFC7BED3}",
8824
+ "Light Style 3 - Accent 6",
8825
+ 5,
8826
+ "accent6"
8827
+ ],
8828
+ [
8829
+ "{793D81CF-94F2-401A-BA57-92F5A7B2D0C5}",
8830
+ "Medium Style 1",
8831
+ 6,
8832
+ "dk1"
8833
+ ],
8834
+ [
8835
+ "{B301B821-A1FF-4177-AEE7-76D212191A09}",
8836
+ "Medium Style 1 - Accent 1",
8837
+ 6,
8838
+ "accent1"
8839
+ ],
8840
+ [
8841
+ "{9DCAF9ED-07DC-4A11-8D7F-57B35C25682E}",
8842
+ "Medium Style 1 - Accent 2",
8843
+ 6,
8844
+ "accent2"
8845
+ ],
8846
+ [
8847
+ "{1FECB4D8-DB02-4DC6-A0A2-4F2EBAE1DC90}",
8848
+ "Medium Style 1 - Accent 3",
8849
+ 6,
8850
+ "accent3"
8851
+ ],
8852
+ [
8853
+ "{1E171933-4619-4E11-9A3F-F7608DF75F80}",
8854
+ "Medium Style 1 - Accent 4",
8855
+ 6,
8856
+ "accent4"
8857
+ ],
8858
+ [
8859
+ "{FABFCF23-3B69-468F-B69F-88F6DE6A72F2}",
8860
+ "Medium Style 1 - Accent 5",
8861
+ 6,
8862
+ "accent5"
8863
+ ],
8864
+ [
8865
+ "{10A1B5D5-9B99-4C35-A422-299274C87663}",
8866
+ "Medium Style 1 - Accent 6",
8867
+ 6,
8868
+ "accent6"
8869
+ ],
8870
+ [
8871
+ "{073A0DAA-6AF3-43AB-8588-CEC1D06C72B9}",
8872
+ "Medium Style 2",
8873
+ 0,
8874
+ "dk1"
8875
+ ],
8876
+ [
8877
+ "{21E4AEA4-8DFA-4A89-87EB-49C32662AFE0}",
8878
+ "Medium Style 2 - Accent 2",
8879
+ 0,
8880
+ "accent2"
8881
+ ],
8882
+ [
8883
+ "{F5AB1C69-6EDB-4FF4-983F-18BD219EF322}",
8884
+ "Medium Style 2 - Accent 3",
8885
+ 0,
8886
+ "accent3"
8887
+ ],
8888
+ [
8889
+ "{00A15C55-8517-42AA-B614-E9B94910E393}",
8890
+ "Medium Style 2 - Accent 4",
8891
+ 0,
8892
+ "accent4"
8893
+ ],
8894
+ [
8895
+ "{7DF18680-E054-41AD-8BC1-D1AEF772440D}",
8896
+ "Medium Style 2 - Accent 5",
8897
+ 0,
8898
+ "accent5"
8899
+ ],
8900
+ [
8901
+ "{93296810-A885-4BE3-A3E7-6D5BEEA58F35}",
8902
+ "Medium Style 2 - Accent 6",
8903
+ 0,
8904
+ "accent6"
8905
+ ],
8906
+ [
8907
+ "{8EC20E35-A176-4012-BC5E-935CFFF8708E}",
8908
+ "Medium Style 3",
8909
+ 13
8910
+ ],
8911
+ [
8912
+ "{6E25E649-3F16-4E02-A733-19D2CDBF48F0}",
8913
+ "Medium Style 3 - Accent 1",
8914
+ 7,
8915
+ "accent1"
8916
+ ],
8917
+ [
8918
+ "{85BE263C-DBD7-4A20-BB59-AAB30ACAA65A}",
8919
+ "Medium Style 3 - Accent 2",
8920
+ 7,
8921
+ "accent2"
8922
+ ],
8923
+ [
8924
+ "{EB344D84-9AFB-497E-A393-DC336BA19D2E}",
8925
+ "Medium Style 3 - Accent 3",
8926
+ 7,
8927
+ "accent3"
8928
+ ],
8929
+ [
8930
+ "{EB9631B5-78F2-41C9-869B-9F39066F8104}",
8931
+ "Medium Style 3 - Accent 4",
8932
+ 7,
8933
+ "accent4"
8934
+ ],
8935
+ [
8936
+ "{74C1A8A3-306A-4EB7-A6B1-4F7E0EB9C5D6}",
8937
+ "Medium Style 3 - Accent 5",
8938
+ 7,
8939
+ "accent5"
8940
+ ],
8941
+ [
8942
+ "{2A488322-F2BA-4B5B-9748-0D474271808F}",
8943
+ "Medium Style 3 - Accent 6",
8944
+ 7,
8945
+ "accent6"
8946
+ ],
8947
+ [
8948
+ "{D7AC3CCA-C797-4891-BE02-D94E43425B78}",
8949
+ "Medium Style 4",
8950
+ 8,
8951
+ "dk1"
8952
+ ],
8953
+ [
8954
+ "{69CF1AB2-1976-4502-BF36-3FF5EA218861}",
8955
+ "Medium Style 4 - Accent 1",
8956
+ 8,
8957
+ "accent1"
8958
+ ],
8959
+ [
8960
+ "{8A107856-5554-42FB-B03E-39F5DBC370BA}",
8961
+ "Medium Style 4 - Accent 2",
8962
+ 8,
8963
+ "accent2"
8964
+ ],
8965
+ [
8966
+ "{0505E3EF-67EA-436B-97B2-0124C06EBD24}",
8967
+ "Medium Style 4 - Accent 3",
8968
+ 8,
8969
+ "accent3"
8970
+ ],
8971
+ [
8972
+ "{C4B1156A-380E-4F78-BDF5-A606A8083BF9}",
8973
+ "Medium Style 4 - Accent 4",
8974
+ 8,
8975
+ "accent4"
8976
+ ],
8977
+ [
8978
+ "{22838BEF-8BB2-4498-84A7-C5851F593DF1}",
8979
+ "Medium Style 4 - Accent 5",
8980
+ 8,
8981
+ "accent5"
8982
+ ],
8983
+ [
8984
+ "{16D9F66E-5EB9-4882-86FB-DCBF35E3C3E4}",
8985
+ "Medium Style 4 - Accent 6",
8986
+ 8,
8987
+ "accent6"
8988
+ ],
8989
+ [
8990
+ "{E8034E78-7F5D-4C2E-B375-FC64B27BC917}",
8991
+ "Dark Style 1",
8992
+ 14
8993
+ ],
8994
+ [
8995
+ "{125E5076-3810-47DD-B79F-674D7AD40C01}",
8996
+ "Dark Style 1 - Accent 1",
8997
+ 9,
8998
+ "accent1"
8999
+ ],
9000
+ [
9001
+ "{37CE84F3-28C3-443E-9E96-99CF82512B78}",
9002
+ "Dark Style 1 - Accent 2",
9003
+ 9,
9004
+ "accent2"
9005
+ ],
9006
+ [
9007
+ "{D03447BB-5D67-496B-8E87-E561075AD55C}",
9008
+ "Dark Style 1 - Accent 3",
9009
+ 9,
9010
+ "accent3"
9011
+ ],
9012
+ [
9013
+ "{E929F9F4-4A8F-4326-A1B4-22849713DDAB}",
9014
+ "Dark Style 1 - Accent 4",
9015
+ 9,
9016
+ "accent4"
9017
+ ],
9018
+ [
9019
+ "{8FD4443E-F989-4FC4-A0C8-D5A2AF1F390B}",
9020
+ "Dark Style 1 - Accent 5",
9021
+ 9,
9022
+ "accent5"
9023
+ ],
9024
+ [
9025
+ "{AF606853-7671-496A-8E4F-DF71F8EC918B}",
9026
+ "Dark Style 1 - Accent 6",
9027
+ 9,
9028
+ "accent6"
9029
+ ],
9030
+ [
9031
+ "{5202B0CA-FC54-4496-8BCA-5EF66A818D29}",
9032
+ "Dark Style 2",
9033
+ 15
9034
+ ],
9035
+ [
9036
+ "{0660B408-B3CF-4A94-85FC-2B1E0A45F4A2}",
9037
+ "Dark Style 2 - Accent 1/Accent 2",
9038
+ 10,
9039
+ "accent1",
9040
+ "accent2"
9041
+ ],
9042
+ [
9043
+ "{91EBBBCC-DAD2-459C-BE2E-F6DE35CF9A28}",
9044
+ "Dark Style 2 - Accent 3/Accent 4",
9045
+ 10,
9046
+ "accent3",
9047
+ "accent4"
9048
+ ],
9049
+ [
9050
+ "{46F890A9-2807-4EBB-B81D-B2AA78EC7F39}",
9051
+ "Dark Style 2 - Accent 5/Accent 6",
9052
+ 10,
9053
+ "accent5",
9054
+ "accent6"
9055
+ ]
9056
+ ];
9057
+ /**
9058
+ * The `a:tblStyle` element PowerPoint writes for the built-in style `styleId`, or `undefined`
9059
+ * when `styleId` is not one of the 74 built-in styles.
9060
+ */
9061
+ function builtinTableStyleXml(styleId) {
9062
+ const row = STYLES.find((s) => s[0] === styleId);
9063
+ if (!row) return void 0;
9064
+ const [, styleName, index, ...args] = row;
9065
+ const body = BODIES[index]?.replace(/\$(\d)/g, (_, i) => args[Number(i)] ?? "") ?? "";
9066
+ return el("a:tblStyle", {
9067
+ styleId,
9068
+ styleName
9069
+ }, raw(body));
9070
+ }
9071
+ // src/package/parts/table.ts
9072
+ const tableContributor = {
9073
+ order: 40,
9074
+ parts: { tableStyles(pres) {
9075
+ const ids = /* @__PURE__ */ new Set();
9076
+ for (const slide of pres.slides) for (const obj of slide._slideObjects) if (obj._type === "table" && obj.options?.tableStyle) ids.add(obj.options.tableStyle);
9077
+ return [...ids.has(DEFAULT_TABLE_STYLE) ? /* @__PURE__ */ new Set([DEFAULT_TABLE_STYLE, ...ids]) : ids].flatMap((id) => builtinTableStyleXml(id) ?? []);
9078
+ } }
9079
+ };
9080
+ // src/families/table.ts
8494
9081
  const tableFamily = {
8495
9082
  name: "table",
8496
9083
  authors: { addTable(slide, tableRows, options) {
8497
9084
  const paged = addTableDefinition(slide, tableRows, options || {});
8498
9085
  for (const made of paged) if (!slide._newAutoPagedSlides.includes(made)) slide._newAutoPagedSlides.push(made);
8499
9086
  } },
8500
- renderers: { ["table"]: renderTableObject }
9087
+ renderers: { ["table"]: renderTableObject },
9088
+ parts: tableContributor
8501
9089
  };
8502
- //#endregion
8503
- //#region src/gen/slide/objects/zoom.ts
9090
+ // src/gen/slide/objects/zoom.ts
8504
9091
  /** Zoom (Slide/Section/Summary) graphicData URI + `mc:Choice Requires` prefix + element local-names, per variant. */
8505
9092
  const ZOOM_VARIANTS = {
8506
9093
  slide: {
@@ -8527,7 +9114,7 @@ const P166_NS = "http://schemas.microsoft.com/office/powerpoint/2016/6/main";
8527
9114
  /**
8528
9115
  * The `p166:blipFill` + `p166:spPr` (preview image + framed tile) shared by a zoom tile's `zmPr`.
8529
9116
  *
8530
- * The same body `previewPicBody` builds for a `p:pic`, one namespace over — which is the only
9117
+ * The same body `previewPicBody` builds for a `p:pic`, one namespace over, which is the only
8531
9118
  * thing that ever differed between them.
8532
9119
  */
8533
9120
  function zoomBlipSpPr(previewRid, xf) {
@@ -8545,7 +9132,7 @@ function zoomObjEl(variant, tile, returnToParent, transitionDur, localXf) {
8545
9132
  zmAttrs["transitionDur"] = transitionDur;
8546
9133
  return el(`${prefix}:${obj}`, objAttrs, raw(el(`${prefix}:zmPr`, zmAttrs, raw(zoomBlipSpPr(tile.previewRid, localXf)))));
8547
9134
  }
8548
- /** The `mc:Fallback` picture (or grouped pictures) — a hyperlinked thumbnail for pre-2016 consumers. */
9135
+ /** The `mc:Fallback` picture (or grouped pictures): a hyperlinked thumbnail for pre-2016 consumers. */
8549
9136
  function zoomFallbackPic(picId, objectName, tile, absXf) {
8550
9137
  return el("p:pic", null, [raw(el("p:nvPicPr", null, [
8551
9138
  raw(cNvPrEl(picId, objectName, "", voidEl("a:hlinkClick", {
@@ -8559,14 +9146,14 @@ function zoomFallbackPic(picId, objectName, tile, absXf) {
8559
9146
  /**
8560
9147
  * Render a `zoom` slide object to its `<mc:AlternateContent>` XML. The `mc:Choice` carries the real
8561
9148
  * `<p:graphicFrame>` (Slide/Section/Summary Zoom in the 2016 zoom namespaces, read by PowerPoint
8562
- * 2016+); the `mc:Fallback` carries a hyperlinked picture — or, for a Summary Zoom, a group of them —
9149
+ * 2016+); the `mc:Fallback` carries a hyperlinked picture (or, for a Summary Zoom, a group of them),
8563
9150
  * so pre-2016 consumers still get a clickable navigation thumbnail. See `gen/define/zoom.ts`.
8564
9151
  */
8565
9152
  function renderZoomObject(ctx) {
8566
9153
  const { obj: slideItemObj, shapeId, frame: { x, y, cx, cy } } = ctx;
8567
9154
  const zoom = slideItemObj.zoom;
8568
9155
  if (!zoom) return "";
8569
- const opts = slideItemObj.options || {};
9156
+ const opts = ctx.itemOpts;
8570
9157
  const objectName = opts.objectName;
8571
9158
  const { uri, prefix, zm } = ZOOM_VARIANTS[zoom.variant];
8572
9159
  const firstTile = zoom.tiles[0];
@@ -8646,8 +9233,7 @@ function renderZoomObject(ctx) {
8646
9233
  fallback: fallbackInner
8647
9234
  });
8648
9235
  }
8649
- //#endregion
8650
- //#region src/gen/define/zoom.ts
9236
+ // src/gen/define/zoom.ts
8651
9237
  const ZOOM_LABEL = {
8652
9238
  slide: "Slide Zoom",
8653
9239
  section: "Section Zoom",
@@ -8725,7 +9311,7 @@ function pushZoomObject(target, variant, options, zoom) {
8725
9311
  };
8726
9312
  target._slideObjects.push(newObject);
8727
9313
  }
8728
- /** Slide Zoom — one tile linking to a single target slide. */
9314
+ /** Slide Zoom: one tile linking to a single target slide. */
8729
9315
  function addSlideZoomDefinition(target, opts) {
8730
9316
  if (!opts?.target) {
8731
9317
  warn("zoom/missing-target", "addSlideZoom requires a `target` slide (a Slide object or its 1-based number); ignoring.");
@@ -8754,7 +9340,7 @@ function addSlideZoomDefinition(target, opts) {
8754
9340
  ...settings
8755
9341
  });
8756
9342
  }
8757
- /** Section Zoom — one tile linking to the start of a named section. */
9343
+ /** Section Zoom: one tile linking to the start of a named section. */
8758
9344
  function addSectionZoomDefinition(target, opts, sections) {
8759
9345
  if (!opts?.sectionTitle) {
8760
9346
  warn("zoom/missing-section-title", "addSectionZoom requires a `sectionTitle`; ignoring.");
@@ -8785,7 +9371,7 @@ function addSectionZoomDefinition(target, opts, sections) {
8785
9371
  });
8786
9372
  }
8787
9373
  /**
8788
- * Summary Zoom — a grid of tiles, one per section (excluding the host slide's own section).
9374
+ * Summary Zoom: a grid of tiles, one per section (excluding the host slide's own section).
8789
9375
  * All tiles share the single placeholder/cover image; each links to its section's first slide.
8790
9376
  */
8791
9377
  function addSummaryZoomDefinition(target, opts, sections) {
@@ -8842,8 +9428,7 @@ function addSummaryZoomDefinition(target, opts, sections) {
8842
9428
  ...settings
8843
9429
  });
8844
9430
  }
8845
- //#endregion
8846
- //#region src/families/zoom.ts
9431
+ // src/families/zoom.ts
8847
9432
  const zoomFamily = {
8848
9433
  name: "zoom",
8849
9434
  authors: {
@@ -8859,7 +9444,6 @@ const zoomFamily = {
8859
9444
  },
8860
9445
  renderers: { ["zoom"]: renderZoomObject }
8861
9446
  };
8862
- //#endregion
8863
- export { renderedSlideObjects as A, pushMediaRel as B, msMediaRid as C, findLayoutPlaceholder as D, placeholderOptionsForSlide as E, warnUnauthoredChild as F, SLIDE_METHOD_FAMILIES as I, composeFamilies as L, shapeIdCount as M, addChildDefinition as N, resolveTextAnchor as O, isGroupableObject as P, familyMethodUnavailable as R, alternateContentEl as S, addTextDefinition as T, resolveImageSource as V, chartPartNames as _, mediaFamily as a, GROUP_SHAPE_LOCK_ATTRS as b, commentsFamily as c, textFamily as d, shapeFamily as f, makeXmlCore as g, groupFamily as h, model3dFamily as i, resolveObjectNameToId as j, collectSlideShapeIds as k, chartFamily as l, imageFamily as m, tableFamily as n, measureFamily as o, notesFamily as p, oleFamily as r, connectorFamily as s, zoomFamily as t, animationsFamily as u, FMT_SCHEME_XML as v, previewRid as w, genXmlObjectLock as x, resolveImageExtent as y, requirePresentationAuthor as z };
9447
+ export { statedPlaceholderBinding as A, composeFamilies as B, msMediaRid as C, checkPlaceholderBinding as D, placeholderOptionsForSlide as E, shapeIdCount as F, requirePresentationAuthor as H, addChildDefinition as I, isGroupableObject as L, collectSlideShapeIds as M, renderedSlideObjects as N, findLayoutPlaceholder as O, resolveObjectNameToId as P, warnUnauthoredChild as R, alternateContentEl as S, addTextDefinition as T, pushMediaRel as U, familyMethodUnavailable as V, resolveImageSource as W, makeXmlCore as _, mediaFamily as a, resolveImageExtent as b, commentsFamily as c, textFamily as d, shapeFamily as f, makeXmlTableStyles as g, groupFamily as h, model3dFamily as i, resolveTextAnchor as j, layoutPlaceholderName as k, chartFamily as l, imageFamily as m, tableFamily as n, measureFamily as o, notesFamily as p, oleFamily as r, connectorFamily as s, zoomFamily as t, animationsFamily as u, chartPartNames as v, previewRid as w, genXmlObjectLock as x, FMT_SCHEME_XML as y, SLIDE_METHOD_FAMILIES as z };
8864
9448
 
8865
- //# sourceMappingURL=zoom-DPUHh85d.js.map
9449
+ //# sourceMappingURL=zoom-CSSeOwM8.js.map