@shbernal/ts-pptx 3.3.0 → 3.5.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 (66) hide show
  1. package/dist/{autopage-D1sqK6j7.js → autopage-BYlTzX-l.js} +8 -5
  2. package/dist/autopage-BYlTzX-l.js.map +1 -0
  3. package/dist/browser.d.ts +5 -5
  4. package/dist/browser.js +11 -11
  5. package/dist/browser.js.map +1 -1
  6. package/dist/{diagnostics-B2yWpcjB.d.ts → diagnostics-BDuR8UkG.d.ts} +39 -7
  7. package/dist/diagnostics-BDuR8UkG.d.ts.map +1 -0
  8. package/dist/{diagnostics-H1QzgRSw.js → diagnostics-CPVADSL1.js} +29 -3
  9. package/dist/{diagnostics-H1QzgRSw.js.map → diagnostics-CPVADSL1.js.map} +1 -1
  10. package/dist/{errors-fB1KDJKQ.d.ts → errors-CgnueTYL.d.ts} +3 -3
  11. package/dist/{errors-fB1KDJKQ.d.ts.map → errors-CgnueTYL.d.ts.map} +1 -1
  12. package/dist/{fit-CYJ1jkQI.js → fit-TjpNbMru.js} +3 -3
  13. package/dist/{fit-CYJ1jkQI.js.map → fit-TjpNbMru.js.map} +1 -1
  14. package/dist/{html-dom-CzewEdE1.js → html-dom-yUSdCExA.js} +5 -5
  15. package/dist/html-dom-yUSdCExA.js.map +1 -0
  16. package/dist/html.d.ts +3 -3
  17. package/dist/html.js +1 -1
  18. package/dist/index.d.ts +5 -5
  19. package/dist/index.js +16 -33
  20. package/dist/index.js.map +1 -1
  21. package/dist/inspect.d.ts +28 -4
  22. package/dist/inspect.d.ts.map +1 -1
  23. package/dist/inspect.js +43 -10
  24. package/dist/inspect.js.map +1 -1
  25. package/dist/math.d.ts +1 -1
  26. package/dist/measure.d.ts +2 -2
  27. package/dist/measure.js +1 -1
  28. package/dist/{st-enums-bVnezkMJ.js → namespaces-CcKuzeuE.js} +291 -200
  29. package/dist/namespaces-CcKuzeuE.js.map +1 -0
  30. package/dist/node.d.ts +5 -5
  31. package/dist/node.js +7 -19
  32. package/dist/node.js.map +1 -1
  33. package/dist/{notes-SCvpJz0l.js → notes-DNqAggXx.js} +221 -140
  34. package/dist/notes-DNqAggXx.js.map +1 -0
  35. package/dist/{pres-Cb-1xDne.d.ts → pres-Dybf7ZUl.d.ts} +2 -2
  36. package/dist/{pres-Cb-1xDne.d.ts.map → pres-Dybf7ZUl.d.ts.map} +1 -1
  37. package/dist/{presentation-DeKTJGHf.js → presentation-VfJ_FT7E.js} +306 -234
  38. package/dist/presentation-VfJ_FT7E.js.map +1 -0
  39. package/dist/{presentation-types-B50aOUFI.d.ts → presentation-types-CpkTx9Xa.d.ts} +352 -16
  40. package/dist/presentation-types-CpkTx9Xa.d.ts.map +1 -0
  41. package/dist/read.d.ts +4 -4
  42. package/dist/read.js +3 -3
  43. package/dist/script.d.ts +2 -2
  44. package/dist/script.d.ts.map +1 -1
  45. package/dist/script.js +128 -63
  46. package/dist/script.js.map +1 -1
  47. package/dist/{shapes-BXVgsk0F.js → shapes-Kt51vry6.js} +717 -54
  48. package/dist/shapes-Kt51vry6.js.map +1 -0
  49. package/dist/{slide-DWw9UoI6.d.ts → slide-B_aInw3N.d.ts} +208 -180
  50. package/dist/slide-B_aInw3N.d.ts.map +1 -0
  51. package/dist/{text-uM-zGton.js → text-D04NUMvA.js} +3563 -3437
  52. package/dist/text-D04NUMvA.js.map +1 -0
  53. package/dist/{units-internal-CGf4VrXy.js → units-internal-DNvK2I6o.js} +54 -34
  54. package/dist/{units-internal-CGf4VrXy.js.map → units-internal-DNvK2I6o.js.map} +1 -1
  55. package/dist/zip.d.ts +1 -1
  56. package/package.json +4 -4
  57. package/dist/autopage-D1sqK6j7.js.map +0 -1
  58. package/dist/diagnostics-B2yWpcjB.d.ts.map +0 -1
  59. package/dist/html-dom-CzewEdE1.js.map +0 -1
  60. package/dist/notes-SCvpJz0l.js.map +0 -1
  61. package/dist/presentation-DeKTJGHf.js.map +0 -1
  62. package/dist/presentation-types-B50aOUFI.d.ts.map +0 -1
  63. package/dist/shapes-BXVgsk0F.js.map +0 -1
  64. package/dist/slide-DWw9UoI6.d.ts.map +0 -1
  65. package/dist/st-enums-bVnezkMJ.js.map +0 -1
  66. package/dist/text-uM-zGton.js.map +0 -1
@@ -1,9 +1,9 @@
1
1
  import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-Bvln0H-7.js";
2
- import { ft as emuToInches } from "./units-internal-CGf4VrXy.js";
3
- import { E as voidEl, T as raw, _ as FONT_DATA_EXTENSION, g as FONT_DATA_CONTENT_TYPE, h as EMBEDDED_FONT_SLOTS, n as makeXmlNotesMaster, o as makeXmlNotesSlideSkeleton, v as FONT_REL_TYPE, w as el } from "./notes-SCvpJz0l.js";
4
- import { _ as SLIDE_LAYOUT_REL, b as THEME_REL, d as IMAGE_REL, f as NOTES_MASTER_REL, h as OFFICE_REL, m as OFFICE_DOCUMENT_REL, p as NOTES_SLIDE_REL, v as SLIDE_MASTER_REL, y as SLIDE_REL } from "./st-enums-bVnezkMJ.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";
5
5
  import { ZipWriter, readZip } from "./zip.js";
6
- import { $ as parseClrScheme, A as readGradientFill, At as getElements, B as placeholderInheritedAnchor, Bt as setAttr, Ct as boolValue, D as spPrXfrmEmu, Dt as escapeXmlAttribute, E as TextFrame, Et as descendantsByTag, F as resolveSlideColorContext, Ft as parseXml, G as placeholderOf, H as placeholderInheritedListStyles, I as resolveSlideThemeParts, It as removeAttr, J as SCHEME_SLOTS, K as slideDefinesColor, Lt as removeChildrenByQName, M as resolveLayoutColorContext, Mt as insertInOrder, N as resolveMasterColorContext, Nt as intValue, O as readPatternFill, Ot as firstChild, P as resolveNotesColorContext, Pt as ownerDocumentOf, Q as parseClrMap, R as LST_STYLE_LEVELS, Rt as replaceInParent, S as AutoShape, St as attr, Tt as createElement, U as placeholderInheritedRunProps, V as placeholderInheritedColor, W as placeholderInheritedXfrm, X as intAttr, Y as fmtEntry, Z as isA, _t as relsPartNameFor, at as FILL_CHOICES, bt as zipPathToPartName, ct as SPPR_AFTER_XFRM, dt as SPPR_LN_AFTER, et as resolveColor, ft as SPPR_SCENE3D_AFTER, gt as relativePartName, ht as partNameToZipPath, it as substitutePhClr, j as resolveColorElement, jt as getOrAddChild, k as readPictureFill, kt as firstChildElement, l as wrapShapeElement, lt as SPPR_EFFECT_AFTER, mt as partNameExtension, n as buildShapes, nt as styleRefFill, ot as RPR_FILL_AFTER, pt as SPPR_SP3D_AFTER, q as slideDefinesProp, r as findShapeByIdDeep, rt as styleRefLine, st as SHAPE_AFTER_SPPR, t as GroupShape, tt as resolveSchemeToken, u as GraphicFrame, ut as SPPR_FILL_AFTER, vt as resolveRelativePartName, wt as childElements, x as Picture, xt as OOXML_NS, yt as resolveSingleRel, z as RUN_PROP_NAMES, zt as serializeXml } from "./shapes-BXVgsk0F.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";
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
@@ -594,7 +594,7 @@ function reverseClrMap(clrMap) {
594
594
  function applyInheritedBackground(slideRoot, ctx) {
595
595
  const inherited = ctx.inheritedBackground;
596
596
  if (!inherited) return;
597
- const cSld = firstChild(slideRoot, "p:cSld");
597
+ const cSld = cSldOf(slideRoot);
598
598
  if (!cSld || firstChild(cSld, "p:bg")) return;
599
599
  const bg = ownerDocumentOf(slideRoot).importNode(inherited, true);
600
600
  insertInOrder(cSld, bg, [
@@ -644,6 +644,28 @@ function resolveSchemeColors(root, ctx) {
644
644
  * re-bind to the destination styles.
645
645
  */
646
646
  function resolvePlaceholderRunColors(slideRoot, ctx) {
647
+ bakePlaceholderRunProperty(slideRoot, ctx, placeholderInheritedColor, (run, color, pPr, slideLst, level) => {
648
+ if (slideDefinesColor(run, pPr, slideLst, level)) return;
649
+ writeRunColor(run, color);
650
+ });
651
+ }
652
+ /**
653
+ * The traversal both run-property passes share: every placeholder shape's text body, every
654
+ * paragraph in it, every `a:r` and `a:fld` in that paragraph.
655
+ *
656
+ * `resolve` is asked once per *list level* per shape and memoized, because walking the
657
+ * layout/master style chain is the expensive half and every paragraph at the same level gets
658
+ * the same answer. `write` then runs per run, and owns the decision to skip a run the slide
659
+ * already fixes — the two passes ask that question differently (one colour check versus three
660
+ * independent property checks), so it stays on their side of the boundary rather than becoming
661
+ * a predicate parameter only one caller could use.
662
+ *
663
+ * @param slideRoot - the slide part's root element
664
+ * @param ctx - the flatten context, carrying the source layout/master roots
665
+ * @param resolve - the inherited value for a placeholder type/idx at a list level, or `null`
666
+ * @param write - apply a resolved value to one run
667
+ */
668
+ function bakePlaceholderRunProperty(slideRoot, ctx, resolve, write) {
647
669
  if (!ctx.layoutRoot && !ctx.masterRoot) return;
648
670
  for (const sp of descendantsByTag(slideRoot, OOXML_NS.p, "sp")) {
649
671
  const ph = placeholderOf(sp);
@@ -659,16 +681,13 @@ function resolvePlaceholderRunColors(slideRoot, ctx) {
659
681
  const level = (pPr && intValue(attr(pPr, "lvl"))) ?? 0;
660
682
  const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
661
683
  if (runs.length === 0) continue;
662
- let color = byLevel.get(level);
663
- if (color === void 0) {
664
- color = placeholderInheritedColor(type, idx, level, ctx);
665
- byLevel.set(level, color);
666
- }
667
- if (!color) continue;
668
- for (const run of runs) {
669
- if (slideDefinesColor(run, pPr, slideLst, level)) continue;
670
- writeRunColor(run, color);
684
+ let value = byLevel.get(level);
685
+ if (value === void 0) {
686
+ value = resolve(type, idx, level, ctx);
687
+ byLevel.set(level, value);
671
688
  }
689
+ if (!value) continue;
690
+ for (const run of runs) write(run, value, pPr, slideLst, level);
672
691
  }
673
692
  }
674
693
  }
@@ -788,8 +807,7 @@ function resolvePlaceholderListStyle(shapeRoot, ctx) {
788
807
  */
789
808
  function demotePlaceholders(shapeRoot) {
790
809
  for (const sp of descendantsByTag(shapeRoot, OOXML_NS.p, "sp")) {
791
- const nvSpPr = firstChild(sp, "p:nvSpPr");
792
- const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
810
+ const nvPr = nvPrOf(sp);
793
811
  if (nvPr) removeChildrenByQName(nvPr, ["p:ph"]);
794
812
  }
795
813
  }
@@ -803,30 +821,7 @@ function demotePlaceholders(shapeRoot) {
803
821
  * is left to re-bind to the destination theme, as the colour pass does for the `fontRef`.
804
822
  */
805
823
  function resolvePlaceholderRunSizes(slideRoot, ctx) {
806
- if (!ctx.layoutRoot && !ctx.masterRoot) return;
807
- for (const sp of descendantsByTag(slideRoot, OOXML_NS.p, "sp")) {
808
- const ph = placeholderOf(sp);
809
- if (!ph) continue;
810
- const txBody = firstChild(sp, "p:txBody");
811
- if (!txBody) continue;
812
- const type = attr(ph, "type");
813
- const idx = attr(ph, "idx") ?? "0";
814
- const slideLst = firstChild(txBody, "a:lstStyle");
815
- const byLevel = /* @__PURE__ */ new Map();
816
- for (const p of getElements(txBody, "a:p")) {
817
- const pPr = firstChild(p, "a:pPr");
818
- const level = (pPr && intValue(attr(pPr, "lvl"))) ?? 0;
819
- const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
820
- if (runs.length === 0) continue;
821
- let props = byLevel.get(level);
822
- if (props === void 0) {
823
- props = placeholderInheritedRunProps(type, idx, level, ctx);
824
- byLevel.set(level, props);
825
- }
826
- if (!props) continue;
827
- for (const run of runs) writeRunProps(run, props, pPr, slideLst, level);
828
- }
829
- }
824
+ bakePlaceholderRunProperty(slideRoot, ctx, placeholderInheritedRunProps, writeRunProps);
830
825
  }
831
826
  /** Write each resolved run property onto a run's `a:rPr`, skipping ones the slide already fixes. */
832
827
  function writeRunProps(run, props, pPr, slideLst, level) {
@@ -907,7 +902,7 @@ function neutralizeRef(ref) {
907
902
  */
908
903
  /** The `p:cSld/p:bg` element of a slide/layout/master root, or `null`. */
909
904
  function backgroundElementOf(root) {
910
- const cSld = root && firstChild(root, "p:cSld");
905
+ const cSld = cSldOf(root);
911
906
  return cSld ? firstChild(cSld, "p:bg") : null;
912
907
  }
913
908
  /**
@@ -1012,8 +1007,7 @@ var NotesPlaceholder = class {
1012
1007
  this.relationships = relationships;
1013
1008
  }
1014
1009
  #ph() {
1015
- const nvSpPr = firstChild(this.sp, "p:nvSpPr");
1016
- const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
1010
+ const nvPr = nvPrOf(this.sp);
1017
1011
  return nvPr ? firstChild(nvPr, "p:ph") : null;
1018
1012
  }
1019
1013
  #cNvPr() {
@@ -1147,12 +1141,26 @@ var NotesSlide = class {
1147
1141
  return this.placeholders.find((ph) => ph.type === type) ?? null;
1148
1142
  }
1149
1143
  #spTree() {
1150
- const root = this.part.dom.documentElement;
1151
- const cSld = root && firstChild(root, "p:cSld");
1152
- return cSld ? firstChild(cSld, "p:spTree") : null;
1144
+ return spTreeOf(this.part.dom.documentElement);
1153
1145
  }
1154
1146
  };
1155
1147
  //#endregion
1148
+ //#region src/read/api/ops/deck-target.ts
1149
+ /**
1150
+ * `ppt/_rels/presentation.xml.rels` -- the deck's own relationship part.
1151
+ *
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
1159
+ */
1160
+ function presentationRels(dest) {
1161
+ return dest.opc.relationshipsFor(dest.presentationPart.partName);
1162
+ }
1163
+ //#endregion
1156
1164
  //#region src/read/api/ops/master-registry.ts
1157
1165
  /**
1158
1166
  * Slide-master bookkeeping in `presentation.xml` and in a master's own
@@ -1175,7 +1183,7 @@ var NotesSlide = class {
1175
1183
  */
1176
1184
  function registerMaster(dest, masterPartName) {
1177
1185
  const presPart = dest.presentationPart;
1178
- const presRels = dest.opc.relationshipsFor(presPart.partName);
1186
+ const presRels = presentationRels(dest);
1179
1187
  for (const rel of presRels.byType(SLIDE_MASTER_REL)) if (presRels.resolveTarget(rel.id) === masterPartName) return;
1180
1188
  const relId = presRels.add(SLIDE_MASTER_REL, relativePartName(presPart.partName, masterPartName)).id;
1181
1189
  const root = presPart.dom.documentElement;
@@ -1214,7 +1222,7 @@ function promoteMasters(dest, masterPartNames) {
1214
1222
  const root = presPart.dom.documentElement;
1215
1223
  const lst = root && firstChild(root, "p:sldMasterIdLst");
1216
1224
  if (!lst) return;
1217
- const rels = dest.opc.relationshipsFor(presPart.partName);
1225
+ const rels = presentationRels(dest);
1218
1226
  const promote = new Set(masterPartNames);
1219
1227
  const entries = getElements(lst, "p:sldMasterId");
1220
1228
  const isPromoted = (entry) => {
@@ -1240,14 +1248,13 @@ function promoteMasters(dest, masterPartNames) {
1240
1248
  */
1241
1249
  function nextMasterLayoutId(dest) {
1242
1250
  let max = 2147483647;
1243
- const presPart = dest.presentationPart;
1244
- const root = presPart.dom.documentElement;
1251
+ const root = dest.presentationPart.dom.documentElement;
1245
1252
  const masterLst = root && firstChild(root, "p:sldMasterIdLst");
1246
1253
  if (masterLst) for (const entry of getElements(masterLst, "p:sldMasterId")) {
1247
1254
  const id = intValue(attr(entry, "id"));
1248
1255
  if (id !== null && id > max) max = id;
1249
1256
  }
1250
- const presRels = dest.opc.relationshipsFor(presPart.partName);
1257
+ const presRels = presentationRels(dest);
1251
1258
  for (const rel of presRels.byType(SLIDE_MASTER_REL)) {
1252
1259
  const masterRoot = dest.opc.part(presRels.resolveTarget(rel.id))?.dom.documentElement;
1253
1260
  const layoutLst = masterRoot && firstChild(masterRoot, "p:sldLayoutIdLst");
@@ -1384,10 +1391,149 @@ function duplicateSubtree(opc, partName, copies) {
1384
1391
  return fresh;
1385
1392
  }
1386
1393
  //#endregion
1394
+ //#region src/read/api/ops/part-reuse.ts
1395
+ /**
1396
+ * Recognising a part the destination deck **already holds**, so an import binds to it
1397
+ * instead of copying it in again.
1398
+ *
1399
+ * The case this exists for is the deck templated from its own source. `fromTemplate`
1400
+ * keeps a package's masters, layouts and theme byte-identical and strips only its
1401
+ * slides, so a script that then imports a slide back out of that same file hands
1402
+ * `copyPart` a `slideLayout -> slideMaster -> theme` subgraph whose every part is
1403
+ * already in the destination under its own partname. The copy registry maps *source*
1404
+ * partnames to copies this import made and knows nothing about what the destination
1405
+ * arrived with, so each of those parts was copied again: the output grew a duplicate
1406
+ * layout and master per imported slide, visible in PowerPoint's layout picker and
1407
+ * enough to make a later `appendSlides({ layout: <name> })` ambiguous.
1408
+ *
1409
+ * The test is deliberately strict, because the cost of getting it wrong is a slide
1410
+ * bound to chrome that only resembles what it asked for. A part is reusable only when
1411
+ * the destination holds it at the *same partname*, with the same content type, the same
1412
+ * bytes (as they would be written, so an edited destination part disqualifies itself),
1413
+ * the same relationships, and the same rule applied recursively to everything those
1414
+ * relationships reach. Byte-equality all the way down means "reuse" and "copy" produce
1415
+ * the same rendering; anything less falls back to the copy, which is always correct and
1416
+ * merely wasteful.
1417
+ *
1418
+ * Two further conditions have nothing to do with identity and everything to do with the
1419
+ * destination being a real deck: a reused master must already be registered in
1420
+ * `presentation.xml`, and a reused layout must already sit in a registered master's
1421
+ * `p:sldLayoutIdLst`. An identical part that is an orphan in the destination is not
1422
+ * something to bind a slide to, and the copy path (which registers and links what it
1423
+ * copies) is the right answer there.
1424
+ *
1425
+ * Reuse mutates nothing, which is what lets it hold across repeated imports: the
1426
+ * destination's chrome stays byte-identical, so the second import recognises it exactly
1427
+ * as the first one did.
1428
+ */
1429
+ /**
1430
+ * Whether the destination already holds `sourcePartName`'s subgraph, part for part and
1431
+ * byte for byte, in a state an imported slide can bind to.
1432
+ *
1433
+ * @param dest the deck being imported into
1434
+ * @param source the package being imported out of
1435
+ * @param sourcePartName the part the copy is about to make
1436
+ * @return `true` when the copy can be skipped and the existing part used
1437
+ */
1438
+ function destinationAlreadyHolds(dest, source, sourcePartName) {
1439
+ const part = dest.opc.part(sourcePartName);
1440
+ if (!part || part.contentType === "application/vnd.openxmlformats-officedocument.presentationml.slide+xml") return false;
1441
+ if (!identicalSubgraph(dest.opc, source, sourcePartName, /* @__PURE__ */ new Set())) return false;
1442
+ return wiredIntoDeck(dest, sourcePartName);
1443
+ }
1444
+ /**
1445
+ * `partName` and everything it reaches are the same in both packages: same content type,
1446
+ * same body bytes, same relationships, recursively.
1447
+ *
1448
+ * The destination side is compared as it would be **written** (`serialize()`), not as it
1449
+ * was read, so a part some earlier edit marked dirty is treated as different even when
1450
+ * the edit was a no-op. Under-reusing costs a duplicated part; over-reusing binds a slide
1451
+ * to something else's chrome.
1452
+ *
1453
+ * The traversal skips exactly what `copyPart` skips — the notes relationship, and a
1454
+ * master's relationships to its layouts — so it asks about the subgraph the copy would
1455
+ * actually have made. Skipping the master's layout list is what keeps one edited layout
1456
+ * from disqualifying every *other* layout that shares its master.
1457
+ */
1458
+ function identicalSubgraph(dest, source, partName, visited) {
1459
+ if (visited.has(partName)) return true;
1460
+ visited.add(partName);
1461
+ const sourcePart = source.part(partName);
1462
+ const destPart = dest.part(partName);
1463
+ if (!sourcePart || !destPart) return false;
1464
+ if (sourcePart.contentType !== destPart.contentType) return false;
1465
+ if (!bytesEqual(sourcePart.bytes, destPart.serialize())) return false;
1466
+ const sourceRels = [...source.relationshipsFor(partName)];
1467
+ const destRels = [...dest.relationshipsFor(partName)];
1468
+ if (sourceRels.length !== destRels.length) return false;
1469
+ const isMaster = sourcePart.contentType === SLIDE_MASTER_CONTENT_TYPE;
1470
+ const destById = new Map(destRels.map((rel) => [rel.id, rel]));
1471
+ for (const rel of sourceRels) {
1472
+ const counterpart = destById.get(rel.id);
1473
+ if (!counterpart) return false;
1474
+ if (counterpart.type !== rel.type || counterpart.targetMode !== rel.targetMode) return false;
1475
+ if (rel.targetMode === "External") {
1476
+ if (counterpart.target !== rel.target) return false;
1477
+ continue;
1478
+ }
1479
+ const target = source.relationshipsFor(partName).resolveTarget(rel.id);
1480
+ if (dest.relationshipsFor(partName).resolveTarget(rel.id) !== target) return false;
1481
+ if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") continue;
1482
+ if (isMaster && rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") continue;
1483
+ if (!identicalSubgraph(dest, source, target, visited)) return false;
1484
+ }
1485
+ return true;
1486
+ }
1487
+ /**
1488
+ * Whether the destination's copy of this part is wired into the deck, for the two kinds
1489
+ * where "present in the package" is not the same as "usable".
1490
+ *
1491
+ * A master absent from `p:sldMasterIdLst` is inert: renderers ignore its background and
1492
+ * shape tree, so a slide bound through it renders blank. A layout absent from a
1493
+ * registered master's `p:sldLayoutIdLst` is not in the deck's gallery, so `layouts()`
1494
+ * cannot name it and `appendSlides` cannot bind to it. Every other kind (theme, media,
1495
+ * table styles) is reached by relationship alone and needs no registration.
1496
+ */
1497
+ function wiredIntoDeck(dest, partName) {
1498
+ const contentType = dest.opc.part(partName)?.contentType;
1499
+ if (contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml") return registeredMasters(dest).includes(partName);
1500
+ if (contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml") return registeredMasters(dest).some((master) => galleryOf(dest, master).includes(partName));
1501
+ return true;
1502
+ }
1503
+ /** The destination's masters in `p:sldMasterIdLst` order — the ones renderers treat as active. */
1504
+ function registeredMasters(dest) {
1505
+ const root = dest.presentationPart.dom.documentElement;
1506
+ const lst = root && firstChild(root, "p:sldMasterIdLst");
1507
+ if (!lst) return [];
1508
+ const rels = presentationRels(dest);
1509
+ return idListTargets(lst, "p:sldMasterId", (relId) => rels.resolveTarget(relId));
1510
+ }
1511
+ /** One master's layouts in `p:sldLayoutIdLst` order — its slice of the deck's gallery. */
1512
+ function galleryOf(dest, masterPartName) {
1513
+ const root = dest.opc.part(masterPartName)?.dom.documentElement;
1514
+ const lst = root && firstChild(root, "p:sldLayoutIdLst");
1515
+ if (!lst) return [];
1516
+ const rels = dest.opc.relationshipsFor(masterPartName);
1517
+ return idListTargets(lst, "p:sldLayoutId", (relId) => rels.resolveTarget(relId));
1518
+ }
1519
+ /** Resolve every `@r:id` in an id list to its partname, skipping entries that carry none. */
1520
+ function idListTargets(lst, qname, resolve) {
1521
+ const out = [];
1522
+ for (const entry of getElements(lst, qname)) {
1523
+ const relId = attr(entry, "r:id");
1524
+ if (relId) out.push(resolve(relId));
1525
+ }
1526
+ return out;
1527
+ }
1528
+ /** Byte-for-byte equality of two part bodies. */
1529
+ function bytesEqual(a, b) {
1530
+ if (a === b) return true;
1531
+ if (a.length !== b.length) return false;
1532
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
1533
+ return true;
1534
+ }
1535
+ //#endregion
1387
1536
  //#region src/read/api/ops/part-copy.ts
1388
- const SLIDE_MASTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml";
1389
- const SLIDE_LAYOUT_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml";
1390
- const NOTES_SLIDE_CONTENT_TYPE$2 = "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml";
1391
1537
  /** Open an ownership scope for one page copy. */
1392
1538
  function newOwnedScope() {
1393
1539
  return /* @__PURE__ */ new Map();
@@ -1444,7 +1590,7 @@ function copySlidePart(ctx, sourcePartName) {
1444
1590
  * from outside, as the rebinding import paths do for the page they build
1445
1591
  * themselves.
1446
1592
  */
1447
- function copyPart(ctx, sourcePartName, owned) {
1593
+ function copyPart(ctx, sourcePartName, owned, allowReuse = false) {
1448
1594
  if (owned) {
1449
1595
  const alreadyOwned = owned.get(sourcePartName);
1450
1596
  if (alreadyOwned !== void 0) return alreadyOwned;
@@ -1453,6 +1599,12 @@ function copyPart(ctx, sourcePartName, owned) {
1453
1599
  const selectedDest = ctx.selection?.destinations.get(sourcePartName);
1454
1600
  if (existing && (selectedDest === void 0 || existing === selectedDest)) return existing;
1455
1601
  }
1602
+ if (allowReuse && !owned && !ctx.selection?.destinations.has(sourcePartName)) {
1603
+ if (destinationAlreadyHolds(ctx.dest, ctx.source, sourcePartName)) {
1604
+ ctx.registry.set(sourcePartName, sourcePartName);
1605
+ return sourcePartName;
1606
+ }
1607
+ }
1456
1608
  const sourcePart = ctx.source.part(sourcePartName);
1457
1609
  if (!sourcePart) throw new PackageReadError("package/part-missing", `importSlide: source package has no part ${sourcePartName}`);
1458
1610
  const newPartName = owned ? ctx.dest.opc.reservePartNameLike(sourcePartName) : ctx.selection?.destinations.get(sourcePartName) ?? ctx.dest.opc.reservePartNameLike(sourcePartName);
@@ -1461,6 +1613,7 @@ function copyPart(ctx, sourcePartName, owned) {
1461
1613
  else ctx.registry.set(sourcePartName, newPartName);
1462
1614
  const scope = owned ?? (ctx.selection?.destinations.has(sourcePartName) ? newOwnedScope() : void 0);
1463
1615
  const isMaster = sourcePart.contentType === SLIDE_MASTER_CONTENT_TYPE;
1616
+ const isPage = sourcePart.contentType === SLIDE_CONTENT_TYPE;
1464
1617
  const sourceRels = ctx.source.relationshipsFor(sourcePartName);
1465
1618
  const targetRels = ctx.dest.opc.relationshipsFor(newPartName);
1466
1619
  for (const rel of sourceRels) {
@@ -1470,14 +1623,14 @@ function copyPart(ctx, sourcePartName, owned) {
1470
1623
  targetRels.addWithId(rel.id, rel.type, rel.target, "External");
1471
1624
  continue;
1472
1625
  }
1473
- const newTargetPartName = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : scope);
1626
+ const newTargetPartName = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : scope, isPage);
1474
1627
  targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTargetPartName));
1475
1628
  }
1476
1629
  if (isMaster) {
1477
1630
  clearLayoutIdList(ctx.dest, newPartName);
1478
1631
  registerMaster(ctx.dest, newPartName);
1479
1632
  }
1480
- if (sourcePart.contentType === SLIDE_LAYOUT_CONTENT_TYPE) linkLayoutIntoMaster(ctx, sourceRels, newPartName);
1633
+ if (sourcePart.contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml") linkLayoutIntoMaster(ctx, sourceRels, newPartName);
1481
1634
  return newPartName;
1482
1635
  }
1483
1636
  const NO_NOTES = {
@@ -1516,8 +1669,8 @@ function checkSelectionCopyable(source, registry, selected, notes = NO_NOTES) {
1516
1669
  const part = source.part(partName);
1517
1670
  if (!part) throw new PackageReadError("package/part-missing", `importSlides: source package has no part ${partName}`);
1518
1671
  const isMaster = part.contentType === SLIDE_MASTER_CONTENT_TYPE;
1519
- const isNotesSlide = part.contentType === NOTES_SLIDE_CONTENT_TYPE$2;
1520
- if (isMaster || part.contentType === SLIDE_LAYOUT_CONTENT_TYPE) part.dom;
1672
+ const isNotesSlide = part.contentType === NOTES_SLIDE_CONTENT_TYPE;
1673
+ if (isMaster || part.contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml") part.dom;
1521
1674
  const rels = source.relationshipsFor(partName);
1522
1675
  for (const rel of rels) {
1523
1676
  if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") {
@@ -1563,8 +1716,6 @@ function linkLayoutIntoMaster(ctx, layoutSourceRels, layoutPartName) {
1563
1716
  * `Presentation`-to-`Presentation` path and the generator-XML path funnel through
1564
1717
  * `registerNotesMaster`: they differ only in how the *part* comes into being.
1565
1718
  */
1566
- const NOTES_MASTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml";
1567
- const THEME_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.theme+xml";
1568
1719
  const textEncoder$3 = new TextEncoder();
1569
1720
  /**
1570
1721
  * Carry the source slide's speaker notes onto the just-imported slide (the
@@ -1625,8 +1776,7 @@ function carryNotes(dest, source, ctx, sourceSlidePartName, newSlidePartName) {
1625
1776
  * registered in `presentation.xml`. Returns the destination notesMaster partname.
1626
1777
  */
1627
1778
  function ensureNotesMaster(dest, ctx, sourceNotesMasterPartName) {
1628
- const presPart = dest.presentationPart;
1629
- const presRels = dest.opc.relationshipsFor(presPart.partName);
1779
+ const presRels = presentationRels(dest);
1630
1780
  const existing = presRels.byType(NOTES_MASTER_REL)[0];
1631
1781
  if (existing) return presRels.resolveTarget(existing.id);
1632
1782
  return registerNotesMaster(dest, copyPart(ctx, sourceNotesMasterPartName));
@@ -1643,7 +1793,7 @@ function ensureNotesMaster(dest, ctx, sourceNotesMasterPartName) {
1643
1793
  */
1644
1794
  function registerNotesMaster(dest, notesMasterPartName) {
1645
1795
  const presPart = dest.presentationPart;
1646
- const relId = dest.opc.relationshipsFor(presPart.partName).add(NOTES_MASTER_REL, relativePartName(presPart.partName, notesMasterPartName)).id;
1796
+ const relId = presentationRels(dest).add(NOTES_MASTER_REL, relativePartName(presPart.partName, notesMasterPartName)).id;
1647
1797
  const root = presPart.dom.documentElement;
1648
1798
  if (!root) throw new PackageReadError("package/part-has-no-root", "presentation.xml has no document element to register a notes master in");
1649
1799
  const lst = getOrAddChild(root, "p:notesMasterIdLst", [
@@ -1675,8 +1825,7 @@ function registerNotesMaster(dest, notesMasterPartName) {
1675
1825
  * theme its `.rels` requires (the normal write path emits that as `theme2.xml`).
1676
1826
  */
1677
1827
  function ensureNotesMasterFromXml(dest, master) {
1678
- const presPart = dest.presentationPart;
1679
- const presRels = dest.opc.relationshipsFor(presPart.partName);
1828
+ const presRels = presentationRels(dest);
1680
1829
  const existing = presRels.byType(NOTES_MASTER_REL)[0];
1681
1830
  if (existing) return presRels.resolveTarget(existing.id);
1682
1831
  const masterPartName = dest.opc.reservePartNameLike("/ppt/notesMasters/notesMaster1.xml");
@@ -1712,8 +1861,7 @@ function ensureNotesMasterFromXml(dest, master) {
1712
1861
  * @return {string} the destination notesMaster partname
1713
1862
  */
1714
1863
  function ensureNotesMasterForAuthoring(dest, slidePartName) {
1715
- const presPart = dest.presentationPart;
1716
- const presRels = dest.opc.relationshipsFor(presPart.partName);
1864
+ const presRels = presentationRels(dest);
1717
1865
  const existing = presRels.byType(NOTES_MASTER_REL)[0];
1718
1866
  if (existing) return presRels.resolveTarget(existing.id);
1719
1867
  const themePartName = resolveSlideThemeParts(dest.opc, slidePartName).themePartName;
@@ -1755,8 +1903,6 @@ function ensureNotesMasterForAuthoring(dest, slidePartName) {
1755
1903
  * multi-run paragraphs are reached afterwards through `slide.notesTextFrame`, which
1756
1904
  * is the read model's normal text-editing surface.
1757
1905
  */
1758
- const NOTES_SLIDE_CONTENT_TYPE$1 = "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml";
1759
- const A_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
1760
1906
  const textEncoder$2 = new TextEncoder();
1761
1907
  /**
1762
1908
  * The `a:p` children of a notes body, one per `\n`-separated line: the write path's
@@ -1791,7 +1937,7 @@ function replaceNotesParagraphs(txBody, text) {
1791
1937
  const doc = txBody.ownerDocument;
1792
1938
  if (!doc) throw new InternalError("oxml/node-has-no-document", "Notes body has no owner document");
1793
1939
  removeChildrenByQName(txBody, ["a:p"]);
1794
- const wrapper = parseXml(`<w xmlns:a="${A_NS}">${notesParagraphsXml(text)}</w>`).documentElement;
1940
+ const wrapper = parseXml(`<w xmlns:a="${OOXML_NS.a}">${notesParagraphsXml(text)}</w>`).documentElement;
1795
1941
  if (!wrapper) throw new InternalError("oxml/node-has-no-document", "Authored notes paragraphs did not parse to a root");
1796
1942
  for (const paragraph of Array.from(wrapper.childNodes)) txBody.appendChild(doc.importNode(paragraph, true));
1797
1943
  }
@@ -1804,12 +1950,10 @@ function replaceNotesParagraphs(txBody, text) {
1804
1950
  * @return {Element | null} the body placeholder's text body
1805
1951
  */
1806
1952
  function notesBodyTxBody(root) {
1807
- const cSld = root && firstChild(root, "p:cSld");
1808
- const spTree = cSld && firstChild(cSld, "p:spTree");
1953
+ const spTree = spTreeOf(root);
1809
1954
  if (!spTree) return null;
1810
1955
  for (const sp of getElements(spTree, "p:sp")) {
1811
- const nvSpPr = firstChild(sp, "p:nvSpPr");
1812
- const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
1956
+ const nvPr = nvPrOf(sp);
1813
1957
  const ph = nvPr && firstChild(nvPr, "p:ph");
1814
1958
  if (ph && attr(ph, "type") === "body") return firstChild(sp, "p:txBody");
1815
1959
  }
@@ -1848,7 +1992,7 @@ function authorNotes(slide, text) {
1848
1992
  }
1849
1993
  const slideNum = slide.index + 1;
1850
1994
  const partName = opc.reservePartNameLike("/ppt/notesSlides/notesSlide1.xml");
1851
- opc.addPart(partName, NOTES_SLIDE_CONTENT_TYPE$1, textEncoder$2.encode(makeXmlNotesSlideSkeleton(notesParagraphsXml(text), slideNum)));
1995
+ opc.addPart(partName, NOTES_SLIDE_CONTENT_TYPE, textEncoder$2.encode(makeXmlNotesSlideSkeleton(notesParagraphsXml(text), slideNum)));
1852
1996
  slide.relationships.add(NOTES_SLIDE_REL, relativePartName(slide.partName, partName));
1853
1997
  const notesRels = opc.relationshipsFor(partName);
1854
1998
  const masterPartName = ensureNotesMasterForAuthoring(slide.presentation, slide.partName);
@@ -2328,12 +2472,10 @@ var SlideMaster = class {
2328
2472
  return rel ? this.opc.part(rels.resolveTarget(rel.id)) ?? null : null;
2329
2473
  }
2330
2474
  #cSld() {
2331
- const root = this.part.dom.documentElement;
2332
- return root ? firstChild(root, "p:cSld") : null;
2475
+ return cSldOf(this.part.dom.documentElement);
2333
2476
  }
2334
2477
  #spTree() {
2335
- const cSld = this.#cSld();
2336
- return cSld ? firstChild(cSld, "p:spTree") : null;
2478
+ return spTreeOf(this.part.dom.documentElement);
2337
2479
  }
2338
2480
  };
2339
2481
  /**
@@ -2439,12 +2581,10 @@ var SlideLayout = class {
2439
2581
  return this.#themeContext ??= resolveLayoutColorContext(this.opc, this.partName);
2440
2582
  }
2441
2583
  #cSld() {
2442
- const root = this.part.dom.documentElement;
2443
- return root ? firstChild(root, "p:cSld") : null;
2584
+ return cSldOf(this.part.dom.documentElement);
2444
2585
  }
2445
2586
  #spTree() {
2446
- const cSld = this.#cSld();
2447
- return cSld ? firstChild(cSld, "p:spTree") : null;
2587
+ return spTreeOf(this.part.dom.documentElement);
2448
2588
  }
2449
2589
  };
2450
2590
  //#endregion
@@ -3103,9 +3243,14 @@ var Slide = class {
3103
3243
  * All text on the slide, flattened in document order — the read-model
3104
3244
  * counterpart to {@link TextFrame.text} one level up. Every text-bearing shape
3105
3245
  * contributes its text, recursing into groups ({@link GroupShape}) and reading
3106
- * table cells ({@link GraphicFrame.table}); text-free shapes (pictures,
3107
- * connectors, empty boxes) contribute nothing. Blocks are joined by `\n`; within
3108
- * a table, cells in a row are joined by `\t` and rows by `\n`.
3246
+ * table cells ({@link GraphicFrame.table}) and SmartArt node text
3247
+ * ({@link GraphicFrame.diagram}); text-free shapes (pictures, connectors, empty
3248
+ * boxes) contribute nothing. Blocks are joined by `\n`; within a table, cells in
3249
+ * a row are joined by `\t` and rows by `\n`.
3250
+ *
3251
+ * A diagram contributes for the same reason a table does: its nodes are body text
3252
+ * PowerPoint itself searches and spell-checks, so a slide whose whole message is a
3253
+ * SmartArt graphic would otherwise flatten to the empty string.
3109
3254
  *
3110
3255
  * This is deliberately scoped to the slide's own shape tree. It does **not**
3111
3256
  * include speaker notes (read those via {@link notesText}) or chart data labels
@@ -3119,11 +3264,16 @@ var Slide = class {
3119
3264
  for (const shape of shapes) if (shape instanceof GroupShape) walk(shape.shapes);
3120
3265
  else if (shape instanceof GraphicFrame) {
3121
3266
  const table = shape.table;
3122
- if (!table) continue;
3123
- for (const row of table.rows) {
3124
- const cells = row.cells.map((cell) => cell.text);
3125
- if (cells.some((cell) => cell.length > 0)) blocks.push(cells.join(" "));
3267
+ if (table) {
3268
+ for (const row of table.rows) {
3269
+ const cells = row.cells.map((cell) => cell.text);
3270
+ if (cells.some((cell) => cell.length > 0)) blocks.push(cells.join(" "));
3271
+ }
3272
+ continue;
3126
3273
  }
3274
+ const diagram = shape.diagram;
3275
+ const diagramText = diagram ? diagram.text : "";
3276
+ if (diagramText.length > 0) blocks.push(diagramText);
3127
3277
  } else {
3128
3278
  const text = shape.text;
3129
3279
  if (text.length > 0) blocks.push(text);
@@ -3462,12 +3612,10 @@ var Slide = class {
3462
3612
  return max + 1;
3463
3613
  }
3464
3614
  #cSld() {
3465
- const root = this.part.dom.documentElement;
3466
- return root ? firstChild(root, "p:cSld") : null;
3615
+ return cSldOf(this.part.dom.documentElement);
3467
3616
  }
3468
3617
  #spTree() {
3469
- const cSld = this.#cSld();
3470
- return cSld ? firstChild(cSld, "p:spTree") : null;
3618
+ return spTreeOf(this.part.dom.documentElement);
3471
3619
  }
3472
3620
  };
3473
3621
  function requireFinite(value, name) {
@@ -3477,39 +3625,53 @@ function requirePositive(value, name) {
3477
3625
  requireFinite(value, name);
3478
3626
  if (value <= 0) throw new InvalidOptionError("coord/not-positive", `${name} must be positive, got ${value}`);
3479
3627
  }
3480
- /** Build a minimal, schema-valid text-box `p:sp` element (not yet attached). */
3481
- function buildTextBox(doc, spec) {
3482
- const make = (qname) => createElement(doc, qname);
3483
- const append = (parent, qname) => {
3484
- const child = make(qname);
3485
- parent.appendChild(child);
3486
- return child;
3487
- };
3488
- const sp = make("p:sp");
3489
- const nvSpPr = append(sp, "p:nvSpPr");
3490
- const cNvPr = append(nvSpPr, "p:cNvPr");
3491
- setAttr(cNvPr, "id", String(spec.id));
3492
- setAttr(cNvPr, "name", spec.name);
3493
- const cNvSpPr = append(nvSpPr, "p:cNvSpPr");
3494
- setAttr(cNvSpPr, "txBox", "1");
3495
- append(nvSpPr, "p:nvPr");
3496
- const spPr = append(sp, "p:spPr");
3497
- const xfrm = append(spPr, "a:xfrm");
3498
- const off = append(xfrm, "a:off");
3628
+ /**
3629
+ * Create `qname` in the parent's document and append it.
3630
+ *
3631
+ * The builders below are uniformly parent-then-child, so this is the only shape
3632
+ * of element creation they need; `ownerDocumentOf` is what lets it take the
3633
+ * parent alone rather than threading a `Document` through every call.
3634
+ */
3635
+ function appendEl(parent, qname) {
3636
+ const child = createElement(ownerDocumentOf(parent), qname);
3637
+ parent.appendChild(child);
3638
+ return child;
3639
+ }
3640
+ /**
3641
+ * Append the `p:spPr` a built `p:sp` and `p:pic` share: the spec's box as an
3642
+ * `a:xfrm`, then a rect `prstGeom` with the empty `a:avLst` the schema requires.
3643
+ */
3644
+ function appendSpPr(parent, spec) {
3645
+ const spPr = appendEl(parent, "p:spPr");
3646
+ const xfrm = appendEl(spPr, "a:xfrm");
3647
+ const off = appendEl(xfrm, "a:off");
3499
3648
  setAttr(off, "x", String(spec.left));
3500
3649
  setAttr(off, "y", String(spec.top));
3501
- const ext = append(xfrm, "a:ext");
3650
+ const ext = appendEl(xfrm, "a:ext");
3502
3651
  setAttr(ext, "cx", String(spec.width));
3503
3652
  setAttr(ext, "cy", String(spec.height));
3504
- const prstGeom = append(spPr, "a:prstGeom");
3653
+ const prstGeom = appendEl(spPr, "a:prstGeom");
3505
3654
  setAttr(prstGeom, "prst", "rect");
3506
- append(prstGeom, "a:avLst");
3507
- const txBody = append(sp, "p:txBody");
3508
- append(txBody, "a:bodyPr");
3509
- append(txBody, "a:lstStyle");
3510
- const p = append(txBody, "a:p");
3655
+ appendEl(prstGeom, "a:avLst");
3656
+ return spPr;
3657
+ }
3658
+ /** Build a minimal, schema-valid text-box `p:sp` element (not yet attached). */
3659
+ function buildTextBox(doc, spec) {
3660
+ const sp = createElement(doc, "p:sp");
3661
+ const nvSpPr = appendEl(sp, "p:nvSpPr");
3662
+ const cNvPr = appendEl(nvSpPr, "p:cNvPr");
3663
+ setAttr(cNvPr, "id", String(spec.id));
3664
+ setAttr(cNvPr, "name", spec.name);
3665
+ const cNvSpPr = appendEl(nvSpPr, "p:cNvSpPr");
3666
+ setAttr(cNvSpPr, "txBox", "1");
3667
+ appendEl(nvSpPr, "p:nvPr");
3668
+ appendSpPr(sp, spec);
3669
+ const txBody = appendEl(sp, "p:txBody");
3670
+ appendEl(txBody, "a:bodyPr");
3671
+ appendEl(txBody, "a:lstStyle");
3672
+ const p = appendEl(txBody, "a:p");
3511
3673
  if (spec.text !== "") {
3512
- const t = append(append(p, "a:r"), "a:t");
3674
+ const t = appendEl(appendEl(p, "a:r"), "a:t");
3513
3675
  t.textContent = spec.text;
3514
3676
  if (spec.text !== spec.text.trim()) setAttr(t, "xml:space", "preserve");
3515
3677
  }
@@ -3517,35 +3679,19 @@ function buildTextBox(doc, spec) {
3517
3679
  }
3518
3680
  /** Build a minimal, schema-valid `p:pic` element (not yet attached). */
3519
3681
  function buildPicture(doc, spec) {
3520
- const make = (qname) => createElement(doc, qname);
3521
- const append = (parent, qname) => {
3522
- const child = make(qname);
3523
- parent.appendChild(child);
3524
- return child;
3525
- };
3526
- const pic = make("p:pic");
3527
- const nvPicPr = append(pic, "p:nvPicPr");
3528
- const cNvPr = append(nvPicPr, "p:cNvPr");
3682
+ const pic = createElement(doc, "p:pic");
3683
+ const nvPicPr = appendEl(pic, "p:nvPicPr");
3684
+ const cNvPr = appendEl(nvPicPr, "p:cNvPr");
3529
3685
  setAttr(cNvPr, "id", String(spec.id));
3530
3686
  setAttr(cNvPr, "name", spec.name);
3531
- const picLocks = append(append(nvPicPr, "p:cNvPicPr"), "a:picLocks");
3687
+ const picLocks = appendEl(appendEl(nvPicPr, "p:cNvPicPr"), "a:picLocks");
3532
3688
  setAttr(picLocks, "noChangeAspect", "1");
3533
- append(nvPicPr, "p:nvPr");
3534
- const blipFill = append(pic, "p:blipFill");
3535
- const blip = append(blipFill, "a:blip");
3689
+ appendEl(nvPicPr, "p:nvPr");
3690
+ const blipFill = appendEl(pic, "p:blipFill");
3691
+ const blip = appendEl(blipFill, "a:blip");
3536
3692
  setAttr(blip, "r:embed", spec.relId);
3537
- append(append(blipFill, "a:stretch"), "a:fillRect");
3538
- const spPr = append(pic, "p:spPr");
3539
- const xfrm = append(spPr, "a:xfrm");
3540
- const off = append(xfrm, "a:off");
3541
- setAttr(off, "x", String(spec.left));
3542
- setAttr(off, "y", String(spec.top));
3543
- const ext = append(xfrm, "a:ext");
3544
- setAttr(ext, "cx", String(spec.width));
3545
- setAttr(ext, "cy", String(spec.height));
3546
- const prstGeom = append(spPr, "a:prstGeom");
3547
- setAttr(prstGeom, "prst", "rect");
3548
- append(prstGeom, "a:avLst");
3693
+ appendEl(appendEl(blipFill, "a:stretch"), "a:fillRect");
3694
+ appendSpPr(pic, spec);
3549
3695
  return pic;
3550
3696
  }
3551
3697
  //#endregion
@@ -3657,70 +3803,6 @@ function readCustomProperties(opc) {
3657
3803
  return out;
3658
3804
  }
3659
3805
  //#endregion
3660
- //#region src/read/oxml/slide-dom.ts
3661
- /** The `p:cSld@name` of a slide/layout/master part (`''` when absent). */
3662
- function cSldName(part) {
3663
- const root = part?.dom.documentElement;
3664
- const cSld = root && firstChild(root, "p:cSld");
3665
- return (cSld && attr(cSld, "name")) ?? "";
3666
- }
3667
- /** Whether `el` is a `p:spTree`'s own group properties (`p:nvGrpSpPr`/`p:grpSpPr`), not a shape. */
3668
- function isSpTreeProperty(el) {
3669
- return el.namespaceURI === OOXML_NS.p && (el.localName === "nvGrpSpPr" || el.localName === "grpSpPr");
3670
- }
3671
- /** Whether a `p:spTree` child is a placeholder shape (its `*nvPr` carries a `p:ph`). */
3672
- function isPlaceholderShape(shape) {
3673
- const nv = firstChildElement(shape);
3674
- const nvPr = nv && firstChild(nv, "p:nvPr");
3675
- return !!(nvPr && firstChild(nvPr, "p:ph"));
3676
- }
3677
- /** The decorative shapes on a layout/master `p:spTree`: every shape child except placeholders. */
3678
- function carriedDecorations(root) {
3679
- if (!root) return [];
3680
- const cSld = firstChild(root, "p:cSld");
3681
- const spTree = cSld && firstChild(cSld, "p:spTree");
3682
- if (!spTree) return [];
3683
- const out = [];
3684
- for (let node = spTree.firstChild; node; node = node.nextSibling) {
3685
- if (node.nodeType !== 1) continue;
3686
- const el = node;
3687
- if (isSpTreeProperty(el) || isPlaceholderShape(el)) continue;
3688
- out.push(el);
3689
- }
3690
- return out;
3691
- }
3692
- /**
3693
- * The `n`-th shape child of a `p:spTree` in document (z-)order, skipping the
3694
- * tree's own `nvGrpSpPr`/`grpSpPr` and any trailing `p:extLst`. Returns `null`
3695
- * when `n` is past the last shape (the caller then appends).
3696
- */
3697
- function nthShapeChild(spTree, n) {
3698
- let i = 0;
3699
- for (let node = spTree.firstChild; node; node = node.nextSibling) {
3700
- if (node.nodeType !== 1) continue;
3701
- const el = node;
3702
- if (isSpTreeProperty(el)) continue;
3703
- if (el.namespaceURI === OOXML_NS.p && el.localName === "extLst") continue;
3704
- if (i === n) return el;
3705
- i++;
3706
- }
3707
- return null;
3708
- }
3709
- /** The first shape child of a `p:spTree` (skipping `nvGrpSpPr`/`grpSpPr`), or `null`. */
3710
- function firstShapeChild(spTree) {
3711
- for (let node = spTree.firstChild; node; node = node.nextSibling) {
3712
- if (node.nodeType !== 1) continue;
3713
- const el = node;
3714
- if (!isSpTreeProperty(el)) return el;
3715
- }
3716
- return null;
3717
- }
3718
- /** Collect `node` and all its descendant elements (document order) into `out`. */
3719
- function collectElements(node, out) {
3720
- out.push(node);
3721
- for (let child = node.firstChild; child; child = child.nextSibling) if (child.nodeType === 1) collectElements(child, out);
3722
- }
3723
- //#endregion
3724
3806
  //#region src/read/api/ops/rescale.ts
3725
3807
  /** Build the EMU transform mapping source-canvas coordinates onto the target canvas (see {@link ImportSlideOptions.rescale}). */
3726
3808
  function computeRescale(source, target, mode) {
@@ -4131,7 +4213,7 @@ function mergeEmbeddedFontEntries(dest, entries) {
4131
4213
  const presPart = dest.presentationPart;
4132
4214
  const presRoot = presPart.dom.documentElement;
4133
4215
  if (!presRoot) throw new PackageReadError("package/part-has-no-root", "presentation.xml has no document element to carry embedded fonts into");
4134
- const presRels = dest.opc.relationshipsFor(presPart.partName);
4216
+ const presRels = presentationRels(dest);
4135
4217
  const targetLst = getOrAddChild(presRoot, "p:embeddedFontLst", PRESENTATION_EMBEDDED_FONT_LST_SUCCESSORS);
4136
4218
  const targetByTypeface = /* @__PURE__ */ new Map();
4137
4219
  for (const entry of getElements(targetLst, "p:embeddedFont")) {
@@ -4178,21 +4260,16 @@ function mergeEmbeddedFontEntries(dest, entries) {
4178
4260
  * Pure with respect to the destination deck: it reads only the source package. It was a
4179
4261
  * private method on `Presentation` that used no instance state.
4180
4262
  */
4181
- /** The `p:cSld/p:bg` element of a slide/layout/master root, or `null`. */
4182
- function backgroundOf(root) {
4183
- const cSld = firstChild(root, "p:cSld");
4184
- return cSld ? firstChild(cSld, "p:bg") : null;
4185
- }
4186
4263
  /**
4187
4264
  * The background the slide effectively inherits from its source subgraph: the layout's
4188
4265
  * `p:bg`, else the master's. Returns `null` when the slide carries its own `p:bg` (it stays
4189
4266
  * on the slide and is flattened directly) or when none exists.
4190
4267
  */
4191
4268
  function effectiveBackground(sourceOpc, slideRoot, layoutPartName, masterPartName) {
4192
- if (slideRoot && backgroundOf(slideRoot)) return null;
4269
+ if (slideRoot && backgroundElementOf(slideRoot)) return null;
4193
4270
  const layoutRoot = layoutPartName ? sourceOpc.part(layoutPartName)?.dom.documentElement ?? null : null;
4194
4271
  const masterRoot = masterPartName ? sourceOpc.part(masterPartName)?.dom.documentElement ?? null : null;
4195
- return (layoutRoot && backgroundOf(layoutRoot)) ?? (masterRoot && backgroundOf(masterRoot)) ?? null;
4272
+ return (layoutRoot && backgroundElementOf(layoutRoot)) ?? (masterRoot && backgroundElementOf(masterRoot)) ?? null;
4196
4273
  }
4197
4274
  /**
4198
4275
  * Gather the flatten context for a source slide: walk slide → layout → master → theme,
@@ -4371,7 +4448,7 @@ function importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics) {
4371
4448
  targetRels.addWithId(rel.id, rel.type, rel.target, "External");
4372
4449
  continue;
4373
4450
  }
4374
- const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : owned);
4451
+ const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : owned, true);
4375
4452
  targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTarget));
4376
4453
  }
4377
4454
  if (carryGraphics) carryMasterGraphics(dest, ctx, slideRoot, newPartName, sourceSlide.partName, owned);
@@ -4401,8 +4478,7 @@ function carryMasterGraphics(dest, ctx, slideRoot, newPartName, slidePartName, o
4401
4478
  const sourceOpc = ctx.source;
4402
4479
  const layoutPartName = resolveSingleRel(sourceOpc, slidePartName, SLIDE_LAYOUT_REL);
4403
4480
  const masterPartName = layoutPartName ? resolveSingleRel(sourceOpc, layoutPartName, SLIDE_MASTER_REL) : null;
4404
- const cSld = firstChild(slideRoot, "p:cSld");
4405
- const spTree = cSld && firstChild(cSld, "p:spTree");
4481
+ const spTree = spTreeOf(slideRoot);
4406
4482
  if (!spTree) return;
4407
4483
  const doc = ownerDocumentOf(slideRoot);
4408
4484
  const slideRels = dest.opc.relationshipsFor(newPartName);
@@ -4455,11 +4531,11 @@ function destinationLayoutPartName(dest) {
4455
4531
  * orphan, even while momentarily unreferenced.
4456
4532
  */
4457
4533
  const SHARED_CHROME_CONTENT_TYPES = /* @__PURE__ */ new Set([
4458
- "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml",
4459
- "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml",
4460
- "application/vnd.openxmlformats-officedocument.theme+xml",
4534
+ SLIDE_MASTER_CONTENT_TYPE,
4535
+ SLIDE_LAYOUT_CONTENT_TYPE,
4536
+ THEME_CONTENT_TYPE,
4461
4537
  "application/vnd.openxmlformats-officedocument.themeOverride+xml",
4462
- "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml",
4538
+ NOTES_MASTER_CONTENT_TYPE,
4463
4539
  "application/vnd.openxmlformats-officedocument.presentationml.handoutMaster+xml",
4464
4540
  "application/vnd.openxmlformats-officedocument.presentationml.presProps+xml",
4465
4541
  "application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml",
@@ -4532,9 +4608,7 @@ function rescalePartGeometry(dest, rescaledParts, partName, transform) {
4532
4608
  if (rescaledParts.has(partName)) return;
4533
4609
  rescaledParts.add(partName);
4534
4610
  const part = dest.opc.part(partName);
4535
- const root = part?.dom.documentElement;
4536
- const cSld = root && firstChild(root, "p:cSld");
4537
- const spTree = cSld && firstChild(cSld, "p:spTree");
4611
+ const spTree = spTreeOf(part?.dom.documentElement);
4538
4612
  if (!part || !spTree) return;
4539
4613
  rescaleSpTree(spTree, transform);
4540
4614
  part.markDirty();
@@ -4562,8 +4636,6 @@ const PACKAGE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relat
4562
4636
  const AUDIO_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/audio";
4563
4637
  const VIDEO_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video";
4564
4638
  const MS_MEDIA_REL = "http://schemas.microsoft.com/office/2007/relationships/media";
4565
- const SLIDE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
4566
- const NOTES_SLIDE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml";
4567
4639
  const CHART_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
4568
4640
  const CHARTEX_CONTENT_TYPE = "application/vnd.ms-office.chartex+xml";
4569
4641
  const CHART_STYLE_CONTENT_TYPE = "application/vnd.ms-office.chartstyle+xml";
@@ -4841,7 +4913,7 @@ var Presentation = class Presentation {
4841
4913
  const slideRels = this.opc.relationshipsFor(partName);
4842
4914
  const formerTargets = [...slideRels].filter((rel) => rel.targetMode !== "External").map((rel) => slideRels.resolveTarget(rel.id));
4843
4915
  const presPart = this.presentationPart;
4844
- const presRels = this.opc.relationshipsFor(presPart.partName);
4916
+ const presRels = presentationRels(this);
4845
4917
  const root = presPart.dom.documentElement;
4846
4918
  const sldIdLst = root && firstChild(root, "p:sldIdLst");
4847
4919
  if (sldIdLst) for (const sldId of getElements(sldIdLst, "p:sldId")) {
@@ -5413,7 +5485,7 @@ var Presentation = class Presentation {
5413
5485
  */
5414
5486
  #insertSlidePart(newPart, at) {
5415
5487
  const presPart = this.presentationPart;
5416
- const presRels = this.opc.relationshipsFor(presPart.partName);
5488
+ const presRels = presentationRels(this);
5417
5489
  for (const rel of presRels) {
5418
5490
  if (rel.type !== "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" || rel.targetMode === "External") continue;
5419
5491
  if (presRels.resolveTarget(rel.id) !== newPart.partName) continue;
@@ -5453,4 +5525,4 @@ var Presentation = class Presentation {
5453
5525
  //#endregion
5454
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 };
5455
5527
 
5456
- //# sourceMappingURL=presentation-DeKTJGHf.js.map
5528
+ //# sourceMappingURL=presentation-VfJ_FT7E.js.map