@shbernal/ts-pptx 1.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +10 -3
  2. package/dist/{autopage-tmfjRzL4.js → autopage-MxulehqQ.js} +3 -4
  3. package/dist/{autopage-tmfjRzL4.js.map → autopage-MxulehqQ.js.map} +1 -1
  4. package/dist/browser.d.ts +14 -6
  5. package/dist/browser.d.ts.map +1 -1
  6. package/dist/browser.js +12 -4
  7. package/dist/browser.js.map +1 -1
  8. package/dist/{diagnostics-DzY9Tyfm.d.ts → diagnostics-BqBTmA3a.d.ts} +95 -23
  9. package/dist/diagnostics-BqBTmA3a.d.ts.map +1 -0
  10. package/dist/{enums-D3aF4QGb.d.ts → enums-oLLeaSW3.d.ts} +2 -1
  11. package/dist/{enums-D3aF4QGb.d.ts.map → enums-oLLeaSW3.d.ts.map} +1 -1
  12. package/dist/{errors-DRLpOpgQ.d.ts → errors-BENA-Xuw.d.ts} +3 -3
  13. package/dist/{errors-DRLpOpgQ.d.ts.map → errors-BENA-Xuw.d.ts.map} +1 -1
  14. package/dist/errors-DGE9zh3U.js.map +1 -1
  15. package/dist/{fit-CbxyHN69.js → fit-DGSwMMNs.js} +0 -0
  16. package/dist/{fit-CbxyHN69.js.map → fit-DGSwMMNs.js.map} +1 -1
  17. package/dist/{html-dom-wVa3TiG7.js → html-dom--J-Xuucf.js} +19 -5
  18. package/dist/html-dom--J-Xuucf.js.map +1 -0
  19. package/dist/html.d.ts +3 -3
  20. package/dist/html.d.ts.map +1 -1
  21. package/dist/html.js +6 -3
  22. package/dist/html.js.map +1 -1
  23. package/dist/index.d.ts +6 -6
  24. package/dist/index.js +4 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/inspect.d.ts +1 -1
  27. package/dist/inspect.js +2 -2
  28. package/dist/inspect.js.map +1 -1
  29. package/dist/math.d.ts +1 -1
  30. package/dist/math.js +2 -1
  31. package/dist/math.js.map +1 -1
  32. package/dist/measure.d.ts +2 -2
  33. package/dist/measure.js +1 -1
  34. package/dist/node.d.ts +14 -6
  35. package/dist/node.d.ts.map +1 -1
  36. package/dist/node.js +11 -3
  37. package/dist/node.js.map +1 -1
  38. package/dist/{pres-5x1bjCzk.d.ts → pres-2WsBGimU.d.ts} +3 -3
  39. package/dist/{pres-5x1bjCzk.d.ts.map → pres-2WsBGimU.d.ts.map} +1 -1
  40. package/dist/{presentation-RGOiun5P.d.ts → presentation-CTVPpiwP.d.ts} +912 -485
  41. package/dist/presentation-CTVPpiwP.d.ts.map +1 -0
  42. package/dist/{presentation-B0JWdTN1.js → presentation-DAcOfzsP.js} +880 -366
  43. package/dist/presentation-DAcOfzsP.js.map +1 -0
  44. package/dist/read.d.ts +4 -4
  45. package/dist/read.d.ts.map +1 -1
  46. package/dist/read.js +2 -2
  47. package/dist/script.d.ts +2 -2
  48. package/dist/script.d.ts.map +1 -1
  49. package/dist/script.js +0 -0
  50. package/dist/script.js.map +1 -1
  51. package/dist/{shapes-BZU8UTW2.js → shapes-BWifcHDV.js} +1520 -996
  52. package/dist/shapes-BWifcHDV.js.map +1 -0
  53. package/dist/{slide-B6mDaM-P.d.ts → slide-YuSCGa45.d.ts} +409 -103
  54. package/dist/slide-YuSCGa45.d.ts.map +1 -0
  55. package/dist/{image-size-C5Z1sKof.js → st-enums-CgadEyPM.js} +235 -4
  56. package/dist/st-enums-CgadEyPM.js.map +1 -0
  57. package/dist/{text-WRUbOy2r.js → text-120VFSDm.js} +1027 -369
  58. package/dist/text-120VFSDm.js.map +1 -0
  59. package/dist/{units-internal-7JcMfYti.js → units-internal-CiFWZWk4.js} +2 -1
  60. package/dist/units-internal-CiFWZWk4.js.map +1 -0
  61. package/dist/zip.d.ts +2 -2
  62. package/dist/zip.js.map +1 -1
  63. package/package.json +38 -36
  64. package/dist/diagnostics-DzY9Tyfm.d.ts.map +0 -1
  65. package/dist/html-dom-wVa3TiG7.js.map +0 -1
  66. package/dist/image-size-C5Z1sKof.js.map +0 -1
  67. package/dist/presentation-B0JWdTN1.js.map +0 -1
  68. package/dist/presentation-RGOiun5P.d.ts.map +0 -1
  69. package/dist/shapes-BZU8UTW2.js.map +0 -1
  70. package/dist/slide-B6mDaM-P.d.ts.map +0 -1
  71. package/dist/text-WRUbOy2r.js.map +0 -1
  72. package/dist/units-internal-7JcMfYti.js.map +0 -1
@@ -1,8 +1,9 @@
1
1
  import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-DGE9zh3U.js";
2
2
  import { d as emuToInches } from "./units-B-JUKwCS.js";
3
+ import { _ as SLIDE_LAYOUT_REL, b as THEME_REL, d as IMAGE_REL, f as NOTES_MASTER_REL, m as OFFICE_DOCUMENT_REL, p as NOTES_SLIDE_REL, v as SLIDE_MASTER_REL, y as SLIDE_REL } from "./st-enums-CgadEyPM.js";
3
4
  import { i as FONT_REL_TYPE, n as FONT_DATA_CONTENT_TYPE, r as FONT_DATA_EXTENSION, t as EMBEDDED_FONT_SLOTS } from "./embedded-fonts-MaynAHa9.js";
4
5
  import { ZipWriter, readZip } from "./zip.js";
5
- import { $ as escapeXmlAttribute, A as resolveMasterColorContext, B as restyleSlide, D as readGradientFill, E as readPictureFill, F as flattenShape, G as relsPartNameFor, H as partNameExtension, I as flattenSlide, J as OOXML_NS, K as resolveRelativePartName, L as parseClrMap, M as resolveSlideColorContext, N as resolveSlideThemeParts, O as resolveColorElement, Q as createElement, R as parseClrScheme, T as TextFrame, U as partNameToZipPath, V as styleRefFill, W as relativePartName, X as boolValue, Y as attr, Z as childElements, at as intValue, b as Picture, c as wrapShapeElement, ct as removeAttr, dt as setAttr, et as firstChild, it as insertInOrder, j as resolveNotesColorContext, k as resolveLayoutColorContext, l as GraphicFrame, lt as removeChildrenByQName, n as buildShapes, nt as getElements, ot as ownerDocumentOf, q as zipPathToPartName, rt as getOrAddChild, st as parseXml, t as GroupShape, tt as firstChildElement, ut as serializeXml, x as AutoShape, z as remapLiteralColors } from "./shapes-BZU8UTW2.js";
6
+ import { $ as resolveColor, A as resolveColorElement, At as getOrAddChild, B as placeholderInheritedColor, Ct as childElements, D as readPatternFill, Dt as firstChild, E as spPrXfrmEmu, Et as escapeXmlAttribute, F as resolveSlideThemeParts, Ft as removeAttr, G as slideDefinesColor, H as placeholderInheritedRunProps, It as removeChildrenByQName, J as fmtEntry, K as slideDefinesProp, L as LST_STYLE_LEVELS, Lt as replaceInParent, M as resolveMasterColorContext, Mt as intValue, N as resolveNotesColorContext, Nt as ownerDocumentOf, O as readPictureFill, Ot as firstChildElement, P as resolveSlideColorContext, Pt as parseXml, Q as parseClrScheme, R as RUN_PROP_NAMES, Rt as serializeXml, St as boolValue, T as TextFrame, Tt as descendantsByTag, U as placeholderInheritedXfrm, V as placeholderInheritedListStyles, W as placeholderOf, X as isA, Y as intAttr, Z as parseClrMap, _t as resolveRelativePartName, at as RPR_FILL_AFTER, b as Picture, bt as OOXML_NS, c as wrapShapeElement, ct as SPPR_EFFECT_AFTER, dt as SPPR_SCENE3D_AFTER, et as resolveSchemeToken, ft as SPPR_SP3D_AFTER, gt as relsPartNameFor, ht as relativePartName, it as FILL_CHOICES, j as resolveLayoutColorContext, jt as insertInOrder, k as readGradientFill, kt as getElements, l as GraphicFrame, lt as SPPR_FILL_AFTER, mt as partNameToZipPath, n as buildShapes, nt as styleRefLine, ot as SHAPE_AFTER_SPPR, pt as partNameExtension, q as SCHEME_SLOTS, rt as substitutePhClr, st as SPPR_AFTER_XFRM, t as GroupShape, tt as styleRefFill, ut as SPPR_LN_AFTER, vt as resolveSingleRel, wt as createElement, x as AutoShape, xt as attr, yt as zipPathToPartName, z as placeholderInheritedAnchor, zt as setAttr } from "./shapes-BWifcHDV.js";
6
7
  //#region src/read/opc/content-types.ts
7
8
  /**
8
9
  * Overlay over `[Content_Types].xml`, used to resolve part content types at
@@ -420,6 +421,477 @@ var OpcPackage = class OpcPackage {
420
421
  }
421
422
  };
422
423
  //#endregion
424
+ //#region src/read/api/ops/flatten.ts
425
+ /**
426
+ * Baking a slide's theme dependencies into the slide itself, for `Presentation.importSlide` /
427
+ * `importShape`.
428
+ *
429
+ * A slide imported into another deck is rebound to the *destination* master, so everything it
430
+ * resolved symbolically against its own theme silently re-resolves against a different one — its
431
+ * scheme colours change, its style-matrix fills change, its placeholders snap to different
432
+ * geometry and type sizes. The `theme: 'preserve'` mode exists to stop that: each pass here
433
+ * resolves a dependency against the **source** theme (via `read/oxml/theme.ts` and
434
+ * `read/oxml/placeholder-inherit.ts`) and writes the answer explicitly onto the slide, so after
435
+ * the rebind there is nothing left to re-resolve.
436
+ *
437
+ * What gets flattened, and why each one matters:
438
+ *
439
+ * 1. **`a:schemeClr` tokens** — rewritten to the literal `a:srgbClr` the source `clrMap` +
440
+ * `clrScheme` produce. Child transforms (`lumMod`/`shade`/`alpha`/…) are carried through
441
+ * untouched, so tints and shades render identically; only the *base* reference is swapped,
442
+ * never the transform math.
443
+ * 2. **Style-matrix refs** — a shape's `p:style` (`lnRef`/`fillRef`/`effectRef`) indexes the
444
+ * theme `fmtScheme`; the indexed entry is resolved into an explicit `spPr` fill/line/effect
445
+ * (with its `phClr` substituted) and the ref neutralized so it cannot re-resolve. The
446
+ * `fontRef` is deliberately left intact so its font can re-bind to the destination theme —
447
+ * the "normalize fonts on attach" bonus.
448
+ * 3. **Placeholder-inherited run colour, size and weight** — a run that sets none of its own
449
+ * takes them from the source placeholder → layout → master text-style chain. Rebinding
450
+ * replaces that chain, so each is resolved from the source styles and written onto the run.
451
+ * Typeface (`a:latin`) is deliberately *not* baked — it re-binds along with `fontRef`.
452
+ * 4. **Placeholder-inherited geometry** — a placeholder with no own `a:xfrm` takes position and
453
+ * size from the matching source layout/master placeholder; without baking it, a title snaps
454
+ * to the destination default and often clips off-canvas.
455
+ *
456
+ * The `restyle` mode is the deliberate inverse ({@link restyleSlide}): it bakes *nothing*, so
457
+ * everything re-resolves against the destination and the slide takes on the new brand.
458
+ *
459
+ * **Why this lives in `api/ops/` and not in `read/oxml/`.** Everything here *mutates* a live
460
+ * part. The modules it calls into resolve and build detached elements but never write, which is
461
+ * what lets the read model's getters share them; keeping the writes on this side of the line is
462
+ * what keeps that true. Callers own marking the part dirty.
463
+ */
464
+ /**
465
+ * Flatten one slide's theme dependencies in place:
466
+ *
467
+ * 1. carry the background the slide inherited from its source layout/master onto
468
+ * the slide (so it survives rebinding to a different master);
469
+ * 2. materialize `p:bgRef` and style-matrix refs into explicit fills/lines/effects;
470
+ * 3. bake each placeholder's effective geometry (inherited `a:xfrm`) onto the
471
+ * shape so a rebind cannot move or resize it;
472
+ * 4. bake each placeholder run's effective colour and size/weight (inherited from
473
+ * the source layout/master text styles) explicitly onto the run;
474
+ * 5. rewrite every remaining `a:schemeClr` to its literal `a:srgbClr`.
475
+ *
476
+ * Steps run in this order so the inherited/materialized backgrounds are present
477
+ * before the final scheme-colour sweep resolves the colours they carry. The
478
+ * placeholder geometry/colour/size passes have no data dependency on the others.
479
+ * The caller marks the part dirty.
480
+ */
481
+ function flattenSlide(slideRoot, ctx) {
482
+ applyInheritedBackground(slideRoot, ctx);
483
+ materializeBackground(slideRoot, ctx);
484
+ materializeStyleRefs(slideRoot, ctx);
485
+ resolvePlaceholderGeometry(slideRoot, ctx);
486
+ resolvePlaceholderRunColors(slideRoot, ctx);
487
+ resolvePlaceholderRunSizes(slideRoot, ctx);
488
+ resolveSchemeColors(slideRoot, ctx);
489
+ }
490
+ /**
491
+ * Flatten a single lifted shape's theme dependencies in place — the shape-scoped
492
+ * subset of {@link flattenSlide} used by `Presentation.importShape` `preserve`
493
+ * mode. It runs every pass that resolves a *shape's* theme references against the
494
+ * source theme (style-matrix refs, placeholder-inherited geometry/colour/size/
495
+ * anchor/list-style, scheme colours) but deliberately **omits** the two
496
+ * slide-scoped background passes (`applyInheritedBackground`/`materializeBackground`):
497
+ * a background belongs to a slide, not to a shape being composed onto a foreign host.
498
+ *
499
+ * Unlike {@link flattenSlide}, this also **demotes** a lifted placeholder to a
500
+ * plain shape ({@link demotePlaceholders}) once everything it inherited is baked.
501
+ * A placeholder makes sense on its own slide, where it resolves against that deck's
502
+ * master/layout; lifted onto a foreign host its surviving `p:ph` would re-resolve
503
+ * against the *host* placeholder of the same type/idx (wrong inheritance, or a
504
+ * fallback when absent) and could collide with the host's own placeholder. The
505
+ * extra bakes here (anchor + list style, on top of the geometry/colour/size the
506
+ * shared passes cover) make the shape self-contained so demotion loses nothing
507
+ * visible. This is why the demotion is scoped to `flattenShape`: `flattenSlide`
508
+ * keeps placeholders as placeholders by design.
509
+ *
510
+ * `shapeRoot` must be an element whose *descendants* include the lifted shape
511
+ * (the passes match via `getElementsByTagNameNS`, which excludes the root element
512
+ * itself) — the caller wraps the imported `p:sp`/`p:pic`/`p:graphicFrame`/`p:grpSp`
513
+ * in a throwaway container before calling. The caller marks the part dirty.
514
+ */
515
+ function flattenShape(shapeRoot, ctx) {
516
+ materializeStyleRefs(shapeRoot, ctx);
517
+ resolvePlaceholderGeometry(shapeRoot, ctx);
518
+ resolvePlaceholderRunColors(shapeRoot, ctx);
519
+ resolvePlaceholderRunSizes(shapeRoot, ctx);
520
+ resolvePlaceholderBodyPr(shapeRoot, ctx);
521
+ resolvePlaceholderListStyle(shapeRoot, ctx);
522
+ resolveSchemeColors(shapeRoot, ctx);
523
+ demotePlaceholders(shapeRoot);
524
+ }
525
+ /**
526
+ * Restyle a rebound slide in place (the `theme: 'restyle'` mode): the exact
527
+ * inverse of {@link flattenSlide}. It bakes *nothing* — leaving every
528
+ * `a:schemeClr`/style-matrix ref and `p:bg` `bgRef` symbolic is the whole point,
529
+ * so they re-resolve against the *destination* master's `clrMap` + theme once the
530
+ * slide is rebound. The single mutation is dropping the slide's own colour-map
531
+ * override (`p:clrMapOvr/a:overrideClrMapping`): a source override would keep
532
+ * mapping the slide's scheme-token names the source way and defeat the re-brand,
533
+ * so it must yield to the destination master's `p:clrMap`.
534
+ *
535
+ * Caveat carried from the plan: only *symbolic* colours re-brand. Anything the
536
+ * source authored as a literal `a:srgbClr` has no theme reference to re-resolve
537
+ * and stays exactly that colour. The caller marks the part dirty.
538
+ */
539
+ function restyleSlide(slideRoot) {
540
+ removeChildrenByQName(slideRoot, ["p:clrMapOvr"]);
541
+ }
542
+ /**
543
+ * The optional inverse of {@link resolveSchemeColors}, for `restyle`'s
544
+ * force-remap-literals mode (the `Presentation.importSlide` `remapLiterals`
545
+ * option). Every literal `a:srgbClr` whose value equals a *source* `clrScheme`
546
+ * slot is rewritten back to a symbolic `a:schemeClr` so it re-resolves against the
547
+ * destination theme; a literal matching no slot (the common case) is left exactly
548
+ * as authored. Transform children (`lumMod`/`shade`/`alpha`/…) are carried across.
549
+ *
550
+ * Plain `restyle` cannot re-brand a literal — it carries no theme reference. This
551
+ * re-introduces one by matching the literal's RGB against the slots the *source*
552
+ * theme defined, emitting the scheme token that routes through the source `clrMap`
553
+ * (so a literal equal to the source `accent1` slot becomes `schemeClr accent1`,
554
+ * which the destination `clrMap`/theme then re-resolve). Slots are matched in
555
+ * `clrScheme` order, so the first slot defining a given RGB wins when several share
556
+ * it. Opt-in because it deliberately reinterprets authored literals as theme
557
+ * colours — visual QA territory, the same caveat as the rest of `restyle`.
558
+ */
559
+ function remapLiteralColors(slideRoot, ctx) {
560
+ const slotByHex = reverseClrScheme(ctx.clrScheme);
561
+ if (slotByHex.size === 0) return;
562
+ const tokenBySlot = reverseClrMap(ctx.clrMap);
563
+ const doc = ownerDocumentOf(slideRoot);
564
+ for (const srgb of descendantsByTag(slideRoot, OOXML_NS.a, "srgbClr")) {
565
+ const hex = attr(srgb, "val");
566
+ const slot = hex ? slotByHex.get(hex.toUpperCase()) : void 0;
567
+ if (!slot) continue;
568
+ const scheme = createElement(doc, "a:schemeClr");
569
+ setAttr(scheme, "val", tokenBySlot.get(slot) ?? slot);
570
+ while (srgb.firstChild) scheme.appendChild(srgb.firstChild);
571
+ replaceInParent(srgb, scheme);
572
+ }
573
+ }
574
+ /** Reverse a slot → RGB `clrScheme` into RGB → slot, in `SCHEME_SLOTS` order (first slot wins on a shared RGB). */
575
+ function reverseClrScheme(clrScheme) {
576
+ const out = /* @__PURE__ */ new Map();
577
+ for (const slot of SCHEME_SLOTS) {
578
+ const hex = clrScheme.get(slot);
579
+ if (hex && !out.has(hex.toUpperCase())) out.set(hex.toUpperCase(), slot);
580
+ }
581
+ return out;
582
+ }
583
+ /** Reverse a token → slot `clrMap` into slot → token (first token wins on a shared slot). */
584
+ function reverseClrMap(clrMap) {
585
+ const out = /* @__PURE__ */ new Map();
586
+ for (const [token, slot] of clrMap) if (!out.has(slot)) out.set(slot, token);
587
+ return out;
588
+ }
589
+ /**
590
+ * If the slide has no own `p:bg`, insert (a copy of) the background it inherited
591
+ * from its source layout/master as an explicit `p:cSld/p:bg`. The clone is left
592
+ * unresolved here; the later passes flatten its `bgRef`/`schemeClr` in place.
593
+ */
594
+ function applyInheritedBackground(slideRoot, ctx) {
595
+ const inherited = ctx.inheritedBackground;
596
+ if (!inherited) return;
597
+ const cSld = firstChild(slideRoot, "p:cSld");
598
+ if (!cSld || firstChild(cSld, "p:bg")) return;
599
+ const bg = ownerDocumentOf(slideRoot).importNode(inherited, true);
600
+ insertInOrder(cSld, bg, [
601
+ "p:spTree",
602
+ "p:custDataLst",
603
+ "p:controls",
604
+ "p:extLst"
605
+ ]);
606
+ }
607
+ /**
608
+ * Resolve every `p:bgRef` (theme-indexed background) under the slide into an
609
+ * explicit `p:bgPr` fill, so the background no longer depends on the destination
610
+ * theme's `fmtScheme`. A `bgPr` background is left for the scheme-colour sweep.
611
+ */
612
+ function materializeBackground(slideRoot, ctx) {
613
+ const doc = ownerDocumentOf(slideRoot);
614
+ for (const bg of descendantsByTag(slideRoot, OOXML_NS.p, "bg")) {
615
+ const bgRef = firstChild(bg, "p:bgRef");
616
+ if (!bgRef) continue;
617
+ const fill = styleRefFill(bgRef, ctx);
618
+ const bgPr = createElement(doc, "p:bgPr");
619
+ bgPr.appendChild(fill ?? createElement(doc, "a:noFill"));
620
+ bg.replaceChild(bgPr, bgRef);
621
+ }
622
+ }
623
+ /** Rewrite every `a:schemeClr` under `root` to a literal `a:srgbClr` when resolvable. */
624
+ function resolveSchemeColors(root, ctx) {
625
+ const doc = ownerDocumentOf(root);
626
+ for (const schemeClr of descendantsByTag(root, OOXML_NS.a, "schemeClr")) {
627
+ const token = attr(schemeClr, "val");
628
+ const hex = token ? resolveSchemeToken(token, ctx) : null;
629
+ if (!hex) continue;
630
+ const srgb = createElement(doc, "a:srgbClr");
631
+ setAttr(srgb, "val", hex);
632
+ while (schemeClr.firstChild) srgb.appendChild(schemeClr.firstChild);
633
+ replaceInParent(schemeClr, srgb);
634
+ }
635
+ }
636
+ /**
637
+ * Bake placeholder-inherited run colours onto the slide. For each placeholder run
638
+ * that defines no colour of its own (nor at paragraph/text-body level on the
639
+ * *slide*), resolve the colour it would inherit from the source
640
+ * `slideLayout`/`slideMaster` text styles and write it explicitly onto the run's
641
+ * `a:rPr`. After this the run's colour cannot change when the slide is rebound to
642
+ * the destination master. `a:fld` runs (dates, slide numbers) are treated like
643
+ * `a:r`. Only colour is resolved; other inheritable run properties are left to
644
+ * re-bind to the destination styles.
645
+ */
646
+ function resolvePlaceholderRunColors(slideRoot, ctx) {
647
+ if (!ctx.layoutRoot && !ctx.masterRoot) return;
648
+ for (const sp of descendantsByTag(slideRoot, OOXML_NS.p, "sp")) {
649
+ const ph = placeholderOf(sp);
650
+ if (!ph) continue;
651
+ const txBody = firstChild(sp, "p:txBody");
652
+ if (!txBody) continue;
653
+ const type = attr(ph, "type");
654
+ const idx = attr(ph, "idx") ?? "0";
655
+ const slideLst = firstChild(txBody, "a:lstStyle");
656
+ const byLevel = /* @__PURE__ */ new Map();
657
+ for (const p of getElements(txBody, "a:p")) {
658
+ const pPr = firstChild(p, "a:pPr");
659
+ const level = (pPr && intValue(attr(pPr, "lvl"))) ?? 0;
660
+ const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
661
+ 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);
671
+ }
672
+ }
673
+ }
674
+ }
675
+ /** Write a resolved colour as an explicit `a:solidFill` (with carried transforms) onto a run's `a:rPr`. */
676
+ function writeRunColor(run, color) {
677
+ const doc = ownerDocumentOf(run);
678
+ const rPr = getOrAddChild(run, "a:rPr", ["a:t"]);
679
+ const fill = createElement(doc, "a:solidFill");
680
+ const srgb = createElement(doc, "a:srgbClr");
681
+ setAttr(srgb, "val", color.hex);
682
+ for (const t of color.transforms) srgb.appendChild(t.cloneNode(true));
683
+ fill.appendChild(srgb);
684
+ insertInOrder(rPr, fill, RPR_FILL_AFTER);
685
+ }
686
+ /**
687
+ * Bake placeholder-inherited geometry onto the slide. A placeholder shape
688
+ * that carries no own `p:spPr/a:xfrm` takes its position/size from the matching
689
+ * source `slideLayout` placeholder, else the `slideMaster` placeholder. Rebinding
690
+ * to the destination master replaces that inheritance, so the placeholder would
691
+ * snap to the destination default (often clipping off-canvas). We deep-clone the
692
+ * effective source `a:xfrm` and write it explicitly onto the shape. Shapes with
693
+ * their own `a:xfrm` are left untouched (explicit geometry is not inherited), and
694
+ * an orphan placeholder with no source match keeps the current fall-back behaviour.
695
+ */
696
+ function resolvePlaceholderGeometry(slideRoot, ctx) {
697
+ if (!ctx.layoutRoot && !ctx.masterRoot) return;
698
+ for (const sp of descendantsByTag(slideRoot, OOXML_NS.p, "sp")) {
699
+ const ph = placeholderOf(sp);
700
+ if (!ph) continue;
701
+ const spPr = firstChild(sp, "p:spPr");
702
+ if (spPr && firstChild(spPr, "a:xfrm")) continue;
703
+ const found = placeholderInheritedXfrm(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
704
+ if (!found) continue;
705
+ const target = getOrAddChild(sp, "p:spPr", SHAPE_AFTER_SPPR);
706
+ insertInOrder(target, found.xfrm.cloneNode(true), SPPR_AFTER_XFRM);
707
+ }
708
+ }
709
+ /**
710
+ * Bake the placeholder-inherited vertical anchor onto a lifted shape's text body
711
+ * (the {@link flattenShape} placeholder-demotion path). A placeholder whose own
712
+ * `a:bodyPr` sets no `@anchor` inherits it from the source layout/master placeholder;
713
+ * once {@link demotePlaceholders} strips the `p:ph` the shape would lose that
714
+ * inheritance and fall back to top-anchored, so a vertically-centred title jumps.
715
+ * We resolve the effective anchor from the source chain and write it explicitly.
716
+ * Shapes whose `a:bodyPr` already fixes `@anchor`, and placeholders with no
717
+ * resolvable inherited anchor, are left untouched. Other `a:bodyPr` knobs (insets,
718
+ * autofit) are left as authored — they have sane defaults a plain shape keeps.
719
+ */
720
+ function resolvePlaceholderBodyPr(shapeRoot, ctx) {
721
+ if (!ctx.layoutRoot && !ctx.masterRoot) return;
722
+ for (const sp of descendantsByTag(shapeRoot, OOXML_NS.p, "sp")) {
723
+ const ph = placeholderOf(sp);
724
+ if (!ph) continue;
725
+ const txBody = firstChild(sp, "p:txBody");
726
+ if (!txBody) continue;
727
+ const bodyPr = firstChild(txBody, "a:bodyPr");
728
+ if (bodyPr && attr(bodyPr, "anchor") != null) continue;
729
+ const anchor = placeholderInheritedAnchor(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
730
+ if (!anchor) continue;
731
+ setAttr(bodyPr ?? getOrAddChild(txBody, "a:bodyPr", ["a:lstStyle", "a:p"]), "anchor", anchor);
732
+ }
733
+ }
734
+ /**
735
+ * Bake the placeholder-inherited list style onto a lifted shape's text body (the
736
+ * {@link flattenShape} placeholder-demotion path). A placeholder's per-level
737
+ * *paragraph* formatting — indent (`marL`/`indent`), bullets (`a:buChar`/
738
+ * `a:buAutoNum`/`a:buNone`), alignment, and the level `a:defRPr` — is inherited
739
+ * from the source layout/master placeholder `a:lstStyle` and the master
740
+ * `p:txStyles` category style. Run colour/size are baked onto each run by the
741
+ * sibling passes, but paragraph-level defaults live here; once
742
+ * {@link demotePlaceholders} strips the `p:ph` the shape stops inheriting them, so
743
+ * bullets and indents would vanish. We materialize the effective list style onto
744
+ * the shape's `p:txBody/a:lstStyle`.
745
+ *
746
+ * Resolution is per *level*, most specific tier wins whole: the slide's own level
747
+ * (if it defines one) is kept verbatim, else the first source tier that defines it
748
+ * (layout placeholder, then master placeholder, then master category style) is
749
+ * cloned. This is a whole-element overlay, not the per-attribute merge PowerPoint
750
+ * does — but explicit paragraph `a:pPr` on the slide's own runs travels with the
751
+ * shape and still wins, so this only supplies defaults for the inherited case
752
+ * (paragraphs that set no `a:pPr` of their own). Scheme colours in the cloned
753
+ * levels are resolved by the later `resolveSchemeColors` pass.
754
+ */
755
+ function resolvePlaceholderListStyle(shapeRoot, ctx) {
756
+ if (!ctx.layoutRoot && !ctx.masterRoot) return;
757
+ for (const sp of descendantsByTag(shapeRoot, OOXML_NS.p, "sp")) {
758
+ const ph = placeholderOf(sp);
759
+ if (!ph) continue;
760
+ const txBody = firstChild(sp, "p:txBody");
761
+ if (!txBody) continue;
762
+ const tiers = placeholderInheritedListStyles(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
763
+ if (tiers.length === 0) continue;
764
+ const slideLst = firstChild(txBody, "a:lstStyle");
765
+ const merged = createElement(ownerDocumentOf(txBody), "a:lstStyle");
766
+ let any = false;
767
+ for (const level of LST_STYLE_LEVELS) {
768
+ const src = (slideLst && firstChild(slideLst, level)) ?? tiers.map((t) => firstChild(t, level)).find((e) => !!e) ?? null;
769
+ if (!src) continue;
770
+ merged.appendChild(src.cloneNode(true));
771
+ any = true;
772
+ }
773
+ if (!any) continue;
774
+ if (slideLst) txBody.replaceChild(merged, slideLst);
775
+ else insertInOrder(txBody, merged, ["a:p"]);
776
+ }
777
+ }
778
+ /**
779
+ * Strip the `p:ph` marker from every placeholder shape in a lifted subtree so it
780
+ * becomes a self-contained ordinary shape (the {@link flattenShape} path only). By
781
+ * the time this runs, the shape's inherited geometry, colour, run size, anchor, and
782
+ * list style are all baked explicitly, so it no longer needs — and must not keep —
783
+ * its placeholder identity: a surviving `p:ph` would re-resolve against the *host*
784
+ * deck's layout/master placeholder of the same type/idx (wrong inheritance, or a
785
+ * fallback when the host has none) and could collide with the host slide's own
786
+ * placeholder of that type. Removing the marker severs both. The `p:nvPr` itself is
787
+ * kept (it can carry media/custom-data children); only the `p:ph` child goes.
788
+ */
789
+ function demotePlaceholders(shapeRoot) {
790
+ 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");
793
+ if (nvPr) removeChildrenByQName(nvPr, ["p:ph"]);
794
+ }
795
+ }
796
+ /**
797
+ * Bake placeholder-inherited run size/weight onto the slide. Mirrors
798
+ * {@link resolvePlaceholderRunColors}: for each placeholder run that sets no
799
+ * `sz`/`b`/`i` of its own (nor at paragraph/text-body level on the *slide*),
800
+ * resolve the value it would inherit from the source `slideLayout`/`slideMaster`
801
+ * text styles — per paragraph list level — and write it explicitly onto the run's
802
+ * `a:rPr`. Each property resolves independently up the chain. Typeface (`a:latin`)
803
+ * is left to re-bind to the destination theme, as the colour pass does for the `fontRef`.
804
+ */
805
+ 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
+ }
830
+ }
831
+ /** Write each resolved run property onto a run's `a:rPr`, skipping ones the slide already fixes. */
832
+ function writeRunProps(run, props, pPr, slideLst, level) {
833
+ let rPr = null;
834
+ for (const name of RUN_PROP_NAMES) {
835
+ const value = props[name];
836
+ if (value == null) continue;
837
+ if (slideDefinesProp(name, run, pPr, slideLst, level)) continue;
838
+ rPr ??= getOrAddChild(run, "a:rPr", ["a:t"]);
839
+ setAttr(rPr, name, value);
840
+ }
841
+ }
842
+ /**
843
+ * Resolve each shape's `p:style` `lnRef`/`fillRef`/`effectRef` into explicit
844
+ * `spPr` children (using the theme `fmtScheme`), then neutralize the ref. The
845
+ * `fontRef` is intentionally left for the destination theme to re-resolve.
846
+ */
847
+ function materializeStyleRefs(root, ctx) {
848
+ if (!ctx.fmtScheme) return;
849
+ for (const style of descendantsByTag(root, OOXML_NS.p, "style")) {
850
+ const shape = style.parentNode;
851
+ if (!shape) continue;
852
+ const spPr = getOrAddChild(shape, "p:spPr", SHAPE_AFTER_SPPR);
853
+ materializeFill(spPr, firstChild(style, "a:fillRef"), ctx);
854
+ materializeLine(spPr, firstChild(style, "a:lnRef"), ctx);
855
+ materializeEffect(spPr, firstChild(style, "a:effectRef"), ctx);
856
+ }
857
+ }
858
+ function materializeFill(spPr, fillRef, ctx) {
859
+ if (!fillRef) return;
860
+ if (!FILL_CHOICES.some((q) => firstChild(spPr, q))) {
861
+ const fill = styleRefFill(fillRef, ctx);
862
+ if (fill) insertInOrder(spPr, fill, SPPR_FILL_AFTER);
863
+ }
864
+ neutralizeRef(fillRef);
865
+ }
866
+ function materializeLine(spPr, lnRef, ctx) {
867
+ if (!lnRef) return;
868
+ if (!firstChild(spPr, "a:ln")) {
869
+ const ln = styleRefLine(lnRef, ctx);
870
+ if (ln) insertInOrder(spPr, ln, SPPR_LN_AFTER);
871
+ }
872
+ neutralizeRef(lnRef);
873
+ }
874
+ function materializeEffect(spPr, effectRef, ctx) {
875
+ if (!effectRef) return;
876
+ const idx = intAttr(effectRef, "idx");
877
+ if (idx !== null && idx > 0 && !firstChild(spPr, "a:effectLst") && !firstChild(spPr, "a:effectDag")) {
878
+ const style = fmtEntry(ctx, "a:effectStyleLst", idx);
879
+ const ref = resolveColor(firstChildElement(effectRef), ctx);
880
+ if (style && ref) {
881
+ substitutePhClr(style, ref);
882
+ for (const child of childElements(style)) if (isA(child, "effectLst") || isA(child, "effectDag")) insertInOrder(spPr, child, SPPR_EFFECT_AFTER);
883
+ else if (isA(child, "scene3d")) insertInOrder(spPr, child, SPPR_SCENE3D_AFTER);
884
+ else if (isA(child, "sp3d")) insertInOrder(spPr, child, SPPR_SP3D_AFTER);
885
+ }
886
+ }
887
+ neutralizeRef(effectRef);
888
+ }
889
+ /** Strip a style-matrix ref to `idx="0"` with no colour child so it contributes nothing. */
890
+ function neutralizeRef(ref) {
891
+ setAttr(ref, "idx", "0");
892
+ for (const child of childElements(ref)) ref.removeChild(child);
893
+ }
894
+ //#endregion
423
895
  //#region src/read/api/slide-background.ts
424
896
  /**
425
897
  * Read a slide's effective background (`p:cSld/p:bg`), decoded into a typed union.
@@ -460,20 +932,13 @@ function decodeBackgroundFill(container, ctx, rels) {
460
932
  relId: picture.relId,
461
933
  partName: picture.partName
462
934
  };
463
- const patt = firstChild(container, "a:pattFill");
464
- if (patt) {
465
- const wrapColor = (qname) => {
466
- const wrap = firstChild(patt, qname);
467
- const colorEl = wrap && firstChildElement(wrap);
468
- return colorEl ? resolveColorElement(colorEl, ctx) : null;
469
- };
470
- return {
471
- type: "pattern",
472
- preset: attr(patt, "prst") ?? null,
473
- foreground: wrapColor("a:fgClr"),
474
- background: wrapColor("a:bgClr")
475
- };
476
- }
935
+ const patt = readPatternFill(container, ctx);
936
+ if (patt) return {
937
+ type: "pattern",
938
+ preset: patt.preset,
939
+ foreground: patt.foreground,
940
+ background: patt.background
941
+ };
477
942
  return { type: "none" };
478
943
  }
479
944
  /**
@@ -528,13 +993,6 @@ function readSlideBackground(bg, source, ctx, rels, themeRels) {
528
993
  }
529
994
  //#endregion
530
995
  //#region src/read/api/notes.ts
531
- /** One EMU coordinate from a placeholder's `p:spPr/a:xfrm` child, or `null` when absent. */
532
- function xfrmEmu$1(sp, container, axis) {
533
- const spPr = firstChild(sp, "p:spPr");
534
- const xfrm = spPr && firstChild(spPr, "a:xfrm");
535
- const el = xfrm && firstChild(xfrm, container);
536
- return el ? intValue(attr(el, axis)) : null;
537
- }
538
996
  /**
539
997
  * One placeholder shape (`p:sp`) of a notes slide. A notes slide holds a fixed set:
540
998
  * the slide thumbnail (`type="sldImg"`), the notes body (`type="body"`), and the
@@ -584,19 +1042,19 @@ var NotesPlaceholder = class {
584
1042
  }
585
1043
  /** Left edge in EMU (`a:off/@x`), or `null` when geometry is inherited (no own `a:xfrm`). */
586
1044
  get left() {
587
- return xfrmEmu$1(this.sp, "a:off", "x");
1045
+ return spPrXfrmEmu(this.sp, "a:off", "x");
588
1046
  }
589
1047
  /** Top edge in EMU (`a:off/@y`), or `null` when geometry is inherited. */
590
1048
  get top() {
591
- return xfrmEmu$1(this.sp, "a:off", "y");
1049
+ return spPrXfrmEmu(this.sp, "a:off", "y");
592
1050
  }
593
1051
  /** Width in EMU (`a:ext/@cx`), or `null` when geometry is inherited. */
594
1052
  get width() {
595
- return xfrmEmu$1(this.sp, "a:ext", "cx");
1053
+ return spPrXfrmEmu(this.sp, "a:ext", "cx");
596
1054
  }
597
1055
  /** Height in EMU (`a:ext/@cy`), or `null` when geometry is inherited. */
598
1056
  get height() {
599
- return xfrmEmu$1(this.sp, "a:ext", "cy");
1057
+ return spPrXfrmEmu(this.sp, "a:ext", "cy");
600
1058
  }
601
1059
  /**
602
1060
  * The placeholder's text as a navigable {@link TextFrame} (`p:txBody`), or `null`
@@ -862,8 +1320,6 @@ function readTagsForPart(opc, ownerPartName) {
862
1320
  }
863
1321
  //#endregion
864
1322
  //#region src/read/api/chrome.ts
865
- const SLIDE_MASTER_REL$4 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
866
- const THEME_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
867
1323
  const THEME_COLOR_SLOTS = [
868
1324
  "dk1",
869
1325
  "lt1",
@@ -973,23 +1429,10 @@ var Theme = class {
973
1429
  return themeElements ? firstChild(themeElements, "a:clrScheme") : null;
974
1430
  }
975
1431
  };
976
- /** One EMU coordinate from a placeholder's `p:spPr/a:xfrm` child, or `null` when absent. */
977
- function xfrmEmu(sp, container, axis) {
978
- const spPr = firstChild(sp, "p:spPr");
979
- const xfrm = spPr && firstChild(spPr, "a:xfrm");
980
- const el = xfrm && firstChild(xfrm, container);
981
- return el ? intValue(attr(el, axis)) : null;
982
- }
983
- /** The `p:ph` element of a shape (`p:sp/p:nvSpPr/p:nvPr/p:ph`), or `null` when it is not a placeholder. */
984
- function placeholderElement(sp) {
985
- const nvSpPr = firstChild(sp, "p:nvSpPr");
986
- const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
987
- return nvPr ? firstChild(nvPr, "p:ph") : null;
988
- }
989
1432
  /** The placeholder shapes (`p:sp` carrying a `p:ph`) of a master/layout `p:spTree`, in document order. */
990
1433
  function placeholderShapes(spTree) {
991
1434
  if (!spTree) return [];
992
- return getElements(spTree, "p:sp").filter((sp) => placeholderElement(sp) !== null);
1435
+ return getElements(spTree, "p:sp").filter((sp) => placeholderOf(sp) !== null);
993
1436
  }
994
1437
  /**
995
1438
  * One placeholder shape (`p:sp` with a `p:ph`) of a slide master or slide layout —
@@ -1015,12 +1458,12 @@ var Placeholder = class {
1015
1458
  }
1016
1459
  /** Placeholder type (`p:ph/@type`: `title` | `body` | `sldNum` | …), or `null` when absent (a body placeholder). */
1017
1460
  get type() {
1018
- const ph = placeholderElement(this.sp);
1461
+ const ph = placeholderOf(this.sp);
1019
1462
  return ph ? attr(ph, "type") : null;
1020
1463
  }
1021
1464
  /** Placeholder index (`p:ph/@idx`), or `null` when unset. */
1022
1465
  get idx() {
1023
- const ph = placeholderElement(this.sp);
1466
+ const ph = placeholderOf(this.sp);
1024
1467
  return ph ? attr(ph, "idx") : null;
1025
1468
  }
1026
1469
  /** Shape name (`p:cNvPr/@name`), or `''` when unnamed. */
@@ -1035,19 +1478,19 @@ var Placeholder = class {
1035
1478
  }
1036
1479
  /** Left edge in EMU (`a:off/@x`), or `null` when the placeholder carries no own `a:xfrm`. */
1037
1480
  get left() {
1038
- return xfrmEmu(this.sp, "a:off", "x");
1481
+ return spPrXfrmEmu(this.sp, "a:off", "x");
1039
1482
  }
1040
1483
  /** Top edge in EMU (`a:off/@y`), or `null` when the placeholder carries no own `a:xfrm`. */
1041
1484
  get top() {
1042
- return xfrmEmu(this.sp, "a:off", "y");
1485
+ return spPrXfrmEmu(this.sp, "a:off", "y");
1043
1486
  }
1044
1487
  /** Width in EMU (`a:ext/@cx`), or `null` when the placeholder carries no own `a:xfrm`. */
1045
1488
  get width() {
1046
- return xfrmEmu(this.sp, "a:ext", "cx");
1489
+ return spPrXfrmEmu(this.sp, "a:ext", "cx");
1047
1490
  }
1048
1491
  /** Height in EMU (`a:ext/@cy`), or `null` when the placeholder carries no own `a:xfrm`. */
1049
1492
  get height() {
1050
- return xfrmEmu(this.sp, "a:ext", "cy");
1493
+ return spPrXfrmEmu(this.sp, "a:ext", "cy");
1051
1494
  }
1052
1495
  /**
1053
1496
  * The placeholder's text as a navigable {@link TextFrame} (`p:txBody`), or `null`
@@ -1093,7 +1536,7 @@ var SlideMaster = class {
1093
1536
  }
1094
1537
  /** The master's theme (via its `theme` relationship), or `null` when absent. */
1095
1538
  get theme() {
1096
- const themePart = this.#relTarget(THEME_REL$1);
1539
+ const themePart = this.#relTarget(THEME_REL);
1097
1540
  return themePart ? new Theme(themePart) : null;
1098
1541
  }
1099
1542
  /**
@@ -1137,7 +1580,7 @@ var SlideMaster = class {
1137
1580
  get background() {
1138
1581
  const bg = backgroundElementOf(this.part.dom.documentElement);
1139
1582
  if (!bg) return null;
1140
- const themePart = this.#relTarget(THEME_REL$1);
1583
+ const themePart = this.#relTarget(THEME_REL);
1141
1584
  return readSlideBackground(bg, "master", this.themeContext(), this.opc.relationshipsFor(this.partName), themePart ? this.opc.relationshipsFor(themePart.partName) : null);
1142
1585
  }
1143
1586
  /**
@@ -1197,7 +1640,7 @@ var SlideLayout = class {
1197
1640
  /** The master this layout is built on (via its `slideMaster` relationship), or `null` when absent. */
1198
1641
  get master() {
1199
1642
  const rels = this.opc.relationshipsFor(this.partName);
1200
- const rel = rels.byType(SLIDE_MASTER_REL$4)[0];
1643
+ const rel = rels.byType(SLIDE_MASTER_REL)[0];
1201
1644
  const part = rel ? this.opc.part(rels.resolveTarget(rel.id)) : null;
1202
1645
  return part ? new SlideMaster(this.opc, part) : null;
1203
1646
  }
@@ -1368,7 +1811,8 @@ function buildTransitionElement(doc, input, speed, withDur) {
1368
1811
  if (withDur && typeof input.durationMs === "number") setAttr(transition, "p14:dur", String(Math.round(input.durationMs)));
1369
1812
  if (input.advanceOnClick === false) setAttr(transition, "advClick", "0");
1370
1813
  if (typeof input.advanceAfterMs === "number") setAttr(transition, "advTm", String(Math.round(input.advanceAfterMs)));
1371
- const type = createElement(doc, `${input.namespace ?? "p"}:${input.type}`);
1814
+ const prefix = input.namespace ?? "p";
1815
+ const type = createElement(doc, `${prefix}:${input.type}`);
1372
1816
  for (const [name, value] of Object.entries(input.variant ?? {})) setAttr(type, name, value);
1373
1817
  transition.appendChild(type);
1374
1818
  return transition;
@@ -1598,7 +2042,8 @@ function getOrCreateMainSeqChildTnLst(root, doc) {
1598
2042
  }
1599
2043
  let tmRootChildLst = timing.getElementsByTagNameNS(P_NS, "childTnLst")[0];
1600
2044
  if (!tmRootChildLst) {
1601
- const freshTnLst = firstChild(importScaffold(doc, TIMING_SCAFFOLD), "p:tnLst");
2045
+ const fresh = importScaffold(doc, TIMING_SCAFFOLD);
2046
+ const freshTnLst = firstChild(fresh, "p:tnLst");
1602
2047
  if (freshTnLst) insertInOrder(timing, freshTnLst, ["p:bldLst", "p:extLst"]);
1603
2048
  tmRootChildLst = timing.getElementsByTagNameNS(P_NS, "childTnLst")[0];
1604
2049
  }
@@ -1670,9 +2115,6 @@ function carryShapeAnimations(sourceRoot, targetRoot, spidMap) {
1670
2115
  }
1671
2116
  //#endregion
1672
2117
  //#region src/read/api/slide.ts
1673
- const IMAGE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
1674
- const NOTES_SLIDE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
1675
- const SLIDE_LAYOUT_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
1676
2118
  /** Recognize a handful of common raster formats from their leading bytes. */
1677
2119
  function sniffImageType(bytes) {
1678
2120
  const b = bytes;
@@ -1947,7 +2389,7 @@ var Slide = class {
1947
2389
  * slide-number field round-trip either way.
1948
2390
  */
1949
2391
  get notesSlide() {
1950
- const notesRel = this.relationships.byType(NOTES_SLIDE_REL_TYPE)[0];
2392
+ const notesRel = this.relationships.byType(NOTES_SLIDE_REL)[0];
1951
2393
  if (!notesRel) return null;
1952
2394
  const notesPart = this.presentation.opc.part(this.relationships.resolveTarget(notesRel.id));
1953
2395
  if (!notesPart) return null;
@@ -1960,7 +2402,7 @@ var Slide = class {
1960
2402
  * {@link master} and {@link theme} through it (`slide.layout.master.theme`).
1961
2403
  */
1962
2404
  get layout() {
1963
- const rel = this.relationships.byType(SLIDE_LAYOUT_REL_TYPE)[0];
2405
+ const rel = this.relationships.byType(SLIDE_LAYOUT_REL)[0];
1964
2406
  if (!rel) return null;
1965
2407
  const part = this.presentation.opc.part(this.relationships.resolveTarget(rel.id));
1966
2408
  return part ? new SlideLayout(this.presentation.opc, part) : null;
@@ -2167,7 +2609,7 @@ var Slide = class {
2167
2609
  const opc = this.presentation.opc;
2168
2610
  const mediaPartName = opc.reserveMediaPartName(extension);
2169
2611
  opc.addPart(mediaPartName, contentType, image);
2170
- const relId = this.relationships.add(IMAGE_REL_TYPE, relativePartName(this.partName, mediaPartName)).id;
2612
+ const relId = this.relationships.add(IMAGE_REL, relativePartName(this.partName, mediaPartName)).id;
2171
2613
  const id = this.#nextShapeId();
2172
2614
  const pic = buildPicture(doc, {
2173
2615
  id,
@@ -2240,7 +2682,8 @@ function buildTextBox(doc, spec) {
2240
2682
  const cNvPr = append(nvSpPr, "p:cNvPr");
2241
2683
  setAttr(cNvPr, "id", String(spec.id));
2242
2684
  setAttr(cNvPr, "name", spec.name);
2243
- setAttr(append(nvSpPr, "p:cNvSpPr"), "txBox", "1");
2685
+ const cNvSpPr = append(nvSpPr, "p:cNvSpPr");
2686
+ setAttr(cNvSpPr, "txBox", "1");
2244
2687
  append(nvSpPr, "p:nvPr");
2245
2688
  const spPr = append(sp, "p:spPr");
2246
2689
  const xfrm = append(spPr, "a:xfrm");
@@ -2277,10 +2720,12 @@ function buildPicture(doc, spec) {
2277
2720
  const cNvPr = append(nvPicPr, "p:cNvPr");
2278
2721
  setAttr(cNvPr, "id", String(spec.id));
2279
2722
  setAttr(cNvPr, "name", spec.name);
2280
- setAttr(append(append(nvPicPr, "p:cNvPicPr"), "a:picLocks"), "noChangeAspect", "1");
2723
+ const picLocks = append(append(nvPicPr, "p:cNvPicPr"), "a:picLocks");
2724
+ setAttr(picLocks, "noChangeAspect", "1");
2281
2725
  append(nvPicPr, "p:nvPr");
2282
2726
  const blipFill = append(pic, "p:blipFill");
2283
- setAttr(append(blipFill, "a:blip"), "r:embed", spec.relId);
2727
+ const blip = append(blipFill, "a:blip");
2728
+ setAttr(blip, "r:embed", spec.relId);
2284
2729
  append(append(blipFill, "a:stretch"), "a:fillRect");
2285
2730
  const spPr = append(pic, "p:spPr");
2286
2731
  const xfrm = append(spPr, "a:xfrm");
@@ -2404,7 +2849,7 @@ function readCustomProperties(opc) {
2404
2849
  return out;
2405
2850
  }
2406
2851
  //#endregion
2407
- //#region src/read/api/slide-dom.ts
2852
+ //#region src/read/oxml/slide-dom.ts
2408
2853
  /** The `p:cSld@name` of a slide/layout/master part (`''` when absent). */
2409
2854
  function cSldName(part) {
2410
2855
  const root = part?.dom.documentElement;
@@ -2468,7 +2913,7 @@ function collectElements(node, out) {
2468
2913
  for (let child = node.firstChild; child; child = child.nextSibling) if (child.nodeType === 1) collectElements(child, out);
2469
2914
  }
2470
2915
  //#endregion
2471
- //#region src/read/api/rescale.ts
2916
+ //#region src/read/api/ops/rescale.ts
2472
2917
  /** Build the EMU transform mapping source-canvas coordinates onto the target canvas (see {@link ImportSlideOptions.rescale}). */
2473
2918
  function computeRescale(source, target, mode) {
2474
2919
  if (mode === "stretch") return {
@@ -2514,7 +2959,6 @@ function rescaleSpTree(spTree, t) {
2514
2959
  case "graphicFrame":
2515
2960
  rescaleXfrm(firstChild(el, "p:xfrm"), t);
2516
2961
  rescaleTableGrid(el, t);
2517
- break;
2518
2962
  }
2519
2963
  }
2520
2964
  }
@@ -2557,7 +3001,7 @@ function rescaleTableGrid(graphicFrame, t) {
2557
3001
  }
2558
3002
  }
2559
3003
  //#endregion
2560
- //#region src/read/api/table-styles.ts
3004
+ //#region src/read/api/ops/table-styles.ts
2561
3005
  const TABLE_STYLES_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableStyles";
2562
3006
  const TABLE_STYLES_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml";
2563
3007
  const TABLE_STYLES_DEFAULT_GUID = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}";
@@ -2662,7 +3106,7 @@ function ensureTableStylesPart(dest) {
2662
3106
  return part;
2663
3107
  }
2664
3108
  //#endregion
2665
- //#region src/read/api/master-registry.ts
3109
+ //#region src/read/api/ops/master-registry.ts
2666
3110
  /**
2667
3111
  * Slide-master bookkeeping in `presentation.xml` and in a master's own
2668
3112
  * `p:sldLayoutIdLst`: registering a master so renderers treat it as active,
@@ -2674,9 +3118,6 @@ function ensureTableStylesPart(dest) {
2674
3118
  * they take a structural {@link DeckTarget} rather than a `Presentation`. The
2675
3119
  * source-side half that drives most of them is `part-copy.ts`.
2676
3120
  */
2677
- const SLIDE_MASTER_REL$3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
2678
- const SLIDE_LAYOUT_REL$3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
2679
- const MIN_SLIDE_MASTER_ID = 2147483648;
2680
3121
  /**
2681
3122
  * Wire a freshly-copied slide master into `presentation.xml`: add a
2682
3123
  * presentation→master relationship and a `p:sldMasterId` entry in
@@ -2688,8 +3129,8 @@ const MIN_SLIDE_MASTER_ID = 2147483648;
2688
3129
  function registerMaster(dest, masterPartName) {
2689
3130
  const presPart = dest.presentationPart;
2690
3131
  const presRels = dest.opc.relationshipsFor(presPart.partName);
2691
- for (const rel of presRels.byType(SLIDE_MASTER_REL$3)) if (presRels.resolveTarget(rel.id) === masterPartName) return;
2692
- const relId = presRels.add(SLIDE_MASTER_REL$3, relativePartName(presPart.partName, masterPartName)).id;
3132
+ for (const rel of presRels.byType(SLIDE_MASTER_REL)) if (presRels.resolveTarget(rel.id) === masterPartName) return;
3133
+ const relId = presRels.add(SLIDE_MASTER_REL, relativePartName(presPart.partName, masterPartName)).id;
2693
3134
  const root = presPart.dom.documentElement;
2694
3135
  if (!root) throw new PackageReadError("package/part-has-no-root", "presentation.xml has no document element to register a master in");
2695
3136
  const lst = getOrAddChild(root, "p:sldMasterIdLst", [
@@ -2751,7 +3192,7 @@ function promoteMasters(dest, masterPartNames) {
2751
3192
  * allocation so ids appended earlier in the same import are counted.
2752
3193
  */
2753
3194
  function nextMasterLayoutId(dest) {
2754
- let max = MIN_SLIDE_MASTER_ID - 1;
3195
+ let max = 2147483647;
2755
3196
  const presPart = dest.presentationPart;
2756
3197
  const root = presPart.dom.documentElement;
2757
3198
  const masterLst = root && firstChild(root, "p:sldMasterIdLst");
@@ -2760,7 +3201,7 @@ function nextMasterLayoutId(dest) {
2760
3201
  if (id !== null && id > max) max = id;
2761
3202
  }
2762
3203
  const presRels = dest.opc.relationshipsFor(presPart.partName);
2763
- for (const rel of presRels.byType(SLIDE_MASTER_REL$3)) {
3204
+ for (const rel of presRels.byType(SLIDE_MASTER_REL)) {
2764
3205
  const masterRoot = dest.opc.part(presRels.resolveTarget(rel.id))?.dom.documentElement;
2765
3206
  const layoutLst = masterRoot && firstChild(masterRoot, "p:sldLayoutIdLst");
2766
3207
  if (!layoutLst) continue;
@@ -2790,7 +3231,7 @@ function addLayoutToMaster(dest, masterPartName, layoutPartName) {
2790
3231
  const masterPart = dest.opc.part(masterPartName);
2791
3232
  const root = masterPart?.dom.documentElement;
2792
3233
  if (!masterPart || !root) return;
2793
- const relId = dest.opc.relationshipsFor(masterPartName).add(SLIDE_LAYOUT_REL$3, relativePartName(masterPartName, layoutPartName)).id;
3234
+ const relId = dest.opc.relationshipsFor(masterPartName).add(SLIDE_LAYOUT_REL, relativePartName(masterPartName, layoutPartName)).id;
2794
3235
  const lst = getOrAddChild(root, "p:sldLayoutIdLst", [
2795
3236
  "p:transition",
2796
3237
  "p:timing",
@@ -2805,10 +3246,7 @@ function addLayoutToMaster(dest, masterPartName, layoutPartName) {
2805
3246
  masterPart.markDirty();
2806
3247
  }
2807
3248
  //#endregion
2808
- //#region src/read/api/part-copy.ts
2809
- const SLIDE_LAYOUT_REL$2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
2810
- const SLIDE_MASTER_REL$2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
2811
- const NOTES_SLIDE_REL$2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
3249
+ //#region src/read/api/ops/part-copy.ts
2812
3250
  const SLIDE_MASTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml";
2813
3251
  const SLIDE_LAYOUT_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml";
2814
3252
  /**
@@ -2833,8 +3271,8 @@ function copyPart(ctx, sourcePartName) {
2833
3271
  const sourceRels = ctx.source.relationshipsFor(sourcePartName);
2834
3272
  const targetRels = ctx.dest.opc.relationshipsFor(newPartName);
2835
3273
  for (const rel of sourceRels) {
2836
- if (rel.type === NOTES_SLIDE_REL$2) continue;
2837
- if (isMaster && rel.type === SLIDE_LAYOUT_REL$2) continue;
3274
+ if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") continue;
3275
+ if (isMaster && rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") continue;
2838
3276
  if (rel.targetMode === "External") {
2839
3277
  targetRels.addWithId(rel.id, rel.type, rel.target, "External");
2840
3278
  continue;
@@ -2857,13 +3295,76 @@ function copyPart(ctx, sourcePartName) {
2857
3295
  * accumulates exactly the imported layouts.
2858
3296
  */
2859
3297
  function linkLayoutIntoMaster(ctx, layoutSourceRels, layoutPartName) {
2860
- const masterRel = layoutSourceRels.byType(SLIDE_MASTER_REL$2)[0];
3298
+ const masterRel = layoutSourceRels.byType(SLIDE_MASTER_REL)[0];
2861
3299
  if (!masterRel) return;
2862
3300
  const masterPartName = ctx.registry.get(layoutSourceRels.resolveTarget(masterRel.id));
2863
3301
  if (!masterPartName) return;
2864
3302
  addLayoutToMaster(ctx.dest, masterPartName, layoutPartName);
2865
3303
  }
2866
3304
  //#endregion
3305
+ //#region src/read/api/ops/carried-rels.ts
3306
+ /**
3307
+ * Relationship rewriting for content carried between packages.
3308
+ *
3309
+ * When a shape or decoration is deep-copied out of a source deck, every relationship
3310
+ * reference it carries (`r:embed` on a picture fill, `r:id` on a chart frame, `r:link` on a
3311
+ * linked image, …) still names an id in the *source* part's relationship list. Left alone
3312
+ * those ids either dangle or — worse — silently resolve to whatever the destination part
3313
+ * happens to have under the same id. This rewrites each one to a fresh relationship on the
3314
+ * destination part, copying the referenced part into the destination package on first sight.
3315
+ *
3316
+ * Both functions are pure with respect to the deck: everything they touch arrives as an
3317
+ * argument. They were private methods on `Presentation` and used no instance state, which
3318
+ * made the import subsystem look more entangled with the read model than it is.
3319
+ */
3320
+ /**
3321
+ * Rewrite every relationship reference inside a carried subtree to a fresh destination-local id.
3322
+ * @param {Element} node - root of the carried subtree (rewritten in place)
3323
+ * @param {ImportContext} ctx - the open import (destination deck + source package + copy registry)
3324
+ * @param {Relationships} sourceRels - relationships of the source part the subtree came from
3325
+ * @param {string} destPartName - partname of the destination part the subtree is being placed in
3326
+ * @param {Relationships} destRels - relationships of that destination part
3327
+ * @param {Map<string, string>} relIdMap - per-call cache (source part + source id → new id) deduping references shared within one import
3328
+ */
3329
+ function rewriteCarriedRels(node, ctx, sourceRels, destPartName, destRels, relIdMap) {
3330
+ const elements = [];
3331
+ collectElements(node, elements);
3332
+ for (const el of elements) {
3333
+ const refs = [];
3334
+ const attrs = el.attributes;
3335
+ for (let i = 0; i < attrs.length; i++) {
3336
+ const a = attrs.item(i);
3337
+ if (!a || a.namespaceURI !== OOXML_NS.r || !a.value) continue;
3338
+ if (!sourceRels.get(a.value)) continue;
3339
+ refs.push({
3340
+ local: a.localName ?? a.name,
3341
+ id: a.value
3342
+ });
3343
+ }
3344
+ for (const { local, id } of refs) setAttr(el, `r:${local}`, carryRel(ctx, sourceRels, id, destPartName, destRels, relIdMap));
3345
+ }
3346
+ }
3347
+ /**
3348
+ * Resolve one carried relationship to a fresh destination-local id, copying its internal target.
3349
+ * @param {ImportContext} ctx - the open import
3350
+ * @param {Relationships} sourceRels - relationships of the source part
3351
+ * @param {string} id - the source relationship id to carry
3352
+ * @param {string} destPartName - partname of the destination part
3353
+ * @param {Relationships} destRels - relationships of that destination part
3354
+ * @param {Map<string, string>} relIdMap - per-call dedupe cache
3355
+ * @return {string} the new relationship id on the destination part
3356
+ */
3357
+ function carryRel(ctx, sourceRels, id, destPartName, destRels, relIdMap) {
3358
+ const key = `${sourceRels.sourcePartName}|${id}`;
3359
+ const cached = relIdMap.get(key);
3360
+ if (cached) return cached;
3361
+ const rel = sourceRels.get(id);
3362
+ if (!rel) throw new InvalidOptionError("relationship/not-found", `Relationships of ${sourceRels.sourcePartName}: no relationship with id ${id}`);
3363
+ const newId = rel.targetMode === "External" ? destRels.add(rel.type, rel.target, "External").id : destRels.add(rel.type, relativePartName(destPartName, copyPart(ctx, sourceRels.resolveTarget(id)))).id;
3364
+ relIdMap.set(key, newId);
3365
+ return newId;
3366
+ }
3367
+ //#endregion
2867
3368
  //#region src/read/api/ops/embedded-fonts.ts
2868
3369
  /**
2869
3370
  * Merging embedded font faces into a deck's `p:embeddedFontLst`.
@@ -3047,6 +3548,277 @@ function mergeEmbeddedFontEntries(dest, entries) {
3047
3548
  if (copiedAny) presPart.markDirty();
3048
3549
  }
3049
3550
  //#endregion
3551
+ //#region src/read/api/ops/flatten-context.ts
3552
+ /**
3553
+ * The theme context a source slide is flattened against.
3554
+ *
3555
+ * `preserve`-mode import bakes a slide's *source* look into its XML — scheme colours and
3556
+ * style-matrix fills resolved to literals — so it keeps that look after being attached to a
3557
+ * different deck's master. Doing so needs the source subgraph's colour map, colour scheme,
3558
+ * format scheme, and the background the slide inherits but does not itself carry. This
3559
+ * gathers exactly that.
3560
+ *
3561
+ * Pure with respect to the destination deck: it reads only the source package. It was a
3562
+ * private method on `Presentation` that used no instance state.
3563
+ */
3564
+ /** The `p:cSld/p:bg` element of a slide/layout/master root, or `null`. */
3565
+ function backgroundOf(root) {
3566
+ const cSld = firstChild(root, "p:cSld");
3567
+ return cSld ? firstChild(cSld, "p:bg") : null;
3568
+ }
3569
+ /**
3570
+ * The background the slide effectively inherits from its source subgraph: the layout's
3571
+ * `p:bg`, else the master's. Returns `null` when the slide carries its own `p:bg` (it stays
3572
+ * on the slide and is flattened directly) or when none exists.
3573
+ */
3574
+ function effectiveBackground(sourceOpc, slideRoot, layoutPartName, masterPartName) {
3575
+ if (slideRoot && backgroundOf(slideRoot)) return null;
3576
+ const layoutRoot = layoutPartName ? sourceOpc.part(layoutPartName)?.dom.documentElement ?? null : null;
3577
+ const masterRoot = masterPartName ? sourceOpc.part(masterPartName)?.dom.documentElement ?? null : null;
3578
+ return (layoutRoot && backgroundOf(layoutRoot)) ?? (masterRoot && backgroundOf(masterRoot)) ?? null;
3579
+ }
3580
+ /**
3581
+ * Gather the flatten context for a source slide: walk slide → layout → master → theme,
3582
+ * reading the effective colour map (the slide's `clrMapOvr` override, or the master
3583
+ * `clrMap`), the theme `clrScheme`, and the theme `fmtScheme`.
3584
+ * @param {OpcPackage} sourceOpc - the source package to read
3585
+ * @param {string} slidePartName - partname of the source slide
3586
+ * @return {FlattenContext} the context {@link flattenSlide} / {@link flattenShape} resolve against
3587
+ */
3588
+ function sourceFlattenContext(sourceOpc, slidePartName) {
3589
+ const parts = resolveSlideThemeParts(sourceOpc, slidePartName);
3590
+ const themeElements = parts.themeElements;
3591
+ return {
3592
+ clrMap: parts.clrMap,
3593
+ clrScheme: parts.clrScheme,
3594
+ fmtScheme: themeElements ? firstChild(themeElements, "a:fmtScheme") : null,
3595
+ inheritedBackground: effectiveBackground(sourceOpc, parts.slideRoot, parts.layoutPartName, parts.masterPartName),
3596
+ layoutRoot: parts.layoutRoot,
3597
+ masterRoot: parts.masterRoot
3598
+ };
3599
+ }
3600
+ //#endregion
3601
+ //#region src/read/api/ops/part-index.ts
3602
+ /**
3603
+ * Walking a deck's master/layout spine by partname.
3604
+ *
3605
+ * The `p:sldMasterIdLst` / `p:sldLayoutIdLst` entries hold relationship ids, not partnames, so
3606
+ * every traversal has to resolve through the owning part's relationships. These are the
3607
+ * source-side reads that do it — used against a *foreign* presentation as often as against this
3608
+ * one, which is why they take the deck rather than living on it.
3609
+ */
3610
+ /** Master partnames in `p:sldMasterIdLst` order. */
3611
+ function slideMasterPartNames(pres) {
3612
+ const root = pres.presentationPart.dom.documentElement;
3613
+ const lst = root && firstChild(root, "p:sldMasterIdLst");
3614
+ if (!lst) return [];
3615
+ const rels = pres.opc.relationshipsFor(pres.presentationPart.partName);
3616
+ const out = [];
3617
+ for (const entry of getElements(lst, "p:sldMasterId")) {
3618
+ const relId = attr(entry, "r:id");
3619
+ if (relId) out.push(rels.resolveTarget(relId));
3620
+ }
3621
+ return out;
3622
+ }
3623
+ /** A master's layout partnames in `p:sldLayoutIdLst` order. */
3624
+ function layoutPartNamesOf(pres, masterPartName) {
3625
+ const root = pres.opc.part(masterPartName)?.dom.documentElement;
3626
+ const lst = root && firstChild(root, "p:sldLayoutIdLst");
3627
+ if (!lst) return [];
3628
+ const rels = pres.opc.relationshipsFor(masterPartName);
3629
+ const out = [];
3630
+ for (const entry of getElements(lst, "p:sldLayoutId")) {
3631
+ const relId = attr(entry, "r:id");
3632
+ if (relId) out.push(rels.resolveTarget(relId));
3633
+ }
3634
+ return out;
3635
+ }
3636
+ //#endregion
3637
+ //#region src/read/api/ops/import-slide.ts
3638
+ /**
3639
+ * The three ways a slide can be brought across from another deck.
3640
+ *
3641
+ * {@link Presentation.importSlide} picks one by `options.theme`, and the difference between
3642
+ * them is entirely about what happens to the slide's *look*:
3643
+ *
3644
+ * - **`copy`** — not here. It copies the source theme subgraph wholesale via `copyPart`, so
3645
+ * the slide keeps its look by keeping its own theme; nothing needs rewriting.
3646
+ * - **`preserve`** ({@link importSlidePreserve}) — rebind to this deck's master, then bake
3647
+ * the source theme into the slide XML. The slide looks the same as it did; it just no
3648
+ * longer depends on the theme it came from.
3649
+ * - **`restyle`** ({@link importSlideRestyle}) — rebind and bake *nothing*, so the slide's
3650
+ * symbolic theme references re-resolve against the destination theme and it re-brands.
3651
+ *
3652
+ * The two share {@link importSlideRebind} and are exact inverses on top of it: preserve
3653
+ * resolves every reference it can, restyle resolves none. Any baking added to the shared
3654
+ * rebind would break restyle by pinning the slide to its source look, which is why the
3655
+ * rebind carries no theme handling of its own — not even the inherited background.
3656
+ *
3657
+ * These were private methods on `Presentation`, where they made the read model's own surface
3658
+ * (open a deck, walk slides, read shapes) hard to see: the import machinery was roughly two
3659
+ * thirds of the class. They live here as free functions taking the destination deck, matching
3660
+ * the other `ops/` modules.
3661
+ */
3662
+ /**
3663
+ * Import a slide in `preserve` mode: rebind it to this deck's master/layout, then flatten its
3664
+ * source theme into the slide XML (scheme colours + style-matrix fills baked to literals).
3665
+ *
3666
+ * The flatten context is gathered from the *source* subgraph, so it can be read before or
3667
+ * after the rebind; the rebind injects any carried decorations before we flatten, so a single
3668
+ * sweep resolves the theme references on the slide's own content and on the carried
3669
+ * decorations together.
3670
+ * @param {Presentation} dest - the destination deck
3671
+ * @param {ImportContext} ctx - the open import out of the source package
3672
+ * @param {Presentation} source - the source deck
3673
+ * @param {Slide} sourceSlide - the slide being imported
3674
+ * @param {boolean} carryGraphics - bake the source master/layout decorations onto the slide
3675
+ * @return {string} partname of the new slide part in the destination package
3676
+ */
3677
+ function importSlidePreserve(dest, ctx, source, sourceSlide, carryGraphics) {
3678
+ const flattenCtx = sourceFlattenContext(source.opc, sourceSlide.partName);
3679
+ const { newPartName, slideRoot, newPart } = importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics);
3680
+ flattenSlide(slideRoot, flattenCtx);
3681
+ newPart.markDirty();
3682
+ return newPartName;
3683
+ }
3684
+ /**
3685
+ * Import a slide in `restyle` mode: rebind it to this deck's master/layout and then
3686
+ * {@link restyleSlide} it — drop its colour map override but bake *nothing*, so its symbolic
3687
+ * theme references re-resolve against the destination theme and the slide re-brands.
3688
+ *
3689
+ * The deliberate inverse of `preserve`: no flatten, no inherited-background bake, no
3690
+ * placeholder colour/size/geometry bake — every one of those would pin the slide to its
3691
+ * source look, the opposite of re-branding. Carried decorations are left symbolic too, so
3692
+ * they re-brand along with the slide.
3693
+ *
3694
+ * With `remapLiterals` it additionally force-remaps the slide's source-theme literal colours
3695
+ * back to symbolic scheme colours and copies any referenced source table style into this deck
3696
+ * — the two things plain `restyle` cannot re-brand.
3697
+ * @param {Presentation} dest - the destination deck
3698
+ * @param {ImportContext} ctx - the open import out of the source package
3699
+ * @param {Presentation} source - the source deck
3700
+ * @param {Slide} sourceSlide - the slide being imported
3701
+ * @param {boolean} carryGraphics - bake the source master/layout decorations onto the slide
3702
+ * @param {boolean} remapLiterals - additionally remap source-theme literal colours to scheme tokens
3703
+ * @return {string} partname of the new slide part in the destination package
3704
+ */
3705
+ function importSlideRestyle(dest, ctx, source, sourceSlide, carryGraphics, remapLiterals) {
3706
+ const { newPartName, slideRoot, newPart } = importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics);
3707
+ restyleSlide(slideRoot);
3708
+ if (remapLiterals) {
3709
+ const parts = resolveSlideThemeParts(source.opc, sourceSlide.partName);
3710
+ remapLiteralColors(slideRoot, {
3711
+ clrMap: parts.clrMap,
3712
+ clrScheme: parts.clrScheme
3713
+ });
3714
+ copySourceTableStyles(dest, source.opc, slideRoot);
3715
+ }
3716
+ newPart.markDirty();
3717
+ return newPartName;
3718
+ }
3719
+ /**
3720
+ * The rebind shared by `preserve` and `restyle`: copy the slide bytes into a fresh part,
3721
+ * rebuild its relationships (drop notes, repoint the `slideLayout` rel at this deck's
3722
+ * existing layout, copy every other internal target — media/charts — and pass externals
3723
+ * through), and optionally bake the source master/layout decorations onto the slide. Returns
3724
+ * the new part, its name, and its live root element for the caller's mode-specific pass.
3725
+ *
3726
+ * This carries *no* theme baking of its own — not even the inherited background.
3727
+ * `preserve` adds that via {@link flattenSlide}'s context; `restyle` must not, so the
3728
+ * background stays symbolic and re-brands.
3729
+ * @param {Presentation} dest - the destination deck
3730
+ * @param {ImportContext} ctx - the open import out of the source package
3731
+ * @param {Presentation} source - the source deck
3732
+ * @param {Slide} sourceSlide - the slide being imported
3733
+ * @param {boolean} carryGraphics - bake the source master/layout decorations onto the slide
3734
+ * @return {RebindResult} the new part, its partname, and its live root element
3735
+ */
3736
+ function importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics) {
3737
+ const destLayout = destinationLayoutPartName(dest);
3738
+ const sourcePart = source.opc.part(sourceSlide.partName);
3739
+ if (!sourcePart) throw new PackageReadError("package/part-missing", `importSlide: source package has no part ${sourceSlide.partName}`);
3740
+ const newPartName = dest.opc.reservePartNameLike(sourceSlide.partName);
3741
+ const newPart = dest.opc.addPart(newPartName, sourcePart.contentType, sourcePart.bytes);
3742
+ const slideRoot = newPart.dom.documentElement;
3743
+ if (!slideRoot) throw new PackageReadError("package/part-has-no-root", `Imported slide ${newPartName} has no root element`);
3744
+ const sourceRels = source.opc.relationshipsFor(sourceSlide.partName);
3745
+ const targetRels = dest.opc.relationshipsFor(newPartName);
3746
+ for (const rel of sourceRels) {
3747
+ if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") continue;
3748
+ if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") {
3749
+ targetRels.addWithId(rel.id, SLIDE_LAYOUT_REL, relativePartName(newPartName, destLayout));
3750
+ continue;
3751
+ }
3752
+ if (rel.targetMode === "External") {
3753
+ targetRels.addWithId(rel.id, rel.type, rel.target, "External");
3754
+ continue;
3755
+ }
3756
+ const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id));
3757
+ targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTarget));
3758
+ }
3759
+ if (carryGraphics) carryMasterGraphics(dest, ctx, slideRoot, newPartName, sourceSlide.partName);
3760
+ return {
3761
+ newPartName,
3762
+ slideRoot,
3763
+ newPart
3764
+ };
3765
+ }
3766
+ /**
3767
+ * Bake the source `slideLayout`/`slideMaster` shape-tree decorations onto the imported slide
3768
+ * (the `carryMasterGraphics` path). Every shape on those trees *except* placeholders is
3769
+ * deep-copied into the slide's `p:spTree` ahead of its own content — master decorations
3770
+ * first, then layout, then the slide's shapes — so document (z-)order keeps the master
3771
+ * furthest back. Each decoration's media and other relationship targets are copied into this
3772
+ * package and its `r:embed`/`r:id`/… references rewritten to fresh slide-local ids. The
3773
+ * injected shapes are left for the caller's {@link flattenSlide} pass to resolve any theme
3774
+ * references they carry.
3775
+ * @param {Presentation} dest - the destination deck
3776
+ * @param {ImportContext} ctx - the open import out of the source package
3777
+ * @param {Element} slideRoot - root element of the new slide part (mutated in place)
3778
+ * @param {string} newPartName - partname of the new slide part
3779
+ * @param {string} slidePartName - partname of the source slide, for resolving its layout/master
3780
+ */
3781
+ function carryMasterGraphics(dest, ctx, slideRoot, newPartName, slidePartName) {
3782
+ const sourceOpc = ctx.source;
3783
+ const layoutPartName = resolveSingleRel(sourceOpc, slidePartName, SLIDE_LAYOUT_REL);
3784
+ const masterPartName = layoutPartName ? resolveSingleRel(sourceOpc, layoutPartName, SLIDE_MASTER_REL) : null;
3785
+ const cSld = firstChild(slideRoot, "p:cSld");
3786
+ const spTree = cSld && firstChild(cSld, "p:spTree");
3787
+ if (!spTree) return;
3788
+ const doc = ownerDocumentOf(slideRoot);
3789
+ const slideRels = dest.opc.relationshipsFor(newPartName);
3790
+ const relIdMap = /* @__PURE__ */ new Map();
3791
+ const anchor = firstShapeChild(spTree);
3792
+ for (const partName of [masterPartName, layoutPartName]) {
3793
+ if (!partName) continue;
3794
+ const decorations = carriedDecorations(sourceOpc.part(partName)?.dom.documentElement ?? null);
3795
+ if (decorations.length === 0) continue;
3796
+ const sourceRels = sourceOpc.relationshipsFor(partName);
3797
+ for (const deco of decorations) {
3798
+ const imported = doc.importNode(deco, true);
3799
+ rewriteCarriedRels(imported, ctx, sourceRels, newPartName, slideRels, relIdMap);
3800
+ spTree.insertBefore(imported, anchor);
3801
+ }
3802
+ }
3803
+ }
3804
+ /**
3805
+ * The partname of the layout this deck's slides should attach to in `preserve` mode: the
3806
+ * first layout of the first slide master. Throws when the deck has no master/layout to attach
3807
+ * to (a deck ts-pptx always provides).
3808
+ * @param {Presentation} dest - the destination deck
3809
+ * @return {string} partname of the destination layout
3810
+ */
3811
+ function destinationLayoutPartName(dest) {
3812
+ const presRels = dest.opc.relationshipsFor(dest.presentationPart.partName);
3813
+ const masterRel = presRels.byType(SLIDE_MASTER_REL)[0];
3814
+ if (!masterRel) throw new InvalidOptionError("import/destination-missing-master", "importSlide preserve mode requires a slide master in the destination deck");
3815
+ const masterPartName = presRels.resolveTarget(masterRel.id);
3816
+ const masterRels = dest.opc.relationshipsFor(masterPartName);
3817
+ const layoutRel = masterRels.byType(SLIDE_LAYOUT_REL)[0];
3818
+ if (!layoutRel) throw new InvalidOptionError("import/destination-missing-layout", "importSlide preserve mode requires a slide layout in the destination deck");
3819
+ return masterRels.resolveTarget(layoutRel.id);
3820
+ }
3821
+ //#endregion
3050
3822
  //#region src/read/api/ops/notes-master.ts
3051
3823
  /**
3052
3824
  * Carrying speaker notes and the deck's single notes master across an import or an append.
@@ -3058,10 +3830,6 @@ function mergeEmbeddedFontEntries(dest, entries) {
3058
3830
  * `Presentation`-to-`Presentation` path and the generator-XML path funnel through
3059
3831
  * `registerNotesMaster`: they differ only in how the *part* comes into being.
3060
3832
  */
3061
- const SLIDE_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
3062
- const NOTES_SLIDE_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
3063
- const NOTES_MASTER_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster";
3064
- const THEME_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
3065
3833
  const NOTES_MASTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml";
3066
3834
  const THEME_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.theme+xml";
3067
3835
  const textEncoder$1 = new TextEncoder();
@@ -3084,24 +3852,24 @@ const textEncoder$1 = new TextEncoder();
3084
3852
  */
3085
3853
  function carryNotes(dest, source, ctx, sourceSlidePartName, newSlidePartName) {
3086
3854
  const sourceSlideRels = source.opc.relationshipsFor(sourceSlidePartName);
3087
- const notesRel = sourceSlideRels.byType(NOTES_SLIDE_REL$1)[0];
3855
+ const notesRel = sourceSlideRels.byType(NOTES_SLIDE_REL)[0];
3088
3856
  if (!notesRel) return;
3089
3857
  const sourceNotesPartName = sourceSlideRels.resolveTarget(notesRel.id);
3090
3858
  const sourceNotesPart = source.opc.part(sourceNotesPartName);
3091
3859
  if (!sourceNotesPart) return;
3092
3860
  const newNotesPartName = dest.opc.reservePartNameLike(sourceNotesPartName);
3093
3861
  dest.opc.addPart(newNotesPartName, sourceNotesPart.contentType, sourceNotesPart.bytes);
3094
- dest.opc.relationshipsFor(newSlidePartName).add(NOTES_SLIDE_REL$1, relativePartName(newSlidePartName, newNotesPartName));
3862
+ dest.opc.relationshipsFor(newSlidePartName).add(NOTES_SLIDE_REL, relativePartName(newSlidePartName, newNotesPartName));
3095
3863
  const notesSourceRels = source.opc.relationshipsFor(sourceNotesPartName);
3096
3864
  const notesTargetRels = dest.opc.relationshipsFor(newNotesPartName);
3097
3865
  for (const rel of notesSourceRels) {
3098
- if (rel.type === SLIDE_REL$1) {
3099
- notesTargetRels.addWithId(rel.id, SLIDE_REL$1, relativePartName(newNotesPartName, newSlidePartName));
3866
+ if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide") {
3867
+ notesTargetRels.addWithId(rel.id, SLIDE_REL, relativePartName(newNotesPartName, newSlidePartName));
3100
3868
  continue;
3101
3869
  }
3102
- if (rel.type === NOTES_MASTER_REL$1) {
3870
+ if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster") {
3103
3871
  const notesMaster = ensureNotesMaster(dest, ctx, notesSourceRels.resolveTarget(rel.id));
3104
- notesTargetRels.addWithId(rel.id, NOTES_MASTER_REL$1, relativePartName(newNotesPartName, notesMaster));
3872
+ notesTargetRels.addWithId(rel.id, NOTES_MASTER_REL, relativePartName(newNotesPartName, notesMaster));
3105
3873
  continue;
3106
3874
  }
3107
3875
  if (rel.targetMode === "External") {
@@ -3123,7 +3891,7 @@ function carryNotes(dest, source, ctx, sourceSlidePartName, newSlidePartName) {
3123
3891
  function ensureNotesMaster(dest, ctx, sourceNotesMasterPartName) {
3124
3892
  const presPart = dest.presentationPart;
3125
3893
  const presRels = dest.opc.relationshipsFor(presPart.partName);
3126
- const existing = presRels.byType(NOTES_MASTER_REL$1)[0];
3894
+ const existing = presRels.byType(NOTES_MASTER_REL)[0];
3127
3895
  if (existing) return presRels.resolveTarget(existing.id);
3128
3896
  return registerNotesMaster(dest, copyPart(ctx, sourceNotesMasterPartName));
3129
3897
  }
@@ -3139,7 +3907,7 @@ function ensureNotesMaster(dest, ctx, sourceNotesMasterPartName) {
3139
3907
  */
3140
3908
  function registerNotesMaster(dest, notesMasterPartName) {
3141
3909
  const presPart = dest.presentationPart;
3142
- const relId = dest.opc.relationshipsFor(presPart.partName).add(NOTES_MASTER_REL$1, relativePartName(presPart.partName, notesMasterPartName)).id;
3910
+ const relId = dest.opc.relationshipsFor(presPart.partName).add(NOTES_MASTER_REL, relativePartName(presPart.partName, notesMasterPartName)).id;
3143
3911
  const root = presPart.dom.documentElement;
3144
3912
  if (!root) throw new PackageReadError("package/part-has-no-root", "presentation.xml has no document element to register a notes master in");
3145
3913
  const lst = getOrAddChild(root, "p:notesMasterIdLst", [
@@ -3173,7 +3941,7 @@ function registerNotesMaster(dest, notesMasterPartName) {
3173
3941
  function ensureNotesMasterFromXml(dest, master) {
3174
3942
  const presPart = dest.presentationPart;
3175
3943
  const presRels = dest.opc.relationshipsFor(presPart.partName);
3176
- const existing = presRels.byType(NOTES_MASTER_REL$1)[0];
3944
+ const existing = presRels.byType(NOTES_MASTER_REL)[0];
3177
3945
  if (existing) return presRels.resolveTarget(existing.id);
3178
3946
  const masterPartName = dest.opc.reservePartNameLike("/ppt/notesMasters/notesMaster1.xml");
3179
3947
  dest.opc.addPart(masterPartName, NOTES_MASTER_CONTENT_TYPE, textEncoder$1.encode(master.xml));
@@ -3183,48 +3951,6 @@ function ensureNotesMasterFromXml(dest, master) {
3183
3951
  return registerNotesMaster(dest, masterPartName);
3184
3952
  }
3185
3953
  //#endregion
3186
- //#region src/read/api/ops/part-index.ts
3187
- /**
3188
- * Walking a deck's master/layout spine by partname.
3189
- *
3190
- * The `p:sldMasterIdLst` / `p:sldLayoutIdLst` entries hold relationship ids, not partnames, so
3191
- * every traversal has to resolve through the owning part's relationships. These are the
3192
- * source-side reads that do it — used against a *foreign* presentation as often as against this
3193
- * one, which is why they take the deck rather than living on it.
3194
- */
3195
- /** Master partnames in `p:sldMasterIdLst` order. */
3196
- function slideMasterPartNames(pres) {
3197
- const root = pres.presentationPart.dom.documentElement;
3198
- const lst = root && firstChild(root, "p:sldMasterIdLst");
3199
- if (!lst) return [];
3200
- const rels = pres.opc.relationshipsFor(pres.presentationPart.partName);
3201
- const out = [];
3202
- for (const entry of getElements(lst, "p:sldMasterId")) {
3203
- const relId = attr(entry, "r:id");
3204
- if (relId) out.push(rels.resolveTarget(relId));
3205
- }
3206
- return out;
3207
- }
3208
- /** A master's layout partnames in `p:sldLayoutIdLst` order. */
3209
- function layoutPartNamesOf(pres, masterPartName) {
3210
- const root = pres.opc.part(masterPartName)?.dom.documentElement;
3211
- const lst = root && firstChild(root, "p:sldLayoutIdLst");
3212
- if (!lst) return [];
3213
- const rels = pres.opc.relationshipsFor(masterPartName);
3214
- const out = [];
3215
- for (const entry of getElements(lst, "p:sldLayoutId")) {
3216
- const relId = attr(entry, "r:id");
3217
- if (relId) out.push(rels.resolveTarget(relId));
3218
- }
3219
- return out;
3220
- }
3221
- /** Resolve the single relationship of `type` owned by `partName`, or `null`. */
3222
- function resolveSingleRel(opc, partName, type) {
3223
- const rels = opc.relationshipsFor(partName);
3224
- const rel = rels.byType(type)[0];
3225
- return rel ? rels.resolveTarget(rel.id) : null;
3226
- }
3227
- //#endregion
3228
3954
  //#region src/read/api/ops/prune.ts
3229
3955
  /**
3230
3956
  * Orphan pruning after a part stops being referenced.
@@ -3290,8 +4016,6 @@ function isReferenced(pres, partName) {
3290
4016
  * scales it again on top of the first. It is owned by the calling `Presentation` and threaded
3291
4017
  * through here, so it lives as long as the deck does rather than as long as one call.
3292
4018
  */
3293
- const SLIDE_LAYOUT_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
3294
- const SLIDE_MASTER_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
3295
4019
  /**
3296
4020
  * Rescale an imported slide's geometry onto this deck's canvas (the `rescale`
3297
4021
  * option of {@link Presentation.importSlide}). Rewrites every top-level shape/group/
@@ -3306,8 +4030,8 @@ function rescaleImportedGeometry(dest, rescaledParts, slidePartName, theme, sour
3306
4030
  const transform = computeRescale(source, target, mode);
3307
4031
  rescalePartGeometry(dest, rescaledParts, slidePartName, transform);
3308
4032
  if (theme === void 0 || theme === "copy") {
3309
- const layout = resolveSingleRel(dest.opc, slidePartName, SLIDE_LAYOUT_REL$1);
3310
- const master = layout ? resolveSingleRel(dest.opc, layout, SLIDE_MASTER_REL$1) : null;
4033
+ const layout = resolveSingleRel(dest.opc, slidePartName, SLIDE_LAYOUT_REL);
4034
+ const master = layout ? resolveSingleRel(dest.opc, layout, SLIDE_MASTER_REL) : null;
3311
4035
  if (layout) rescalePartGeometry(dest, rescaledParts, layout, transform);
3312
4036
  if (master) rescalePartGeometry(dest, rescaledParts, master, transform);
3313
4037
  }
@@ -3334,14 +4058,14 @@ function rescalePartGeometry(dest, rescaledParts, partName, transform) {
3334
4058
  * Read-model entry point: `Presentation` wraps an `OpcPackage` and exposes a
3335
4059
  * navigable, typed view of the deck (slides → shapes → text), backed by the
3336
4060
  * live DOM so the same nodes can later be mutated.
4061
+ *
4062
+ * The class holds the model and the deck-level plumbing every operation needs — the part
4063
+ * index, the slide list, the copy registry that lets repeated imports from one source share
4064
+ * what they already copied, and the `p:sldIdLst` wiring. The operations themselves live in
4065
+ * `ops/`, one job per module, taking this deck as an argument. The slide-import machinery
4066
+ * used to sit here as ~280 lines of private methods and made that split hard to see: the
4067
+ * read model's own surface was outnumbered by one feature's internals.
3337
4068
  */
3338
- const OFFICE_DOCUMENT_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
3339
- const SLIDE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
3340
- const SLIDE_LAYOUT_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
3341
- const SLIDE_MASTER_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
3342
- const NOTES_SLIDE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
3343
- const NOTES_MASTER_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster";
3344
- const IMAGE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
3345
4069
  const HYPERLINK_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
3346
4070
  const CHART_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
3347
4071
  const PACKAGE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
@@ -3375,8 +4099,6 @@ const PRESENTATION_SLD_ID_LST_SUCCESSORS = [
3375
4099
  "p:modifyVerifier",
3376
4100
  "p:extLst"
3377
4101
  ];
3378
- /** ST_SlideId minimum (ECMA-376): slide ids live in [256, 2147483647]. */
3379
- const MIN_SLIDE_ID = 256;
3380
4102
  var Presentation = class Presentation {
3381
4103
  opc;
3382
4104
  #presentationPart;
@@ -3674,13 +4396,14 @@ var Presentation = class Presentation {
3674
4396
  throw new InvalidOptionError("import/slide-size-mismatch", `importSlide requires equal slide sizes (pass { rescale: 'fit' | 'stretch' } to rescale); target is ${fmt(target)}, source is ${fmt(incoming)}`);
3675
4397
  }
3676
4398
  if (sizesDiffer && options.rescale && (!target || !incoming)) throw new InvalidOptionError("import/slide-size-unknown", "importSlide rescale requires both decks to declare a slide size (p:sldSz)");
3677
- const newPartName = options.theme === "preserve" ? this.#importSlidePreserve(source, sourceSlide, options.carryMasterGraphics === true) : options.theme === "restyle" ? this.#importSlideRestyle(source, sourceSlide, options.carryMasterGraphics === true, options.remapLiterals === true) : copyPart(this.#importContext(source.opc), sourceSlide.partName);
4399
+ const importCtx = this.#importContext(source.opc);
4400
+ const newPartName = options.theme === "preserve" ? importSlidePreserve(this, importCtx, source, sourceSlide, options.carryMasterGraphics === true) : options.theme === "restyle" ? importSlideRestyle(this, importCtx, source, sourceSlide, options.carryMasterGraphics === true, options.remapLiterals === true) : copyPart(importCtx, sourceSlide.partName);
3678
4401
  const newPart = this.opc.part(newPartName);
3679
4402
  if (!newPart) throw new InternalError("import/part-went-missing", `Imported slide part went missing: ${newPartName}`);
3680
4403
  if (sizesDiffer && options.rescale && target && incoming) rescaleImportedGeometry(this, this.#rescaledParts, newPartName, options.theme, incoming, target, options.rescale === true ? "fit" : options.rescale);
3681
4404
  const slide = this.#insertSlidePart(newPart, options.at);
3682
- if (options.importNotes) carryNotes(this, source, this.#importContext(source.opc), sourceSlide.partName, newPartName);
3683
- if (options.embedFonts) carryEmbeddedFonts(this, source, this.#importContext(source.opc));
4405
+ if (options.importNotes) carryNotes(this, source, importCtx, sourceSlide.partName, newPartName);
4406
+ if (options.embedFonts) carryEmbeddedFonts(this, source, importCtx);
3684
4407
  return slide;
3685
4408
  }
3686
4409
  /**
@@ -3971,14 +4694,14 @@ var Presentation = class Presentation {
3971
4694
  const sourceRels = sourceOpc.relationshipsFor(source.partName);
3972
4695
  const targetRels = this.opc.relationshipsFor(target.partName);
3973
4696
  const relIdMap = /* @__PURE__ */ new Map();
3974
- const ctx = theme === "preserve" ? this.#sourceFlattenContext(sourceOpc, source.partName) : null;
4697
+ const ctx = theme === "preserve" ? sourceFlattenContext(sourceOpc, source.partName) : null;
3975
4698
  const importCtx = this.#importContext(sourceOpc);
3976
4699
  const extLst = firstChild(spTree, "p:extLst");
3977
4700
  const anchor = options.at == null ? extLst : nthShapeChild(spTree, options.at) ?? extLst;
3978
4701
  const result = [];
3979
4702
  for (const shapeEl of sourceElements) {
3980
4703
  const imported = targetDoc.importNode(shapeEl, true);
3981
- this.#rewriteCarriedRels(imported, importCtx, sourceRels, target.partName, targetRels, relIdMap);
4704
+ rewriteCarriedRels(imported, importCtx, sourceRels, target.partName, targetRels, relIdMap);
3982
4705
  if (ctx) {
3983
4706
  const holder = createElement(targetDoc, "p:spTree");
3984
4707
  holder.appendChild(imported);
@@ -4014,215 +4737,6 @@ var Presentation = class Presentation {
4014
4737
  return result;
4015
4738
  }
4016
4739
  /**
4017
- * Import a slide in `preserve` mode: rebind it to this deck's master/layout
4018
- * (see {@link #importSlideRebind}), then flatten its source theme into the slide
4019
- * XML (scheme colours + style-matrix fills baked to literals). Returns the new
4020
- * partname.
4021
- *
4022
- * The flatten context is gathered from the *source* subgraph, so it can be read
4023
- * before or after the rebind; the rebind injects any carried decorations before
4024
- * we flatten, so a single sweep resolves the theme references on the slide's own
4025
- * content and on the carried decorations together.
4026
- */
4027
- #importSlidePreserve(source, sourceSlide, carryGraphics) {
4028
- const ctx = this.#sourceFlattenContext(source.opc, sourceSlide.partName);
4029
- const { newPartName, slideRoot, newPart } = this.#importSlideRebind(source, sourceSlide, carryGraphics);
4030
- flattenSlide(slideRoot, ctx);
4031
- newPart.markDirty();
4032
- return newPartName;
4033
- }
4034
- /**
4035
- * Import a slide in `restyle` mode: rebind it to this deck's master/layout (see
4036
- * {@link #importSlideRebind}) and then {@link restyleSlide} it — drop its colour
4037
- * map override but bake *nothing*, so its symbolic theme references re-resolve
4038
- * against the destination theme and the slide re-brands. Returns the new
4039
- * partname.
4040
- *
4041
- * The deliberate inverse of `preserve`: no flatten, no inherited-background
4042
- * bake, no placeholder colour/size/geometry bake — every one of those would pin
4043
- * the slide to its source look, the opposite of re-branding. Carried
4044
- * decorations are left symbolic too, so they re-brand along with the slide.
4045
- *
4046
- * With `remapLiterals` it additionally force-remaps the slide's source-theme
4047
- * literal colours back to symbolic scheme colours and copies any referenced
4048
- * source table style into this deck — the two things plain `restyle` cannot
4049
- * re-brand (see {@link ImportSlideOptions.remapLiterals}).
4050
- */
4051
- #importSlideRestyle(source, sourceSlide, carryGraphics, remapLiterals) {
4052
- const { newPartName, slideRoot, newPart } = this.#importSlideRebind(source, sourceSlide, carryGraphics);
4053
- restyleSlide(slideRoot);
4054
- if (remapLiterals) {
4055
- const parts = resolveSlideThemeParts(source.opc, sourceSlide.partName);
4056
- remapLiteralColors(slideRoot, {
4057
- clrMap: parts.clrMap,
4058
- clrScheme: parts.clrScheme
4059
- });
4060
- copySourceTableStyles(this, source.opc, slideRoot);
4061
- }
4062
- newPart.markDirty();
4063
- return newPartName;
4064
- }
4065
- /**
4066
- * The rebind shared by `preserve` and `restyle`: copy the slide bytes into a
4067
- * fresh part, rebuild its relationships (drop notes, repoint the `slideLayout`
4068
- * rel at this deck's existing layout, copy every other internal target —
4069
- * media/charts — and pass externals through), and optionally bake the source
4070
- * master/layout decorations onto the slide. Returns the new part, its name, and
4071
- * its live root element for the caller's mode-specific pass (flatten vs restyle).
4072
- *
4073
- * This carries *no* theme baking of its own — not even the inherited background.
4074
- * `preserve` adds that via {@link flattenSlide}'s context; `restyle` must not,
4075
- * so the background stays symbolic and re-brands.
4076
- */
4077
- #importSlideRebind(source, sourceSlide, carryGraphics) {
4078
- const destLayout = this.#destinationLayoutPartName();
4079
- const sourcePart = source.opc.part(sourceSlide.partName);
4080
- if (!sourcePart) throw new PackageReadError("package/part-missing", `importSlide: source package has no part ${sourceSlide.partName}`);
4081
- const newPartName = this.opc.reservePartNameLike(sourceSlide.partName);
4082
- const newPart = this.opc.addPart(newPartName, sourcePart.contentType, sourcePart.bytes);
4083
- const slideRoot = newPart.dom.documentElement;
4084
- if (!slideRoot) throw new PackageReadError("package/part-has-no-root", `Imported slide ${newPartName} has no root element`);
4085
- const ctx = this.#importContext(source.opc);
4086
- const sourceRels = source.opc.relationshipsFor(sourceSlide.partName);
4087
- const targetRels = this.opc.relationshipsFor(newPartName);
4088
- for (const rel of sourceRels) {
4089
- if (rel.type === NOTES_SLIDE_REL) continue;
4090
- if (rel.type === SLIDE_LAYOUT_REL) {
4091
- targetRels.addWithId(rel.id, SLIDE_LAYOUT_REL, relativePartName(newPartName, destLayout));
4092
- continue;
4093
- }
4094
- if (rel.targetMode === "External") {
4095
- targetRels.addWithId(rel.id, rel.type, rel.target, "External");
4096
- continue;
4097
- }
4098
- const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id));
4099
- targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTarget));
4100
- }
4101
- if (carryGraphics) this.#carryMasterGraphics(ctx, slideRoot, newPartName, sourceSlide.partName);
4102
- return {
4103
- newPartName,
4104
- slideRoot,
4105
- newPart
4106
- };
4107
- }
4108
- /**
4109
- * Bake the source `slideLayout`/`slideMaster` shape-tree decorations onto the
4110
- * imported slide (the `carryMasterGraphics` path). Every shape on those trees
4111
- * *except* placeholders is deep-copied into the slide's `p:spTree` ahead of its
4112
- * own content — master decorations first, then layout, then the slide's shapes —
4113
- * so document (z-)order keeps the master furthest back. Each decoration's media
4114
- * and other relationship targets are copied into this package and its
4115
- * `r:embed`/`r:id`/… references rewritten to fresh slide-local ids. The injected
4116
- * shapes are left for the caller's {@link flattenSlide} pass to resolve any
4117
- * theme references they carry.
4118
- */
4119
- #carryMasterGraphics(ctx, slideRoot, newPartName, slidePartName) {
4120
- const sourceOpc = ctx.source;
4121
- const layoutPartName = resolveSingleRel(sourceOpc, slidePartName, SLIDE_LAYOUT_REL);
4122
- const masterPartName = layoutPartName ? resolveSingleRel(sourceOpc, layoutPartName, SLIDE_MASTER_REL) : null;
4123
- const cSld = firstChild(slideRoot, "p:cSld");
4124
- const spTree = cSld && firstChild(cSld, "p:spTree");
4125
- if (!spTree) return;
4126
- const doc = ownerDocumentOf(slideRoot);
4127
- const slideRels = this.opc.relationshipsFor(newPartName);
4128
- const relIdMap = /* @__PURE__ */ new Map();
4129
- const anchor = firstShapeChild(spTree);
4130
- for (const partName of [masterPartName, layoutPartName]) {
4131
- if (!partName) continue;
4132
- const decorations = carriedDecorations(sourceOpc.part(partName)?.dom.documentElement ?? null);
4133
- if (decorations.length === 0) continue;
4134
- const sourceRels = sourceOpc.relationshipsFor(partName);
4135
- for (const deco of decorations) {
4136
- const imported = doc.importNode(deco, true);
4137
- this.#rewriteCarriedRels(imported, ctx, sourceRels, newPartName, slideRels, relIdMap);
4138
- spTree.insertBefore(imported, anchor);
4139
- }
4140
- }
4141
- }
4142
- /**
4143
- * Rewrite every relationship reference (`r:embed`, `r:id`, `r:link`, …) inside a
4144
- * carried decoration so it points at a fresh slide-local relationship, copying
4145
- * the referenced part into this package on first sight. `relIdMap` (keyed by
4146
- * source part + source rel id) dedupes references shared within one import call.
4147
- */
4148
- #rewriteCarriedRels(node, ctx, sourceRels, newPartName, slideRels, relIdMap) {
4149
- const elements = [];
4150
- collectElements(node, elements);
4151
- for (const el of elements) {
4152
- const refs = [];
4153
- const attrs = el.attributes;
4154
- for (let i = 0; i < attrs.length; i++) {
4155
- const a = attrs.item(i);
4156
- if (!a || a.namespaceURI !== OOXML_NS.r || !a.value) continue;
4157
- if (!sourceRels.get(a.value)) continue;
4158
- refs.push({
4159
- local: a.localName ?? a.name,
4160
- id: a.value
4161
- });
4162
- }
4163
- for (const { local, id } of refs) setAttr(el, `r:${local}`, this.#carryRel(ctx, sourceRels, id, newPartName, slideRels, relIdMap));
4164
- }
4165
- }
4166
- /** Resolve a carried decoration's source relationship to a fresh slide-local id, copying its internal target. */
4167
- #carryRel(ctx, sourceRels, id, newPartName, slideRels, relIdMap) {
4168
- const key = `${sourceRels.sourcePartName}|${id}`;
4169
- const cached = relIdMap.get(key);
4170
- if (cached) return cached;
4171
- const rel = sourceRels.get(id);
4172
- if (!rel) throw new InvalidOptionError("relationship/not-found", `Relationships of ${sourceRels.sourcePartName}: no relationship with id ${id}`);
4173
- const newId = rel.targetMode === "External" ? slideRels.add(rel.type, rel.target, "External").id : slideRels.add(rel.type, relativePartName(newPartName, copyPart(ctx, sourceRels.resolveTarget(id)))).id;
4174
- relIdMap.set(key, newId);
4175
- return newId;
4176
- }
4177
- /**
4178
- * The partname of the layout this deck's slides should attach to in `preserve`
4179
- * mode: the first layout of the first slide master. Throws when the deck has no
4180
- * master/layout to attach to (a deck ts-pptx always provides).
4181
- */
4182
- #destinationLayoutPartName() {
4183
- const presRels = this.opc.relationshipsFor(this.presentationPart.partName);
4184
- const masterRel = presRels.byType(SLIDE_MASTER_REL)[0];
4185
- if (!masterRel) throw new InvalidOptionError("import/destination-missing-master", "importSlide preserve mode requires a slide master in the destination deck");
4186
- const masterPartName = presRels.resolveTarget(masterRel.id);
4187
- const masterRels = this.opc.relationshipsFor(masterPartName);
4188
- const layoutRel = masterRels.byType(SLIDE_LAYOUT_REL)[0];
4189
- if (!layoutRel) throw new InvalidOptionError("import/destination-missing-layout", "importSlide preserve mode requires a slide layout in the destination deck");
4190
- return masterRels.resolveTarget(layoutRel.id);
4191
- }
4192
- /**
4193
- * Gather the flatten context for a source slide: walk slide → layout → master →
4194
- * theme, reading the effective colour map (the slide's `clrMapOvr` override, or
4195
- * the master `clrMap`), the theme `clrScheme`, and the theme `fmtScheme`.
4196
- */
4197
- #sourceFlattenContext(sourceOpc, slidePartName) {
4198
- const parts = resolveSlideThemeParts(sourceOpc, slidePartName);
4199
- const themeElements = parts.themeElements;
4200
- return {
4201
- clrMap: parts.clrMap,
4202
- clrScheme: parts.clrScheme,
4203
- fmtScheme: themeElements ? firstChild(themeElements, "a:fmtScheme") : null,
4204
- inheritedBackground: this.#effectiveBackground(sourceOpc, parts.slideRoot, parts.layoutPartName, parts.masterPartName),
4205
- layoutRoot: parts.layoutRoot,
4206
- masterRoot: parts.masterRoot
4207
- };
4208
- }
4209
- /**
4210
- * The background the slide effectively inherits from its source subgraph: the
4211
- * layout's `p:bg`, else the master's. Returns `null` when the slide carries its
4212
- * own `p:bg` (it stays on the slide and is flattened directly) or none exists.
4213
- */
4214
- #effectiveBackground(sourceOpc, slideRoot, layoutPartName, masterPartName) {
4215
- if (slideRoot && this.#backgroundOf(slideRoot)) return null;
4216
- const layoutRoot = layoutPartName ? sourceOpc.part(layoutPartName)?.dom.documentElement ?? null : null;
4217
- const masterRoot = masterPartName ? sourceOpc.part(masterPartName)?.dom.documentElement ?? null : null;
4218
- return (layoutRoot && this.#backgroundOf(layoutRoot)) ?? (masterRoot && this.#backgroundOf(masterRoot)) ?? null;
4219
- }
4220
- /** The `p:cSld/p:bg` element of a slide/layout/master root, or `null`. */
4221
- #backgroundOf(root) {
4222
- const cSld = firstChild(root, "p:cSld");
4223
- return cSld ? firstChild(cSld, "p:bg") : null;
4224
- }
4225
- /**
4226
4740
  * Open an import out of `source`: this deck as the destination, paired with the
4227
4741
  * copy registry for that package (created on first use). The registry is held on
4228
4742
  * the class rather than in the context because it must outlive any one call —
@@ -4268,7 +4782,7 @@ var Presentation = class Presentation {
4268
4782
  }
4269
4783
  /** A slide id one past the highest existing, but at least ST_SlideId's minimum. */
4270
4784
  #nextSlideId(sldIds) {
4271
- let max = MIN_SLIDE_ID - 1;
4785
+ let max = 255;
4272
4786
  for (const sldId of sldIds) {
4273
4787
  const id = intValue(attr(sldId, "id"));
4274
4788
  if (id !== null && id > max) max = id;
@@ -4283,4 +4797,4 @@ var Presentation = class Presentation {
4283
4797
  //#endregion
4284
4798
  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 };
4285
4799
 
4286
- //# sourceMappingURL=presentation-B0JWdTN1.js.map
4800
+ //# sourceMappingURL=presentation-DAcOfzsP.js.map