@shbernal/ts-pptx 3.3.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/{autopage-D1sqK6j7.js → autopage-BYlTzX-l.js} +8 -5
  2. package/dist/autopage-BYlTzX-l.js.map +1 -0
  3. package/dist/browser.d.ts +5 -5
  4. package/dist/browser.js +11 -11
  5. package/dist/browser.js.map +1 -1
  6. package/dist/{diagnostics-B2yWpcjB.d.ts → diagnostics-BDuR8UkG.d.ts} +39 -7
  7. package/dist/diagnostics-BDuR8UkG.d.ts.map +1 -0
  8. package/dist/{diagnostics-H1QzgRSw.js → diagnostics-CPVADSL1.js} +29 -3
  9. package/dist/{diagnostics-H1QzgRSw.js.map → diagnostics-CPVADSL1.js.map} +1 -1
  10. package/dist/{errors-fB1KDJKQ.d.ts → errors-CgnueTYL.d.ts} +3 -3
  11. package/dist/{errors-fB1KDJKQ.d.ts.map → errors-CgnueTYL.d.ts.map} +1 -1
  12. package/dist/{fit-CYJ1jkQI.js → fit-TjpNbMru.js} +3 -3
  13. package/dist/{fit-CYJ1jkQI.js.map → fit-TjpNbMru.js.map} +1 -1
  14. package/dist/{html-dom-CzewEdE1.js → html-dom-yUSdCExA.js} +5 -5
  15. package/dist/html-dom-yUSdCExA.js.map +1 -0
  16. package/dist/html.d.ts +3 -3
  17. package/dist/html.js +1 -1
  18. package/dist/index.d.ts +5 -5
  19. package/dist/index.js +16 -33
  20. package/dist/index.js.map +1 -1
  21. package/dist/inspect.d.ts +28 -4
  22. package/dist/inspect.d.ts.map +1 -1
  23. package/dist/inspect.js +43 -10
  24. package/dist/inspect.js.map +1 -1
  25. package/dist/math.d.ts +1 -1
  26. package/dist/measure.d.ts +2 -2
  27. package/dist/measure.js +1 -1
  28. package/dist/{st-enums-bVnezkMJ.js → namespaces-CcKuzeuE.js} +291 -200
  29. package/dist/namespaces-CcKuzeuE.js.map +1 -0
  30. package/dist/node.d.ts +5 -5
  31. package/dist/node.js +7 -19
  32. package/dist/node.js.map +1 -1
  33. package/dist/{notes-SCvpJz0l.js → notes-DNqAggXx.js} +221 -140
  34. package/dist/notes-DNqAggXx.js.map +1 -0
  35. package/dist/{pres-Cb-1xDne.d.ts → pres-Dybf7ZUl.d.ts} +2 -2
  36. package/dist/{pres-Cb-1xDne.d.ts.map → pres-Dybf7ZUl.d.ts.map} +1 -1
  37. package/dist/{presentation-DeKTJGHf.js → presentation-VfJ_FT7E.js} +306 -234
  38. package/dist/presentation-VfJ_FT7E.js.map +1 -0
  39. package/dist/{presentation-types-B50aOUFI.d.ts → presentation-types-CpkTx9Xa.d.ts} +352 -16
  40. package/dist/presentation-types-CpkTx9Xa.d.ts.map +1 -0
  41. package/dist/read.d.ts +4 -4
  42. package/dist/read.js +3 -3
  43. package/dist/script.d.ts +2 -2
  44. package/dist/script.d.ts.map +1 -1
  45. package/dist/script.js +128 -63
  46. package/dist/script.js.map +1 -1
  47. package/dist/{shapes-BXVgsk0F.js → shapes-Kt51vry6.js} +717 -54
  48. package/dist/shapes-Kt51vry6.js.map +1 -0
  49. package/dist/{slide-DWw9UoI6.d.ts → slide-B_aInw3N.d.ts} +208 -180
  50. package/dist/slide-B_aInw3N.d.ts.map +1 -0
  51. package/dist/{text-uM-zGton.js → text-D04NUMvA.js} +3563 -3437
  52. package/dist/text-D04NUMvA.js.map +1 -0
  53. package/dist/{units-internal-CGf4VrXy.js → units-internal-DNvK2I6o.js} +54 -34
  54. package/dist/{units-internal-CGf4VrXy.js.map → units-internal-DNvK2I6o.js.map} +1 -1
  55. package/dist/zip.d.ts +1 -1
  56. package/package.json +4 -4
  57. package/dist/autopage-D1sqK6j7.js.map +0 -1
  58. package/dist/diagnostics-B2yWpcjB.d.ts.map +0 -1
  59. package/dist/html-dom-CzewEdE1.js.map +0 -1
  60. package/dist/notes-SCvpJz0l.js.map +0 -1
  61. package/dist/presentation-DeKTJGHf.js.map +0 -1
  62. package/dist/presentation-types-B50aOUFI.d.ts.map +0 -1
  63. package/dist/shapes-BXVgsk0F.js.map +0 -1
  64. package/dist/slide-DWw9UoI6.d.ts.map +0 -1
  65. package/dist/st-enums-bVnezkMJ.js.map +0 -1
  66. package/dist/text-uM-zGton.js.map +0 -1
@@ -1,6 +1,6 @@
1
- import { n as warn } from "./diagnostics-H1QzgRSw.js";
1
+ import { r as warn } from "./diagnostics-CPVADSL1.js";
2
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-bVnezkMJ.js";
3
+ import { M as TEXT_HORZ_OVERFLOW, N as TEXT_VERTICAL, P as checkEnumOrThrow, a as NOTES_MASTER_REL, c as OFFICE_DOCUMENT_REL, h as SLIDE_MASTER_REL, j as TEXT_ANCHORS, p as SLIDE_LAYOUT_REL, r as IMAGE_REL, t as OOXML_NS, v as THEME_REL, x as getImageSizeFromBytes, y as fitSrcRectPercents } from "./namespaces-CcKuzeuE.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) {
@@ -14,24 +14,6 @@ function parseXml(xml) {
14
14
  function serializeXml(doc) {
15
15
  return new XMLSerializer().serializeToString(doc);
16
16
  }
17
- /** Canonical OOXML prefix → namespace URI registry. */
18
- const OOXML_NS = Object.freeze({
19
- a: "http://schemas.openxmlformats.org/drawingml/2006/main",
20
- c: "http://schemas.openxmlformats.org/drawingml/2006/chart",
21
- cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
22
- ct: "http://schemas.openxmlformats.org/package/2006/content-types",
23
- cx: "http://schemas.microsoft.com/office/drawing/2014/chartex",
24
- dc: "http://purl.org/dc/elements/1.1/",
25
- dcterms: "http://purl.org/dc/terms/",
26
- dgm: "http://schemas.openxmlformats.org/drawingml/2006/diagram",
27
- ep: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",
28
- mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
29
- p: "http://schemas.openxmlformats.org/presentationml/2006/main",
30
- p14: "http://schemas.microsoft.com/office/powerpoint/2010/main",
31
- p188: "http://schemas.microsoft.com/office/powerpoint/2018/8/main",
32
- pr: "http://schemas.openxmlformats.org/package/2006/relationships",
33
- r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
34
- });
35
17
  function splitQName(qname) {
36
18
  const colon = qname.indexOf(":");
37
19
  if (colon < 0) throw new InvalidOptionError("oxml/invalid-qname", `Expected a prefixed qname like "p:sld", got: ${qname}`);
@@ -686,6 +668,94 @@ function intAttr(el, name) {
686
668
  return Number.isFinite(n) ? n : null;
687
669
  }
688
670
  //#endregion
671
+ //#region src/read/oxml/slide-dom.ts
672
+ /**
673
+ * The `p:cSld` of a slide/layout/master/notes part root.
674
+ *
675
+ * Takes a nullable root and returns a nullable element so a caller can chain from
676
+ * `part?.dom.documentElement` without a guard of its own — which is what a dozen callers were
677
+ * writing by hand, each in a slightly different spelling (`root && …`, `root ? … : null`).
678
+ */
679
+ function cSldOf(root) {
680
+ return root ? firstChild(root, "p:cSld") : null;
681
+ }
682
+ /** The `p:spTree` of a slide/layout/master/notes part root, through its `p:cSld`. */
683
+ function spTreeOf(root) {
684
+ const cSld = cSldOf(root);
685
+ return cSld ? firstChild(cSld, "p:spTree") : null;
686
+ }
687
+ /**
688
+ * The `p:nvPr` of a shape, whichever `*nvPr` wrapper its kind uses.
689
+ *
690
+ * The wrapper's name varies by shape kind — `p:nvSpPr` on a `p:sp`, `p:nvPicPr` on a `p:pic`,
691
+ * `p:nvGraphicFramePr`, `p:nvCxnSpPr`, `p:nvGrpSpPr` — but it is always the shape's first child
692
+ * element, and `p:nvPr` is always inside it. Taking the first child element rather than naming
693
+ * the wrapper is what lets one helper serve every kind; the callers that named `p:nvSpPr`
694
+ * silently returned null on a picture.
695
+ */
696
+ function nvPrOf(shape) {
697
+ const nv = firstChildElement(shape);
698
+ return nv ? firstChild(nv, "p:nvPr") : null;
699
+ }
700
+ /** The `p:cSld@name` of a slide/layout/master part (`''` when absent). */
701
+ function cSldName(part) {
702
+ const cSld = cSldOf(part?.dom.documentElement);
703
+ return (cSld && attr(cSld, "name")) ?? "";
704
+ }
705
+ /** Whether `el` is a `p:spTree`'s own group properties (`p:nvGrpSpPr`/`p:grpSpPr`), not a shape. */
706
+ function isSpTreeProperty(el) {
707
+ return el.namespaceURI === OOXML_NS.p && (el.localName === "nvGrpSpPr" || el.localName === "grpSpPr");
708
+ }
709
+ /** Whether a `p:spTree` child is a placeholder shape (its `*nvPr` carries a `p:ph`). */
710
+ function isPlaceholderShape(shape) {
711
+ const nvPr = nvPrOf(shape);
712
+ return !!(nvPr && firstChild(nvPr, "p:ph"));
713
+ }
714
+ /** The decorative shapes on a layout/master `p:spTree`: every shape child except placeholders. */
715
+ function carriedDecorations(root) {
716
+ const spTree = spTreeOf(root);
717
+ if (!spTree) return [];
718
+ const out = [];
719
+ for (let node = spTree.firstChild; node; node = node.nextSibling) {
720
+ if (node.nodeType !== 1) continue;
721
+ const el = node;
722
+ if (isSpTreeProperty(el) || isPlaceholderShape(el)) continue;
723
+ out.push(el);
724
+ }
725
+ return out;
726
+ }
727
+ /**
728
+ * The `n`-th shape child of a `p:spTree` in document (z-)order, skipping the
729
+ * tree's own `nvGrpSpPr`/`grpSpPr` and any trailing `p:extLst`. Returns `null`
730
+ * when `n` is past the last shape (the caller then appends).
731
+ */
732
+ function nthShapeChild(spTree, n) {
733
+ let i = 0;
734
+ for (let node = spTree.firstChild; node; node = node.nextSibling) {
735
+ if (node.nodeType !== 1) continue;
736
+ const el = node;
737
+ if (isSpTreeProperty(el)) continue;
738
+ if (el.namespaceURI === OOXML_NS.p && el.localName === "extLst") continue;
739
+ if (i === n) return el;
740
+ i++;
741
+ }
742
+ return null;
743
+ }
744
+ /** The first shape child of a `p:spTree` (skipping `nvGrpSpPr`/`grpSpPr`), or `null`. */
745
+ function firstShapeChild(spTree) {
746
+ for (let node = spTree.firstChild; node; node = node.nextSibling) {
747
+ if (node.nodeType !== 1) continue;
748
+ const el = node;
749
+ if (!isSpTreeProperty(el)) return el;
750
+ }
751
+ return null;
752
+ }
753
+ /** Collect `node` and all its descendant elements (document order) into `out`. */
754
+ function collectElements(node, out) {
755
+ out.push(node);
756
+ for (let child = node.firstChild; child; child = child.nextSibling) if (child.nodeType === 1) collectElements(child, out);
757
+ }
758
+ //#endregion
689
759
  //#region src/read/oxml/placeholder-inherit.ts
690
760
  /**
691
761
  * Resolving what a placeholder shape *inherits* from its source layout/master chain.
@@ -733,8 +803,7 @@ const RUN_PROP_NAMES = [
733
803
  ];
734
804
  /** The `p:ph` element of a shape (`p:sp/p:nvSpPr/p:nvPr/p:ph`), or `null`. */
735
805
  function placeholderOf(sp) {
736
- const nvSpPr = firstChild(sp, "p:nvSpPr");
737
- const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
806
+ const nvPr = nvPrOf(sp);
738
807
  return nvPr ? firstChild(nvPr, "p:ph") : null;
739
808
  }
740
809
  /**
@@ -2460,6 +2529,16 @@ var Paragraph = class {
2460
2529
  }
2461
2530
  return out;
2462
2531
  }
2532
+ /**
2533
+ * Replace **this paragraph's** content with a single run, preserving the character
2534
+ * formatting (`a:rPr`) of its first existing run and leaving its `a:pPr` (level,
2535
+ * alignment, bullet) alone. Sibling paragraphs are untouched — the difference from
2536
+ * {@link TextFrame.text}, which collapses the whole body to one paragraph.
2537
+ */
2538
+ set text(value) {
2539
+ setParagraphText(this.element, value);
2540
+ this.part.markDirty();
2541
+ }
2463
2542
  /** Escape hatch: the underlying `a:p` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
2464
2543
  get element_() {
2465
2544
  return this.element;
@@ -2603,8 +2682,6 @@ function setTextBodyText(txBody, value) {
2603
2682
  const doc = txBody.ownerDocument;
2604
2683
  if (!doc) throw new InternalError("oxml/node-has-no-document", "Cannot set text: text body has no owner document");
2605
2684
  const paragraphs = getElements(txBody, "a:p");
2606
- const firstRun = paragraphs[0] && firstChild(paragraphs[0], "a:r");
2607
- const rPrTemplate = firstRun && firstChild(firstRun, "a:rPr");
2608
2685
  for (let i = paragraphs.length - 1; i >= 1; i--) {
2609
2686
  const extra = paragraphs[i];
2610
2687
  if (extra) txBody.removeChild(extra);
@@ -2614,6 +2691,21 @@ function setTextBodyText(txBody, value) {
2614
2691
  p = createElement(doc, "a:p");
2615
2692
  txBody.appendChild(p);
2616
2693
  }
2694
+ setParagraphText(p, value);
2695
+ }
2696
+ /**
2697
+ * Replace **one paragraph's** content with a single run, preserving the `a:rPr` of that
2698
+ * paragraph's first existing run and leaving its `a:pPr` (level, alignment, bullet) alone.
2699
+ * Sibling paragraphs are untouched, which is the whole difference from
2700
+ * {@link setTextBodyText} and the reason this exists: a SmartArt drawing cache packs several
2701
+ * nodes' text into one `dsp:txBody`, so collapsing the body there would delete the other
2702
+ * nodes' strings. Does **not** mark any part dirty — the caller owns the `Part`.
2703
+ */
2704
+ function setParagraphText(p, value) {
2705
+ const doc = p.ownerDocument;
2706
+ if (!doc) throw new InternalError("oxml/node-has-no-document", "Cannot set text: paragraph has no owner document");
2707
+ const firstRun = firstChild(p, "a:r");
2708
+ const rPrTemplate = firstRun && firstChild(firstRun, "a:rPr");
2617
2709
  for (const child of childElements(p)) if (child.localName === "r" || child.localName === "br" || child.localName === "fld") p.removeChild(child);
2618
2710
  const run = createElement(doc, "a:r");
2619
2711
  if (rPrTemplate) run.appendChild(rPrTemplate.cloneNode(true));
@@ -2649,6 +2741,21 @@ var Shape = class {
2649
2741
  this.host = host;
2650
2742
  }
2651
2743
  /**
2744
+ * The transform element carrying this shape's geometry, or `null` if inherited.
2745
+ *
2746
+ * Defaults to `p:spPr/a:xfrm`, which is where three of the four shape kinds keep it
2747
+ * (`p:sp`, `p:pic`, `p:cxnSp`). {@link GraphicFrame} overrides it: a `p:graphicFrame`
2748
+ * has no `p:spPr` and carries a `p:xfrm` of its own directly.
2749
+ */
2750
+ xfrm() {
2751
+ const spPr = firstChild(this.element, "p:spPr");
2752
+ return spPr ? firstChild(spPr, "a:xfrm") : null;
2753
+ }
2754
+ /** The transform element, creating it (and its container) in document order if absent. */
2755
+ getOrAddXfrm() {
2756
+ return getOrAddSpPrXfrm(this.element);
2757
+ }
2758
+ /**
2652
2759
  * Mark the owning host's part dirty so `save()` reserializes it. Public
2653
2760
  * because {@link element_} hands out the live DOM node: the hatch and the
2654
2761
  * obligation that comes with it belong on the same object.
@@ -3366,13 +3473,6 @@ var Shape = class {
3366
3473
  /** An auto shape, text box, or placeholder (`p:sp`). The only kind that holds text. */
3367
3474
  var AutoShape = class extends Shape {
3368
3475
  shapeType = "autoShape";
3369
- xfrm() {
3370
- const spPr = firstChild(this.element, "p:spPr");
3371
- return spPr ? firstChild(spPr, "a:xfrm") : null;
3372
- }
3373
- getOrAddXfrm() {
3374
- return getOrAddSpPrXfrm(this.element);
3375
- }
3376
3476
  get hasTextFrame() {
3377
3477
  return firstChild(this.element, "p:txBody") !== null;
3378
3478
  }
@@ -3394,8 +3494,7 @@ var AutoShape = class extends Shape {
3394
3494
  * PowerPoint does. Use {@link Slide.placeholder} to find a placeholder by type.
3395
3495
  */
3396
3496
  get placeholder() {
3397
- const nvSpPr = firstChild(this.element, "p:nvSpPr");
3398
- const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
3497
+ const nvPr = nvPrOf(this.element);
3399
3498
  const ph = nvPr && firstChild(nvPr, "p:ph");
3400
3499
  return ph ? {
3401
3500
  type: attr(ph, "type"),
@@ -3470,13 +3569,6 @@ function recolorColorOf(color) {
3470
3569
  /** A picture (`p:pic`). */
3471
3570
  var Picture = class extends Shape {
3472
3571
  shapeType = "picture";
3473
- xfrm() {
3474
- const spPr = firstChild(this.element, "p:spPr");
3475
- return spPr ? firstChild(spPr, "a:xfrm") : null;
3476
- }
3477
- getOrAddXfrm() {
3478
- return getOrAddSpPrXfrm(this.element);
3479
- }
3480
3572
  get supportsFill() {
3481
3573
  return false;
3482
3574
  }
@@ -3719,13 +3811,6 @@ var Picture = class extends Shape {
3719
3811
  /** A connector / line (`p:cxnSp`). */
3720
3812
  var Connector = class extends Shape {
3721
3813
  shapeType = "connector";
3722
- xfrm() {
3723
- const spPr = firstChild(this.element, "p:spPr");
3724
- return spPr ? firstChild(spPr, "a:xfrm") : null;
3725
- }
3726
- getOrAddXfrm() {
3727
- return getOrAddSpPrXfrm(this.element);
3728
- }
3729
3814
  /**
3730
3815
  * The connector's **start**-point shape binding (`p:nvCxnSpPr/p:cNvCxnSpPr/a:stCxn`),
3731
3816
  * or `null` when the start point is unbound (a bare `p:cNvCxnSpPr`, i.e. a
@@ -4405,6 +4490,548 @@ function floatValue(value) {
4405
4490
  return Number.isFinite(number) ? number : null;
4406
4491
  }
4407
4492
  //#endregion
4493
+ //#region src/read/api/diagram.ts
4494
+ /**
4495
+ * Read proxies for a SmartArt diagram (`dgm:dataModel`) hosted in a `p:graphicFrame`.
4496
+ *
4497
+ * SmartArt is a four-part construct, and the frame itself holds none of it: the
4498
+ * `a:graphicData` carries only a `dgm:relIds` with four relationship ids pointing at the
4499
+ * data, layout, quick-style and colours parts under `/ppt/diagrams/`. The **data** part is
4500
+ * the one with content in it — a flat `dgm:ptLst` of points plus a `dgm:cxnLst` of
4501
+ * connections that give the points their tree — and it is what this surface decodes. The
4502
+ * other three are generated presets (`urn:microsoft.com/office/officeart/…`) describing how
4503
+ * PowerPoint *draws* the graph rather than what it says; they surface as parts, not getters.
4504
+ *
4505
+ * The text is ordinary DrawingML: `dgm:pt/dgm:t` is an `a:CT_TextBody`, the same type a
4506
+ * shape's `p:txBody` is, so a point's text reads back through the same
4507
+ * {@link TextFrame}/`Paragraph`/`Run` proxies as any other text on the slide, run formatting
4508
+ * included.
4509
+ *
4510
+ * **Not every point is content.** A saved data model interleaves the user's nodes with
4511
+ * points the layout engine generated (`pres`), the diagram root (`doc`), and the transition
4512
+ * points sitting on each edge (`parTrans`/`sibTrans`, which carry text only where a layout
4513
+ * labels its arrows). {@link Diagram.text} applies exactly that filter; {@link Diagram.points}
4514
+ * applies none, so a consumer that needs the raw graph gets it.
4515
+ *
4516
+ * **The structure is in the connections, and {@link Diagram.nodes} is the view of it.** A
4517
+ * `parOf` edge names the parent in `@srcId`, the child in `@destId` and the child's sibling
4518
+ * position in `@srcOrd`; `points` order is document order and says nothing about depth. Three
4519
+ * decisions that tree makes, each of which could defensibly have gone the other way:
4520
+ *
4521
+ * - **`asst` points are in it.** An assistant is user content, and an org chart merely draws
4522
+ * it off the main branch rather than under it. {@link DiagramPoint.type} carries the
4523
+ * distinction, so folding it silently in with `node` would hide something a consumer can
4524
+ * act on while omitting it would lose authored text.
4525
+ * - **Transition points are not.** A `parTrans`/`sibTrans` labels an *edge*, not a node, and
4526
+ * reaches its edge through {@link DiagramConnection.parentTransitionId} /
4527
+ * `siblingTransitionId`. Hanging one off `children` would make the tree disagree with what
4528
+ * PowerPoint's own text pane shows.
4529
+ * - **A cycle in `parOf` throws.** It is a corrupt model rather than a shape the format can
4530
+ * express, and the walk would not terminate; see `diagram/parent-edge-cycle`.
4531
+ *
4532
+ * **A point's text is stored twice.** The data model is what PowerPoint reads, but a deck
4533
+ * also carries a *drawing* part (`dsp:drawing`) holding a copy of every drawn string, and
4534
+ * every renderer without a SmartArt layout engine — LibreOffice, Google Slides, thumbnailers
4535
+ * — paints that copy and nothing else. {@link DiagramPoint.drawnShape} is the link between
4536
+ * the two, and {@link DiagramPoint.text}'s setter is what keeps them in step.
4537
+ *
4538
+ * Authoring a SmartArt graphic from nothing is out of scope: the layout part is a
4539
+ * constraint-solver program PowerPoint executes, and the presentation tree it generates is
4540
+ * not derivable from the user's content. Editing the text of one that already exists is
4541
+ * supported — see {@link DiagramPoint.text}.
4542
+ */
4543
+ const POINT_TYPES = [
4544
+ "node",
4545
+ "asst",
4546
+ "doc",
4547
+ "pres",
4548
+ "parTrans",
4549
+ "sibTrans"
4550
+ ];
4551
+ const CONNECTION_TYPES = [
4552
+ "parOf",
4553
+ "presOf",
4554
+ "presParOf",
4555
+ "unknownRelationship"
4556
+ ];
4557
+ /** The MS extension (`dgm:extLst/a:ext`) whose `@relId` names the fallback drawing part. */
4558
+ const DRAWING_EXT_URI = "http://schemas.microsoft.com/office/drawing/2008/diagram";
4559
+ /**
4560
+ * The node → drawn-shape index of one diagram: the `presOf` edges of the data model and the
4561
+ * `dsp:sp` elements of the drawing part, both keyed for lookup.
4562
+ *
4563
+ * Built once per {@link Diagram}, and only when a point is actually asked what draws it — the
4564
+ * drawing part is a second XML DOM and a consumer reading node text should not pay to parse
4565
+ * it. The consequence of that memo: a consumer who *adds* or *removes* shapes in the drawing
4566
+ * part through the escape hatches must re-reach the diagram to see them here.
4567
+ */
4568
+ var DrawingIndex = class {
4569
+ drawingPart;
4570
+ themeContext;
4571
+ /** `presOf` arms out of each source point, in `@srcOrd` order. */
4572
+ #arms = /* @__PURE__ */ new Map();
4573
+ /** Each `dsp:sp` by the `pres` modelId it draws. */
4574
+ #shapes = /* @__PURE__ */ new Map();
4575
+ constructor(root, drawingPart, themeContext) {
4576
+ this.drawingPart = drawingPart;
4577
+ this.themeContext = themeContext;
4578
+ const cxnLst = root && firstChild(root, "dgm:cxnLst");
4579
+ for (const cxn of cxnLst ? getElements(cxnLst, "dgm:cxn") : []) {
4580
+ if (attr(cxn, "type") !== "presOf") continue;
4581
+ const srcId = attr(cxn, "srcId");
4582
+ const destId = attr(cxn, "destId");
4583
+ if (!srcId || !destId) continue;
4584
+ const arm = {
4585
+ destId,
4586
+ destinationOrder: intValue(attr(cxn, "destOrd")) ?? 0,
4587
+ sourceOrder: intValue(attr(cxn, "srcOrd")) ?? 0
4588
+ };
4589
+ const list = this.#arms.get(srcId);
4590
+ if (list) list.push(arm);
4591
+ else this.#arms.set(srcId, [arm]);
4592
+ }
4593
+ for (const list of this.#arms.values()) list.sort((a, b) => a.sourceOrder - b.sourceOrder);
4594
+ const drawingRoot = drawingPart?.dom.documentElement ?? null;
4595
+ for (const sp of drawingRoot ? descendantsByTag(drawingRoot, OOXML_NS.dsp, "sp") : []) {
4596
+ const modelId = attr(sp, "modelId");
4597
+ if (modelId !== null && !this.#shapes.has(modelId)) this.#shapes.set(modelId, sp);
4598
+ }
4599
+ }
4600
+ /**
4601
+ * Resolve one authored point to the `pres` point that presents it and to the drawn
4602
+ * paragraph carrying its text.
4603
+ *
4604
+ * A point commonly has **several** `presOf` arms — an org-chart node's box and the
4605
+ * connector beneath it are two presentations of one node — so the arm is chosen by what it
4606
+ * reaches rather than by its `@srcOrd`: the first, in `@srcOrd` order, whose `pres` point
4607
+ * draws a `dsp:sp` that has a `dsp:txBody`. That selector produced a unique hit for all 90
4608
+ * authored points measured across five layout families, and it degrades to "no arm" rather
4609
+ * than to "the wrong arm" on a layout that was not.
4610
+ */
4611
+ resolve(modelId) {
4612
+ const arms = (modelId === null ? void 0 : this.#arms.get(modelId)) ?? [];
4613
+ const first = arms[0];
4614
+ if (!first) return {
4615
+ presentationId: null,
4616
+ drawnShape: null
4617
+ };
4618
+ for (const arm of arms) {
4619
+ const sp = this.#shapes.get(arm.destId);
4620
+ const txBody = sp && firstChild(sp, "dsp:txBody");
4621
+ if (!sp || !txBody || !this.drawingPart) continue;
4622
+ const paragraph = getElements(txBody, "a:p")[arm.destinationOrder];
4623
+ return {
4624
+ presentationId: arm.destId,
4625
+ drawnShape: paragraph ? {
4626
+ part: this.drawingPart,
4627
+ modelId: arm.destId,
4628
+ paragraphIndex: arm.destinationOrder,
4629
+ textFrame: new TextFrame(txBody, this.drawingPart, this.themeContext),
4630
+ element_: sp
4631
+ } : null
4632
+ };
4633
+ }
4634
+ return {
4635
+ presentationId: first.destId,
4636
+ drawnShape: null
4637
+ };
4638
+ }
4639
+ };
4640
+ /** One point (`dgm:pt`) of a diagram's data model. */
4641
+ var DiagramPoint = class {
4642
+ pt;
4643
+ part;
4644
+ themeContext;
4645
+ relationships;
4646
+ drawing;
4647
+ constructor(pt, part, themeContext, relationships, drawing) {
4648
+ this.pt = pt;
4649
+ this.part = part;
4650
+ this.themeContext = themeContext;
4651
+ this.relationships = relationships;
4652
+ this.drawing = drawing;
4653
+ }
4654
+ /** This point's id (`@modelId`), which connections reference. */
4655
+ get modelId() {
4656
+ return attr(this.pt, "modelId");
4657
+ }
4658
+ /** What kind of point this is (`@type`); `node` when absent, its schema default. */
4659
+ get type() {
4660
+ const raw = attr(this.pt, "type");
4661
+ return raw !== null && POINT_TYPES.includes(raw) ? raw : "node";
4662
+ }
4663
+ /**
4664
+ * For a transition point, the edge it labels (`@cxnId`), or `null`. The schema's default
4665
+ * is the literal `0`, which means "none" rather than naming a point, so it reads `null`.
4666
+ */
4667
+ get connectionId() {
4668
+ return idAttr(this.pt, "cxnId");
4669
+ }
4670
+ /**
4671
+ * Whether this point is an unfilled prompt (`dgm:prSet/@phldr`) — a node PowerPoint draws
4672
+ * with a grey placeholder string and treats as empty. Excluded from {@link Diagram.text}:
4673
+ * a layout that stores its prompt in `dgm:t` would otherwise extract as content.
4674
+ */
4675
+ get isPlaceholder() {
4676
+ const prSet = this.#prSet();
4677
+ return prSet ? boolValue(attr(prSet, "phldr")) === true : false;
4678
+ }
4679
+ /** The prompt string a placeholder point displays (`dgm:prSet/@phldrT`), or `null`. */
4680
+ get placeholderText() {
4681
+ const prSet = this.#prSet();
4682
+ return prSet ? attr(prSet, "phldrT") : null;
4683
+ }
4684
+ /**
4685
+ * This point's text body (`dgm:t`) as a {@link TextFrame}, or `null` when the point
4686
+ * carries none. It is an `a:CT_TextBody` like any other, so `paragraphs`, `runs` and the
4687
+ * `resolved*` getters all apply.
4688
+ *
4689
+ * **Writing through this edits the data model only**, and leaves the drawing cache
4690
+ * holding the old string — which is what PowerPoint-less renderers draw. It is the escape
4691
+ * hatch for run-level formatting, so it does exactly what it is told and nothing more;
4692
+ * {@link text}'s setter is the path that mirrors.
4693
+ */
4694
+ get textFrame() {
4695
+ const t = firstChild(this.pt, "dgm:t");
4696
+ return t ? new TextFrame(t, this.part, this.themeContext, void 0, this.relationships) : null;
4697
+ }
4698
+ /**
4699
+ * The generated `pres` point that presents this one (`dgm:cxn[@type="presOf"]/@destId`),
4700
+ * or `null` when nothing presents it — the normal state of an unlabelled transition point.
4701
+ *
4702
+ * Where a point has several `presOf` arms the one named here is the arm that draws text;
4703
+ * see {@link drawnShape}, which resolves both.
4704
+ */
4705
+ get presentationId() {
4706
+ return this.drawing?.().resolve(this.modelId).presentationId ?? null;
4707
+ }
4708
+ /**
4709
+ * The paragraph of the fallback drawing part (`dsp:drawing`) that carries this point's
4710
+ * text, or `null` when nothing draws it.
4711
+ *
4712
+ * The mapping runs through the `pres` point rather than directly: a `dsp:sp/@modelId` is
4713
+ * always a `pres` point's id, so a lookup keyed on the authored point's own id finds
4714
+ * nothing at all. It is many-to-one in both directions — one shape draws several points
4715
+ * (`@destOrd` says which paragraph is whose, and it can contradict document order), and
4716
+ * one point has several presentations, of which at most one holds text.
4717
+ *
4718
+ * `null` is a defined outcome, not a failure, and covers four real cases: the package
4719
+ * carries no drawing part; the point has no `presOf` edge (every unlabelled
4720
+ * `parTrans`/`sibTrans`); the `pres` point draws no `dsp:sp`; and the shape it draws has
4721
+ * no `dsp:txBody` (a connector, or a picture node's filled rectangle).
4722
+ */
4723
+ get drawnShape() {
4724
+ return this.drawing?.().resolve(this.modelId).drawnShape ?? null;
4725
+ }
4726
+ /** This point's text, paragraphs joined by `\n`; `''` when it carries none. */
4727
+ get text() {
4728
+ return this.textFrame?.text ?? "";
4729
+ }
4730
+ /**
4731
+ * Replace this point's text, in the data model **and** in the drawing cache.
4732
+ *
4733
+ * A diagram stores every string twice. `dgm:t` is what PowerPoint reads, and it recomputes
4734
+ * the drawing from the data model on open; the `dsp:drawing` part is what every other
4735
+ * renderer paints, and none of them recompute anything. Writing only the first is an edit
4736
+ * that is invisible in LibreOffice, Google Slides, thumbnailers and web previews until
4737
+ * someone opens the deck in PowerPoint and saves it.
4738
+ *
4739
+ * The data-model write always happens. The mirror is best-effort: when the point resolves
4740
+ * to no drawn paragraph (see {@link drawnShape} for the four ways that occurs) the cache
4741
+ * keeps the old string and a `diagram/drawing-cache-not-updated` diagnostic says so.
4742
+ * Throwing instead would make the common case unusable in order to report the rare one,
4743
+ * and returning a status would be a shape no other text setter here has.
4744
+ *
4745
+ * Two things it deliberately does not do. It does **not** recompute geometry: the drawn
4746
+ * shape keeps its cached position and size, so a much longer string overflows its box in
4747
+ * those same renderers until PowerPoint re-lays the diagram out. And it does not *create*
4748
+ * a place to draw text — a transition point whose layout has no label slot has no
4749
+ * `dsp:sp`, and PowerPoint strips text put on one, so the honest outcome is the
4750
+ * diagnostic. Like every other `text` setter here it collapses the point to one run,
4751
+ * keeping the first run's `a:rPr`; use {@link textFrame} for run-level work.
4752
+ */
4753
+ set text(value) {
4754
+ const frame = this.textFrame;
4755
+ if (!frame) {
4756
+ warn("diagram/point-has-no-text-body", `SmartArt point ${this.#label()} (type ${this.type}) has no dgm:t, so it is not a point text can be written to; nothing was changed`);
4757
+ return;
4758
+ }
4759
+ frame.text = value;
4760
+ const drawn = this.drawnShape;
4761
+ const paragraph = drawn?.textFrame.paragraphs[drawn.paragraphIndex];
4762
+ if (!drawn || !paragraph) {
4763
+ warn("diagram/drawing-cache-not-updated", `SmartArt point ${this.#label()} resolves to no drawn paragraph, so ${this.part.partName} now holds the new text but the drawing cache still holds the old one; PowerPoint redraws it on open, other renderers do not`);
4764
+ return;
4765
+ }
4766
+ setParagraphText(paragraph.element_, value);
4767
+ drawn.part.markDirty();
4768
+ }
4769
+ /** Escape hatch: the underlying `dgm:pt` element. After mutating it call {@link Diagram.markDirty}. */
4770
+ get element_() {
4771
+ return this.pt;
4772
+ }
4773
+ #prSet() {
4774
+ return firstChild(this.pt, "dgm:prSet");
4775
+ }
4776
+ /** How a diagnostic names this point: its `@modelId`, which is all a corrupt point may have. */
4777
+ #label() {
4778
+ return this.modelId ?? "(no modelId)";
4779
+ }
4780
+ };
4781
+ /**
4782
+ * One user-authored point in its place in the diagram's tree — a `node` or an `asst`, never a
4783
+ * generated `pres` point or a transition label. See {@link Diagram.nodes}.
4784
+ */
4785
+ var DiagramNode = class {
4786
+ point;
4787
+ parent;
4788
+ level;
4789
+ /** Child nodes, ordered by their `parOf` edge's `@srcOrd`. Empty for a leaf. */
4790
+ children = [];
4791
+ constructor(point, parent, level) {
4792
+ this.point = point;
4793
+ this.parent = parent;
4794
+ this.level = level;
4795
+ }
4796
+ };
4797
+ /** Sort key for a root with no `parOf` edge at all, so it lands after the ordered ones. */
4798
+ const MAX_ORDER = Number.MAX_SAFE_INTEGER;
4799
+ /** A SmartArt graphic frame's diagram, backed by its `dgm:dataModel` part. */
4800
+ var Diagram = class {
4801
+ part;
4802
+ relIds;
4803
+ opc;
4804
+ frameRelationships;
4805
+ themeContext;
4806
+ #relationships;
4807
+ #docPrSetCache;
4808
+ #drawing;
4809
+ constructor(part, relIds, opc, frameRelationships, themeContext) {
4810
+ this.part = part;
4811
+ this.relIds = relIds;
4812
+ this.opc = opc;
4813
+ this.frameRelationships = frameRelationships;
4814
+ this.themeContext = themeContext;
4815
+ }
4816
+ /** Partname of the diagram data part. */
4817
+ get partName() {
4818
+ return this.part.partName;
4819
+ }
4820
+ /**
4821
+ * Every point (`dgm:ptLst/dgm:pt`) in document order, unfiltered — generated `pres`
4822
+ * points and the `doc` root included. Filter on {@link DiagramPoint.type} for the user's
4823
+ * nodes; {@link text} is the shortcut for the common case, {@link nodes} the structured one.
4824
+ *
4825
+ * Built per access like every other read proxy (`docs/reference/pptx-read.md`, "Object
4826
+ * model"), so `points[0] !== points[0]` while both wrap the same `dgm:pt`. Key a `Map`
4827
+ * on {@link DiagramPoint.modelId}, not on the point.
4828
+ */
4829
+ get points() {
4830
+ const root = this.#root();
4831
+ const ptLst = root && firstChild(root, "dgm:ptLst");
4832
+ if (!ptLst) return [];
4833
+ const relationships = this.#relationships ??= this.opc.relationshipsFor(this.part.partName);
4834
+ const drawing = () => this.#drawingIndex();
4835
+ return getElements(ptLst, "dgm:pt").map((pt) => new DiagramPoint(pt, this.part, this.themeContext, relationships, drawing));
4836
+ }
4837
+ /**
4838
+ * The authored tree — every `node` and `asst` point in its place, roots in `@srcOrd`
4839
+ * order — as a view over {@link points} and {@link connections} rather than a replacement
4840
+ * for either.
4841
+ *
4842
+ * A root is a content point whose `parOf` parent is not itself content, which in a
4843
+ * PowerPoint-authored model means the `doc` point. Transition points are not members; see
4844
+ * this module's header for that decision and the two beside it.
4845
+ *
4846
+ * @throws PackageReadError `diagram/parent-edge-cycle` when the `parOf` edges make a
4847
+ * point its own ancestor, which is a corrupt model rather than a diagram shape.
4848
+ */
4849
+ get nodes() {
4850
+ const content = /* @__PURE__ */ new Map();
4851
+ for (const point of this.points) {
4852
+ const modelId = point.modelId;
4853
+ if (modelId !== null && (point.type === "node" || point.type === "asst")) content.set(modelId, point);
4854
+ }
4855
+ const childrenOf = /* @__PURE__ */ new Map();
4856
+ const edgeTo = /* @__PURE__ */ new Map();
4857
+ for (const connection of this.connections) {
4858
+ const { sourceId, destinationId } = connection;
4859
+ if (connection.type !== "parOf" || sourceId === null || destinationId === null) continue;
4860
+ if (!content.has(destinationId)) continue;
4861
+ const edge = {
4862
+ parentId: sourceId,
4863
+ childId: destinationId,
4864
+ order: connection.sourceOrder ?? 0
4865
+ };
4866
+ const list = childrenOf.get(sourceId);
4867
+ if (list) list.push(edge);
4868
+ else childrenOf.set(sourceId, [edge]);
4869
+ edgeTo.set(destinationId, edge);
4870
+ }
4871
+ for (const list of childrenOf.values()) list.sort((a, b) => a.order - b.order);
4872
+ const roots = [...content].filter(([modelId]) => {
4873
+ const parentId = edgeTo.get(modelId)?.parentId;
4874
+ return parentId === void 0 || !content.has(parentId);
4875
+ });
4876
+ roots.sort(([a], [b]) => (edgeTo.get(a)?.order ?? MAX_ORDER) - (edgeTo.get(b)?.order ?? MAX_ORDER));
4877
+ const placed = /* @__PURE__ */ new Set();
4878
+ const build = (point, parent, level, path) => {
4879
+ const modelId = point.modelId;
4880
+ if (modelId !== null && path.has(modelId)) throw this.#cycleError(modelId);
4881
+ const node = new DiagramNode(point, parent, level);
4882
+ if (modelId === null) return node;
4883
+ placed.add(modelId);
4884
+ path.add(modelId);
4885
+ for (const edge of childrenOf.get(modelId) ?? []) {
4886
+ const child = content.get(edge.childId);
4887
+ if (child) node.children.push(build(child, node, level + 1, path));
4888
+ }
4889
+ path.delete(modelId);
4890
+ return node;
4891
+ };
4892
+ const tree = roots.map(([, point]) => build(point, null, 0, /* @__PURE__ */ new Set()));
4893
+ if (placed.size !== content.size) {
4894
+ const orphan = [...content.keys()].find((modelId) => !placed.has(modelId));
4895
+ throw this.#cycleError(orphan ?? "(unidentified)");
4896
+ }
4897
+ return tree;
4898
+ }
4899
+ /**
4900
+ * The point with this `@modelId`, or `null` — the lookup every connection getter implies,
4901
+ * since a `DiagramConnection` names its ends by id and nothing else resolves them.
4902
+ */
4903
+ point(modelId) {
4904
+ return this.points.find((candidate) => candidate.modelId === modelId) ?? null;
4905
+ }
4906
+ /** Every edge (`dgm:cxnLst/dgm:cxn`) in document order. */
4907
+ get connections() {
4908
+ const root = this.#root();
4909
+ const cxnLst = root && firstChild(root, "dgm:cxnLst");
4910
+ if (!cxnLst) return [];
4911
+ return getElements(cxnLst, "dgm:cxn").map((cxn) => {
4912
+ const rawType = attr(cxn, "type");
4913
+ return {
4914
+ modelId: attr(cxn, "modelId"),
4915
+ type: rawType !== null && CONNECTION_TYPES.includes(rawType) ? rawType : "parOf",
4916
+ sourceId: attr(cxn, "srcId"),
4917
+ destinationId: attr(cxn, "destId"),
4918
+ sourceOrder: intValue(attr(cxn, "srcOrd")),
4919
+ destinationOrder: intValue(attr(cxn, "destOrd")),
4920
+ parentTransitionId: idAttr(cxn, "parTransId"),
4921
+ siblingTransitionId: idAttr(cxn, "sibTransId"),
4922
+ presentationId: attr(cxn, "presId") || null
4923
+ };
4924
+ });
4925
+ }
4926
+ /**
4927
+ * The diagram's text in document order, blocks joined by `\n` — the counterpart to
4928
+ * `TextFrame.text` for a construct that has no single text body.
4929
+ *
4930
+ * Contributing points are the ones a user can type into: everything except the generated
4931
+ * `pres` points, the `doc` root, and any point flagged as an unfilled placeholder. A
4932
+ * point with no text contributes no blank line. Transition labels (`parTrans`/`sibTrans`)
4933
+ * are included where a layout has them, which is why this is not simply the node list.
4934
+ */
4935
+ get text() {
4936
+ return this.points.filter((point) => point.type !== "pres" && point.type !== "doc" && !point.isPlaceholder).map((point) => point.text).filter((text) => text.length > 0).join("\n");
4937
+ }
4938
+ /**
4939
+ * The layout preset the diagram is drawn with (the `doc` point's `dgm:prSet/@loTypeId`),
4940
+ * e.g. `urn:microsoft.com/office/officeart/2005/8/layout/hList1`. This is what names the
4941
+ * SmartArt *kind*; {@link layoutPart} is that preset's definition.
4942
+ */
4943
+ get layoutTypeId() {
4944
+ return this.#docPrSetAttr("loTypeId");
4945
+ }
4946
+ /** The quick-style preset (the `doc` point's `dgm:prSet/@qsTypeId`). */
4947
+ get quickStyleTypeId() {
4948
+ return this.#docPrSetAttr("qsTypeId");
4949
+ }
4950
+ /** The colour preset (the `doc` point's `dgm:prSet/@csTypeId`). */
4951
+ get colorsTypeId() {
4952
+ return this.#docPrSetAttr("csTypeId");
4953
+ }
4954
+ /** The layout definition part (`dgm:relIds/@r:lo`), or `null` when missing from the package. */
4955
+ get layoutPart() {
4956
+ return this.#relPart("r:lo");
4957
+ }
4958
+ /** The quick-style part (`dgm:relIds/@r:qs`), or `null` when missing from the package. */
4959
+ get quickStylePart() {
4960
+ return this.#relPart("r:qs");
4961
+ }
4962
+ /** The colours part (`dgm:relIds/@r:cs`), or `null` when missing from the package. */
4963
+ get colorsPart() {
4964
+ return this.#relPart("r:cs");
4965
+ }
4966
+ /**
4967
+ * The fallback drawing part (`dsp:drawing`) that renders the diagram for a consumer with
4968
+ * no SmartArt layout engine, or `null` when the deck carries none. It is named by an MS
4969
+ * extension on the data model rather than by `dgm:relIds`, so a slide holding two
4970
+ * diagrams still resolves each to its own drawing.
4971
+ */
4972
+ get drawingPart() {
4973
+ const root = this.#root();
4974
+ const extLst = root && firstChild(root, "dgm:extLst");
4975
+ if (!extLst) return null;
4976
+ for (const ext of getElements(extLst, "a:ext")) {
4977
+ if (attr(ext, "uri") !== DRAWING_EXT_URI) continue;
4978
+ const dataModelExt = firstChildElement(ext);
4979
+ if (!dataModelExt || dataModelExt.localName !== "dataModelExt") continue;
4980
+ return this.#partForRelId(attr(dataModelExt, "relId"));
4981
+ }
4982
+ return null;
4983
+ }
4984
+ /** Escape hatch: the underlying `dgm:dataModel` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
4985
+ get element_() {
4986
+ return this.part.dom.documentElement;
4987
+ }
4988
+ /** Mark the diagram data part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
4989
+ markDirty() {
4990
+ this.part.markDirty();
4991
+ }
4992
+ #root() {
4993
+ return this.part.dom.documentElement;
4994
+ }
4995
+ #cycleError(modelId) {
4996
+ return new PackageReadError("diagram/parent-edge-cycle", `Diagram ${this.part.partName} has a parOf cycle reaching point ${modelId}, so its points do not form a tree`);
4997
+ }
4998
+ /**
4999
+ * The `doc` point's `dgm:prSet`, which carries all three preset ids — resolved once
5000
+ * rather than once per getter, since each lookup is a scan of the whole `ptLst`.
5001
+ * `undefined` means "not looked up yet"; `null` means "looked up, not there".
5002
+ */
5003
+ #docPrSet() {
5004
+ if (this.#docPrSetCache !== void 0) return this.#docPrSetCache;
5005
+ const root = this.#root();
5006
+ const ptLst = root && firstChild(root, "dgm:ptLst");
5007
+ const doc = ptLst && getElements(ptLst, "dgm:pt").find((pt) => attr(pt, "type") === "doc");
5008
+ return this.#docPrSetCache = doc && firstChild(doc, "dgm:prSet") || null;
5009
+ }
5010
+ #docPrSetAttr(name) {
5011
+ const prSet = this.#docPrSet();
5012
+ return prSet ? attr(prSet, name) : null;
5013
+ }
5014
+ /**
5015
+ * The drawing index, built on first use and kept — see {@link DrawingIndex} for what that
5016
+ * memo costs a consumer who mutates the drawing part's shape tree by hand.
5017
+ */
5018
+ #drawingIndex() {
5019
+ return this.#drawing ??= new DrawingIndex(this.#root(), this.drawingPart, this.themeContext);
5020
+ }
5021
+ #relPart(qname) {
5022
+ return this.#partForRelId(attr(this.relIds, qname));
5023
+ }
5024
+ #partForRelId(relId) {
5025
+ if (!relId) return null;
5026
+ return this.opc.part(this.frameRelationships.resolveTarget(relId)) ?? null;
5027
+ }
5028
+ };
5029
+ /** An `ST_ModelId` attribute whose schema default `0` means "unset" rather than naming a point. */
5030
+ function idAttr(element, name) {
5031
+ const raw = attr(element, name);
5032
+ return raw === null || raw === "" || raw === "0" ? null : raw;
5033
+ }
5034
+ //#endregion
4408
5035
  //#region src/read/api/table-edit.ts
4409
5036
  /**
4410
5037
  * Ordered mutation of a table cell's `a:tcPr`, and the cell-scoped schema facts every such
@@ -5675,16 +6302,20 @@ var TableCell = class {
5675
6302
  //#endregion
5676
6303
  //#region src/read/api/shapes/graphic-frame.ts
5677
6304
  /**
5678
- * A graphic frame (`p:graphicFrame`) — the host element for a table, a chart, or a chartEx chart.
6305
+ * A graphic frame (`p:graphicFrame`) — the host element for a table, a chart, a chartEx
6306
+ * chart, or a SmartArt diagram.
5679
6307
  *
5680
- * Which one it holds is told by the `a:graphicData/@uri`, so the accessors below each check that
5681
- * URI before wrapping the payload; `graphicDataUri` is there for the frames this library does not
5682
- * model (SmartArt, OLE, ink), which read as a frame with no table and no chart.
6308
+ * Which one it holds is told by the `a:graphicData/@uri`, so the accessors below each check
6309
+ * that URI before wrapping the payload. {@link GraphicFrame.graphicDataUri} reports it raw,
6310
+ * which is the only signal for the frames this library still does not model (OLE, ink):
6311
+ * without it a consumer cannot tell "this frame holds content I cannot reach" from "this
6312
+ * frame holds a chart with nothing in it", since every predicate answers `false` for both.
5683
6313
  */
5684
6314
  const A_TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
5685
6315
  const A_CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
5686
6316
  const A_CHARTEX_URI = "http://schemas.microsoft.com/office/drawing/2014/chartex";
5687
- /** A graphic frame (`p:graphicFrame`) — host for tables and charts. */
6317
+ const A_DIAGRAM_URI = "http://schemas.openxmlformats.org/drawingml/2006/diagram";
6318
+ /** A graphic frame (`p:graphicFrame`) — host for tables, charts and SmartArt diagrams. */
5688
6319
  var GraphicFrame = class extends Shape {
5689
6320
  shapeType = "graphicFrame";
5690
6321
  xfrm() {
@@ -5708,6 +6339,22 @@ var GraphicFrame = class extends Shape {
5708
6339
  get hasChartEx() {
5709
6340
  return this.#graphicDataUri() === A_CHARTEX_URI;
5710
6341
  }
6342
+ /** Whether this frame hosts a SmartArt diagram (`a:graphicData/@uri` is the diagram URI). */
6343
+ get hasDiagram() {
6344
+ return this.#graphicDataUri() === A_DIAGRAM_URI;
6345
+ }
6346
+ /**
6347
+ * The `a:graphicData/@uri` verbatim — the namespace naming what this frame hosts, or
6348
+ * `null` when the frame carries no `a:graphicData`.
6349
+ *
6350
+ * Every `has*` predicate is a comparison against this, so a frame whose URI matches none
6351
+ * of them is one the read model does not decode (an OLE object, an ink `p:contentPart`).
6352
+ * Reading the URI is what lets a consumer say *which* construct it could not reach
6353
+ * instead of inferring loss from four `false`s.
6354
+ */
6355
+ get graphicDataUri() {
6356
+ return this.#graphicDataUri();
6357
+ }
5711
6358
  /** The hosted table, or `null` when this frame is not a table. */
5712
6359
  get table() {
5713
6360
  if (!this.hasTable) return null;
@@ -5742,6 +6389,22 @@ var GraphicFrame = class extends Shape {
5742
6389
  const part = this.host.opc.part(partName);
5743
6390
  return part ? new ChartEx(part) : null;
5744
6391
  }
6392
+ /**
6393
+ * The hosted SmartArt diagram, or `null` when this frame is not a diagram or its data
6394
+ * part is missing. The payload child is `dgm:relIds`, which names four parts by
6395
+ * relationship id; the `@r:dm` one is the data model this resolves.
6396
+ */
6397
+ get diagram() {
6398
+ if (!this.hasDiagram) return null;
6399
+ const graphicData = this.#graphicData();
6400
+ const relIds = graphicData && firstChild(graphicData, "dgm:relIds");
6401
+ if (!relIds) return null;
6402
+ const relId = attr(relIds, "r:dm");
6403
+ if (!relId) return null;
6404
+ const partName = this.host.relationships.resolveTarget(relId);
6405
+ const part = this.host.opc.part(partName);
6406
+ return part ? new Diagram(part, relIds, this.host.opc, this.host.relationships, this.host.themeContext()) : null;
6407
+ }
5745
6408
  #graphicData() {
5746
6409
  const graphic = firstChild(this.element, "a:graphic");
5747
6410
  return graphic ? firstChild(graphic, "a:graphicData") : null;
@@ -5923,6 +6586,6 @@ function findShapeByIdDeep(shapes, id) {
5923
6586
  }
5924
6587
  }
5925
6588
  //#endregion
5926
- export { parseClrScheme as $, readGradientFill as A, getElements as At, placeholderInheritedAnchor as B, setAttr as Bt, Shape as C, boolValue as Ct, spPrXfrmEmu as D, escapeXmlAttribute as Dt, TextFrame as E, descendantsByTag as Et, resolveSlideColorContext as F, parseXml as Ft, placeholderOf as G, placeholderInheritedListStyles as H, resolveSlideThemeParts as I, removeAttr as It, SCHEME_SLOTS as J, slideDefinesColor as K, applyColorTransforms as L, removeChildrenByQName as Lt, resolveLayoutColorContext as M, insertInOrder as Mt, resolveMasterColorContext as N, intValue as Nt, readPatternFill as O, firstChild as Ot, resolveNotesColorContext as P, ownerDocumentOf as Pt, parseClrMap as Q, LST_STYLE_LEVELS as R, replaceInParent as Rt, AutoShape as S, attr as St, Run as T, createElement as Tt, placeholderInheritedRunProps as U, placeholderInheritedColor as V, placeholderInheritedXfrm as W, intAttr as X, fmtEntry as Y, isA as Z, Chart as _, relsPartNameFor as _t, isConnector as a, FILL_CHOICES as at, Connector as b, zipPathToPartName as bt, isPicture as c, SPPR_AFTER_XFRM as ct, Table as d, SPPR_LN_AFTER as dt, resolveColor as et, TableCell as f, SPPR_SCENE3D_AFTER as ft, ChartExSeries as g, relativePartName as gt, ChartExAxis as h, partNameToZipPath as ht, isAutoShape as i, substitutePhClr as it, resolveColorElement as j, getOrAddChild as jt, readPictureFill as k, firstChildElement as kt, wrapShapeElement as l, SPPR_EFFECT_AFTER as lt, ChartEx as m, partNameExtension as mt, buildShapes as n, styleRefFill as nt, isGraphicFrame as o, RPR_FILL_AFTER as ot, TableRow as p, SPPR_SP3D_AFTER as pt, slideDefinesProp as q, findShapeByIdDeep as r, styleRefLine as rt, isGroupShape as s, SHAPE_AFTER_SPPR as st, GroupShape as t, resolveSchemeToken as tt, GraphicFrame as u, SPPR_FILL_AFTER as ut, ChartAxis as v, resolveRelativePartName as vt, Paragraph as w, childElements as wt, Picture as x, OOXML_NS as xt, ChartSeries as y, resolveSingleRel as yt, RUN_PROP_NAMES as z, serializeXml as zt };
6589
+ export { carriedDecorations as $, spPrXfrmEmu as A, resolveSingleRel as At, applyColorTransforms as B, getElements as Bt, Connector as C, SPPR_SCENE3D_AFTER as Ct, Paragraph as D, relativePartName as Dt, Shape as E, partNameToZipPath as Et, resolveLayoutColorContext as F, createElement as Ft, placeholderInheritedListStyles as G, parseXml as Gt, RUN_PROP_NAMES as H, insertInOrder as Ht, resolveMasterColorContext as I, descendantsByTag as It, placeholderOf as J, replaceInParent as Jt, placeholderInheritedRunProps as K, removeAttr as Kt, resolveNotesColorContext as L, escapeXmlAttribute as Lt, readPictureFill as M, attr as Mt, readGradientFill as N, boolValue as Nt, Run as O, relsPartNameFor as Ot, resolveColorElement as P, childElements as Pt, cSldOf as Q, resolveSlideColorContext as R, firstChild as Rt, ChartSeries as S, SPPR_LN_AFTER as St, AutoShape as T, partNameExtension as Tt, placeholderInheritedAnchor as U, intValue as Ut, LST_STYLE_LEVELS as V, getOrAddChild as Vt, placeholderInheritedColor as W, ownerDocumentOf as Wt, slideDefinesProp as X, setAttr as Xt, slideDefinesColor as Y, serializeXml as Yt, cSldName as Z, ChartEx as _, RPR_FILL_AFTER as _t, isConnector as a, SCHEME_SLOTS as at, Chart as b, SPPR_EFFECT_AFTER as bt, isPicture as c, isA as ct, Table as d, resolveColor as dt, collectElements as et, TableCell as f, resolveSchemeToken as ft, DiagramPoint as g, FILL_CHOICES as gt, DiagramNode as h, substitutePhClr as ht, isAutoShape as i, spTreeOf as it, readPatternFill as j, zipPathToPartName as jt, TextFrame as k, resolveRelativePartName as kt, wrapShapeElement as l, parseClrMap as lt, Diagram as m, styleRefLine as mt, buildShapes as n, nthShapeChild as nt, isGraphicFrame as o, fmtEntry as ot, TableRow as p, styleRefFill as pt, placeholderInheritedXfrm as q, removeChildrenByQName as qt, findShapeByIdDeep as r, nvPrOf as rt, isGroupShape as s, intAttr as st, GroupShape as t, firstShapeChild as tt, GraphicFrame as u, parseClrScheme as ut, ChartExAxis as v, SHAPE_AFTER_SPPR as vt, Picture as w, SPPR_SP3D_AFTER as wt, ChartAxis as x, SPPR_FILL_AFTER as xt, ChartExSeries as y, SPPR_AFTER_XFRM as yt, resolveSlideThemeParts as z, firstChildElement as zt };
5927
6590
 
5928
- //# sourceMappingURL=shapes-BXVgsk0F.js.map
6591
+ //# sourceMappingURL=shapes-Kt51vry6.js.map