@shbernal/ts-pptx 4.1.0 → 5.0.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 +11 -11
  2. package/dist/anim-presets-Qbgh8uut.js +55 -0
  3. package/dist/anim-presets-Qbgh8uut.js.map +1 -0
  4. package/dist/{autopage-D4kyVp11.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-kVHmjGc6.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-DwDbakcl.js → chart-metadata-CwiTTcJq.js} +576 -538
  15. package/dist/chart-metadata-CwiTTcJq.js.map +1 -0
  16. package/dist/{clip-DHDlnHUq.d.ts → clip-ISfCMtWA.d.ts} +6 -10
  17. package/dist/clip-ISfCMtWA.d.ts.map +1 -0
  18. package/dist/{notes-BcT571R4.js → comments-CKIZYRbZ.js} +517 -389
  19. package/dist/comments-CKIZYRbZ.js.map +1 -0
  20. package/dist/{diagnostics-DiMmBU8P.d.ts → diagnostics-MoA4MBq5.d.ts} +52 -50
  21. package/dist/diagnostics-MoA4MBq5.d.ts.map +1 -0
  22. package/dist/{embedded-fonts-CI_YGW2d.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-6hF9aTmT.d.ts → entry-compose-CiakSt-f.d.ts} +53 -74
  25. package/dist/entry-compose-CiakSt-f.d.ts.map +1 -0
  26. package/dist/{errors-Da2nXCJm.js → entry-errors-JMthgJ2g.js} +41 -25
  27. package/dist/entry-errors-JMthgJ2g.js.map +1 -0
  28. package/dist/{table-cell-margins-PDshga8T.js → enums-BP9wsb9Q.js} +42 -45
  29. package/dist/enums-BP9wsb9Q.js.map +1 -0
  30. package/dist/{enums-DQRpVOLh.d.ts → enums-PcXr3o3J.d.ts} +11 -12
  31. package/dist/{enums-DQRpVOLh.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-CcXbg__l.js → fit-Bpmzep6O.js} +60 -52
  36. package/dist/fit-Bpmzep6O.js.map +1 -0
  37. package/dist/{font-metrics-CBGmhLo0.d.ts → font-metrics-DTppw4t3.d.ts} +61 -37
  38. package/dist/font-metrics-DTppw4t3.d.ts.map +1 -0
  39. package/dist/{grid-9B2w5EaY.js → grid-DUIMxjfl.js} +23 -26
  40. package/dist/grid-DUIMxjfl.js.map +1 -0
  41. package/dist/{html-dom-DvJmuHt2.js → html-dom-LZCgntnJ.js} +42 -43
  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 +14 -16
  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-BgLPbwbL.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-KoEgVwII.d.ts → package-CANBWuSm.d.ts} +4 -12
  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-BA9_lJbY.d.ts → pres-BkEkUAEM.d.ts} +383 -230
  75. package/dist/pres-BkEkUAEM.d.ts.map +1 -0
  76. package/dist/{presentation-Cyl74rq2.js → presentation-4Ggq0_Xa.js} +408 -288
  77. package/dist/presentation-4Ggq0_Xa.js.map +1 -0
  78. package/dist/{presentation-types-B3VQH4Bz.d.ts → presentation-types-BgnZR-0a.d.ts} +1104 -457
  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 +2697 -777
  86. package/dist/script.js.map +1 -1
  87. package/dist/{shapes-BcyFdZpp.js → shapes-CAPOjU0Q.js} +1556 -487
  88. package/dist/shapes-CAPOjU0Q.js.map +1 -0
  89. package/dist/{slide-BqPtyKmb.d.ts → slide-BmT4kMoO.d.ts} +94 -86
  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-CVbvUfgh.js → table-dom-BYga4FYY.js} +3 -4
  94. package/dist/{table-dom-CVbvUfgh.js.map → table-dom-BYga4FYY.js.map} +1 -1
  95. package/dist/{text-BvFFMMFQ.js → text-Dz0ArGIp.js} +365 -318
  96. package/dist/text-Dz0ArGIp.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-DFcUYjh3.js → units-internal-BR3a4cIi.js} +26 -29
  100. package/dist/units-internal-BR3a4cIi.js.map +1 -0
  101. package/dist/{zip-CYZ0F6BV.js → zip-7JTh61LX.js} +8 -10
  102. package/dist/zip-7JTh61LX.js.map +1 -0
  103. package/dist/{zip-CTll_dr0.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-BoNyOlPm.js → zoom-CSSeOwM8.js} +1153 -583
  108. package/dist/zoom-CSSeOwM8.js.map +1 -0
  109. package/package.json +20 -21
  110. package/skills/{ts-pptx-upstream → pptx-ts-upstream}/SKILL.md +27 -74
  111. package/dist/autopage-D4kyVp11.js.map +0 -1
  112. package/dist/binary-string-CKVAYI3M.js.map +0 -1
  113. package/dist/body-insets-kVHmjGc6.js.map +0 -1
  114. package/dist/clip-DHDlnHUq.d.ts.map +0 -1
  115. package/dist/diagnostics-DiMmBU8P.d.ts.map +0 -1
  116. package/dist/embedded-fonts-CI_YGW2d.d.ts.map +0 -1
  117. package/dist/entry-compose-6hF9aTmT.d.ts.map +0 -1
  118. package/dist/errors-Da2nXCJm.js.map +0 -1
  119. package/dist/fit-CcXbg__l.js.map +0 -1
  120. package/dist/font-metrics-CBGmhLo0.d.ts.map +0 -1
  121. package/dist/grid-9B2w5EaY.js.map +0 -1
  122. package/dist/html-dom-DvJmuHt2.js.map +0 -1
  123. package/dist/image-size-DwDbakcl.js.map +0 -1
  124. package/dist/notes-BcT571R4.js.map +0 -1
  125. package/dist/options-internal-WqgMf720.js.map +0 -1
  126. package/dist/package-KoEgVwII.d.ts.map +0 -1
  127. package/dist/playbtn-CUqQdoDf.js.map +0 -1
  128. package/dist/pres-BA9_lJbY.d.ts.map +0 -1
  129. package/dist/presentation-Cyl74rq2.js.map +0 -1
  130. package/dist/presentation-types-B3VQH4Bz.d.ts.map +0 -1
  131. package/dist/shapes-BcyFdZpp.js.map +0 -1
  132. package/dist/slide-BqPtyKmb.d.ts.map +0 -1
  133. package/dist/table-cell-margins-PDshga8T.js.map +0 -1
  134. package/dist/text-BvFFMMFQ.js.map +0 -1
  135. package/dist/text-anchor-BgLPbwbL.js.map +0 -1
  136. package/dist/units-internal-DFcUYjh3.js.map +0 -1
  137. package/dist/zip-CTll_dr0.d.ts.map +0 -1
  138. package/dist/zip-CYZ0F6BV.js.map +0 -1
  139. package/dist/zoom-BoNyOlPm.js.map +0 -1
@@ -1,16 +1,17 @@
1
- import { l as warn, n as InvalidOptionError, r as MediaError, t as InternalError, u as warnOnce } from "./errors-Da2nXCJm.js";
2
- import { F as DEF_PRES_LAYOUT_NAME, J as SLDNUM_PLACEHOLDER_TEXT, P as DEF_PRES_LAYOUT, R as DEF_SLIDE_MARGIN_IN, U as LEVEL_MARGINS_EMU, V as LAYOUT_IDX_SERIES_BASE, X as MIN_SLIDE_MASTER_ID, a as convertRotationDegrees, n as clampRangedInput, q as SLDNUMFLDID, s as getSmartParseNumber, u as mapStated, v as resolveInsetsEmu } from "./units-internal-DFcUYjh3.js";
3
- import { A as inchesToEmu, D as emuToInches, F as EMU_PER_INCH, T as STANDARD_LAYOUTS } from "./table-cell-margins-PDshga8T.js";
4
- import { $t as THEME_CONTENT_TYPE, Bt as PRESENTATION_MAIN_CONTENT_TYPE, E as EMBEDDED_FONT_SLOTS, Gt as SLIDE_CONTENT_TYPE, Ht as PRES_PROPS_REL, It as OFFICE_DOCUMENT_REL, Jt as SLIDE_MASTER_CONTENT_TYPE, Kt as SLIDE_LAYOUT_CONTENT_TYPE, Mt as NOTES_MASTER_REL, Ot as MS_MEDIA_REL, Pt as NOTES_SLIDE_REL, Qt as TABLE_STYLES_REL, St as EXTENDED_PROPS_REL, Tt as IMAGE_REL, Ut as RELATIONSHIPS_CONTENT_TYPE, Vt as PRES_PROPS_CONTENT_TYPE, Xt as SLIDE_REL, Yt as SLIDE_MASTER_REL, Zt as TABLE_STYLES_CONTENT_TYPE, _t as CORE_PROPS_CONTENT_TYPE, a as textAlignToken, an as OOXML_NS, bt as CUSTOM_PROPS_REL, c as checkEnumOrThrow, cn as bytesToBase64, d as xsdBool, en as THEME_REL, f as xsdBoolIfTrue, fn as toMediaDataUri, gt as COMMENT_AUTHORS_REL, h as stripHash, it as AUDIO_REL, l as checkEnumOrWarn, ln as decodeBase64ToBytes, mt as COMMENTS_REL, nn as VIEW_PROPS_CONTENT_TYPE, nt as TRANSITION_TYPES, on as PML_ROOT_NS, ot as CHARTEX_REL, p as isHexColor, qt as SLIDE_LAYOUT_REL, rn as VIEW_PROPS_REL, rt as TRANSITION_VARIANT_ATTRIBUTES, tn as VIDEO_REL, ut as CHART_REL, vt as CORE_PROPS_REL, w as DEFAULT_COLOR_MAP, xt as EXTENDED_PROPS_CONTENT_TYPE, yt as CUSTOM_PROPS_CONTENT_TYPE } from "./image-size-DwDbakcl.js";
5
- import { a as avContentType, i as audioExtensionForSubtype, o as dataUriMediaType, s as imageContentType } from "./text-anchor-BgLPbwbL.js";
6
- import { At as getDuplicateObjectNames, C as targetBetweenPptSubparts, Ct as FONT_DATA_CONTENT_TYPE, D as cNvPrEl, Dt as serializeEmbeddedFontLst, Et as flattenEmbeddedFaces, G as clampParaMarginInchesEmu, It as preencodedPath, K as buAutoNumEl, N as spTreeEl, Nt as isHyperlinkRel, Ot as XML_DECL, Pt as isPreencodedPath, R as prstGeomRect, Rt as encodeXmlAttrValue, S as slidePath, St as voidEl, T as targetFromPresentation, Tt as FONT_REL_TYPE, U as clampFontSizeSz, W as clampParaIndentInchesEmu, _ as fontPath, at as fillNamesPaint, b as relsPath, bt as elOrVoid, c as themeFontDefRPr, f as relationshipsPart, g as commentPath, h as SLIDE_MASTER_PATH, ht as createColorElement, i as makeXmlNotesSlide, j as grpXfrmEl, jt as getNewRelId, kt as bracedGuid, l as externalHyperlinkRel, m as PRESENTATION_PATH, n as makeXmlNotesMaster, ot as genXmlColorSelection, p as NOTES_MASTER_PATH, q as buCharEl, s as lvlPPr, t as buildNotesSlideRels, u as relationshipEl, ut as STRETCH_FILL_RECT, v as notesSlidePath, vt as rejectEmptyColor, w as targetFromPptSubpart, wt as FONT_DATA_EXTENSION, x as slideLayoutPath, xt as raw, y as overrideName, yt as el } from "./notes-BcT571R4.js";
7
- import { A as renderedSlideObjects, B as pushMediaRel, C as msMediaRid, D as findLayoutPlaceholder, E as placeholderOptionsForSlide, F as warnUnauthoredChild, I as SLIDE_METHOD_FAMILIES, L as composeFamilies, M as shapeIdCount, N as addChildDefinition, O as resolveTextAnchor, P as isGroupableObject, R as familyMethodUnavailable, S as alternateContentEl, T as addTextDefinition, V as resolveImageSource, _ as chartPartNames, a as mediaFamily, b as GROUP_SHAPE_LOCK_ATTRS, c as commentsFamily, d as textFamily, f as shapeFamily, g as makeXmlCore, h as groupFamily, i as model3dFamily, j as resolveObjectNameToId, k as collectSlideShapeIds, l as chartFamily, m as imageFamily, n as tableFamily, o as measureFamily, p as notesFamily, r as oleFamily, s as connectorFamily, t as zoomFamily, u as animationsFamily, v as FMT_SCHEME_XML, w as previewRid, x as genXmlObjectLock, y as resolveImageExtent, z as requirePresentationAuthor } from "./zoom-BoNyOlPm.js";
8
- import { n as setOrClear, t as pickDefined } from "./options-internal-WqgMf720.js";
9
- import { b as isFontCollection, g as FontMetricsRegistry, t as applyMeasuredFit, y as parseFontMetrics } from "./fit-CcXbg__l.js";
10
- import { t as ZipWriter } from "./zip-CYZ0F6BV.js";
11
- import { t as transitionSpeedForDuration } from "./transition-speed-kUEWDWTx.js";
12
- import { n as presentationFormatLabel, r as slideSizeType } from "./slide-size-BalTjFuv.js";
13
- //#region src/gen/define/background.ts
1
+ import { d as warnOnce, i as MediaError, n as InternalError, r as InvalidOptionError, u as warn } from "./entry-errors-JMthgJ2g.js";
2
+ import { F as DEF_PRES_LAYOUT_NAME, J as SLDNUM_PLACEHOLDER_TEXT, P as DEF_PRES_LAYOUT, R as DEF_SLIDE_MARGIN_IN, S as transparencyToAlpha, U as LEVEL_MARGINS_EMU, V as LAYOUT_IDX_SERIES_BASE, X as MIN_SLIDE_MASTER_ID, a as convertRotationDegrees, n as clampRangedInput, q as SLDNUMFLDID, s as getSmartParseNumber, u as mapStated, v as resolveInsetsEmu } from "./units-internal-BR3a4cIi.js";
3
+ import { A as inchesToEmu, D as emuToInches, F as EMU_PER_INCH, T as STANDARD_LAYOUTS, o as PlaceholderType } from "./enums-BP9wsb9Q.js";
4
+ import { $ as SLIDE_LAYOUT_CONTENT_TYPE, C as COMMENT_AUTHORS_REL, Ct as DEFAULT_COLOR_MAP, D as CUSTOM_PROPS_REL, E as CUSTOM_PROPS_CONTENT_TYPE, F as MS_MEDIA_REL, Gt as TEXT_CAPS_TYPES, J as PRES_PROPS_CONTENT_TYPE, M as IMAGE_REL, O as EXTENDED_PROPS_CONTENT_TYPE, Q as SLIDE_CONTENT_TYPE, T as CORE_PROPS_REL, Tt as EMBEDDED_FONT_SLOTS, U as OFFICE_DOCUMENT_REL, V as NOTES_SLIDE_REL, X as RELATIONSHIPS_CONTENT_TYPE, Xt as TEXT_UNDERLINE_TYPES, Y as PRES_PROPS_REL, Zt as TEXT_VERTICAL, _ as CHART_REL, an as checkEnumOrWarn, at as TABLE_STYLES_REL, cn as xsdBoolIfTrue, ct as VIDEO_REL, d as AUDIO_REL, dn as stripHash, et as SLIDE_LAYOUT_REL, fn as bytesToBase64, ft as OOXML_NS, gn as toMediaDataUri, in as checkEnumOrThrow, it as TABLE_STYLES_CONTENT_TYPE, k as EXTENDED_PROPS_REL, ln as isHexColor, lt as VIEW_PROPS_CONTENT_TYPE, nn as TRANSITION_TYPES, nt as SLIDE_MASTER_REL, ot as THEME_CONTENT_TYPE, p as CHARTEX_REL, pn as decodeBase64ToBytes, pt as PML_ROOT_NS, q as PRESENTATION_MAIN_CONTENT_TYPE, qt as TEXT_SHAPE_TYPES, rn as TRANSITION_VARIANT_ATTRIBUTES, rt as SLIDE_REL, s as textAlignToken, sn as xsdBool, st as THEME_REL, tt as SLIDE_MASTER_CONTENT_TYPE, ut as VIEW_PROPS_REL, w as CORE_PROPS_CONTENT_TYPE, x as COMMENTS_REL, z as NOTES_MASTER_REL } from "./chart-metadata-CwiTTcJq.js";
5
+ import { c as audioExtensionForSubtype, d as imageContentType, l as avContentType, n as GROUP_SHAPE_LOCK_ATTRS, u as dataUriMediaType } from "./lock-attrs-CSQnFDHP.js";
6
+ import { $ as buAutoNumEl, A as cNvPrEl, C as relsPath, Ct as resolveFillKind, D as targetFromPptSubpart, E as targetBetweenPptSubparts, Et as genXmlImageCropRect, Ft as voidEl, H as prstGeomRect, Ht as isPreencodedPath, It as XML_DECL, J as clampFontSizeSz, Kt as encodeXmlAttrValue, L as spTreeEl, Lt as bracedGuid, Mt as el, Nt as elOrVoid, O as targetFromPresentation, Ot as createColorElement, P as grpXfrmEl, Pt as raw, Q as clampParaMarginInchesEmu, Rt as getDuplicateObjectNames, S as overrideName, T as slidePath, Tt as STRETCH_FILL_RECT, Vt as isHyperlinkRel, Wt as preencodedPath, X as clampParaIndentInchesEmu, Y as clampParaIndentEmu, Z as clampParaMarginEmu, _ as PRESENTATION_PATH, _t as flattenEmbeddedFaces, a as makeXmlNotesMaster, b as fontPath, bt as genXmlColorSelection, d as themeFontDefRPr, dt as withLineDefaults, et as buCharEl, f as externalHyperlinkRel, g as NOTES_MASTER_PATH, gt as FONT_REL_TYPE, h as relationshipsPart, ht as FONT_DATA_EXTENSION, i as buildNotesSlideRels, jt as rejectEmptyColor, mt as FONT_DATA_CONTENT_TYPE, p as relationshipEl, q as underlineProps, s as makeXmlNotesSlide, u as lvlPPr, v as SLIDE_MASTER_PATH, vt as serializeEmbeddedFontLst, w as slideLayoutPath, wt as solidPaint, x as notesSlidePath, y as commentPath, yt as fillNamesPaint, zt as getNewRelId } from "./comments-CKIZYRbZ.js";
7
+ import { A as statedPlaceholderBinding, B as composeFamilies, C as msMediaRid, D as checkPlaceholderBinding, E as placeholderOptionsForSlide, F as shapeIdCount, H as requirePresentationAuthor, I as addChildDefinition, L as isGroupableObject, M as collectSlideShapeIds, N as renderedSlideObjects, O as findLayoutPlaceholder, P as resolveObjectNameToId, R as warnUnauthoredChild, S as alternateContentEl, T as addTextDefinition, U as pushMediaRel, V as familyMethodUnavailable, W as resolveImageSource, _ as makeXmlCore, a as mediaFamily, b as resolveImageExtent, c as commentsFamily, d as textFamily, f as shapeFamily, g as makeXmlTableStyles, h as groupFamily, i as model3dFamily, j as resolveTextAnchor, k as layoutPlaceholderName, l as chartFamily, m as imageFamily, n as tableFamily, o as measureFamily, p as notesFamily, r as oleFamily, s as connectorFamily, t as zoomFamily, u as animationsFamily, v as chartPartNames, w as previewRid, x as genXmlObjectLock, y as FMT_SCHEME_XML, z as SLIDE_METHOD_FAMILIES } from "./zoom-CSSeOwM8.js";
8
+ import { n as setOrClear, t as pickDefined } from "./options-internal-BWgmLPdx.js";
9
+ import { b as isFontCollection, g as FontMetricsRegistry, t as applyMeasuredFit, y as parseFontMetrics } from "./fit-Bpmzep6O.js";
10
+ import { t as ZipWriter } from "./zip-7JTh61LX.js";
11
+ import { t as ANIM_PRESET_IDENTITY } from "./anim-presets-Qbgh8uut.js";
12
+ import { t as transitionSpeedForDuration } from "./transition-speed-CNJ0fSpQ.js";
13
+ import { n as presentationFormatLabel, r as slideSizeType } from "./slide-size-SkScz1ig.js";
14
+ // src/gen/define/background.ts
14
15
  /**
15
16
  * pptx-ts: Background Definition
16
17
  *
@@ -21,7 +22,7 @@ import { n as presentationFormatLabel, r as slideSizeType } from "./slide-size-B
21
22
  * Adds a background image or color to a slide definition.
22
23
  *
23
24
  * Only an image background does anything here: it is the one that needs a media relationship.
24
- * A colour — object or the bare-string shorthand — carries no rel and is emitted straight from
25
+ * A colour (object or the bare-string shorthand) carries no rel and is emitted straight from
25
26
  * `slide.background` at serialize time.
26
27
  *
27
28
  * The rel id and the part name come from the shared allocators. This used to take the id as
@@ -49,11 +50,12 @@ import { n as presentationFormatLabel, r as slideSizeType } from "./slide-size-B
49
50
  * @param {SlideLayoutInternal} target - slide or layout that the background is set on
50
51
  */
51
52
  function addBackgroundDefinition(props, target) {
52
- if (!(props && typeof props === "object" && (props.path || props.data))) {
53
+ const image = backgroundImage(props);
54
+ if (!image) {
53
55
  delete target._bkgdImgRid;
54
56
  return;
55
57
  }
56
- const source = resolveImageSource(props);
58
+ const source = resolveImageSource(image);
57
59
  if (typeof source === "string") {
58
60
  warn("background/missing-base64-header", "background `data` value lacks a base64 header (ex: 'image/png;base64,...'); ignoring the background image.");
59
61
  delete target._bkgdImgRid;
@@ -87,8 +89,24 @@ function addBackgroundDefinition(props, target) {
87
89
  });
88
90
  target._bkgdImgRid = rId;
89
91
  }
90
- //#endregion
91
- //#region src/slide.ts
92
+ /**
93
+ * The picture a background names, in either of its two spellings: `{ data }` / `{ path }` from
94
+ * `DataOrPathProps`, or `{ image: { data, crop } }` from `ShapeFillProps`, which `BackgroundProps`
95
+ * also extends. The second used to type-check and register nothing, so the background was written
96
+ * as `<a:noFill/>` and its crop was lost with it.
97
+ *
98
+ * The top-level spelling wins, as it always has. The `image` one follows the fill rule that an
99
+ * explicit `type` other than `'image'` wins over a sub-object.
100
+ * @param props - the background option
101
+ * @returns the picture's source, or `null` when the background names none
102
+ */
103
+ function backgroundImage(props) {
104
+ if (!props || typeof props !== "object") return null;
105
+ if (props.path || props.data) return props;
106
+ const image = props.image;
107
+ return resolveFillKind(props) === "image" && image && (image.path || image.data) ? image : null;
108
+ }
109
+ // src/slide.ts
92
110
  /**
93
111
  * Project one authored render-object onto the public {@link SlideObjectInfo}, recursing into a
94
112
  * group's children.
@@ -139,7 +157,7 @@ var SlideBuilder = class {
139
157
  constructor(params) {
140
158
  this.addSlide = params.addSlide;
141
159
  this.getSlide = params.getSlide;
142
- this.getSections = params.getSections ?? (() => []);
160
+ this.getSections = params.getSections;
143
161
  this._name = `Slide ${params.slideNumber}`;
144
162
  this._presLayout = params.presLayout;
145
163
  this._rId = params.slideRId;
@@ -148,7 +166,7 @@ var SlideBuilder = class {
148
166
  this._relsMedia = [];
149
167
  this._setSlideNum = params.setSlideNum;
150
168
  this._slideId = params.slideId;
151
- this._slideLayout = params.slideLayout || null;
169
+ this._slideLayout = params.slideLayout;
152
170
  this._slideNum = params.slideNumber;
153
171
  this._slideObjects = [];
154
172
  this._childAuthors = params.childAuthors;
@@ -157,7 +175,7 @@ var SlideBuilder = class {
157
175
  * `defineSlideMaster` and `addNewSlide.slideNumber` will add {slideNumber} to `this.masterSlide` and `this.slideLayouts`
158
176
  * so, lastly, add to the Slide now.
159
177
  */
160
- this._slideNumberProps = this._slideLayout?._slideNumberProps ? this._slideLayout._slideNumberProps : null;
178
+ this._slideNumberProps = params.slideLayout._slideNumberProps ?? null;
161
179
  }
162
180
  /**
163
181
  * Put this presentation's family methods on the slide.
@@ -269,8 +287,7 @@ var SlideBuilder = class {
269
287
  return emuToInches(this._presLayout.height);
270
288
  }
271
289
  };
272
- //#endregion
273
- //#region src/font-source.ts
290
+ // src/font-source.ts
274
291
  /**
275
292
  * pptx-ts: getting font bytes out of whatever the caller handed over.
276
293
  *
@@ -310,8 +327,11 @@ async function resolveFontBytes(source, runtime, opts, label) {
310
327
  }
311
328
  throw new InvalidOptionError("font/missing-source", `${label} must be a font path, raw bytes, or base64 data`);
312
329
  }
313
- //#endregion
314
- //#region src/gen/define/master.ts
330
+ // src/gen/define/master.ts
331
+ /** Whether a definition's `type` is one of the six friendly ones the `p:ph` writer maps itself. */
332
+ function isFriendlyPlaceholderType(type) {
333
+ return Object.hasOwn(PlaceholderType, type) || Object.values(PlaceholderType).includes(type);
334
+ }
315
335
  /**
316
336
  * Transforms a slide definition to a slide object that is then passed to the XML transformation process.
317
337
  * @param {SlideMasterProps} props - slide definition
@@ -323,40 +343,59 @@ function createSlideMaster(props, target, children) {
323
343
  const tgt = target;
324
344
  if (addChildDefinition(tgt, object, children)) {} else if ("placeholder" in object) {
325
345
  const placeholder = object.placeholder;
326
- const { name, type, ...rawPlaceholderOptions } = placeholder.options;
346
+ const { name, type, idx: statedIdx, ...rawPlaceholderOptions } = placeholder.options;
347
+ checkPlaceholderBinding({
348
+ ...statedIdx === void 0 ? {} : { idx: statedIdx },
349
+ ...isFriendlyPlaceholderType(type) ? {} : { type }
350
+ }, "defineSlideMaster");
327
351
  const placeholderOptions = rawPlaceholderOptions;
328
352
  placeholderOptions.placeholder = name;
329
353
  placeholderOptions._placeholderType = type;
330
- placeholderOptions._placeholderIdx = 100 + idx;
354
+ placeholderOptions._placeholderIdx = statedIdx ?? 100 + idx;
331
355
  const placeholderRun = placeholder.text === void 0 ? {} : { text: placeholder.text };
332
356
  addTextDefinition(tgt, [placeholderRun], placeholderOptions, true);
333
357
  } else warnUnauthoredChild(object, "defineSlideMaster()");
334
358
  });
335
359
  if (props.slideNumber && typeof props.slideNumber === "object") target._slideNumberProps = props.slideNumber;
336
360
  }
337
- //#endregion
338
- //#region src/gen/define/placeholder.ts
361
+ // src/gen/define/placeholder.ts
339
362
  /**
340
363
  * Adds placeholder objects to slide
341
364
  * @param {PresSlideInternal} slide - slide object containing layouts
342
365
  */
343
366
  function addPlaceholdersToSlideLayouts(slide) {
344
367
  if (!slide._slideLayout) return;
345
- (slide._slideLayout._slideObjects || []).forEach((slideLayoutObj) => {
368
+ slide._slideLayout._slideObjects.forEach((slideLayoutObj) => {
346
369
  if (slideLayoutObj._type === "placeholder") {
347
370
  const slideLayoutOptions = slideLayoutObj.options || {};
348
- if (!slide._slideObjects.some((slideObj) => slideObj.options && slideObj.options.placeholder === slideLayoutOptions.placeholder)) addTextDefinition(slide, [{ text: "" }], placeholderOptionsForSlide(slideLayoutOptions), true);
371
+ const fills = (slideObj) => {
372
+ if (layoutPlaceholderName(slideObj.options?.placeholder) === slideLayoutOptions.placeholder) return true;
373
+ const binding = statedPlaceholderBinding(slideObj.options?.placeholder);
374
+ if (!binding || slideLayoutOptions._placeholderIdx === void 0) return false;
375
+ if (binding.idx !== void 0) return binding.idx === slideLayoutOptions._placeholderIdx;
376
+ return slideLayoutOptions._placeholderIdx === 0 && binding.type === slideLayoutOptions._placeholderType;
377
+ };
378
+ if (!slide._slideObjects.some(fills)) {
379
+ addTextDefinition(slide, [{ text: "" }], placeholderOptionsForSlide(slideLayoutOptions), true);
380
+ const seeded = slide._slideObjects.at(-1);
381
+ if (seeded) {
382
+ seeded._seeded = true;
383
+ seeded.text = [];
384
+ const options = seeded.options ?? (seeded.options = {});
385
+ const line = options.line;
386
+ options.line = line?.type === "none" ? { type: "none" } : line && fillNamesPaint(line) ? withLineDefaults(line, "line.color") : { type: "inherit" };
387
+ }
388
+ }
349
389
  }
350
390
  });
351
391
  }
352
- //#endregion
353
- //#region src/media/placeholders.ts
392
+ // src/media/placeholders.ts
354
393
  /**
355
394
  * The base64 placeholder images the library falls back to when a real asset is unavailable.
356
395
  *
357
396
  * Their own module because of where the bundler puts them, not because they group naturally.
358
397
  * The chunker splits by module, so a constant is pulled into every chunk that reaches the module
359
- * declaring it — and these lived in `constants-internal.ts` beside `XML_DECL`, `DEF_FONT_SIZE`
398
+ * declaring it, and these lived in `constants-internal.ts` beside `XML_DECL`, `DEF_FONT_SIZE`
360
399
  * and the rest of the vocabulary all of `src/gen/` imports. The rule that follows: a payload
361
400
  * measured in kilobytes does not share a module with vocabulary, however tidy that grouping reads.
362
401
  *
@@ -368,8 +407,7 @@ function addPlaceholdersToSlideLayouts(slide) {
368
407
  const IMG_BROKEN = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAB3CAYAAAD1oOVhAAAGAUlEQVR4Xu2dT0xcRRzHf7tAYSsc0EBSIq2xEg8mtTGebVzEqOVIolz0siRE4gGTStqKwdpWsXoyGhMuyAVJOHBgqyvLNgonDkabeCBYW/8kTUr0wsJC+Wfm0bfuvn37Znbem9mR9303mJnf/Pb7ed95M7PDI5JIJPYJV5EC7e3t1N/fT62trdqViQCIu+bVgpIHEo/Hqbe3V/sdYVKHyWSSZmZm8ilVA0oeyNjYmEnaVC2Xvr6+qg5fAOJAz4DU1dURGzFSqZRVqtMpAFIGyMjICC0vL9PExIRWKADiAYTNshYWFrRCARAOEFZcCKWtrY0GBgaUTYkBRACIE4rKZwqACALR5RQAqQCIDqcASIVAVDsFQCSAqHQKgEgCUeUUAPEBRIVTAMQnEBvK5OQkbW9vk991CoAEAMQJxc86BUACAhKUUwAkQCBBOAVAAgbi1ykAogCIH6cAiCIgsk4BEIVAZJwCIIqBVLqiBxANQFgXS0tLND4+zl08AogmIG5OSSQS1gGKwgtANAIRcQqAaAbCe6YASBWA2E6xDyeyDUl7+AKQMkDYYevm5mZHabA/Li4uUiaTsYLau8QA4gLE/hU7wajyYtv1hReDAiAOxQcHBymbzark4BkbQKom/X8dp9Npmpqasn4BIAYAYSnYp+4BBEAMUcCwNOCQsAKZnp62NtQOw8WmwT09PUo+ijaHsOMx7GppaaH6+nolH0Z10K2tLVpdXbW6UfV3mNqBdHd3U1NTk2rtlMRfW1uj2dlZAFGirkRQAJEQTWUTAFGprkRsAJEQTWUTAFGprkRsAJEQTWUTAFGprkRsAJEQTWUTAFGprkRsAJEQTWUTAFGprkRsAJEQTWUTAGHqrm8caPzQ0WC1logbeiC7X3xJm0PvUmRzh45cuki1588FAmVn9BO6P3yF9utrqGH0MtW82S8UN9RA9v/4k7InjhcJFTs/TLVXLwmJV67S7vD7tHF5pKi46fYdosdOcOOGG8j1OcqefbFEJD9Q3GCwDhqT31HklS4A8VRgfYM2Op6k3bt/BQJl58J7lPvwg5JYNccepaMry0LPqFA7hCm39+NNyp2J0172b19QysGINj5CsRtpij57musOViH0QPJQXn6J9u7dlYJSFkbrMYolrwvDAJAC+WWdEpQz7FTgECeUCpzi6YxvvqXoM6eEhqnCSgDikEzUKUE7Aw7xuHctKB5OYU3dZlNR9syQdAaAcAYTC0pXF+39c09o2Ik+3EqxVKqiB7hbYAxZkk4pbBaEM+AQofv+wTrFwylBOQNABIGwavdfe4O2pg5elO+86l99nY58/VUF0byrYsjiSFluNlXYrOHcBar7+EogUADEQ0YRGHbzoKAASBkg2+9cpM1rV0tK2QOcXW7bLEFAARAXIF4w2DrDWoeUWaf4hQIgDiA8GPZ2iNfi0Q8UACkAIgrDbrJ385eDxaPLLrEsFAB5oG6lMPJQPLZZZKAACBGVhcG2Q+bmuLu2nk55e4jqPv1IeEoceiBeX7s2zCa5MAqdstl91vfXwaEGsv/rb5TtOFk6tWXOuJGh6KmnhO9sayrMninPx103JBtXblHkice58cINZP4Hyr5wpkgkdiChEmc4FWazLzenNKa/p0jncwDiqcD6BuWePk07t1asatZGoYQzSqA4nFJ7soNiP/+EUyfc25GI2GG53dHPrKo1g/1Cw4pIXLrzO+1c+/wg7tBbFDle/EbQcjFCPWQJCau5EoBoFpzXHYDwFNJcDiCaBed1ByA8hTSXA4hmwXndAQhPIc3lAKJZcF53AMJTSHM5gGgWnNcdgPAU0lwOIJoF53UHIDyFNJcfSiCdnZ0Ui8U0SxlMd7lcjubn561gh+Y1scFIU/0o/3sgeLO12E2k7UXKYumgFoAYdg8ACIAYpoBh6cAhAGKYAoalA4cAiGEKGJYOHAIghilgWDpwCIAYpoBh6cAhAGKYAoalA4cAiGEKGJYOHAIghilgWDpwCIAYpoBh6ZQ4JB6PKzviYthnNy4d9h+1M5mMlVckkUjsG5dhiBMCEMPg/wuOfrZZ/RSywQAAAABJRU5ErkJggg==";
369
408
  /** 1x1 transparent PNG, standing in for an SVG the runtime could not rasterize. */
370
409
  const IMG_SVG_PLACEHOLDER = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
371
- //#endregion
372
- //#region src/gen/media.ts
410
+ // src/gen/media.ts
373
411
  /**
374
412
  * pptx-ts: Media Methods
375
413
  */
@@ -398,14 +436,14 @@ async function writeSvgPreview(rel, runtime, onMediaError) {
398
436
  * Encode Image/Audio/Video into base64
399
437
  * @param {PresSlideInternal | SlideLayoutInternal | SlideMasterInternal} layout - slide, layout or master
400
438
  * @param {RuntimeAdapter} runtime - runtime adapter (Node/browser media loader)
401
- * @param {'throw' | 'placeholder'} onMediaError - failure policy: reject the export (default) or substitute a placeholder and warn
439
+ * @param {'throw' | 'placeholder'} onMediaError - failure policy: reject the export or substitute a placeholder and warn
402
440
  * @return {Promise} promise
403
441
  */
404
- function encodeSlideMediaRels(layout, runtime, onMediaError = "throw") {
442
+ function encodeSlideMediaRels(layout, runtime, onMediaError) {
405
443
  const imageProms = [];
406
444
  const defaultCoverRels = layout._relsMedia.filter((rel) => rel.isDefaultCover && !rel.data);
407
445
  if (defaultCoverRels.length > 0) imageProms.push((async () => {
408
- const { IMG_PLAYBTN } = await import("./playbtn-CUqQdoDf.js");
446
+ const { IMG_PLAYBTN } = await import("./playbtn-BQZFJir9.js");
409
447
  for (const rel of defaultCoverRels) rel.data = IMG_PLAYBTN;
410
448
  return "done";
411
449
  })());
@@ -445,24 +483,23 @@ function encodeSlideMediaRels(layout, runtime, onMediaError = "throw") {
445
483
  });
446
484
  return imageProms;
447
485
  }
448
- //#endregion
449
- //#region src/gen/prepare.ts
486
+ // src/gen/prepare.ts
450
487
  /**
451
488
  * pptx-ts: the pre-serialization pass
452
489
  *
453
490
  * Everything that must happen to authored slide state *before* any XML is built. Two callers
454
491
  * reach serialization and both need it:
455
492
  *
456
- * - `package/assemble.ts` — the normal `write`/`stream`/`writeFile` path, building a
493
+ * - `package/assemble.ts`: the normal `write`/`stream`/`writeFile` path, building a
457
494
  * complete `.pptx`.
458
- * - `PresentationCore.extractSlides()` — serializes slide bodies only, for splicing into
495
+ * - `PresentationCore.extractSlides()`: serializes slide bodies only, for splicing into
459
496
  * an already-loaded deck via `Presentation.appendSlides()` (`pptx-ts/read`).
460
497
  *
461
498
  * The second used to reimplement the first inline, kept in step by a comment that said
462
499
  * "exactly as ... does". Nothing failed when they drifted: `extractSlides` would simply emit
463
500
  * slides that did not match what a normal write produces, and no test compares the two.
464
501
  *
465
- * Three steps rather than one combined pass, because the package path has work of its own that
502
+ * Separate steps rather than one combined pass, because the package path has work of its own that
466
503
  * must land between the last two: it de-duplicates identical media across the deck (which needs
467
504
  * the encoded bytes {@link encodeMediaForTargets} produces) and assigns package-unique chart part
468
505
  * filenames, both before any text is measured. Exposing the steps lets `assemble` keep that work
@@ -470,7 +507,9 @@ function encodeSlideMediaRels(layout, runtime, onMediaError = "throw") {
470
507
  *
471
508
  * The order is load-bearing:
472
509
  *
473
- * 1. **Backfill placeholders first**, so a slide carries its layout's placeholder objects before
510
+ * 0. **Register transition sounds**, before media encoding loads their bytes and before
511
+ * backfill, so a slide's rel ids come out the same on both paths.
512
+ * 1. **Backfill placeholders**, so a slide carries its layout's placeholder objects before
474
513
  * anything reads its media. A seeded placeholder can register media of its own, an image fill,
475
514
  * and when backfill ran after encoding that image was never loaded and its rel named a part
476
515
  * that was never written.
@@ -482,7 +521,7 @@ function encodeSlideMediaRels(layout, runtime, onMediaError = "throw") {
482
521
  *
483
522
  * The functions take different target sets on purpose: media lives on layouts and the master as
484
523
  * well as on slides, while placeholder backfill and measured fit apply only to slides.
485
- * `extractSlides` passes only its slides to all three, because it emits no layout or master
524
+ * `extractSlides` passes only its slides to every step, because it emits no layout or master
486
525
  * parts.
487
526
  */
488
527
  /**
@@ -518,10 +557,19 @@ function requireSlideLinksInDeck(slides, layouts = [], master) {
518
557
  part: master
519
558
  }] : []
520
559
  ];
560
+ const refuse = (label, target) => {
561
+ throw new InvalidOptionError("slide/link-past-last-slide", `${label} links to slide ${String(target)}, but the deck has ${slides.length} slide${slides.length === 1 ? "" : "s"}.`);
562
+ };
521
563
  for (const { label, part } of sources) for (const rel of part._rels) {
522
564
  if (!isHyperlinkRel(rel) || rel.data !== "slide") continue;
523
- if (!(Number(rel.Target) > slides.length)) continue;
524
- throw new InvalidOptionError("slide/link-past-last-slide", `${label} links to slide ${String(rel.Target)}, but the deck has ${slides.length} slide${slides.length === 1 ? "" : "s"}.`);
565
+ if (Number(rel.Target) > slides.length) refuse(label, rel.Target);
566
+ }
567
+ for (const slide of slides) for (const obj of slide._slideObjects) {
568
+ if (obj._type !== "notes") continue;
569
+ for (const run of obj.text ?? []) {
570
+ const target = run.options?.hyperlink?.slide;
571
+ if (target !== void 0 && target > slides.length) refuse(`The notes of slide ${slide._slideNum}`, target);
572
+ }
525
573
  }
526
574
  }
527
575
  /**
@@ -536,6 +584,61 @@ async function encodeMediaForTargets(targets, runtime, onMediaError) {
536
584
  await Promise.all(promises);
537
585
  }
538
586
  /**
587
+ * Each slide's registered transition sound.
588
+ *
589
+ * Kept per slide, never on the transition: one transition object can be assigned to several slides,
590
+ * and a relationship id means something only inside the slide part that declares it. Kept across
591
+ * writes as well, so a deck written twice registers each sound once. An entry is reused only while
592
+ * the slide still holds its relationship and still has the same sound assigned.
593
+ */
594
+ const registeredTransitionSounds = /* @__PURE__ */ new WeakMap();
595
+ /**
596
+ * Step 0: register an audio media part + relationship for each slide-transition start sound
597
+ * (`transition.sound` with `data`/`path`), and return the relationship id each slide's
598
+ * `p:sndAc/p:snd r:embed` refers to. Runs before media encoding so the bytes are loaded. Re-export
599
+ * is safe: a slide whose sound is already registered reuses that relationship. The stop-previous
600
+ * form (`sound.stopPrevious`) needs no part and is skipped.
601
+ *
602
+ * Registered here, at write time, rather than when `slide.transition` is assigned. A slide's rel
603
+ * ids and media part names are handed out in registration order, and a transition is often set
604
+ * before the slide's pictures and media are added; registering the sound then would move every
605
+ * later rel id and part name on the slide.
606
+ */
607
+ function registerTransitionSounds(slides) {
608
+ const soundRIds = /* @__PURE__ */ new Map();
609
+ slides.forEach((slide) => {
610
+ const transition = slide.transition;
611
+ if (!transition || !TRANSITION_TYPES.includes(transition.type)) return;
612
+ const sound = transition.sound;
613
+ if (!sound || sound.stopPrevious) return;
614
+ if (!sound.data && !sound.path) return;
615
+ const registered = registeredTransitionSounds.get(slide);
616
+ if (registered && slide._relsMedia.includes(registered.rel) && registered.data === sound.data && registered.path === sound.path) {
617
+ soundRIds.set(slide, registered.rel.rId);
618
+ return;
619
+ }
620
+ const dataMime = dataUriMediaType(sound.data ?? "");
621
+ const pathFile = sound.path ? (sound.path.split("/").pop() ?? "").split("?")[0] ?? "" : "";
622
+ const extn = dataMime?.startsWith("audio/") ? audioExtensionForSubtype(dataMime.slice(6)) : (pathFile.split(".").pop() ?? "wav").toLowerCase();
623
+ const rId = getNewRelId(slide);
624
+ const rel = pushMediaRel(slide, {
625
+ kind: "audio",
626
+ extn,
627
+ type: `audio/${extn}`,
628
+ path: sound.path,
629
+ data: sound.data,
630
+ rId
631
+ });
632
+ registeredTransitionSounds.set(slide, {
633
+ rel,
634
+ data: sound.data,
635
+ path: sound.path
636
+ });
637
+ soundRIds.set(slide, rId);
638
+ });
639
+ return soundRIds;
640
+ }
641
+ /**
539
642
  * Step 1: seed each slide with the layout placeholders it leaves empty.
540
643
  * @param {PresSlideInternal[]} slides - the slides to prepare
541
644
  */
@@ -551,10 +654,9 @@ function backfillPlaceholders(slides) {
551
654
  function bakeMeasuredFit(slides, fontMetrics) {
552
655
  return applyMeasuredFit(slides, fontMetrics);
553
656
  }
554
- //#endregion
555
- //#region src/gen/anim/animation.ts
657
+ // src/gen/anim/animation.ts
556
658
  /**
557
- * Resolved animation target's shape id (`spid`), or `null` when it cannot be resolved — in which
659
+ * Resolved animation target's shape id (`spid`), or `null` when it cannot be resolved. In that
558
660
  * case the effect is dropped, so every `null` warns rather than leaving the animation silently
559
661
  * missing from the deck.
560
662
  *
@@ -566,10 +668,10 @@ function bakeMeasuredFit(slides, fontMetrics) {
566
668
  *
567
669
  * `shapeIndex` is a 0-based index into the top-level objects that RENDER, which is the same
568
670
  * sequence `collectSlideShapeIds` allocates along; group children take ids past that range. It
569
- * counted `_slideObjects` itself, and four of that array's members draw nothing — so `addNotes`
671
+ * counted `_slideObjects` itself, and four of that array's members draw nothing, so `addNotes`
570
672
  * before the first shape shifted every index by one and `shapeIndex: 0` addressed the notes.
571
673
  * An index outside `[0, renderedCount)` would emit a `<p:spTgt spid>` naming no shape on the
572
- * slide — a dangling spid PowerPoint reports as a repair (0x80070570) — so it warns and drops,
674
+ * slide (a dangling spid PowerPoint reports as a repair, 0x80070570), so it warns and drops,
573
675
  * exactly like an unresolvable `objectName` does.
574
676
  * @param shapeIds - the slide's shape ids, from `collectSlideShapeIds`
575
677
  * @param slideObjects - the slide's top-level objects, which a `shapeIndex` addresses
@@ -670,38 +772,23 @@ const ANIM_FLY_AXIS = (direction, axis, spid, dur, next) => {
670
772
  };
671
773
  const ANIM_PRESETS = {
672
774
  fadeIn: {
673
- presetID: 10,
674
- presetClass: "entr",
675
- presetSubtype: 0,
676
- defaultDurationMs: 500,
775
+ ...ANIM_PRESET_IDENTITY.fadeIn,
677
776
  behaviors: (spid, dur, next) => ANIM_SET_VISIBLE(spid, next) + ANIM_FADE("in", spid, dur, next)
678
777
  },
679
778
  flyIn: {
680
- presetID: 2,
681
- presetClass: "entr",
682
- presetSubtype: 4,
683
- defaultDurationMs: 500,
779
+ ...ANIM_PRESET_IDENTITY.flyIn,
684
780
  behaviors: (spid, dur, next) => ANIM_SET_VISIBLE(spid, next) + ANIM_FLY_AXIS("in", "x", spid, dur, next) + ANIM_FLY_AXIS("in", "y", spid, dur, next)
685
781
  },
686
782
  appear: {
687
- presetID: 1,
688
- presetClass: "entr",
689
- presetSubtype: 0,
690
- defaultDurationMs: 500,
783
+ ...ANIM_PRESET_IDENTITY.appear,
691
784
  behaviors: (spid, _dur, next) => ANIM_SET_VISIBLE(spid, next)
692
785
  },
693
786
  wipe: {
694
- presetID: 22,
695
- presetClass: "entr",
696
- presetSubtype: 4,
697
- defaultDurationMs: 500,
787
+ ...ANIM_PRESET_IDENTITY.wipe,
698
788
  behaviors: (spid, dur, next) => ANIM_SET_VISIBLE(spid, next) + ANIM_EFFECT("in", "wipe(down)", spid, dur, next)
699
789
  },
700
790
  grow: {
701
- presetID: 6,
702
- presetClass: "emph",
703
- presetSubtype: 0,
704
- defaultDurationMs: 2e3,
791
+ ...ANIM_PRESET_IDENTITY.grow,
705
792
  behaviors: (spid, dur, next) => el("p:animScale", null, [raw(el("p:cBhvr", null, [raw(voidEl("p:cTn", {
706
793
  id: next(),
707
794
  dur,
@@ -712,10 +799,7 @@ const ANIM_PRESETS = {
712
799
  }))])
713
800
  },
714
801
  spin: {
715
- presetID: 8,
716
- presetClass: "emph",
717
- presetSubtype: 0,
718
- defaultDurationMs: 2e3,
802
+ ...ANIM_PRESET_IDENTITY.spin,
719
803
  behaviors: (spid, dur, next) => el("p:animRot", { by: 216e5 }, [raw(el("p:cBhvr", null, [
720
804
  raw(voidEl("p:cTn", {
721
805
  id: next(),
@@ -727,17 +811,11 @@ const ANIM_PRESETS = {
727
811
  ]))])
728
812
  },
729
813
  fadeOut: {
730
- presetID: 10,
731
- presetClass: "exit",
732
- presetSubtype: 0,
733
- defaultDurationMs: 500,
814
+ ...ANIM_PRESET_IDENTITY.fadeOut,
734
815
  behaviors: (spid, dur, next) => ANIM_FADE("out", spid, dur, next) + ANIM_SET_HIDDEN(spid, dur, next)
735
816
  },
736
817
  flyOut: {
737
- presetID: 2,
738
- presetClass: "exit",
739
- presetSubtype: 4,
740
- defaultDurationMs: 500,
818
+ ...ANIM_PRESET_IDENTITY.flyOut,
741
819
  behaviors: (spid, dur, next) => ANIM_FLY_AXIS("out", "x", spid, dur, next) + ANIM_FLY_AXIS("out", "y", spid, dur, next) + ANIM_SET_HIDDEN(spid, dur, next)
742
820
  }
743
821
  };
@@ -847,8 +925,7 @@ function buildBldList(animations) {
847
925
  }
848
926
  return el("p:bldLst", null, raw(bldPs.join("")));
849
927
  }
850
- //#endregion
851
- //#region src/gen/anim/timing.ts
928
+ // src/gen/anim/timing.ts
852
929
  /**
853
930
  * Build the slide-level `<p:timing>` tree that makes embedded media loop.
854
931
  * - PowerPoint stores playback looping as `repeatCount` on the media node's `<p:cTn>`
@@ -863,7 +940,7 @@ function buildBldList(animations) {
863
940
  function slideTimingToXml(slide) {
864
941
  const loopMedia = slide._slideObjects.filter((obj) => obj._type === "media" && obj.mtype !== "online" && typeof obj.mediaRid === "number" && (obj.loop === true || typeof obj.loopCount === "number" && obj.loopCount > 0));
865
942
  const shapeIds = collectSlideShapeIds(slide._slideObjects);
866
- const animations = (slide._animations ?? []).filter((anim) => hasKnownAnimationPreset(anim)).map((anim) => ({
943
+ const animations = slide._animations.filter((anim) => hasKnownAnimationPreset(anim)).map((anim) => ({
867
944
  anim,
868
945
  spid: resolveAnimationSpid(shapeIds, slide._slideObjects, anim)
869
946
  })).filter((entry) => entry.spid !== null);
@@ -901,8 +978,7 @@ function slideTimingToXml(slide) {
901
978
  nodeType: "tmRoot"
902
979
  }, raw(el("p:childTnLst", null, raw(seq + mediaNodes))))))))), raw(bldLst)]);
903
980
  }
904
- //#endregion
905
- //#region src/gen/anim/transition.ts
981
+ // src/gen/anim/transition.ts
906
982
  /**
907
983
  * The attributes of a transition's type element, from the caller's `variant`.
908
984
  *
@@ -919,7 +995,7 @@ function transitionVariantAttrs(type, variant) {
919
995
  attrs[name] = value;
920
996
  continue;
921
997
  }
922
- warnOnce("transition/unknown-variant", `slide transition \`${type}\` variant \`${name}\` is not an attribute of <p:${type}> and is ignored — ${allowed.length > 0 ? `use ${allowed.join(", ")}` : "it takes none"}.`, {
998
+ warnOnce("transition/unknown-variant", `slide transition \`${type}\` variant \`${name}\` is not an attribute of <p:${type}> and is ignored; ${allowed.length > 0 ? `use ${allowed.join(", ")}` : "it takes none"}.`, {
923
999
  received: name,
924
1000
  valid: allowed
925
1001
  });
@@ -982,9 +1058,8 @@ function slideTransitionToXml(slide, soundRId) {
982
1058
  fallback: el("p:transition", baseAttrs, [raw(typeEl), raw(sndAc)])
983
1059
  });
984
1060
  }
985
- //#endregion
986
- //#region src/gen/slide/object.ts
987
- /** The four axes that make up an explicit group frame. All or nothing — see `givenGroupFrameAxes`. */
1061
+ // src/gen/slide/object.ts
1062
+ /** The four axes that make up an explicit group frame. All or nothing; see `givenGroupFrameAxes`. */
988
1063
  const GROUP_FRAME_AXES = [
989
1064
  "x",
990
1065
  "y",
@@ -996,14 +1071,14 @@ const GROUP_FRAME_AXES = [
996
1071
  *
997
1072
  * A group frame is explicit only when **all four** are given; anything less falls back to
998
1073
  * auto-bounds on every axis. Partial frames used to be honoured per-axis, which let the unset ones
999
- * take the shared per-object defaults (`x=0`, `y=0`, `cx=75%` of the layout width, `cy=0`) — so
1074
+ * take the shared per-object defaults (`x=0`, `y=0`, `cx=75%` of the layout width, `cy=0`), so
1000
1075
  * `addGroup([rect], { x: 5, y: 2 })` emitted a zero-height group whose width was a silent
1001
1076
  * slide-width fraction, and every child of it then re-read as `null` through the read path's
1002
1077
  * degenerate-`chExt` guard.
1003
1078
  *
1004
1079
  * Per-axis fallback was the other candidate, but it cannot mean what it reads like: the writer keeps
1005
1080
  * an identity child space (`chOff/chExt == off/ext`), so a group's frame never moves or scales its
1006
- * children — it only places the selection handle and the rotate pivot. `{ x: 5 }` would leave the
1081
+ * children; it only places the selection handle and the rotate pivot. `{ x: 5 }` would leave the
1007
1082
  * children where they were and put the group's box somewhere they are not. Falling back whole, with
1008
1083
  * a warning, keeps the group box around its content and says so out loud.
1009
1084
  * @param options - the group object's options
@@ -1023,7 +1098,7 @@ const hasCompleteGroupFrame = (options) => givenGroupFrameAxes(options).length =
1023
1098
  * `<a:ext cx>`/`<a:ext cy>` are `ST_PositiveCoordinate` (ECMA-376 Part 1, `CT_PositiveSize2D`), so a
1024
1099
  * negative extent is schema-invalid. PowerPoint rejects the *whole* presentation with "The file or
1025
1100
  * directory is corrupted and unreadable" (0x80070570) and names no shape, part, or slide, while
1026
- * LibreOffice renders the same package happily — so the defect is invisible until the deck reaches
1101
+ * LibreOffice renders the same package happily, so the defect is invisible until the deck reaches
1027
1102
  * PowerPoint.
1028
1103
  *
1029
1104
  * A signed delta is the natural way to write "draw from A to B" (`{ x: x0, y: y0, w: x1 - x0, h: y1 - y0 }`),
@@ -1075,7 +1150,7 @@ function resolveObjectFrame(obj, slide) {
1075
1150
  const layout = slide._presLayout;
1076
1151
  const placeholder = findLayoutPlaceholder(slide._slideLayout, itemOpts.placeholder);
1077
1152
  const phOpts = placeholder?.options ?? {};
1078
- const inherited = (own, ph) => own !== void 0 ? own : ph ?? void 0;
1153
+ const inherited = (own, ph) => own ?? ph ?? void 0;
1079
1154
  const ownX = inherited(itemOpts.x, phOpts.x);
1080
1155
  const ownY = inherited(itemOpts.y, phOpts.y);
1081
1156
  const ownW = inherited(itemOpts.w, phOpts.w);
@@ -1096,7 +1171,7 @@ function resolveObjectFrame(obj, slide) {
1096
1171
  * Whether this part has a real slide number to cache in a `slidenum` field.
1097
1172
  *
1098
1173
  * Only a slide does. A master leaves `_slideNum` null and a layout carries the internal 1000+
1099
- * counter that keeps layout media keys from colliding with slide media — neither is a page
1174
+ * counter that keeps layout media keys from colliding with slide media. Neither is a page
1100
1175
  * number, and neither belongs in the field's cached text.
1101
1176
  */
1102
1177
  function hasRealSlideNumber(slide) {
@@ -1107,7 +1182,7 @@ function hasRealSlideNumber(slide) {
1107
1182
  *
1108
1183
  * Unique `objectName` values are what consumers (e.g. semantic manifests) rely on, so
1109
1184
  * collisions are flagged loudly. Deliberately NOT `warnOnce`: this runs per emit, and two
1110
- * `write()` calls are two separate exports — a caller capturing diagnostics around the second
1185
+ * `write()` calls are two separate exports, and a caller capturing diagnostics around the second
1111
1186
  * would otherwise be told its deck is clean because the first one had already said otherwise. Groups are recursed into: a group's children are
1112
1187
  * `<p:cNvPr>`-named on this same slide, so a child colliding with a top-level object (or with a
1113
1188
  * child of another group) is a collision the Selection Pane shows, and checking only the top
@@ -1126,14 +1201,32 @@ function warnDuplicateObjectNames(slide) {
1126
1201
  * mutually exclusive because a master carrying both a `color` and a `path` must still produce a
1127
1202
  * single `<p:bg>`.
1128
1203
  */
1204
+ /**
1205
+ * The `<a:srcRect>` of a picture background: the crop an `image: { crop }` background states, else
1206
+ * the empty, uncropped form every picture background wrote before it could have one.
1207
+ */
1208
+ function backgroundSrcRect(background) {
1209
+ const image = backgroundImage(background);
1210
+ const crop = image && "crop" in image ? image.crop : void 0;
1211
+ return crop ? genXmlImageCropRect(crop, "background image", "") : voidEl("a:srcRect");
1212
+ }
1213
+ /**
1214
+ * The children of a picture background's `<a:blip>`: its `transparency` as `a:alphaModFix`, as a
1215
+ * shape's picture fill writes it and PowerPoint writes Format Background's picture transparency
1216
+ * (#98), then the `a:lum` every picture background has always carried.
1217
+ */
1218
+ function backgroundBlipEffects(background) {
1219
+ const transparency = typeof background === "object" ? background.transparency : void 0;
1220
+ return (transparency ? voidEl("a:alphaModFix", { amt: transparencyToAlpha(transparency) }) : "") + voidEl("a:lum");
1221
+ }
1129
1222
  function slideBackgroundXml(slide) {
1130
1223
  let strSlideXml = "";
1131
1224
  if (slide._bkgdImgRid) strSlideXml += el("p:bg", null, raw(el("p:bgPr", null, [raw(el("a:blipFill", {
1132
1225
  dpi: "0",
1133
1226
  rotWithShape: "1"
1134
1227
  }, [
1135
- raw(el("a:blip", { "r:embed": `rId${slide._bkgdImgRid}` }, raw(voidEl("a:lum")))),
1136
- raw(voidEl("a:srcRect")),
1228
+ raw(el("a:blip", { "r:embed": `rId${slide._bkgdImgRid}` }, raw(backgroundBlipEffects(slide.background)))),
1229
+ raw(backgroundSrcRect(slide.background)),
1137
1230
  raw(STRETCH_FILL_RECT)
1138
1231
  ])), raw(voidEl("a:effectLst"))])));
1139
1232
  else if (fillNamesPaint(slide.background)) strSlideXml += el("p:bg", null, raw(el("p:bgPr", null, [raw(genXmlColorSelection(slide.background)), raw(voidEl("a:effectLst"))])));
@@ -1144,7 +1237,7 @@ function slideBackgroundXml(slide) {
1144
1237
  * The slide-number placeholder shape.
1145
1238
  *
1146
1239
  * Emitted after every authored object, so its `<p:cNvPr>` id can come from the same monotonic
1147
- * counter the walk has been advancing — the caller allocates it and passes it in.
1240
+ * counter the walk has been advancing; the caller allocates it and passes it in.
1148
1241
  *
1149
1242
  * @param slide - the slide, layout or master being emitted
1150
1243
  * @param snProps - the part's slide-number properties, read but never written: a serializer
@@ -1178,19 +1271,21 @@ function slideNumberPlaceholderXml(slide, snProps, slideNumberId) {
1178
1271
  })))), { openPrefix: " " }) + "</p:spPr>";
1179
1272
  strSlideXml += "<p:txBody>";
1180
1273
  const snInsets = resolveInsetsEmu(snProps.margin);
1181
- strSlideXml += voidEl("a:bodyPr", {
1274
+ const snWarp = checkEnumOrWarn(snProps.textWarp, TEXT_SHAPE_TYPES, "text/invalid-warp", "slideNumber: textWarp");
1275
+ strSlideXml += elOrVoid("a:bodyPr", {
1182
1276
  lIns: snInsets?.l ?? null,
1183
1277
  tIns: snInsets?.t ?? null,
1184
1278
  rIns: snInsets?.r ?? null,
1185
1279
  bIns: snInsets?.b ?? null,
1186
- anchor: resolveTextAnchor(snProps.valign)
1187
- });
1280
+ anchor: resolveTextAnchor(snProps.valign),
1281
+ vert: checkEnumOrWarn(snProps.textDirection, TEXT_VERTICAL, "text/invalid-vertical", "slideNumber: textDirection")
1282
+ }, snWarp ? el("a:prstTxWarp", { prst: snWarp }, raw(voidEl("a:avLst"))) : "");
1188
1283
  let defRPr = "";
1189
1284
  rejectEmptyColor(snProps.color, "slideNumber color");
1190
1285
  if (snProps.fontFace || snProps.fontSize || snProps.color) {
1191
1286
  const face = snProps.fontFace;
1192
1287
  defRPr = el("a:defRPr", { sz: clampFontSizeSz(snProps.fontSize || 12) }, [
1193
- snProps.color ? raw(genXmlColorSelection(snProps.color)) : null,
1288
+ snProps.color ? raw(genXmlColorSelection(solidPaint(snProps.color, snProps.transparency))) : null,
1194
1289
  face ? raw(voidEl("a:latin", { typeface: face })) : null,
1195
1290
  face ? raw(voidEl("a:ea", { typeface: face })) : null,
1196
1291
  face ? raw(voidEl("a:cs", { typeface: face })) : null
@@ -1200,20 +1295,47 @@ function slideNumberPlaceholderXml(slide, snProps, slideNumberId) {
1200
1295
  const snAlignRaw = snProps.align ?? "left";
1201
1296
  const snAlign = snAlignRaw.startsWith("c") ? "ctr" : snAlignRaw.startsWith("r") ? "r" : "l";
1202
1297
  strSlideXml += el("a:p", null, [
1203
- raw(voidEl("a:pPr", { algn: snAlign })),
1298
+ raw(voidEl("a:pPr", {
1299
+ algn: snAlign,
1300
+ marL: paragraphMarginEmu(snProps.paraMarginLeft, clampParaMarginEmu),
1301
+ indent: paragraphMarginEmu(snProps.paraIndent, clampParaIndentEmu)
1302
+ })),
1204
1303
  raw(el("a:fld", {
1205
1304
  id: SLDNUMFLDID,
1206
1305
  type: "slidenum"
1207
- }, [raw(voidEl("a:rPr", {
1208
- b: xsdBool(snProps.bold),
1209
- lang: "en-US"
1210
- })), raw(el("a:t", null, hasRealSlideNumber(slide) ? String(slide._slideNum) : SLDNUM_PLACEHOLDER_TEXT))])),
1306
+ }, [raw(slideNumberRunProperties(snProps)), raw(el("a:t", null, hasRealSlideNumber(slide) ? String(slide._slideNum) : SLDNUM_PLACEHOLDER_TEXT))])),
1211
1307
  raw(voidEl("a:endParaRPr", { lang: "en-US" }))
1212
1308
  ]);
1213
1309
  strSlideXml += "</p:txBody></p:sp>";
1214
1310
  return strSlideXml;
1215
1311
  }
1216
1312
  /**
1313
+ * The slide-number field's own `a:rPr`: `b` and `lang` as it has always written them, then the
1314
+ * character options `addText` writes on a run's `a:rPr` (`genXmlTextRunProperties`). Colour, face
1315
+ * and size stay on the list style's `a:defRPr`, where they were written first.
1316
+ * @param snProps - the part's slide-number properties
1317
+ */
1318
+ function slideNumberRunProperties(snProps) {
1319
+ const underline = underlineProps(snProps.underline);
1320
+ rejectEmptyColor(snProps.highlight, "slideNumber highlight");
1321
+ rejectEmptyColor(underline?.color, "slideNumber underline.color");
1322
+ return elOrVoid("a:rPr", {
1323
+ b: xsdBool(snProps.bold),
1324
+ lang: snProps.lang || "en-US",
1325
+ i: xsdBoolIfTrue(snProps.italic),
1326
+ cap: snProps.caps ? checkEnumOrWarn(snProps.caps, TEXT_CAPS_TYPES, "text/invalid-caps", "slideNumber `caps`") : null,
1327
+ u: underline?.style ? checkEnumOrWarn(underline.style, TEXT_UNDERLINE_TYPES, "text/invalid-underline", "slideNumber `underline.style`") : null
1328
+ }, [
1329
+ snProps.highlight ? el("a:highlight", null, raw(createColorElement(snProps.highlight))) : "",
1330
+ underline?.color ? el("a:uFill", null, raw(genXmlColorSelection(underline.color))) : "",
1331
+ snProps.fontFaceEA ? voidEl("a:ea", { typeface: snProps.fontFaceEA }) : ""
1332
+ ].join(""));
1333
+ }
1334
+ /** `paraMarginLeft` / `paraIndent` in EMU through the attribute's clamp, or `null` to write none. */
1335
+ function paragraphMarginEmu(option, clamp) {
1336
+ return option === void 0 || option === "inherit" ? null : clamp(option);
1337
+ }
1338
+ /**
1217
1339
  * Transforms a slide or slideLayout to resulting XML string - Creates `ppt/slide*.xml`
1218
1340
  * @param slide - slide object created within createSlideObject
1219
1341
  * @param renderers - which renderer emits each shape family; see {@link RendererTable} for why
@@ -1379,8 +1501,8 @@ function slideObjectToXml(slide, renderers) {
1379
1501
  function defaultRelIdStart(slide) {
1380
1502
  let lastRid = 0;
1381
1503
  for (const rel of slide._rels) lastRid = Math.max(lastRid, rel.rId);
1382
- for (const rel of slide._relsChart || []) lastRid = Math.max(lastRid, rel.rId);
1383
- for (const rel of slide._relsMedia || []) lastRid = Math.max(lastRid, rel.rId);
1504
+ for (const rel of slide._relsChart) lastRid = Math.max(lastRid, rel.rId);
1505
+ for (const rel of slide._relsMedia) lastRid = Math.max(lastRid, rel.rId);
1384
1506
  return lastRid + 1;
1385
1507
  }
1386
1508
  /**
@@ -1390,7 +1512,7 @@ function defaultRelIdStart(slide) {
1390
1512
  * `selfPath` is the emitting part's own path, and it is required because a relationship target
1391
1513
  * resolves against the part that states it. An internal slide link used to be written
1392
1514
  * `slide${n}.xml` whatever the part, which is right from `ppt/slides/` and names nothing from
1393
- * `ppt/slideLayouts/` or `ppt/slideMasters/` — so a `hyperlink: { slide }` on an object given to
1515
+ * `ppt/slideLayouts/` or `ppt/slideMasters/`, so a `hyperlink: { slide }` on an object given to
1394
1516
  * `defineSlideMaster({ objects })` wrote a dangling relationship.
1395
1517
  * @param {PresSlideInternal | SlideLayoutInternal | SlideMasterInternal} slide - slide, layout or master whose relations are being transformed
1396
1518
  * @param {{ target: string; type: string }[]} defaultRels - array of default relations
@@ -1405,7 +1527,7 @@ function slideObjectRelationsToXml(slide, defaultRels, selfPath) {
1405
1527
  * told from the first by the first already being there.
1406
1528
  *
1407
1529
  * Two things about the shape. It holds raw Targets rather than escaped ones, because this
1408
- * asks about the model and not about markup — the probe used to substring-scan the emitted
1530
+ * asks about the model and not about markup. The probe used to substring-scan the emitted
1409
1531
  * XML for ` Target="…"`, which forced the caller to escape by hand with the same escaper the
1410
1532
  * builder uses or the two drifted apart, and cost O(rels squared) in string scanning.
1411
1533
  *
@@ -1422,10 +1544,11 @@ function slideObjectRelationsToXml(slide, defaultRels, selfPath) {
1422
1544
  else rels.push(externalHyperlinkRel(rel.rId, rel.Target));
1423
1545
  }
1424
1546
  });
1425
- (slide._relsChart || []).forEach((rel) => {
1547
+ slide._relsChart.forEach((rel) => {
1426
1548
  rels.push(relationshipEl(rel.rId, rel.isChartEx ? CHARTEX_REL : CHART_REL, rel.Target));
1427
1549
  });
1428
- (slide._relsMedia || []).forEach((rel) => {
1550
+ slide._relsMedia.forEach((rel) => {
1551
+ if (rel.chartOwned) return;
1429
1552
  const relType = rel.type.toLowerCase();
1430
1553
  const seen = mediaTargets.has(rel.Target);
1431
1554
  mediaTargets.add(rel.Target);
@@ -1443,8 +1566,7 @@ function slideObjectRelationsToXml(slide, defaultRels, selfPath) {
1443
1566
  });
1444
1567
  return relationshipsPart(rels);
1445
1568
  }
1446
- //#endregion
1447
- //#region src/gen/slide/slide.ts
1569
+ // src/gen/slide/slide.ts
1448
1570
  /**
1449
1571
  * pptx-ts: slide part + slide/layout rels
1450
1572
  *
@@ -1462,7 +1584,7 @@ function slideObjectRelationsToXml(slide, defaultRels, selfPath) {
1462
1584
  function makeXmlSlide(slide, renderers, transitionSoundRId) {
1463
1585
  return XML_DECL + "\r\n" + el("p:sld", {
1464
1586
  ...PML_ROOT_NS,
1465
- show: slide?.hidden ? "0" : null
1587
+ show: slide.hidden ? "0" : null
1466
1588
  }, [
1467
1589
  raw(slideObjectToXml(slide, renderers)),
1468
1590
  raw(el("p:clrMapOvr", null, raw(voidEl("a:masterClrMapping")))),
@@ -1501,7 +1623,7 @@ function makeXmlSlideRel(slides, slideLayouts, slideNumber) {
1501
1623
  target: targetFromPptSubpart(notesSlidePath(slideNumber)),
1502
1624
  type: NOTES_SLIDE_REL
1503
1625
  }];
1504
- if ((slide._comments || []).length > 0) defaultRels.push({
1626
+ if (slide._comments.length > 0) defaultRels.push({
1505
1627
  target: targetFromPptSubpart(commentPath(slideNumber)),
1506
1628
  type: COMMENTS_REL
1507
1629
  });
@@ -1518,8 +1640,7 @@ function getLayoutIdxForSlide(slides, slideLayouts, slideNumber) {
1518
1640
  for (let i = 0; i < slideLayouts.length; i++) if (slideLayouts[i]?._name === slides[slideNumber - 1]?._slideLayout?._name) return i + 1;
1519
1641
  return 1;
1520
1642
  }
1521
- //#endregion
1522
- //#region src/gen/pres/theme.ts
1643
+ // src/gen/pres/theme.ts
1523
1644
  /**
1524
1645
  * pptx-ts: `ppt/theme/theme1.xml`
1525
1646
  *
@@ -1572,13 +1693,13 @@ function buildThemeClrScheme(scheme) {
1572
1693
  }
1573
1694
  /**
1574
1695
  * The per-script theme font fallback table (`a:fontScheme`'s CT_TextFont lists), in OOXML
1575
- * document order. Static Office defaults — no caller data, no escaping risk — unlike the
1696
+ * document order. Static Office defaults (no caller data, no escaping risk), unlike the
1576
1697
  * `<a:latin>`/`<a:ea>`/`<a:cs>` slots above.
1577
1698
  *
1578
1699
  * Forty-one of the forty-seven scripts take the same face in the major and minor lists, so the
1579
1700
  * shared table below is the whole thing and the two override maps hold the six-odd rows that
1580
1701
  * actually differ. Written out twice, ninety-four lines said less than these do, and one row
1581
- * mistyped in one copy produces a theme that opens fine and paints a script in the wrong face —
1702
+ * mistyped in one copy produces a theme that opens fine and paints a script in the wrong face:
1582
1703
  * a difference nobody reviewing a diff of two 47-row tables would see.
1583
1704
  */
1584
1705
  const THEME_FONT_LIST = [
@@ -1703,15 +1824,14 @@ function makeXmlTheme(pres) {
1703
1824
  raw(extLst)
1704
1825
  ]);
1705
1826
  }
1706
- //#endregion
1707
- //#region src/gen/extract-slides.ts
1827
+ // src/gen/extract-slides.ts
1708
1828
  /**
1709
1829
  * Embedded audio/video. addMedia (`gen/define/media.ts`) pushes three consecutive
1710
1830
  * _relsMedia entries per item off `mediaRid`: the ECMA audio/video rel
1711
1831
  * (rId=mediaRid), the MS-2007 `media` rel (mediaRid+1, sharing one Target),
1712
1832
  * and the preview image rel (mediaRid+2). The body references all three; we
1713
1833
  * surface the descriptor so appendSlides can reproduce the rel graph. Online
1714
- * media (external link) is excluded — it has a different rel shape and no part.
1834
+ * media (external link) is excluded: it has a different rel shape and no part.
1715
1835
  */
1716
1836
  function avMediaOf(slide, relByRid) {
1717
1837
  return slide._slideObjects.filter((obj) => obj._type === "media" && obj.mtype !== "online" && typeof obj.mediaRid === "number").map((obj) => {
@@ -1720,8 +1840,8 @@ function avMediaOf(slide, relByRid) {
1720
1840
  const mediaRel = relByRid.get(mediaRid);
1721
1841
  const previewRel = relByRid.get(previewRid(mediaRid));
1722
1842
  if (!mediaRel || !previewRel) return null;
1723
- const mediaBytes = decodeBase64ToBytes(typeof mediaRel.data === "string" ? mediaRel.data : "");
1724
- const previewBytes = decodeBase64ToBytes(typeof previewRel.data === "string" ? previewRel.data : "");
1843
+ const mediaBytes = decodeBase64ToBytes(mediaRel.data);
1844
+ const previewBytes = decodeBase64ToBytes(previewRel.data);
1725
1845
  if (!mediaBytes || !previewBytes) return null;
1726
1846
  const mediaExtn = relExtension(mediaRel, "mp4");
1727
1847
  const previewExtn = relExtension(previewRel, "png");
@@ -1756,9 +1876,8 @@ function relExtension(rel, fallback) {
1756
1876
  * excluded here rather than surfaced twice.
1757
1877
  */
1758
1878
  function imageMediaOf(slide, avPreviewRids) {
1759
- return slide._relsMedia.filter((rel) => rel.type.toLowerCase().includes("image") && !avPreviewRids.has(rel.rId)).map((rel) => {
1760
- const data = rel.data && typeof rel.data === "string" ? rel.data : "";
1761
- const bytes = decodeBase64ToBytes(data);
1879
+ return slide._relsMedia.filter((rel) => rel.type.toLowerCase().includes("image") && !avPreviewRids.has(rel.rId) && !rel.chartOwned).map((rel) => {
1880
+ const bytes = decodeBase64ToBytes(rel.data);
1762
1881
  const extn = relExtension(rel, "png");
1763
1882
  return bytes ? {
1764
1883
  rId: rel.rId,
@@ -1769,6 +1888,23 @@ function imageMediaOf(slide, avPreviewRids) {
1769
1888
  }).filter((m) => m !== null);
1770
1889
  }
1771
1890
  /**
1891
+ * A transition's start sound: the audio part behind `p:sndAc/p:stSnd/p:snd r:embed`, under the
1892
+ * `rId` {@link registerTransitionSounds} gave it. `undefined` when the slide has no start sound.
1893
+ */
1894
+ function transitionSoundOf(rId, relByRid) {
1895
+ const rel = rId === void 0 ? void 0 : relByRid.get(rId);
1896
+ if (!rel || rId === void 0) return void 0;
1897
+ const bytes = decodeBase64ToBytes(rel.data);
1898
+ if (!bytes) return void 0;
1899
+ const extn = relExtension(rel, "wav");
1900
+ return {
1901
+ rId,
1902
+ bytes,
1903
+ extn,
1904
+ contentType: avContentType(extn, "audio")
1905
+ };
1906
+ }
1907
+ /**
1772
1908
  * Online (external-link) video. addMedia type:'online' pushes three rels off
1773
1909
  * mediaRid: the ECMA video rel (mediaRid, External), the MS-2007 media rel
1774
1910
  * (mediaRid+1, External, sharing the link Target), and the poster image rel
@@ -1801,10 +1937,10 @@ function hyperlinksOf(slide) {
1801
1937
  * A Target that does not read as a slide number throws rather than passing `NaN` on to the
1802
1938
  * append path's rel-graph rebuild, where it surfaces as "links to source slide NaN" a whole
1803
1939
  * subsystem later. `addText` writes this Target itself, so the condition is a defect on this
1804
- * side rather than bad input — an {@link InternalError}, like the chart router's own.
1940
+ * side rather than bad input: an {@link InternalError}, like the chart router's own.
1805
1941
  */
1806
- function slideLinksOf(slide) {
1807
- return slide._rels.filter((rel) => isHyperlinkRel(rel) && rel.data === "slide").map((rel) => {
1942
+ function slideLinksOf(rels) {
1943
+ return rels.filter((rel) => isHyperlinkRel(rel) && rel.data === "slide").map((rel) => {
1808
1944
  const sourceSlideNumber = Number(rel.Target);
1809
1945
  if (!Number.isInteger(sourceSlideNumber) || sourceSlideNumber < 1) throw new InternalError("slide/link-target-not-a-number", `Internal slide link rId${rel.rId} targets "${String(rel.Target)}", which is not a slide number`);
1810
1946
  return {
@@ -1823,10 +1959,11 @@ function notesOf(slide) {
1823
1959
  const notes = buildNotesSlideRels(slide);
1824
1960
  return {
1825
1961
  xml: makeXmlNotesSlide(slide, notes),
1826
- hyperlinks: notes.rels.filter((rel) => typeof rel.Target === "string" && rel.Target).map((rel) => ({
1962
+ hyperlinks: notes.rels.filter((rel) => rel.data !== "slide" && typeof rel.Target === "string" && rel.Target).map((rel) => ({
1827
1963
  rId: rel.rId,
1828
1964
  target: rel.Target
1829
- }))
1965
+ })),
1966
+ slideLinks: slideLinksOf(notes.rels)
1830
1967
  };
1831
1968
  }
1832
1969
  /**
@@ -1839,6 +1976,7 @@ async function extractSlides(source, opts = {}) {
1839
1976
  const { presentation } = source;
1840
1977
  const deckSlides = presentation.slides;
1841
1978
  requireSlideLinksInDeck(deckSlides);
1979
+ const transitionSoundRIds = registerTransitionSounds(deckSlides);
1842
1980
  backfillPlaceholders(deckSlides);
1843
1981
  await encodeMediaForTargets(deckSlides, source.runtime, onMediaError);
1844
1982
  const restoreAuthoredFit = bakeMeasuredFit(deckSlides, source.fontMetrics);
@@ -1848,15 +1986,19 @@ async function extractSlides(source, opts = {}) {
1848
1986
  const relByRid = new Map(slide._relsMedia.map((rel) => [rel.rId, rel]));
1849
1987
  const avMedia = avMediaOf(slide, relByRid);
1850
1988
  const notes = notesOf(slide);
1989
+ const soundRId = transitionSoundRIds.get(slide);
1990
+ const transitionSound = transitionSoundOf(soundRId, relByRid);
1851
1991
  return {
1852
- xml: makeXmlSlide(slide, source.renderers),
1992
+ xml: makeXmlSlide(slide, source.renderers, soundRId),
1853
1993
  media: imageMediaOf(slide, new Set(avMedia.map((item) => item.previewRid))),
1854
1994
  hyperlinks: hyperlinksOf(slide),
1855
1995
  charts: source.extract.charts?.(slide) ?? [],
1856
- slideLinks: slideLinksOf(slide),
1996
+ slideLinks: slideLinksOf(slide._rels),
1857
1997
  avMedia,
1858
1998
  onlineMedia: onlineMediaOf(slide, relByRid),
1859
- ...notes ? { notes } : {}
1999
+ ...notes ? { notes } : {},
2000
+ ...transitionSound ? { transitionSound } : {},
2001
+ ...slide._comments.length ? { comments: slide._comments } : {}
1860
2002
  };
1861
2003
  });
1862
2004
  } finally {
@@ -1874,8 +2016,7 @@ async function extractSlides(source, opts = {}) {
1874
2016
  ...notesMaster ? { notesMaster } : {}
1875
2017
  };
1876
2018
  }
1877
- //#endregion
1878
- //#region src/gen/opc/app.ts
2019
+ // src/gen/opc/app.ts
1879
2020
  /**
1880
2021
  * pptx-ts: `docProps/app.xml`
1881
2022
  *
@@ -1957,8 +2098,7 @@ function makeXmlApp(slides, company, presLayout) {
1957
2098
  raw(el("AppVersion", null, "16.0000", PROP))
1958
2099
  ], { closePrefix: INDENT_1 });
1959
2100
  }
1960
- //#endregion
1961
- //#region src/gen/opc/content-types.ts
2101
+ // src/gen/opc/content-types.ts
1962
2102
  /**
1963
2103
  * pptx-ts: `[Content_Types].xml`
1964
2104
  *
@@ -1967,24 +2107,16 @@ function makeXmlApp(slides, company, presLayout) {
1967
2107
  * Override entries for every part the package skeleton writes.
1968
2108
  *
1969
2109
  * Entries that exist only because a construct family put a part in the package arrive as
1970
- * {@link ContentTypeContributions} — already resolved to data and grouped by where they land.
2110
+ * {@link ContentTypeContributions}, already resolved to data and grouped by where they land.
1971
2111
  * The order below is a property of the format, not of whoever assembled that list, so a deck
1972
2112
  * written by a program that links three families and one that links ten emit the same bytes.
1973
2113
  */
1974
2114
  /**
1975
2115
  * Some Override entries have always been emitted with a leading space. It is insignificant
1976
2116
  * whitespace, but it is in the bytes this library has shipped for years, so it is reproduced
1977
- * verbatim rather than normalized (see AGENTS.md "Byte identity": whitespace diffs are a STOP).
2117
+ * verbatim rather than normalized (see "Byte identity" in `docs/contributing/testing.md`: whitespace diffs fail the gate).
1978
2118
  */
1979
2119
  const LEADING_SPACE = { openPrefix: " " };
1980
- /** Nothing beyond the skeleton — the shape a deck written with no construct families contributes. */
1981
- const NO_CONTENT_TYPE_CONTRIBUTIONS = Object.freeze({
1982
- defaults: [],
1983
- presentation: [],
1984
- perSlide: [],
1985
- perLayout: [],
1986
- trailing: []
1987
- });
1988
2120
  function contentDefault(extension, contentType) {
1989
2121
  return voidEl("Default", {
1990
2122
  Extension: extension,
@@ -2007,16 +2139,15 @@ function contributedOverride(entry) {
2007
2139
  * @returns XML
2008
2140
  */
2009
2141
  function makeXmlContTypes(opts) {
2010
- const { slides, slideLayouts, masterSlide, hasCustomProps, embeddedFonts } = opts;
2011
- const contributions = opts.contributions ?? NO_CONTENT_TYPE_CONTRIBUTIONS;
2142
+ const { slides, slideLayouts, masterSlide, hasCustomProps, embeddedFonts, contributions } = opts;
2012
2143
  const parts = [contentDefault("xml", "application/xml"), contentDefault("rels", RELATIONSHIPS_CONTENT_TYPE)];
2013
2144
  const extnTypeMap = /* @__PURE__ */ new Map();
2014
2145
  const ctTargets = [];
2015
- (slides || []).forEach((s) => ctTargets.push(s));
2016
- (slideLayouts || []).forEach((l) => ctTargets.push(l));
2017
- if (masterSlide) ctTargets.push(masterSlide);
2146
+ slides.forEach((s) => ctTargets.push(s));
2147
+ slideLayouts.forEach((l) => ctTargets.push(l));
2148
+ ctTargets.push(masterSlide);
2018
2149
  ctTargets.forEach((target) => {
2019
- (target._relsMedia || []).forEach((rel) => {
2150
+ target._relsMedia.forEach((rel) => {
2020
2151
  if (rel.type === "online" || !rel.extn || !rel.type) return;
2021
2152
  const contentType = rel.type.startsWith("audio/") ? avContentType(rel.extn, "audio") : rel.type.startsWith("video/") ? avContentType(rel.extn, "video") : rel.type;
2022
2153
  if (!extnTypeMap.has(rel.extn)) extnTypeMap.set(rel.extn, contentType);
@@ -2030,7 +2161,7 @@ function makeXmlContTypes(opts) {
2030
2161
  extnTypeMap.set(entry.extension, entry.contentType);
2031
2162
  parts.push(contentDefault(entry.extension, entry.contentType));
2032
2163
  });
2033
- if ((embeddedFonts || []).some((font) => font.faces.some((face) => face.bytes))) parts.push(contentDefault(FONT_DATA_EXTENSION, FONT_DATA_CONTENT_TYPE));
2164
+ if (embeddedFonts.some((font) => font.faces.some((face) => face.bytes))) parts.push(contentDefault(FONT_DATA_EXTENSION, FONT_DATA_CONTENT_TYPE));
2034
2165
  parts.push(override(overrideName(PRESENTATION_PATH), PRESENTATION_MAIN_CONTENT_TYPE));
2035
2166
  contributions.presentation.forEach((entry) => parts.push(contributedOverride(entry)));
2036
2167
  parts.push(override(overrideName(SLIDE_MASTER_PATH), SLIDE_MASTER_CONTENT_TYPE));
@@ -2053,8 +2184,7 @@ function makeXmlContTypes(opts) {
2053
2184
  if (hasCustomProps) parts.push(override("/docProps/custom.xml", CUSTOM_PROPS_CONTENT_TYPE, LEADING_SPACE));
2054
2185
  return XML_DECL + "\r\n" + el("Types", { xmlns: OOXML_NS.ct }, parts.map(raw));
2055
2186
  }
2056
- //#endregion
2057
- //#region src/gen/opc/custom-props.ts
2187
+ // src/gen/opc/custom-props.ts
2058
2188
  /**
2059
2189
  * pptx-ts: `docProps/custom.xml`
2060
2190
  *
@@ -2086,8 +2216,7 @@ function makeXmlCustomProperties(props) {
2086
2216
  }, raw(valueEl(value)))));
2087
2217
  return XML_DECL + "\r\n" + el("Properties", PROPS_NS, properties);
2088
2218
  }
2089
- //#endregion
2090
- //#region src/gen/opc/root-rels.ts
2219
+ // src/gen/opc/root-rels.ts
2091
2220
  /**
2092
2221
  * pptx-ts: `_rels/.rels`
2093
2222
  *
@@ -2109,8 +2238,7 @@ function makeXmlRootRels(hasCustomProps) {
2109
2238
  if (hasCustomProps) rels.push(relationshipEl("rId4", CUSTOM_PROPS_REL, "docProps/custom.xml", INDENTED));
2110
2239
  return relationshipsPart(rels, { closePrefix: "\n " });
2111
2240
  }
2112
- //#endregion
2113
- //#region src/gen/pres/presentation-rels.ts
2241
+ // src/gen/pres/presentation-rels.ts
2114
2242
  /**
2115
2243
  * Creates `ppt/_rels/presentation.xml.rels`
2116
2244
  * @param {PresSlideInternal[]} slides - Presenation Slides
@@ -2124,16 +2252,16 @@ function makeXmlRootRels(hasCustomProps) {
2124
2252
  * theme1/tableStyles, then commentAuthors when the deck has any comment, then the embedded
2125
2253
  * fonts.
2126
2254
  *
2127
- * The rels writer and `makeXmlPresentation` both need these numbers — the presentation part
2128
- * names the notesMaster and each embedded face by `r:id` — and each derived them separately,
2255
+ * The rels writer and `makeXmlPresentation` both need these numbers (the presentation part
2256
+ * names the notesMaster and each embedded face by `r:id`), and each derived them separately,
2129
2257
  * one as `slides.length + 2` under a comment saying it copied the other's logic. Inserting a
2130
2258
  * relationship before `notesMaster` then broke the presentation's own reference with no
2131
2259
  * signal.
2132
2260
  * @param slides - the deck's slides, whose count and comments decide the layout
2133
2261
  */
2134
2262
  function presentationFixedRelIds(slides) {
2135
- const first = (slides?.length ?? 0) + 2;
2136
- const hasComments = (slides || []).some((slide) => (slide._comments || []).length > 0);
2263
+ const first = slides.length + 2;
2264
+ const hasComments = slides.some((slide) => slide._comments.length > 0);
2137
2265
  return {
2138
2266
  notesMaster: first,
2139
2267
  presProps: first + 1,
@@ -2145,7 +2273,7 @@ function presentationFixedRelIds(slides) {
2145
2273
  };
2146
2274
  }
2147
2275
  /**
2148
- * The first relationship id free for embedded-font rels — {@link presentationFixedRelIds}'
2276
+ * The first relationship id free for embedded-font rels: {@link presentationFixedRelIds}'
2149
2277
  * `fontStart`, kept as its own name because that is what the two font walks ask for.
2150
2278
  */
2151
2279
  function presentationFontRelStart(slides) {
@@ -2157,11 +2285,10 @@ function makeXmlPresentationRels(slides, embeddedFonts) {
2157
2285
  for (let idx = 1; idx <= slides.length; idx++) rels.push(relationshipEl(idx + 1, SLIDE_REL, targetFromPresentation(slidePath(idx))));
2158
2286
  rels.push(relationshipEl(fixed.notesMaster, NOTES_MASTER_REL, targetFromPresentation(NOTES_MASTER_PATH)), relationshipEl(fixed.presProps, PRES_PROPS_REL, "presProps.xml"), relationshipEl(fixed.viewProps, VIEW_PROPS_REL, "viewProps.xml"), relationshipEl(fixed.theme, THEME_REL, "theme/theme1.xml"), relationshipEl(fixed.tableStyles, TABLE_STYLES_REL, "tableStyles.xml"));
2159
2287
  if (fixed.commentAuthors !== null) rels.push(relationshipEl(fixed.commentAuthors, COMMENT_AUTHORS_REL, "commentAuthors.xml"));
2160
- for (const face of flattenEmbeddedFaces(embeddedFonts || [], presentationFontRelStart(slides))) rels.push(relationshipEl(face.rId, FONT_REL_TYPE, targetFromPresentation(fontPath(face.partIndex))));
2288
+ for (const face of flattenEmbeddedFaces(embeddedFonts, presentationFontRelStart(slides))) rels.push(relationshipEl(face.rId, FONT_REL_TYPE, targetFromPresentation(fontPath(face.partIndex))));
2161
2289
  return relationshipsPart(rels);
2162
2290
  }
2163
- //#endregion
2164
- //#region src/gen/pres/presentation.ts
2291
+ // src/gen/pres/presentation.ts
2165
2292
  /**
2166
2293
  * pptx-ts: `ppt/presentation.xml` + presProps/viewProps
2167
2294
  *
@@ -2191,7 +2318,7 @@ function sectionsExtLst(sections) {
2191
2318
  * @return {string} XML
2192
2319
  */
2193
2320
  function makeXmlPresentation(pres) {
2194
- const openTag = `<p:presentation xmlns:a="${OOXML_NS.a}" xmlns:r="${OOXML_NS.r}" xmlns:p="${OOXML_NS.p}" ${pres.rtlMode ? "rtl=\"1\"" : ""} ${(pres.embeddedFonts || []).some((font) => font.faces.some((face) => face.bytes)) ? "embedTrueTypeFonts=\"1\" saveSubsetFonts=\"0\"" : "saveSubsetFonts=\"1\""} autoCompressPictures="0"${pres.firstSlideNum !== 1 ? ` firstSlideNum="${pres.firstSlideNum}"` : ""}>`;
2321
+ const openTag = `<p:presentation xmlns:a="${OOXML_NS.a}" xmlns:r="${OOXML_NS.r}" xmlns:p="${OOXML_NS.p}" ${pres.rtlMode ? "rtl=\"1\"" : ""} ${pres.embeddedFonts.some((font) => font.faces.some((face) => face.bytes)) ? "embedTrueTypeFonts=\"1\" saveSubsetFonts=\"0\"" : "saveSubsetFonts=\"1\""} autoCompressPictures="0"${pres.firstSlideNum !== 1 ? ` firstSlideNum="${pres.firstSlideNum}"` : ""}>`;
2195
2322
  const sldMasterIdLst = el("p:sldMasterIdLst", null, raw(voidEl("p:sldMasterId", {
2196
2323
  id: MIN_SLIDE_MASTER_ID,
2197
2324
  "r:id": "rId1"
@@ -2211,12 +2338,12 @@ function makeXmlPresentation(pres) {
2211
2338
  cx: pres.presLayout.height,
2212
2339
  cy: pres.presLayout.width
2213
2340
  });
2214
- const fonts = pres.embeddedFonts || [];
2341
+ const fonts = pres.embeddedFonts;
2215
2342
  const flat = flattenEmbeddedFaces(fonts, presentationFontRelStart(pres.slides));
2216
2343
  const rIdOf = new Map(flat.map((face) => [`${face.fontIndex}:${face.slot}`, face.rId]));
2217
2344
  const embeddedFontLst = serializeEmbeddedFontLst(fonts, (fontIndex, slot) => rIdOf.get(`${fontIndex}:${slot}`));
2218
2345
  const defaultTextStyle = el("p:defaultTextStyle", null, LEVEL_MARGINS_EMU.map((marL, i) => raw(defaultTextStyleLevel(i + 1, marL))));
2219
- const extLst = pres.sections && pres.sections.length > 0 ? sectionsExtLst(pres.sections) : "";
2346
+ const extLst = pres.sections.length > 0 ? sectionsExtLst(pres.sections) : "";
2220
2347
  return XML_DECL + "\r\n" + openTag + sldMasterIdLst + notesMasterIdLst + sldIdLst + sldSz + notesSz + embeddedFontLst + defaultTextStyle + extLst + "</p:presentation>";
2221
2348
  }
2222
2349
  /**
@@ -2262,21 +2389,7 @@ function makeXmlViewProps() {
2262
2389
  }))
2263
2390
  ]);
2264
2391
  }
2265
- //#endregion
2266
- //#region src/gen/pres/table-styles.ts
2267
- /**
2268
- * Create `ppt/tableStyles.xml`
2269
- * @see: http://openxmldeveloper.org/discussions/formats/f/13/p/2398/8107.aspx
2270
- * @return {string} XML
2271
- */
2272
- function makeXmlTableStyles() {
2273
- return XML_DECL + "\r\n" + voidEl("a:tblStyleLst", {
2274
- "xmlns:a": OOXML_NS.a,
2275
- def: "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"
2276
- });
2277
- }
2278
- //#endregion
2279
- //#region src/gen/slide/layout.ts
2392
+ // src/gen/slide/layout.ts
2280
2393
  /**
2281
2394
  * pptx-ts: slide-layout part
2282
2395
  *
@@ -2297,8 +2410,7 @@ function makeXmlLayout(layout, renderers) {
2297
2410
  childPrefix: "\n "
2298
2411
  });
2299
2412
  }
2300
- //#endregion
2301
- //#region src/gen/slide/master.ts
2413
+ // src/gen/slide/master.ts
2302
2414
  /**
2303
2415
  * pptx-ts: slide-master parts
2304
2416
  *
@@ -2436,6 +2548,7 @@ function masterAlignAttr(align) {
2436
2548
  /** Build the bullet element for a master level: caller override wins over the level default. */
2437
2549
  function masterBulletXml(bulletOverride, base) {
2438
2550
  if (bulletOverride === false) return voidEl("a:buNone");
2551
+ if (bulletOverride === true && (base === "none" || base === void 0)) return masterBulletXml({}, base);
2439
2552
  if (bulletOverride && typeof bulletOverride === "object") {
2440
2553
  const font = bulletOverride.fontFace ? voidEl("a:buFont", { typeface: bulletOverride.fontFace }) : "";
2441
2554
  if (bulletOverride.type === "number") {
@@ -2534,7 +2647,7 @@ function makeXmlMasterTxStyles(textStyles) {
2534
2647
  * The built-in Office master's `<p:txStyles>`, used verbatim when `defineSlideMaster({ textStyles })`
2535
2648
  * was never called. Deliberately NOT built via `masterLevelXml`: a configured title level always
2536
2649
  * carries `marL="0"` (from `MASTER_TITLE_DEFAULT.marL`), but the true unconfigured default titleStyle
2537
- * has no `marL`/`indent` attribute at all — a pre-existing asymmetry between the two paths, preserved
2650
+ * has no `marL`/`indent` attribute at all: a pre-existing asymmetry between the two paths, preserved
2538
2651
  * exactly rather than unified.
2539
2652
  */
2540
2653
  function makeXmlMasterDefaultTxStyles() {
@@ -2624,8 +2737,7 @@ function makeXmlMasterRel(masterSlide, slideLayouts) {
2624
2737
  });
2625
2738
  return slideObjectRelationsToXml(masterSlide, defaultRels, SLIDE_MASTER_PATH);
2626
2739
  }
2627
- //#endregion
2628
- //#region src/package/parts/shared.ts
2740
+ // src/package/parts/shared.ts
2629
2741
  /**
2630
2742
  * The contributors in emission order. Sorting here rather than trusting the caller's array is the
2631
2743
  * whole point of {@link PartContributor.order}; the sort is stable, so two families that share a
@@ -2636,7 +2748,7 @@ function orderedContributors(contributors) {
2636
2748
  }
2637
2749
  /**
2638
2750
  * Ask every contributor for its content-type entries and flatten them into the slot-keyed data
2639
- * `makeXmlContTypes` emits. Takes the contributors already ordered — within a slot the entries
2751
+ * `makeXmlContTypes` emits. Takes the contributors already ordered; within a slot the entries
2640
2752
  * come out in the order they are collected here.
2641
2753
  */
2642
2754
  function collectContentTypes(contributors, pres) {
@@ -2668,15 +2780,14 @@ function collectContentTypes(contributors, pres) {
2668
2780
  trailing
2669
2781
  };
2670
2782
  }
2671
- //#endregion
2672
- //#region src/package/assemble.ts
2783
+ // src/package/assemble.ts
2673
2784
  /**
2674
2785
  * Package assembly: turn an authored presentation's internal state into the full set of
2675
2786
  * OOXML package parts and hand the bytes to the ZIP writer. This is the write-side
2676
- * "packaging" layer — `[Content_Types].xml`, the `_rels` graph, docProps, theme, the
2677
- * per-slide/layout/master parts, and media rels — split out of the authoring class
2678
- * (`TsPptx`) so that class stays a façade over slide authoring. The parts a construct
2679
- * family adds on top of that skeleton — charts, comments, notes — come from the part
2787
+ * "packaging" layer (`[Content_Types].xml`, the `_rels` graph, docProps, theme, the
2788
+ * per-slide/layout/master parts, and media rels), split out of the authoring class
2789
+ * (`PptxTs`) so that class stays a façade over slide authoring. The parts a construct
2790
+ * family adds on top of that skeleton (charts, comments, notes) come from the part
2680
2791
  * contributors it is handed, so nothing here names a family.
2681
2792
  *
2682
2793
  * The entry point `writePackage` takes a structural {@link PackageSource} that the
@@ -2717,7 +2828,7 @@ const ALREADY_COMPRESSED_MEDIA_EXTN = /* @__PURE__ */ new Set([
2717
2828
  "oga"
2718
2829
  ]);
2719
2830
  /**
2720
- * Extensions whose payload is itself a ZIP archive — the embedded OPC packages an OLE object can
2831
+ * Extensions whose payload is itself a ZIP archive: the embedded OPC packages an OLE object can
2721
2832
  * carry (`addOleObject`). Deflating a zip inside a zip buys nothing, so these are STOREd like the
2722
2833
  * already-compressed media above. No media/image rel ever uses one of these extensions, so decks
2723
2834
  * without an OLE object are unaffected.
@@ -2731,61 +2842,6 @@ const ZIP_CONTAINER_EXTN = /* @__PURE__ */ new Set([
2731
2842
  "pptm"
2732
2843
  ]);
2733
2844
  /**
2734
- * Each slide's registered transition sound.
2735
- *
2736
- * Kept per slide, never on the transition: one transition object can be assigned to several slides,
2737
- * and a relationship id means something only inside the slide part that declares it. Kept across
2738
- * writes as well, so a deck written twice registers each sound once. An entry is reused only while
2739
- * the slide still holds its relationship and still has the same sound assigned.
2740
- */
2741
- const registeredTransitionSounds = /* @__PURE__ */ new WeakMap();
2742
- /**
2743
- * Register an audio media part + relationship for each slide-transition start sound
2744
- * (`transition.sound` with `data`/`path`), and return the relationship id each slide's
2745
- * `p:sndAc/p:snd r:embed` refers to. Runs before media encoding so the bytes are loaded. Re-export
2746
- * is safe: a slide whose sound is already registered reuses that relationship. The stop-previous
2747
- * form (`sound.stopPrevious`) needs no part and is skipped.
2748
- *
2749
- * Registered here, at write time, rather than when `slide.transition` is assigned. A slide's rel
2750
- * ids and media part names are handed out in registration order, and a transition is often set
2751
- * before the slide's pictures and media are added; registering the sound then would move every
2752
- * later rel id and part name on the slide.
2753
- */
2754
- function registerTransitionSounds(slides) {
2755
- const soundRIds = /* @__PURE__ */ new Map();
2756
- slides.forEach((slide) => {
2757
- const transition = slide.transition;
2758
- if (!transition || !TRANSITION_TYPES.includes(transition.type)) return;
2759
- const sound = transition.sound;
2760
- if (!sound || sound.stopPrevious) return;
2761
- if (!sound.data && !sound.path) return;
2762
- const registered = registeredTransitionSounds.get(slide);
2763
- if (registered && slide._relsMedia.includes(registered.rel) && registered.data === sound.data && registered.path === sound.path) {
2764
- soundRIds.set(slide, registered.rel.rId);
2765
- return;
2766
- }
2767
- const dataMime = dataUriMediaType(sound.data ?? "");
2768
- const pathFile = sound.path ? (sound.path.split("/").pop() ?? "").split("?")[0] ?? "" : "";
2769
- const extn = dataMime?.startsWith("audio/") ? audioExtensionForSubtype(dataMime.slice(6)) : (pathFile.split(".").pop() ?? "wav").toLowerCase();
2770
- const rId = getNewRelId(slide);
2771
- const rel = pushMediaRel(slide, {
2772
- kind: "audio",
2773
- extn,
2774
- type: `audio/${extn}`,
2775
- path: sound.path,
2776
- data: sound.data,
2777
- rId
2778
- });
2779
- registeredTransitionSounds.set(slide, {
2780
- rel,
2781
- data: sound.data,
2782
- path: sound.path
2783
- });
2784
- soundRIds.set(slide, rId);
2785
- });
2786
- return soundRIds;
2787
- }
2788
- /**
2789
2845
  * Write the media parts one target's rels point at. Images are how every deck carries a picture,
2790
2846
  * so this stays on the core path; the chart half of what used to be one function is a part
2791
2847
  * contributor (`parts/chart.ts`) and runs just before it, per target, so part order is unchanged.
@@ -2804,8 +2860,7 @@ function createMediaParts(slide, zip, written) {
2804
2860
  if (rel.type !== "online" && rel.type !== "hyperlink") {
2805
2861
  const path = rel.Target.replace("..", "ppt");
2806
2862
  if (written.has(path)) return;
2807
- const data = rel.data && typeof rel.data === "string" ? rel.data : "";
2808
- const bytes = decodeBase64ToBytes(data);
2863
+ const bytes = decodeBase64ToBytes(rel.data);
2809
2864
  if (!bytes) return;
2810
2865
  const extn = (rel.extn || rel.Target.split(".").pop() || "").toLowerCase();
2811
2866
  zip.add(path, bytes, { store: ALREADY_COMPRESSED_MEDIA_EXTN.has(extn) || ZIP_CONTAINER_EXTN.has(extn) });
@@ -2819,7 +2874,7 @@ function createMediaParts(slide, zip, written) {
2819
2874
  * media de-dup, chart-part-id assignment, and measured-fit passes before the synchronous
2820
2875
  * XML pass reads slide state. The bytes are the same the ZIP writer would compress; splitting the
2821
2876
  * assembly from the zip lets the byte-identity harness (and a future parts API) read parts
2822
- * directly. Only `onMediaError` is meaningful here — compression/output shape are zip concerns
2877
+ * directly. Only `onMediaError` is meaningful here; compression/output shape are zip concerns
2823
2878
  * handled by {@link zipPackageParts}.
2824
2879
  */
2825
2880
  async function buildPackageParts(source, props) {
@@ -2838,16 +2893,16 @@ async function buildPackageParts(source, props) {
2838
2893
  ];
2839
2894
  return await encodeMediaForTargets(mediaTargets, source.runtime, onMediaError).then(async () => {
2840
2895
  const canonicalMediaTargets = /* @__PURE__ */ new Map();
2841
- for (const target of mediaTargets) for (const rel of target._relsMedia || []) {
2842
- if (rel.type === "online" || rel.type === "hyperlink" || typeof rel.data !== "string" || !rel.data) continue;
2896
+ for (const target of mediaTargets) for (const rel of target._relsMedia) {
2897
+ if (rel.type === "online" || rel.type === "hyperlink" || !rel.data) continue;
2843
2898
  if (rel.oleRelType) continue;
2844
- const key = (rel.extn || "") + "\0" + rel.data;
2899
+ const key = rel.extn + "\0" + rel.data;
2845
2900
  const canonical = canonicalMediaTargets.get(key);
2846
2901
  if (canonical) rel.Target = canonical;
2847
2902
  else canonicalMediaTargets.set(key, rel.Target);
2848
2903
  }
2849
2904
  let chartPartIdx = 0;
2850
- for (const target of mediaTargets) for (const rel of target._relsChart || []) {
2905
+ for (const target of mediaTargets) for (const rel of target._relsChart) {
2851
2906
  const chartId = ++chartPartIdx;
2852
2907
  rel.globalId = chartId;
2853
2908
  const { fileName, target } = chartPartNames(chartId, rel.isChartEx);
@@ -2876,7 +2931,7 @@ async function buildPackageParts(source, props) {
2876
2931
  zip.add("ppt/theme/theme2.xml", themeXml);
2877
2932
  zip.add(PRESENTATION_PATH, makeXmlPresentation(pres));
2878
2933
  zip.add("ppt/presProps.xml", makeXmlPresProps());
2879
- zip.add("ppt/tableStyles.xml", makeXmlTableStyles());
2934
+ zip.add("ppt/tableStyles.xml", makeXmlTableStyles(contributors.flatMap((contributor) => contributor.parts?.tableStyles?.(pres) ?? [])));
2880
2935
  zip.add("ppt/viewProps.xml", makeXmlViewProps());
2881
2936
  pres.slideLayouts.forEach((layout, idx) => {
2882
2937
  zip.add(slideLayoutPath(idx + 1), makeXmlLayout(layout, source.renderers));
@@ -2909,7 +2964,7 @@ async function buildPackageParts(source, props) {
2909
2964
  }
2910
2965
  /**
2911
2966
  * Zip an ordered list of package parts into the output shape `props.outputType` selects. Re-adds
2912
- * each part to a fresh {@link ZipWriter} in order — preserving each part's `store` hint — so the
2967
+ * each part to a fresh {@link ZipWriter} in order (preserving each part's `store` hint), so the
2913
2968
  * archive is byte-identical to assembling straight into one writer. Compression and output type
2914
2969
  * are the only zip-level knobs; part assembly happened in {@link buildPackageParts}.
2915
2970
  */
@@ -2928,8 +2983,7 @@ async function zipPackageParts(parts, props) {
2928
2983
  async function writePackage(source, props) {
2929
2984
  return await zipPackageParts(await buildPackageParts(source, props), props);
2930
2985
  }
2931
- //#endregion
2932
- //#region src/presentation.ts
2986
+ // src/presentation.ts
2933
2987
  /**
2934
2988
  * pptx-ts: the presentation core
2935
2989
  *
@@ -2937,14 +2991,14 @@ async function writePackage(source, props) {
2937
2991
  * adapter (`index.ts`, `node.ts`, `browser.ts`). See the class doc below for the layout of
2938
2992
  * its body and where package assembly actually happens.
2939
2993
  *
2940
- * Units: this library takes user coordinates in inches and converts to EMU on output — see
2994
+ * Units: this library takes user coordinates in inches and converts to EMU on output. See
2941
2995
  * `units.ts` for the conversions and `STANDARD_LAYOUTS` for the built-in slide sizes.
2942
2996
  *
2943
2997
  * Derived from PptxGenJS (C) 2015-present Brent Ely (MIT), which in turn took some code from
2944
2998
  * the OfficeGen project (Copyright 2013 Ziv Barber). This project is likewise MIT; the full
2945
2999
  * license text is in `LICENSE` at the repository root.
2946
3000
  */
2947
- const VERSION = "4.1.0";
3001
+ const VERSION = "5.0.0";
2948
3002
  function standardLayoutToPresLayout(layout) {
2949
3003
  return {
2950
3004
  name: layout.name,
@@ -2973,8 +3027,8 @@ function layoutSideInches(value, side) {
2973
3027
  return clampRangedInput(Number(value), 1, 56, "layout/size-out-of-range", `defineLayout ${side} (inches)`, "coord/non-finite");
2974
3028
  }
2975
3029
  /**
2976
- * Main presentation class and package export flow — the public entry point consumers
2977
- * instantiate (`new TsPptx()`). Owns presentation-level state and metadata, collects
3030
+ * Main presentation class and package export flow: the public entry point consumers
3031
+ * instantiate (`new PptxTs()`). Owns presentation-level state and metadata, collects
2978
3032
  * slides, and drives `write`/`writeFile`/`stream`. The actual OOXML string building is
2979
3033
  * delegated to the `gen-*` modules; runtime file/stream output goes through the injected
2980
3034
  * `RuntimeAdapter`. Enums (`AlignH`, `ChartType`, `ShapeType`, …) are imported from the
@@ -2983,12 +3037,12 @@ function layoutSideInches(value, side) {
2983
3037
  * Rough layout of the class body:
2984
3038
  * - Metadata accessors layout / author / company / title / theme / sections getters+setters
2985
3039
  * - Private slide helpers addNewSlide, getSlide, setSlideNumber
2986
- * - Public export methods stream / write / writeFile — delegate packaging to `writePackage`
3040
+ * - Public export methods stream / write / writeFile; delegate packaging to `writePackage`
2987
3041
  * - Public authoring methods addSlide / defineLayout / defineSlideMaster / defineTableStyle
2988
3042
  *
2989
3043
  * Package assembly (`[Content_Types].xml`, the rels graph, per-part XML, the ZIP) lives in
2990
3044
  * `package/assemble.ts`; this class provides the deck state via {@link PresentationCore.packageSource}.
2991
- * The live-DOM `tableToSlides()` is NOT here — it is added by the browser entry subclass
3045
+ * The live-DOM `tableToSlides()` is NOT here; it is added by the browser entry subclass
2992
3046
  * (`browser.ts`) so it stays out of the Node build and out of the core chunk.
2993
3047
  */
2994
3048
  var PresentationCore = class {
@@ -3124,7 +3178,7 @@ var PresentationCore = class {
3124
3178
  /**
3125
3179
  * slide layout definition objects, used for generating slide layout files.
3126
3180
  * `protected` (not `private`) so the browser entry subclass can resolve
3127
- * `tableToSlides({ masterTitle })` against them — that method lives on the
3181
+ * `tableToSlides({ masterTitle })` against them. That method lives on the
3128
3182
  * browser build only (it reads a live DOM), see `browser.ts`.
3129
3183
  */
3130
3184
  _slideLayouts;
@@ -3153,7 +3207,7 @@ var PresentationCore = class {
3153
3207
  LAYOUTS;
3154
3208
  /**
3155
3209
  * The built-in default layout, or a throw. `LAYOUTS` is a string-keyed map, so the lookup is
3156
- * typed as possibly-missing at every call site even though the constructor registers it — and
3210
+ * typed as possibly-missing at every call site even though the constructor registers it, and
3157
3211
  * the two callers that need it were spelling the same guard and the same message.
3158
3212
  */
3159
3213
  #requireDefaultLayout() {
@@ -3281,14 +3335,14 @@ var PresentationCore = class {
3281
3335
  * Author + serialize this presentation's slides as injectable descriptors,
3282
3336
  * WITHOUT producing a `.pptx` package. Runs the same media-encode, placeholder
3283
3337
  * backfill, and measured-fit passes `write()` uses, then serializes each slide
3284
- * body and resolves its image media to decoded bytes — so a loaded deck can
3338
+ * body and resolves its image media to decoded bytes, so a loaded deck can
3285
3339
  * splice the slides in via `Presentation.appendSlides()` (see `pptx-ts/read`)
3286
3340
  * while keeping its own masters/layouts/theme byte-identical.
3287
3341
  *
3288
3342
  * Returns the deck's slide size (EMU, for the destination size check) and one
3289
3343
  * descriptor per authored slide. Charts, audio/video media, online media, and
3290
3344
  * internal slide-to-slide hyperlinks are surfaced as descriptors alongside the
3291
- * serialized body — this method does not resolve them into a package; the append
3345
+ * serialized body. This method does not resolve them into a package; the append
3292
3346
  * path consumes each descriptor to reserve the parts and rebuild the rel graph.
3293
3347
  */
3294
3348
  extractSlides = async (opts = {}) => extractSlides({
@@ -3391,11 +3445,11 @@ var PresentationCore = class {
3391
3445
  }
3392
3446
  /**
3393
3447
  * Measure how tall text wraps at a given width, using the **same** calibrated wrap
3394
- * model the export-time autofit bake uses — so a layout-time prediction matches the
3448
+ * model the export-time autofit bake uses, so a layout-time prediction matches the
3395
3449
  * value `fit:'shrink'`/`'resize'` would bake. Synchronous: register the face's metrics
3396
- * first with {@link TsPptx.registerFontMetrics} (lookup is sync).
3450
+ * first with {@link PptxTs.registerFontMetrics} (lookup is sync).
3397
3451
  *
3398
- * Lets a consumer size its own geometry before export — grow a card to fit its text,
3452
+ * Lets a consumer size its own geometry before export: grow a card to fit its text,
3399
3453
  * reflow a grid, or detect overflow at layout time. Heights err **tall** (conservative),
3400
3454
  * so the returned height is ≥ what PowerPoint/LibreOffice render.
3401
3455
  * @param {string | TextProps[]} text - a string or run array (per-run options override the defaults in `opts`)
@@ -3410,7 +3464,7 @@ var PresentationCore = class {
3410
3464
  /**
3411
3465
  * Convenience overflow check: `true` if `text` does not fit a box of inner size
3412
3466
  * `wIn`×`hIn` (inches) at full size. Because the model errs tall, this is a
3413
- * **conservative** (slightly over-reporting) check — appropriate for a build-time
3467
+ * **conservative** (slightly over-reporting) check, appropriate for a build-time
3414
3468
  * warning, not a hard gate. An unmeasurable (unnamed theme-default) face reports
3415
3469
  * `false` (no overflow) so the linter does not false-positive on faces it cannot measure.
3416
3470
  * @param {string | TextProps[]} text - a string or run array
@@ -3422,13 +3476,13 @@ var PresentationCore = class {
3422
3476
  }
3423
3477
  /**
3424
3478
  * Compute the per-cell geometry of a table laid out at `opts.x`/`y`/`w`, without
3425
- * adding it to a slide — so a consumer can place images or shapes precisely over
3479
+ * adding it to a slide, so a consumer can place images or shapes precisely over
3426
3480
  * cells. Column widths (cell `x`/`w`) are exact, derived from the same logic the
3427
3481
  * writer uses. Row heights (`y`/`h`) are exact when pinned by `rowH` (array or
3428
3482
  * scalar) or table `h`; an auto-height row is estimated with the same conservative
3429
- * (tall) text model as {@link TsPptx.measureText} and flagged `heightExact:false`
3430
- * (register the cell font via {@link TsPptx.registerFontMetrics} for an exact
3431
- * estimate). Geometry is for a single, un-paginated table — `autoPage` paging is
3483
+ * (tall) text model as {@link PptxTs.measureText} and flagged `heightExact:false`
3484
+ * (register the cell font via {@link PptxTs.registerFontMetrics} for an exact
3485
+ * estimate). Geometry is for a single, un-paginated table; `autoPage` paging is
3432
3486
  * not modeled.
3433
3487
  * @param {TableRow[]} rows - the same `rows` passed to `slide.addTable`
3434
3488
  * @param {TableProps} opts - the same table options (`x`, `y`, `w`, `colW`, `rowH`, `h`, …)
@@ -3470,7 +3524,7 @@ var PresentationCore = class {
3470
3524
  ]));
3471
3525
  }
3472
3526
  /**
3473
- * Assemble the current Presentation into its OOXML package parts WITHOUT zipping — the raw
3527
+ * Assemble the current Presentation into its OOXML package parts WITHOUT zipping: the raw
3474
3528
  * `path → bytes` contents `write()` would compress into the `.pptx`. Use this to stream parts
3475
3529
  * into a custom container, inspect individual parts, or feed a pipeline that does its own
3476
3530
  * archiving. To produce a real `.pptx` file, use {@link write} / {@link writeFile} instead.
@@ -3649,8 +3703,7 @@ var PresentationCore = class {
3649
3703
  if (newLayout._slideNumberProps && !this._masterSlide._slideNumberProps) this._masterSlide._slideNumberProps = newLayout._slideNumberProps;
3650
3704
  }
3651
3705
  };
3652
- //#endregion
3653
- //#region src/families/core.ts
3706
+ // src/families/core.ts
3654
3707
  /**
3655
3708
  * pptx-ts: the construct families every presentation carries
3656
3709
  *
@@ -3671,8 +3724,7 @@ const CORE_CONSTRUCT_FAMILIES = [
3671
3724
  groupFamily,
3672
3725
  notesFamily
3673
3726
  ];
3674
- //#endregion
3675
- //#region src/entry-compose.ts
3727
+ // src/entry-compose.ts
3676
3728
  /**
3677
3729
  * pptx-ts: composing a presentation from the construct families it actually needs
3678
3730
  *
@@ -3685,7 +3737,7 @@ const CORE_CONSTRUCT_FAMILIES = [
3685
3737
  * three-condition treatment `.` gets, so three more source entries, three more `dist` files, three
3686
3738
  * more budget rows and a second place for the entries to diverge -- and it would buy nothing that
3687
3739
  * export-level shaking does not already give. `pptx-ts` is an intermediate module in a consumer's
3688
- * graph: a program that imports only `createPresentation` drops the `TsPptx` class beside it and,
3740
+ * graph: a program that imports only `createPresentation` drops the `PptxTs` class beside it and,
3689
3741
  * with it, every family that class names.
3690
3742
  */
3691
3743
  /**
@@ -3699,13 +3751,12 @@ const CORE_CONSTRUCT_FAMILIES = [
3699
3751
  function composePresentation(runtime, opts) {
3700
3752
  return new PresentationCore(runtime, [...CORE_CONSTRUCT_FAMILIES, ...opts?.use ?? []]);
3701
3753
  }
3702
- //#endregion
3703
- //#region src/entry-families.ts
3754
+ // src/entry-families.ts
3704
3755
  /**
3705
3756
  * pptx-ts: the construct families the three main entries are composed with
3706
3757
  *
3707
3758
  * The full authoring surface, as a list: `index.ts`, `node.ts` and `browser.ts` each compose every
3708
- * family, so `TsPptx` authors everything it ever has; the browser entry adds the table family's
3759
+ * family, so `PptxTs` authors everything it ever has; the browser entry adds the table family's
3709
3760
  * live-DOM half on top, because that one needs a `document` to read. The families a *composed*
3710
3761
  * presentation gets without asking are the shorter list in `families/core.ts`.
3711
3762
  *
@@ -3739,14 +3790,13 @@ const ALL_CONSTRUCT_FAMILIES = /* @__PURE__ */ Object.freeze([
3739
3790
  tableFamily,
3740
3791
  zoomFamily
3741
3792
  ]);
3742
- //#endregion
3743
- //#region src/runtime/fetch-media.ts
3793
+ // src/runtime/fetch-media.ts
3744
3794
  /**
3745
3795
  * The parts of a runtime adapter that are not runtime-specific.
3746
3796
  *
3747
3797
  * `fetch`, `btoa` and `TextEncoder` exist in Node, in every browser, and in the edge/worker
3748
3798
  * runtimes the neutral adapter serves, so the remote-load paths were the same code in all three
3749
- * adapters — byte-identical in two of them and an inline branch in the third. What is genuinely
3799
+ * adapters: byte-identical in two of them and an inline branch in the third. What is genuinely
3750
3800
  * per-runtime stays in each adapter: `node:fs`, `FileReader`, the canvas rasterizer, the
3751
3801
  * `<a download>` writer.
3752
3802
  *
@@ -3755,13 +3805,13 @@ const ALL_CONSTRUCT_FAMILIES = /* @__PURE__ */ Object.freeze([
3755
3805
  /**
3756
3806
  * Whether `source` names something to `fetch` rather than something to read from a filesystem.
3757
3807
  *
3758
- * A real scheme test, not `source.startsWith('http')`. That prefix matched a *relative path* —
3759
- * `httpdocs/logo.png`, `http-icons/x.svg` — and sent it to `fetch`, which then failed with a
3808
+ * A real scheme test, not `source.startsWith('http')`. That prefix matched a *relative path*
3809
+ * (`httpdocs/logo.png`, `http-icons/x.svg`) and sent it to `fetch`, which then failed with a
3760
3810
  * fetch error naming a file that exists on disk. It was also case-sensitive, so
3761
3811
  * `HTTPS://example.com/f.ttf` missed and went to `fs.readFile`.
3762
3812
  *
3763
3813
  * Only `http:` and `https:` count. A `file:` or `data:` URL falls through to the adapter's
3764
- * local branch, where it fails — the same as before this was tightened, and deliberately left
3814
+ * local branch, where it fails, the same as before this was tightened, and deliberately left
3765
3815
  * that way: making either work is a feature with its own decisions (what a `file:` URL means
3766
3816
  * off Node, whether a `data:` URL should bypass loading entirely), not a side effect of fixing
3767
3817
  * a prefix test.
@@ -3777,7 +3827,7 @@ async function fetchFontBytes(source) {
3777
3827
  return new Uint8Array(await response.arrayBuffer());
3778
3828
  }
3779
3829
  /**
3780
- * Fetch a media file as raw base64 (no `data:` prefix) — see {@link RuntimeAdapter.loadMedia}
3830
+ * Fetch a media file as raw base64 (no `data:` prefix). See {@link RuntimeAdapter.loadMedia}
3781
3831
  * for why both encodings are accepted.
3782
3832
  *
3783
3833
  * Encodes through `bytesToBase64` rather than `Buffer`, so the same function serves a runtime
@@ -3802,16 +3852,15 @@ async function placeholderSvgPreview(rel) {
3802
3852
  rel.data = IMG_SVG_PLACEHOLDER;
3803
3853
  return null;
3804
3854
  }
3805
- //#endregion
3806
- //#region src/clip.ts
3855
+ // src/clip.ts
3807
3856
  /**
3808
3857
  * pptx-ts: named clip silhouettes for images
3809
3858
  *
3810
- * A `ClipShape` is declarative data — a named silhouette plus its options — and {@link clipPath}
3859
+ * A `ClipShape` is declarative data (a named silhouette plus its options), and {@link clipPath}
3811
3860
  * resolves it to the freeform `points` path `addImage` emits as the `<a:custGeom>` clip mask on
3812
3861
  * the `<p:pic>`. Paired with `sizing: { type: 'cover' }` (an `<a:srcRect>` crop) it reproduces
3813
- * what a PowerPoint *picture placeholder* does — a layout `custGeom` clipping an inherited
3814
- * blipFill — but standalone, with no placeholder involved.
3862
+ * what a PowerPoint *picture placeholder* does (a layout `custGeom` clipping an inherited
3863
+ * blipFill), but standalone, with no placeholder involved.
3815
3864
  *
3816
3865
  * These are silhouettes recurring often enough in real decks to be worth naming; hand-authored
3817
3866
  * `points` remain available for anything else. Nothing here is theme- or brand-aware: which
@@ -3941,7 +3990,7 @@ function halfDisc(w, h, flat, preset) {
3941
3990
  * to `addImage({ points })`.
3942
3991
  *
3943
3992
  * `w`/`h` are the image box's size **in inches** and must match the `w`/`h` the picture is drawn
3944
- * at — the path is emitted in the box's own coordinate space, not normalized (see the module
3993
+ * at, because the path is emitted in the box's own coordinate space, not normalized (see the module
3945
3994
  * note above).
3946
3995
  * @param {ClipShape} shape - the named silhouette and its options
3947
3996
  * @param {number} w - image box width (inches)
@@ -3963,8 +4012,7 @@ function clipPath(shape, w, h) {
3963
4012
  case "half-disc": return halfDisc(w, h, checkEnumOrThrow(shape.flat, FLAT_SIDES, "clipPath `flat`", "clip/invalid-shape"), checkEnumOrThrow(shape.preset ?? "deep", HALF_DISC_PRESETS, "clipPath `preset`", "clip/invalid-shape"));
3964
4013
  }
3965
4014
  }
3966
- //#endregion
3967
- //#region src/types/text.ts
4015
+ // src/types/text.ts
3968
4016
  /** Factory for a single inline text run. Prevents `as never` casts when building mixed-style run arrays. */
3969
4017
  function textRun(text, options) {
3970
4018
  return options !== void 0 ? {
@@ -3976,7 +4024,6 @@ function textRun(text, options) {
3976
4024
  function textRuns(runs) {
3977
4025
  return runs;
3978
4026
  }
3979
- //#endregion
3980
4027
  export { fetchMediaBase64 as a, ALL_CONSTRUCT_FAMILIES as c, IMG_SVG_PLACEHOLDER as d, fetchFontBytes as i, composePresentation as l, textRuns as n, isRemote as o, clipPath as r, placeholderSvgPreview as s, textRun as t, PresentationCore as u };
3981
4028
 
3982
- //# sourceMappingURL=text-BvFFMMFQ.js.map
4029
+ //# sourceMappingURL=text-Dz0ArGIp.js.map