@shbernal/ts-pptx 2.0.0 → 3.1.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 (85) hide show
  1. package/README.md +31 -2
  2. package/dist/{autopage-tmfjRzL4.js → autopage-QQyfRtoK.js} +4 -5
  3. package/dist/{autopage-tmfjRzL4.js.map → autopage-QQyfRtoK.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 +14 -6
  7. package/dist/browser.js.map +1 -1
  8. package/dist/{diagnostics-CQ0JWc9m.d.ts → diagnostics-PMINsVP6.d.ts} +97 -8
  9. package/dist/diagnostics-PMINsVP6.d.ts.map +1 -0
  10. package/dist/{enums-D3aF4QGb.d.ts → enums-CoXnxiCI.d.ts} +6 -5
  11. package/dist/{enums-D3aF4QGb.d.ts.map → enums-CoXnxiCI.d.ts.map} +1 -1
  12. package/dist/{errors-B22h8Qd0.d.ts → errors-BeUEkNWL.d.ts} +26 -4
  13. package/dist/errors-BeUEkNWL.d.ts.map +1 -0
  14. package/dist/{errors-DGE9zh3U.js → errors-Bvln0H-7.js} +21 -2
  15. package/dist/errors-Bvln0H-7.js.map +1 -0
  16. package/dist/{fit-BSWY0AYt.js → fit-DhMbQG5O.js} +0 -0
  17. package/dist/fit-DhMbQG5O.js.map +1 -0
  18. package/dist/{html-dom-BQLUntho.js → html-dom-DajBuobe.js} +20 -6
  19. package/dist/html-dom-DajBuobe.js.map +1 -0
  20. package/dist/html.d.ts +3 -3
  21. package/dist/html.d.ts.map +1 -1
  22. package/dist/html.js +7 -4
  23. package/dist/html.js.map +1 -1
  24. package/dist/index.d.ts +6 -6
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +6 -6
  27. package/dist/index.js.map +1 -1
  28. package/dist/inspect.d.ts +1 -1
  29. package/dist/inspect.js +4 -4
  30. package/dist/inspect.js.map +1 -1
  31. package/dist/math.d.ts +1 -1
  32. package/dist/math.d.ts.map +1 -1
  33. package/dist/math.js +98 -2
  34. package/dist/math.js.map +1 -1
  35. package/dist/measure.d.ts +3 -3
  36. package/dist/measure.js +2 -2
  37. package/dist/node.d.ts +14 -6
  38. package/dist/node.d.ts.map +1 -1
  39. package/dist/node.js +13 -5
  40. package/dist/node.js.map +1 -1
  41. package/dist/package-CaOLXSNi.d.ts.map +1 -1
  42. package/dist/{pres-GU-jjBEx.d.ts → pres-BgvxhQ_m.d.ts} +3 -3
  43. package/dist/{pres-GU-jjBEx.d.ts.map → pres-BgvxhQ_m.d.ts.map} +1 -1
  44. package/dist/{presentation-MJe9WDi4.js → presentation-BP1B8PCF.js} +863 -343
  45. package/dist/presentation-BP1B8PCF.js.map +1 -0
  46. package/dist/{presentation-CVaTZw1V.d.ts → presentation-DyIRDKkp.d.ts} +742 -595
  47. package/dist/presentation-DyIRDKkp.d.ts.map +1 -0
  48. package/dist/{presentation-types-BVw0EknS.d.ts → presentation-types-Dj4riuDs.d.ts} +2 -2
  49. package/dist/{presentation-types-BVw0EknS.d.ts.map → presentation-types-Dj4riuDs.d.ts.map} +1 -1
  50. package/dist/read.d.ts +5 -5
  51. package/dist/read.d.ts.map +1 -1
  52. package/dist/read.js +3 -3
  53. package/dist/script.d.ts +2 -2
  54. package/dist/script.d.ts.map +1 -1
  55. package/dist/script.js +0 -0
  56. package/dist/script.js.map +1 -1
  57. package/dist/{shapes-CaOgR0i1.js → shapes-DMThLsZN.js} +689 -1032
  58. package/dist/shapes-DMThLsZN.js.map +1 -0
  59. package/dist/{slide-BBlElWr9.d.ts → slide-BRAtT8Dl.d.ts} +197 -22
  60. package/dist/slide-BRAtT8Dl.d.ts.map +1 -0
  61. package/dist/{image-size-C8uYE8GJ.js → st-enums-evQG2A7Z.js} +233 -2
  62. package/dist/st-enums-evQG2A7Z.js.map +1 -0
  63. package/dist/{text-B1ZrPEeK.js → text-B6PbMFih.js} +725 -319
  64. package/dist/text-B6PbMFih.js.map +1 -0
  65. package/dist/{units-B-JUKwCS.js → units-C7QM1KgH.js} +2 -2
  66. package/dist/{units-B-JUKwCS.js.map → units-C7QM1KgH.js.map} +1 -1
  67. package/dist/{units-internal-7JcMfYti.js → units-internal-CR8s8YQa.js} +4 -3
  68. package/dist/units-internal-CR8s8YQa.js.map +1 -0
  69. package/dist/zip.d.ts +2 -2
  70. package/dist/zip.js +1 -1
  71. package/dist/zip.js.map +1 -1
  72. package/package.json +40 -29
  73. package/skills/ts-pptx-upstream/SKILL.md +247 -0
  74. package/dist/diagnostics-CQ0JWc9m.d.ts.map +0 -1
  75. package/dist/errors-B22h8Qd0.d.ts.map +0 -1
  76. package/dist/errors-DGE9zh3U.js.map +0 -1
  77. package/dist/fit-BSWY0AYt.js.map +0 -1
  78. package/dist/html-dom-BQLUntho.js.map +0 -1
  79. package/dist/image-size-C8uYE8GJ.js.map +0 -1
  80. package/dist/presentation-CVaTZw1V.d.ts.map +0 -1
  81. package/dist/presentation-MJe9WDi4.js.map +0 -1
  82. package/dist/shapes-CaOgR0i1.js.map +0 -1
  83. package/dist/slide-BBlElWr9.d.ts.map +0 -1
  84. package/dist/text-B1ZrPEeK.js.map +0 -1
  85. package/dist/units-internal-7JcMfYti.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { n as warn } from "./diagnostics-DYQC7xLV.js";
2
- import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-DGE9zh3U.js";
3
- import { r as getImageSizeFromBytes, t as fitSrcRectPercents } from "./image-size-C8uYE8GJ.js";
2
+ import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-Bvln0H-7.js";
3
+ import { C as getImageSizeFromBytes, _ as SLIDE_LAYOUT_REL, b as THEME_REL, c as TEXT_VERTICAL, d as IMAGE_REL, f as NOTES_MASTER_REL, l as checkEnumOrThrow, m as OFFICE_DOCUMENT_REL, o as TEXT_ANCHORS, s as TEXT_HORZ_OVERFLOW, v as SLIDE_MASTER_REL, x as fitSrcRectPercents } from "./st-enums-evQG2A7Z.js";
4
4
  import { DOMParser, MIME_TYPE, XMLSerializer, onErrorStopParsing } from "@xmldom/xmldom";
5
5
  /** Parse an XML string strictly: any well-formedness error throws. */
6
6
  function parseXml(xml) {
@@ -58,11 +58,25 @@ function getElements(parent, qname) {
58
58
  return out;
59
59
  }
60
60
  /** All direct child elements in document order, regardless of qname. */
61
- function childElements$2(parent) {
61
+ function childElements(parent) {
62
62
  const out = [];
63
63
  for (let node = parent.firstChild; node; node = node.nextSibling) if (node.nodeType === 1) out.push(node);
64
64
  return out;
65
65
  }
66
+ /**
67
+ * All *descendant* elements of `root` matching a namespace + local name, snapshotted into an
68
+ * array. Unlike {@link getElements} (direct children only) this searches the whole subtree, and
69
+ * unlike the live `HTMLCollection` that `getElementsByTagNameNS` returns, the result does not
70
+ * change as the caller mutates the tree — which is what makes it safe to iterate while replacing
71
+ * the very elements being iterated.
72
+ *
73
+ * Note the DOM's own exclusion: `root` itself is never a candidate, only its descendants.
74
+ */
75
+ function descendantsByTag(root, ns, local) {
76
+ const out = [];
77
+ for (const element of root.getElementsByTagNameNS(ns, local)) out.push(element);
78
+ return out;
79
+ }
66
80
  /** First direct child element matching a qname, or `null`. */
67
81
  function firstChild(parent, qname) {
68
82
  const { uri, local } = splitQName(qname);
@@ -216,6 +230,20 @@ function escapeXmlAttribute(value) {
216
230
  * A partname is an absolute, `/`-separated path inside the package, e.g.
217
231
  * `/ppt/slides/slide1.xml`. Zip entry paths omit the leading slash.
218
232
  */
233
+ /**
234
+ * Resolve the single relationship of `type` owned by `partName` to its target partname, or
235
+ * `null` when the part declares none. For the one-of-a-kind links in a deck's spine — a slide to
236
+ * its layout, a layout to its master, a master to its theme — where a second relationship of the
237
+ * same type would itself be malformed.
238
+ *
239
+ * The `OpcPackage` import is type-only, so this does not create a cycle with `package.ts` (which
240
+ * imports this module at run time).
241
+ */
242
+ function resolveSingleRel(opc, partName, type) {
243
+ const rels = opc.relationshipsFor(partName);
244
+ const rel = rels.byType(type)[0];
245
+ return rel ? rels.resolveTarget(rel.id) : null;
246
+ }
219
247
  function zipPathToPartName(zipPath) {
220
248
  return zipPath.startsWith("/") ? zipPath : `/${zipPath}`;
221
249
  }
@@ -272,16 +300,11 @@ function resolveRelativePartName(sourcePartName, target) {
272
300
  return `/${segments.join("/")}`;
273
301
  }
274
302
  //#endregion
275
- //#region src/read/oxml/fill.ts
303
+ //#region src/ooxml/sequence.ts
276
304
  /**
277
- * Shared solid-fill read/mutation helpers for DrawingML colour-bearing parents:
278
- * a run's `a:rPr`, a shape's `p:spPr` / `p:grpSpPr`, and a line's `a:ln`.
279
- *
280
- * A parent carries at most one `EG_FillProperties` choice, so setting a solid
281
- * fill first clears any competing choice, then inserts `a:solidFill` in document
282
- * order. These helpers never mark a part dirty — callers own that.
305
+ * `EG_FillProperties` — the mutually exclusive fill choices, in schema order.
306
+ * @see ECMA-376 Part 1 §20.1.8 (DrawingML fill group)
283
307
  */
284
- /** The mutually-exclusive fill choices (`EG_FillProperties`); a parent has at most one. */
285
308
  const FILL_CHOICES = [
286
309
  "a:noFill",
287
310
  "a:solidFill",
@@ -290,6 +313,143 @@ const FILL_CHOICES = [
290
313
  "a:pattFill",
291
314
  "a:grpFill"
292
315
  ];
316
+ /** `EG_EffectProperties` — the two mutually exclusive effect containers. */
317
+ const EFFECT_CHOICES = ["a:effectLst", "a:effectDag"];
318
+ /** `EG_Geometry` — the two mutually exclusive geometry choices. */
319
+ const GEOMETRY_CHOICES = ["a:custGeom", "a:prstGeom"];
320
+ /**
321
+ * Everything that legally follows `member` in `sequence`, flattened.
322
+ *
323
+ * `member` may name a single element or any member of a choice group; either way the result
324
+ * starts after the step it occupies, so a choice member never lists its own siblings. Throws on
325
+ * an unknown name rather than returning `[]` — an empty successor list silently *appends*, which
326
+ * is exactly the corruption these lists exist to prevent, so a typo must fail loudly and at
327
+ * module-load time rather than produce a subtly out-of-order part at run time.
328
+ */
329
+ function successorsOf(sequence, member) {
330
+ const index = sequence.findIndex((step) => typeof step === "string" ? step === member : step.includes(member));
331
+ if (index < 0) throw new Error(`successorsOf: ${member} is not part of the given sequence`);
332
+ return sequence.slice(index + 1).flat();
333
+ }
334
+ /**
335
+ * `CT_ShapeProperties` (`p:spPr`), in declaration order.
336
+ * @see ECMA-376 Part 1 §20.1.2.2.35
337
+ */
338
+ const SPPR_SEQUENCE = [
339
+ "a:xfrm",
340
+ GEOMETRY_CHOICES,
341
+ FILL_CHOICES,
342
+ "a:ln",
343
+ EFFECT_CHOICES,
344
+ "a:scene3d",
345
+ "a:sp3d",
346
+ "a:extLst"
347
+ ];
348
+ /**
349
+ * `CT_GroupShapeProperties` (`p:grpSpPr`), in declaration order. A group carries no `a:ln` and
350
+ * no `a:sp3d` — which is exactly why it needs its own successor lists rather than borrowing the
351
+ * shape ones.
352
+ * @see ECMA-376 Part 1 §20.1.2.2.19
353
+ */
354
+ const GRPSPPR_SEQUENCE = [
355
+ "a:xfrm",
356
+ FILL_CHOICES,
357
+ EFFECT_CHOICES,
358
+ "a:scene3d",
359
+ "a:extLst"
360
+ ];
361
+ /**
362
+ * `CT_LineProperties` (`a:ln`), in declaration order.
363
+ * @see ECMA-376 Part 1 §20.1.2.2.24
364
+ */
365
+ const LN_SEQUENCE = [
366
+ FILL_CHOICES,
367
+ ["a:prstDash", "a:custDash"],
368
+ [
369
+ "a:round",
370
+ "a:bevel",
371
+ "a:miter"
372
+ ],
373
+ "a:headEnd",
374
+ "a:tailEnd",
375
+ "a:extLst"
376
+ ];
377
+ /**
378
+ * `CT_TextCharacterProperties` (`a:rPr`/`a:defRPr`/`a:endParaRPr`), in declaration order.
379
+ * @see ECMA-376 Part 1 §21.1.2.3.9
380
+ */
381
+ const RPR_SEQUENCE = [
382
+ "a:ln",
383
+ FILL_CHOICES,
384
+ EFFECT_CHOICES,
385
+ "a:highlight",
386
+ ["a:uLnTx", "a:uLn"],
387
+ ["a:uFillTx", "a:uFill"],
388
+ "a:latin",
389
+ "a:ea",
390
+ "a:cs",
391
+ "a:sym",
392
+ "a:hlinkClick",
393
+ "a:hlinkMouseOver",
394
+ "a:rtl",
395
+ "a:extLst"
396
+ ];
397
+ /**
398
+ * `CT_TableCellProperties` (`a:tcPr`), in declaration order.
399
+ * @see ECMA-376 Part 1 §21.1.3.17
400
+ */
401
+ const TCPR_SEQUENCE = [
402
+ "a:lnL",
403
+ "a:lnR",
404
+ "a:lnT",
405
+ "a:lnB",
406
+ "a:lnTlToBr",
407
+ "a:lnBlToTr",
408
+ "a:cell3D",
409
+ ...FILL_CHOICES,
410
+ "a:headers",
411
+ "a:extLst"
412
+ ];
413
+ /**
414
+ * For each `a:tcPr` child, the children that must follow it — i.e. what a new one is inserted
415
+ * *before*. Every child gets an entry, so a caller can look one up by qname.
416
+ */
417
+ const TCPR_AFTER = Object.fromEntries(TCPR_SEQUENCE.map((qname, index) => [qname, TCPR_SEQUENCE.slice(index + 1)]));
418
+ /** Successors of `a:xfrm` inside `p:spPr`. */
419
+ const SPPR_AFTER_XFRM = successorsOf(SPPR_SEQUENCE, "a:xfrm");
420
+ /** Successors of a fill choice inside `p:spPr`. */
421
+ const SPPR_FILL_AFTER = successorsOf(SPPR_SEQUENCE, "a:solidFill");
422
+ /** Successors of `a:ln` inside `p:spPr`. */
423
+ const SPPR_LN_AFTER = successorsOf(SPPR_SEQUENCE, "a:ln");
424
+ /** Successors of an effect container inside `p:spPr`. */
425
+ const SPPR_EFFECT_AFTER = successorsOf(SPPR_SEQUENCE, "a:effectLst");
426
+ /** Successors of `a:scene3d` inside `p:spPr`. */
427
+ const SPPR_SCENE3D_AFTER = successorsOf(SPPR_SEQUENCE, "a:scene3d");
428
+ /** Successors of `a:sp3d` inside `p:spPr`. */
429
+ const SPPR_SP3D_AFTER = successorsOf(SPPR_SEQUENCE, "a:sp3d");
430
+ /** Successors of `a:xfrm` inside `p:grpSpPr`. */
431
+ const GRPSPPR_AFTER_XFRM = successorsOf(GRPSPPR_SEQUENCE, "a:xfrm");
432
+ /** Successors of a fill choice inside `p:grpSpPr`. */
433
+ const GRPSPPR_FILL_AFTER = successorsOf(GRPSPPR_SEQUENCE, "a:solidFill");
434
+ /**
435
+ * Successors of `p:spPr` within `p:sp` (and before `p:style` within `p:pic` / `p:cxnSp`).
436
+ * `p:blipFill` and the `p:nv*Pr` wrapper precede `p:spPr` and so are deliberately absent.
437
+ */
438
+ const SHAPE_AFTER_SPPR = ["p:style", "p:txBody"];
439
+ /** Successors of a fill choice inside `a:ln`. */
440
+ const LN_FILL_AFTER = successorsOf(LN_SEQUENCE, "a:solidFill");
441
+ /** Successors of a fill choice inside `a:rPr` (and `a:defRPr`/`a:endParaRPr`). */
442
+ const RPR_FILL_AFTER = successorsOf(RPR_SEQUENCE, "a:solidFill");
443
+ //#endregion
444
+ //#region src/read/oxml/fill.ts
445
+ /**
446
+ * Shared solid-fill read/mutation helpers for DrawingML colour-bearing parents:
447
+ * a run's `a:rPr`, a shape's `p:spPr` / `p:grpSpPr`, and a line's `a:ln`.
448
+ *
449
+ * A parent carries at most one `EG_FillProperties` choice, so setting a solid
450
+ * fill first clears any competing choice, then inserts `a:solidFill` in document
451
+ * order. These helpers never mark a part dirty — callers own that.
452
+ */
293
453
  /** Normalize a 6-hex RGB string (optional leading `#`) to upper-case, or throw. */
294
454
  function normalizeHex(value) {
295
455
  const hex = value.startsWith("#") ? value.slice(1) : value;
@@ -318,41 +478,27 @@ function setSolidFill(parent, afterOrder, color) {
318
478
  //#endregion
319
479
  //#region src/read/oxml/theme.ts
320
480
  /**
321
- * Theme resolution for the {@link Presentation.importSlide} `theme: 'preserve'`
322
- * mode: bake the values a slide's *source* theme would have produced into the
323
- * slide XML, so the slide no longer depends on which theme it resolves against.
481
+ * Theme colour resolution: turning a DrawingML colour reference or a style-matrix reference into
482
+ * something literal.
324
483
  *
325
- * Two kinds of theme dependency are flattened (see IMPORT_SLIDE_THEME_PRESERVE):
484
+ * Two maps do the colour work. A scheme token (`accent1`, `bg1`, …) routes through the master's
485
+ * `clrMap` to a `clrScheme` slot, whose literal RGB is the answer; child colour transforms
486
+ * (`lumMod`/`shade`/`alpha`/…) are carried through untouched rather than computed, so a caller
487
+ * that re-emits them renders identically. A style-matrix reference (`a:fillRef`/`a:lnRef`) instead
488
+ * indexes the theme's `fmtScheme`, and resolves to a deep-cloned entry with its `phClr`
489
+ * placeholder substituted.
326
490
  *
327
- * 1. **`a:schemeClr` tokens** — a scheme token (`accent1`, `bg1`, …) routes
328
- * through the master's `clrMap` to a `clrScheme` slot, whose literal RGB we
329
- * emit as `a:srgbClr`. Child colour transforms (`lumMod`/`shade`/`alpha`/…)
330
- * are carried through untouched, so tints/shades render identically — we swap
331
- * only the *base* colour reference, never compute the transform math.
332
- * 2. **Style-matrix refs** — a shape's `p:style` (`lnRef`/`fillRef`/`effectRef`)
333
- * indexes the theme's `fmtScheme`; we resolve the indexed entry into an
334
- * explicit `spPr` fill/line/effect (substituting its `phClr` placeholder with
335
- * the ref's own colour) and neutralize the ref so it cannot re-resolve. The
336
- * `fontRef` is left intact so its font (and resolved colour) can re-bind to
337
- * the destination theme — the deliberate "normalize fonts on attach" bonus.
338
- * 3. **Placeholder-inherited run colour** — a run whose `a:rPr` carries no own
339
- * fill takes its colour from the source placeholder → layout → master text
340
- * style chain (`p:txStyles` / placeholder `a:lstStyle`). Rebinding to the
341
- * destination master would replace that chain and flip the colour, so we
342
- * resolve each such run's effective colour from the *source* styles and write
343
- * it explicitly onto the run.
344
- * 4. **Placeholder-inherited geometry & run size** — a placeholder shape with no
345
- * own `a:xfrm` takes its position/size from the matching source layout/master
346
- * placeholder, and a run with no own `sz`/`b`/`i` takes them from the same text
347
- * style chain. Rebinding to the destination master replaces both inheritances,
348
- * so a title clips off-canvas and type comes out at the wrong size. We bake the
349
- * effective `a:xfrm` onto the shape and the effective `sz`/`b`/`i` onto each run.
350
- * Typeface (`a:latin`) is deliberately *not* baked — it re-binds to the
351
- * destination theme along with `fontRef`.
491
+ * Everything here is **pure**: it reads a DOM and builds detached elements, and mutates nothing
492
+ * the caller passes in. Two very different consumers depend on that:
352
493
  *
353
- * All functions operate purely on DOM elements; the caller gathers the source
354
- * `clrMap` / `clrScheme` / `fmtScheme` parts (and the source layout/master roots
355
- * for the placeholder inheritance passes) and owns marking the slide dirty.
494
+ * - the read model's colour getters, which resolve a colour to report it;
495
+ * - the import-time flatten passes (`read/api/ops/flatten.ts`), which resolve the same colour in
496
+ * order to *bake* it into a slide.
497
+ *
498
+ * They must agree, so they share this. The passes that write results back into a part live with
499
+ * the other import operations, not here — this module deliberately has no mutating exports.
500
+ * Placeholder-inheritance resolution (what a placeholder gets from its layout/master chain) is
501
+ * its own concern and lives in `placeholder-inherit.ts`.
356
502
  */
357
503
  /** The 12 `a:clrScheme` slot names, in schema order. */
358
504
  const SCHEME_SLOTS = [
@@ -376,39 +522,6 @@ const DIRECT_SLOT_TOKENS = /* @__PURE__ */ new Set([
376
522
  "dk2",
377
523
  "lt2"
378
524
  ]);
379
- /** Schema successors for ordered insertion into `p:spPr` (CT_ShapeProperties). */
380
- const SPPR_XFRM_AFTER = [
381
- "a:custGeom",
382
- "a:prstGeom",
383
- ...FILL_CHOICES,
384
- "a:ln",
385
- "a:effectLst",
386
- "a:effectDag",
387
- "a:scene3d",
388
- "a:sp3d",
389
- "a:extLst"
390
- ];
391
- const SPPR_FILL_AFTER$1 = [
392
- "a:ln",
393
- "a:effectLst",
394
- "a:effectDag",
395
- "a:scene3d",
396
- "a:sp3d",
397
- "a:extLst"
398
- ];
399
- const SPPR_LN_AFTER$1 = [
400
- "a:effectLst",
401
- "a:effectDag",
402
- "a:scene3d",
403
- "a:sp3d",
404
- "a:extLst"
405
- ];
406
- const SPPR_EFFECT_AFTER = [
407
- "a:scene3d",
408
- "a:sp3d",
409
- "a:extLst"
410
- ];
411
- const SHAPE_AFTER_SPPR$1 = ["p:style", "p:txBody"];
412
525
  /** Parse an `a:clrScheme` into slot → 6-hex RGB, reading `srgbClr`/`sysClr`. */
413
526
  function parseClrScheme(clrScheme) {
414
527
  const out = /* @__PURE__ */ new Map();
@@ -452,12 +565,6 @@ function resolveSchemeToken(token, ctx) {
452
565
  const slot = DIRECT_SLOT_TOKENS.has(token) ? token : ctx.clrMap.get(token);
453
566
  return slot ? ctx.clrScheme.get(slot) ?? null : null;
454
567
  }
455
- /** Direct child *elements* of `parent`, in order. */
456
- function childElements$1(parent) {
457
- const out = [];
458
- for (let node = parent.firstChild; node; node = node.nextSibling) if (node.nodeType === 1) out.push(node);
459
- return out;
460
- }
461
568
  /** Whether `el` is a DrawingML element with the given local name. */
462
569
  function isA(el, local) {
463
570
  return !!el && el.namespaceURI === OOXML_NS.a && el.localName === local;
@@ -476,7 +583,7 @@ function colorElementHex(color) {
476
583
  */
477
584
  function resolveColor(color, ctx) {
478
585
  if (!color) return null;
479
- const transforms = childElements$1(color);
586
+ const transforms = childElements(color);
480
587
  if (isA(color, "srgbClr")) {
481
588
  const hex = attr(color, "val");
482
589
  return hex ? {
@@ -502,239 +609,128 @@ function resolveColor(color, ctx) {
502
609
  return null;
503
610
  }
504
611
  /**
505
- * Flatten one slide's theme dependencies in place:
506
- *
507
- * 1. carry the background the slide inherited from its source layout/master onto
508
- * the slide (so it survives rebinding to a different master);
509
- * 2. materialize `p:bgRef` and style-matrix refs into explicit fills/lines/effects;
510
- * 3. bake each placeholder's effective geometry (inherited `a:xfrm`) onto the
511
- * shape so a rebind cannot move or resize it;
512
- * 4. bake each placeholder run's effective colour and size/weight (inherited from
513
- * the source layout/master text styles) explicitly onto the run;
514
- * 5. rewrite every remaining `a:schemeClr` to its literal `a:srgbClr`.
515
- *
516
- * Steps run in this order so the inherited/materialized backgrounds are present
517
- * before the final scheme-colour sweep resolves the colours they carry. The
518
- * placeholder geometry/colour/size passes have no data dependency on the others.
519
- * The caller marks the part dirty.
612
+ * Resolve a `+mj-*`/`+mn-*` major/minor font token against a theme `a:fontScheme`
613
+ * to a literal typeface name. A non-token `typeface` (an already-literal face) is
614
+ * returned verbatim. `null` when `typeface` is absent, or when a token cannot be
615
+ * resolved (no `fontScheme`, or the indexed major/minor script slot is empty).
616
+ * The script suffix selects the scheme child: `lt`→`a:latin`, `ea`→`a:ea`,
617
+ * `cs`→`a:cs`.
520
618
  */
521
- function flattenSlide(slideRoot, ctx) {
522
- applyInheritedBackground(slideRoot, ctx);
523
- materializeBackground(slideRoot, ctx);
524
- materializeStyleRefs(slideRoot, ctx);
525
- resolvePlaceholderGeometry(slideRoot, ctx);
526
- resolvePlaceholderRunColors(slideRoot, ctx);
527
- resolvePlaceholderRunSizes(slideRoot, ctx);
528
- resolveSchemeColors(slideRoot, ctx);
619
+ function resolveThemeFont(typeface, fontScheme) {
620
+ if (!typeface) return null;
621
+ const match = /^\+(mj|mn)-(lt|ea|cs)$/.exec(typeface);
622
+ if (!match) return typeface;
623
+ if (!fontScheme) return null;
624
+ const font = firstChild(fontScheme, match[1] === "mj" ? "a:majorFont" : "a:minorFont");
625
+ const childName = match[2] === "lt" ? "a:latin" : match[2] === "ea" ? "a:ea" : "a:cs";
626
+ const child = font && firstChild(font, childName);
627
+ return child && attr(child, "typeface") || null;
529
628
  }
530
- /**
531
- * Flatten a single lifted shape's theme dependencies in place — the shape-scoped
532
- * subset of {@link flattenSlide} used by `Presentation.importShape` `preserve`
533
- * mode. It runs every pass that resolves a *shape's* theme references against the
534
- * source theme (style-matrix refs, placeholder-inherited geometry/colour/size/
535
- * anchor/list-style, scheme colours) but deliberately **omits** the two
536
- * slide-scoped background passes (`applyInheritedBackground`/`materializeBackground`):
537
- * a background belongs to a slide, not to a shape being composed onto a foreign host.
538
- *
539
- * Unlike {@link flattenSlide}, this also **demotes** a lifted placeholder to a
540
- * plain shape ({@link demotePlaceholders}) once everything it inherited is baked.
541
- * A placeholder makes sense on its own slide, where it resolves against that deck's
542
- * master/layout; lifted onto a foreign host its surviving `p:ph` would re-resolve
543
- * against the *host* placeholder of the same type/idx (wrong inheritance, or a
544
- * fallback when absent) and could collide with the host's own placeholder. The
545
- * extra bakes here (anchor + list style, on top of the geometry/colour/size the
546
- * shared passes cover) make the shape self-contained so demotion loses nothing
547
- * visible. This is why the demotion is scoped to `flattenShape`: `flattenSlide`
548
- * keeps placeholders as placeholders by design.
549
- *
550
- * `shapeRoot` must be an element whose *descendants* include the lifted shape
551
- * (the passes match via `getElementsByTagNameNS`, which excludes the root element
552
- * itself) — the caller wraps the imported `p:sp`/`p:pic`/`p:graphicFrame`/`p:grpSp`
553
- * in a throwaway container before calling. The caller marks the part dirty.
554
- */
555
- function flattenShape(shapeRoot, ctx) {
556
- materializeStyleRefs(shapeRoot, ctx);
557
- resolvePlaceholderGeometry(shapeRoot, ctx);
558
- resolvePlaceholderRunColors(shapeRoot, ctx);
559
- resolvePlaceholderRunSizes(shapeRoot, ctx);
560
- resolvePlaceholderBodyPr(shapeRoot, ctx);
561
- resolvePlaceholderListStyle(shapeRoot, ctx);
562
- resolveSchemeColors(shapeRoot, ctx);
563
- demotePlaceholders(shapeRoot);
629
+ /** Replace every `phClr` under `el` with the ref colour (ref transforms first, then the `phClr`'s own). */
630
+ function substitutePhClr(el, ref) {
631
+ const doc = ownerDocumentOf(el);
632
+ for (const phClr of descendantsByTag(el, OOXML_NS.a, "schemeClr")) {
633
+ if (attr(phClr, "val") !== "phClr") continue;
634
+ const srgb = createElement(doc, "a:srgbClr");
635
+ setAttr(srgb, "val", ref.hex);
636
+ for (const t of ref.transforms) srgb.appendChild(t.cloneNode(true));
637
+ while (phClr.firstChild) srgb.appendChild(phClr.firstChild);
638
+ replaceInParent(phClr, srgb);
639
+ }
564
640
  }
565
- /**
566
- * Restyle a rebound slide in place (the `theme: 'restyle'` mode): the exact
567
- * inverse of {@link flattenSlide}. It bakes *nothing* — leaving every
568
- * `a:schemeClr`/style-matrix ref and `p:bg` `bgRef` symbolic is the whole point,
569
- * so they re-resolve against the *destination* master's `clrMap` + theme once the
570
- * slide is rebound. The single mutation is dropping the slide's own colour-map
571
- * override (`p:clrMapOvr/a:overrideClrMapping`): a source override would keep
572
- * mapping the slide's scheme-token names the source way and defeat the re-brand,
573
- * so it must yield to the destination master's `p:clrMap`.
574
- *
575
- * Caveat carried from the plan: only *symbolic* colours re-brand. Anything the
576
- * source authored as a literal `a:srgbClr` has no theme reference to re-resolve
577
- * and stays exactly that colour. The caller marks the part dirty.
578
- */
579
- function restyleSlide(slideRoot) {
580
- removeChildrenByQName(slideRoot, ["p:clrMapOvr"]);
641
+ /** The `idx`-th entry (1-based) of a `fmtScheme` style list, deep-cloned, or `null`. */
642
+ function fmtEntry(ctx, listName, idx) {
643
+ const list = ctx.fmtScheme && firstChild(ctx.fmtScheme, listName);
644
+ if (!list || idx < 1) return null;
645
+ const entry = childElements(list)[idx - 1];
646
+ return entry ? entry.cloneNode(true) : null;
581
647
  }
582
648
  /**
583
- * The optional inverse of {@link resolveSchemeColors}, for `restyle`'s
584
- * force-remap-literals mode (the {@link Presentation.importSlide} `remapLiterals`
585
- * option). Every literal `a:srgbClr` whose value equals a *source* `clrScheme`
586
- * slot is rewritten back to a symbolic `a:schemeClr` so it re-resolves against the
587
- * destination theme; a literal matching no slot (the common case) is left exactly
588
- * as authored. Transform children (`lumMod`/`shade`/`alpha`/…) are carried across.
589
- *
590
- * Plain `restyle` cannot re-brand a literal — it carries no theme reference. This
591
- * re-introduces one by matching the literal's RGB against the slots the *source*
592
- * theme defined, emitting the scheme token that routes through the source `clrMap`
593
- * (so a literal equal to the source `accent1` slot becomes `schemeClr accent1`,
594
- * which the destination `clrMap`/theme then re-resolve). Slots are matched in
595
- * `clrScheme` order, so the first slot defining a given RGB wins when several share
596
- * it. Opt-in because it deliberately reinterprets authored literals as theme
597
- * colours — visual QA territory, the same caveat as the rest of `restyle`.
649
+ * Build the explicit fill element a `p:style` `a:fillRef` resolves to — the indexed
650
+ * `fmtScheme` `fillStyleLst`/`bgFillStyleLst` entry (deep-cloned) with its `phClr`
651
+ * replaced by the ref's resolved colour. Pure: mutates neither the ref nor the
652
+ * theme. `null` when the ref is absent, `idx` is 0/unset, or the entry or its
653
+ * colour cannot be resolved. Shared by the flatten path and the read-model
654
+ * `resolveStyleFillColor` getter so both see the same fill.
598
655
  */
599
- function remapLiteralColors(slideRoot, ctx) {
600
- const slotByHex = reverseClrScheme(ctx.clrScheme);
601
- if (slotByHex.size === 0) return;
602
- const tokenBySlot = reverseClrMap(ctx.clrMap);
603
- const doc = ownerDocumentOf(slideRoot);
604
- for (const srgb of elementsByTag(slideRoot, OOXML_NS.a, "srgbClr")) {
605
- const hex = attr(srgb, "val");
606
- const slot = hex ? slotByHex.get(hex.toUpperCase()) : void 0;
607
- if (!slot) continue;
608
- const scheme = createElement(doc, "a:schemeClr");
609
- setAttr(scheme, "val", tokenBySlot.get(slot) ?? slot);
610
- while (srgb.firstChild) scheme.appendChild(srgb.firstChild);
611
- replaceInParent(srgb, scheme);
612
- }
613
- }
614
- /** Reverse a slot → RGB `clrScheme` into RGB → slot, in `SCHEME_SLOTS` order (first slot wins on a shared RGB). */
615
- function reverseClrScheme(clrScheme) {
616
- const out = /* @__PURE__ */ new Map();
617
- for (const slot of SCHEME_SLOTS) {
618
- const hex = clrScheme.get(slot);
619
- if (hex && !out.has(hex.toUpperCase())) out.set(hex.toUpperCase(), slot);
620
- }
621
- return out;
622
- }
623
- /** Reverse a token → slot `clrMap` into slot → token (first token wins on a shared slot). */
624
- function reverseClrMap(clrMap) {
625
- const out = /* @__PURE__ */ new Map();
626
- for (const [token, slot] of clrMap) if (!out.has(slot)) out.set(slot, token);
627
- return out;
656
+ function styleRefFill(fillRef, ctx) {
657
+ if (!fillRef) return null;
658
+ const idx = intAttr(fillRef, "idx");
659
+ if (idx === null || idx <= 0) return null;
660
+ const fill = idx >= 1e3 ? fmtEntry(ctx, "a:bgFillStyleLst", idx - 1e3) : fmtEntry(ctx, "a:fillStyleLst", idx);
661
+ const ref = resolveColor(firstChildElement(fillRef), ctx);
662
+ if (!fill || !ref) return null;
663
+ substitutePhClr(fill, ref);
664
+ return fill;
628
665
  }
629
666
  /**
630
- * If the slide has no own `p:bg`, insert (a copy of) the background it inherited
631
- * from its source layout/master as an explicit `p:cSld/p:bg`. The clone is left
632
- * unresolved here; the later passes flatten its `bgRef`/`schemeClr` in place.
667
+ * Build the explicit `a:ln` element a `p:style` `a:lnRef` resolves to — the indexed
668
+ * `fmtScheme` `lnStyleLst` entry (deep-cloned) with its `phClr` replaced by the
669
+ * ref's resolved colour. Pure; the line/read counterpart of {@link styleRefFill}.
633
670
  */
634
- function applyInheritedBackground(slideRoot, ctx) {
635
- const inherited = ctx.inheritedBackground;
636
- if (!inherited) return;
637
- const cSld = firstChild(slideRoot, "p:cSld");
638
- if (!cSld || firstChild(cSld, "p:bg")) return;
639
- insertInOrder(cSld, ownerDocumentOf(slideRoot).importNode(inherited, true), [
640
- "p:spTree",
641
- "p:custDataLst",
642
- "p:controls",
643
- "p:extLst"
644
- ]);
671
+ function styleRefLine(lnRef, ctx) {
672
+ if (!lnRef) return null;
673
+ const idx = intAttr(lnRef, "idx");
674
+ if (idx === null || idx <= 0) return null;
675
+ const ln = fmtEntry(ctx, "a:lnStyleLst", idx);
676
+ const ref = resolveColor(firstChildElement(lnRef), ctx);
677
+ if (!ln || !ref) return null;
678
+ substitutePhClr(ln, ref);
679
+ return ln;
680
+ }
681
+ /** Read an integer attribute; `null`/empty/non-finite → `null`. */
682
+ function intAttr(el, name) {
683
+ const value = attr(el, name);
684
+ if (value === null || value === "") return null;
685
+ const n = Number(value);
686
+ return Number.isFinite(n) ? n : null;
645
687
  }
688
+ //#endregion
689
+ //#region src/read/oxml/placeholder-inherit.ts
646
690
  /**
647
- * Resolve every `p:bgRef` (theme-indexed background) under the slide into an
648
- * explicit `p:bgPr` fill, so the background no longer depends on the destination
649
- * theme's `fmtScheme`. A `bgPr` background is left for the scheme-colour sweep.
691
+ * Resolving what a placeholder shape *inherits* from its source layout/master chain.
692
+ *
693
+ * A placeholder that sets none of its own colour, size, geometry, anchor or list style takes
694
+ * each from a chain: the layout placeholder's `a:lstStyle`, then the master placeholder's, then
695
+ * the master's `p:txStyles` category style (and, on a notes context, the notesMaster
696
+ * `p:notesStyle`). Every function here answers "what would this placeholder get?" — none of them
697
+ * writes anything.
698
+ *
699
+ * **Two callers, one answer.** The read model's getters (`Run.resolvedColor`,
700
+ * `TextFrame.resolvedAnchor`, the font getters) and the import-time flatten passes
701
+ * (`read/api/ops/flatten.ts`, which bakes the inherited values onto a slide so they survive a
702
+ * rebind to a different master) both ask the same questions. They must not answer them
703
+ * differently: if the getter and the bake disagreed, a caller would see one colour before export
704
+ * and another in the file. Sharing this module is what makes that structurally impossible.
705
+ *
706
+ * This module is pure — mutation lives in the flatten pass, which is also why it sits in
707
+ * `read/oxml/` (substrate) rather than `read/api/ops/`.
650
708
  */
651
- function materializeBackground(slideRoot, ctx) {
652
- const doc = ownerDocumentOf(slideRoot);
653
- for (const bg of elementsByTag(slideRoot, OOXML_NS.p, "bg")) {
654
- const bgRef = firstChild(bg, "p:bgRef");
655
- if (!bgRef) continue;
656
- const fill = styleRefFill(bgRef, ctx);
657
- const bgPr = createElement(doc, "p:bgPr");
658
- bgPr.appendChild(fill ?? createElement(doc, "a:noFill"));
659
- bg.replaceChild(bgPr, bgRef);
660
- }
661
- }
662
- /** Rewrite every `a:schemeClr` under `root` to a literal `a:srgbClr` when resolvable. */
663
- function resolveSchemeColors(root, ctx) {
664
- const doc = ownerDocumentOf(root);
665
- for (const schemeClr of elementsByTag(root, OOXML_NS.a, "schemeClr")) {
666
- const token = attr(schemeClr, "val");
667
- const hex = token ? resolveSchemeToken(token, ctx) : null;
668
- if (!hex) continue;
669
- const srgb = createElement(doc, "a:srgbClr");
670
- setAttr(srgb, "val", hex);
671
- while (schemeClr.firstChild) srgb.appendChild(schemeClr.firstChild);
672
- replaceInParent(schemeClr, srgb);
673
- }
674
- }
675
- /** Schema successors of `a:solidFill` inside `a:rPr` (CT_TextCharacterProperties sequence). */
676
- const RPR_FILL_AFTER = [
677
- "a:effectLst",
678
- "a:effectDag",
679
- "a:highlight",
680
- "a:uLnTx",
681
- "a:uLn",
682
- "a:uFillTx",
683
- "a:uFill",
684
- "a:latin",
685
- "a:ea",
686
- "a:cs",
687
- "a:sym",
688
- "a:hlinkClick",
689
- "a:hlinkMouseOver",
690
- "a:rtl",
691
- "a:extLst"
692
- ];
693
709
  /** The master `p:txStyles` style element name for a placeholder category. */
694
710
  const TX_STYLE_NAME = {
695
711
  title: "p:titleStyle",
696
712
  body: "p:bodyStyle",
697
713
  other: "p:otherStyle"
698
714
  };
699
- /**
700
- * Bake placeholder-inherited run colours onto the slide (gap 1). For each
701
- * placeholder run that defines no colour of its own (nor at paragraph/text-body
702
- * level on the *slide*), resolve the colour it would inherit from the source
703
- * `slideLayout`/`slideMaster` text styles and write it explicitly onto the run's
704
- * `a:rPr`. After this the run's colour cannot change when the slide is rebound to
705
- * the destination master. `a:fld` runs (dates, slide numbers) are treated like
706
- * `a:r`. Only colour is resolved; other inheritable run properties are left to
707
- * re-bind to the destination styles.
708
- */
709
- function resolvePlaceholderRunColors(slideRoot, ctx) {
710
- if (!ctx.layoutRoot && !ctx.masterRoot) return;
711
- for (const sp of elementsByTag(slideRoot, OOXML_NS.p, "sp")) {
712
- const ph = placeholderOf(sp);
713
- if (!ph) continue;
714
- const txBody = firstChild(sp, "p:txBody");
715
- if (!txBody) continue;
716
- const type = attr(ph, "type");
717
- const idx = attr(ph, "idx") ?? "0";
718
- const slideLst = firstChild(txBody, "a:lstStyle");
719
- const byLevel = /* @__PURE__ */ new Map();
720
- for (const p of getElements(txBody, "a:p")) {
721
- const pPr = firstChild(p, "a:pPr");
722
- const level = (pPr && intValue(attr(pPr, "lvl"))) ?? 0;
723
- const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
724
- if (runs.length === 0) continue;
725
- let color = byLevel.get(level);
726
- if (color === void 0) {
727
- color = placeholderInheritedColor(type, idx, level, ctx);
728
- byLevel.set(level, color);
729
- }
730
- if (!color) continue;
731
- for (const run of runs) {
732
- if (slideDefinesColor(run, pPr, slideLst, level)) continue;
733
- writeRunColor(run, color);
734
- }
735
- }
736
- }
737
- }
715
+ /** The ordered children of a `CT_TextListStyle` (`a:lstStyle` / a `p:txStyles` style). */
716
+ const LST_STYLE_LEVELS = [
717
+ "a:defPPr",
718
+ "a:lvl1pPr",
719
+ "a:lvl2pPr",
720
+ "a:lvl3pPr",
721
+ "a:lvl4pPr",
722
+ "a:lvl5pPr",
723
+ "a:lvl6pPr",
724
+ "a:lvl7pPr",
725
+ "a:lvl8pPr",
726
+ "a:lvl9pPr"
727
+ ];
728
+ /** Inheritable run properties baked under `preserve`: size and weight/slant (not typeface). */
729
+ const RUN_PROP_NAMES = [
730
+ "sz",
731
+ "b",
732
+ "i"
733
+ ];
738
734
  /** The `p:ph` element of a shape (`p:sp/p:nvSpPr/p:nvPr/p:ph`), or `null`. */
739
735
  function placeholderOf(sp) {
740
736
  const nvSpPr = firstChild(sp, "p:nvSpPr");
@@ -784,7 +780,7 @@ const SINGLETON_PH = /* @__PURE__ */ new Set([
784
780
  */
785
781
  function findPlaceholder(root, slideType, slideIdx) {
786
782
  if (slideType && SINGLETON_PH.has(slideType)) {
787
- for (const sp of elementsByTag(root, OOXML_NS.p, "sp")) {
783
+ for (const sp of descendantsByTag(root, OOXML_NS.p, "sp")) {
788
784
  const ph = placeholderOf(sp);
789
785
  if (ph && attr(ph, "type") === slideType) return sp;
790
786
  }
@@ -793,7 +789,7 @@ function findPlaceholder(root, slideType, slideIdx) {
793
789
  const cat = phCategory(slideType);
794
790
  let idxMatch = null;
795
791
  let catMatch = null;
796
- for (const sp of elementsByTag(root, OOXML_NS.p, "sp")) {
792
+ for (const sp of descendantsByTag(root, OOXML_NS.p, "sp")) {
797
793
  const ph = placeholderOf(sp);
798
794
  if (!ph) continue;
799
795
  const type = attr(ph, "type");
@@ -827,259 +823,14 @@ function lstStyleLevelFill(listStyle, level) {
827
823
  return defRPr ? firstChild(defRPr, "a:solidFill") : null;
828
824
  }
829
825
  /**
830
- * The colour *element* a placeholder run inherits from the source style chain: the
831
- * layout placeholder's `a:lstStyle`, then the master placeholder's, then the
832
- * master `p:txStyles` category style. Returns the first tier's colour element that
833
- * resolves against `ctx` (the `a:srgbClr`/`a:schemeClr`/… inside its
834
- * `a:solidFill`), or `null` when nothing in the chain defines a resolvable colour.
835
- * The read-model `Run.resolvedColor` getter feeds this element to
836
- * `resolveColorElement` for the `effectiveHex`; the flatten path resolves it
837
- * directly via {@link placeholderInheritedColor}.
838
- */
839
- function placeholderInheritedFill(type, idx, level, ctx) {
840
- const tiers = [];
841
- if (ctx.layoutRoot) {
842
- const layoutPh = findPlaceholder(ctx.layoutRoot, type, idx);
843
- tiers.push(layoutPh && lstStyleLevelFill(placeholderLstStyle(layoutPh), level));
844
- }
845
- if (ctx.masterRoot) {
846
- const masterPh = findPlaceholder(ctx.masterRoot, type, idx);
847
- tiers.push(masterPh && lstStyleLevelFill(placeholderLstStyle(masterPh), level));
848
- const txStyles = firstChild(ctx.masterRoot, "p:txStyles");
849
- const styleEl = txStyles && firstChild(txStyles, TX_STYLE_NAME[phCategory(type)]);
850
- tiers.push(styleEl && lstStyleLevelFill(styleEl, level));
851
- }
852
- if (ctx.notesStyle) tiers.push(lstStyleLevelFill(ctx.notesStyle, level));
853
- for (const fill of tiers) {
854
- const colorEl = fill && firstChildElement(fill);
855
- if (colorEl && resolveColor(colorEl, ctx)) return colorEl;
856
- }
857
- return null;
858
- }
859
- /**
860
- * The level `a:defRPr` elements a placeholder inherits from the source style
861
- * chain, in resolution order: the layout placeholder's `a:lstStyle`, then the
862
- * master placeholder's, then the master `p:txStyles` category style — and, on a
863
- * notes context only, the notesMaster `p:notesStyle` (see `ctx.notesStyle`). Tiers
864
- * with no `a:defRPr` for `level` are dropped. The shared root for inherited run
865
- * *size* and *typeface* resolution (the size/face sibling of
866
- * {@link placeholderInheritedFill}), read directly by the flatten path and the
867
- * read-model font getters.
868
- */
869
- function placeholderInheritedDefRPrs(type, idx, level, ctx) {
870
- const tiers = [];
871
- if (ctx.layoutRoot) {
872
- const layoutPh = findPlaceholder(ctx.layoutRoot, type, idx);
873
- tiers.push(layoutPh && lstStyleLevelDefRPr(placeholderLstStyle(layoutPh), level));
874
- }
875
- if (ctx.masterRoot) {
876
- const masterPh = findPlaceholder(ctx.masterRoot, type, idx);
877
- tiers.push(masterPh && lstStyleLevelDefRPr(placeholderLstStyle(masterPh), level));
878
- const txStyles = firstChild(ctx.masterRoot, "p:txStyles");
879
- const styleEl = txStyles && firstChild(txStyles, TX_STYLE_NAME[phCategory(type)]);
880
- tiers.push(styleEl && lstStyleLevelDefRPr(styleEl, level));
881
- }
882
- if (ctx.notesStyle) tiers.push(lstStyleLevelDefRPr(ctx.notesStyle, level));
883
- return tiers.filter((t) => t !== null);
884
- }
885
- /**
886
- * Resolve a `+mj-*`/`+mn-*` major/minor font token against a theme `a:fontScheme`
887
- * to a literal typeface name. A non-token `typeface` (an already-literal face) is
888
- * returned verbatim. `null` when `typeface` is absent, or when a token cannot be
889
- * resolved (no `fontScheme`, or the indexed major/minor script slot is empty).
890
- * The script suffix selects the scheme child: `lt`→`a:latin`, `ea`→`a:ea`,
891
- * `cs`→`a:cs`.
892
- */
893
- function resolveThemeFont(typeface, fontScheme) {
894
- if (!typeface) return null;
895
- const match = /^\+(mj|mn)-(lt|ea|cs)$/.exec(typeface);
896
- if (!match) return typeface;
897
- if (!fontScheme) return null;
898
- const font = firstChild(fontScheme, match[1] === "mj" ? "a:majorFont" : "a:minorFont");
899
- const childName = match[2] === "lt" ? "a:latin" : match[2] === "ea" ? "a:ea" : "a:cs";
900
- const child = font && firstChild(font, childName);
901
- return child && attr(child, "typeface") || null;
902
- }
903
- /**
904
- * The colour a placeholder run inherits from the source style chain, resolved to a
905
- * literal `{ hex, transforms }`. Thin wrapper over {@link placeholderInheritedFill}
906
- * for the flatten path, which re-emits the transforms verbatim. Returns `null`
907
- * when nothing in the chain defines a resolvable colour (the run then re-binds to
908
- * the destination).
909
- */
910
- function placeholderInheritedColor(type, idx, level, ctx) {
911
- const colorEl = placeholderInheritedFill(type, idx, level, ctx);
912
- return colorEl ? resolveColor(colorEl, ctx) : null;
913
- }
914
- /** Whether the *slide itself* already fixes this run's colour (so a rebind cannot change it). */
915
- function slideDefinesColor(run, pPr, slideLst, level) {
916
- const rPr = firstChild(run, "a:rPr");
917
- if (rPr && FILL_CHOICES.some((q) => firstChild(rPr, q))) return true;
918
- const defRPr = pPr && firstChild(pPr, "a:defRPr");
919
- if (defRPr && firstChild(defRPr, "a:solidFill")) return true;
920
- return !!lstStyleLevelFill(slideLst, level);
921
- }
922
- /** Write a resolved colour as an explicit `a:solidFill` (with carried transforms) onto a run's `a:rPr`. */
923
- function writeRunColor(run, color) {
924
- const doc = ownerDocumentOf(run);
925
- const rPr = getOrAddChild(run, "a:rPr", ["a:t"]);
926
- const fill = createElement(doc, "a:solidFill");
927
- const srgb = createElement(doc, "a:srgbClr");
928
- setAttr(srgb, "val", color.hex);
929
- for (const t of color.transforms) srgb.appendChild(t.cloneNode(true));
930
- fill.appendChild(srgb);
931
- insertInOrder(rPr, fill, RPR_FILL_AFTER);
932
- }
933
- /**
934
- * Bake placeholder-inherited geometry onto the slide (gap 3). A placeholder shape
935
- * that carries no own `p:spPr/a:xfrm` takes its position/size from the matching
936
- * source `slideLayout` placeholder, else the `slideMaster` placeholder. Rebinding
937
- * to the destination master replaces that inheritance, so the placeholder would
938
- * snap to the destination default (often clipping off-canvas). We deep-clone the
939
- * effective source `a:xfrm` and write it explicitly onto the shape. Shapes with
940
- * their own `a:xfrm` are left untouched (explicit geometry is not inherited), and
941
- * an orphan placeholder with no source match keeps the current fall-back behaviour.
942
- */
943
- function resolvePlaceholderGeometry(slideRoot, ctx) {
944
- if (!ctx.layoutRoot && !ctx.masterRoot) return;
945
- for (const sp of elementsByTag(slideRoot, OOXML_NS.p, "sp")) {
946
- const ph = placeholderOf(sp);
947
- if (!ph) continue;
948
- const spPr = firstChild(sp, "p:spPr");
949
- if (spPr && firstChild(spPr, "a:xfrm")) continue;
950
- const found = placeholderInheritedXfrm(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
951
- if (!found) continue;
952
- insertInOrder(getOrAddChild(sp, "p:spPr", SHAPE_AFTER_SPPR$1), found.xfrm.cloneNode(true), SPPR_XFRM_AFTER);
953
- }
954
- }
955
- /**
956
- * The `a:xfrm` a placeholder inherits from the source layout, then master,
957
- * tagged with which tier it came from — `null` when neither defines one. The
958
- * read-model {@link resolveInheritedFrame} (`theme-context.ts`) sibling of
959
- * {@link placeholderInheritedAnchor}; also the bake source for
960
- * {@link resolvePlaceholderGeometry}.
961
- */
962
- function placeholderInheritedXfrm(type, idx, ctx) {
963
- for (const [root, source] of [[ctx.layoutRoot, "layout"], [ctx.masterRoot, "master"]]) {
964
- if (!root) continue;
965
- const ph = findPlaceholder(root, type, idx);
966
- const spPr = ph && firstChild(ph, "p:spPr");
967
- const xfrm = spPr && firstChild(spPr, "a:xfrm");
968
- if (xfrm) return {
969
- xfrm,
970
- source
971
- };
972
- }
973
- return null;
974
- }
975
- /**
976
- * The vertical anchor (`a:bodyPr/@anchor`) a placeholder inherits from the source
977
- * layout, then master, or `null`. Resolves per-attribute: the first tier whose
978
- * placeholder `a:bodyPr` actually sets `@anchor` wins, so a layout `a:bodyPr`
979
- * present but without `@anchor` does not mask the master's. The read-model
980
- * {@link TextFrame.resolvedAnchor} sibling of {@link placeholderInheritedXfrm}.
981
- */
982
- function placeholderInheritedAnchor(type, idx, ctx) {
983
- for (const root of [ctx.layoutRoot, ctx.masterRoot]) {
984
- if (!root) continue;
985
- const ph = findPlaceholder(root, type, idx);
986
- const txBody = ph && firstChild(ph, "p:txBody");
987
- const bodyPr = txBody && firstChild(txBody, "a:bodyPr");
988
- const anchor = bodyPr && attr(bodyPr, "anchor");
989
- if (anchor) return anchor;
990
- }
991
- return null;
992
- }
993
- /**
994
- * Bake the placeholder-inherited vertical anchor onto a lifted shape's text body
995
- * (the {@link flattenShape} placeholder-demotion path). A placeholder whose own
996
- * `a:bodyPr` sets no `@anchor` inherits it from the source layout/master placeholder;
997
- * once {@link demotePlaceholders} strips the `p:ph` the shape would lose that
998
- * inheritance and fall back to top-anchored, so a vertically-centred title jumps.
999
- * We resolve the effective anchor from the source chain (via
1000
- * {@link placeholderInheritedAnchor}) and write it explicitly. Shapes whose
1001
- * `a:bodyPr` already fixes `@anchor`, and placeholders with no resolvable inherited
1002
- * anchor, are left untouched. Other `a:bodyPr` knobs (insets, autofit) are left as
1003
- * authored — they have sane defaults a plain shape keeps.
1004
- */
1005
- function resolvePlaceholderBodyPr(shapeRoot, ctx) {
1006
- if (!ctx.layoutRoot && !ctx.masterRoot) return;
1007
- for (const sp of elementsByTag(shapeRoot, OOXML_NS.p, "sp")) {
1008
- const ph = placeholderOf(sp);
1009
- if (!ph) continue;
1010
- const txBody = firstChild(sp, "p:txBody");
1011
- if (!txBody) continue;
1012
- const bodyPr = firstChild(txBody, "a:bodyPr");
1013
- if (bodyPr && attr(bodyPr, "anchor") != null) continue;
1014
- const anchor = placeholderInheritedAnchor(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
1015
- if (!anchor) continue;
1016
- setAttr(bodyPr ?? getOrAddChild(txBody, "a:bodyPr", ["a:lstStyle", "a:p"]), "anchor", anchor);
1017
- }
1018
- }
1019
- /** The ordered children of a `CT_TextListStyle` (`a:lstStyle` / a `p:txStyles` style). */
1020
- const LST_STYLE_LEVELS = [
1021
- "a:defPPr",
1022
- "a:lvl1pPr",
1023
- "a:lvl2pPr",
1024
- "a:lvl3pPr",
1025
- "a:lvl4pPr",
1026
- "a:lvl5pPr",
1027
- "a:lvl6pPr",
1028
- "a:lvl7pPr",
1029
- "a:lvl8pPr",
1030
- "a:lvl9pPr"
1031
- ];
1032
- /**
1033
- * Bake the placeholder-inherited list style onto a lifted shape's text body (the
1034
- * {@link flattenShape} placeholder-demotion path). A placeholder's per-level
1035
- * *paragraph* formatting — indent (`marL`/`indent`), bullets (`a:buChar`/
1036
- * `a:buAutoNum`/`a:buNone`), alignment, and the level `a:defRPr` — is inherited
1037
- * from the source layout/master placeholder `a:lstStyle` and the master
1038
- * `p:txStyles` category style. Run colour/size are baked onto each run by the
1039
- * sibling passes, but paragraph-level defaults live here; once
1040
- * {@link demotePlaceholders} strips the `p:ph` the shape stops inheriting them, so
1041
- * bullets and indents would vanish. We materialize the effective list style onto
1042
- * the shape's `p:txBody/a:lstStyle`.
826
+ * The source style tiers a placeholder resolves against, most specific first: the layout
827
+ * placeholder's `a:lstStyle`, the master placeholder's, then the master `p:txStyles` category
828
+ * style — and, on a notes context only, the notesMaster `p:notesStyle`.
1043
829
  *
1044
- * Resolution is per *level*, most specific tier wins whole: the slide's own level
1045
- * (if it defines one) is kept verbatim, else the first source tier that defines it
1046
- * (layout placeholder, then master placeholder, then master category style) is
1047
- * cloned. This is a whole-element overlay, not the per-attribute merge PowerPoint
1048
- * does — but explicit paragraph `a:pPr` on the slide's own runs travels with the
1049
- * shape and still wins, so this only supplies defaults for the inherited case
1050
- * (paragraphs that set no `a:pPr` of their own). Scheme colours in the cloned
1051
- * levels are resolved by the later {@link resolveSchemeColors} pass.
830
+ * The one place the chain is spelled out. `placeholderInherited*` differ only in what they pull
831
+ * from each tier, so they all walk this.
1052
832
  */
1053
- function resolvePlaceholderListStyle(shapeRoot, ctx) {
1054
- if (!ctx.layoutRoot && !ctx.masterRoot) return;
1055
- for (const sp of elementsByTag(shapeRoot, OOXML_NS.p, "sp")) {
1056
- const ph = placeholderOf(sp);
1057
- if (!ph) continue;
1058
- const txBody = firstChild(sp, "p:txBody");
1059
- if (!txBody) continue;
1060
- const tiers = placeholderInheritedListStyles(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
1061
- if (tiers.length === 0) continue;
1062
- const slideLst = firstChild(txBody, "a:lstStyle");
1063
- const merged = createElement(ownerDocumentOf(txBody), "a:lstStyle");
1064
- let any = false;
1065
- for (const level of LST_STYLE_LEVELS) {
1066
- const src = (slideLst && firstChild(slideLst, level)) ?? tiers.map((t) => firstChild(t, level)).find((e) => !!e) ?? null;
1067
- if (!src) continue;
1068
- merged.appendChild(src.cloneNode(true));
1069
- any = true;
1070
- }
1071
- if (!any) continue;
1072
- if (slideLst) txBody.replaceChild(merged, slideLst);
1073
- else insertInOrder(txBody, merged, ["a:p"]);
1074
- }
1075
- }
1076
- /**
1077
- * The source list-style tiers a placeholder inherits paragraph formatting from,
1078
- * most specific first: layout placeholder `a:lstStyle`, master placeholder
1079
- * `a:lstStyle`, then the master `p:txStyles` category style (itself a
1080
- * `CT_TextListStyle`). The paragraph-level sibling of {@link placeholderInheritedDefRPrs}.
1081
- */
1082
- function placeholderInheritedListStyles(type, idx, ctx) {
833
+ function styleTiers(type, idx, ctx) {
1083
834
  const tiers = [];
1084
835
  if (ctx.layoutRoot) {
1085
836
  const layoutPh = findPlaceholder(ctx.layoutRoot, type, idx);
@@ -1091,73 +842,61 @@ function placeholderInheritedListStyles(type, idx, ctx) {
1091
842
  const txStyles = firstChild(ctx.masterRoot, "p:txStyles");
1092
843
  tiers.push(txStyles && firstChild(txStyles, TX_STYLE_NAME[phCategory(type)]));
1093
844
  }
845
+ if (ctx.notesStyle) tiers.push(ctx.notesStyle);
1094
846
  return tiers.filter((t) => t !== null);
1095
847
  }
1096
848
  /**
1097
- * Strip the `p:ph` marker from every placeholder shape in a lifted subtree so it
1098
- * becomes a self-contained ordinary shape (the {@link flattenShape} path only). By
1099
- * the time this runs, the shape's inherited geometry, colour, run size, anchor, and
1100
- * list style are all baked explicitly, so it no longer needs — and must not keep —
1101
- * its placeholder identity: a surviving `p:ph` would re-resolve against the *host*
1102
- * deck's layout/master placeholder of the same type/idx (wrong inheritance, or a
1103
- * fallback when the host has none) and could collide with the host slide's own
1104
- * placeholder of that type. Removing the marker severs both. The `p:nvPr` itself is
1105
- * kept (it can carry media/custom-data children); only the `p:ph` child goes.
849
+ * The colour *element* a placeholder run inherits from the source style chain. Returns the
850
+ * first tier's colour element that resolves against `ctx` (the `a:srgbClr`/`a:schemeClr`/…
851
+ * inside its `a:solidFill`), or `null` when nothing in the chain defines a resolvable colour.
852
+ * The read-model `Run.resolvedColor` getter feeds this element to `resolveColorElement` for the
853
+ * `effectiveHex`; the flatten path resolves it directly via {@link placeholderInheritedColor}.
1106
854
  */
1107
- function demotePlaceholders(shapeRoot) {
1108
- for (const sp of elementsByTag(shapeRoot, OOXML_NS.p, "sp")) {
1109
- const nvSpPr = firstChild(sp, "p:nvSpPr");
1110
- const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
1111
- if (nvPr) removeChildrenByQName(nvPr, ["p:ph"]);
855
+ function placeholderInheritedFill(type, idx, level, ctx) {
856
+ for (const tier of styleTiers(type, idx, ctx)) {
857
+ const fill = lstStyleLevelFill(tier, level);
858
+ const colorEl = fill && firstChildElement(fill);
859
+ if (colorEl && resolveColor(colorEl, ctx)) return colorEl;
1112
860
  }
861
+ return null;
1113
862
  }
1114
- /** Inheritable run properties baked under `preserve`: size and weight/slant (not typeface). */
1115
- const RUN_PROP_NAMES = [
1116
- "sz",
1117
- "b",
1118
- "i"
1119
- ];
1120
863
  /**
1121
- * Bake placeholder-inherited run size/weight onto the slide (gap 3). Mirrors
1122
- * {@link resolvePlaceholderRunColors}: for each placeholder run that sets no
1123
- * `sz`/`b`/`i` of its own (nor at paragraph/text-body level on the *slide*),
1124
- * resolve the value it would inherit from the source `slideLayout`/`slideMaster`
1125
- * text styles — per paragraph list level — and write it explicitly onto the run's
1126
- * `a:rPr`. Each property resolves independently up the chain. Typeface (`a:latin`)
1127
- * is left to re-bind to the destination theme, as gap 1 does for the `fontRef`.
864
+ * The level `a:defRPr` elements a placeholder inherits from the source style chain, in
865
+ * resolution order. Tiers with no `a:defRPr` for `level` are dropped. The shared root for
866
+ * inherited run *size* and *typeface* resolution (the size/face sibling of
867
+ * {@link placeholderInheritedFill}), read directly by the flatten path and the read-model font
868
+ * getters.
1128
869
  */
1129
- function resolvePlaceholderRunSizes(slideRoot, ctx) {
1130
- if (!ctx.layoutRoot && !ctx.masterRoot) return;
1131
- for (const sp of elementsByTag(slideRoot, OOXML_NS.p, "sp")) {
1132
- const ph = placeholderOf(sp);
1133
- if (!ph) continue;
1134
- const txBody = firstChild(sp, "p:txBody");
1135
- if (!txBody) continue;
1136
- const type = attr(ph, "type");
1137
- const idx = attr(ph, "idx") ?? "0";
1138
- const slideLst = firstChild(txBody, "a:lstStyle");
1139
- const byLevel = /* @__PURE__ */ new Map();
1140
- for (const p of getElements(txBody, "a:p")) {
1141
- const pPr = firstChild(p, "a:pPr");
1142
- const level = (pPr && intValue(attr(pPr, "lvl"))) ?? 0;
1143
- const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
1144
- if (runs.length === 0) continue;
1145
- let props = byLevel.get(level);
1146
- if (props === void 0) {
1147
- props = placeholderInheritedRunProps(type, idx, level, ctx);
1148
- byLevel.set(level, props);
1149
- }
1150
- if (!props) continue;
1151
- for (const run of runs) writeRunProps(run, props, pPr, slideLst, level);
1152
- }
1153
- }
870
+ function placeholderInheritedDefRPrs(type, idx, level, ctx) {
871
+ return styleTiers(type, idx, ctx).map((tier) => lstStyleLevelDefRPr(tier, level)).filter((t) => t !== null);
872
+ }
873
+ /**
874
+ * The source list-style tiers a placeholder inherits paragraph formatting from, most specific
875
+ * first. The paragraph-level sibling of {@link placeholderInheritedDefRPrs} — it hands back the
876
+ * tier elements whole rather than pulling one level's properties out of each.
877
+ *
878
+ * The notes tier is included for consistency with the rest of the chain, though it cannot arise
879
+ * in practice: the only caller is the list-style bake in `flattenShape`, which runs on slide and
880
+ * shape contexts, and `ctx.notesStyle` is set only on a notes context.
881
+ */
882
+ function placeholderInheritedListStyles(type, idx, ctx) {
883
+ return styleTiers(type, idx, ctx);
884
+ }
885
+ /**
886
+ * The colour a placeholder run inherits from the source style chain, resolved to a
887
+ * literal `{ hex, transforms }`. Thin wrapper over {@link placeholderInheritedFill}
888
+ * for the flatten path, which re-emits the transforms verbatim. Returns `null`
889
+ * when nothing in the chain defines a resolvable colour (the run then re-binds to
890
+ * the destination).
891
+ */
892
+ function placeholderInheritedColor(type, idx, level, ctx) {
893
+ const colorEl = placeholderInheritedFill(type, idx, level, ctx);
894
+ return colorEl ? resolveColor(colorEl, ctx) : null;
1154
895
  }
1155
896
  /**
1156
- * The run size/weight a placeholder run inherits from the source style chain:
1157
- * layout placeholder `a:lstStyle` → master placeholder `a:lstStyle` → master
1158
- * `p:txStyles` category style, per list level. Each of `sz`/`b`/`i` is taken from
1159
- * the first tier that defines it (properties resolve independently). Returns
1160
- * `null` when no tier defines any of them.
897
+ * The run size/weight a placeholder run inherits from the source style chain, per list level.
898
+ * Each of `sz`/`b`/`i` is taken from the first tier that defines it (properties resolve
899
+ * independently). Returns `null` when no tier defines any of them.
1161
900
  */
1162
901
  function placeholderInheritedRunProps(type, idx, level, ctx) {
1163
902
  const tiers = placeholderInheritedDefRPrs(type, idx, level, ctx);
@@ -1174,141 +913,60 @@ function placeholderInheritedRunProps(type, idx, level, ctx) {
1174
913
  }
1175
914
  return any ? props : null;
1176
915
  }
1177
- /** Whether the *slide itself* already fixes a run property (so a rebind cannot change it). */
1178
- function slideDefinesProp(name, run, pPr, slideLst, level) {
1179
- const rPr = firstChild(run, "a:rPr");
1180
- if (rPr && attr(rPr, name) != null) return true;
1181
- const defRPr = pPr && firstChild(pPr, "a:defRPr");
1182
- if (defRPr && attr(defRPr, name) != null) return true;
1183
- const slideDefRPr = lstStyleLevelDefRPr(slideLst, level);
1184
- return !!(slideDefRPr && attr(slideDefRPr, name) != null);
1185
- }
1186
- /** Write each resolved run property onto a run's `a:rPr`, skipping ones the slide already fixes. */
1187
- function writeRunProps(run, props, pPr, slideLst, level) {
1188
- let rPr = null;
1189
- for (const name of RUN_PROP_NAMES) {
1190
- const value = props[name];
1191
- if (value == null) continue;
1192
- if (slideDefinesProp(name, run, pPr, slideLst, level)) continue;
1193
- rPr ??= getOrAddChild(run, "a:rPr", ["a:t"]);
1194
- setAttr(rPr, name, value);
1195
- }
1196
- }
1197
- /** Snapshot all descendant elements of `root` matching a namespace + local name. */
1198
- function elementsByTag(root, ns, local) {
1199
- const out = [];
1200
- for (const el of root.getElementsByTagNameNS(ns, local)) out.push(el);
1201
- return out;
1202
- }
1203
916
  /**
1204
- * Resolve each shape's `p:style` `lnRef`/`fillRef`/`effectRef` into explicit
1205
- * `spPr` children (using the theme `fmtScheme`), then neutralize the ref. The
1206
- * `fontRef` is intentionally left for the destination theme to re-resolve.
917
+ * The `a:xfrm` a placeholder inherits from the source layout, then master,
918
+ * tagged with which tier it came from — `null` when neither defines one. The
919
+ * read-model `resolveInheritedFrame` (`theme-context.ts`) sibling of
920
+ * {@link placeholderInheritedAnchor}; also the bake source for the flatten pass'
921
+ * `resolvePlaceholderGeometry`.
1207
922
  */
1208
- function materializeStyleRefs(root, ctx) {
1209
- if (!ctx.fmtScheme) return;
1210
- for (const style of elementsByTag(root, OOXML_NS.p, "style")) {
1211
- const shape = style.parentNode;
1212
- if (!shape) continue;
1213
- const spPr = getOrAddChild(shape, "p:spPr", SHAPE_AFTER_SPPR$1);
1214
- materializeFill(spPr, firstChild(style, "a:fillRef"), ctx);
1215
- materializeLine(spPr, firstChild(style, "a:lnRef"), ctx);
1216
- materializeEffect(spPr, firstChild(style, "a:effectRef"), ctx);
1217
- }
1218
- }
1219
- /** Replace every `phClr` under `el` with the ref colour (ref transforms first, then the `phClr`'s own). */
1220
- function substitutePhClr(el, ref) {
1221
- const doc = ownerDocumentOf(el);
1222
- for (const phClr of elementsByTag(el, OOXML_NS.a, "schemeClr")) {
1223
- if (attr(phClr, "val") !== "phClr") continue;
1224
- const srgb = createElement(doc, "a:srgbClr");
1225
- setAttr(srgb, "val", ref.hex);
1226
- for (const t of ref.transforms) srgb.appendChild(t.cloneNode(true));
1227
- while (phClr.firstChild) srgb.appendChild(phClr.firstChild);
1228
- replaceInParent(phClr, srgb);
923
+ function placeholderInheritedXfrm(type, idx, ctx) {
924
+ for (const [root, source] of [[ctx.layoutRoot, "layout"], [ctx.masterRoot, "master"]]) {
925
+ if (!root) continue;
926
+ const ph = findPlaceholder(root, type, idx);
927
+ const spPr = ph && firstChild(ph, "p:spPr");
928
+ const xfrm = spPr && firstChild(spPr, "a:xfrm");
929
+ if (xfrm) return {
930
+ xfrm,
931
+ source
932
+ };
1229
933
  }
1230
- }
1231
- /** The `idx`-th entry (1-based) of a `fmtScheme` style list, deep-cloned, or `null`. */
1232
- function fmtEntry(ctx, listName, idx) {
1233
- const list = ctx.fmtScheme && firstChild(ctx.fmtScheme, listName);
1234
- if (!list || idx < 1) return null;
1235
- const entry = childElements$1(list)[idx - 1];
1236
- return entry ? entry.cloneNode(true) : null;
1237
- }
1238
- /**
1239
- * Build the explicit fill element a `p:style` `a:fillRef` resolves to — the indexed
1240
- * `fmtScheme` `fillStyleLst`/`bgFillStyleLst` entry (deep-cloned) with its `phClr`
1241
- * replaced by the ref's resolved colour. Pure: mutates neither the ref nor the
1242
- * theme. `null` when the ref is absent, `idx` is 0/unset, or the entry or its
1243
- * colour cannot be resolved. Shared by the flatten path ({@link materializeFill})
1244
- * and the read-model `resolveStyleFillColor` getter so both see the same fill.
1245
- */
1246
- function styleRefFill(fillRef, ctx) {
1247
- if (!fillRef) return null;
1248
- const idx = intAttr(fillRef, "idx");
1249
- if (idx === null || idx <= 0) return null;
1250
- const fill = idx >= 1e3 ? fmtEntry(ctx, "a:bgFillStyleLst", idx - 1e3) : fmtEntry(ctx, "a:fillStyleLst", idx);
1251
- const ref = resolveColor(firstChildElement(fillRef), ctx);
1252
- if (!fill || !ref) return null;
1253
- substitutePhClr(fill, ref);
1254
- return fill;
934
+ return null;
1255
935
  }
1256
936
  /**
1257
- * Build the explicit `a:ln` element a `p:style` `a:lnRef` resolves to — the indexed
1258
- * `fmtScheme` `lnStyleLst` entry (deep-cloned) with its `phClr` replaced by the
1259
- * ref's resolved colour. Pure; the line/read counterpart of {@link styleRefFill}.
937
+ * The vertical anchor (`a:bodyPr/@anchor`) a placeholder inherits from the source
938
+ * layout, then master, or `null`. Resolves per-attribute: the first tier whose
939
+ * placeholder `a:bodyPr` actually sets `@anchor` wins, so a layout `a:bodyPr`
940
+ * present but without `@anchor` does not mask the master's. The read-model
941
+ * `TextFrame.resolvedAnchor` sibling of {@link placeholderInheritedXfrm}.
1260
942
  */
1261
- function styleRefLine(lnRef, ctx) {
1262
- if (!lnRef) return null;
1263
- const idx = intAttr(lnRef, "idx");
1264
- if (idx === null || idx <= 0) return null;
1265
- const ln = fmtEntry(ctx, "a:lnStyleLst", idx);
1266
- const ref = resolveColor(firstChildElement(lnRef), ctx);
1267
- if (!ln || !ref) return null;
1268
- substitutePhClr(ln, ref);
1269
- return ln;
1270
- }
1271
- function materializeFill(spPr, fillRef, ctx) {
1272
- if (!fillRef) return;
1273
- if (!FILL_CHOICES.some((q) => firstChild(spPr, q))) {
1274
- const fill = styleRefFill(fillRef, ctx);
1275
- if (fill) insertInOrder(spPr, fill, SPPR_FILL_AFTER$1);
1276
- }
1277
- neutralizeRef(fillRef);
1278
- }
1279
- function materializeLine(spPr, lnRef, ctx) {
1280
- if (!lnRef) return;
1281
- if (!firstChild(spPr, "a:ln")) {
1282
- const ln = styleRefLine(lnRef, ctx);
1283
- if (ln) insertInOrder(spPr, ln, SPPR_LN_AFTER$1);
1284
- }
1285
- neutralizeRef(lnRef);
1286
- }
1287
- function materializeEffect(spPr, effectRef, ctx) {
1288
- if (!effectRef) return;
1289
- const idx = intAttr(effectRef, "idx");
1290
- if (idx !== null && idx > 0 && !firstChild(spPr, "a:effectLst") && !firstChild(spPr, "a:effectDag")) {
1291
- const style = fmtEntry(ctx, "a:effectStyleLst", idx);
1292
- const ref = resolveColor(firstChildElement(effectRef), ctx);
1293
- if (style && ref) {
1294
- substitutePhClr(style, ref);
1295
- for (const child of childElements$1(style)) if (isA(child, "effectLst") || isA(child, "effectDag")) insertInOrder(spPr, child, SPPR_EFFECT_AFTER);
1296
- else if (isA(child, "scene3d")) insertInOrder(spPr, child, ["a:sp3d", "a:extLst"]);
1297
- else if (isA(child, "sp3d")) insertInOrder(spPr, child, ["a:extLst"]);
1298
- }
943
+ function placeholderInheritedAnchor(type, idx, ctx) {
944
+ for (const root of [ctx.layoutRoot, ctx.masterRoot]) {
945
+ if (!root) continue;
946
+ const ph = findPlaceholder(root, type, idx);
947
+ const txBody = ph && firstChild(ph, "p:txBody");
948
+ const bodyPr = txBody && firstChild(txBody, "a:bodyPr");
949
+ const anchor = bodyPr && attr(bodyPr, "anchor");
950
+ if (anchor) return anchor;
1299
951
  }
1300
- neutralizeRef(effectRef);
952
+ return null;
1301
953
  }
1302
- /** Strip a style-matrix ref to `idx="0"` with no colour child so it contributes nothing. */
1303
- function neutralizeRef(ref) {
1304
- setAttr(ref, "idx", "0");
1305
- for (const child of childElements$1(ref)) ref.removeChild(child);
954
+ /** Whether the *slide itself* already fixes this run's colour (so a rebind cannot change it). */
955
+ function slideDefinesColor(run, pPr, slideLst, level) {
956
+ const rPr = firstChild(run, "a:rPr");
957
+ if (rPr && FILL_CHOICES.some((q) => firstChild(rPr, q))) return true;
958
+ const defRPr = pPr && firstChild(pPr, "a:defRPr");
959
+ if (defRPr && firstChild(defRPr, "a:solidFill")) return true;
960
+ return !!lstStyleLevelFill(slideLst, level);
1306
961
  }
1307
- function intAttr(el, name) {
1308
- const value = attr(el, name);
1309
- if (value === null || value === "") return null;
1310
- const n = Number(value);
1311
- return Number.isFinite(n) ? n : null;
962
+ /** Whether the *slide itself* already fixes a run property (so a rebind cannot change it). */
963
+ function slideDefinesProp(name, run, pPr, slideLst, level) {
964
+ const rPr = firstChild(run, "a:rPr");
965
+ if (rPr && attr(rPr, name) != null) return true;
966
+ const defRPr = pPr && firstChild(pPr, "a:defRPr");
967
+ if (defRPr && attr(defRPr, name) != null) return true;
968
+ const slideDefRPr = lstStyleLevelDefRPr(slideLst, level);
969
+ return !!(slideDefRPr && attr(slideDefRPr, name) != null);
1312
970
  }
1313
971
  //#endregion
1314
972
  //#region src/read/oxml/color-transform.ts
@@ -1503,17 +1161,6 @@ function applyColorTransforms(baseHex, transforms) {
1503
1161
  * background needs on top of {@link resolveSlideThemeParts} — so a token resolves
1504
1162
  * identically whether it is read or baked.
1505
1163
  */
1506
- const SLIDE_LAYOUT_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
1507
- const SLIDE_MASTER_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
1508
- const NOTES_MASTER_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster";
1509
- const THEME_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
1510
- const OFFICE_DOCUMENT_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
1511
- /** Resolve the single relationship of `type` owned by `partName`, or `null`. */
1512
- function resolveSingleRel(opc, partName, type) {
1513
- const rels = opc.relationshipsFor(partName);
1514
- const rel = rels.byType(type)[0];
1515
- return rel ? rels.resolveTarget(rel.id) : null;
1516
- }
1517
1164
  /** The document element of a part, or `null` when the partname/part is absent. */
1518
1165
  function documentElement(opc, partName) {
1519
1166
  return partName ? opc.part(partName)?.dom.documentElement ?? null : null;
@@ -1522,7 +1169,7 @@ function documentElement(opc, partName) {
1522
1169
  * The presentation's `p:defaultTextStyle` (`presentation.xml`, reached via the
1523
1170
  * package `officeDocument` relationship), or `null` when absent. This is
1524
1171
  * PowerPoint's lowest-priority text fallback — the bottom tier of a slide run's
1525
- * size/colour/face/bold resolution (see `FlattenContext.defaultTextStyle`).
1172
+ * size/colour/face/bold resolution (see `ThemeContext.defaultTextStyle`).
1526
1173
  */
1527
1174
  function presentationDefaultTextStyle(opc) {
1528
1175
  const root = documentElement(opc, resolveSingleRel(opc, "/", OFFICE_DOCUMENT_REL));
@@ -2044,73 +1691,15 @@ function readPatternFill(container, ctx) {
2044
1691
  //#endregion
2045
1692
  //#region src/read/api/shapes/oxml.ts
2046
1693
  /**
2047
- * Shape-element plumbing: the schema-successor lists that keep a get-or-added child in document
2048
- * order, and the small element lookups every shape kind performs.
1694
+ * Shape-element plumbing: the small element lookups every shape kind performs, plus the
1695
+ * shape-scoped re-exports of the shared schema-successor lists.
2049
1696
  *
2050
1697
  * The successor arrays are the reason a setter can create a missing `a:xfrm` / `a:solidFill` /
2051
1698
  * `a:ln` without corrupting the part: `getOrAddChild` inserts before the first listed sibling it
2052
1699
  * finds, so each list must name exactly the children that legally *follow* the one being added.
1700
+ * They are declared once in `src/ooxml/sequence.ts` (derived from each complexType's sequence)
1701
+ * and re-exported here so the shape modules keep importing them from one place.
2053
1702
  */
2054
- const SPPR_AFTER_XFRM = [
2055
- "a:custGeom",
2056
- "a:prstGeom",
2057
- "a:noFill",
2058
- "a:solidFill",
2059
- "a:gradFill",
2060
- "a:blipFill",
2061
- "a:pattFill",
2062
- "a:grpFill",
2063
- "a:ln",
2064
- "a:effectLst",
2065
- "a:effectDag",
2066
- "a:scene3d",
2067
- "a:sp3d",
2068
- "a:extLst"
2069
- ];
2070
- const GRPSPPR_AFTER_XFRM = [
2071
- "a:noFill",
2072
- "a:solidFill",
2073
- "a:gradFill",
2074
- "a:blipFill",
2075
- "a:pattFill",
2076
- "a:grpFill",
2077
- "a:effectLst",
2078
- "a:effectDag",
2079
- "a:scene3d",
2080
- "a:extLst"
2081
- ];
2082
- const SHAPE_AFTER_SPPR = ["p:style", "p:txBody"];
2083
- const SPPR_FILL_AFTER = [
2084
- "a:ln",
2085
- "a:effectLst",
2086
- "a:effectDag",
2087
- "a:scene3d",
2088
- "a:sp3d",
2089
- "a:extLst"
2090
- ];
2091
- const SPPR_LN_AFTER = [
2092
- "a:effectLst",
2093
- "a:effectDag",
2094
- "a:scene3d",
2095
- "a:sp3d",
2096
- "a:extLst"
2097
- ];
2098
- const GRPSPPR_FILL_AFTER = [
2099
- "a:effectLst",
2100
- "a:effectDag",
2101
- "a:scene3d",
2102
- "a:extLst"
2103
- ];
2104
- const LN_FILL_AFTER = [
2105
- "a:prstDash",
2106
- "a:custDash",
2107
- "a:round",
2108
- "a:bevel",
2109
- "a:miter",
2110
- "a:headEnd",
2111
- "a:tailEnd",
2112
- "a:extLst"
2113
- ];
2114
1703
  /** First `<p:cNvPr>` reached through the shape's non-visual properties wrapper (`p:nv*Pr`). */
2115
1704
  function nonVisualCNvPr(element) {
2116
1705
  for (let node = element.firstChild; node; node = node.nextSibling) {
@@ -2118,24 +1707,141 @@ function nonVisualCNvPr(element) {
2118
1707
  const child = node;
2119
1708
  if (child.namespaceURI === OOXML_NS.p && child.localName?.startsWith("nv")) return firstChild(child, "p:cNvPr");
2120
1709
  }
2121
- return null;
1710
+ return null;
1711
+ }
1712
+ function emuFrom(parent, qname, attribute) {
1713
+ const element = parent && firstChild(parent, qname);
1714
+ return element ? intValue(attr(element, attribute)) : null;
1715
+ }
1716
+ /**
1717
+ * One EMU coordinate from a shape's own `p:spPr/a:xfrm`, or `null` when any link in that chain
1718
+ * is absent — which is how an inheriting placeholder (one with no `a:xfrm` of its own) reports
1719
+ * that its geometry comes from the layout/master instead. See `placeholderInheritedXfrm` for
1720
+ * resolving what it would inherit.
1721
+ */
1722
+ function spPrXfrmEmu(sp, container, axis) {
1723
+ const spPr = firstChild(sp, "p:spPr");
1724
+ const xfrm = spPr && firstChild(spPr, "a:xfrm");
1725
+ const el = xfrm && firstChild(xfrm, container);
1726
+ return el ? intValue(attr(el, axis)) : null;
1727
+ }
1728
+ /** Get-or-add `p:spPr/a:xfrm` for shapes whose transform lives in `p:spPr` (`p:sp`, `p:pic`, `p:cxnSp`). */
1729
+ function getOrAddSpPrXfrm(shapeElement) {
1730
+ return getOrAddChild(getOrAddChild(shapeElement, "p:spPr", SHAPE_AFTER_SPPR), "a:xfrm", SPPR_AFTER_XFRM);
1731
+ }
1732
+ //#endregion
1733
+ //#region src/read/api/shapes/geometry.ts
1734
+ /**
1735
+ * Reading geometry out of a shape: transform boxes, rotation and flips, and custom-geometry paths.
1736
+ *
1737
+ * Every value here comes straight off `a:xfrm` / `a:path` attributes, so these are pure element
1738
+ * readers with no theme or relationship context.
1739
+ */
1740
+ /**
1741
+ * One `a:pt` coordinate as a raw path-unit integer. A guide-name reference
1742
+ * (the `ST_AdjCoordinate` string form) is not produced by authored freeforms;
1743
+ * a non-numeric value degrades to `0` rather than crashing (documented edge).
1744
+ */
1745
+ function ptAxis(pt, axis) {
1746
+ return (pt ? intValue(attr(pt, axis)) : null) ?? 0;
1747
+ }
1748
+ /** Parse one `<a:path>` into its viewport attrs (with schema defaults) and ordered segments. */
1749
+ function readGeometryPath(path) {
1750
+ const commands = [];
1751
+ for (let node = path.firstChild; node; node = node.nextSibling) {
1752
+ if (node.nodeType !== 1) continue;
1753
+ const seg = node;
1754
+ if (seg.namespaceURI !== OOXML_NS.a) continue;
1755
+ const pts = getElements(seg, "a:pt");
1756
+ switch (seg.localName) {
1757
+ case "moveTo":
1758
+ commands.push({
1759
+ cmd: "moveTo",
1760
+ x: ptAxis(pts[0], "x"),
1761
+ y: ptAxis(pts[0], "y")
1762
+ });
1763
+ break;
1764
+ case "lnTo":
1765
+ commands.push({
1766
+ cmd: "lnTo",
1767
+ x: ptAxis(pts[0], "x"),
1768
+ y: ptAxis(pts[0], "y")
1769
+ });
1770
+ break;
1771
+ case "cubicBezTo":
1772
+ commands.push({
1773
+ cmd: "cubicBezTo",
1774
+ x1: ptAxis(pts[0], "x"),
1775
+ y1: ptAxis(pts[0], "y"),
1776
+ x2: ptAxis(pts[1], "x"),
1777
+ y2: ptAxis(pts[1], "y"),
1778
+ x: ptAxis(pts[2], "x"),
1779
+ y: ptAxis(pts[2], "y")
1780
+ });
1781
+ break;
1782
+ case "quadBezTo":
1783
+ commands.push({
1784
+ cmd: "quadBezTo",
1785
+ x1: ptAxis(pts[0], "x"),
1786
+ y1: ptAxis(pts[0], "y"),
1787
+ x: ptAxis(pts[1], "x"),
1788
+ y: ptAxis(pts[1], "y")
1789
+ });
1790
+ break;
1791
+ case "arcTo":
1792
+ commands.push({
1793
+ cmd: "arcTo",
1794
+ wR: intValue(attr(seg, "wR")) ?? 0,
1795
+ hR: intValue(attr(seg, "hR")) ?? 0,
1796
+ stAng: (intValue(attr(seg, "stAng")) ?? 0) / 6e4,
1797
+ swAng: (intValue(attr(seg, "swAng")) ?? 0) / 6e4
1798
+ });
1799
+ break;
1800
+ case "close": commands.push({ cmd: "close" });
1801
+ }
1802
+ }
1803
+ return {
1804
+ w: intValue(attr(path, "w")) ?? 0,
1805
+ h: intValue(attr(path, "h")) ?? 0,
1806
+ fill: attr(path, "fill") ?? "norm",
1807
+ stroke: boolValue(attr(path, "stroke")) ?? true,
1808
+ commands
1809
+ };
2122
1810
  }
2123
- function emuFrom(parent, qname, attribute) {
2124
- const element = parent && firstChild(parent, qname);
2125
- return element ? intValue(attr(element, attribute)) : null;
1811
+ /** Validate and round an EMU geometry value; extents (`cx`/`cy`) must be non-negative. */
1812
+ function toEmu(value, attribute, allowNegative) {
1813
+ if (!Number.isFinite(value)) throw new InvalidOptionError("coord/non-finite", `${attribute} must be a finite number of EMU, got ${value}`);
1814
+ if (!allowNegative && value < 0) throw new InvalidOptionError("coord/negative", `${attribute} must be non-negative, got ${value}`);
1815
+ return Math.round(value);
2126
1816
  }
2127
- /** Direct child *elements* of `parent`, in document order. */
2128
- function childElements(parent) {
2129
- const out = [];
2130
- for (let node = parent.firstChild; node; node = node.nextSibling) if (node.nodeType === 1) out.push(node);
2131
- return out;
1817
+ /** A point + extent pair (`a:off`/`a:ext` or `a:chOff`/`a:chExt`) from a transform, or `null` if either is incomplete. */
1818
+ function readBox(xfrm, offName, extName) {
1819
+ const off = firstChild(xfrm, offName);
1820
+ const ext = firstChild(xfrm, extName);
1821
+ const x = off && intValue(attr(off, "x"));
1822
+ const y = off && intValue(attr(off, "y"));
1823
+ const cx = ext && intValue(attr(ext, "cx"));
1824
+ const cy = ext && intValue(attr(ext, "cy"));
1825
+ if (x === null || y === null || cx === null || cy === null) return null;
1826
+ return {
1827
+ x,
1828
+ y,
1829
+ cx,
1830
+ cy
1831
+ };
2132
1832
  }
2133
- /** Get-or-add `p:spPr/a:xfrm` for shapes whose transform lives in `p:spPr` (`p:sp`, `p:pic`, `p:cxnSp`). */
2134
- function getOrAddSpPrXfrm(shapeElement) {
2135
- return getOrAddChild(getOrAddChild(shapeElement, "p:spPr", SHAPE_AFTER_SPPR), "a:xfrm", SPPR_AFTER_XFRM);
1833
+ function rotationDegrees(xfrm) {
1834
+ const rot = intValue(attr(xfrm, "rot"));
1835
+ return rot === null ? 0 : rot / 6e4;
1836
+ }
1837
+ function transformFlipH(xfrm) {
1838
+ return boolValue(attr(xfrm, "flipH")) === true;
1839
+ }
1840
+ function transformFlipV(xfrm) {
1841
+ return boolValue(attr(xfrm, "flipV")) === true;
2136
1842
  }
2137
1843
  //#endregion
2138
- //#region src/read/group-transform.ts
1844
+ //#region src/read/api/shapes/group-transform.ts
2139
1845
  /** Normalise a degree value into [0, 360). */
2140
1846
  function normalizeDegrees(value) {
2141
1847
  return (value % 360 + 360) % 360;
@@ -2664,22 +2370,68 @@ var Paragraph = class {
2664
2370
  return this.#emuAttrPt("indent");
2665
2371
  }
2666
2372
  /**
2667
- * Bullet description for this paragraph, derived from the `a:pPr` bullet
2668
- * children, or `null` when unset (inherited from the list style):
2669
- * - `'none'` — explicit `a:buNone` (bullet suppressed)
2670
- * - `'char:•'` — `a:buChar/@char` (the literal glyph follows the colon)
2671
- * - `'autoNum:arabicPeriod'` — `a:buAutoNum/@type` (auto-numbered)
2373
+ * This paragraph's bullet — its kind, and for a drawn bullet the glyph, the
2374
+ * numbering start, and the bullet's own font/size/colour. `null` when the
2375
+ * paragraph names no bullet at all and inherits one from the list style.
2376
+ *
2377
+ * Structured rather than a tagged string, which is not merely tidier. The
2378
+ * previous `bullet` accessor reported `'none'` / `'char:•'` /
2379
+ * `'autoNum:arabicPeriod'`, and that shape is ambiguous when the glyph is
2380
+ * itself a colon; worse, it reads as a bare glyph, which is exactly how the
2381
+ * script converter first consumed it — `'none'.codePointAt(0)` put a literal
2382
+ * `n` bullet on every converted deck, silently. See {@link BulletDetail}.
2672
2383
  */
2673
- get bullet() {
2384
+ get bulletDetail() {
2674
2385
  const pPr = firstChild(this.element, "a:pPr");
2675
2386
  if (!pPr) return null;
2676
- if (firstChild(pPr, "a:buNone")) return "none";
2387
+ if (firstChild(pPr, "a:buNone")) return { kind: "none" };
2388
+ const style = this.#bulletStyle(pPr);
2677
2389
  const buChar = firstChild(pPr, "a:buChar");
2678
- if (buChar) return `char:${attr(buChar, "char") ?? ""}`;
2390
+ if (buChar) return {
2391
+ kind: "char",
2392
+ char: attr(buChar, "char") ?? "",
2393
+ ...style
2394
+ };
2679
2395
  const buAutoNum = firstChild(pPr, "a:buAutoNum");
2680
- if (buAutoNum) return `autoNum:${attr(buAutoNum, "type") ?? ""}`;
2396
+ if (buAutoNum) return {
2397
+ kind: "autoNum",
2398
+ scheme: attr(buAutoNum, "type") ?? "",
2399
+ startAt: intValue(attr(buAutoNum, "startAt")),
2400
+ ...style
2401
+ };
2402
+ const buBlip = firstChild(pPr, "a:buBlip");
2403
+ if (buBlip) return {
2404
+ kind: "picture",
2405
+ imagePartName: this.#bulletImagePartName(buBlip),
2406
+ ...style
2407
+ };
2681
2408
  return null;
2682
2409
  }
2410
+ /** The `a:buFont` / `a:buSz*` / `a:buClr` siblings of a `a:pPr` bullet choice. */
2411
+ #bulletStyle(pPr) {
2412
+ const buFont = firstChild(pPr, "a:buFont");
2413
+ const buSzPct = firstChild(pPr, "a:buSzPct");
2414
+ const buSzPts = firstChild(pPr, "a:buSzPts");
2415
+ const buClr = firstChild(pPr, "a:buClr");
2416
+ const colorEl = buClr ? firstChildElement(buClr) : null;
2417
+ const pctVal = buSzPct ? intValue(attr(buSzPct, "val")) : null;
2418
+ const ptVal = buSzPts ? intValue(attr(buSzPts, "val")) : null;
2419
+ return {
2420
+ font: buFont ? attr(buFont, "typeface") ?? null : null,
2421
+ sizePct: pctVal === null ? null : pctVal / 1e3,
2422
+ sizePt: ptVal === null ? null : ptVal / 100,
2423
+ color: colorEl?.localName === "srgbClr" ? attr(colorEl, "val") ?? null : null,
2424
+ schemeColor: colorEl?.localName === "schemeClr" ? attr(colorEl, "val") ?? null : null,
2425
+ resolvedColor: this.themeContext ? resolveColorElement(colorEl, this.themeContext) : null
2426
+ };
2427
+ }
2428
+ /** Resolve a picture bullet's `a:buBlip/a:blip/@r:embed` to an absolute partname. */
2429
+ #bulletImagePartName(buBlip) {
2430
+ const blip = firstChild(buBlip, "a:blip");
2431
+ const relId = blip && attr(blip, "r:embed");
2432
+ if (!relId || !this.relationships) return null;
2433
+ return this.relationships.resolveTarget(relId);
2434
+ }
2683
2435
  /** Points from a spacing child's `a:spcPts/@val` (hundredths of a point), or `null`. */
2684
2436
  #spacingPt(qname) {
2685
2437
  const pPr = firstChild(this.element, "a:pPr");
@@ -2862,7 +2614,7 @@ function setTextBodyText(txBody, value) {
2862
2614
  p = createElement(doc, "a:p");
2863
2615
  txBody.appendChild(p);
2864
2616
  }
2865
- for (const child of [...childElements$2(p)]) if (child.localName === "r" || child.localName === "br" || child.localName === "fld") p.removeChild(child);
2617
+ for (const child of childElements(p)) if (child.localName === "r" || child.localName === "br" || child.localName === "fld") p.removeChild(child);
2866
2618
  const run = createElement(doc, "a:r");
2867
2619
  if (rPrTemplate) run.appendChild(rPrTemplate.cloneNode(true));
2868
2620
  const t = createElement(doc, "a:t");
@@ -2874,117 +2626,6 @@ function setTextBodyText(txBody, value) {
2874
2626
  p.insertBefore(run, endParaRPr);
2875
2627
  }
2876
2628
  //#endregion
2877
- //#region src/read/api/shapes/geometry.ts
2878
- /**
2879
- * Reading geometry out of a shape: transform boxes, rotation and flips, and custom-geometry paths.
2880
- *
2881
- * Every value here comes straight off `a:xfrm` / `a:path` attributes, so these are pure element
2882
- * readers with no theme or relationship context.
2883
- */
2884
- /**
2885
- * One `a:pt` coordinate as a raw path-unit integer. A guide-name reference
2886
- * (the `ST_AdjCoordinate` string form) is not produced by authored freeforms;
2887
- * a non-numeric value degrades to `0` rather than crashing (documented edge).
2888
- */
2889
- function ptAxis(pt, axis) {
2890
- return (pt ? intValue(attr(pt, axis)) : null) ?? 0;
2891
- }
2892
- /** Parse one `<a:path>` into its viewport attrs (with schema defaults) and ordered segments. */
2893
- function readGeometryPath(path) {
2894
- const commands = [];
2895
- for (let node = path.firstChild; node; node = node.nextSibling) {
2896
- if (node.nodeType !== 1) continue;
2897
- const seg = node;
2898
- if (seg.namespaceURI !== OOXML_NS.a) continue;
2899
- const pts = getElements(seg, "a:pt");
2900
- switch (seg.localName) {
2901
- case "moveTo":
2902
- commands.push({
2903
- cmd: "moveTo",
2904
- x: ptAxis(pts[0], "x"),
2905
- y: ptAxis(pts[0], "y")
2906
- });
2907
- break;
2908
- case "lnTo":
2909
- commands.push({
2910
- cmd: "lnTo",
2911
- x: ptAxis(pts[0], "x"),
2912
- y: ptAxis(pts[0], "y")
2913
- });
2914
- break;
2915
- case "cubicBezTo":
2916
- commands.push({
2917
- cmd: "cubicBezTo",
2918
- x1: ptAxis(pts[0], "x"),
2919
- y1: ptAxis(pts[0], "y"),
2920
- x2: ptAxis(pts[1], "x"),
2921
- y2: ptAxis(pts[1], "y"),
2922
- x: ptAxis(pts[2], "x"),
2923
- y: ptAxis(pts[2], "y")
2924
- });
2925
- break;
2926
- case "quadBezTo":
2927
- commands.push({
2928
- cmd: "quadBezTo",
2929
- x1: ptAxis(pts[0], "x"),
2930
- y1: ptAxis(pts[0], "y"),
2931
- x: ptAxis(pts[1], "x"),
2932
- y: ptAxis(pts[1], "y")
2933
- });
2934
- break;
2935
- case "arcTo":
2936
- commands.push({
2937
- cmd: "arcTo",
2938
- wR: intValue(attr(seg, "wR")) ?? 0,
2939
- hR: intValue(attr(seg, "hR")) ?? 0,
2940
- stAng: (intValue(attr(seg, "stAng")) ?? 0) / 6e4,
2941
- swAng: (intValue(attr(seg, "swAng")) ?? 0) / 6e4
2942
- });
2943
- break;
2944
- case "close": commands.push({ cmd: "close" });
2945
- }
2946
- }
2947
- return {
2948
- w: intValue(attr(path, "w")) ?? 0,
2949
- h: intValue(attr(path, "h")) ?? 0,
2950
- fill: attr(path, "fill") ?? "norm",
2951
- stroke: boolValue(attr(path, "stroke")) ?? true,
2952
- commands
2953
- };
2954
- }
2955
- /** Validate and round an EMU geometry value; extents (`cx`/`cy`) must be non-negative. */
2956
- function toEmu(value, attribute, allowNegative) {
2957
- if (!Number.isFinite(value)) throw new InvalidOptionError("coord/non-finite", `${attribute} must be a finite number of EMU, got ${value}`);
2958
- if (!allowNegative && value < 0) throw new InvalidOptionError("coord/negative", `${attribute} must be non-negative, got ${value}`);
2959
- return Math.round(value);
2960
- }
2961
- /** A point + extent pair (`a:off`/`a:ext` or `a:chOff`/`a:chExt`) from a transform, or `null` if either is incomplete. */
2962
- function readBox(xfrm, offName, extName) {
2963
- const off = firstChild(xfrm, offName);
2964
- const ext = firstChild(xfrm, extName);
2965
- const x = off && intValue(attr(off, "x"));
2966
- const y = off && intValue(attr(off, "y"));
2967
- const cx = ext && intValue(attr(ext, "cx"));
2968
- const cy = ext && intValue(attr(ext, "cy"));
2969
- if (x === null || y === null || cx === null || cy === null) return null;
2970
- return {
2971
- x,
2972
- y,
2973
- cx,
2974
- cy
2975
- };
2976
- }
2977
- function rotationDegrees(xfrm) {
2978
- const rot = intValue(attr(xfrm, "rot"));
2979
- return rot === null ? 0 : rot / 6e4;
2980
- }
2981
- function transformFlipH(xfrm) {
2982
- return boolValue(attr(xfrm, "flipH")) === true;
2983
- }
2984
- function transformFlipV(xfrm) {
2985
- return boolValue(attr(xfrm, "flipV")) === true;
2986
- }
2987
- //#endregion
2988
2629
  //#region src/read/api/shapes/base.ts
2989
2630
  /**
2990
2631
  * The abstract base every shape kind extends.
@@ -3283,9 +2924,25 @@ var Shape = class {
3283
2924
  });
3284
2925
  }
3285
2926
  /**
2927
+ * `true` when the shape sets an explicit no-fill (`spPr/a:noFill`) — a
2928
+ * deliberately transparent surface. The fill-side counterpart of
2929
+ * {@link lineNoFill}, and the only accessor that separates it from a shape
2930
+ * carrying no fill child at all (one inheriting through `p:style/a:fillRef`):
2931
+ * every other fill accessor — {@link fillColor}, {@link fillSchemeColor},
2932
+ * {@link resolvedFill}, {@link gradientFill}, {@link patternFill},
2933
+ * {@link pictureFill} — reports `null` for both. The two paint completely
2934
+ * differently, so a consumer that cannot tell them apart paints a transparent
2935
+ * shape in the theme's accent colour.
2936
+ */
2937
+ get fillNoFill() {
2938
+ const props = this.properties();
2939
+ return !!(props && firstChild(props, "a:noFill"));
2940
+ }
2941
+ /**
3286
2942
  * Set an explicit `<a:noFill/>` on the shape — a transparent surface. This is
3287
2943
  * distinct from clearing the fill (`fillColor = null`), which removes the
3288
2944
  * `a:solidFill` and lets the fill inherit from the shape's style/placeholder.
2945
+ * Read it back with {@link fillNoFill}.
3289
2946
  */
3290
2947
  noFill() {
3291
2948
  if (!this.supportsFill) throw new UnsupportedFeatureError("shape/fill-unsupported", `${this.shapeType} shapes do not support a solid fill`);
@@ -3343,6 +3000,32 @@ var Shape = class {
3343
3000
  return !!(ln && firstChild(ln, "a:noFill"));
3344
3001
  }
3345
3002
  /**
3003
+ * The line end cap (`spPr/a:ln/@cap`) as the raw OOXML token — `'flat'`,
3004
+ * `'rnd'` (round) or `'sq'` (square) — or `null` when unset (PowerPoint's
3005
+ * default is `flat`). The write API authors this attribute through
3006
+ * `ShapeLineProps.cap`, so without the accessor a deck this library produced
3007
+ * could not be read back without losing it.
3008
+ *
3009
+ * Not cosmetic on a thick dashed rule: the cap decides whether each dash reads
3010
+ * as a rectangle or a lozenge, and it extends every dash by the stroke width.
3011
+ * SVG's `stroke-linecap` is the exact equivalent (`flat`→`butt`, `rnd`→`round`,
3012
+ * `sq`→`square`).
3013
+ */
3014
+ get lineCap() {
3015
+ const ln = this.#line();
3016
+ return ln ? attr(ln, "cap") ?? null : null;
3017
+ }
3018
+ /**
3019
+ * The line alignment (`spPr/a:ln/@algn`) as the raw OOXML token — `'ctr'`
3020
+ * (centred on the shape's outline) or `'in'` (inset, drawn wholly inside it) —
3021
+ * or `null` when unset. It shifts a thick outline by half its width, so it
3022
+ * changes where the border sits relative to the fill.
3023
+ */
3024
+ get lineAlign() {
3025
+ const ln = this.#line();
3026
+ return ln ? attr(ln, "algn") ?? null : null;
3027
+ }
3028
+ /**
3346
3029
  * Preset geometry name (`spPr/a:prstGeom/@prst`, e.g. `rect`), or `null` for
3347
3030
  * custom geometry or none. Not an auto-shape-only property: PowerPoint gives a
3348
3031
  * picture and a connector a preset geometry too (a `p:pic` is `rect` unless it
@@ -3743,7 +3426,6 @@ var AutoShape = class extends Shape {
3743
3426
  * blip plumbing (content-type → extension, the SVG extension blip, the recolour effects) lives
3744
3427
  * here rather than on the base: no other shape kind carries it.
3745
3428
  */
3746
- const IMAGE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
3747
3429
  const ASVG_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main";
3748
3430
  const PIC_AFTER_BLIPFILL = ["p:spPr", "p:style"];
3749
3431
  const BLIPFILL_AFTER_BLIP = [
@@ -3986,7 +3668,7 @@ var Picture = class extends Shape {
3986
3668
  const opc = this.slide.presentation.opc;
3987
3669
  const mediaPartName = opc.reserveMediaPartName(extension);
3988
3670
  opc.addPart(mediaPartName, contentType, bytes);
3989
- const relId = this.slide.relationships.add(IMAGE_REL_TYPE, relativePartName(this.slide.partName, mediaPartName)).id;
3671
+ const relId = this.slide.relationships.add(IMAGE_REL, relativePartName(this.slide.partName, mediaPartName)).id;
3990
3672
  setAttr(this.#getOrAddBlip(), "r:embed", relId);
3991
3673
  if (options.fit) this.#applyFit(options.fit, bytes);
3992
3674
  this.markDirty();
@@ -4115,7 +3797,7 @@ var Chart = class {
4115
3797
  for (let node = plotArea.firstChild; node; node = node.nextSibling) {
4116
3798
  if (node.nodeType !== 1) continue;
4117
3799
  const element = node;
4118
- if (element.namespaceURI === OOXML_NS.c && /Ax$/.test(element.localName ?? "")) out.push(new ChartAxis(element, this.part));
3800
+ if (element.namespaceURI === OOXML_NS.c && (element.localName ?? "").endsWith("Ax")) out.push(new ChartAxis(element, this.part));
4119
3801
  }
4120
3802
  return out;
4121
3803
  }
@@ -4372,7 +4054,7 @@ var ChartSeries = class {
4372
4054
  /** Cached numeric values (`c:val`); non-numeric or missing points are `null`. */
4373
4055
  get values() {
4374
4056
  const val = firstChild(this.ser, "c:val");
4375
- return readPoints(val && findCache(val)).map(toNumberOrNull$1);
4057
+ return readPoints(val && findCache(val)).map(intValue);
4376
4058
  }
4377
4059
  /** Cached category labels for this series (`c:cat`), as written. */
4378
4060
  get categories() {
@@ -4460,11 +4142,6 @@ function readPoints(cache) {
4460
4142
  }
4461
4143
  return points;
4462
4144
  }
4463
- function toNumberOrNull$1(value) {
4464
- if (value === null || value === "") return null;
4465
- const number = Number(value);
4466
- return Number.isFinite(number) ? number : null;
4467
- }
4468
4145
  //#endregion
4469
4146
  //#region src/read/api/chartex.ts
4470
4147
  /** A chartEx graphic-frame's chart, backed by its `cx:chartSpace` part. */
@@ -4608,7 +4285,7 @@ var ChartExSeries = class {
4608
4285
  get values() {
4609
4286
  const data = this.chart.dataElementById(this.dataId);
4610
4287
  const numDim = data && firstChild(data, "cx:numDim");
4611
- return readLevelPoints(numDim && firstChild(numDim, "cx:lvl")).map(toNumberOrNull);
4288
+ return readLevelPoints(numDim && firstChild(numDim, "cx:lvl")).map(intValue);
4612
4289
  }
4613
4290
  /**
4614
4291
  * Cached category labels (`cx:strDim`'s leaf `cx:lvl` — the first level, which
@@ -4726,56 +4403,30 @@ function floatValue(value) {
4726
4403
  const number = Number(value);
4727
4404
  return Number.isFinite(number) ? number : null;
4728
4405
  }
4729
- function toNumberOrNull(value) {
4730
- if (value === null || value === "") return null;
4731
- const number = Number(value);
4732
- return Number.isFinite(number) ? number : null;
4733
- }
4734
4406
  //#endregion
4735
4407
  //#region src/read/api/table-edit.ts
4736
4408
  /**
4737
- * Ordered mutation of a table cell's `a:tcPr`, and the schema facts every such edit needs.
4409
+ * Ordered mutation of a table cell's `a:tcPr`, and the cell-scoped schema facts every such
4410
+ * edit needs.
4738
4411
  *
4739
4412
  * `CT_TableCellProperties` declares its children as a **sequence**, so an append-only
4740
4413
  * implementation produces an out-of-order `a:tcPr` — which PowerPoint reports as a corrupt
4741
4414
  * file rather than as a bad edit. Every insertion therefore goes through
4742
- * {@link getOrAddChild} / {@link insertInOrder} with the new element's *successors*, which
4743
- * is what {@link TCPR_AFTER} tabulates. Writing that table once, here, is the point of this
4744
- * module: a setter that hand-rolls its own successor list is one rename away from silently
4745
- * producing an invalid part.
4415
+ * {@link getOrAddChild} / {@link insertInOrder} with the new element's *successors*, which is
4416
+ * what `TCPR_AFTER` tabulates; it and the sequence it derives from live in
4417
+ * `src/ooxml/sequence.ts` alongside the other complexType orderings.
4746
4418
  *
4747
4419
  * The attribute values are the other half. A value outside its `ST_` union is equally fatal
4748
4420
  * and equally silent, so each is checked against the enum before it is written — the same
4749
4421
  * validate-at-the-boundary rule the write path follows, with the difference that here there
4750
- * is a caller to throw at rather than a deck to degrade.
4751
- */
4752
- /**
4753
- * `CT_TableCellProperties`' child sequence, in declaration order.
4754
- * @see ECMA-376 Part 1 §21.1.3.17 (`a:tcPr`)
4755
- */
4756
- const TCPR_SEQUENCE = [
4757
- "a:lnL",
4758
- "a:lnR",
4759
- "a:lnT",
4760
- "a:lnB",
4761
- "a:lnTlToBr",
4762
- "a:lnBlToTr",
4763
- "a:cell3D",
4764
- "a:noFill",
4765
- "a:solidFill",
4766
- "a:gradFill",
4767
- "a:blipFill",
4768
- "a:pattFill",
4769
- "a:grpFill",
4770
- "a:headers",
4771
- "a:extLst"
4772
- ];
4773
- /**
4774
- * For each `a:tcPr` child, the children that must follow it — i.e. what a new one is
4775
- * inserted *before*. Derived from {@link TCPR_SEQUENCE} rather than written out, so the two
4776
- * cannot disagree and adding a child to the sequence updates every successor list at once.
4422
+ * is a caller to throw at rather than a deck to degrade (see `ooxml/check-enum.ts`).
4777
4423
  */
4778
- const TCPR_AFTER = Object.fromEntries(TCPR_SEQUENCE.map((qname, index) => [qname, TCPR_SEQUENCE.slice(index + 1)]));
4424
+ /** `ST_TextAnchoringType` — `a:tcPr/@anchor`. */
4425
+ const ANCHOR_VALUES = TEXT_ANCHORS;
4426
+ /** `ST_TextVerticalType` — `a:tcPr/@vert`. */
4427
+ const VERT_VALUES = TEXT_VERTICAL;
4428
+ /** `ST_TextHorzOverflowType` — `a:tcPr/@horzOverflow`. */
4429
+ const HORZ_OVERFLOW_VALUES = TEXT_HORZ_OVERFLOW;
4779
4430
  /** The four edges plus the two diagonals, keyed as {@link TableCellEdge} names them. */
4780
4431
  const EDGE_QNAMES = {
4781
4432
  left: "a:lnL",
@@ -4785,45 +4436,6 @@ const EDGE_QNAMES = {
4785
4436
  tlToBr: "a:lnTlToBr",
4786
4437
  blToTr: "a:lnBlToTr"
4787
4438
  };
4788
- /** `ST_TextAnchoringType` — `a:tcPr/@anchor`. */
4789
- const ANCHOR_VALUES = [
4790
- "t",
4791
- "ctr",
4792
- "b",
4793
- "just",
4794
- "dist"
4795
- ];
4796
- /** `ST_TextVerticalType` — `a:tcPr/@vert`. */
4797
- const VERT_VALUES = [
4798
- "horz",
4799
- "vert",
4800
- "vert270",
4801
- "wordArtVert",
4802
- "eaVert",
4803
- "mongolianVert",
4804
- "wordArtVertRtl"
4805
- ];
4806
- /** `ST_TextHorzOverflowType` — `a:tcPr/@horzOverflow`. */
4807
- const HORZ_OVERFLOW_VALUES = ["clip", "overflow"];
4808
- /**
4809
- * Check a value against its `ST_` union, throwing when it is outside.
4810
- *
4811
- * Throwing rather than warn-and-drop, which is the opposite of what the *write* path does
4812
- * with the same enums — and deliberately so. On the write path an option comes from a deck
4813
- * being built, and dropping one value is better than failing a whole build; here it comes
4814
- * from a caller editing one attribute, so silently doing nothing would leave them looking at
4815
- * an unchanged deck with no explanation.
4816
- *
4817
- * @param {string} value - the value the caller asked for
4818
- * @param {readonly string[]} valid - the enum's members
4819
- * @param {string} attribute - the attribute's name, for the message
4820
- * @param {InvalidOptionErrorCode} code - the condition to report
4821
- * @returns {string} `value`, when it is legal
4822
- */
4823
- function checkEnum(value, valid, attribute, code) {
4824
- if (valid.includes(value)) return value;
4825
- throw new InvalidOptionError(code, `Invalid ${attribute}: ${JSON.stringify(value)}. Expected one of: ${valid.join(", ")}.`);
4826
- }
4827
4439
  /**
4828
4440
  * Get or create a child of `a:tcPr` at its schema position.
4829
4441
  * @param {Element} tcPr - the cell's properties element
@@ -5756,7 +5368,7 @@ var TableCell = class {
5756
5368
  this.part.markDirty();
5757
5369
  return;
5758
5370
  }
5759
- const checked = checkEnum(value, valid, name, code);
5371
+ const checked = checkEnumOrThrow(value, valid, name, code);
5760
5372
  setAttr(this.#getOrAddTcPr(), name, checked);
5761
5373
  this.part.markDirty();
5762
5374
  }
@@ -5813,6 +5425,27 @@ var TableCell = class {
5813
5425
  return !!tcPr && FILL_CHOICES.some((q) => firstChild(tcPr, q));
5814
5426
  }
5815
5427
  /**
5428
+ * `true` when the cell sets an explicit no-fill (`a:tcPr/a:noFill`) — a deliberately
5429
+ * transparent cell showing the table background (or the slide) through. The cell-side
5430
+ * counterpart of {@link import('./shapes.js').AutoShape.fillNoFill}, and what
5431
+ * {@link noFill} writes.
5432
+ *
5433
+ * {@link hasOwnFill} is not this question: it is `true` for *any* `EG_FillProperties`
5434
+ * child, so on its own it cannot separate a suppressed fill from a gradient or an image
5435
+ * one — and every colour accessor ({@link resolvedFill}, {@link fillColor},
5436
+ * {@link fillSchemeColor}) reports `null` for a no-fill cell exactly as it does for a
5437
+ * cell that inherits its shading from the table style. Deriving it as "has a fill of its
5438
+ * own, and no accessor recognises it" instead of reading it has two failure modes: it
5439
+ * folds `a:grpFill` in with `a:noFill`, and its meaning changes silently the day a
5440
+ * further fill kind gets an accessor. The two paint completely differently — an
5441
+ * inherited banding colour versus nothing at all — so a consumer that cannot tell them
5442
+ * apart paints a transparent cell in the style's shading.
5443
+ */
5444
+ get fillNoFill() {
5445
+ const tcPr = this.#tcPr();
5446
+ return !!tcPr && !!firstChild(tcPr, "a:noFill");
5447
+ }
5448
+ /**
5816
5449
  * The cell's picture (image) fill (`a:tcPr/a:blipFill`), or `null` when the cell
5817
5450
  * is not image-filled. The cell counterpart of
5818
5451
  * {@link import('./shapes.js').AutoShape.pictureFill}: {@link resolvedFill}
@@ -6168,6 +5801,30 @@ var GroupShape = class extends Shape {
6168
5801
  "p:graphicFrame"
6169
5802
  ]);
6170
5803
  }
5804
+ /**
5805
+ * The group's own child coordinate space (`p:grpSpPr/a:xfrm/a:chOff` and
5806
+ * `a:chExt`) in EMU, or `null` when the group has no transform or either
5807
+ * element is incomplete.
5808
+ *
5809
+ * Most consumers should not need this: {@link Shape.absoluteFrame} already
5810
+ * composes the whole ancestor chain — child space, group flips and rotations —
5811
+ * and doing that arithmetic per consumer is how a shape in a nested group ends
5812
+ * up subtly displaced. It is here for a *replica* consumer rather than a
5813
+ * *paint* one: rebuilding this group and its children as OOXML needs the
5814
+ * source child space to reproduce the scaling, and without it only groups whose
5815
+ * child space is the identity can be rebuilt.
5816
+ */
5817
+ get childFrame() {
5818
+ const xfrm = this.xfrm();
5819
+ const box = xfrm && readBox(xfrm, "a:chOff", "a:chExt");
5820
+ if (!box) return null;
5821
+ return {
5822
+ offsetX: box.x,
5823
+ offsetY: box.y,
5824
+ extentX: box.cx,
5825
+ extentY: box.cy
5826
+ };
5827
+ }
6171
5828
  /** The shapes nested directly inside this group, in document order. */
6172
5829
  get shapes() {
6173
5830
  return buildShapes(this.element, this.slide);
@@ -6248,6 +5905,6 @@ function buildShapes(parent, slide) {
6248
5905
  return shapes;
6249
5906
  }
6250
5907
  //#endregion
6251
- export { createElement as $, resolveLayoutColorContext as A, remapLiteralColors as B, Paragraph as C, readPictureFill as D, readPatternFill as E, applyColorTransforms as F, relativePartName as G, styleRefFill as H, flattenShape as I, zipPathToPartName as J, relsPartNameFor as K, flattenSlide as L, resolveNotesColorContext as M, resolveSlideColorContext as N, readGradientFill as O, resolveSlideThemeParts as P, childElements$2 as Q, parseClrMap as R, Shape as S, TextFrame as T, partNameExtension as U, restyleSlide as V, partNameToZipPath as W, attr as X, OOXML_NS as Y, boolValue as Z, ChartAxis as _, isGraphicFrame as a, insertInOrder as at, Picture as b, wrapShapeElement as c, parseXml as ct, TableCell as d, serializeXml as dt, escapeXmlAttribute as et, TableRow as f, setAttr as ft, Chart as g, ChartExSeries as h, isConnector as i, getOrAddChild as it, resolveMasterColorContext as j, resolveColorElement as k, GraphicFrame as l, removeAttr as lt, ChartExAxis as m, buildShapes as n, firstChildElement as nt, isGroupShape as o, intValue as ot, ChartEx as p, resolveRelativePartName as q, isAutoShape as r, getElements as rt, isPicture as s, ownerDocumentOf as st, GroupShape as t, firstChild as tt, Table as u, removeChildrenByQName as ut, ChartSeries as v, Run as w, AutoShape as x, Connector as y, parseClrScheme as z };
5908
+ export { resolveColor as $, resolveColorElement as A, getOrAddChild as At, placeholderInheritedColor as B, Paragraph as C, childElements as Ct, readPatternFill as D, firstChild as Dt, spPrXfrmEmu as E, escapeXmlAttribute as Et, resolveSlideThemeParts as F, removeAttr as Ft, slideDefinesColor as G, placeholderInheritedRunProps as H, applyColorTransforms as I, removeChildrenByQName as It, fmtEntry as J, slideDefinesProp as K, LST_STYLE_LEVELS as L, replaceInParent as Lt, resolveMasterColorContext as M, intValue as Mt, resolveNotesColorContext as N, ownerDocumentOf as Nt, readPictureFill as O, firstChildElement as Ot, resolveSlideColorContext as P, parseXml as Pt, parseClrScheme as Q, RUN_PROP_NAMES as R, serializeXml as Rt, Shape as S, boolValue as St, TextFrame as T, descendantsByTag as Tt, placeholderInheritedXfrm as U, placeholderInheritedListStyles as V, placeholderOf as W, isA as X, intAttr as Y, parseClrMap as Z, ChartAxis as _, resolveRelativePartName as _t, isGraphicFrame as a, RPR_FILL_AFTER as at, Picture as b, OOXML_NS as bt, wrapShapeElement as c, SPPR_EFFECT_AFTER as ct, TableCell as d, SPPR_SCENE3D_AFTER as dt, resolveSchemeToken as et, TableRow as f, SPPR_SP3D_AFTER as ft, Chart as g, relsPartNameFor as gt, ChartExSeries as h, relativePartName as ht, isConnector as i, FILL_CHOICES as it, resolveLayoutColorContext as j, insertInOrder as jt, readGradientFill as k, getElements as kt, GraphicFrame as l, SPPR_FILL_AFTER as lt, ChartExAxis as m, partNameToZipPath as mt, buildShapes as n, styleRefLine as nt, isGroupShape as o, SHAPE_AFTER_SPPR as ot, ChartEx as p, partNameExtension as pt, SCHEME_SLOTS as q, isAutoShape as r, substitutePhClr as rt, isPicture as s, SPPR_AFTER_XFRM as st, GroupShape as t, styleRefFill as tt, Table as u, SPPR_LN_AFTER as ut, ChartSeries as v, resolveSingleRel as vt, Run as w, createElement as wt, AutoShape as x, attr as xt, Connector as y, zipPathToPartName as yt, placeholderInheritedAnchor as z, setAttr as zt };
6252
5909
 
6253
- //# sourceMappingURL=shapes-CaOgR0i1.js.map
5910
+ //# sourceMappingURL=shapes-DMThLsZN.js.map