@shbernal/ts-pptx 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +8 -0
  2. package/dist/{autopage-BYlTzX-l.js → autopage-DkjYZUFD.js} +3 -3
  3. package/dist/{autopage-BYlTzX-l.js.map → autopage-DkjYZUFD.js.map} +1 -1
  4. package/dist/browser.d.ts +5 -5
  5. package/dist/browser.js +4 -4
  6. package/dist/browser.js.map +1 -1
  7. package/dist/{diagnostics-BDuR8UkG.d.ts → diagnostics-DfBdDHre.d.ts} +20 -5
  8. package/dist/diagnostics-DfBdDHre.d.ts.map +1 -0
  9. package/dist/{errors-CgnueTYL.d.ts → errors-PflMPWBn.d.ts} +2 -2
  10. package/dist/{errors-CgnueTYL.d.ts.map → errors-PflMPWBn.d.ts.map} +1 -1
  11. package/dist/{fit-TjpNbMru.js → fit-BKs0zxMI.js} +3 -3
  12. package/dist/{fit-TjpNbMru.js.map → fit-BKs0zxMI.js.map} +1 -1
  13. package/dist/{html-dom-yUSdCExA.js → html-dom-B0I0QSbU.js} +4 -4
  14. package/dist/{html-dom-yUSdCExA.js.map → html-dom-B0I0QSbU.js.map} +1 -1
  15. package/dist/html.d.ts +3 -3
  16. package/dist/html.js +1 -1
  17. package/dist/index.d.ts +5 -5
  18. package/dist/index.js +3 -3
  19. package/dist/inspect.d.ts +1 -1
  20. package/dist/inspect.js +4 -5
  21. package/dist/inspect.js.map +1 -1
  22. package/dist/math.d.ts +1 -1
  23. package/dist/measure.d.ts +2 -2
  24. package/dist/measure.js +1 -1
  25. package/dist/{namespaces-CcKuzeuE.js → namespaces-BVnNu7sg.js} +74 -3
  26. package/dist/namespaces-BVnNu7sg.js.map +1 -0
  27. package/dist/node.d.ts +5 -5
  28. package/dist/node.js +3 -3
  29. package/dist/{notes-DNqAggXx.js → notes-CJFJaG6M.js} +310 -313
  30. package/dist/notes-CJFJaG6M.js.map +1 -0
  31. package/dist/{pres-Dybf7ZUl.d.ts → pres-BcBR3CSM.d.ts} +2 -2
  32. package/dist/{pres-Dybf7ZUl.d.ts.map → pres-BcBR3CSM.d.ts.map} +1 -1
  33. package/dist/{presentation-VfJ_FT7E.js → presentation-DrJtj3-C.js} +414 -515
  34. package/dist/presentation-DrJtj3-C.js.map +1 -0
  35. package/dist/{presentation-types-CpkTx9Xa.d.ts → presentation-types-CDjScsev.d.ts} +351 -274
  36. package/dist/presentation-types-CDjScsev.d.ts.map +1 -0
  37. package/dist/read.d.ts +31 -48
  38. package/dist/read.d.ts.map +1 -1
  39. package/dist/read.js +3 -3
  40. package/dist/script.d.ts +2 -2
  41. package/dist/script.d.ts.map +1 -1
  42. package/dist/script.js +18 -47
  43. package/dist/script.js.map +1 -1
  44. package/dist/{shapes-Kt51vry6.js → shapes-BemroU-z.js} +625 -265
  45. package/dist/shapes-BemroU-z.js.map +1 -0
  46. package/dist/{slide-B_aInw3N.d.ts → slide-ZqAdVvHV.d.ts} +1135 -1058
  47. package/dist/slide-ZqAdVvHV.d.ts.map +1 -0
  48. package/dist/{text-D04NUMvA.js → text-B8SLEaZx.js} +2089 -1418
  49. package/dist/text-B8SLEaZx.js.map +1 -0
  50. package/dist/units-1kRzYShk.js +231 -0
  51. package/dist/units-1kRzYShk.js.map +1 -0
  52. package/dist/units-internal-Dg95w_YD.js +753 -0
  53. package/dist/units-internal-Dg95w_YD.js.map +1 -0
  54. package/dist/zip.d.ts +1 -1
  55. package/package.json +2 -1
  56. package/dist/diagnostics-BDuR8UkG.d.ts.map +0 -1
  57. package/dist/diagnostics-CPVADSL1.js +0 -90
  58. package/dist/diagnostics-CPVADSL1.js.map +0 -1
  59. package/dist/namespaces-CcKuzeuE.js.map +0 -1
  60. package/dist/notes-DNqAggXx.js.map +0 -1
  61. package/dist/presentation-VfJ_FT7E.js.map +0 -1
  62. package/dist/presentation-types-CpkTx9Xa.d.ts.map +0 -1
  63. package/dist/shapes-Kt51vry6.js.map +0 -1
  64. package/dist/slide-B_aInw3N.d.ts.map +0 -1
  65. package/dist/text-D04NUMvA.js.map +0 -1
  66. package/dist/units-internal-DNvK2I6o.js +0 -896
  67. package/dist/units-internal-DNvK2I6o.js.map +0 -1
@@ -1,9 +1,9 @@
1
+ import { d as emuToInches } from "./units-1kRzYShk.js";
1
2
  import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-Bvln0H-7.js";
2
- import { mt as emuToInches } from "./units-internal-DNvK2I6o.js";
3
- import { D as voidEl, E as raw, T as el, g as FONT_REL_TYPE, h as FONT_DATA_EXTENSION, m as FONT_DATA_CONTENT_TYPE, n as makeXmlNotesMaster, o as makeXmlNotesSlideSkeleton, p as EMBEDDED_FONT_SLOTS } from "./notes-DNqAggXx.js";
4
- import { _ as THEME_CONTENT_TYPE, a as NOTES_MASTER_REL, c as OFFICE_DOCUMENT_REL, d as SLIDE_CONTENT_TYPE, f as SLIDE_LAYOUT_CONTENT_TYPE, g as SLIDE_REL, h as SLIDE_MASTER_REL, i as NOTES_MASTER_CONTENT_TYPE, l as OFFICE_REL, m as SLIDE_MASTER_CONTENT_TYPE, o as NOTES_SLIDE_CONTENT_TYPE, p as SLIDE_LAYOUT_REL, r as IMAGE_REL, s as NOTES_SLIDE_REL, t as OOXML_NS, v as THEME_REL } from "./namespaces-CcKuzeuE.js";
3
+ import { D as voidEl, E as raw, T as el, g as FONT_REL_TYPE, h as FONT_DATA_EXTENSION, m as FONT_DATA_CONTENT_TYPE, n as makeXmlNotesMaster, o as makeXmlNotesSlideSkeleton, p as EMBEDDED_FONT_SLOTS } from "./notes-CJFJaG6M.js";
4
+ import { D as COLOR_MAP_TOKENS, I as THEME_COLOR_SLOTS, _ as THEME_CONTENT_TYPE, a as NOTES_MASTER_REL, c as OFFICE_DOCUMENT_REL, d as SLIDE_CONTENT_TYPE, f as SLIDE_LAYOUT_CONTENT_TYPE, g as SLIDE_REL, h as SLIDE_MASTER_REL, i as NOTES_MASTER_CONTENT_TYPE, l as OFFICE_REL, m as SLIDE_MASTER_CONTENT_TYPE, o as NOTES_SLIDE_CONTENT_TYPE, p as SLIDE_LAYOUT_REL, r as IMAGE_REL, s as NOTES_SLIDE_REL, t as OOXML_NS, v as THEME_REL } from "./namespaces-BVnNu7sg.js";
5
5
  import { ZipWriter, readZip } from "./zip.js";
6
- import { $ as carriedDecorations, A as spPrXfrmEmu, At as resolveSingleRel, Bt as getElements, Ct as SPPR_SCENE3D_AFTER, Dt as relativePartName, Et as partNameToZipPath, F as resolveLayoutColorContext, Ft as createElement, G as placeholderInheritedListStyles, Gt as parseXml, H as RUN_PROP_NAMES, Ht as insertInOrder, I as resolveMasterColorContext, It as descendantsByTag, J as placeholderOf, Jt as replaceInParent, K as placeholderInheritedRunProps, Kt as removeAttr, L as resolveNotesColorContext, Lt as escapeXmlAttribute, M as readPictureFill, Mt as attr, N as readGradientFill, Nt as boolValue, Ot as relsPartNameFor, P as resolveColorElement, Pt as childElements, Q as cSldOf, R as resolveSlideColorContext, Rt as firstChild, St as SPPR_LN_AFTER, T as AutoShape, Tt as partNameExtension, U as placeholderInheritedAnchor, Ut as intValue, V as LST_STYLE_LEVELS, Vt as getOrAddChild, W as placeholderInheritedColor, Wt as ownerDocumentOf, X as slideDefinesProp, Xt as setAttr, Y as slideDefinesColor, Yt as serializeXml, Z as cSldName, _t as RPR_FILL_AFTER, at as SCHEME_SLOTS, bt as SPPR_EFFECT_AFTER, ct as isA, dt as resolveColor, et as collectElements, ft as resolveSchemeToken, gt as FILL_CHOICES, ht as substitutePhClr, it as spTreeOf, j as readPatternFill, jt as zipPathToPartName, k as TextFrame, kt as resolveRelativePartName, l as wrapShapeElement, lt as parseClrMap, mt as styleRefLine, n as buildShapes, nt as nthShapeChild, ot as fmtEntry, pt as styleRefFill, q as placeholderInheritedXfrm, qt as removeChildrenByQName, r as findShapeByIdDeep, rt as nvPrOf, st as intAttr, t as GroupShape, tt as firstShapeChild, u as GraphicFrame, ut as parseClrScheme, vt as SHAPE_AFTER_SPPR, w as Picture, wt as SPPR_SP3D_AFTER, xt as SPPR_FILL_AFTER, yt as SPPR_AFTER_XFRM, z as resolveSlideThemeParts, zt as firstChildElement } from "./shapes-Kt51vry6.js";
6
+ import { $ as collectElements, A as spPrXfrmEmu, At as resolveRelativePartName, B as LST_STYLE_LEVELS, Bt as firstChildElement, Ct as SPPR_LN_AFTER, Dt as partNameToZipPath, Et as partNameExtension, F as resolveLayoutColorContext, Ft as childElements, G as placeholderInheritedRunProps, Gt as ownerDocumentOf, H as placeholderInheritedAnchor, Ht as getOrAddChild, I as resolveMasterColorContext, It as createElement, J as slideDefinesColor, Jt as removeChildrenByQName, K as placeholderInheritedXfrm, Kt as parseXml, L as resolveNotesColorContext, Lt as descendantsByTag, M as readPictureFill, Mt as zipPathToPartName, N as readGradientFill, Nt as attr, Ot as relativePartName, P as resolveColorElement, Pt as boolValue, Q as carriedDecorations, R as resolveSlideColorContext, Rt as escapeXmlAttribute, St as SPPR_FILL_AFTER, T as AutoShape, Tt as SPPR_SP3D_AFTER, U as placeholderInheritedColor, Ut as insertInOrder, V as RUN_PROP_NAMES, Vt as getElements, W as placeholderInheritedListStyles, Wt as intValue, X as cSldName, Xt as serializeXml, Y as slideDefinesProp, Yt as replaceInParent, Z as cSldOf, Zt as setAttr, _t as FILL_CHOICES, at as fmtEntry, bt as SPPR_AFTER_XFRM, ct as parseClrMap, dt as resolveSchemeToken, et as firstShapeChild, ft as styleRefFill, it as SCHEME_SLOTS, j as readPatternFill, jt as resolveSingleRel, k as TextFrame, kt as relsPartNameFor, l as wrapShapeElement, lt as parseClrScheme, mt as substitutePhClr, n as buildShapes, nt as nvPrOf, ot as intAttr, pt as styleRefLine, q as placeholderOf, qt as removeAttr, r as findShapeByIdDeep, rt as spTreeOf, st as isA, t as GroupShape, tt as nthShapeChild, u as GraphicFrame, ut as resolveColor, vt as RPR_FILL_AFTER, w as Picture, wt as SPPR_SCENE3D_AFTER, xt as SPPR_EFFECT_AFTER, yt as SHAPE_AFTER_SPPR, z as resolveSlideThemeParts, zt as firstChild } from "./shapes-BemroU-z.js";
7
7
  //#region src/read/opc/content-types.ts
8
8
  /**
9
9
  * Overlay over `[Content_Types].xml`, used to resolve part content types at
@@ -987,15 +987,108 @@ function readSlideBackground(bg, source, ctx, rels, themeRels) {
987
987
  };
988
988
  }
989
989
  //#endregion
990
- //#region src/read/api/notes.ts
990
+ //#region src/read/api/chrome.ts
991
+ /** Read `<a:latin>`/`<a:ea>`/`<a:cs>` typefaces of a theme font family; empty string ⇒ `null`. */
992
+ function readThemeFontFace(font) {
993
+ const face = (child) => {
994
+ const el = font && firstChild(font, child);
995
+ return el && attr(el, "typeface") || null;
996
+ };
997
+ return {
998
+ latin: face("a:latin"),
999
+ ea: face("a:ea"),
1000
+ cs: face("a:cs")
1001
+ };
1002
+ }
991
1003
  /**
992
- * One placeholder shape (`p:sp`) of a notes slide. A notes slide holds a fixed set:
993
- * the slide thumbnail (`type="sldImg"`), the notes body (`type="body"`), and the
994
- * slide number (`type="sldNum"`). Geometry getters read the placeholder's *own*
995
- * `a:xfrm` and are `null` when it inherits geometry from the notesMaster (the case
996
- * on an authored deck, whose `sldImg`/`sldNum` carry an empty `p:spPr`).
1004
+ * A deck's theme part (`theme1.xml`) as a modeled object. Exposes the two property
1005
+ * tiers a slide resolves against: the {@link colorScheme} (the 12 `a:clrScheme`
1006
+ * slots as literal hex, `a:sysClr` resolved via its `lastClr`) and the
1007
+ * {@link fontScheme} (major/minor Latin/EA/CS faces). Reachable from
1008
+ * {@link SlideMaster.theme} and `Slide.theme`.
1009
+ */
1010
+ var Theme = class {
1011
+ part;
1012
+ constructor(part) {
1013
+ this.part = part;
1014
+ }
1015
+ /** Partname of the theme part. */
1016
+ get partName() {
1017
+ return this.part.partName;
1018
+ }
1019
+ /** Theme name (`a:theme/@name`, e.g. `Office Theme`), or `null` when unnamed. */
1020
+ get name() {
1021
+ const root = this.part.dom.documentElement;
1022
+ return root ? attr(root, "name") : null;
1023
+ }
1024
+ /** Colour-scheme name (`a:clrScheme/@name`, e.g. `Office`), or `null`. */
1025
+ get colorSchemeName() {
1026
+ const clrScheme = this.#clrScheme();
1027
+ return clrScheme ? attr(clrScheme, "name") : null;
1028
+ }
1029
+ /**
1030
+ * The theme colour scheme: the 12 {@link ThemeColorSlot}s resolved to a 6-hex RGB
1031
+ * (an `a:sysClr` slot resolves through its `lastClr`). A slot the theme does not
1032
+ * define reads `null`. Use {@link color} to look one slot up.
1033
+ */
1034
+ get colorScheme() {
1035
+ const parsed = parseClrScheme(this.#clrScheme());
1036
+ const out = {};
1037
+ for (const slot of THEME_COLOR_SLOTS) out[slot] = parsed.get(slot) ?? null;
1038
+ return out;
1039
+ }
1040
+ /** The 6-hex RGB of one colour-scheme slot, or `null` when the theme does not define it. */
1041
+ color(slot) {
1042
+ return parseClrScheme(this.#clrScheme()).get(slot) ?? null;
1043
+ }
1044
+ /** The theme's `a:fontScheme` (major/minor font families), or `null` when the theme declares none. */
1045
+ get fontScheme() {
1046
+ const themeElements = this.#themeElements();
1047
+ const fontScheme = themeElements && firstChild(themeElements, "a:fontScheme");
1048
+ if (!fontScheme) return null;
1049
+ return {
1050
+ name: attr(fontScheme, "name"),
1051
+ major: readThemeFontFace(firstChild(fontScheme, "a:majorFont")),
1052
+ minor: readThemeFontFace(firstChild(fontScheme, "a:minorFont"))
1053
+ };
1054
+ }
1055
+ /** Escape hatch: the underlying `a:theme` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
1056
+ get element_() {
1057
+ return this.part.dom.documentElement;
1058
+ }
1059
+ /** Mark the theme part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
1060
+ markDirty() {
1061
+ this.part.markDirty();
1062
+ }
1063
+ #themeElements() {
1064
+ const root = this.part.dom.documentElement;
1065
+ return root ? firstChild(root, "a:themeElements") : null;
1066
+ }
1067
+ #clrScheme() {
1068
+ const themeElements = this.#themeElements();
1069
+ return themeElements ? firstChild(themeElements, "a:clrScheme") : null;
1070
+ }
1071
+ };
1072
+ /** The placeholder shapes (`p:sp` carrying a `p:ph`) of a master/layout `p:spTree`, in document order. */
1073
+ function placeholderShapes(spTree) {
1074
+ if (!spTree) return [];
1075
+ return getElements(spTree, "p:sp").filter((sp) => placeholderOf(sp) !== null);
1076
+ }
1077
+ /**
1078
+ * One placeholder shape (`p:sp` with a `p:ph`) of a slide master or slide layout —
1079
+ * the definition a slide's placeholder of the same `type`/`idx` inherits geometry
1080
+ * and text style from. Geometry getters read the placeholder's *own* `a:xfrm`,
1081
+ * which a master/layout placeholder carries explicitly (so it round-trips, unlike a
1082
+ * notes placeholder's inherited geometry).
1083
+ *
1084
+ * This is the identity-and-geometry view. The same `p:sp` also appears in
1085
+ * {@link SlideMaster.shapes} / {@link SlideLayout.shapes} as an `AutoShape`, which
1086
+ * additionally carries the paint surface (`resolvedFill`, `resolvedLine`,
1087
+ * `presetGeometry`, `rotation`, `absoluteFrame`) and reports its `p:ph` through
1088
+ * `AutoShape.placeholder`. Read a placeholder here to *place* it; read it there to
1089
+ * *draw* it.
997
1090
  */
998
- var NotesPlaceholder = class {
1091
+ var Placeholder = class {
999
1092
  sp;
1000
1093
  part;
1001
1094
  themeContext;
@@ -1006,22 +1099,18 @@ var NotesPlaceholder = class {
1006
1099
  this.themeContext = themeContext;
1007
1100
  this.relationships = relationships;
1008
1101
  }
1009
- #ph() {
1010
- const nvPr = nvPrOf(this.sp);
1011
- return nvPr ? firstChild(nvPr, "p:ph") : null;
1012
- }
1013
1102
  #cNvPr() {
1014
1103
  const nvSpPr = firstChild(this.sp, "p:nvSpPr");
1015
1104
  return nvSpPr ? firstChild(nvSpPr, "p:cNvPr") : null;
1016
1105
  }
1017
- /** Placeholder type (`p:ph/@type`: `sldImg` | `body` | `sldNum`), or `null` when absent. */
1106
+ /** Placeholder type (`p:ph/@type`: `title` | `body` | `sldNum` | …), or `null` when absent (a body placeholder). */
1018
1107
  get type() {
1019
- const ph = this.#ph();
1108
+ const ph = placeholderOf(this.sp);
1020
1109
  return ph ? attr(ph, "type") : null;
1021
1110
  }
1022
1111
  /** Placeholder index (`p:ph/@idx`), or `null` when unset. */
1023
1112
  get idx() {
1024
- const ph = this.#ph();
1113
+ const ph = placeholderOf(this.sp);
1025
1114
  return ph ? attr(ph, "idx") : null;
1026
1115
  }
1027
1116
  /** Shape name (`p:cNvPr/@name`), or `''` when unnamed. */
@@ -1034,63 +1123,63 @@ var NotesPlaceholder = class {
1034
1123
  const cNvPr = this.#cNvPr();
1035
1124
  return cNvPr ? intValue(attr(cNvPr, "id")) : null;
1036
1125
  }
1037
- /** Left edge in EMU (`a:off/@x`), or `null` when geometry is inherited (no own `a:xfrm`). */
1126
+ /** Left edge in EMU (`a:off/@x`), or `null` when the placeholder carries no own `a:xfrm`. */
1038
1127
  get left() {
1039
1128
  return spPrXfrmEmu(this.sp, "a:off", "x");
1040
1129
  }
1041
- /** Top edge in EMU (`a:off/@y`), or `null` when geometry is inherited. */
1130
+ /** Top edge in EMU (`a:off/@y`), or `null` when the placeholder carries no own `a:xfrm`. */
1042
1131
  get top() {
1043
1132
  return spPrXfrmEmu(this.sp, "a:off", "y");
1044
1133
  }
1045
- /** Width in EMU (`a:ext/@cx`), or `null` when geometry is inherited. */
1134
+ /** Width in EMU (`a:ext/@cx`), or `null` when the placeholder carries no own `a:xfrm`. */
1046
1135
  get width() {
1047
1136
  return spPrXfrmEmu(this.sp, "a:ext", "cx");
1048
1137
  }
1049
- /** Height in EMU (`a:ext/@cy`), or `null` when geometry is inherited. */
1138
+ /** Height in EMU (`a:ext/@cy`), or `null` when the placeholder carries no own `a:xfrm`. */
1050
1139
  get height() {
1051
1140
  return spPrXfrmEmu(this.sp, "a:ext", "cy");
1052
1141
  }
1053
1142
  /**
1054
1143
  * The placeholder's text as a navigable {@link TextFrame} (`p:txBody`), or `null`
1055
- * when it carries no text body (the `sldImg` thumbnail). The body placeholder's
1056
- * runs round-trip a slide's authored notes; the `sldNum` placeholder's frame
1057
- * holds the slide-number `a:fld`, whose value surfaces through `TextFrame.text`.
1144
+ * when it carries no text body. Threaded with the owning master/layout theme
1145
+ * context so a run's own `schemeClr` resolves through `Run.resolvedColor`.
1058
1146
  */
1059
1147
  get textFrame() {
1060
1148
  const txBody = firstChild(this.sp, "p:txBody");
1061
- if (!txBody) return null;
1062
- const placeholder = this.type === "body" ? {
1063
- ph: {
1064
- type: this.type,
1065
- idx: this.idx ?? "0"
1066
- },
1067
- flatten: this.themeContext
1068
- } : void 0;
1069
- return new TextFrame(txBody, this.part, this.themeContext, placeholder, this.relationships);
1070
- }
1071
- /** The placeholder's flattened text (paragraphs joined by `\n`), or `''` when it has no text body. */
1072
- get text() {
1073
- return this.textFrame?.text ?? "";
1149
+ return txBody ? new TextFrame(txBody, this.part, this.themeContext, void 0, this.relationships) : null;
1074
1150
  }
1075
1151
  /** Escape hatch: the underlying `p:sp` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
1076
1152
  get element_() {
1077
1153
  return this.sp;
1078
1154
  }
1079
- /** Mark the owning notes-slide part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
1155
+ /** Mark the owning part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
1080
1156
  markDirty() {
1081
1157
  this.part.markDirty();
1082
1158
  }
1083
1159
  };
1084
1160
  /**
1085
- * A slide's speaker-notes slide (`notesSlideN.xml`) as a modeled object — the deep
1086
- * companion to {@link import('./slide.js').Slide.notesText}. Exposes the notes
1087
- * shape tree as {@link NotesPlaceholder}s ({@link body}/{@link slideImage}/
1088
- * {@link slideNumber}) plus the body {@link textFrame} the older getters flatten.
1161
+ * The shared body of a slide master and a slide layout — the two template tiers a slide
1162
+ * inherits from.
1089
1163
  *
1090
- * The theme context (notesMaster → `theme2.xml`) is resolved once and shared across
1091
- * every placeholder's text frame.
1164
+ * Both are an OPC part holding a `p:cSld` with a shape tree and a resolvable theme context, and
1165
+ * both were written out in full, member for member: `partName`, `relationships`, `name`,
1166
+ * `shapes`, `shapeByIdDeep`, `placeholders`, `themeContext` and the two DOM lookups behind them
1167
+ * were character-for-character identical in the two classes. Nothing about that was broken, but
1168
+ * it meant every accessor added to a template tier had to be added twice, and the ones meant to
1169
+ * agree could quietly stop agreeing.
1170
+ *
1171
+ * What genuinely differs stays on the subclasses. `theme` differs because a layout has to walk
1172
+ * to its master first. `background` differs in the tier label it decodes with and in where it
1173
+ * finds the theme part. And the context itself differs, which is why {@link resolveThemeContext}
1174
+ * is abstract: a master resolves its own `p:clrMap` + theme, a layout walks layout → master →
1175
+ * theme. The caching around it is shared, so a subclass supplies the walk and nothing else.
1176
+ *
1177
+ * `Slide` deliberately does not extend this. It is a shape host too, but it is constructed from
1178
+ * a `Presentation` rather than an `OpcPackage`, reaches its relationships through that, and
1179
+ * reports an unnamed slide as `null` where a template tier reports `''` — three differences in
1180
+ * the same handful of members, which is more contortion than the sharing is worth.
1092
1181
  */
1093
- var NotesSlide = class {
1182
+ var TemplatePart = class {
1094
1183
  opc;
1095
1184
  part;
1096
1185
  #themeContext;
@@ -1098,72 +1187,303 @@ var NotesSlide = class {
1098
1187
  this.opc = opc;
1099
1188
  this.part = part;
1100
1189
  }
1101
- /** Partname of the notes slide part. */
1190
+ /** Partname of this part. */
1102
1191
  get partName() {
1103
1192
  return this.part.partName;
1104
1193
  }
1194
+ /** This part's relationships (its theme or master, image embeds, hyperlinks, …). */
1195
+ get relationships() {
1196
+ return this.opc.relationshipsFor(this.partName);
1197
+ }
1198
+ /** The authoring name (`p:cSld/@name`), or `''` when unnamed. */
1199
+ get name() {
1200
+ const cSld = this.cSld();
1201
+ return (cSld && attr(cSld, "name")) ?? "";
1202
+ }
1105
1203
  /**
1106
- * The notes theme context, resolved through the notesMaster → `theme2.xml` chain
1107
- * and cached. Backs {@link NotesPlaceholder.textFrame}'s `Run.resolvedColor`.
1204
+ * Every shape in this tier's `p:cSld/p:spTree`, in document order — the same `AnyShape`
1205
+ * union `Slide.shapes` returns, so shape-walking code applies unchanged.
1206
+ *
1207
+ * {@link placeholders} is the filtered view of the same tree.
1108
1208
  */
1109
- themeContext() {
1110
- return this.#themeContext ??= resolveNotesColorContext(this.opc, this.partName);
1209
+ get shapes() {
1210
+ const spTree = this.spTree();
1211
+ return spTree ? buildShapes(spTree, this) : [];
1111
1212
  }
1112
- /** The placeholders (`p:sp`) in the notes shape tree, in document order. */
1213
+ /** The shape anywhere in this tier's tree with the given drawing id, or `undefined`. */
1214
+ shapeByIdDeep(id) {
1215
+ return findShapeByIdDeep(this.shapes, id);
1216
+ }
1217
+ /** This tier's placeholder shapes (`p:sp` carrying a `p:ph`), in document order. */
1113
1218
  get placeholders() {
1114
- const spTree = this.#spTree();
1115
- if (!spTree) return [];
1116
1219
  const ctx = this.themeContext();
1117
- const rels = this.opc.relationshipsFor(this.partName);
1118
- return getElements(spTree, "p:sp").map((sp) => new NotesPlaceholder(sp, this.part, ctx, rels));
1220
+ const rels = this.relationships;
1221
+ return placeholderShapes(this.spTree()).map((sp) => new Placeholder(sp, this.part, ctx, rels));
1119
1222
  }
1120
- /** The notes body placeholder (`p:ph type="body"`), or `null` when the notes slide has none. */
1121
- get body() {
1122
- return this.#byType("body");
1223
+ /** This tier's colour/font context, resolved once and cached. Backs each {@link Placeholder}'s text frame. */
1224
+ themeContext() {
1225
+ return this.#themeContext ??= this.resolveThemeContext();
1123
1226
  }
1124
- /** The slide-thumbnail placeholder (`p:ph type="sldImg"`), or `null` when absent. */
1125
- get slideImage() {
1126
- return this.#byType("sldImg");
1227
+ /** The `p:cSld` of this part, or `null`. */
1228
+ cSld() {
1229
+ return cSldOf(this.part.dom.documentElement);
1127
1230
  }
1128
- /** The slide-number placeholder (`p:ph type="sldNum"`, carrying the slide-number field), or `null`. */
1129
- get slideNumber() {
1130
- return this.#byType("sldNum");
1231
+ /** The `p:cSld/p:spTree` of this part, or `null`. */
1232
+ spTree() {
1233
+ return spTreeOf(this.part.dom.documentElement);
1131
1234
  }
1132
- /** The notes body as a navigable {@link TextFrame}, or `null` when there is no body text frame. */
1133
- get textFrame() {
1134
- return this.body?.textFrame ?? null;
1235
+ /** The part this one's first relationship of `type` points at, or `null`. */
1236
+ relTarget(type) {
1237
+ const rels = this.relationships;
1238
+ const rel = rels.byType(type)[0];
1239
+ return rel ? this.opc.part(rels.resolveTarget(rel.id)) ?? null : null;
1135
1240
  }
1136
- /** The notes body text flattened (paragraphs joined by `\n`), or `''` when the body is empty/absent. */
1137
- get text() {
1138
- return this.body?.text ?? "";
1241
+ };
1242
+ /**
1243
+ * A deck's slide master (`slideMasterN.xml`) as a modeled object. Exposes the
1244
+ * property tiers a bound slide inherits: the {@link colorMap} (token → theme slot),
1245
+ * its {@link theme}, its `shapes` and the `placeholders` subset of them, its own
1246
+ * {@link background}, and the {@link layouts} that build on it. Reachable from
1247
+ * {@link SlideLayout.master} and `Slide.master`.
1248
+ *
1249
+ * `shapes` is where a template's non-placeholder furniture lives: the header band, the
1250
+ * rule under the title, the logo. Whether a given slide draws them is
1251
+ * `Slide.showMasterSp` (and, for a layout, {@link SlideLayout.showMasterSp}).
1252
+ */
1253
+ var SlideMaster = class extends TemplatePart {
1254
+ /** The master's theme (via its `theme` relationship), or `null` when absent. */
1255
+ get theme() {
1256
+ const themePart = this.relTarget(THEME_REL);
1257
+ return themePart ? new Theme(themePart) : null;
1139
1258
  }
1140
- #byType(type) {
1141
- return this.placeholders.find((ph) => ph.type === type) ?? null;
1259
+ /**
1260
+ * The master's colour map (`p:clrMap`): each of the 12 {@link ColorMapToken}s
1261
+ * mapped to the {@link ThemeColorSlot} it resolves through. This is the indirection
1262
+ * that lets a slide's `schemeClr val="tx1"` reach a theme slot (e.g. `tx1` → `dk1`).
1263
+ * A token the map omits reads `null`.
1264
+ */
1265
+ get colorMap() {
1266
+ const root = this.part.dom.documentElement;
1267
+ const parsed = parseClrMap(root ? firstChild(root, "p:clrMap") : null);
1268
+ const out = {};
1269
+ for (const token of COLOR_MAP_TOKENS) out[token] = parsed.get(token) ?? null;
1270
+ return out;
1142
1271
  }
1143
- #spTree() {
1144
- return spTreeOf(this.part.dom.documentElement);
1272
+ /** The layouts built on this master (via `p:sldLayoutIdLst` → its relationships), in list order. */
1273
+ get layouts() {
1274
+ const root = this.part.dom.documentElement;
1275
+ const lst = root && firstChild(root, "p:sldLayoutIdLst");
1276
+ if (!lst) return [];
1277
+ const rels = this.relationships;
1278
+ const out = [];
1279
+ for (const entry of getElements(lst, "p:sldLayoutId")) {
1280
+ const relId = attr(entry, "r:id");
1281
+ const part = relId ? this.opc.part(rels.resolveTarget(relId)) : null;
1282
+ if (part) out.push(new SlideLayout(this.opc, part));
1283
+ }
1284
+ return out;
1285
+ }
1286
+ /**
1287
+ * The master's *own* background (`p:cSld/p:bg`), decoded, or `null` when it defines
1288
+ * none. Scoped to the master's own element — a slide's *effective* background,
1289
+ * resolved through the slide → layout → master chain, is `Slide.background`.
1290
+ */
1291
+ get background() {
1292
+ const bg = backgroundElementOf(this.part.dom.documentElement);
1293
+ if (!bg) return null;
1294
+ const themePart = this.relTarget(THEME_REL);
1295
+ return readSlideBackground(bg, "master", this.themeContext(), this.relationships, themePart ? this.opc.relationshipsFor(themePart.partName) : null);
1296
+ }
1297
+ /** A master's context is its own `p:clrMap` plus its theme — no walk beyond this part. */
1298
+ resolveThemeContext() {
1299
+ return resolveMasterColorContext(this.opc, this.partName);
1145
1300
  }
1146
1301
  };
1147
- //#endregion
1148
- //#region src/read/api/ops/deck-target.ts
1149
1302
  /**
1150
- * `ppt/_rels/presentation.xml.rels` -- the deck's own relationship part.
1303
+ * A deck's slide layout (`slideLayoutN.xml`) as a modeled object — the gallery entry
1304
+ * a slide binds to. Exposes its {@link name}, its {@link type} (import-only; the
1305
+ * writer authors none), its {@link master} (and, through it, the {@link theme}), its
1306
+ * `shapes` and the `placeholders` subset of them, and its own {@link background}.
1307
+ * Reachable from `Slide.layout` and {@link SlideMaster.layouts}.
1151
1308
  *
1152
- * Every part that masters, layouts, the notes master and embedded fonts hang off
1153
- * is reached through here, so the two-step `dest.presentationPart` ->
1154
- * `dest.opc.relationshipsFor(part.partName)` was written out at every one of
1155
- * those wiring sites. Naming it once means a call site says which rels it wants
1156
- * rather than how to find them.
1157
- * @param {DeckTarget} dest - the destination deck
1158
- * @returns {Relationships} the presentation part's relationships
1309
+ * The write API authors non-placeholder shapes into a layout: every
1310
+ * `defineSlideMaster({ objects })` member that is not a `placeholder` — a `rect`, a
1311
+ * `line`, an `image`, a `chart`, a `text` box — lands in this tier's tree.
1159
1312
  */
1160
- function presentationRels(dest) {
1161
- return dest.opc.relationshipsFor(dest.presentationPart.partName);
1162
- }
1163
- //#endregion
1164
- //#region src/read/api/ops/master-registry.ts
1165
- /**
1166
- * Slide-master bookkeeping in `presentation.xml` and in a master's own
1313
+ var SlideLayout = class extends TemplatePart {
1314
+ /**
1315
+ * The layout type (`p:sldLayout/@type`, e.g. `title` | `obj` | `blank`), or `null`
1316
+ * when the layout declares none. Import-only: the writer authors no `@type`, so an
1317
+ * authored deck reads `null`; an imported deck carries PowerPoint's value.
1318
+ */
1319
+ get type() {
1320
+ const root = this.part.dom.documentElement;
1321
+ return root ? attr(root, "type") : null;
1322
+ }
1323
+ /**
1324
+ * Whether this layout draws the master's non-placeholder shapes
1325
+ * (`p:sldLayout/@showMasterSp`). `xsd:boolean` defaulting to `true`, so an absent
1326
+ * attribute means shown — the layout-tier counterpart of `Slide.showMasterSp`,
1327
+ * and the one PowerPoint actually writes on a section-divider or full-bleed
1328
+ * layout. A renderer resolving what to paint under a slide's own shapes has to
1329
+ * consult both: the slide's flag, then its layout's.
1330
+ */
1331
+ get showMasterSp() {
1332
+ const root = this.part.dom.documentElement;
1333
+ return boolValue(root && attr(root, "showMasterSp")) !== false;
1334
+ }
1335
+ /** The master this layout is built on (via its `slideMaster` relationship), or `null` when absent. */
1336
+ get master() {
1337
+ const rels = this.relationships;
1338
+ const rel = rels.byType(SLIDE_MASTER_REL)[0];
1339
+ const part = rel ? this.opc.part(rels.resolveTarget(rel.id)) : null;
1340
+ return part ? new SlideMaster(this.opc, part) : null;
1341
+ }
1342
+ /** The theme this layout resolves against, via its {@link master}, or `null`. */
1343
+ get theme() {
1344
+ return this.master?.theme ?? null;
1345
+ }
1346
+ /**
1347
+ * The layout's *own* background (`p:cSld/p:bg`), decoded, or `null` when it defines
1348
+ * none. A layout usually authors one — an explicit fill (`p:bgPr`) or a
1349
+ * theme-indexed reference (`p:bgRef`). The slide's *effective* background is
1350
+ * `Slide.background`.
1351
+ */
1352
+ get background() {
1353
+ const bg = backgroundElementOf(this.part.dom.documentElement);
1354
+ if (!bg) return null;
1355
+ const themePart = this.master?.theme?.part ?? null;
1356
+ return readSlideBackground(bg, "layout", this.themeContext(), this.relationships, themePart ? this.opc.relationshipsFor(themePart.partName) : null);
1357
+ }
1358
+ /** A layout's context is walked layout → master → theme, which is why it is not the master's. */
1359
+ resolveThemeContext() {
1360
+ return resolveLayoutColorContext(this.opc, this.partName);
1361
+ }
1362
+ };
1363
+ //#endregion
1364
+ //#region src/read/api/notes.ts
1365
+ /**
1366
+ * One placeholder shape (`p:sp`) of a notes slide. A notes slide holds a fixed set:
1367
+ * the slide thumbnail (`type="sldImg"`), the notes body (`type="body"`), and the
1368
+ * slide number (`type="sldNum"`). Geometry getters read the placeholder's *own*
1369
+ * `a:xfrm` and are `null` when it inherits geometry from the notesMaster (the case
1370
+ * on an authored deck, whose `sldImg`/`sldNum` carry an empty `p:spPr`).
1371
+ *
1372
+ * A notes placeholder IS a {@link Placeholder} — identity, geometry and the escape hatch are
1373
+ * the same twelve members read off the same `p:sp`, down to `p:ph` being found the same way —
1374
+ * so it extends one rather than repeating it. Two things are its own: the flattened
1375
+ * {@link text} convenience, and a {@link textFrame} that threads the notesMaster inheritance
1376
+ * context onto the body frame.
1377
+ */
1378
+ var NotesPlaceholder = class extends Placeholder {
1379
+ /**
1380
+ * The placeholder's text as a navigable {@link TextFrame} (`p:txBody`), or `null`
1381
+ * when it carries no text body (the `sldImg` thumbnail). The body placeholder's
1382
+ * runs round-trip a slide's authored notes; the `sldNum` placeholder's frame
1383
+ * holds the slide-number `a:fld`, whose value surfaces through `TextFrame.text`.
1384
+ *
1385
+ * Overrides {@link Placeholder.textFrame} for the inheritance context alone — see below.
1386
+ */
1387
+ get textFrame() {
1388
+ const txBody = firstChild(this.sp, "p:txBody");
1389
+ if (!txBody) return null;
1390
+ const placeholder = this.type === "body" ? {
1391
+ ph: {
1392
+ type: this.type,
1393
+ idx: this.idx ?? "0"
1394
+ },
1395
+ flatten: this.themeContext
1396
+ } : void 0;
1397
+ return new TextFrame(txBody, this.part, this.themeContext, placeholder, this.relationships);
1398
+ }
1399
+ /** The placeholder's flattened text (paragraphs joined by `\n`), or `''` when it has no text body. */
1400
+ get text() {
1401
+ return this.textFrame?.text ?? "";
1402
+ }
1403
+ };
1404
+ /**
1405
+ * A slide's speaker-notes slide (`notesSlideN.xml`) as a modeled object — the deep
1406
+ * companion to {@link import('./slide.js').Slide.notesText}. Exposes the notes
1407
+ * shape tree as {@link NotesPlaceholder}s ({@link body}/{@link slideImage}/
1408
+ * {@link slideNumber}) plus the body {@link textFrame} the older getters flatten.
1409
+ *
1410
+ * The theme context (notesMaster → `theme2.xml`) is resolved once and shared across
1411
+ * every placeholder's text frame.
1412
+ */
1413
+ var NotesSlide = class {
1414
+ opc;
1415
+ part;
1416
+ #themeContext;
1417
+ constructor(opc, part) {
1418
+ this.opc = opc;
1419
+ this.part = part;
1420
+ }
1421
+ /** Partname of the notes slide part. */
1422
+ get partName() {
1423
+ return this.part.partName;
1424
+ }
1425
+ /**
1426
+ * The notes theme context, resolved through the notesMaster → `theme2.xml` chain
1427
+ * and cached. Backs {@link NotesPlaceholder.textFrame}'s `Run.resolvedColor`.
1428
+ */
1429
+ themeContext() {
1430
+ return this.#themeContext ??= resolveNotesColorContext(this.opc, this.partName);
1431
+ }
1432
+ /** The placeholders (`p:sp`) in the notes shape tree, in document order. */
1433
+ get placeholders() {
1434
+ const spTree = this.#spTree();
1435
+ if (!spTree) return [];
1436
+ const ctx = this.themeContext();
1437
+ const rels = this.opc.relationshipsFor(this.partName);
1438
+ return getElements(spTree, "p:sp").map((sp) => new NotesPlaceholder(sp, this.part, ctx, rels));
1439
+ }
1440
+ /** The notes body placeholder (`p:ph type="body"`), or `null` when the notes slide has none. */
1441
+ get body() {
1442
+ return this.#byType("body");
1443
+ }
1444
+ /** The slide-thumbnail placeholder (`p:ph type="sldImg"`), or `null` when absent. */
1445
+ get slideImage() {
1446
+ return this.#byType("sldImg");
1447
+ }
1448
+ /** The slide-number placeholder (`p:ph type="sldNum"`, carrying the slide-number field), or `null`. */
1449
+ get slideNumber() {
1450
+ return this.#byType("sldNum");
1451
+ }
1452
+ /** The notes body as a navigable {@link TextFrame}, or `null` when there is no body text frame. */
1453
+ get textFrame() {
1454
+ return this.body?.textFrame ?? null;
1455
+ }
1456
+ /** The notes body text flattened (paragraphs joined by `\n`), or `''` when the body is empty/absent. */
1457
+ get text() {
1458
+ return this.body?.text ?? "";
1459
+ }
1460
+ #byType(type) {
1461
+ return this.placeholders.find((ph) => ph.type === type) ?? null;
1462
+ }
1463
+ #spTree() {
1464
+ return spTreeOf(this.part.dom.documentElement);
1465
+ }
1466
+ };
1467
+ //#endregion
1468
+ //#region src/read/api/ops/deck-target.ts
1469
+ /**
1470
+ * `ppt/_rels/presentation.xml.rels` -- the deck's own relationship part.
1471
+ *
1472
+ * Every part that masters, layouts, the notes master and embedded fonts hang off
1473
+ * is reached through here, so the two-step `dest.presentationPart` ->
1474
+ * `dest.opc.relationshipsFor(part.partName)` was written out at every one of
1475
+ * those wiring sites. Naming it once means a call site says which rels it wants
1476
+ * rather than how to find them.
1477
+ * @param {DeckTarget} dest - the destination deck
1478
+ * @returns {Relationships} the presentation part's relationships
1479
+ */
1480
+ function presentationRels(dest) {
1481
+ return dest.opc.relationshipsFor(dest.presentationPart.partName);
1482
+ }
1483
+ //#endregion
1484
+ //#region src/read/api/ops/master-registry.ts
1485
+ /**
1486
+ * Slide-master bookkeeping in `presentation.xml` and in a master's own
1167
1487
  * `p:sldLayoutIdLst`: registering a master so renderers treat it as active,
1168
1488
  * promoting masters to the front of the id list, allocating ids out of the shared
1169
1489
  * master/layout id space, and emptying a freshly-copied master's layout list.
@@ -2167,427 +2487,6 @@ function readTagsForPart(opc, ownerPartName) {
2167
2487
  return out;
2168
2488
  }
2169
2489
  //#endregion
2170
- //#region src/read/api/chrome.ts
2171
- const THEME_COLOR_SLOTS = [
2172
- "dk1",
2173
- "lt1",
2174
- "dk2",
2175
- "lt2",
2176
- "accent1",
2177
- "accent2",
2178
- "accent3",
2179
- "accent4",
2180
- "accent5",
2181
- "accent6",
2182
- "hlink",
2183
- "folHlink"
2184
- ];
2185
- const COLOR_MAP_TOKENS = [
2186
- "bg1",
2187
- "tx1",
2188
- "bg2",
2189
- "tx2",
2190
- "accent1",
2191
- "accent2",
2192
- "accent3",
2193
- "accent4",
2194
- "accent5",
2195
- "accent6",
2196
- "hlink",
2197
- "folHlink"
2198
- ];
2199
- /** Read `<a:latin>`/`<a:ea>`/`<a:cs>` typefaces of a theme font family; empty string ⇒ `null`. */
2200
- function readThemeFontFace(font) {
2201
- const face = (child) => {
2202
- const el = font && firstChild(font, child);
2203
- return el && attr(el, "typeface") || null;
2204
- };
2205
- return {
2206
- latin: face("a:latin"),
2207
- ea: face("a:ea"),
2208
- cs: face("a:cs")
2209
- };
2210
- }
2211
- /**
2212
- * A deck's theme part (`theme1.xml`) as a modeled object. Exposes the two property
2213
- * tiers a slide resolves against: the {@link colorScheme} (the 12 `a:clrScheme`
2214
- * slots as literal hex, `a:sysClr` resolved via its `lastClr`) and the
2215
- * {@link fontScheme} (major/minor Latin/EA/CS faces). Reachable from
2216
- * {@link SlideMaster.theme} and `Slide.theme`.
2217
- */
2218
- var Theme = class {
2219
- part;
2220
- constructor(part) {
2221
- this.part = part;
2222
- }
2223
- /** Partname of the theme part. */
2224
- get partName() {
2225
- return this.part.partName;
2226
- }
2227
- /** Theme name (`a:theme/@name`, e.g. `Office Theme`), or `null` when unnamed. */
2228
- get name() {
2229
- const root = this.part.dom.documentElement;
2230
- return root ? attr(root, "name") : null;
2231
- }
2232
- /** Colour-scheme name (`a:clrScheme/@name`, e.g. `Office`), or `null`. */
2233
- get colorSchemeName() {
2234
- const clrScheme = this.#clrScheme();
2235
- return clrScheme ? attr(clrScheme, "name") : null;
2236
- }
2237
- /**
2238
- * The theme colour scheme: the 12 {@link ThemeColorSlot}s resolved to a 6-hex RGB
2239
- * (an `a:sysClr` slot resolves through its `lastClr`). A slot the theme does not
2240
- * define reads `null`. Use {@link color} to look one slot up.
2241
- */
2242
- get colorScheme() {
2243
- const parsed = parseClrScheme(this.#clrScheme());
2244
- const out = {};
2245
- for (const slot of THEME_COLOR_SLOTS) out[slot] = parsed.get(slot) ?? null;
2246
- return out;
2247
- }
2248
- /** The 6-hex RGB of one colour-scheme slot, or `null` when the theme does not define it. */
2249
- color(slot) {
2250
- return parseClrScheme(this.#clrScheme()).get(slot) ?? null;
2251
- }
2252
- /** The theme's `a:fontScheme` (major/minor font families), or `null` when the theme declares none. */
2253
- get fontScheme() {
2254
- const themeElements = this.#themeElements();
2255
- const fontScheme = themeElements && firstChild(themeElements, "a:fontScheme");
2256
- if (!fontScheme) return null;
2257
- return {
2258
- name: attr(fontScheme, "name"),
2259
- major: readThemeFontFace(firstChild(fontScheme, "a:majorFont")),
2260
- minor: readThemeFontFace(firstChild(fontScheme, "a:minorFont"))
2261
- };
2262
- }
2263
- /** Escape hatch: the underlying `a:theme` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
2264
- get element_() {
2265
- return this.part.dom.documentElement;
2266
- }
2267
- /** Mark the theme part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
2268
- markDirty() {
2269
- this.part.markDirty();
2270
- }
2271
- #themeElements() {
2272
- const root = this.part.dom.documentElement;
2273
- return root ? firstChild(root, "a:themeElements") : null;
2274
- }
2275
- #clrScheme() {
2276
- const themeElements = this.#themeElements();
2277
- return themeElements ? firstChild(themeElements, "a:clrScheme") : null;
2278
- }
2279
- };
2280
- /** The placeholder shapes (`p:sp` carrying a `p:ph`) of a master/layout `p:spTree`, in document order. */
2281
- function placeholderShapes(spTree) {
2282
- if (!spTree) return [];
2283
- return getElements(spTree, "p:sp").filter((sp) => placeholderOf(sp) !== null);
2284
- }
2285
- /**
2286
- * One placeholder shape (`p:sp` with a `p:ph`) of a slide master or slide layout —
2287
- * the definition a slide's placeholder of the same `type`/`idx` inherits geometry
2288
- * and text style from. Geometry getters read the placeholder's *own* `a:xfrm`,
2289
- * which a master/layout placeholder carries explicitly (so it round-trips, unlike a
2290
- * notes placeholder's inherited geometry).
2291
- *
2292
- * This is the identity-and-geometry view. The same `p:sp` also appears in
2293
- * {@link SlideMaster.shapes} / {@link SlideLayout.shapes} as an `AutoShape`, which
2294
- * additionally carries the paint surface (`resolvedFill`, `resolvedLine`,
2295
- * `presetGeometry`, `rotation`, `absoluteFrame`) and reports its `p:ph` through
2296
- * `AutoShape.placeholder`. Read a placeholder here to *place* it; read it there to
2297
- * *draw* it.
2298
- */
2299
- var Placeholder = class {
2300
- sp;
2301
- part;
2302
- themeContext;
2303
- relationships;
2304
- constructor(sp, part, themeContext, relationships) {
2305
- this.sp = sp;
2306
- this.part = part;
2307
- this.themeContext = themeContext;
2308
- this.relationships = relationships;
2309
- }
2310
- #cNvPr() {
2311
- const nvSpPr = firstChild(this.sp, "p:nvSpPr");
2312
- return nvSpPr ? firstChild(nvSpPr, "p:cNvPr") : null;
2313
- }
2314
- /** Placeholder type (`p:ph/@type`: `title` | `body` | `sldNum` | …), or `null` when absent (a body placeholder). */
2315
- get type() {
2316
- const ph = placeholderOf(this.sp);
2317
- return ph ? attr(ph, "type") : null;
2318
- }
2319
- /** Placeholder index (`p:ph/@idx`), or `null` when unset. */
2320
- get idx() {
2321
- const ph = placeholderOf(this.sp);
2322
- return ph ? attr(ph, "idx") : null;
2323
- }
2324
- /** Shape name (`p:cNvPr/@name`), or `''` when unnamed. */
2325
- get name() {
2326
- const cNvPr = this.#cNvPr();
2327
- return (cNvPr && attr(cNvPr, "name")) ?? "";
2328
- }
2329
- /** Drawing id (`p:cNvPr/@id`), or `null` when absent. */
2330
- get id() {
2331
- const cNvPr = this.#cNvPr();
2332
- return cNvPr ? intValue(attr(cNvPr, "id")) : null;
2333
- }
2334
- /** Left edge in EMU (`a:off/@x`), or `null` when the placeholder carries no own `a:xfrm`. */
2335
- get left() {
2336
- return spPrXfrmEmu(this.sp, "a:off", "x");
2337
- }
2338
- /** Top edge in EMU (`a:off/@y`), or `null` when the placeholder carries no own `a:xfrm`. */
2339
- get top() {
2340
- return spPrXfrmEmu(this.sp, "a:off", "y");
2341
- }
2342
- /** Width in EMU (`a:ext/@cx`), or `null` when the placeholder carries no own `a:xfrm`. */
2343
- get width() {
2344
- return spPrXfrmEmu(this.sp, "a:ext", "cx");
2345
- }
2346
- /** Height in EMU (`a:ext/@cy`), or `null` when the placeholder carries no own `a:xfrm`. */
2347
- get height() {
2348
- return spPrXfrmEmu(this.sp, "a:ext", "cy");
2349
- }
2350
- /**
2351
- * The placeholder's text as a navigable {@link TextFrame} (`p:txBody`), or `null`
2352
- * when it carries no text body. Threaded with the owning master/layout theme
2353
- * context so a run's own `schemeClr` resolves through `Run.resolvedColor`.
2354
- */
2355
- get textFrame() {
2356
- const txBody = firstChild(this.sp, "p:txBody");
2357
- return txBody ? new TextFrame(txBody, this.part, this.themeContext, void 0, this.relationships) : null;
2358
- }
2359
- /** Escape hatch: the underlying `p:sp` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
2360
- get element_() {
2361
- return this.sp;
2362
- }
2363
- /** Mark the owning master/layout part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
2364
- markDirty() {
2365
- this.part.markDirty();
2366
- }
2367
- };
2368
- /**
2369
- * A deck's slide master (`slideMasterN.xml`) as a modeled object. Exposes the
2370
- * property tiers a bound slide inherits: the {@link colorMap} (token → theme slot),
2371
- * its {@link theme}, its {@link shapes} and the {@link placeholders} subset of them,
2372
- * its own {@link background}, and the {@link layouts} that build on it. Reachable
2373
- * from {@link SlideLayout.master} and `Slide.master`.
2374
- */
2375
- var SlideMaster = class {
2376
- opc;
2377
- part;
2378
- #themeContext;
2379
- constructor(opc, part) {
2380
- this.opc = opc;
2381
- this.part = part;
2382
- }
2383
- /** Partname of the master part. */
2384
- get partName() {
2385
- return this.part.partName;
2386
- }
2387
- /** This master part's relationships (its layouts, its theme, image embeds, …). */
2388
- get relationships() {
2389
- return this.opc.relationshipsFor(this.partName);
2390
- }
2391
- /** The master's authoring name (`p:cSld/@name`), or `''` when unnamed (the writer's default). */
2392
- get name() {
2393
- const cSld = this.#cSld();
2394
- return (cSld && attr(cSld, "name")) ?? "";
2395
- }
2396
- /** The master's theme (via its `theme` relationship), or `null` when absent. */
2397
- get theme() {
2398
- const themePart = this.#relTarget(THEME_REL);
2399
- return themePart ? new Theme(themePart) : null;
2400
- }
2401
- /**
2402
- * The master's colour map (`p:clrMap`): each of the 12 {@link ColorMapToken}s
2403
- * mapped to the {@link ThemeColorSlot} it resolves through. This is the indirection
2404
- * that lets a slide's `schemeClr val="tx1"` reach a theme slot (e.g. `tx1` → `dk1`).
2405
- * A token the map omits reads `null`.
2406
- */
2407
- get colorMap() {
2408
- const root = this.part.dom.documentElement;
2409
- const parsed = parseClrMap(root ? firstChild(root, "p:clrMap") : null);
2410
- const out = {};
2411
- for (const token of COLOR_MAP_TOKENS) out[token] = parsed.get(token) ?? null;
2412
- return out;
2413
- }
2414
- /**
2415
- * Every shape in the master's `p:cSld/p:spTree`, in document order — the same
2416
- * `AnyShape` union `Slide.shapes` returns, so shape-walking code applies
2417
- * unchanged. This is where a template's non-placeholder furniture lives: the
2418
- * header band, the rule under the title, the logo. Whether a given slide draws
2419
- * them is `Slide.showMasterSp` (and, for a layout, {@link SlideLayout.showMasterSp}).
2420
- *
2421
- * {@link placeholders} is the filtered view of the same tree.
2422
- */
2423
- get shapes() {
2424
- const spTree = this.#spTree();
2425
- return spTree ? buildShapes(spTree, this) : [];
2426
- }
2427
- /** The shape anywhere in the master's tree with the given drawing id, or `undefined`. */
2428
- shapeByIdDeep(id) {
2429
- return findShapeByIdDeep(this.shapes, id);
2430
- }
2431
- /** The master's placeholder shapes (`p:sp` carrying a `p:ph`), in document order. */
2432
- get placeholders() {
2433
- const ctx = this.themeContext();
2434
- const rels = this.relationships;
2435
- return placeholderShapes(this.#spTree()).map((sp) => new Placeholder(sp, this.part, ctx, rels));
2436
- }
2437
- /** The layouts built on this master (via `p:sldLayoutIdLst` → its relationships), in list order. */
2438
- get layouts() {
2439
- const root = this.part.dom.documentElement;
2440
- const lst = root && firstChild(root, "p:sldLayoutIdLst");
2441
- if (!lst) return [];
2442
- const rels = this.relationships;
2443
- const out = [];
2444
- for (const entry of getElements(lst, "p:sldLayoutId")) {
2445
- const relId = attr(entry, "r:id");
2446
- const part = relId ? this.opc.part(rels.resolveTarget(relId)) : null;
2447
- if (part) out.push(new SlideLayout(this.opc, part));
2448
- }
2449
- return out;
2450
- }
2451
- /**
2452
- * The master's *own* background (`p:cSld/p:bg`), decoded, or `null` when it defines
2453
- * none. Scoped to the master's own element — a slide's *effective* background,
2454
- * resolved through the slide → layout → master chain, is `Slide.background`.
2455
- */
2456
- get background() {
2457
- const bg = backgroundElementOf(this.part.dom.documentElement);
2458
- if (!bg) return null;
2459
- const themePart = this.#relTarget(THEME_REL);
2460
- return readSlideBackground(bg, "master", this.themeContext(), this.relationships, themePart ? this.opc.relationshipsFor(themePart.partName) : null);
2461
- }
2462
- /**
2463
- * The master's colour/font context (its `p:clrMap` + theme), resolved once and
2464
- * cached. Backs each {@link Placeholder}'s text frame.
2465
- */
2466
- themeContext() {
2467
- return this.#themeContext ??= resolveMasterColorContext(this.opc, this.partName);
2468
- }
2469
- #relTarget(type) {
2470
- const rels = this.relationships;
2471
- const rel = rels.byType(type)[0];
2472
- return rel ? this.opc.part(rels.resolveTarget(rel.id)) ?? null : null;
2473
- }
2474
- #cSld() {
2475
- return cSldOf(this.part.dom.documentElement);
2476
- }
2477
- #spTree() {
2478
- return spTreeOf(this.part.dom.documentElement);
2479
- }
2480
- };
2481
- /**
2482
- * A deck's slide layout (`slideLayoutN.xml`) as a modeled object — the gallery entry
2483
- * a slide binds to. Exposes its {@link name}, its {@link type} (import-only; the
2484
- * writer authors none), its {@link master} (and, through it, the {@link theme}), its
2485
- * {@link shapes} and the {@link placeholders} subset of them, and its own
2486
- * {@link background}. Reachable from `Slide.layout` and {@link SlideMaster.layouts}.
2487
- */
2488
- var SlideLayout = class {
2489
- opc;
2490
- part;
2491
- #themeContext;
2492
- constructor(opc, part) {
2493
- this.opc = opc;
2494
- this.part = part;
2495
- }
2496
- /** Partname of the layout part. */
2497
- get partName() {
2498
- return this.part.partName;
2499
- }
2500
- /** This layout part's relationships (its master, image embeds, hyperlinks, …). */
2501
- get relationships() {
2502
- return this.opc.relationshipsFor(this.partName);
2503
- }
2504
- /** The layout's authoring name (`p:cSld/@name`, e.g. `Title and Content`), or `''` when unnamed. */
2505
- get name() {
2506
- const cSld = this.#cSld();
2507
- return (cSld && attr(cSld, "name")) ?? "";
2508
- }
2509
- /**
2510
- * The layout type (`p:sldLayout/@type`, e.g. `title` | `obj` | `blank`), or `null`
2511
- * when the layout declares none. Import-only: the writer authors no `@type`, so an
2512
- * authored deck reads `null`; an imported deck carries PowerPoint's value.
2513
- */
2514
- get type() {
2515
- const root = this.part.dom.documentElement;
2516
- return root ? attr(root, "type") : null;
2517
- }
2518
- /**
2519
- * Whether this layout draws the master's non-placeholder shapes
2520
- * (`p:sldLayout/@showMasterSp`). `xsd:boolean` defaulting to `true`, so an absent
2521
- * attribute means shown — the layout-tier counterpart of `Slide.showMasterSp`,
2522
- * and the one PowerPoint actually writes on a section-divider or full-bleed
2523
- * layout. A renderer resolving what to paint under a slide's own shapes has to
2524
- * consult both: the slide's flag, then its layout's.
2525
- */
2526
- get showMasterSp() {
2527
- const root = this.part.dom.documentElement;
2528
- return boolValue(root && attr(root, "showMasterSp")) !== false;
2529
- }
2530
- /** The master this layout is built on (via its `slideMaster` relationship), or `null` when absent. */
2531
- get master() {
2532
- const rels = this.relationships;
2533
- const rel = rels.byType(SLIDE_MASTER_REL)[0];
2534
- const part = rel ? this.opc.part(rels.resolveTarget(rel.id)) : null;
2535
- return part ? new SlideMaster(this.opc, part) : null;
2536
- }
2537
- /** The theme this layout resolves against, via its {@link master}, or `null`. */
2538
- get theme() {
2539
- return this.master?.theme ?? null;
2540
- }
2541
- /**
2542
- * Every shape in the layout's `p:cSld/p:spTree`, in document order — the same
2543
- * `AnyShape` union `Slide.shapes` returns, so shape-walking code applies
2544
- * unchanged. The write API authors non-placeholder shapes here: every
2545
- * `defineSlideMaster({ objects })` member that is not a `placeholder` (a `rect`,
2546
- * a `line`, an `image`, a `chart`, a `text` box) lands in this tree.
2547
- *
2548
- * {@link placeholders} is the filtered view of the same tree.
2549
- */
2550
- get shapes() {
2551
- const spTree = this.#spTree();
2552
- return spTree ? buildShapes(spTree, this) : [];
2553
- }
2554
- /** The shape anywhere in the layout's tree with the given drawing id, or `undefined`. */
2555
- shapeByIdDeep(id) {
2556
- return findShapeByIdDeep(this.shapes, id);
2557
- }
2558
- /** The layout's placeholder shapes (`p:sp` carrying a `p:ph`), in document order. */
2559
- get placeholders() {
2560
- const ctx = this.themeContext();
2561
- const rels = this.relationships;
2562
- return placeholderShapes(this.#spTree()).map((sp) => new Placeholder(sp, this.part, ctx, rels));
2563
- }
2564
- /**
2565
- * The layout's *own* background (`p:cSld/p:bg`), decoded, or `null` when it defines
2566
- * none. A layout usually authors one — an explicit fill (`p:bgPr`) or a
2567
- * theme-indexed reference (`p:bgRef`). The slide's *effective* background is
2568
- * `Slide.background`.
2569
- */
2570
- get background() {
2571
- const bg = backgroundElementOf(this.part.dom.documentElement);
2572
- if (!bg) return null;
2573
- const themePart = this.master?.theme?.part ?? null;
2574
- return readSlideBackground(bg, "layout", this.themeContext(), this.relationships, themePart ? this.opc.relationshipsFor(themePart.partName) : null);
2575
- }
2576
- /**
2577
- * The layout's colour/font context (walked layout → master → theme), resolved once
2578
- * and cached. Backs each {@link Placeholder}'s text frame.
2579
- */
2580
- themeContext() {
2581
- return this.#themeContext ??= resolveLayoutColorContext(this.opc, this.partName);
2582
- }
2583
- #cSld() {
2584
- return cSldOf(this.part.dom.documentElement);
2585
- }
2586
- #spTree() {
2587
- return spTreeOf(this.part.dom.documentElement);
2588
- }
2589
- };
2590
- //#endregion
2591
2490
  //#region src/read/api/transition.ts
2592
2491
  /**
2593
2492
  * Typed read/edit model for a slide's `p:transition` (slide-show transition).
@@ -5523,6 +5422,6 @@ var Presentation = class Presentation {
5523
5422
  }
5524
5423
  };
5525
5424
  //#endregion
5526
- export { Placeholder as a, Theme as c, NotesSlide as d, OpcPackage as f, ContentTypes as h, Slide as i, readTagsForPart as l, Part as m, readCoreProperties as n, SlideLayout as o, Relationships as p, readCustomProperties as r, SlideMaster as s, Presentation as t, NotesPlaceholder as u };
5425
+ export { readTagsForPart as a, Placeholder as c, Theme as d, OpcPackage as f, ContentTypes as h, Slide as i, SlideLayout as l, Part as m, readCoreProperties as n, NotesPlaceholder as o, Relationships as p, readCustomProperties as r, NotesSlide as s, Presentation as t, SlideMaster as u };
5527
5426
 
5528
- //# sourceMappingURL=presentation-VfJ_FT7E.js.map
5427
+ //# sourceMappingURL=presentation-DrJtj3-C.js.map