@shbernal/ts-pptx 4.0.1 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +147 -114
  2. package/dist/anim-presets-Qbgh8uut.js +55 -0
  3. package/dist/anim-presets-Qbgh8uut.js.map +1 -0
  4. package/dist/{autopage-odPz7zZO.js → autopage-DqZ37VpL.js} +11 -12
  5. package/dist/autopage-DqZ37VpL.js.map +1 -0
  6. package/dist/{binary-string-CKVAYI3M.js → binary-string-Ba8VM3b9.js} +3 -4
  7. package/dist/binary-string-Ba8VM3b9.js.map +1 -0
  8. package/dist/{body-insets-Dw_BeWD_.js → body-insets-BDHymJvz.js} +7 -9
  9. package/dist/body-insets-BDHymJvz.js.map +1 -0
  10. package/dist/browser.d.ts +24 -16
  11. package/dist/browser.d.ts.map +1 -1
  12. package/dist/browser.js +19 -19
  13. package/dist/browser.js.map +1 -1
  14. package/dist/{image-size-CvN2iCA4.js → chart-metadata-CwiTTcJq.js} +634 -537
  15. package/dist/chart-metadata-CwiTTcJq.js.map +1 -0
  16. package/dist/{clip-Bl01BPcN.d.ts → clip-ISfCMtWA.d.ts} +6 -10
  17. package/dist/clip-ISfCMtWA.d.ts.map +1 -0
  18. package/dist/{notes-Dh12JAbn.js → comments-CKIZYRbZ.js} +530 -401
  19. package/dist/comments-CKIZYRbZ.js.map +1 -0
  20. package/dist/{diagnostics-D8ot4Ei7.d.ts → diagnostics-MoA4MBq5.d.ts} +55 -53
  21. package/dist/diagnostics-MoA4MBq5.d.ts.map +1 -0
  22. package/dist/{embedded-fonts-DarT9aoa.d.ts → embedded-fonts-U7HIIhPO.d.ts} +4 -6
  23. package/dist/embedded-fonts-U7HIIhPO.d.ts.map +1 -0
  24. package/dist/{entry-compose-DCnvBZz2.d.ts → entry-compose-CiakSt-f.d.ts} +62 -81
  25. package/dist/entry-compose-CiakSt-f.d.ts.map +1 -0
  26. package/dist/{errors-C4oENPcu.js → entry-errors-JMthgJ2g.js} +45 -29
  27. package/dist/entry-errors-JMthgJ2g.js.map +1 -0
  28. package/dist/{table-cell-margins-EVg0EwxT.js → enums-BP9wsb9Q.js} +44 -47
  29. package/dist/enums-BP9wsb9Q.js.map +1 -0
  30. package/dist/{enums-BUKTUB6V.d.ts → enums-PcXr3o3J.d.ts} +13 -14
  31. package/dist/{enums-BUKTUB6V.d.ts.map → enums-PcXr3o3J.d.ts.map} +1 -1
  32. package/dist/families.d.ts +24 -26
  33. package/dist/families.d.ts.map +1 -1
  34. package/dist/families.js +3 -4
  35. package/dist/{fit-Cb7naFj6.js → fit-Bpmzep6O.js} +64 -56
  36. package/dist/fit-Bpmzep6O.js.map +1 -0
  37. package/dist/{font-metrics-v5fn7s7e.d.ts → font-metrics-DTppw4t3.d.ts} +62 -38
  38. package/dist/font-metrics-DTppw4t3.d.ts.map +1 -0
  39. package/dist/{grid-DikTjFey.js → grid-DUIMxjfl.js} +23 -26
  40. package/dist/grid-DUIMxjfl.js.map +1 -0
  41. package/dist/{html-dom-Iuog2wdK.js → html-dom-LZCgntnJ.js} +46 -47
  42. package/dist/html-dom-LZCgntnJ.js.map +1 -0
  43. package/dist/html.d.ts +53 -9
  44. package/dist/html.d.ts.map +1 -1
  45. package/dist/html.js +12 -13
  46. package/dist/html.js.map +1 -1
  47. package/dist/index.d.ts +21 -13
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +15 -15
  50. package/dist/index.js.map +1 -1
  51. package/dist/inspect.d.ts +16 -18
  52. package/dist/inspect.d.ts.map +1 -1
  53. package/dist/inspect.js +18 -19
  54. package/dist/inspect.js.map +1 -1
  55. package/dist/{text-anchor-CrYXAfUu.js → lock-attrs-CSQnFDHP.js} +62 -12
  56. package/dist/lock-attrs-CSQnFDHP.js.map +1 -0
  57. package/dist/math.d.ts +2 -4
  58. package/dist/math.d.ts.map +1 -1
  59. package/dist/math.js +12 -13
  60. package/dist/math.js.map +1 -1
  61. package/dist/measure.d.ts +23 -12
  62. package/dist/measure.d.ts.map +1 -1
  63. package/dist/measure.js +3 -3
  64. package/dist/node.d.ts +21 -13
  65. package/dist/node.d.ts.map +1 -1
  66. package/dist/node.js +12 -12
  67. package/dist/node.js.map +1 -1
  68. package/dist/{options-internal-WqgMf720.js → options-internal-BWgmLPdx.js} +4 -5
  69. package/dist/options-internal-BWgmLPdx.js.map +1 -0
  70. package/dist/{package-J49Ck6S2.d.ts → package-CANBWuSm.d.ts} +9 -13
  71. package/dist/package-CANBWuSm.d.ts.map +1 -0
  72. package/dist/{playbtn-CUqQdoDf.js → playbtn-BQZFJir9.js} +4 -5
  73. package/dist/playbtn-BQZFJir9.js.map +1 -0
  74. package/dist/{pres-C6qgOFAa.d.ts → pres-BkEkUAEM.d.ts} +410 -237
  75. package/dist/pres-BkEkUAEM.d.ts.map +1 -0
  76. package/dist/{presentation-DGYlAWhl.js → presentation-4Ggq0_Xa.js} +470 -315
  77. package/dist/presentation-4Ggq0_Xa.js.map +1 -0
  78. package/dist/{presentation-types-8jLQHI4M.d.ts → presentation-types-BgnZR-0a.d.ts} +1119 -468
  79. package/dist/presentation-types-BgnZR-0a.d.ts.map +1 -0
  80. package/dist/read.d.ts +18 -13
  81. package/dist/read.d.ts.map +1 -1
  82. package/dist/read.js +4 -4
  83. package/dist/script.d.ts +116 -65
  84. package/dist/script.d.ts.map +1 -1
  85. package/dist/script.js +2700 -780
  86. package/dist/script.js.map +1 -1
  87. package/dist/{shapes-re0KyQk_.js → shapes-CAPOjU0Q.js} +1564 -491
  88. package/dist/shapes-CAPOjU0Q.js.map +1 -0
  89. package/dist/{slide-Dx2ZeVZ6.d.ts → slide-BmT4kMoO.d.ts} +102 -89
  90. package/dist/slide-BmT4kMoO.d.ts.map +1 -0
  91. package/dist/{slide-size-BalTjFuv.js → slide-size-SkScz1ig.js} +2 -3
  92. package/dist/{slide-size-BalTjFuv.js.map → slide-size-SkScz1ig.js.map} +1 -1
  93. package/dist/{table-dom-BTDP3lEP.js → table-dom-BYga4FYY.js} +4 -5
  94. package/dist/{table-dom-BTDP3lEP.js.map → table-dom-BYga4FYY.js.map} +1 -1
  95. package/dist/{text-sN64Otf_.js → text-CU08xJGs.js} +393 -344
  96. package/dist/text-CU08xJGs.js.map +1 -0
  97. package/dist/{transition-speed-kUEWDWTx.js → transition-speed-CNJ0fSpQ.js} +2 -3
  98. package/dist/{transition-speed-kUEWDWTx.js.map → transition-speed-CNJ0fSpQ.js.map} +1 -1
  99. package/dist/{units-internal-XJlf-hOl.js → units-internal-BR3a4cIi.js} +34 -32
  100. package/dist/units-internal-BR3a4cIi.js.map +1 -0
  101. package/dist/{zip-CKd8ihcf.js → zip-7JTh61LX.js} +8 -10
  102. package/dist/zip-7JTh61LX.js.map +1 -0
  103. package/dist/{zip-C0leZZMj.d.ts → zip-uUjs9Cqx.d.ts} +4 -6
  104. package/dist/zip-uUjs9Cqx.d.ts.map +1 -0
  105. package/dist/zip.d.ts +3 -3
  106. package/dist/zip.js +3 -3
  107. package/dist/{zoom-DPUHh85d.js → zoom-CSSeOwM8.js} +1204 -620
  108. package/dist/zoom-CSSeOwM8.js.map +1 -0
  109. package/package.json +27 -28
  110. package/skills/{ts-pptx-upstream → pptx-ts-upstream}/SKILL.md +37 -84
  111. package/dist/autopage-odPz7zZO.js.map +0 -1
  112. package/dist/binary-string-CKVAYI3M.js.map +0 -1
  113. package/dist/body-insets-Dw_BeWD_.js.map +0 -1
  114. package/dist/clip-Bl01BPcN.d.ts.map +0 -1
  115. package/dist/diagnostics-D8ot4Ei7.d.ts.map +0 -1
  116. package/dist/embedded-fonts-DarT9aoa.d.ts.map +0 -1
  117. package/dist/entry-compose-DCnvBZz2.d.ts.map +0 -1
  118. package/dist/errors-C4oENPcu.js.map +0 -1
  119. package/dist/fit-Cb7naFj6.js.map +0 -1
  120. package/dist/font-metrics-v5fn7s7e.d.ts.map +0 -1
  121. package/dist/grid-DikTjFey.js.map +0 -1
  122. package/dist/html-dom-Iuog2wdK.js.map +0 -1
  123. package/dist/image-size-CvN2iCA4.js.map +0 -1
  124. package/dist/notes-Dh12JAbn.js.map +0 -1
  125. package/dist/options-internal-WqgMf720.js.map +0 -1
  126. package/dist/package-J49Ck6S2.d.ts.map +0 -1
  127. package/dist/playbtn-CUqQdoDf.js.map +0 -1
  128. package/dist/pres-C6qgOFAa.d.ts.map +0 -1
  129. package/dist/presentation-DGYlAWhl.js.map +0 -1
  130. package/dist/presentation-types-8jLQHI4M.d.ts.map +0 -1
  131. package/dist/shapes-re0KyQk_.js.map +0 -1
  132. package/dist/slide-Dx2ZeVZ6.d.ts.map +0 -1
  133. package/dist/table-cell-margins-EVg0EwxT.js.map +0 -1
  134. package/dist/text-anchor-CrYXAfUu.js.map +0 -1
  135. package/dist/text-sN64Otf_.js.map +0 -1
  136. package/dist/units-internal-XJlf-hOl.js.map +0 -1
  137. package/dist/zip-C0leZZMj.d.ts.map +0 -1
  138. package/dist/zip-CKd8ihcf.js.map +0 -1
  139. package/dist/zoom-DPUHh85d.js.map +0 -1
@@ -1,13 +1,13 @@
1
- import { i as PackageReadError, l as warn, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-C4oENPcu.js";
2
- import { X as MIN_SLIDE_MASTER_ID, Y as MAX_SLIDE_ID } from "./units-internal-XJlf-hOl.js";
3
- import { D as emuToInches } from "./table-cell-margins-EVg0EwxT.js";
4
- import { $t as THEME_REL, At as NOTES_MASTER_CONTENT_TYPE, Ct as HYPERLINK_REL, Dt as MS_MEDIA_REL, E as EMBEDDED_FONT_SLOTS, Et as MODERN_COMMENT_AUTHORS_REL, Ft as OFFICE_DOCUMENT_REL, Ht as RELATIONSHIPS_CONTENT_TYPE, It as OFFICE_REL, Jt as SLIDE_MASTER_REL, Kt as SLIDE_LAYOUT_REL, Lt as PACKAGE_REL, Mt as NOTES_SLIDE_CONTENT_TYPE, Nt as NOTES_SLIDE_REL, Ot as MS_POWERPOINT_CONTENT, Qt as THEME_CONTENT_TYPE, S as COLOR_MAP_TOKENS, Ut as SHARED_PARTS, Wt as SLIDE_CONTENT_TYPE, Xt as TABLE_STYLES_CONTENT_TYPE, Yt as SLIDE_REL, Z as THEME_COLOR_SLOTS, Zt as TABLE_STYLES_REL, _t as CORE_PROPS_REL, at as CHARTEX_REL, ct as CHART_CONTENT_TYPE, dt as CHART_STYLE_REL, en as VIDEO_REL, fn as imageFormatForBytes, in as OOXML_NS, it as CHARTEX_CONTENT_TYPE, jt as NOTES_MASTER_REL, kt as MS_REL, lt as CHART_REL, ot as CHART_COLOR_STYLE_CONTENT_TYPE, pt as COMMENTS_REL, rn as XLSX_CONTENT_TYPE, rt as AUDIO_REL, st as CHART_COLOR_STYLE_REL, u as boolValue, ut as CHART_STYLE_CONTENT_TYPE, wt as IMAGE_REL, zt as PRESENTATION_MAIN_CONTENT_TYPE } from "./image-size-CvN2iCA4.js";
5
- import { Ct as FONT_DATA_CONTENT_TYPE, Ot as XML_DECL, Rt as encodeXmlAttrValue, St as voidEl, Tt as FONT_REL_TYPE, n as makeXmlNotesMaster, o as makeXmlNotesSlideSkeleton, wt as FONT_DATA_EXTENSION, xt as raw, yt as el } from "./notes-Dh12JAbn.js";
6
- import { t as pickDefined } from "./options-internal-WqgMf720.js";
7
- import { n as readZip, t as ZipWriter } from "./zip-CKd8ihcf.js";
8
- import { t as transitionSpeedForDuration } from "./transition-speed-kUEWDWTx.js";
9
- import { $ as placeholderInheritedColor, $t as relsPartNameFor, A as flattenAnimations, At as CSLD_AFTER_BG, B as readColorRef, Bt as SLIDE_AFTER_TRANSITION, Ct as styleRefFill, E as AutoShape, Et as themeElementsOfRoot, Ft as PRESENTATION_AFTER_SLD_ID_LST, G as resolveSlideColorContext, Gt as SPPR_LN_AFTER, H as resolveLayoutColorContext, Ht as SPPR_AFTER_XFRM, It as PRESENTATION_AFTER_SLD_MASTER_ID_LST, J as checkPositiveEmu, Jt as TXBODY_AFTER_BODYPR, K as resolveSlideThemeParts, Kt as SPPR_SCENE3D_AFTER, L as readPatternFill, Lt as RPR_FILL_AFTER, M as pruneSpids, Mt as LN_SLOTS, N as remapSpids, Nt as PRESENTATION_AFTER_EMBEDDED_FONT_LST, O as carryShapeAnimations, Ot as hasFillChoice, P as TextFrame, Pt as PRESENTATION_AFTER_NOTES_MASTER_ID_LST, Q as placeholderInheritedAnchor, Qt as relativePartName, R as readPictureFill, Rt as RUN_AFTER_RPR, St as resolveSchemeToken, T as Picture, Tt as substitutePhClr, U as resolveMasterColorContext, Ut as SPPR_EFFECT_AFTER, Vt as SLIDE_MASTER_AFTER_SLD_LAYOUT_ID_LST, W as resolveNotesColorContext, Wt as SPPR_FILL_AFTER, X as RUN_PROP_NAMES, Xt as partNameExtension, Y as LST_STYLE_LEVELS, Yt as TXBODY_AFTER_LSTSTYLE, Z as lstStyleLevelDefRPr, Zt as partNameToZipPath, _n as parseXml, _t as isA, an as boolAttr, at as slideDefinesProp, bn as serializeXml, bt as replaceColorElement, cn as descendantsByTag, ct as carriedDecorations, dn as getElements, dt as nextDrawingId, en as resolveRelativePartName, et as placeholderInheritedListStyles, fn as getOrAddChild, ft as nthShapeChild, gn as ownerDocumentOf, gt as fmtEntry, hn as numberValue, ht as spTreeOf, in as attr, it as slideDefinesColor, j as hasAnimations, jt as EMBEDDED_FONT_ENTRY_AFTER, k as enumerateSpids, l as wrapShapeElement, ln as firstChild, lt as collectElements, m as resolveTableCellTextStyle, mn as numberAttr, mt as reassignDrawingIds, n as buildShapes, nn as singleRelPart, nt as placeholderInheritedXfrm, on as childElements, ot as cSldName, pn as insertInOrder, pt as nvPrOf, q as checkFiniteEmu, qt as SPPR_SP3D_AFTER, r as findShapeByIdDeep, rn as zipPathToPartName, rt as placeholderOf, sn as createElement, st as cSldOf, t as GroupShape, tn as resolveSingleRel, tt as placeholderInheritedRunProps, u as GraphicFrame, un as firstChildElement, ut as firstShapeChild, vn as removeAttr, vt as parseClrMap, wt as styleRefLine, xn as setAttr, xt as resolveColor, yn as removeChildrenByQName, yt as parseClrScheme, z as readGradientFill, zt as SHAPE_AFTER_SPPR } from "./shapes-re0KyQk_.js";
10
- //#region src/read/opc/content-types.ts
1
+ import { D as emuToInches } from "./enums-BP9wsb9Q.js";
2
+ import { n as readZip, t as ZipWriter } from "./zip-7JTh61LX.js";
3
+ import { $ as LST_STYLE_LEVELS, $t as TXBODY_AFTER_LSTSTYLE, A as enumerateSpids, At as themeElementsOfRoot, Bt as PRESENTATION_AFTER_SLD_MASTER_ID_LST, Cn as removeChildrenByQName, Ct as parseClrScheme, D as AutoShape, Dt as styleRefFill, E as Picture, Et as resolveSchemeToken, F as remapSpids, Ft as EMBEDDED_FONT_ENTRY_AFTER, Gt as SLIDE_MASTER_AFTER_SLD_LAYOUT_ID_LST, H as readGradientFill, Ht as RUN_AFTER_RPR, I as TextFrame, It as LN_SLOTS, J as resolveNotesColorContext, Jt as SPPR_FILL_AFTER, K as resolveLayoutColorContext, Kt as SPPR_AFTER_XFRM, Lt as PRESENTATION_AFTER_EMBEDDED_FONT_LST, M as hasAnimations, Mt as hasFillChoice, N as pruneSpids, Ot as styleRefLine, P as readBuildEffects, Pt as CSLD_AFTER_BG, Q as checkPositiveEmu, Qt as TXBODY_AFTER_BODYPR, Rt as PRESENTATION_AFTER_NOTES_MASTER_ID_LST, Sn as removeAttr, St as parseClrMap, Tn as setAttr, Tt as resolveColor, U as readPictureFill, Ut as SHAPE_AFTER_SPPR, V as readPatternFill, Vt as RPR_FILL_AFTER, W as readColorRef, Wt as SLIDE_AFTER_TRANSITION, X as resolveSlideThemeParts, Xt as SPPR_SCENE3D_AFTER, Y as resolveSlideColorContext, Yt as SPPR_LN_AFTER, Z as checkFiniteEmu, Zt as SPPR_SP3D_AFTER, _n as insertInOrder, _t as nvPrOf, an as resolveSingleRel, at as placeholderInheritedRunProps, bn as ownerDocumentOf, bt as fmtEntry, cn as attr, ct as slideDefinesColor, dn as createElement, dt as cSldOf, en as partNameExtension, et as RUN_PROP_NAMES, fn as descendantsByTag, ft as carriedDecorations, gn as getOrAddChild, gt as nthShapeChild, hn as getElements, ht as nextDrawingId, in as resolveRelativePartName, it as placeholderInheritedListStyles, j as flattenAnimations, k as carryShapeAnimations, kt as substitutePhClr, l as wrapShapeElement, ln as boolAttr, lt as slideDefinesProp, m as resolveTableCellTextStyle, mn as firstChildElement, mt as firstShapeChild, n as buildShapes, nn as relativePartName, nt as placeholderInheritedAnchor, on as singleRelPart, ot as placeholderInheritedXfrm, pn as firstChild, pt as collectElements, q as resolveMasterColorContext, qt as SPPR_EFFECT_AFTER, r as findShapeByIdDeep, rn as relsPartNameFor, rt as placeholderInheritedColor, sn as zipPathToPartName, st as placeholderOf, t as GroupShape, tn as partNameToZipPath, tt as lstStyleLevelDefRPr, u as GraphicFrame, un as childElements, ut as cSldName, vn as numberAttr, vt as reassignDrawingIds, wn as serializeXml, wt as replaceColorElement, xn as parseXml, xt as isA, yn as numberValue, yt as spTreeOf, zt as PRESENTATION_AFTER_SLD_ID_LST } from "./shapes-CAPOjU0Q.js";
4
+ import { Ft as voidEl, It as XML_DECL, Kt as encodeXmlAttrValue, Mt as el, Pt as raw, a as makeXmlNotesMaster, gt as FONT_REL_TYPE, ht as FONT_DATA_EXTENSION, l as makeXmlNotesSlideSkeleton, mt as FONT_DATA_CONTENT_TYPE, n as makeXmlComments, t as makeXmlCommentAuthors } from "./comments-CKIZYRbZ.js";
5
+ import { a as PackageReadError, n as InternalError, r as InvalidOptionError, s as UnsupportedFeatureError, u as warn } from "./entry-errors-JMthgJ2g.js";
6
+ import { B as NOTES_SLIDE_CONTENT_TYPE, C as COMMENT_AUTHORS_REL, F as MS_MEDIA_REL, G as PACKAGE_REL, I as MS_POWERPOINT_CONTENT, L as MS_REL, M as IMAGE_REL, P as MODERN_COMMENT_AUTHORS_REL, Q as SLIDE_CONTENT_TYPE, Qt as THEME_COLOR_SLOTS, R as NOTES_MASTER_CONTENT_TYPE, S as COMMENT_AUTHORS_CONTENT_TYPE, T as CORE_PROPS_REL, Tt as EMBEDDED_FONT_SLOTS, U as OFFICE_DOCUMENT_REL, V as NOTES_SLIDE_REL, W as OFFICE_REL, X as RELATIONSHIPS_CONTENT_TYPE, Z as SHARED_PARTS, _ as CHART_REL, _n as imageFormatForBytes, at as TABLE_STYLES_REL, b as COMMENTS_CONTENT_TYPE, ct as VIDEO_REL, d as AUDIO_REL, dt as XLSX_CONTENT_TYPE, et as SLIDE_LAYOUT_REL, f as CHARTEX_CONTENT_TYPE, ft as OOXML_NS, g as CHART_CONTENT_TYPE, h as CHART_COLOR_STYLE_REL, it as TABLE_STYLES_CONTENT_TYPE, j as HYPERLINK_REL, m as CHART_COLOR_STYLE_CONTENT_TYPE, nt as SLIDE_MASTER_REL, on as boolValue, ot as THEME_CONTENT_TYPE, p as CHARTEX_REL, q as PRESENTATION_MAIN_CONTENT_TYPE, rt as SLIDE_REL, st as THEME_REL, v as CHART_STYLE_CONTENT_TYPE, x as COMMENTS_REL, xt as COLOR_MAP_TOKENS, y as CHART_STYLE_REL, z as NOTES_MASTER_REL } from "./chart-metadata-CwiTTcJq.js";
7
+ import { X as MIN_SLIDE_MASTER_ID, Y as MAX_SLIDE_ID } from "./units-internal-BR3a4cIi.js";
8
+ import { t as transitionSpeedForDuration } from "./transition-speed-CNJ0fSpQ.js";
9
+ import { t as pickDefined } from "./options-internal-BWgmLPdx.js";
10
+ // src/read/opc/content-types.ts
11
11
  /**
12
12
  * Overlay over `[Content_Types].xml`, used to resolve part content types at
13
13
  * load and to register new ones when parts are added. While clean, the original
@@ -57,7 +57,7 @@ var ContentTypes = class ContentTypes {
57
57
  }
58
58
  /**
59
59
  * Drop the `Override` for `partName` if present (e.g. when a part is removed).
60
- * `Default` rules by extension are left untouched — they may still serve other
60
+ * `Default` rules by extension are left untouched; they may still serve other
61
61
  * parts. Marks the overlay dirty when something was removed.
62
62
  */
63
63
  removeOverride(partName) {
@@ -78,10 +78,9 @@ var ContentTypes = class ContentTypes {
78
78
  return lines.join("");
79
79
  }
80
80
  };
81
- //#endregion
82
- //#region src/read/opc/part.ts
81
+ // src/read/opc/part.ts
83
82
  const textDecoder$1 = new TextDecoder("utf-8");
84
- const textEncoder$4 = new TextEncoder();
83
+ const textEncoder$5 = new TextEncoder();
85
84
  const XML_DECLARATION_RE = /^\uFEFF?<\?xml[^>]*\?>\s*/;
86
85
  /**
87
86
  * One OPC part. Holds the original bytes from the zip for its whole life;
@@ -147,11 +146,10 @@ var Part = class {
147
146
  if (!this.#dirty) return this.#bytes;
148
147
  let xml = serializeXml(this.dom);
149
148
  if (!xml.startsWith("<?xml")) xml = (XML_DECLARATION_RE.exec(textDecoder$1.decode(this.#bytes))?.[0] ?? "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n") + xml;
150
- return textEncoder$4.encode(xml);
149
+ return textEncoder$5.encode(xml);
151
150
  }
152
151
  };
153
- //#endregion
154
- //#region src/read/opc/relationships.ts
152
+ // src/read/opc/relationships.ts
155
153
  /**
156
154
  * Overlay over one `.rels` part, keyed by relationship id. While clean, the
157
155
  * `.rels` bytes pass through verbatim on save (byte-identical); once `add()`
@@ -302,17 +300,16 @@ var Relationships = class Relationships {
302
300
  return lines.join("");
303
301
  }
304
302
  };
305
- //#endregion
306
- //#region src/read/opc/package.ts
303
+ // src/read/opc/package.ts
307
304
  const CONTENT_TYPES_ZIP_PATH = "[Content_Types].xml";
308
305
  const textDecoder = new TextDecoder("utf-8");
309
- const textEncoder$3 = new TextEncoder();
306
+ const textEncoder$4 = new TextEncoder();
310
307
  /**
311
308
  * An OPC package loaded from `.pptx` bytes.
312
309
  *
313
310
  * Fidelity contract: parts that are never mutated (`Part.markDirty()`) are
314
311
  * written back byte-identically by `save()`. Whole-zip byte-identity is not
315
- * promised — zip metadata and compression may differ — but part bodies, the
312
+ * promised (zip metadata and compression may differ), but part bodies, the
316
313
  * part-name set, and part order are preserved.
317
314
  */
318
315
  var OpcPackage = class OpcPackage {
@@ -357,8 +354,12 @@ var OpcPackage = class OpcPackage {
357
354
  }
358
355
  return new OpcPackage(parts, contentTypes, contentTypesBytes);
359
356
  }
357
+ /**
358
+ * The part at `partName`, or `undefined`. Takes `null`, as a part-name getter such as
359
+ * `Picture.imagePartName` reads when there is no part to name, and misses on it.
360
+ */
360
361
  part(partName) {
361
- return this.parts.get(partName);
362
+ return partName === null ? void 0 : this.parts.get(partName);
362
363
  }
363
364
  partsByContentType(contentType) {
364
365
  if (!this.#partsByContentType) {
@@ -403,7 +404,7 @@ var OpcPackage = class OpcPackage {
403
404
  * later `save()` neither re-emits it nor flushes a stale `.rels` for it. A relationship set
404
405
  * belongs to its part: one left behind would come back as the relationships of the next part
405
406
  * added under the same name. Low-level: it does not touch references *to* this part
406
- * (dangling rels are the caller's concern) nor cascade to parts this one referenced — see
407
+ * (dangling rels are the caller's concern) nor cascade to parts this one referenced; see
407
408
  * {@link Presentation.removeSlide} for the slide-aware variant that unwires the presentation
408
409
  * and prunes orphans.
409
410
  */
@@ -477,21 +478,20 @@ var OpcPackage = class OpcPackage {
477
478
  for (const relationships of this.#relationshipsCache.values()) {
478
479
  if (!relationships.isDirty) continue;
479
480
  const relsPartName = relsPartNameFor(relationships.sourcePartName);
480
- const bytes = textEncoder$3.encode(relationships.serialize());
481
+ const bytes = textEncoder$4.encode(relationships.serialize());
481
482
  this.#parts.set(relsPartName, new Part(relsPartName, RELATIONSHIPS_CONTENT_TYPE, bytes));
482
483
  this.#partsByContentType = null;
483
484
  }
484
485
  }
485
486
  };
486
- //#endregion
487
- //#region src/read/api/slide-background.ts
487
+ // src/read/api/slide-background.ts
488
488
  /**
489
489
  * Read a slide's effective background (`p:cSld/p:bg`), decoded into a typed union.
490
490
  *
491
491
  * A background lives on the slide itself, or is inherited from its slideLayout,
492
- * else its slideMaster — the {@link SlideBackground.source} field records which.
492
+ * else its slideMaster; the {@link SlideBackground.source} field records which.
493
493
  * The writer authors solid-colour, gradient, pattern and image backgrounds (all FAITHFUL);
494
- * theme-indexed (`p:bgRef`) backgrounds are read-only for imported decks — surface
494
+ * theme-indexed (`p:bgRef`) backgrounds are read-only for imported decks. Surface
495
495
  * them so a codegen pass can carry the part rather than fake it. A
496
496
  * `themeRef` additionally resolves its `idx` through the slide theme's `fmtScheme`
497
497
  * to a concrete {@link BackgroundFill} in `resolvedFill`, so a consumer can ask what
@@ -534,13 +534,13 @@ function decodeBackgroundFill(container, ctx, rels) {
534
534
  /**
535
535
  * Resolve a `p:bgRef`'s `idx` into the concrete {@link BackgroundFill} it renders
536
536
  * as, through the slide theme's `fmtScheme`. A `p:bgRef` is a
537
- * `CT_StyleMatrixReference` — the same shape as a shape's `a:fillRef` — so
537
+ * `CT_StyleMatrixReference` (the same shape as a shape's `a:fillRef`), so
538
538
  * {@link styleRefFill} builds the indexed `bgFillStyleLst`/`fillStyleLst` entry with
539
539
  * its `phClr` substituted by the bgRef's colour, and the resulting fill element is
540
540
  * decoded like a `p:bgPr`. `null` when the theme has no `fmtScheme`, the entry is
541
541
  * absent, or the colour cannot be resolved.
542
542
  *
543
- * `themeRels` — not the owning slide/layout/master's rels — is what an `a:blipFill`
543
+ * `themeRels`, not the owning slide/layout/master's rels, is what an `a:blipFill`
544
544
  * entry's `r:embed` resolves against: the fill element is lifted out of the *theme*
545
545
  * part, so its relationship id is scoped to that part. Several stock Office themes
546
546
  * (Ion, Facet, …) put a picture in the third `bgFillStyleLst` slot, so a deck using
@@ -581,14 +581,13 @@ function readSlideBackground(bg, source, ctx, rels, themeRels) {
581
581
  source
582
582
  };
583
583
  }
584
- //#endregion
585
- //#region src/read/api/ops/part-index.ts
584
+ // src/read/api/ops/part-index.ts
586
585
  /**
587
586
  * Walking a deck's master/layout spine by partname.
588
587
  *
589
588
  * The `p:sldMasterIdLst` / `p:sldLayoutIdLst` entries hold relationship ids, not partnames, so
590
589
  * every traversal has to resolve through the owning part's relationships. These are the
591
- * source-side reads that do it — used against a *foreign* presentation as often as against this
590
+ * source-side reads that do it, used against a *foreign* presentation as often as against this
592
591
  * one, which is why they take the deck rather than living on it.
593
592
  */
594
593
  /**
@@ -628,8 +627,7 @@ function idListTargets(lst, qname, resolve) {
628
627
  }
629
628
  return out;
630
629
  }
631
- //#endregion
632
- //#region src/read/api/chrome.ts
630
+ // src/read/api/chrome.ts
633
631
  /** Read `<a:latin>`/`<a:ea>`/`<a:cs>` typefaces of a theme font family; empty string ⇒ `null`. */
634
632
  function readThemeFontFace(font) {
635
633
  const face = (child) => {
@@ -723,7 +721,7 @@ function placeholderShapes(spTree) {
723
721
  return getElements(spTree, "p:sp").filter((sp) => placeholderOf(sp) !== null);
724
722
  }
725
723
  /**
726
- * One placeholder shape (`p:sp` with a `p:ph`) of a slide master or slide layout —
724
+ * One placeholder shape (`p:sp` with a `p:ph`) of a slide master or slide layout:
727
725
  * the definition a slide's placeholder of the same `type`/`idx` inherits geometry
728
726
  * and text style from. Geometry getters read the placeholder's *own* `a:xfrm`,
729
727
  * which a master/layout placeholder carries explicitly (so it round-trips, unlike a
@@ -749,7 +747,7 @@ var Placeholder = class {
749
747
  * `xfrm()` + `emuFrom`; and,
750
748
  * the one that showed, the text frame was built with **no** inheritance context, so
751
749
  * `Run.resolvedSizePt`, `resolvedFontFace`, `resolvedColor` and `resolvedBold` resolved
752
- * through `SlideMaster.shapes` and came back `null` through `SlideMaster.placeholders` —
750
+ * through `SlideMaster.shapes` and came back `null` through `SlideMaster.placeholders`:
753
751
  * two views of one element disagreeing about the same run.
754
752
  */
755
753
  shape;
@@ -817,7 +815,7 @@ var Placeholder = class {
817
815
  }
818
816
  };
819
817
  /**
820
- * The shared body of a slide master and a slide layout — the two template tiers a slide
818
+ * The shared body of a slide master and a slide layout, the two template tiers a slide
821
819
  * inherits from.
822
820
  *
823
821
  * Both are an OPC part holding a `p:cSld` with a shape tree and a resolvable theme context, and
@@ -835,7 +833,7 @@ var Placeholder = class {
835
833
  *
836
834
  * `Slide` deliberately does not extend this. It is a shape host too, but it is constructed from
837
835
  * a `Presentation` rather than an `OpcPackage`, reaches its relationships through that, and
838
- * reports an unnamed slide as `null` where a template tier reports `''` — three differences in
836
+ * reports an unnamed slide as `null` where a template tier reports `''`. That is three differences in
839
837
  * the same handful of members, which is more contortion than the sharing is worth.
840
838
  */
841
839
  var TemplatePart = class {
@@ -860,7 +858,7 @@ var TemplatePart = class {
860
858
  return (cSld && attr(cSld, "name")) ?? "";
861
859
  }
862
860
  /**
863
- * Every shape in this tier's `p:cSld/p:spTree`, in document order — the same `AnyShape`
861
+ * Every shape in this tier's `p:cSld/p:spTree`, in document order: the same `AnyShape`
864
862
  * union `Slide.shapes` returns, so shape-walking code applies unchanged.
865
863
  *
866
864
  * {@link placeholders} is the filtered view of the same tree.
@@ -869,7 +867,7 @@ var TemplatePart = class {
869
867
  const spTree = this.spTree();
870
868
  return spTree ? buildShapes(spTree, this) : [];
871
869
  }
872
- /** The shape anywhere in this tier's tree with the given drawing id, or `undefined`. */
870
+ /** The shape anywhere in this tier's tree with the given drawing id, or `undefined` (always, for `null`). */
873
871
  shapeByIdDeep(id) {
874
872
  return findShapeByIdDeep(this.shapes, id);
875
873
  }
@@ -930,7 +928,7 @@ var SlideMaster = class extends TemplatePart {
930
928
  }
931
929
  /**
932
930
  * The master's *own* background (`p:cSld/p:bg`), decoded, or `null` when it defines
933
- * none. Scoped to the master's own element — a slide's *effective* background,
931
+ * none. Scoped to the master's own element. A slide's *effective* background,
934
932
  * resolved through the slide → layout → master chain, is `Slide.background`.
935
933
  */
936
934
  get background() {
@@ -939,21 +937,21 @@ var SlideMaster = class extends TemplatePart {
939
937
  const themePart = this.relTarget(THEME_REL);
940
938
  return readSlideBackground(bg, "master", this.themeContext(), this.relationships, themePart ? this.opc.relationshipsFor(themePart.partName) : null);
941
939
  }
942
- /** A master's context is its own `p:clrMap` plus its theme — no walk beyond this part. */
940
+ /** A master's context is its own `p:clrMap` plus its theme; no walk beyond this part. */
943
941
  resolveThemeContext() {
944
942
  return resolveMasterColorContext(this.opc, this.partName);
945
943
  }
946
944
  };
947
945
  /**
948
- * A deck's slide layout (`slideLayoutN.xml`) as a modeled object — the gallery entry
946
+ * A deck's slide layout (`slideLayoutN.xml`) as a modeled object: the gallery entry
949
947
  * a slide binds to. Exposes its {@link name}, its {@link type} (import-only; the
950
948
  * writer authors none), its {@link master} (and, through it, the {@link theme}), its
951
949
  * `shapes` and the `placeholders` subset of them, and its own {@link background}.
952
950
  * Reachable from `Slide.layout` and {@link SlideMaster.layouts}.
953
951
  *
954
952
  * The write API authors non-placeholder shapes into a layout: every
955
- * `defineSlideMaster({ objects })` member that is not a `placeholder` — a `rect`, a
956
- * `line`, an `image`, a `chart`, a `text` box — lands in this tier's tree.
953
+ * `defineSlideMaster({ objects })` member that is not a `placeholder` (a `rect`, a
954
+ * `line`, an `image`, a `chart`, a `text` box) lands in this tier's tree.
957
955
  */
958
956
  var SlideLayout = class extends TemplatePart {
959
957
  /**
@@ -968,7 +966,7 @@ var SlideLayout = class extends TemplatePart {
968
966
  /**
969
967
  * Whether this layout draws the master's non-placeholder shapes
970
968
  * (`p:sldLayout/@showMasterSp`). `xsd:boolean` defaulting to `true`, so an absent
971
- * attribute means shown — the layout-tier counterpart of `Slide.showMasterSp`,
969
+ * attribute means shown. This is the layout-tier counterpart of `Slide.showMasterSp`,
972
970
  * and the one PowerPoint actually writes on a section-divider or full-bleed
973
971
  * layout. A renderer resolving what to paint under a slide's own shapes has to
974
972
  * consult both: the slide's flag, then its layout's.
@@ -988,7 +986,7 @@ var SlideLayout = class extends TemplatePart {
988
986
  }
989
987
  /**
990
988
  * The layout's *own* background (`p:cSld/p:bg`), decoded, or `null` when it defines
991
- * none. A layout usually authors one — an explicit fill (`p:bgPr`) or a
989
+ * none. A layout usually authors one: an explicit fill (`p:bgPr`) or a
992
990
  * theme-indexed reference (`p:bgRef`). The slide's *effective* background is
993
991
  * `Slide.background`.
994
992
  */
@@ -1003,8 +1001,7 @@ var SlideLayout = class extends TemplatePart {
1003
1001
  return resolveLayoutColorContext(this.opc, this.partName);
1004
1002
  }
1005
1003
  };
1006
- //#endregion
1007
- //#region src/read/api/notes.ts
1004
+ // src/read/api/notes.ts
1008
1005
  /**
1009
1006
  * One placeholder shape (`p:sp`) of a notes slide. A notes slide holds a fixed set:
1010
1007
  * the slide thumbnail (`type="sldImg"`), the notes body (`type="body"`), and the
@@ -1012,8 +1009,8 @@ var SlideLayout = class extends TemplatePart {
1012
1009
  * `a:xfrm` and are `null` when it inherits geometry from the notesMaster (the case
1013
1010
  * on an authored deck, whose `sldImg`/`sldNum` carry an empty `p:spPr`).
1014
1011
  *
1015
- * A notes placeholder IS a {@link Placeholder} — identity, geometry and the escape hatch are
1016
- * the same twelve members read off the same `p:sp`, down to `p:ph` being found the same way —
1012
+ * A notes placeholder IS a {@link Placeholder}. Identity, geometry and the escape hatch are
1013
+ * the same twelve members read off the same `p:sp`, down to `p:ph` being found the same way,
1017
1014
  * so it extends one rather than repeating it. Two things are its own: the flattened
1018
1015
  * {@link text} convenience, and a {@link textFrame} that threads the notesMaster inheritance
1019
1016
  * context onto the body frame.
@@ -1025,7 +1022,7 @@ var NotesPlaceholder = class extends Placeholder {
1025
1022
  * runs round-trip a slide's authored notes; the `sldNum` placeholder's frame
1026
1023
  * holds the slide-number `a:fld`, whose value surfaces through `TextFrame.text`.
1027
1024
  *
1028
- * Overrides {@link Placeholder.textFrame} for the inheritance context alone — see below.
1025
+ * Overrides {@link Placeholder.textFrame} for the inheritance context alone (see below).
1029
1026
  */
1030
1027
  get textFrame() {
1031
1028
  const txBody = firstChild(this.sp, "p:txBody");
@@ -1051,7 +1048,7 @@ var NotesPlaceholder = class extends Placeholder {
1051
1048
  }
1052
1049
  };
1053
1050
  /**
1054
- * A slide's speaker-notes slide (`notesSlideN.xml`) as a modeled object — the deep
1051
+ * A slide's speaker-notes slide (`notesSlideN.xml`) as a modeled object: the deep
1055
1052
  * companion to {@link Slide.notesText}. Exposes the notes
1056
1053
  * shape tree as {@link NotesPlaceholder}s ({@link body}/{@link slideImage}/
1057
1054
  * {@link slideNumber}) plus the body {@link textFrame} the older getters flatten.
@@ -1071,7 +1068,7 @@ var NotesSlide = class {
1071
1068
  get partName() {
1072
1069
  return this.part.partName;
1073
1070
  }
1074
- /** The notes part's own relationships — a notes hyperlink resolves through these. */
1071
+ /** The notes part's own relationships; a notes hyperlink resolves through these. */
1075
1072
  get relationships() {
1076
1073
  return this.opc.relationshipsFor(this.partName);
1077
1074
  }
@@ -1079,7 +1076,7 @@ var NotesSlide = class {
1079
1076
  * The notes shape tree as full shapes, in document order.
1080
1077
  *
1081
1078
  * A notes slide holds nothing but its three placeholders, so {@link placeholders} is the
1082
- * view to read. This one exists because a notes slide is a {@link ShapeHost} — which is
1079
+ * view to read. This one exists because a notes slide is a {@link ShapeHost}, which is
1083
1080
  * what lets a {@link NotesPlaceholder} be the same {@link AutoShape} view of its `p:sp`
1084
1081
  * that a master or layout placeholder is, rather than a second reading of one.
1085
1082
  */
@@ -1087,7 +1084,7 @@ var NotesSlide = class {
1087
1084
  const spTree = this.#spTree();
1088
1085
  return spTree ? buildShapes(spTree, this) : [];
1089
1086
  }
1090
- /** The shape anywhere in the notes tree with the given drawing id, or `undefined`. */
1087
+ /** The shape anywhere in the notes tree with the given drawing id, or `undefined` (always, for `null`). */
1091
1088
  shapeByIdDeep(id) {
1092
1089
  return findShapeByIdDeep(this.shapes, id);
1093
1090
  }
@@ -1131,8 +1128,7 @@ var NotesSlide = class {
1131
1128
  return spTreeOf(this.part.dom.documentElement);
1132
1129
  }
1133
1130
  };
1134
- //#endregion
1135
- //#region src/read/api/ops/deck-target.ts
1131
+ // src/read/api/ops/deck-target.ts
1136
1132
  /**
1137
1133
  * `ppt/_rels/presentation.xml.rels` -- the deck's own relationship part.
1138
1134
  *
@@ -1147,8 +1143,7 @@ var NotesSlide = class {
1147
1143
  function presentationRels(dest) {
1148
1144
  return dest.opc.relationshipsFor(dest.presentationPart.partName);
1149
1145
  }
1150
- //#endregion
1151
- //#region src/read/api/ops/master-registry.ts
1146
+ // src/read/api/ops/master-registry.ts
1152
1147
  /**
1153
1148
  * Slide-master bookkeeping in `presentation.xml` and in a master's own
1154
1149
  * `p:sldLayoutIdLst`: registering a master so renderers treat it as active,
@@ -1185,7 +1180,7 @@ function registerMaster(dest, masterPartName) {
1185
1180
  /**
1186
1181
  * Move the `p:sldMasterId` entries for `masterPartNames` to the front of
1187
1182
  * `p:sldMasterIdLst`, preserving their existing relative order, so the first of
1188
- * them becomes the deck's `Designs(1)` — the theme PowerPoint's Design tab shows.
1183
+ * them becomes the deck's `Designs(1)`, the theme PowerPoint's Design tab shows.
1189
1184
  * Reorders the id list only; relationships, ids, and all other parts are left as
1190
1185
  * they are. A no-op when the named masters already lead (idempotent re-call).
1191
1186
  */
@@ -1215,7 +1210,7 @@ function promoteMasters(dest, masterPartNames) {
1215
1210
  * unique across the WHOLE presentation, not just within their own list. A duplicate
1216
1211
  * anywhere in this space makes PowerPoint report the file as corrupt on open
1217
1212
  * ("found a problem with content" / 0x80070570), even though LibreOffice silently
1218
- * tolerates it — so an imported master AND each of its layouts must take an id past
1213
+ * tolerates it. So an imported master AND each of its layouts must take an id past
1219
1214
  * the max of both the master-id list and every layout-id list. Recomputed per
1220
1215
  * allocation so ids appended earlier in the same import are counted.
1221
1216
  *
@@ -1271,20 +1266,19 @@ function addLayoutToMaster(dest, masterPartName, layoutPartName) {
1271
1266
  lst.appendChild(entry);
1272
1267
  masterPart.markDirty();
1273
1268
  }
1274
- //#endregion
1275
- //#region src/read/api/ops/copy-traversal.ts
1269
+ // src/read/api/ops/copy-traversal.ts
1276
1270
  /**
1277
1271
  * What a copy traversal does with one relationship: skip it, carry it as an external link, or
1278
1272
  * follow it into the part it names.
1279
1273
  *
1280
1274
  * Notes pull in a notesMaster and its own theme, which an imported page does not need, so the
1281
- * notes relationship is never followed — `carryNotes` picks it up afterwards for the pages
1275
+ * notes relationship is never followed; `carryNotes` picks it up afterwards for the pages
1282
1276
  * that asked. A master's relationships to its layouts are skipped so the copy stays lean:
1283
1277
  * copied layouts re-link themselves, and skipping the list is also what keeps one edited
1284
1278
  * layout from disqualifying every other layout that shares its master.
1285
1279
  *
1286
- * Each caller still owns its own extra arms — a copy's overrides and its jump-link rule, the reuse
1287
- * check's byte comparison — which is why this answers only the part they share.
1280
+ * Each caller still owns its own extra arms (a copy's overrides and its jump-link rule, the reuse
1281
+ * check's byte comparison), which is why this answers only the part they share.
1288
1282
  * @param part - the part the relationship belongs to
1289
1283
  * @param rel - the relationship being considered
1290
1284
  */
@@ -1293,13 +1287,12 @@ function copyTraversalStep(part, rel) {
1293
1287
  if (part.contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml" && rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") return "skip";
1294
1288
  return rel.targetMode === "External" ? "external" : "recurse";
1295
1289
  }
1296
- //#endregion
1297
- //#region src/read/api/ops/page-owned.ts
1290
+ // src/read/api/ops/page-owned.ts
1298
1291
  /**
1299
1292
  * What a page copy may share with the page it was copied from, and what it must own.
1300
1293
  *
1301
- * Duplicating a page — `cloneSlide`, `importSlide` of the same page twice,
1302
- * `importSlides` naming it twice — copies the page part and then has to decide,
1294
+ * Duplicating a page (`cloneSlide`, `importSlide` of the same page twice,
1295
+ * `importSlides` naming it twice) copies the page part and then has to decide,
1303
1296
  * for every part hanging off it, whether the copy points at the same part or gets
1304
1297
  * one of its own. Sharing is the cheap answer and is right for most of the graph:
1305
1298
  * a layout, a master, a theme, an image are deck-wide assets PowerPoint itself
@@ -1308,7 +1301,7 @@ function copyTraversalStep(part, rel) {
1308
1301
  * It is not right for the parts a page *owns*. A chart and its embedded workbook,
1309
1302
  * a SmartArt diagram's five parts, an OLE embedding, a notes slide: PowerPoint
1310
1303
  * treats each as belonging to exactly one page, and a package where two slides
1311
- * resolve to one of them is one it refuses to open at all — the "the file or
1304
+ * resolve to one of them is one it refuses to open at all: the "the file or
1312
1305
  * directory is corrupted and unreadable" (`0x80070570`) dialog, with the whole
1313
1306
  * deck rejected rather than the duplicate page. The schema validator accepts such
1314
1307
  * a package: nothing in ECMA-376 says a chart part has one referrer, so this rule
@@ -1338,14 +1331,13 @@ function copyTraversalStep(part, rel) {
1338
1331
  const SHARED_BY_PAGE_COPIES = new Set(SHARED_PARTS.map((kind) => kind.relType));
1339
1332
  /**
1340
1333
  * Whether a page copy may point at this relationship's target rather than taking
1341
- * a copy of it. Everything not listed is owned by the page and copied — see the
1334
+ * a copy of it. Everything not listed is owned by the page and copied; see the
1342
1335
  * module comment for why that is the safe default.
1343
1336
  */
1344
1337
  function isSharedByPageCopies(relType) {
1345
1338
  return SHARED_BY_PAGE_COPIES.has(relType);
1346
1339
  }
1347
- //#endregion
1348
- //#region src/read/api/ops/part-reuse.ts
1340
+ // src/read/api/ops/part-reuse.ts
1349
1341
  /**
1350
1342
  * Whether the destination already holds `sourcePartName`'s subgraph, part for part and
1351
1343
  * byte for byte, in a state an imported slide can bind to.
@@ -1426,8 +1418,7 @@ function bytesEqual(a, b) {
1426
1418
  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
1427
1419
  return true;
1428
1420
  }
1429
- //#endregion
1430
- //#region src/read/api/ops/part-copy.ts
1421
+ // src/read/api/ops/part-copy.ts
1431
1422
  /** Open an ownership scope for one page copy. */
1432
1423
  function newOwnedScope() {
1433
1424
  return /* @__PURE__ */ new Map();
@@ -1441,7 +1432,7 @@ function copyTarget(ctx) {
1441
1432
  * it would throw, found before anything in the destination moves.
1442
1433
  *
1443
1434
  * This is what lets a refused import leave the deck byte-identical. The copy changes the deck as it
1444
- * goes — parts added, a master registered in `presentation.xml`, a layout linked into its master —
1435
+ * goes (parts added, a master registered in `presentation.xml`, a layout linked into its master),
1445
1436
  * so a failure it met halfway would leave all of that behind. An import therefore runs the same
1446
1437
  * traversal twice: first with a plan in its context, which throws what the copy would and writes
1447
1438
  * nothing, then for real. The dry run used to be a separate walk of the source, transcribed from the
@@ -1452,8 +1443,8 @@ function copyTarget(ctx) {
1452
1443
  * A plan stands in for the destination package as a {@link CopyTarget}. It hands out the partnames
1453
1444
  * the copy will be given, keeps its own copy of each source's registry so a part it planned is found
1454
1445
  * again as the copy would find it, and remembers the notes master it would install in a deck that has
1455
- * none. Destination bookkeeping that adds no part — registering a master, linking a layout into it —
1456
- * is not recorded.
1446
+ * none. Destination bookkeeping that adds no part, such as registering a master or linking a layout
1447
+ * into it, is not recorded.
1457
1448
  */
1458
1449
  var CopyPlan = class {
1459
1450
  api;
@@ -1547,7 +1538,7 @@ var CopyPlan = class {
1547
1538
  * registry idempotence is right for a theme, master, layout or image, where a
1548
1539
  * second copy is waste; applied to the slide it made a repeated import of the
1549
1540
  * same source page return the first copy's partname, and the caller then wired a
1550
- * second `p:sldId` to a part that already had one — a package PowerPoint refuses
1541
+ * second `p:sldId` to a part that already had one: a package PowerPoint refuses
1551
1542
  * to open (0x80070570), with nothing in the read model to show for it. So the
1552
1543
  * page goes into the selection plan `copyPart` already honours for a batch, which
1553
1544
  * re-materializes exactly the named pages and leaves the dedup of their
@@ -1570,7 +1561,7 @@ function copySlidePart(ctx, sourcePartName) {
1570
1561
  * per source package via the copy registry. Relationship ids are preserved so
1571
1562
  * the copied part body's `r:id`/`r:embed` references stay valid; targets are
1572
1563
  * rewritten to the freshly-allocated partnames. Notes relationships are
1573
- * dropped. A copied `slideMaster` does not drag in all its sibling layouts —
1564
+ * dropped. A copied `slideMaster` does not drag in all its sibling layouts;
1574
1565
  * each imported `slideLayout` wires itself into the master instead (see
1575
1566
  * {@link linkLayoutIntoMaster}).
1576
1567
  *
@@ -1580,13 +1571,13 @@ function copySlidePart(ctx, sourcePartName) {
1580
1571
  * a `slide → slide` link may not leave the selection is enforced as each link is
1581
1572
  * followed (see {@link rebuildRels}). Imports run this traversal as a
1582
1573
  * {@link CopyPlan} first, which throws that and every other failure the copy
1583
- * could meet — so once copying starts there is nothing left to throw, and a
1574
+ * could meet, so once copying starts there is nothing left to throw, and a
1584
1575
  * rejected batch never leaves a half-copied deck behind.
1585
1576
  *
1586
1577
  * Idempotence stops at the page's own parts. Reaching a page opens an
1587
1578
  * {@link OwnedScope}, and everything under it that {@link isSharedByPageCopies}
1588
- * does not clear for sharing — a chart, a diagram, an OLE embedding, each with
1589
- * its own subtree — is copied into that scope instead of the registry, so the
1579
+ * does not clear for sharing (a chart, a diagram, an OLE embedding, each with
1580
+ * its own subtree) is copied into that scope instead of the registry, so the
1590
1581
  * next copy of the page gets parts of its own. Pass `owned` to open the scope
1591
1582
  * from outside, as the rebinding import paths do for the page they build
1592
1583
  * themselves.
@@ -1694,7 +1685,7 @@ function rebuildRels(ctx, options) {
1694
1685
  * The page's shared targets are carried as the source wrote them. Each owned one is repointed at a
1695
1686
  * fresh copy, and the subtree under it is copied the same way, so a chart's workbook and
1696
1687
  * user-shapes drawing come along while the image inside that drawing stays shared. A relationship
1697
- * *back* to the source page — a notes slide names the slide it annotates — is repointed at the
1688
+ * *back* to the source page (a notes slide names the slide it annotates) is repointed at the
1698
1689
  * clone, which is what makes the copied notes belong to it.
1699
1690
  *
1700
1691
  * Unlike an import, a clone keeps its page's notes, and nothing here consults the copy registry or
@@ -1769,19 +1760,18 @@ function linkLayoutIntoMaster(ctx, layoutSourceRels, layoutPartName) {
1769
1760
  if (!masterPartName) return;
1770
1761
  addLayoutToMaster(ctx.dest, masterPartName, layoutPartName);
1771
1762
  }
1772
- //#endregion
1773
- //#region src/read/api/ops/notes-master.ts
1763
+ // src/read/api/ops/notes-master.ts
1774
1764
  /**
1775
1765
  * Carrying speaker notes and the deck's single notes master across an import or an append.
1776
1766
  *
1777
1767
  * A `notesSlide` is not self-contained: it back-references the slide it annotates and forward-
1778
1768
  * references the deck's notes master. `CT_NotesMasterIdList` allows at most one master per
1779
- * presentation, so a deck that already has one keeps it — the destination's notes styling wins —
1769
+ * presentation, so a deck that already has one keeps it (the destination's notes styling wins),
1780
1770
  * and a source master is copied only into a deck that has none. That single rule is why both the
1781
1771
  * `Presentation`-to-`Presentation` path and the generator-XML path funnel through
1782
1772
  * `registerNotesMaster`: they differ only in how the *part* comes into being.
1783
1773
  */
1784
- const textEncoder$2 = new TextEncoder();
1774
+ const textEncoder$3 = new TextEncoder();
1785
1775
  /**
1786
1776
  * Carry the source slide's speaker notes onto the just-imported slide (the
1787
1777
  * `importNotes` option). The slide copy itself dropped the `notesSlide` rel, so
@@ -1789,7 +1779,7 @@ const textEncoder$2 = new TextEncoder();
1789
1779
  * `slide → notesSlide` rel on the new slide, and rebuilds the copied notesSlide's
1790
1780
  * own relationships:
1791
1781
  *
1792
- * - its `slide` back-rel is repointed at the new slide (`newSlidePartName`) — the
1782
+ * - its `slide` back-rel is repointed at the new slide (`newSlidePartName`); the
1793
1783
  * source slide is *not* copied (that would be circular);
1794
1784
  * - its `notesMaster` rel is resolved through {@link ensureNotesMaster}, which
1795
1785
  * reuses this deck's notesMaster when it has one and copies the source's only
@@ -1838,7 +1828,7 @@ function carryNotes(dest, source, ctx, sourceSlidePartName, newSlidePartName) {
1838
1828
  */
1839
1829
  function addNotesSlidePart(dest, xml, slidePartName, notesMasterPartName) {
1840
1830
  const notesPartName = dest.opc.reservePartNameLike("/ppt/notesSlides/notesSlide1.xml");
1841
- dest.opc.addPart(notesPartName, NOTES_SLIDE_CONTENT_TYPE, textEncoder$2.encode(xml));
1831
+ dest.opc.addPart(notesPartName, NOTES_SLIDE_CONTENT_TYPE, textEncoder$3.encode(xml));
1842
1832
  const notesRels = dest.opc.relationshipsFor(notesPartName);
1843
1833
  if (notesMasterPartName) notesRels.addWithId("rId1", NOTES_MASTER_REL, relativePartName(notesPartName, notesMasterPartName));
1844
1834
  notesRels.addWithId("rId2", SLIDE_REL, relativePartName(notesPartName, slidePartName));
@@ -1876,8 +1866,8 @@ function presentationRoot(dest) {
1876
1866
  * allows. Returns the partname, so callers can use it as a rel target.
1877
1867
  *
1878
1868
  * Split out of {@link ensureNotesMaster} because the two ways a notesMaster arrives
1879
- * — copied from another `Presentation`, or authored by a generator and injected by
1880
- * {@link Presentation.appendSlides} — differ only in how the *part* is created, not in how it is
1869
+ * (copied from another `Presentation`, or authored by a generator and injected by
1870
+ * {@link Presentation.appendSlides}) differ only in how the *part* is created, not in how it is
1881
1871
  * registered.
1882
1872
  */
1883
1873
  function registerNotesMaster(dest, notesMasterPartName) {
@@ -1921,7 +1911,7 @@ function installNotesMaster(dest, masterBytes, themeBytes, themeContentType = TH
1921
1911
  * theme its `.rels` requires (the normal write path emits that as `theme2.xml`).
1922
1912
  */
1923
1913
  function ensureNotesMasterFromXml(dest, master) {
1924
- return existingNotesMaster(dest) ?? installNotesMaster(dest, textEncoder$2.encode(master.xml), textEncoder$2.encode(master.themeXml));
1914
+ return existingNotesMaster(dest) ?? installNotesMaster(dest, textEncoder$3.encode(master.xml), textEncoder$3.encode(master.themeXml));
1925
1915
  }
1926
1916
  /**
1927
1917
  * Resolve the notesMaster a *newly authored* notes slide should bind to
@@ -1941,7 +1931,7 @@ function ensureNotesMasterFromXml(dest, master) {
1941
1931
  * arrangement PowerPoint writes (`theme1.xml` for the master, `theme2.xml` for the
1942
1932
  * notes master).
1943
1933
  *
1944
- * Throws when the deck has no theme to clone — a package that malformed cannot be
1934
+ * Throws when the deck has no theme to clone: a package that malformed cannot be
1945
1935
  * given a valid notesMaster, and silently emitting one without a resolvable theme
1946
1936
  * is what PowerPoint reports as a repair prompt rather than a bad edit.
1947
1937
  * @param {Presentation} dest - the deck being authored onto
@@ -1954,10 +1944,9 @@ function ensureNotesMasterForAuthoring(dest, slidePartName) {
1954
1944
  const themePartName = resolveSlideThemeParts(dest.opc, slidePartName).themePartName;
1955
1945
  const themePart = themePartName ? dest.opc.part(themePartName) : void 0;
1956
1946
  if (!themePart) throw new PackageReadError("package/part-missing", `addNotes: no theme reachable from ${slidePartName} to bind a new notes master to`);
1957
- return installNotesMaster(dest, textEncoder$2.encode(makeXmlNotesMaster()), themePart.serialize(), themePart.contentType);
1947
+ return installNotesMaster(dest, textEncoder$3.encode(makeXmlNotesMaster()), themePart.serialize(), themePart.contentType);
1958
1948
  }
1959
- //#endregion
1960
- //#region src/read/api/ops/notes-author.ts
1949
+ // src/read/api/ops/notes-author.ts
1961
1950
  /**
1962
1951
  * Authoring speaker notes onto a slide of a *loaded* deck ({@link Slide.addNotes}).
1963
1952
  *
@@ -1969,8 +1958,8 @@ function ensureNotesMasterForAuthoring(dest, slidePartName) {
1969
1958
  * The part it builds is the generator's, not a second design: the fixed three-
1970
1959
  * placeholder frame comes from {@link makeXmlNotesSlideSkeleton}, and the body
1971
1960
  * paragraphs carry the same elements and attributes the write path emits for a plain
1972
- * `pptx.addSlide().addNotes(text)`. `test/read/add-notes.test.js` asserts that
1973
- * equivalence, so the two cannot drift apart unnoticed — the same guarantee
1961
+ * `pptx.addSlide().addNotes(text)`. `test/read/add-notes.test.ts` asserts that
1962
+ * equivalence, so the two cannot drift apart unnoticed: the same guarantee
1974
1963
  * `src/ooxml/` gives the constants both halves share.
1975
1964
  *
1976
1965
  * The one difference is empty-element *spelling*: the write path emits `a:rPr` as an
@@ -2005,7 +1994,7 @@ function notesParagraphsXml(text) {
2005
1994
  /**
2006
1995
  * Replace a notes body's paragraphs with `text`, in the body's own document.
2007
1996
  *
2008
- * The path taken when the slide *already* has a notes part — an imported one, or one
1997
+ * The path taken when the slide *already* has a notes part: an imported one, or one
2009
1998
  * an earlier `addNotes` wrote. Only the `a:p` children are replaced, so the part's
2010
1999
  * geometry, its `a:bodyPr`/`a:lstStyle`, and its other two placeholders survive. The
2011
2000
  * body's hyperlink relationships are deliberately *not* pruned: a caller replacing
@@ -2047,7 +2036,7 @@ function notesBodyTxBody(root) {
2047
2036
  * When the slide already has a notes part, only the body paragraphs are rewritten
2048
2037
  * (see {@link replaceNotesParagraphs}). When it has none, the part is built and
2049
2038
  * wired: `slide → notesSlide`, and on the new part the two relationships a notes
2050
- * slide always carries — `notesMaster` as rId1 and a `slide` back-reference as rId2,
2039
+ * slide always carries: `notesMaster` as rId1 and a `slide` back-reference as rId2,
2051
2040
  * the ids and order the write path reserves.
2052
2041
  *
2053
2042
  * The notes master is resolved through {@link ensureNotesMasterForAuthoring}: this
@@ -2077,8 +2066,7 @@ function authorNotes(slide, text) {
2077
2066
  slide.relationships.add(NOTES_SLIDE_REL, relativePartName(slide.partName, partName));
2078
2067
  return partName;
2079
2068
  }
2080
- //#endregion
2081
- //#region src/read/api/comments.ts
2069
+ // src/read/api/comments.ts
2082
2070
  /** The slide → modern-comments-part relationship type (2018 schema). Only this module reads one. */
2083
2071
  const MODERN_COMMENTS_REL_TYPE = MS_REL + "2018/10/relationships/comments";
2084
2072
  /** Content type of the modern per-slide comments part (`ppt/comments/modernComment_*.xml`). */
@@ -2199,8 +2187,7 @@ function commentSchema(opc) {
2199
2187
  if (opc.partsByContentType("application/vnd.openxmlformats-officedocument.presentationml.comments+xml").length > 0) return "legacy";
2200
2188
  return "none";
2201
2189
  }
2202
- //#endregion
2203
- //#region src/read/api/tags.ts
2190
+ // src/read/api/tags.ts
2204
2191
  /** The owner → tags-part relationship type. Only this module follows one. */
2205
2192
  const TAGS_REL_TYPE = OFFICE_REL + "tags";
2206
2193
  /**
@@ -2223,8 +2210,7 @@ function readTagsForPart(opc, ownerPartName) {
2223
2210
  }
2224
2211
  return out;
2225
2212
  }
2226
- //#endregion
2227
- //#region src/read/api/transition.ts
2213
+ // src/read/api/transition.ts
2228
2214
  /**
2229
2215
  * Typed read/edit model for a slide's `p:transition` (slide-show transition).
2230
2216
  *
@@ -2235,7 +2221,7 @@ function readTagsForPart(opc, ownerPartName) {
2235
2221
  * when the duration matches a coarse `spd` speed bucket; and
2236
2222
  * - **wrapped** `<mc:AlternateContent>` carrying a `<mc:Choice Requires="p14">`
2237
2223
  * whose `p:transition` adds the precise `p14:dur` (milliseconds), plus a base
2238
- * `<mc:Fallback>` without it — emitted for an off-bucket exact duration.
2224
+ * `<mc:Fallback>` without it. This form is emitted for an off-bucket exact duration.
2239
2225
  *
2240
2226
  * The getter prefers the `p14` Choice (so `durationMs` is recovered); the setter
2241
2227
  * emits the `mc:AlternateContent` form when `durationMs` is set and the bare form
@@ -2250,7 +2236,6 @@ function typeElement(transition) {
2250
2236
  }
2251
2237
  /** Namespace prefix for a URI, defaulting to `p` for the base presentationml namespace. */
2252
2238
  function prefixFor(uri) {
2253
- if (!uri) return "p";
2254
2239
  for (const [prefix, ns] of Object.entries(OOXML_NS)) if (ns === uri) return prefix;
2255
2240
  return "p";
2256
2241
  }
@@ -2413,8 +2398,7 @@ function removeTransition(root) {
2413
2398
  const found = findTransition(root);
2414
2399
  if (found) root.removeChild(found.outer);
2415
2400
  }
2416
- //#endregion
2417
- //#region src/read/api/slide-build.ts
2401
+ // src/read/api/slide-build.ts
2418
2402
  /**
2419
2403
  * Create `qname` in the parent's document and append it.
2420
2404
  *
@@ -2484,8 +2468,7 @@ function buildPicture(doc, spec) {
2484
2468
  appendSpPr(pic, spec);
2485
2469
  return pic;
2486
2470
  }
2487
- //#endregion
2488
- //#region src/read/api/slide.ts
2471
+ // src/read/api/slide.ts
2489
2472
  /** Recognize a common raster format from its leading bytes, through the shared registry. */
2490
2473
  function sniffImageType(bytes) {
2491
2474
  const format = imageFormatForBytes(bytes);
@@ -2542,8 +2525,8 @@ var Slide = class {
2542
2525
  * `fmtScheme` + `fontScheme`, plus the layout/master roots), walked once from
2543
2526
  * slide → layout → master → theme and cached on this proxy. Backs the read-model
2544
2527
  * resolved getters ({@link Shape.resolvedFill}, `Run.resolvedColor`,
2545
- * `Run.resolvedSizePt`, `Run.resolvedFontFace`) so a `schemeClr` token — including
2546
- * one delivered through a shape's `p:style` `fillRef`/`lnRef` — resolves to a
2528
+ * `Run.resolvedSizePt`, `Run.resolvedFontFace`) so a `schemeClr` token (including
2529
+ * one delivered through a shape's `p:style` `fillRef`/`lnRef`) resolves to a
2547
2530
  * literal hex, and a placeholder run's inherited size/typeface (a `+mj-*`/`+mn-*`
2548
2531
  * font token included) resolves to a literal value. The maps/roots are empty when
2549
2532
  * the theme chain is incomplete, in which case tokens simply stay unresolved.
@@ -2593,7 +2576,7 @@ var Slide = class {
2593
2576
  /**
2594
2577
  * Whether this slide draws the master's non-placeholder shapes
2595
2578
  * (`p:sld/@showMasterSp`). `xsd:boolean` defaulting to `true`, so an absent
2596
- * attribute means shown — the same shape as {@link hidden}.
2579
+ * attribute means shown, the same shape as {@link hidden}.
2597
2580
  *
2598
2581
  * This is the switch that decides whether {@link SlideMaster.shapes} belongs on
2599
2582
  * *this* slide. A slide the author gave a full-bleed image or a section divider
@@ -2620,7 +2603,7 @@ var Slide = class {
2620
2603
  * Set or clear the slide's show transition. Assigning `null` removes it.
2621
2604
  * Writing a transition with `durationMs` emits the `mc:AlternateContent` form
2622
2605
  * (a `p14` Choice carrying `p14:dur` plus a base `mc:Fallback`); otherwise the
2623
- * bare `<p:transition>` is written. The node is inserted at its schema slot —
2606
+ * bare `<p:transition>` is written. The node is inserted at its schema slot,
2624
2607
  * after `p:clrMapOvr`, before `p:timing`/`p:extLst`. Marks the slide part dirty.
2625
2608
  *
2626
2609
  * The new transition is built from the current one before that is removed: it keeps the sound
@@ -2646,6 +2629,15 @@ var Slide = class {
2646
2629
  return root ? hasAnimations(root) : false;
2647
2630
  }
2648
2631
  /**
2632
+ * The slide's build effects: every time node in its `p:timing` with a `presetClass`, in document
2633
+ * order, with the sequence it plays in, its preset, trigger, duration, step delay and target shape
2634
+ * id. `[]` when the slide has no timing. Read-only: see {@link BuildEffect}.
2635
+ */
2636
+ get animations() {
2637
+ const root = this.part.dom.documentElement;
2638
+ return root ? readBuildEffects(root) : [];
2639
+ }
2640
+ /**
2649
2641
  * @internal The sorted, de-duplicated set of shape ids (`spid`) referenced by
2650
2642
  * the slide's animations (`<p:spTgt spid>` and `<p:bldP spid>`). Exposed for the
2651
2643
  * import paths' spid-coherence checks.
@@ -2675,14 +2667,14 @@ var Slide = class {
2675
2667
  /**
2676
2668
  * Flatten the slide's build animations: remove the `<p:timing>` block so the
2677
2669
  * slide renders and edits as its final static state, with every shape shown at
2678
- * once. Gated like {@link hasAnimations} — a `<p:timing>` that is purely a media
2670
+ * once. Gated like {@link hasAnimations}: a `<p:timing>` that is purely a media
2679
2671
  * loop (no `<p:bldP>` or `presetID`) is preserved so media playback survives.
2680
2672
  * Marks the slide part dirty and returns `true` only when a timing block was
2681
2673
  * removed.
2682
2674
  *
2683
2675
  * This removes click-through staging only; it does not delete shapes. If a slide
2684
2676
  * animated alternating states over the same region, the flattened render shows
2685
- * them all at once — keep that distinct from removing staged/duplicate shapes.
2677
+ * them all at once. Keep that distinct from removing staged/duplicate shapes.
2686
2678
  */
2687
2679
  flattenAnimations() {
2688
2680
  const root = this.part.dom.documentElement;
@@ -2698,7 +2690,7 @@ var Slide = class {
2698
2690
  return spTree ? buildShapes(spTree, this) : [];
2699
2691
  }
2700
2692
  /**
2701
- * All text on the slide, flattened in document order — the read-model
2693
+ * All text on the slide, flattened in document order: the read-model
2702
2694
  * counterpart to {@link TextFrame.text} one level up. Every text-bearing shape
2703
2695
  * contributes its text, recursing into groups ({@link GroupShape}) and reading
2704
2696
  * table cells ({@link GraphicFrame.table}) and SmartArt node text
@@ -2741,12 +2733,12 @@ var Slide = class {
2741
2733
  return blocks.join("\n");
2742
2734
  }
2743
2735
  /**
2744
- * The slide's speaker-note text — the companion to {@link text} for the notes
2736
+ * The slide's speaker-note text, the companion to {@link text} for the notes
2745
2737
  * that {@link text} deliberately excludes. Delegates to {@link notesSlide}: finds
2746
2738
  * the notes body placeholder (`p:ph` `type="body"`) and flattens its text frame
2747
2739
  * the same way {@link TextFrame.text} does (paragraphs joined by `\n`).
2748
2740
  *
2749
- * Returns `null` when the slide has **no notes slide part at all** — distinct
2741
+ * Returns `null` when the slide has **no notes slide part at all**, distinct
2750
2742
  * from `''`, which means a notes slide exists but its body is empty (PowerPoint
2751
2743
  * often attaches an empty notes slide to every slide). Only the body placeholder
2752
2744
  * is read; the slide-thumbnail (`sldImg`) and slide-number (`sldNum`)
@@ -2757,14 +2749,14 @@ var Slide = class {
2757
2749
  return notes ? notes.text : null;
2758
2750
  }
2759
2751
  /**
2760
- * The slide's speaker-note body as a navigable {@link TextFrame} — the rich
2752
+ * The slide's speaker-note body as a navigable {@link TextFrame}: the rich
2761
2753
  * companion to {@link notesText}, which flattens the same body to a plain string.
2762
2754
  * Walk `paragraphs → runs` to recover per-run formatting (bold/italic/underline,
2763
2755
  * colour, size, face) and any notes hyperlink that {@link notesText} discards.
2764
2756
  *
2765
2757
  * `null` when the slide has **no notes slide part** (the same boundary
2766
2758
  * {@link notesText} returns `null` at), and also when a notes part exists but
2767
- * carries no body-placeholder text frame — there is then no frame to hand back
2759
+ * carries no body-placeholder text frame; there is then no frame to hand back
2768
2760
  * (whereas {@link notesText} reports `''` for that empty-body case). Convenience
2769
2761
  * for `notesSlide.textFrame`; see {@link notesSlide} for the whole modeled notes
2770
2762
  * slide (its `sldImg`/`sldNum` placeholders and their geometry).
@@ -2776,9 +2768,9 @@ var Slide = class {
2776
2768
  * The slide's speaker-notes slide (`notesSlideN.xml`) as a modeled
2777
2769
  * {@link NotesSlide}, or `null` when the slide has no notes slide part. Beyond the
2778
2770
  * body text {@link notesText}/{@link notesTextFrame} surface, this exposes the
2779
- * notes slide's three placeholders — the slide thumbnail (`slideImage`), the notes
2780
- * body, and the slide-number field (`slideNumber`) — each with its geometry and
2781
- * (where present) a navigable text frame.
2771
+ * notes slide's three placeholders, each with its geometry and (where present) a
2772
+ * navigable text frame: the slide thumbnail (`slideImage`), the notes body, and the
2773
+ * slide-number field (`slideNumber`).
2782
2774
  *
2783
2775
  * The writer authors all three placeholders but leaves `sldImg`/`sldNum` with an
2784
2776
  * empty `p:spPr`, so on an authored deck their geometry reads `null` while an
@@ -2834,7 +2826,7 @@ var Slide = class {
2834
2826
  * carries its body text, `created` timestamp, marker position (EMU), its author
2835
2827
  * resolved through the deck-wide {@link Presentation.modernCommentAuthors}
2836
2828
  * registry (`@authorId` GUID → name/initials), and its reply thread nested under
2837
- * `replies`. Read-only — the writer authors the legacy schema; see
2829
+ * `replies`. Read-only: the writer authors the legacy schema; see
2838
2830
  * {@link Presentation.commentSchema} to tell which schema a deck uses.
2839
2831
  */
2840
2832
  get modernComments() {
@@ -2843,7 +2835,7 @@ var Slide = class {
2843
2835
  /**
2844
2836
  * The slide's programmatic tags (`p:custDataLst/p:tags` on the slide part,
2845
2837
  * resolved to `ppt/tags/tagN.xml`) as `{ name, val }` string pairs, `[]` when it
2846
- * has none. Host/add-in metadata with no visible rendering and no writer —
2838
+ * has none. Host/add-in metadata with no visible rendering and no writer:
2847
2839
  * read-only, preserved byte-for-byte on round-trip. Deck-level tags are
2848
2840
  * {@link Presentation.tags}.
2849
2841
  */
@@ -2853,7 +2845,7 @@ var Slide = class {
2853
2845
  /**
2854
2846
  * The slide's effective background (`p:cSld/p:bg`), decoded into a typed
2855
2847
  * {@link SlideBackground}. Resolved through the inheritance chain: the slide's
2856
- * own `p:bg` wins; failing that the slideLayout's, then the slideMaster's — the
2848
+ * own `p:bg` wins; failing that the slideLayout's, then the slideMaster's. The
2857
2849
  * result's `source` records which supplied it. `null` when nothing in the chain
2858
2850
  * defines a background.
2859
2851
  *
@@ -2899,20 +2891,24 @@ var Slide = class {
2899
2891
  * `slide.slideNumber`, or added to a master defined with `slideNumber`; its geometry and run formatting
2900
2892
  * read off the returned {@link AutoShape} the same as any placeholder.
2901
2893
  *
2902
- * Scoped to the slide's *own* shape tree — a slide number inherited purely from
2894
+ * Scoped to the slide's *own* shape tree: a slide number inherited purely from
2903
2895
  * the master's `p:hf`/placeholder (with no shape on the slide) is a master-level
2904
2896
  * concern this getter does not resolve.
2905
2897
  */
2906
2898
  get slideNumberPlaceholder() {
2907
2899
  return this.placeholder("sldNum") ?? null;
2908
2900
  }
2909
- /** The first top-level shape with the given drawing id (`p:cNvPr/@id`), or `undefined`. */
2901
+ /**
2902
+ * The first top-level shape with the given drawing id (`p:cNvPr/@id`), or `undefined`. Takes
2903
+ * `null`, as a shape's `id` reads when its `p:cNvPr` has no `@id`, and misses on it.
2904
+ */
2910
2905
  shapeById(id) {
2906
+ if (id === null) return void 0;
2911
2907
  return this.shapes.find((shape) => shape.id === id);
2912
2908
  }
2913
2909
  /**
2914
2910
  * The first shape *anywhere* in the slide's shape tree with the given drawing id
2915
- * (`p:cNvPr/@id`), descending into groups — unlike {@link shapeById}, which scans
2911
+ * (`p:cNvPr/@id`), descending into groups, unlike {@link shapeById}, which scans
2916
2912
  * only top-level shapes. Walked pre-order (a group is visited before its children),
2917
2913
  * matching how the writer allocates ids. `undefined` when no shape carries that id.
2918
2914
  *
@@ -2931,8 +2927,9 @@ var Slide = class {
2931
2927
  /**
2932
2928
  * The first placeholder of the given type (`p:ph/@type`, e.g. `title`,
2933
2929
  * `ctrTitle`, `subTitle`, `body`), optionally narrowed by `idx`. Returns
2934
- * `undefined` when none match. Only `p:sp` shapes can be placeholders, so the
2935
- * result is an {@link AutoShape}.
2930
+ * `undefined` when none match. Only {@link AutoShape}s are searched: a filled
2931
+ * picture, table or chart placeholder is not found here, though its own
2932
+ * `placeholder` getter still reads it.
2936
2933
  */
2937
2934
  placeholder(type, idx) {
2938
2935
  return this.shapes.find((shape) => {
@@ -3012,7 +3009,7 @@ var Slide = class {
3012
3009
  * afterwards through {@link notesTextFrame}.
3013
3010
  *
3014
3011
  * The counterpart to the read side's `notesText`/`notesTextFrame`/`notesSlide`
3015
- * getters, and the way to annotate a slide that has **no notes part at all** —
3012
+ * getters, and the way to annotate a slide that has **no notes part at all**:
3016
3013
  * the state an `importSlide` without `{ importNotes: true }` leaves behind, and
3017
3014
  * the one a `notesTextFrame` edit cannot reach because there is no frame to
3018
3015
  * hand back. Calling it on a slide that already has notes replaces the body
@@ -3067,8 +3064,7 @@ var Slide = class {
3067
3064
  return spTreeOf(this.part.dom.documentElement);
3068
3065
  }
3069
3066
  };
3070
- //#endregion
3071
- //#region src/read/api/document-properties.ts
3067
+ // src/read/api/document-properties.ts
3072
3068
  /** `dc:title`-style core-property fields, keyed by output field → element qname. */
3073
3069
  const CORE_FIELDS = [
3074
3070
  ["title", "dc:title"],
@@ -3138,7 +3134,7 @@ function readExtendedProperties(opc) {
3138
3134
  * number; real types (`r4`/`r8`/`decimal`) → number; `bool` → boolean;
3139
3135
  * `filetime`/`date` → the **raw string** (see {@link CoreProperties} on
3140
3136
  * timestamps). Any unrecognized `vt:` element falls back to its text content as a
3141
- * string — lossy but never throws.
3137
+ * string, which is lossy but never throws.
3142
3138
  */
3143
3139
  function decodeValue(vt) {
3144
3140
  const text = vt.textContent ?? "";
@@ -3195,13 +3191,12 @@ function readCustomProperties(opc) {
3195
3191
  }
3196
3192
  return out;
3197
3193
  }
3198
- //#endregion
3199
- //#region src/read/api/ops/embedded-fonts.ts
3194
+ // src/read/api/ops/embedded-fonts.ts
3200
3195
  /**
3201
3196
  * Merging embedded font faces into a deck's `p:embeddedFontLst`.
3202
3197
  *
3203
- * Fonts arrive two ways — copied out of another `Presentation`, or handed over as raw bytes by a
3204
- * generator during an append — and the two differ only in how the binary part comes into being.
3198
+ * Fonts arrive two ways (copied out of another `Presentation`, or handed over as raw bytes by a
3199
+ * generator during an append), and the two differ only in how the binary part comes into being.
3205
3200
  * That difference is confined to a per-face thunk, so both paths share one merge core: entries
3206
3201
  * join by typeface, faces de-dupe by slot, and the thunk runs only for a face actually being
3207
3202
  * added, so a face the deck already embeds never mints an orphan part.
@@ -3263,7 +3258,7 @@ function readEmbeddedFontEntries(deck) {
3263
3258
  * every face this deck would copy names a part that is actually there.
3264
3259
  *
3265
3260
  * Every import that carries fonts calls it before it changes anything, because the carry runs
3266
- * last — after the page or the masters are already in the deck — and a face it cannot copy would
3261
+ * last (after the page or the masters are already in the deck), and a face it cannot copy would
3267
3262
  * throw with parts added and no way back. A face whose `r:id` names no relationship and a face
3268
3263
  * whose relationship names no part are the same failure to a caller, the face's binary is not in
3269
3264
  * the package, so both are `package/part-missing`.
@@ -3346,7 +3341,7 @@ function carryGeneratedEmbeddedFonts(dest, fonts) {
3346
3341
  }
3347
3342
  /**
3348
3343
  * Merge normalized {@link IncomingEmbeddedFont} entries into this deck's
3349
- * `p:embeddedFontLst` — the shared core of {@link carryEmbeddedFonts} (import-side)
3344
+ * `p:embeddedFontLst`: the shared core of {@link carryEmbeddedFonts} (import-side)
3350
3345
  * and {@link carryGeneratedEmbeddedFonts} (append-side). Entries merge by `typeface`,
3351
3346
  * faces de-dupe by slot (a face this deck already embeds is left as is). For each newly
3352
3347
  * added face the `fntdata` Default is ensured, the binary part is created via the face's
@@ -3396,10 +3391,128 @@ function mergeEmbeddedFontEntries(dest, entries) {
3396
3391
  presPart.markDirty();
3397
3392
  }
3398
3393
  }
3399
- //#endregion
3400
- //#region src/read/api/ops/slide-size.ts
3394
+ // src/read/api/ops/comments.ts
3395
+ /**
3396
+ * Carrying legacy review comments onto a deck: a comments part per slide, and the deck-wide
3397
+ * author registry (`ppt/commentAuthors.xml`) every comment names its author in by `@authorId`.
3398
+ * `appendSlides` builds the comments part from a generator's comments; `importSlide` and
3399
+ * `importSlides` copy the source's part with the page and then renumber it here.
3400
+ *
3401
+ * The registry is the part that makes this more than a copy. The destination may already have
3402
+ * one, with its own ids and its own per-author numbering, so an incoming comment's author is
3403
+ * looked up there by name and initials (the key the writer resolves authors by) and its `idx`
3404
+ * continues that author's `lastIdx`. An author the destination does not have is added under the
3405
+ * next free id.
3406
+ */
3407
+ const textEncoder$2 = new TextEncoder();
3408
+ /** The deck's comment-author registry part, created and related from the presentation when it has none. */
3409
+ function commentAuthorsPart(dest) {
3410
+ const existing = singleRelPart(dest.opc, dest.presentationPart.partName, COMMENT_AUTHORS_REL);
3411
+ if (existing) return existing;
3412
+ const partName = dest.opc.reservePartNameLike("/ppt/commentAuthors.xml");
3413
+ const part = dest.opc.addPart(partName, COMMENT_AUTHORS_CONTENT_TYPE, textEncoder$2.encode(makeXmlCommentAuthors([])));
3414
+ presentationRels(dest).add(COMMENT_AUTHORS_REL, relativePartName(dest.presentationPart.partName, partName));
3415
+ return part;
3416
+ }
3417
+ /**
3418
+ * The deck's author registry, open for registering authors: each call to `register` finds or adds
3419
+ * the author by name and initials, takes that author's next `idx`, and marks the part dirty.
3420
+ */
3421
+ function authorRegistry(dest) {
3422
+ const part = commentAuthorsPart(dest);
3423
+ const root = part.dom.documentElement;
3424
+ if (!root) throw new PackageReadError("package/part-has-no-root", `${part.partName} has no document element to register comment authors in`);
3425
+ const authors = getElements(root, "p:cmAuthor");
3426
+ return (name, initials) => {
3427
+ let author = authors.find((a) => attr(a, "name") === name && attr(a, "initials") === initials);
3428
+ if (!author) {
3429
+ const id = Math.max(-1, ...authors.map((a) => numberValue(attr(a, "id")) ?? -1)) + 1;
3430
+ author = createElement(part.dom, "p:cmAuthor");
3431
+ setAttr(author, "id", String(id));
3432
+ setAttr(author, "name", name);
3433
+ setAttr(author, "initials", initials);
3434
+ setAttr(author, "lastIdx", "0");
3435
+ setAttr(author, "clrIdx", String(id));
3436
+ root.appendChild(author);
3437
+ authors.push(author);
3438
+ }
3439
+ const idx = (numberValue(attr(author, "lastIdx")) ?? 0) + 1;
3440
+ setAttr(author, "lastIdx", String(idx));
3441
+ part.markDirty();
3442
+ return {
3443
+ authorId: numberValue(attr(author, "id")) ?? 0,
3444
+ idx
3445
+ };
3446
+ };
3447
+ }
3401
3448
  /**
3402
- * ts-pptx: slide-size preconditions for the import surface
3449
+ * Add a comments part holding `comments`, registering each author in the deck's
3450
+ * `commentAuthors.xml`. The slide's own relationship *to* the part is left to the caller, as
3451
+ * `addNotesSlidePart` leaves the notes one, because the append path adds it after every id
3452
+ * the slide body names.
3453
+ * @param dest - the deck the part is added to
3454
+ * @param comments - the slide's comments, in order
3455
+ * @returns the comments part's name
3456
+ */
3457
+ function addCommentsPart(dest, comments) {
3458
+ const register = authorRegistry(dest);
3459
+ const meta = new Map(comments.map((comment) => [comment, register(comment.author, comment.initials)]));
3460
+ const partName = dest.opc.reservePartNameLike("/ppt/comments/comment1.xml");
3461
+ dest.opc.addPart(partName, COMMENTS_CONTENT_TYPE, textEncoder$2.encode(makeXmlComments(comments, meta)));
3462
+ return partName;
3463
+ }
3464
+ /**
3465
+ * Renumber the comments part a page copy brought from `source` against this deck's registry
3466
+ * (#235). The copy keeps each `@authorId` and `@idx` as the source numbered them, which on this
3467
+ * deck names no author, or the wrong one. Each comment's author is resolved in the source's
3468
+ * registry and registered in this deck's, and the comment takes the id and the next `idx` it gets
3469
+ * there. A comment whose author the source itself does not register is left as it is.
3470
+ *
3471
+ * Runs once per page copy, after the copy: a comments part is owned by its page (see
3472
+ * `page-owned.ts`), so every copy has a part of its own to renumber.
3473
+ * @param dest - the deck the page was copied into
3474
+ * @param source - the deck it was copied from
3475
+ * @param slidePartName - the copied page in `dest`
3476
+ */
3477
+ function carryCommentAuthors(dest, source, slidePartName) {
3478
+ const part = singleRelPart(dest.opc, slidePartName, COMMENTS_REL);
3479
+ const root = part?.dom.documentElement;
3480
+ if (!part || !root) return;
3481
+ const comments = getElements(root, "p:cm");
3482
+ if (comments.length === 0) return;
3483
+ const sourceAuthors = new Map(readCommentAuthors(source.opc, source.presentationPart.partName).map((a) => [a.id, a]));
3484
+ const register = authorRegistry(dest);
3485
+ const renumber = (cm) => {
3486
+ const author = sourceAuthors.get(numberValue(attr(cm, "authorId")));
3487
+ if (!author) return;
3488
+ const { authorId, idx } = register(author.name, author.initials);
3489
+ setAttr(cm, "authorId", String(authorId));
3490
+ setAttr(cm, "idx", String(idx));
3491
+ };
3492
+ comments.forEach(renumber);
3493
+ part.markDirty();
3494
+ }
3495
+ /**
3496
+ * Reset every author's `lastIdx` in the deck's registry to 0, for a deck with no comments left
3497
+ * (#244). `fromTemplate` strips the template's slides, and their comments with them, but the
3498
+ * registry keeps counting from the comments it removed, so the next comment would be numbered
3499
+ * after one the deck no longer has. `lastIdx` is the author's highest used index (ECMA-376
3500
+ * §19.4.2), and in an empty deck that is none. The authors themselves stay, with their ids and
3501
+ * colours, so a comment re-authored under the same name lands on the same entry.
3502
+ * @param dest - the deck whose slides were all removed
3503
+ */
3504
+ function resetCommentAuthorIndexes(dest) {
3505
+ const part = singleRelPart(dest.opc, dest.presentationPart.partName, COMMENT_AUTHORS_REL);
3506
+ const root = part?.dom.documentElement;
3507
+ if (!part || !root) return;
3508
+ const authors = getElements(root, "p:cmAuthor").filter((author) => attr(author, "lastIdx") !== "0");
3509
+ if (authors.length === 0) return;
3510
+ for (const author of authors) setAttr(author, "lastIdx", "0");
3511
+ part.markDirty();
3512
+ }
3513
+ // src/read/api/ops/slide-size.ts
3514
+ /**
3515
+ * pptx-ts: slide-size preconditions for the import surface
3403
3516
  *
3404
3517
  * Every import entry point starts by asking whether the two decks agree on canvas size, and
3405
3518
  * the five that asked wrote out the same comparison, the same `unknown`-printing formatter
@@ -3409,9 +3522,9 @@ function mergeEmbeddedFontEntries(dest, entries) {
3409
3522
  * except `importSlide`, and only when a rescale had been asked for.
3410
3523
  *
3411
3524
  * The two conditions are separated here, and the codes now mean what their names say:
3412
- * - `import/slide-size-unknown` — a deck does not declare `p:sldSz`, so there is no size to
3525
+ * - `import/slide-size-unknown`: a deck does not declare `p:sldSz`, so there is no size to
3413
3526
  * compare and no rescale to compute. Nothing the caller passes can make it comparable.
3414
- * - `import/slide-size-mismatch` — both sizes are known and they differ. This one *is*
3527
+ * - `import/slide-size-mismatch`: both sizes are known and they differ. This one *is*
3415
3528
  * answerable, which is why each caller supplies the escape hatch it offers.
3416
3529
  */
3417
3530
  /** A size as the error messages print it. */
@@ -3422,7 +3535,7 @@ function fmt(size) {
3422
3535
  * Both decks' sizes, or a throw when either deck does not declare one.
3423
3536
  *
3424
3537
  * Returned rather than asserted because every caller that needs both sizes known needs the
3425
- * values too — to compute a rescale — and TypeScript cannot narrow two parameters from one
3538
+ * values too, to compute a rescale, and TypeScript cannot narrow two parameters from one
3426
3539
  * assertion signature.
3427
3540
  *
3428
3541
  * @param target - this deck's slide size
@@ -3447,19 +3560,18 @@ function requireEqualSlideSize(target, incoming, api, hint = "") {
3447
3560
  if (known.widthEmu === source.widthEmu && known.heightEmu === source.heightEmu) return;
3448
3561
  throw new InvalidOptionError("import/slide-size-mismatch", `${api} requires equal slide sizes${hint ? ` (${hint})` : ""}; target is ${fmt(target)}, source is ${fmt(incoming)}`);
3449
3562
  }
3450
- /** Whether both sizes are known and equal — the question a caller with a rescale asks first. */
3563
+ /** Whether both sizes are known and equal: the question a caller with a rescale asks first. */
3451
3564
  function slideSizesMatch(target, incoming) {
3452
3565
  return !!target && !!incoming && target.widthEmu === incoming.widthEmu && target.heightEmu === incoming.heightEmu;
3453
3566
  }
3454
- //#endregion
3455
- //#region src/read/api/ops/append-slides.ts
3567
+ // src/read/api/ops/append-slides.ts
3456
3568
  /**
3457
- * ts-pptx: the body of {@link Presentation.appendSlides}
3569
+ * pptx-ts: the body of {@link Presentation.appendSlides}
3458
3570
  *
3459
3571
  * The hybrid "generate onto an existing deck" path: a slide producer authors slides, they are
3460
- * spliced into this package under fresh partnames, and every dependency each one carries —
3461
- * images, embedded and online media, hyperlinks, speaker notes, charts, intra-batch slide links
3462
- * — is wired into its `.rels`.
3572
+ * spliced into this package under fresh partnames, and every dependency each one carries
3573
+ * (images, embedded and online media, hyperlinks, speaker notes, review comments, charts,
3574
+ * intra-batch slide links) is wired into its `.rels`.
3463
3575
  *
3464
3576
  * Here rather than on the class for the reason `presentation.ts` states about the four import
3465
3577
  * bodies: the *contract* is the doc comment a caller reads and stays on the public method, while
@@ -3472,12 +3584,12 @@ function slideSizesMatch(target, incoming) {
3472
3584
  */
3473
3585
  const textEncoder$1 = new TextEncoder();
3474
3586
  /**
3475
- * Resolve `options.layout` — a layout *name* or a {@link LayoutHandle} — against this deck's
3476
- * gallery, with no silent fallback: an unusable value is one of three named errors rather than a
3587
+ * Resolve `options.layout` (a layout *name* or a {@link LayoutHandle}) against this deck's
3588
+ * gallery, with no silent fallback: an unusable value is one of four named errors rather than a
3477
3589
  * default layout, because a slide bound to the wrong layout is a deck that looks authored.
3478
3590
  *
3479
3591
  * Split out because it is the part of the append most likely to be wanted by a second caller, and
3480
- * because it is the only place `layout/ambiguous-name`, `layout/not-found` and
3592
+ * because it is the only place `layout/missing`, `layout/ambiguous-name`, `layout/not-found` and
3481
3593
  * `layout/foreign-handle` are raised.
3482
3594
  *
3483
3595
  * @param deck - the destination deck, whose `layouts()` gallery is searched
@@ -3486,6 +3598,8 @@ const textEncoder$1 = new TextEncoder();
3486
3598
  */
3487
3599
  function resolveLayoutTarget(deck, layout, api = "appendSlides") {
3488
3600
  const gallery = deck.layouts();
3601
+ const names = () => gallery.map((l) => JSON.stringify(l.name)).join(", ") || "(none)";
3602
+ if (layout == null) throw new InvalidOptionError("layout/missing", `${api}: options.layout is required, a layout name or a LayoutHandle from layouts(); available: ${names()}`);
3489
3603
  if (typeof layout !== "string") {
3490
3604
  if (!gallery.some((l) => l.partName === layout.partName)) throw new InvalidOptionError("layout/foreign-handle", `${api}: layout ${layout.partName} does not belong to this presentation`);
3491
3605
  return layout;
@@ -3493,10 +3607,7 @@ function resolveLayoutTarget(deck, layout, api = "appendSlides") {
3493
3607
  const matches = gallery.filter((l) => l.name === layout);
3494
3608
  if (matches.length > 1) throw new InvalidOptionError("layout/ambiguous-name", `${api}: layout name ${JSON.stringify(layout)} is ambiguous (${matches.length} layouts share it); pass a LayoutHandle from layouts() instead`);
3495
3609
  const [only] = matches;
3496
- if (!only) {
3497
- const names = gallery.map((l) => JSON.stringify(l.name)).join(", ");
3498
- throw new InvalidOptionError("layout/not-found", `${api}: no layout named ${JSON.stringify(layout)}; available: ${names || "(none)"}`);
3499
- }
3610
+ if (!only) throw new InvalidOptionError("layout/not-found", `${api}: no layout named ${JSON.stringify(layout)}; available: ${names()}`);
3500
3611
  return only;
3501
3612
  }
3502
3613
  /** Image parts behind the slide body's `image` rels, each keeping the id the body was built with. */
@@ -3528,8 +3639,20 @@ function wireAvMedia(deck, rels, partName, slide) {
3528
3639
  }
3529
3640
  }
3530
3641
  /**
3531
- * Online (external-link) video: two External rels share the link Target — the ECMA video rel and
3532
- * the MS-2007 media rel — with no media binary part and no content-type entry. The poster image is
3642
+ * A transition's start sound: one audio part behind the `audio` rel the body's `p:snd r:embed`
3643
+ * names. Registered as a Default extension entry, as {@link wireAvMedia} does.
3644
+ */
3645
+ function wireTransitionSound(deck, rels, partName, slide) {
3646
+ const sound = slide.transitionSound;
3647
+ if (!sound) return;
3648
+ const mediaPartName = deck.opc.reserveMediaPartName(sound.extn, "media");
3649
+ deck.opc.contentTypes.ensureDefault(sound.extn, sound.contentType);
3650
+ deck.opc.addPart(mediaPartName, sound.contentType, sound.bytes);
3651
+ rels.addWithId(`rId${sound.rId}`, AUDIO_REL, relativePartName(partName, mediaPartName));
3652
+ }
3653
+ /**
3654
+ * Online (external-link) video: two External rels share the link Target (the ECMA video rel and
3655
+ * the MS-2007 media rel), with no media binary part and no content-type entry. The poster image is
3533
3656
  * wired by {@link wireMedia}, which runs first.
3534
3657
  */
3535
3658
  function wireOnlineMedia(rels, slide) {
@@ -3544,7 +3667,7 @@ function wireHyperlinks(rels, slide) {
3544
3667
  }
3545
3668
  /**
3546
3669
  * Speaker notes. The notes part carries its own rel namespace, independent of the slide's:
3547
- * rId1 = notesMaster, rId2 = the slide it annotates, hyperlinks from rId3 — the order the
3670
+ * rId1 = notesMaster, rId2 = the slide it annotates, hyperlinks from rId3. That is the order the
3548
3671
  * generator's body was serialized against, so these are added by explicit id rather than left to
3549
3672
  * auto-numbering.
3550
3673
  *
@@ -3552,12 +3675,13 @@ function wireHyperlinks(rels, slide) {
3552
3675
  * so {@link wireAutoIdRels} adds it once every id the body does name is claimed.
3553
3676
  * @returns the notes part's name, or `null` when the slide has no notes
3554
3677
  */
3555
- function wireNotes(deck, partName, slide, sourceNotesMaster) {
3678
+ function wireNotes(deck, partName, slide, sourceNotesMaster, partBySourceNumber, index) {
3556
3679
  if (!slide.notes) return null;
3557
3680
  const notesMasterPartName = sourceNotesMaster ? ensureNotesMasterFromXml(deck, sourceNotesMaster) : null;
3558
3681
  const notesPartName = addNotesSlidePart(deck, slide.notes.xml, partName, notesMasterPartName);
3559
3682
  const notesRels = deck.opc.relationshipsFor(notesPartName);
3560
3683
  for (const h of slide.notes.hyperlinks) notesRels.addWithId(`rId${h.rId}`, HYPERLINK_REL, h.target, "External");
3684
+ wireSlideLinks(notesRels, notesPartName, slide.notes.slideLinks ?? [], partBySourceNumber, index);
3561
3685
  return notesPartName;
3562
3686
  }
3563
3687
  /**
@@ -3567,7 +3691,7 @@ function wireNotes(deck, partName, slide, sourceNotesMaster) {
3567
3691
  *
3568
3692
  * A chartEx chart differs in every other coordinate: the `chartEx{N}.xml` name family, the MS
3569
3693
  * chartex content type, the MS `chartEx` rel off the slide, and two mandatory sidecars at
3570
- * rId2/rId3 — without which PowerPoint reports the deck as corrupt (schema-valid but unopenable).
3694
+ * rId2/rId3, without which PowerPoint reports the deck as corrupt (schema-valid but unopenable).
3571
3695
  * `c.chartEx` carries both sidecar bodies; the generator built them, so nothing here reaches into
3572
3696
  * the emitters.
3573
3697
  */
@@ -3581,6 +3705,11 @@ function wireCharts(deck, rels, partName, slide) {
3581
3705
  deck.opc.addPart(embeddingPartName, XLSX_CONTENT_TYPE, c.embeddingBytes);
3582
3706
  const chartRels = deck.opc.relationshipsFor(chartPartName);
3583
3707
  chartRels.addWithId("rId1", PACKAGE_REL, relativePartName(chartPartName, embeddingPartName));
3708
+ for (const picture of c.pictures ?? []) {
3709
+ const mediaPartName = deck.opc.reserveMediaPartName(picture.extn);
3710
+ deck.opc.addPart(mediaPartName, picture.contentType, picture.bytes);
3711
+ chartRels.addWithId(`rId${picture.rId}`, IMAGE_REL, relativePartName(chartPartName, mediaPartName));
3712
+ }
3584
3713
  if (c.chartEx) {
3585
3714
  const colorsPartName = deck.opc.reservePartNameLike("/ppt/charts/colors1.xml");
3586
3715
  deck.opc.addPart(colorsPartName, CHART_COLOR_STYLE_CONTENT_TYPE, textEncoder$1.encode(c.chartEx.colorsXml));
@@ -3593,12 +3722,12 @@ function wireCharts(deck, rels, partName, slide) {
3593
3722
  }
3594
3723
  }
3595
3724
  /**
3596
- * Intra-batch slide-to-slide links: a `slide:N` in the source is repointed at the Nth appended
3597
- * slide's new partname, which is why pass 1 places every slide before any of this runs. A link out
3725
+ * Intra-batch slide-to-slide links, from a slide or from its notes: a `slide:N` in the source is
3726
+ * repointed at the Nth appended slide's new partname, which is why pass 1 places every slide before any of this runs. A link out
3598
3727
  * of the batch was refused before pass 1 by {@link requireLinksInBatch}.
3599
3728
  */
3600
- function wireSlideLinks(rels, partName, slide, partBySourceNumber, index) {
3601
- for (const link of slide.slideLinks) {
3729
+ function wireSlideLinks(rels, partName, links, partBySourceNumber, index) {
3730
+ for (const link of links) {
3602
3731
  const targetPartName = partBySourceNumber.get(link.sourceSlideNumber);
3603
3732
  if (!targetPartName) throw new InternalError("import/slide-link-not-placed", `appendSlides: slide ${index} links to source slide ${link.sourceSlideNumber}, which was checked against the batch but has no appended slide`);
3604
3733
  rels.addWithId(`rId${link.rId}`, SLIDE_REL, relativePartName(partName, targetPartName));
@@ -3611,12 +3740,13 @@ function wireSlideLinks(rels, partName, slide, partBySourceNumber, index) {
3611
3740
  */
3612
3741
  function requireLinksInBatch(slides) {
3613
3742
  slides.forEach((slide, index) => {
3614
- for (const link of slide.slideLinks) if (link.sourceSlideNumber > slides.length) throw new InvalidOptionError("import/unresolved-slide-link", `appendSlides: slide ${index} links to source slide ${link.sourceSlideNumber}, which is not among the appended slides`);
3743
+ for (const link of [...slide.slideLinks, ...slide.notes?.slideLinks ?? []]) if (link.sourceSlideNumber > slides.length) throw new InvalidOptionError("import/unresolved-slide-link", `appendSlides: slide ${index} links to source slide ${link.sourceSlideNumber}, which is not among the appended slides`);
3615
3744
  });
3616
3745
  }
3617
3746
  /**
3618
- * The first of pass 2's two phases: every rel the slide body names by id — media, embedded and
3619
- * online media, hyperlinks, charts, slide links — each added with the rId the generator wrote.
3747
+ * The first of pass 2's two phases: every rel the slide body names by id (media, embedded and
3748
+ * online media, a transition sound, hyperlinks, charts, slide links), each added with the rId the
3749
+ * generator wrote.
3620
3750
  * Also creates the notes part, whose own rels are fixed ids too.
3621
3751
  *
3622
3752
  * A new rel the body references by id belongs here, and nowhere after {@link wireAutoIdRels}.
@@ -3626,24 +3756,26 @@ function wireFixedIdRels(deck, rels, placed, sourceNotesMaster, partBySourceNumb
3626
3756
  const { slide, partName } = placed;
3627
3757
  wireMedia(deck, rels, partName, slide);
3628
3758
  wireAvMedia(deck, rels, partName, slide);
3759
+ wireTransitionSound(deck, rels, partName, slide);
3629
3760
  wireOnlineMedia(rels, slide);
3630
3761
  wireHyperlinks(rels, slide);
3631
- const notesPartName = wireNotes(deck, partName, slide, sourceNotesMaster);
3762
+ const notesPartName = wireNotes(deck, partName, slide, sourceNotesMaster, partBySourceNumber, index);
3632
3763
  wireCharts(deck, rels, partName, slide);
3633
- wireSlideLinks(rels, partName, slide, partBySourceNumber, index);
3764
+ wireSlideLinks(rels, partName, slide.slideLinks, partBySourceNumber, index);
3634
3765
  return notesPartName;
3635
3766
  }
3636
3767
  /**
3637
- * The second phase: the rels the slide body names by no id — its notes and its layout — numbered
3638
- * by `add()`, which takes one past the highest id present.
3768
+ * The second phase: the rels the slide body names by no id (its notes, its comments and its
3769
+ * layout), numbered by `add()`, which takes one past the highest id present.
3639
3770
  *
3640
3771
  * Strictly after {@link wireFixedIdRels}. The generator numbers a slide's rels from rId1, so an
3641
3772
  * auto id taken before a fixed one is claimed is routinely that fixed one: the notes rel used to
3642
3773
  * be added in the middle of the first phase, and a slide carrying notes and a chart or a slide
3643
3774
  * link threw `relationship/duplicate-id`.
3644
3775
  */
3645
- function wireAutoIdRels(rels, partName, notesPartName, layoutPartName) {
3776
+ function wireAutoIdRels(rels, partName, notesPartName, commentsPartName, layoutPartName) {
3646
3777
  if (notesPartName) rels.add(NOTES_SLIDE_REL, relativePartName(partName, notesPartName));
3778
+ if (commentsPartName) rels.add(COMMENTS_REL, relativePartName(partName, commentsPartName));
3647
3779
  rels.add(SLIDE_LAYOUT_REL, relativePartName(partName, layoutPartName));
3648
3780
  }
3649
3781
  /**
@@ -3651,7 +3783,7 @@ function wireAutoIdRels(rels, partName, notesPartName, layoutPartName) {
3651
3783
  * {@link Presentation.appendSlides}.
3652
3784
  */
3653
3785
  async function appendSlides(deck, source, options) {
3654
- const target = resolveLayoutTarget(deck, options.layout);
3786
+ const target = resolveLayoutTarget(deck, options?.layout);
3655
3787
  const extracted = await source.extractSlides(pickDefined(options, ["onMediaError"]));
3656
3788
  requireEqualSlideSize(deck.slideSize, {
3657
3789
  widthEmu: extracted.widthEmu,
@@ -3675,15 +3807,16 @@ async function appendSlides(deck, source, options) {
3675
3807
  placed.forEach((placedSlide, i) => {
3676
3808
  const rels = deck.opc.relationshipsFor(placedSlide.partName);
3677
3809
  const notesPartName = wireFixedIdRels(deck, rels, placedSlide, extracted.notesMaster, partBySourceNumber, i);
3678
- wireAutoIdRels(rels, placedSlide.partName, notesPartName, target.partName);
3810
+ const comments = placedSlide.slide.comments;
3811
+ const commentsPartName = comments?.length ? addCommentsPart(deck, comments) : null;
3812
+ wireAutoIdRels(rels, placedSlide.partName, notesPartName, commentsPartName, target.partName);
3679
3813
  const at = options.at === void 0 ? void 0 : options.at + i;
3680
3814
  added.push(deck.insertSlidePart(placedSlide.part, at));
3681
3815
  });
3682
3816
  carryGeneratedEmbeddedFonts(deck, extracted.embeddedFonts || []);
3683
3817
  return added;
3684
3818
  }
3685
- //#endregion
3686
- //#region src/read/api/ops/prune.ts
3819
+ // src/read/api/ops/prune.ts
3687
3820
  /**
3688
3821
  * Content types that are shared deck chrome, not owned by any one slide: the `deck` rows of
3689
3822
  * {@link SHARED_PARTS}, reached through the presentation → master → layout → theme graph or named
@@ -3815,8 +3948,7 @@ function isReferenced(pres, partName) {
3815
3948
  function relationshipOwners(pres) {
3816
3949
  return [...[...pres.opc.parts.keys()].filter((partName) => !partName.endsWith(".rels")), "/"];
3817
3950
  }
3818
- //#endregion
3819
- //#region src/read/api/ops/import-memo.ts
3951
+ // src/read/api/ops/import-memo.ts
3820
3952
  var ImportMemo = class {
3821
3953
  #registries = /* @__PURE__ */ new Map();
3822
3954
  #rescaled = /* @__PURE__ */ new Map();
@@ -3840,14 +3972,13 @@ var ImportMemo = class {
3840
3972
  for (const partName of gone) this.#rescaled.delete(partName);
3841
3973
  }
3842
3974
  };
3843
- //#endregion
3844
- //#region src/read/api/ops/flatten.ts
3975
+ // src/read/api/ops/flatten.ts
3845
3976
  /**
3846
3977
  * Baking a slide's theme dependencies into the slide itself, for `Presentation.importSlide` /
3847
3978
  * `importShape`.
3848
3979
  *
3849
3980
  * A slide imported into another deck is rebound to the *destination* master, so everything it
3850
- * resolved symbolically against its own theme silently re-resolves against a different one — its
3981
+ * resolved symbolically against its own theme silently re-resolves against a different one: its
3851
3982
  * scheme colours change, its style-matrix fills change, its placeholders snap to different
3852
3983
  * geometry and type sizes. The `theme: 'preserve'` mode exists to stop that: each pass here
3853
3984
  * resolves a dependency against the **source** theme (via `read/oxml/theme.ts` and
@@ -3856,25 +3987,25 @@ var ImportMemo = class {
3856
3987
  *
3857
3988
  * What gets flattened, and why each one matters:
3858
3989
  *
3859
- * 1. **`a:schemeClr` tokens** — rewritten to the literal `a:srgbClr` the source `clrMap` +
3990
+ * 1. **`a:schemeClr` tokens**: rewritten to the literal `a:srgbClr` the source `clrMap` +
3860
3991
  * `clrScheme` produce. Child transforms (`lumMod`/`shade`/`alpha`/…) are carried through
3861
3992
  * untouched, so tints and shades render identically; only the *base* reference is swapped,
3862
3993
  * never the transform math.
3863
- * 2. **Style-matrix refs** — a shape's `p:style` (`lnRef`/`fillRef`/`effectRef`) indexes the
3994
+ * 2. **Style-matrix refs**: a shape's `p:style` (`lnRef`/`fillRef`/`effectRef`) indexes the
3864
3995
  * theme `fmtScheme`; the indexed entry is resolved into an explicit `spPr` fill/line/effect
3865
3996
  * (with its `phClr` substituted) and the ref neutralized so it cannot re-resolve. The
3866
- * `fontRef` is deliberately left intact so its font can re-bind to the destination theme —
3867
- * the "normalize fonts on attach" bonus.
3868
- * 3. **Placeholder-inherited run colour, size and weight** — a run that sets none of its own
3997
+ * `fontRef` is deliberately left intact so its font can re-bind to the destination theme
3998
+ * (the "normalize fonts on attach" bonus).
3999
+ * 3. **Placeholder-inherited run colour, size and weight**: a run that sets none of its own
3869
4000
  * takes them from the source placeholder → layout → master text-style chain. Rebinding
3870
4001
  * replaces that chain, so each is resolved from the source styles and written onto the run.
3871
- * Typeface (`a:latin`) is deliberately *not* baked — it re-binds along with `fontRef`.
4002
+ * Typeface (`a:latin`) is deliberately *not* baked; it re-binds along with `fontRef`.
3872
4003
  * A shape that is not a placeholder takes the same properties from the presentation's
3873
4004
  * `p:defaultTextStyle` instead, which the rebind swaps for the destination's, so those
3874
4005
  * are baked from the source one. A table cell's text takes its size from the master's
3875
4006
  * `p:otherStyle`, and its weight too where the table style states none, so those are
3876
4007
  * baked from the source master.
3877
- * 4. **Placeholder-inherited geometry** — a placeholder with no own `a:xfrm` takes position and
4008
+ * 4. **Placeholder-inherited geometry**: a placeholder with no own `a:xfrm` takes position and
3878
4009
  * size from the matching source layout/master placeholder; without baking it, a title snaps
3879
4010
  * to the destination default and often clips off-canvas.
3880
4011
  *
@@ -3897,7 +4028,7 @@ var ImportMemo = class {
3897
4028
  * 4. bake each placeholder run's effective colour and size/weight (inherited from
3898
4029
  * the source layout/master text styles) explicitly onto the run, each other
3899
4030
  * shape's run the ones it takes from the source `p:defaultTextStyle`, and each
3900
- * table cell's run the ones it takes from the source `p:otherStyle`;
4031
+ * table cell's run the ones it takes from the source `p:otherStyle` and theme;
3901
4032
  * 5. rewrite every remaining `a:schemeClr` to its literal `a:srgbClr`.
3902
4033
  *
3903
4034
  * Steps run in this order so the inherited/materialized backgrounds are present
@@ -3917,7 +4048,7 @@ function flattenSlide(slideRoot, ctx) {
3917
4048
  resolveSchemeColors(slideRoot, ctx);
3918
4049
  }
3919
4050
  /**
3920
- * Flatten a single lifted shape's theme dependencies in place — the shape-scoped
4051
+ * Flatten a single lifted shape's theme dependencies in place: the shape-scoped
3921
4052
  * subset of {@link flattenSlide} used by `Presentation.importShape` `preserve`
3922
4053
  * mode. It runs every pass that resolves a *shape's* theme references against the
3923
4054
  * source theme (style-matrix refs, placeholder-inherited geometry/colour/size/
@@ -3938,7 +4069,7 @@ function flattenSlide(slideRoot, ctx) {
3938
4069
  *
3939
4070
  * `shapeRoot` must be an element whose *descendants* include the lifted shape
3940
4071
  * (the passes match via `getElementsByTagNameNS`, which excludes the root element
3941
- * itself) — the caller wraps the imported `p:sp`/`p:pic`/`p:graphicFrame`/`p:grpSp`
4072
+ * itself), so the caller wraps the imported `p:sp`/`p:pic`/`p:graphicFrame`/`p:grpSp`
3942
4073
  * in a throwaway container before calling. The caller marks the part dirty.
3943
4074
  */
3944
4075
  function flattenShape(shapeRoot, ctx) {
@@ -3955,7 +4086,7 @@ function flattenShape(shapeRoot, ctx) {
3955
4086
  }
3956
4087
  /**
3957
4088
  * Restyle a rebound slide in place (the `theme: 'restyle'` mode): the exact
3958
- * inverse of {@link flattenSlide}. It bakes *nothing* — leaving every
4089
+ * inverse of {@link flattenSlide}. It bakes *nothing*: leaving every
3959
4090
  * `a:schemeClr`/style-matrix ref and `p:bg` `bgRef` symbolic is the whole point,
3960
4091
  * so they re-resolve against the *destination* master's `clrMap` + theme once the
3961
4092
  * slide is rebound. The single mutation is dropping the slide's own colour-map
@@ -3978,14 +4109,14 @@ function restyleSlide(slideRoot) {
3978
4109
  * destination theme; a literal matching no slot (the common case) is left exactly
3979
4110
  * as authored. Transform children (`lumMod`/`shade`/`alpha`/…) are carried across.
3980
4111
  *
3981
- * Plain `restyle` cannot re-brand a literal — it carries no theme reference. This
4112
+ * Plain `restyle` cannot re-brand a literal, since it carries no theme reference. This
3982
4113
  * re-introduces one by matching the literal's RGB against the slots the *source*
3983
4114
  * theme defined, emitting the scheme token that routes through the source `clrMap`
3984
4115
  * (so a literal equal to the source `accent1` slot becomes `schemeClr accent1`,
3985
4116
  * which the destination `clrMap`/theme then re-resolve). Slots are matched in
3986
4117
  * `clrScheme` order, so the first slot defining a given RGB wins when several share
3987
4118
  * it. Opt-in because it deliberately reinterprets authored literals as theme
3988
- * colours — visual QA territory, the same caveat as the rest of `restyle`.
4119
+ * colours: visual QA territory, the same caveat as the rest of `restyle`.
3989
4120
  */
3990
4121
  function remapLiteralColors(slideRoot, ctx) {
3991
4122
  const slotByHex = reverseClrScheme(ctx.clrScheme);
@@ -4074,7 +4205,7 @@ function resolvePlaceholderRunColors(slideRoot, ctx) {
4074
4205
  * `resolve` is asked once per *list level* per shape and memoized, because walking the
4075
4206
  * layout/master style chain is the expensive half and every paragraph at the same level gets
4076
4207
  * the same answer. `write` then runs per run, and owns the decision to skip a run the slide
4077
- * already fixes — the two passes ask that question differently (one colour check versus three
4208
+ * already fixes. The two passes ask that question differently (one colour check versus three
4078
4209
  * independent property checks), so it stays on their side of the boundary rather than becoming
4079
4210
  * a predicate parameter only one caller could use.
4080
4211
  *
@@ -4169,7 +4300,7 @@ function resolvePlaceholderGeometry(slideRoot, ctx) {
4169
4300
  * We resolve the effective anchor from the source chain and write it explicitly.
4170
4301
  * Shapes whose `a:bodyPr` already fixes `@anchor`, and placeholders with no
4171
4302
  * resolvable inherited anchor, are left untouched. Other `a:bodyPr` knobs (insets,
4172
- * autofit) are left as authored — they have sane defaults a plain shape keeps.
4303
+ * autofit) are left as authored; they have sane defaults a plain shape keeps.
4173
4304
  */
4174
4305
  function resolvePlaceholderBodyPr(shapeRoot, ctx) {
4175
4306
  forEachPlaceholderTextBody(shapeRoot, ctx, (txBody, type, idx) => {
@@ -4182,21 +4313,20 @@ function resolvePlaceholderBodyPr(shapeRoot, ctx) {
4182
4313
  }
4183
4314
  /**
4184
4315
  * Bake the placeholder-inherited list style onto a lifted shape's text body (the
4185
- * {@link flattenShape} placeholder-demotion path). A placeholder's per-level
4186
- * *paragraph* formatting — indent (`marL`/`indent`), bullets (`a:buChar`/
4187
- * `a:buAutoNum`/`a:buNone`), alignment, and the level `a:defRPr` — is inherited
4188
- * from the source layout/master placeholder `a:lstStyle` and the master
4189
- * `p:txStyles` category style. Run colour/size are baked onto each run by the
4190
- * sibling passes, but paragraph-level defaults live here; once
4191
- * {@link demotePlaceholders} strips the `p:ph` the shape stops inheriting them, so
4192
- * bullets and indents would vanish. We materialize the effective list style onto
4193
- * the shape's `p:txBody/a:lstStyle`.
4316
+ * {@link flattenShape} placeholder-demotion path). A placeholder inherits its per-level
4317
+ * *paragraph* formatting from the source layout/master placeholder `a:lstStyle` and
4318
+ * the master `p:txStyles` category style: indent (`marL`/`indent`), bullets
4319
+ * (`a:buChar`/`a:buAutoNum`/`a:buNone`), alignment, and the level `a:defRPr`. Run
4320
+ * colour/size are baked onto each run by the sibling passes, but paragraph-level
4321
+ * defaults live here; once {@link demotePlaceholders} strips the `p:ph` the shape
4322
+ * stops inheriting them, so bullets and indents would vanish. We materialize the
4323
+ * effective list style onto the shape's `p:txBody/a:lstStyle`.
4194
4324
  *
4195
4325
  * Resolution is per *level*, most specific tier wins whole: the slide's own level
4196
4326
  * (if it defines one) is kept verbatim, else the first source tier that defines it
4197
4327
  * (layout placeholder, then master placeholder, then master category style) is
4198
4328
  * cloned. This is a whole-element overlay, not the per-attribute merge PowerPoint
4199
- * does — but explicit paragraph `a:pPr` on the slide's own runs travels with the
4329
+ * does, but explicit paragraph `a:pPr` on the slide's own runs travels with the
4200
4330
  * shape and still wins, so this only supplies defaults for the inherited case
4201
4331
  * (paragraphs that set no `a:pPr` of their own). Scheme colours in the cloned
4202
4332
  * levels are resolved by the later `resolveSchemeColors` pass.
@@ -4223,7 +4353,7 @@ function resolvePlaceholderListStyle(shapeRoot, ctx) {
4223
4353
  * Strip the `p:ph` marker from every placeholder shape in a lifted subtree so it
4224
4354
  * becomes a self-contained ordinary shape (the {@link flattenShape} path only). By
4225
4355
  * the time this runs, the shape's inherited geometry, colour, run size, anchor, and
4226
- * list style are all baked explicitly, so it no longer needs — and must not keep —
4356
+ * list style are all baked explicitly, so it no longer needs (and must not keep)
4227
4357
  * its placeholder identity: a surviving `p:ph` would re-resolve against the *host*
4228
4358
  * deck's layout/master placeholder of the same type/idx (wrong inheritance, or a
4229
4359
  * fallback when the host has none) and could collide with the host slide's own
@@ -4241,7 +4371,7 @@ function demotePlaceholders(shapeRoot) {
4241
4371
  * {@link resolvePlaceholderRunColors}: for each placeholder run that sets no
4242
4372
  * `sz`/`b`/`i` of its own (nor at paragraph/text-body level on the *slide*),
4243
4373
  * resolve the value it would inherit from the source `slideLayout`/`slideMaster`
4244
- * text styles — per paragraph list level — and write it explicitly onto the run's
4374
+ * text styles, per paragraph list level, and write it explicitly onto the run's
4245
4375
  * `a:rPr`. Each property resolves independently up the chain. Typeface (`a:latin`)
4246
4376
  * is left to re-bind to the destination theme, as the colour pass does for the `fontRef`.
4247
4377
  */
@@ -4294,25 +4424,26 @@ function resolveDefaultTextStyleRuns(root, ctx) {
4294
4424
  }
4295
4425
  }
4296
4426
  /**
4297
- * Bake what a table cell's runs take from the source master's `p:otherStyle`: size, and bold and
4298
- * italic where the cell's table style states neither, per paragraph level, wherever the run, its
4299
- * paragraph and the cell's own list style state none of them.
4427
+ * Bake what a table cell's runs take from the source deck: size, and bold and italic where the
4428
+ * cell's table style states neither, from the master's `p:otherStyle` per paragraph level, and the
4429
+ * colour from the table style's text style, else `tx1`, resolved against the source theme. Each is
4430
+ * written wherever the run, its paragraph and the cell's own list style state none of it.
4300
4431
  *
4301
4432
  * Cell text resolves through `p:otherStyle`, not `p:defaultTextStyle` (`TableCell.textFrame`), and
4302
- * the rebind swaps the source master for the destination's, so without this a cell's text changes
4303
- * size between two decks whose masters differ there. PowerPoint's Keep Source Formatting paste
4304
- * writes nothing onto the cells; it keeps them on a copy of the source master instead
4305
- * (`test/read/fixtures/authoring/probe-table-text-paste.ps1`), which is the look this pins.
4433
+ * the rebind swaps the source master and theme for the destination's, so without this a cell's text
4434
+ * changes size and colour between two decks whose masters or themes differ. PowerPoint's Keep Source
4435
+ * Formatting paste writes nothing onto the cells; it keeps them on a copy of the source master
4436
+ * instead (`test/read/fixtures/authoring/probe-table-text-paste.ps1`), which is the look this pins.
4306
4437
  *
4307
- * The table style travels with the slide, so what it states is left to it. Where the table names a
4308
- * style the source does not define, a built-in PowerPoint draws from its own definition, and bold
4309
- * and italic are left alone because what that style states is unknown. A cell's colour and face do
4310
- * not come from `p:otherStyle` at all, so they are not visited.
4438
+ * Only the table's style id travels with the slide, and PowerPoint resolves that id against its own
4439
+ * built-in gallery, never a definition in the package. The source's `tableStyles.xml` says what the
4440
+ * style states, so bold and italic it states are left to it. Where the source does not define the
4441
+ * style, bold, italic and colour are left alone because what the style states is unknown. The face
4442
+ * re-binds to the destination theme, as it does for every other text tier.
4311
4443
  */
4312
4444
  function resolveTableCellRuns(root, ctx) {
4313
4445
  const txStyles = ctx.masterRoot ? firstChild(ctx.masterRoot, "p:txStyles") : null;
4314
4446
  const otherStyle = txStyles && firstChild(txStyles, "p:otherStyle");
4315
- if (!otherStyle) return;
4316
4447
  for (const tbl of descendantsByTag(root, OOXML_NS.a, "tbl")) {
4317
4448
  const tblPr = firstChild(tbl, "a:tblPr");
4318
4449
  const styleId = (tblPr && firstChild(tblPr, "a:tableStyleId"))?.textContent?.trim() || null;
@@ -4335,25 +4466,51 @@ function resolveTableCellRuns(root, ctx) {
4335
4466
  const txBody = firstChild(tc, "a:txBody");
4336
4467
  if (!txBody) return;
4337
4468
  const styled = style ? resolveTableCellTextStyle(style, flags, rowIndex, colIndex, rows.length, colCount, ctx) : null;
4469
+ const color = styleUnknown ? null : tableCellTextColor(styled, ownerDocumentOf(tbl), ctx);
4338
4470
  const cellLst = firstChild(txBody, "a:lstStyle");
4339
4471
  for (const p of getElements(txBody, "a:p")) {
4340
4472
  const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
4341
4473
  if (runs.length === 0) continue;
4342
4474
  const pPr = firstChild(p, "a:pPr");
4343
4475
  const level = (pPr && numberValue(attr(pPr, "lvl"))) ?? 0;
4344
- const defRPr = lstStyleLevelDefRPr(otherStyle, level);
4345
- if (!defRPr) continue;
4476
+ const defRPr = otherStyle && lstStyleLevelDefRPr(otherStyle, level);
4346
4477
  const props = {
4347
- sz: attr(defRPr, "sz"),
4348
- b: styleUnknown || styled?.bold != null ? null : attr(defRPr, "b"),
4349
- i: styleUnknown || styled?.italic != null ? null : attr(defRPr, "i")
4478
+ sz: defRPr ? attr(defRPr, "sz") : null,
4479
+ b: !defRPr || styleUnknown || styled?.bold != null ? null : attr(defRPr, "b"),
4480
+ i: !defRPr || styleUnknown || styled?.italic != null ? null : attr(defRPr, "i")
4350
4481
  };
4351
- for (const run of runs) writeRunProps(run, props, pPr, cellLst, level);
4482
+ for (const run of runs) {
4483
+ writeRunProps(run, props, pPr, cellLst, level);
4484
+ if (color && !slideDefinesColor(run, pPr, cellLst, level)) writeRunColor(run, color);
4485
+ }
4352
4486
  }
4353
4487
  });
4354
4488
  });
4355
4489
  }
4356
4490
  }
4491
+ /**
4492
+ * The colour a cell's text paints on the source deck: what its table style's text style names,
4493
+ * else `tx1`, as `TableCell.textFrame` resolves it. The transforms are rebuilt as elements so
4494
+ * {@link writeRunColor} re-emits them.
4495
+ */
4496
+ function tableCellTextColor(styled, doc, ctx) {
4497
+ if (styled?.color) {
4498
+ const transforms = styled.color.transforms.map(({ name, value }) => {
4499
+ const t = createElement(doc, `a:${name}`);
4500
+ if (value !== null) setAttr(t, "val", value);
4501
+ return t;
4502
+ });
4503
+ return {
4504
+ hex: styled.color.hex,
4505
+ transforms
4506
+ };
4507
+ }
4508
+ const tx1 = resolveSchemeToken("tx1", ctx);
4509
+ return tx1 ? {
4510
+ hex: tx1,
4511
+ transforms: []
4512
+ } : null;
4513
+ }
4357
4514
  /** The source deck's `a:tblStyle` with this id, or `null` when the source defines none. */
4358
4515
  function sourceTableStyle(ctx, styleId) {
4359
4516
  if (!ctx.tableStyles) return null;
@@ -4448,15 +4605,14 @@ function neutralizeRef(ref) {
4448
4605
  setAttr(ref, "idx", "0");
4449
4606
  for (const child of childElements(ref)) ref.removeChild(child);
4450
4607
  }
4451
- //#endregion
4452
- //#region src/read/api/ops/carried-rels.ts
4608
+ // src/read/api/ops/carried-rels.ts
4453
4609
  /**
4454
4610
  * Relationship rewriting for content carried between packages.
4455
4611
  *
4456
4612
  * When a shape or decoration is deep-copied out of a source deck, every relationship
4457
4613
  * reference it carries (`r:embed` on a picture fill, `r:id` on a chart frame, `r:link` on a
4458
4614
  * linked image, …) still names an id in the *source* part's relationship list. Left alone
4459
- * those ids either dangle or — worse — silently resolve to whatever the destination part
4615
+ * those ids either dangle or, worse, silently resolve to whatever the destination part
4460
4616
  * happens to have under the same id. This rewrites each one to a fresh relationship on the
4461
4617
  * destination part, copying the referenced part into the destination package on first sight.
4462
4618
  *
@@ -4516,8 +4672,7 @@ function carryRel(ctx, sourceRels, id, destPartName, destRels, relIdMap, owned)
4516
4672
  if (!ownsIt) relIdMap.set(key, newId);
4517
4673
  return newId;
4518
4674
  }
4519
- //#endregion
4520
- //#region src/read/api/ops/flatten-context.ts
4675
+ // src/read/api/ops/flatten-context.ts
4521
4676
  /**
4522
4677
  * The background the slide effectively inherits from its source subgraph: the layout's
4523
4678
  * `p:bg`, else the master's. Returns `null` when the slide carries its own `p:bg` (it stays
@@ -4550,8 +4705,7 @@ function sourceFlattenContext(sourceOpc, slidePartName) {
4550
4705
  tableStyles: sourceOpc.partsByContentType("application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml")[0]?.dom.documentElement ?? null
4551
4706
  };
4552
4707
  }
4553
- //#endregion
4554
- //#region src/read/api/ops/table-styles.ts
4708
+ // src/read/api/ops/table-styles.ts
4555
4709
  const TABLE_STYLES_DEFAULT_GUID = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}";
4556
4710
  const textEncoder = new TextEncoder();
4557
4711
  /**
@@ -4560,7 +4714,7 @@ const textEncoder = new TextEncoder();
4560
4714
  * table resolves its `@tableStyleId` against the *destination* `tableStyles` and
4561
4715
  * silently falls back when that id is absent; the source `<a:tblStyle>` is itself
4562
4716
  * symbolic (scheme colours), so copying it verbatim under the **same** id lets the
4563
- * table keep its structure while re-branding to this deck's theme — no table-XML
4717
+ * table keep its structure while re-branding to this deck's theme, with no table-XML
4564
4718
  * rewrite needed. Idempotent: an id this deck already defines is left as-is, and a
4565
4719
  * referenced id with no source definition is skipped. Creates and wires a
4566
4720
  * `tableStyles.xml` part if this deck has none.
@@ -4587,7 +4741,7 @@ function copySourceTableStyles(dest, sourceOpc, slideRoot) {
4587
4741
  }
4588
4742
  /**
4589
4743
  * Append each source `<a:tblStyle>` this deck does not already define, keyed by
4590
- * `styleId` — the shared core of {@link copySourceTableStyles} (which offers only
4744
+ * `styleId`: the shared core of {@link copySourceTableStyles} (which offers only
4591
4745
  * the styles a restyled slide references) and {@link carryTableStyles} (which
4592
4746
  * offers the source's whole list). Destination-wins per id: a style this deck
4593
4747
  * already defines is left untouched, so a re-call adds nothing. Returns whether
@@ -4609,14 +4763,14 @@ function addTableStyles(destList, styles) {
4609
4763
  * Copy the source deck's **whole** `tableStyles.xml` into this deck: every
4610
4764
  * `<a:tblStyle>` it defines, plus its `a:tblStyleLst@def` (the default table
4611
4765
  * style). Presentation-level, so a separate traversal from the master/layout copy
4612
- * chain — and whole-deck, since `tableStyles.xml` does not record which style
4766
+ * chain, and whole-deck, since `tableStyles.xml` does not record which style
4613
4767
  * belongs to which master. See `ImportSlideMastersOptions.tableStyles`.
4614
4768
  *
4615
4769
  * Styles union by `styleId` (destination-wins per id, via {@link addTableStyles}),
4616
4770
  * but `def` is **source-wins**: a caller asking for the source's table styling
4617
4771
  * wants its default too, and the destination's `def` is typically a generator stub
4618
4772
  * rather than a deliberate choice. Carrying the styles without the `def` would be
4619
- * the worse half-measure — the standard default GUID is one most templates also
4773
+ * the worse half-measure: the standard default GUID is one most templates also
4620
4774
  * define, so a new table would silently resolve to the wrong style rather than
4621
4775
  * visibly to none. Idempotent: a re-call re-adds nothing and re-sets `def` to the
4622
4776
  * same value.
@@ -4653,26 +4807,25 @@ function ensureTableStylesPart(dest) {
4653
4807
  dest.opc.relationshipsFor(dest.presentationPart.partName).add(TABLE_STYLES_REL, relativePartName(dest.presentationPart.partName, partName));
4654
4808
  return part;
4655
4809
  }
4656
- //#endregion
4657
- //#region src/read/api/ops/import-slide.ts
4810
+ // src/read/api/ops/import-slide.ts
4658
4811
  /**
4659
4812
  * The three ways a slide can be brought across from another deck.
4660
4813
  *
4661
4814
  * {@link Presentation.importSlide} picks one by `options.theme`, and the difference between
4662
4815
  * them is entirely about what happens to the slide's *look*:
4663
4816
  *
4664
- * - **`copy`** — not here. It copies the source theme subgraph wholesale via `copyPart`, so
4817
+ * - **`copy`**: not here. It copies the source theme subgraph wholesale via `copyPart`, so
4665
4818
  * the slide keeps its look by keeping its own theme; nothing needs rewriting.
4666
- * - **`preserve`** ({@link importSlidePreserve}) — rebind to this deck's master, then bake
4819
+ * - **`preserve`** ({@link importSlidePreserve}): rebind to this deck's master, then bake
4667
4820
  * the source theme into the slide XML. The slide looks the same as it did; it just no
4668
4821
  * longer depends on the theme it came from.
4669
- * - **`restyle`** ({@link importSlideRestyle}) — rebind and bake *nothing*, so the slide's
4822
+ * - **`restyle`** ({@link importSlideRestyle}): rebind and bake *nothing*, so the slide's
4670
4823
  * symbolic theme references re-resolve against the destination theme and it re-brands.
4671
4824
  *
4672
4825
  * The two share {@link importSlideRebind} and are exact inverses on top of it: preserve
4673
4826
  * resolves every reference it can, restyle resolves none. Any baking added to the shared
4674
4827
  * rebind would break restyle by pinning the slide to its source look, which is why the
4675
- * rebind carries no theme handling of its own — not even the inherited background.
4828
+ * rebind carries no theme handling of its own, not even the inherited background.
4676
4829
  *
4677
4830
  * These were private methods on `Presentation`, where they made the read model's own surface
4678
4831
  * (open a deck, walk slides, read shapes) hard to see: the import machinery was roughly two
@@ -4703,17 +4856,17 @@ function importSlidePreserve(dest, ctx, source, sourceSlide, carryGraphics) {
4703
4856
  }
4704
4857
  /**
4705
4858
  * Import a slide in `restyle` mode: rebind it to this deck's master/layout and then
4706
- * {@link restyleSlide} it — drop its colour map override but bake *nothing*, so its symbolic
4859
+ * {@link restyleSlide} it: drop its colour map override but bake *nothing*, so its symbolic
4707
4860
  * theme references re-resolve against the destination theme and the slide re-brands.
4708
4861
  *
4709
4862
  * The deliberate inverse of `preserve`: no flatten, no inherited-background bake, no
4710
- * placeholder colour/size/geometry bake — every one of those would pin the slide to its
4863
+ * placeholder colour/size/geometry bake. Every one of those would pin the slide to its
4711
4864
  * source look, the opposite of re-branding. Carried decorations are left symbolic too, so
4712
4865
  * they re-brand along with the slide.
4713
4866
  *
4714
4867
  * With `remapLiterals` it additionally force-remaps the slide's source-theme literal colours
4715
- * back to symbolic scheme colours and copies any referenced source table style into this deck
4716
- * — the two things plain `restyle` cannot re-brand.
4868
+ * back to symbolic scheme colours and copies any referenced source table style into this deck:
4869
+ * the two things plain `restyle` cannot re-brand.
4717
4870
  * @param {Presentation} dest - the destination deck
4718
4871
  * @param {ImportContext} ctx - the open import out of the source package
4719
4872
  * @param {Presentation} source - the source deck
@@ -4739,11 +4892,11 @@ function importSlideRestyle(dest, ctx, source, sourceSlide, carryGraphics, remap
4739
4892
  /**
4740
4893
  * The rebind shared by `preserve` and `restyle`: copy the slide bytes into a fresh part,
4741
4894
  * rebuild its relationships (drop notes, repoint the `slideLayout` rel at this deck's
4742
- * existing layout, copy every other internal target — media/charts — and pass externals
4895
+ * existing layout, copy every other internal target (media/charts), and pass externals
4743
4896
  * through), and optionally bake the source master/layout decorations onto the slide. Returns
4744
4897
  * the new part, its name, and its live root element for the caller's mode-specific pass.
4745
4898
  *
4746
- * This carries *no* theme baking of its own — not even the inherited background.
4899
+ * This carries *no* theme baking of its own, not even the inherited background.
4747
4900
  * `preserve` adds that via {@link flattenSlide}'s context; `restyle` must not, so the
4748
4901
  * background stays symbolic and re-brands.
4749
4902
  * @param {Presentation} dest - the destination deck
@@ -4804,8 +4957,8 @@ function rebind(dest, ctx, source, sourceSlide, carryGraphics) {
4804
4957
  /**
4805
4958
  * Bake the source `slideLayout`/`slideMaster` shape-tree decorations onto the imported slide
4806
4959
  * (the `carryMasterGraphics` path). Every shape on those trees *except* placeholders is
4807
- * deep-copied into the slide's `p:spTree` ahead of its own content — master decorations
4808
- * first, then layout, then the slide's shapes — so document (z-)order keeps the master
4960
+ * deep-copied into the slide's `p:spTree` ahead of its own content (master decorations
4961
+ * first, then layout, then the slide's shapes), so document (z-)order keeps the master
4809
4962
  * furthest back. Each decoration's media and other relationship targets are copied into this
4810
4963
  * package and its `r:embed`/`r:id`/… references rewritten to fresh slide-local ids. The
4811
4964
  * injected shapes are left for the caller's {@link flattenSlide} pass to resolve any theme
@@ -4847,7 +5000,7 @@ function carryMasterGraphics(ctx, slideRoot, newPartName, slidePartName, owned)
4847
5000
  /**
4848
5001
  * The partname of the layout this deck's slides should attach to in `preserve` mode: the
4849
5002
  * first layout of the first slide master. Throws when the deck has no master/layout to attach
4850
- * to (a deck ts-pptx always provides).
5003
+ * to (a deck pptx-ts always provides).
4851
5004
  * @param {Presentation} dest - the destination deck
4852
5005
  * @return {string} partname of the destination layout
4853
5006
  */
@@ -4858,8 +5011,7 @@ function destinationLayoutPartName(dest) {
4858
5011
  if (!layoutPartName) throw new InvalidOptionError("import/destination-missing-layout", "importSlide with theme 'preserve' or 'restyle' requires a slide layout in the destination deck");
4859
5012
  return layoutPartName;
4860
5013
  }
4861
- //#endregion
4862
- //#region src/read/api/ops/rescale.ts
5014
+ // src/read/api/ops/rescale.ts
4863
5015
  /** Build the EMU transform mapping source-canvas coordinates onto the target canvas (see {@link ImportSlideOptions.rescale}). */
4864
5016
  function computeRescale(source, target, mode) {
4865
5017
  if (mode === "stretch") return {
@@ -4878,7 +5030,7 @@ function computeRescale(source, target, mode) {
4878
5030
  }
4879
5031
  /**
4880
5032
  * Rescale every top-level transform on a `p:spTree`: shapes/pictures/connectors
4881
- * (`p:spPr/a:xfrm`), groups (`p:grpSpPr/a:xfrm` — only the group's own off/ext, so
5033
+ * (`p:spPr/a:xfrm`), groups (`p:grpSpPr/a:xfrm`, only the group's own off/ext, so
4882
5034
  * its children remap via the unchanged `chOff`/`chExt` rather than being recursed
4883
5035
  * into), and graphic frames (`p:graphicFrame/p:xfrm`, plus any inner table grid).
4884
5036
  * Placeholders that inherit geometry carry no `a:xfrm` and are left to inherit from
@@ -4927,8 +5079,8 @@ function rescaleXfrm(xfrm, t) {
4927
5079
  }
4928
5080
  }
4929
5081
  /**
4930
- * Scale a graphic-frame table's intrinsic dimensions — column widths by `sx`, row
4931
- * heights by `sy` — so the table resizes with the slide (PowerPoint derives table
5082
+ * Scale a graphic-frame table's intrinsic dimensions (column widths by `sx`, row
5083
+ * heights by `sy`) so the table resizes with the slide (PowerPoint derives table
4932
5084
  * geometry from the grid, not the frame `a:ext`). No-op for non-table frames.
4933
5085
  */
4934
5086
  function rescaleTableGrid(graphicFrame, t) {
@@ -4946,8 +5098,7 @@ function rescaleTableGrid(graphicFrame, t) {
4946
5098
  if (h !== null) setAttr(tr, "h", String(Math.max(0, Math.round(h * t.sy))));
4947
5099
  }
4948
5100
  }
4949
- //#endregion
4950
- //#region src/read/api/ops/rescale-import.ts
5101
+ // src/read/api/ops/rescale-import.ts
4951
5102
  /**
4952
5103
  * Rescaling an imported slide's geometry onto the destination canvas.
4953
5104
  *
@@ -4964,8 +5115,8 @@ function rescaleTableGrid(graphicFrame, t) {
4964
5115
  * graphicFrame transform and table grid on the slide; in `copy` mode also
4965
5116
  * rescales the imported layout and master shape trees (resolved via the
4966
5117
  * slide → layout → master rel chain) so inherited placeholder/background geometry
4967
- * stays aligned. `preserve`/`restyle` rebind to this deck's own master/layout —
4968
- * already the destination size — so only the slide is touched. Geometry only:
5118
+ * stays aligned. `preserve`/`restyle` rebind to this deck's own master/layout,
5119
+ * already the destination size, so only the slide is touched. Geometry only:
4969
5120
  * font sizes and line widths are left as authored.
4970
5121
  */
4971
5122
  function rescaleImportedGeometry(dest, rescaledParts, slidePartName, theme, source, target, mode) {
@@ -5017,8 +5168,7 @@ function rescalePartGeometry(dest, rescaledParts, partName, transform, mode) {
5017
5168
  rescaleSpTree(spTree, transform);
5018
5169
  part.markDirty();
5019
5170
  }
5020
- //#endregion
5021
- //#region src/read/api/presentation-imports.ts
5171
+ // src/read/api/presentation-imports.ts
5022
5172
  /** Body of {@link Presentation.importSlide}, whose doc comment carries the contract. */
5023
5173
  function importSlide(deck, source, index, options = {}) {
5024
5174
  const sourceSlide = source.slides[index];
@@ -5036,6 +5186,7 @@ function importSlide(deck, source, index, options = {}) {
5036
5186
  const newPart = deck.opc.part(newPartName);
5037
5187
  if (!newPart) throw new InternalError("import/part-went-missing", `Imported slide part went missing: ${newPartName}`);
5038
5188
  if (sizesDiffer && options.rescale && target && incoming) rescaleImportedGeometry(deck, deck.rescaledParts, newPartName, options.theme, incoming, target, options.rescale === true ? "fit" : options.rescale);
5189
+ carryCommentAuthors(deck, source, newPartName);
5039
5190
  const slide = deck.insertSlidePart(newPart, options.at);
5040
5191
  if (options.importNotes) carryNotes(deck, source, importCtx, sourceSlide.partName, newPartName);
5041
5192
  if (options.embedFonts) carryEmbeddedFonts(deck, source, importCtx);
@@ -5090,6 +5241,7 @@ function importSlides(deck, requests) {
5090
5241
  destPart
5091
5242
  };
5092
5243
  });
5244
+ for (const request of planned) carryCommentAuthors(deck, request.source, request.destPartName);
5093
5245
  for (const request of planned) {
5094
5246
  const mode = rescaleBySource.get(request.source.opc);
5095
5247
  if (!mode) continue;
@@ -5283,14 +5435,13 @@ function importShapes(deck, target, source, shapeIndices, options = {}) {
5283
5435
  }
5284
5436
  return result;
5285
5437
  }
5286
- //#endregion
5287
- //#region src/read/api/presentation.ts
5438
+ // src/read/api/presentation.ts
5288
5439
  /**
5289
5440
  * Read-model entry point: `Presentation` wraps an `OpcPackage` and exposes a
5290
5441
  * navigable, typed view of the deck (slides → shapes → text), backed by the
5291
5442
  * live DOM so the same nodes can later be mutated.
5292
5443
  *
5293
- * The class holds the model and the deck-level plumbing every operation needs — the part
5444
+ * The class holds the model and the deck-level plumbing every operation needs: the part
5294
5445
  * index, the slide list, the copy registry that lets repeated imports from one source share
5295
5446
  * what they already copied, and the `p:sldIdLst` wiring. The operations themselves live in
5296
5447
  * `ops/`, one job per module, taking this deck as an argument. The slide-import machinery
@@ -5300,11 +5451,11 @@ function importShapes(deck, target, source, shapeIndices, options = {}) {
5300
5451
  * The four import entry points went the same way, and {@link appendSlides} after them: their
5301
5452
  * contracts stay here as the doc comments a caller reads, and their bodies live in
5302
5453
  * `presentation-imports.ts` and `ops/append-slides.ts`. Those bodies are the one thing in this
5303
- * directory that is not independent of this class — they reach back for {@link importContext},
5454
+ * directory that is not independent of this class. They reach back for {@link importContext},
5304
5455
  * {@link insertSlidePart} and {@link rescaledParts}, which {@link cloneSlide} reads too and so
5305
5456
  * could not travel with them. Those three are `@internal` for that and nothing else.
5306
5457
  */
5307
- /** Content type of the main part in a `.potx` template package — flipped to {@link PRESENTATION_MAIN_CONTENT_TYPE} by {@link Presentation.fromTemplate}. */
5458
+ /** Content type of the main part in a `.potx` template package, flipped to {@link PRESENTATION_MAIN_CONTENT_TYPE} by {@link Presentation.fromTemplate}. */
5308
5459
  const PRESENTATION_TEMPLATE_MAIN_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml";
5309
5460
  var Presentation = class Presentation {
5310
5461
  opc;
@@ -5358,6 +5509,7 @@ var Presentation = class Presentation {
5358
5509
  if (mainPart.contentType === PRESENTATION_TEMPLATE_MAIN_CONTENT_TYPE) pres.opc.contentTypes.ensureRegistered(mainPart.partName, PRESENTATION_MAIN_CONTENT_TYPE);
5359
5510
  }
5360
5511
  while (pres.slides.length > 0) pres.removeSlide(0);
5512
+ resetCommentAuthorIndexes(pres);
5361
5513
  return pres;
5362
5514
  }
5363
5515
  /** The main presentation part (`/ppt/presentation.xml`), resolved via the package `officeDocument` relationship. */
@@ -5409,7 +5561,7 @@ var Presentation = class Presentation {
5409
5561
  /**
5410
5562
  * The deck's embedded font families (`p:embeddedFontLst` in `presentation.xml`),
5411
5563
  * `[]` when it embeds none. Each entry names the typeface and resolves every
5412
- * embedded face's `r:id` to the absolute partname of its `.fntdata` binary — the
5564
+ * embedded face's `r:id` to the absolute partname of its `.fntdata` binary: the
5413
5565
  * read counterpart to the write-side `pptx.embedFont` / `importSlide({ embedFonts })`
5414
5566
  * carry. An entry whose `p:font` has no `@typeface`, or a face whose `r:id` is
5415
5567
  * missing or dangling, is skipped (faithful degradation, no throw). Read-only.
@@ -5439,7 +5591,7 @@ var Presentation = class Presentation {
5439
5591
  * `ppt/authors.xml`), `[]` when the deck carries no modern comments. Unlike the
5440
5592
  * legacy {@link commentAuthors}, each entry is keyed by a GUID `id` (plus
5441
5593
  * `userId`/`providerId`); each slide's {@link Slide.modernComments} resolves its
5442
- * `@authorId` against this list. Read-only — the writer emits legacy comments.
5594
+ * `@authorId` against this list. Read-only: the writer emits legacy comments.
5443
5595
  */
5444
5596
  get modernCommentAuthors() {
5445
5597
  return readModernCommentAuthors(this.opc, this.presentationPart.partName);
@@ -5469,7 +5621,7 @@ var Presentation = class Presentation {
5469
5621
  * The deck's extended document properties (`docProps/app.xml`): the producing
5470
5622
  * application and its version, the company, and the flat `TitlesOfParts` vector.
5471
5623
  * `{}` when the deck carries no extended-properties part. The read counterpart of
5472
- * the write-side `pptx.company` setter — the only one of the four this library
5624
+ * the write-side `pptx.company` setter, the only one of the four this library
5473
5625
  * writes from a caller's value; the other three it states about itself.
5474
5626
  *
5475
5627
  * A deliberate subset of the part: see {@link ExtendedProperties} for why the
@@ -5491,7 +5643,7 @@ var Presentation = class Presentation {
5491
5643
  * The deck-level programmatic tags (`p:custDataLst/p:tags` on `presentation.xml`,
5492
5644
  * resolved to `ppt/tags/tagN.xml`) as `{ name, val }` string pairs, `[]` when the
5493
5645
  * deck carries none. These are add-in/host metadata with no visible rendering and
5494
- * no writer — read-only, preserved byte-for-byte on round-trip. Per-slide tags are
5646
+ * no writer. They are read-only, preserved byte-for-byte on round-trip. Per-slide tags are
5495
5647
  * {@link Slide.tags}.
5496
5648
  */
5497
5649
  get tags() {
@@ -5510,7 +5662,7 @@ var Presentation = class Presentation {
5510
5662
  * charts, SmartArt diagrams and OLE embeddings, each with the subtree under it
5511
5663
  * (a chart's embedded workbook comes along; the image inside its user-shapes
5512
5664
  * drawing stays shared). PowerPoint refuses to open a deck where two slides
5513
- * resolve to one chart or diagram, so this is not tidiness — see
5665
+ * resolve to one chart or diagram, so this is not tidiness; see
5514
5666
  * `page-owned.ts` for the rule and the evidence behind it.
5515
5667
  */
5516
5668
  cloneSlide(index, options = {}) {
@@ -5528,7 +5680,7 @@ var Presentation = class Presentation {
5528
5680
  * `p:sldId` entry and the presentation→slide relationship are dropped, the slide
5529
5681
  * part and its `.rels` are deleted, and any part the slide *privately* owned
5530
5682
  * (its notes slide, slide-only media, charts/embeddings) that no remaining part
5531
- * references is pruned too — recursively. Shared deck chrome (layout, master,
5683
+ * references is pruned too, recursively. Shared deck chrome (layout, master,
5532
5684
  * theme, …) is never pruned, so the deck stays renderable; removing every slide
5533
5685
  * leaves a valid master/layout-only package (a template shell). The slide also
5534
5686
  * leaves every custom show and section it was in, which stay even when that
@@ -5568,9 +5720,9 @@ var Presentation = class Presentation {
5568
5720
  * Append a copy of `source.slides[index]` to this presentation and return it.
5569
5721
  *
5570
5722
  * Unlike {@link cloneSlide} (same-deck duplicate), this copies a slide across
5571
- * a package boundary: it brings the connected sub-graph the slide depends on —
5572
- * its `slideLayout` → `slideMaster` → `theme`, plus any media, charts, and
5573
- * embeddings — into this package under fresh partnames, rewriting every
5723
+ * a package boundary: it brings the connected sub-graph the slide depends on
5724
+ * (its `slideLayout` → `slideMaster` → `theme`, plus any media, charts, and
5725
+ * embeddings) into this package under fresh partnames, rewriting every
5574
5726
  * partname, relationship id, and content-type registration so the result is a
5575
5727
  * self-consistent OPC package. Parts of this (target) package that are not
5576
5728
  * touched stay byte-identical, matching `cloneSlide`'s fidelity contract.
@@ -5578,7 +5730,7 @@ var Presentation = class Presentation {
5578
5730
  * Only the layout(s) actually used by imported slides are copied; the imported
5579
5731
  * master's `p:sldLayoutIdLst` is pruned to exactly those, mirroring how
5580
5732
  * PowerPoint's "Reuse Slides" brings a slide across. Parts shared by repeated
5581
- * imports from the same source deck are copied once and reused — every part
5733
+ * imports from the same source deck are copied once and reused: every part
5582
5734
  * except the page itself. Importing the same source slide twice yields two
5583
5735
  * independent copies over one shared layout/master/theme, which is what lets a
5584
5736
  * deck show one page twice (verbatim, then edited).
@@ -5587,7 +5739,7 @@ var Presentation = class Presentation {
5587
5739
  * into the slide XML and the slide is bound to this deck's existing
5588
5740
  * master/layout; with `{ theme: 'restyle' }` the slide is bound to this deck's
5589
5741
  * master/layout with its theme references left symbolic, so it re-brands to the
5590
- * destination palette — see {@link ImportSlideOptions}.
5742
+ * destination palette. See {@link ImportSlideOptions}.
5591
5743
  *
5592
5744
  * By default the source slide size must equal this presentation's. Pass
5593
5745
  * `{ rescale: 'fit' | 'stretch' }` to rescale the imported geometry onto this
@@ -5606,7 +5758,7 @@ var Presentation = class Presentation {
5606
5758
  * Import selected pages from one or more loaded source presentations as one
5607
5759
  * batch. Each imported page lands at its `outputIndex` in the complete
5608
5760
  * destination slide list after the batch, and the returned array is parallel
5609
- * to `requests` — `result[i]` is the page `requests[i]` asked for, whatever
5761
+ * to `requests`: `result[i]` is the page `requests[i]` asked for, whatever
5610
5762
  * order the output positions were given in.
5611
5763
  *
5612
5764
  * Everything is checked before a single byte of this deck moves: every request
@@ -5619,13 +5771,13 @@ var Presentation = class Presentation {
5619
5771
  * The batch also decides what a `slide → slide` link means: an internal link
5620
5772
  * on a selected page must target another **selected** page (or one this deck
5621
5773
  * already contains via an earlier import from that source), and is rewritten
5622
- * to the fresh partname — importing page 3 of 10 does not drag pages 1–2
5774
+ * to the fresh partname. Importing page 3 of 10 does not drag pages 1–2
5623
5775
  * across as dependencies, and never strands the link. This mirrors
5624
5776
  * `appendSlides`' `import/unresolved-slide-link`, which the write side already
5625
5777
  * enforces for generator decks.
5626
5778
  *
5627
5779
  * One request is one output page, so naming the same source page in several
5628
- * requests is how you ask for several independent copies of it — the page part
5780
+ * requests is how you ask for several independent copies of it; the page part
5629
5781
  * is the one thing an import never shares, exactly as in {@link importSlide}.
5630
5782
  * Everything under it (layout, master, theme, media) is still copied once and
5631
5783
  * shared. Where such a page is the target of a `slide → slide` link, the link
@@ -5636,7 +5788,7 @@ var Presentation = class Presentation {
5636
5788
  * Speaker notes travel per request: `{ importNotes: true }` carries that page's
5637
5789
  * `notesSlide` part across, wired to the new page and bound to a single
5638
5790
  * `notesMaster` under the same 0..1 rule {@link importSlide} and
5639
- * {@link appendSlides} follow — the destination's own master wins when it has
5791
+ * {@link appendSlides} follow: the destination's own master wins when it has
5640
5792
  * one. Notes are part of the up-front dry run too, so a batch that would fail
5641
5793
  * carrying them is refused with the deck still byte-identical. A page named in
5642
5794
  * several requests gets its own copy of its notes each time, as of everything
@@ -5663,9 +5815,9 @@ var Presentation = class Presentation {
5663
5815
  }
5664
5816
  /**
5665
5817
  * Graft slide master(s) from another open package into this one and return what
5666
- * was copied. Unlike {@link importSlide} — which brings a master across only as
5818
+ * was copied. Unlike {@link importSlide}, which brings a master across only as
5667
5819
  * the dependency of an imported *slide* and prunes it to the one layout that
5668
- * slide uses — this copies a master together with its **whole** layout family
5820
+ * slide uses, this copies a master together with its **whole** layout family
5669
5821
  * and attaches it to no slide: the master and its layouts land in this deck's
5670
5822
  * layout gallery (PowerPoint's *Insert ▸ New Slide* / *Layout* picker) without
5671
5823
  * changing any existing slide.
@@ -5697,7 +5849,7 @@ var Presentation = class Presentation {
5697
5849
  }
5698
5850
  /**
5699
5851
  * The deck's slide masters, in `p:sldMasterIdLst` order, as modeled
5700
- * {@link SlideMaster}s — the typed read model over the shared chrome (each
5852
+ * {@link SlideMaster}s: the typed read model over the shared chrome (each
5701
5853
  * master's colour map, theme, placeholders, and the layouts built on it). Walk
5702
5854
  * `pres.masters()[i].layouts` for the rich layout model, or use {@link layouts}
5703
5855
  * for the flat {@link LayoutHandle} gallery {@link appendSlides} binds to.
@@ -5707,7 +5859,7 @@ var Presentation = class Presentation {
5707
5859
  return slideMasterPartNames(this).map((partName) => this.opc.part(partName)).filter((part) => part !== void 0).map((part) => new SlideMaster(this.opc, part));
5708
5860
  }
5709
5861
  /**
5710
- * The deck's slide layouts, in master then layout order — the gallery a new
5862
+ * The deck's slide layouts, in master then layout order: the gallery a new
5711
5863
  * slide can bind to. Each {@link LayoutHandle} addresses one layout for
5712
5864
  * {@link appendSlides}; the `name` is its `p:cSld@name`. Read-only enumeration:
5713
5865
  * it copies nothing and leaves the package byte-identical.
@@ -5730,12 +5882,12 @@ var Presentation = class Presentation {
5730
5882
  /**
5731
5883
  * Append generator-produced slides onto this deck, binding each to an existing
5732
5884
  * layout, and return the new {@link Slide}s. This is the hybrid
5733
- * "generate-onto-existing" path: the deck's masters, layouts, theme — and every
5734
- * other untouched part — stay **byte-identical** (only `presentation.xml`, its
5885
+ * "generate-onto-existing" path: the deck's masters, layouts, theme, and every
5886
+ * other untouched part stay **byte-identical** (only `presentation.xml`, its
5735
5887
  * `.rels`, `[Content_Types].xml`, and the freshly-added slide/media parts
5736
5888
  * change), because the existing chrome is never regenerated.
5737
5889
  *
5738
- * `source` is any slide producer (a `TsPptx` instance); its authored slides
5890
+ * `source` is any slide producer (a `PptxTs` instance); its authored slides
5739
5891
  * are serialized via {@link SlideSource.extractSlides} and spliced in under
5740
5892
  * fresh partnames, with each slide's `slideLayout` relationship pointed at the
5741
5893
  * layout named by `options.layout` and its image/hyperlink relationships rebuilt
@@ -5745,13 +5897,13 @@ var Presentation = class Presentation {
5745
5897
  * Charts and internal slide-to-slide hyperlinks are carried across: chart parts
5746
5898
  * (chart XML + `.rels` + embedded workbook) are injected under fresh names, and a
5747
5899
  * `slide:N` link is repointed at the Nth appended slide's new partname. A chartEx
5748
- * (Office 2016 — waterfall, funnel, treemap, ...) chart carries too, as its own
5900
+ * (Office 2016: waterfall, funnel, treemap, ...) chart carries too, as its own
5749
5901
  * `chartEx{N}.xml` part behind the MS chartEx rel, with the style and color-style
5750
5902
  * sidecars PowerPoint requires alongside it.
5751
5903
  *
5752
5904
  * The generator's presentation-level embedded fonts (`pptx.embedFont`) are also
5753
5905
  * carried into this deck and merged into its `p:embeddedFontLst`, de-duped by
5754
- * typeface + face slot — so author-side embedded fonts survive the append onto a
5906
+ * typeface + face slot, so author-side embedded fonts survive the append onto a
5755
5907
  * template that may itself already embed fonts.
5756
5908
  *
5757
5909
  * Embedded audio/video is carried too: the media part backs the ECMA audio/video rel
@@ -5762,24 +5914,28 @@ var Presentation = class Presentation {
5762
5914
  * Speaker notes ride across too: a slide authored with `addNotes` gets a `notesSlide`
5763
5915
  * part wired back to it, with its hyperlink rels preserved. A notes slide must bind to
5764
5916
  * a notes master, and a template commonly has none, so the generator's is installed
5765
- * (with the theme its `.rels` needs) — but only when this deck has none of its own, so
5917
+ * (with the theme its `.rels` needs), but only when this deck has none of its own, so
5766
5918
  * an existing notes master and its styling always win.
5767
5919
  *
5920
+ * Review comments (`addComment`) ride across as a comments part per slide. Their
5921
+ * authors merge into this deck's `commentAuthors.xml` by name and initials: an author
5922
+ * the deck already has keeps its id and continues its numbering, and a new one is added.
5923
+ *
5768
5924
  * Limitations:
5769
5925
  * - An internal link to a source slide outside the appended batch throws (its
5770
5926
  * target has no counterpart in the destination).
5771
5927
  * - Appended slides are concrete absolute-positioned content with no placeholder
5772
5928
  * inheritance from the bound layout; the binding governs theme/`clrMap`
5773
5929
  * resolution and the "based on" link, not placeholder geometry. Author with
5774
- * concrete colours — any `schemeClr` re-resolves against the destination theme.
5930
+ * concrete colours: any `schemeClr` re-resolves against the destination theme.
5775
5931
  * - Source and destination slide sizes must match (no geometry rescale).
5776
5932
  */
5777
5933
  async appendSlides(source, options) {
5778
5934
  return appendSlides(this, source, options);
5779
5935
  }
5780
5936
  /**
5781
- * Copy one shape — an autoshape, picture, table/chart graphic frame, connector,
5782
- * or group — from `source.shapes[shapeIndex]` onto `target`, returning the new
5937
+ * Copy one shape (an autoshape, picture, table/chart graphic frame, connector,
5938
+ * or group) from `source.shapes[shapeIndex]` onto `target`, returning the new
5783
5939
  * {@link Shape}. `target` must be a slide of *this* presentation; `source` may
5784
5940
  * belong to any open presentation.
5785
5941
  *
@@ -5790,7 +5946,7 @@ var Presentation = class Presentation {
5790
5946
  * so they cannot collide with the host. With `theme: 'preserve'` (default) the
5791
5947
  * shape's theme references are baked to literals against the *source* theme so it
5792
5948
  * renders the same on a foreign host; `restyle` leaves them symbolic to re-brand;
5793
- * `copy` brings the XML across untouched — see {@link ImportShapeOptions}.
5949
+ * `copy` brings the XML across untouched. See {@link ImportShapeOptions}.
5794
5950
  *
5795
5951
  * Differing slide sizes need `{ rescale }` (see {@link ImportShapeOptions.rescale});
5796
5952
  * a lifted `preserve` placeholder is baked self-contained and demoted to a plain
@@ -5822,7 +5978,7 @@ var Presentation = class Presentation {
5822
5978
  }
5823
5979
  /**
5824
5980
  * @internal The parts whose geometry a rescale has already rewritten, and in which mode.
5825
- * Exposed for `presentation-imports.ts` as a live map the callee adds to — the memo is what
5981
+ * Exposed for `presentation-imports.ts` as a live map the callee adds to. The memo is what
5826
5982
  * makes a layout or master shared across repeated imports from one source scale exactly
5827
5983
  * once, so like the copy registry it has to outlive the call that fills it.
5828
5984
  */
@@ -5832,7 +5988,7 @@ var Presentation = class Presentation {
5832
5988
  /**
5833
5989
  * @internal Open an import out of `source`: this deck as the destination, paired with
5834
5990
  * the copy registry for that package (created on first use). The registry is held on
5835
- * the class rather than in the context because it must outlive any one call — that is
5991
+ * the class rather than in the context because it must outlive any one call: that is
5836
5992
  * what makes a second import from the same source reuse the layout, master, theme, and
5837
5993
  * media it already copied instead of duplicating them, and it is why the import bodies
5838
5994
  * in `presentation-imports.ts` call back here rather than carrying it with them.
@@ -5879,7 +6035,7 @@ var Presentation = class Presentation {
5879
6035
  * A slide id one past the highest existing, but at least ST_SlideId's minimum.
5880
6036
  *
5881
6037
  * The module named and enforced that minimum and not the maximum, so a deck near the ceiling
5882
- * got an out-of-range `p:sldId/@id` written with no diagnostic — the package then needs
6038
+ * got an out-of-range `p:sldId/@id` written with no diagnostic. The package then needs
5883
6039
  * repair, for a reason nothing reported. Past the ceiling there is no "next" id to hand out,
5884
6040
  * so the allocation falls back to the lowest id in range that the deck is not already using;
5885
6041
  * a deck holding every one of the two billion has no legal answer and says so.
@@ -5902,7 +6058,6 @@ var Presentation = class Presentation {
5902
6058
  return this.opc.save();
5903
6059
  }
5904
6060
  };
5905
- //#endregion
5906
6061
  export { Slide as a, NotesSlide as c, SlideMaster as d, Theme as f, ContentTypes as g, Part as h, readExtendedProperties as i, Placeholder as l, Relationships as m, readCoreProperties as n, readTagsForPart as o, OpcPackage as p, readCustomProperties as r, NotesPlaceholder as s, Presentation as t, SlideLayout as u };
5907
6062
 
5908
- //# sourceMappingURL=presentation-DGYlAWhl.js.map
6063
+ //# sourceMappingURL=presentation-4Ggq0_Xa.js.map