pptx-kit 0.7.0 → 0.9.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.
@@ -183,6 +183,35 @@ const pi = (target, data) => ({
183
183
  data
184
184
  });
185
185
  const qnameEquals = (a, b) => a.localName === b.localName && a.namespaceURI === b.namespaceURI;
186
+ /**
187
+ * Inserts `element` into `parent.children` at the slot dictated by `rankOf`,
188
+ * keeping element children ordered by ascending rank (stable for equal ranks).
189
+ *
190
+ * Many OOXML complex types are `xsd:sequence`s: a child must appear in a fixed
191
+ * order relative to its siblings or the part fails schema validation. Setters
192
+ * that `push`/`unshift` produce valid output only when the caller happens to
193
+ * invoke them in schema order — fragile across independent mutation calls.
194
+ * Callers should strip any pre-existing same-element first, then use this to
195
+ * drop the new element at its mandated position regardless of call order.
196
+ *
197
+ * `rankOf` returns the sibling's sequence position; return a large number for
198
+ * trailing/unknown children so they sort to the end. Non-element nodes are
199
+ * skipped when scanning, and the new element lands before the first existing
200
+ * element whose rank is strictly greater.
201
+ */
202
+ const insertChildByRank = (parent, element, rankOf) => {
203
+ const rank = rankOf(element);
204
+ let idx = parent.children.length;
205
+ for (let i = 0; i < parent.children.length; i++) {
206
+ const child = parent.children[i];
207
+ if (child?.kind !== "element") continue;
208
+ if (rankOf(child) > rank) {
209
+ idx = i;
210
+ break;
211
+ }
212
+ }
213
+ parent.children.splice(idx, 0, element);
214
+ };
186
215
  //#endregion
187
216
  //#region src/internal/xml/namespaces.ts
188
217
  const NS = {
@@ -571,10 +600,17 @@ const walkElements = (root, visit) => {
571
600
  };
572
601
  //#endregion
573
602
  //#region src/internal/xml/serialize.ts
603
+ const rejectForbiddenControlChar = (c) => {
604
+ if (c < 32 && c !== 9 && c !== 10 && c !== 13) {
605
+ const hex = c.toString(16).toUpperCase().padStart(4, "0");
606
+ throw new Error(`XML-illegal control character U+${hex} in text; strip control characters before authoring`);
607
+ }
608
+ };
574
609
  const escapeAttr = (s) => {
575
610
  let out = "";
576
611
  for (let i = 0; i < s.length; i++) {
577
612
  const c = s.charCodeAt(i);
613
+ rejectForbiddenControlChar(c);
578
614
  if (c === 38) out += "&amp;";
579
615
  else if (c === 60) out += "&lt;";
580
616
  else if (c === 62) out += "&gt;";
@@ -590,6 +626,7 @@ const escapeText = (s) => {
590
626
  let out = "";
591
627
  for (let i = 0; i < s.length; i++) {
592
628
  const c = s.charCodeAt(i);
629
+ rejectForbiddenControlChar(c);
593
630
  if (c === 38) out += "&amp;";
594
631
  else if (c === 60) out += "&lt;";
595
632
  else if (c === 62) out += "&gt;";
@@ -1501,8 +1538,11 @@ const textBodyText = (txBody) => {
1501
1538
  const NAME_BU_CHAR = qname("a", "buChar", NS.dml);
1502
1539
  const NAME_BU_AUTO_NUM = qname("a", "buAutoNum", NS.dml);
1503
1540
  const NAME_BU_NONE$1 = qname("a", "buNone", NS.dml);
1541
+ const NAME_BU_FONT = qname("a", "buFont", NS.dml);
1504
1542
  const ATTR_CHAR = qname("", "char", "");
1505
1543
  const ATTR_BU_TYPE = qname("", "type", "");
1544
+ const ATTR_START_AT = qname("", "startAt", "");
1545
+ const ATTR_TYPEFACE$2 = qname("", "typeface", "");
1506
1546
  const NAME_P$5 = qname("a", "p", NS.dml);
1507
1547
  const NAME_R$4 = qname("a", "r", NS.dml);
1508
1548
  const NAME_T$5 = qname("a", "t", NS.dml);
@@ -1650,7 +1690,7 @@ const buildBulletElement = (style) => {
1650
1690
  const n = normalizeBulletStyle(style);
1651
1691
  switch (n.kind) {
1652
1692
  case "char": return elem(NAME_BU_CHAR, { attrs: [attr(ATTR_CHAR, n.char)] });
1653
- case "autoNum": return elem(NAME_BU_AUTO_NUM, { attrs: [attr(ATTR_BU_TYPE, n.type)] });
1693
+ case "autoNum": return elem(NAME_BU_AUTO_NUM, { attrs: [attr(ATTR_START_AT, "1"), attr(ATTR_BU_TYPE, n.type)] });
1654
1694
  case "none": return elem(NAME_BU_NONE$1);
1655
1695
  }
1656
1696
  };
@@ -1726,13 +1766,14 @@ const applyBulletToParagraph = (paragraph, style) => {
1726
1766
  pPr = elem(NAME_PPR_FOR_BULLET);
1727
1767
  paragraph.children.unshift(pPr);
1728
1768
  }
1729
- pPr.children = pPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && (c.name.localName === "buChar" || c.name.localName === "buAutoNum" || c.name.localName === "buNone")));
1769
+ pPr.children = pPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && (c.name.localName === "buChar" || c.name.localName === "buAutoNum" || c.name.localName === "buNone" || c.name.localName === "buFont")));
1730
1770
  if (style !== "none") {
1731
1771
  const lvl = Number.parseInt(pPr.attrs.find((a) => a.name.localName === "lvl")?.value ?? "0", 10);
1732
1772
  const { marL, indent } = bulletIndentForLevel(Number.isFinite(lvl) ? lvl : 0);
1733
1773
  if (!hasAttr(pPr, "marL")) pPr.attrs.push(attr(ATTR_MAR_L$1, String(marL)));
1734
1774
  if (!hasAttr(pPr, "indent")) pPr.attrs.push(attr(ATTR_INDENT$1, String(indent)));
1735
1775
  }
1776
+ if (normalizeBulletStyle(style).kind === "autoNum") pPr.children.push(elem(NAME_BU_FONT, { attrs: [attr(ATTR_TYPEFACE$2, "+mj-lt")] }));
1736
1777
  pPr.children.push(buildBulletElement(style));
1737
1778
  };
1738
1779
  /**
@@ -1772,28 +1813,74 @@ const setTextBody = (txBody, value) => {
1772
1813
  }
1773
1814
  };
1774
1815
  //#endregion
1775
- //#region src/internal/drawingml/text-format.ts
1776
- NS.dml;
1777
- const NAME_RPR$5 = qname("a", "rPr", NS.dml);
1778
- const NAME_LATIN = qname("a", "latin", NS.dml);
1779
- NS.dml;
1780
- NS.dml;
1781
- const NAME_SOLID_FILL$6 = qname("a", "solidFill", NS.dml);
1816
+ //#region src/internal/bounds.ts
1817
+ const RANGES = {
1818
+ coordinate: [-27273042329600, 27273042316900],
1819
+ positiveCoordinate: [0, 27273042316900],
1820
+ coordinate32: [-2147483648, 2147483647],
1821
+ positiveCoordinate32: [0, 2147483647],
1822
+ lineWidth: [0, 20116800],
1823
+ angle: [-2147483648, 2147483647],
1824
+ fontSize: [100, 4e5],
1825
+ textPoint: [-4e5, 4e5],
1826
+ textSpacingPoint: [0, 158400],
1827
+ unsignedInt: [0, 4294967295],
1828
+ columnCount: [1, 16],
1829
+ overlap: [-100, 100],
1830
+ gapAmount: [0, 500],
1831
+ holeSize: [1, 90],
1832
+ firstSliceAng: [0, 360]
1833
+ };
1834
+ const boundedInt = (value, key, field) => {
1835
+ if (!Number.isFinite(value)) throw new RangeError(`${field}: expected a finite number, got ${value}`);
1836
+ const n = Math.round(value);
1837
+ const [min, max] = RANGES[key];
1838
+ if (n < min || n > max) throw new RangeError(`${field}: ${value} is out of range for ${key} (${min}..${max})`);
1839
+ return n;
1840
+ };
1841
+ /** EMU position coordinate (`<a:off>` x/y) — ST_Coordinate. */
1842
+ const emuCoordinate = (v, field) => boundedInt(v, "coordinate", field);
1843
+ /** EMU extent (`<a:ext>` cx/cy, column/table widths, row heights) — ST_PositiveCoordinate. */
1844
+ const emuExtent = (v, field) => boundedInt(v, "positiveCoordinate", field);
1845
+ /** 32-bit EMU (text-body insets, cell margins) — ST_Coordinate32. */
1846
+ const emuCoordinate32 = (v, field) => boundedInt(v, "coordinate32", field);
1847
+ /** Non-negative 32-bit EMU (column gap) — ST_PositiveCoordinate32. */
1848
+ const emuPositiveCoordinate32 = (v, field) => boundedInt(v, "positiveCoordinate32", field);
1849
+ /** Line width in EMU — ST_LineWidth. */
1850
+ const lineWidthEmu = (v, field) => boundedInt(v, "lineWidth", field);
1851
+ /** Angle in 1/60000 degree — ST_Angle. */
1852
+ const angle60000 = (v, field) => boundedInt(v, "angle", field);
1853
+ /** Font size in 1/100 pt — ST_TextFontSize. */
1854
+ const fontSizeHundredthPt = (v, field) => boundedInt(v, "fontSize", field);
1855
+ /** Character spacing in 1/100 pt — ST_TextPoint. */
1856
+ const textPointSpacing = (v, field) => boundedInt(v, "textPoint", field);
1857
+ /** Auto-advance / timing duration in ms — xsd:unsignedInt. */
1858
+ const unsignedIntMs = (v, field) => boundedInt(v, "unsignedInt", field);
1859
+ /** Text column count — ST_TextColumnCount (1..16). */
1860
+ const textColumnCount = (v, field) => boundedInt(v, "columnCount", field);
1861
+ /** Bar/column series overlap percent — ST_OverlapByte (-100..100). */
1862
+ const overlapPercent = (v, field) => boundedInt(v, "overlap", field);
1863
+ /** Bar/column gap width percent — ST_GapAmount (0..500). */
1864
+ const gapAmountPercent = (v, field) => boundedInt(v, "gapAmount", field);
1865
+ /** Doughnut hole size percent — ST_HoleSizeUByte (1..90). */
1866
+ const holeSizePercent = (v, field) => boundedInt(v, "holeSize", field);
1867
+ /** Pie/doughnut first-slice angle in degrees — ST_FirstSliceAng (0..360). */
1868
+ const firstSliceAngle = (v, field) => boundedInt(v, "firstSliceAng", field);
1869
+ const GUID_RE = /^\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\}$/;
1870
+ const normalizeGuid = (value, field) => {
1871
+ if (!GUID_RE.test(value)) throw new RangeError(`${field}: ${JSON.stringify(value)} is not a GUID of the form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}`);
1872
+ return value.toUpperCase();
1873
+ };
1874
+ const oneOf = (value, allowed, field) => {
1875
+ if (!allowed.includes(value)) throw new RangeError(`${field}: ${JSON.stringify(value)} is not one of: ${allowed.join(", ")}`);
1876
+ return value;
1877
+ };
1878
+ //#endregion
1879
+ //#region src/internal/drawingml/color.ts
1782
1880
  const NAME_SRGB_CLR$4 = qname("a", "srgbClr", NS.dml);
1783
- const NAME_SCHEME_CLR$1 = qname("a", "schemeClr", NS.dml);
1784
- const ATTR_SZ = qname("", "sz", "");
1785
- const ATTR_B = qname("", "b", "");
1786
- const ATTR_I = qname("", "i", "");
1787
- const ATTR_U = qname("", "u", "");
1788
- const ATTR_STRIKE = qname("", "strike", "");
1789
- const ATTR_SPC = qname("", "spc", "");
1790
- const ATTR_KERN = qname("", "kern", "");
1791
- const ATTR_BASELINE = qname("", "baseline", "");
1792
- const ATTR_CAP = qname("", "cap", "");
1793
- const ATTR_TYPEFACE$1 = qname("", "typeface", "");
1794
- const ATTR_VAL$7 = qname("", "val", "");
1795
- const NAME_HIGHLIGHT = qname("a", "highlight", NS.dml);
1796
- const SCHEME_TOKENS$1 = new Set([
1881
+ const NAME_SCHEME_CLR$2 = qname("a", "schemeClr", NS.dml);
1882
+ const ATTR_VAL$8 = qname("", "val", "");
1883
+ const SCHEME_TOKENS = new Set([
1797
1884
  "bg1",
1798
1885
  "tx1",
1799
1886
  "bg2",
@@ -1812,18 +1899,105 @@ const SCHEME_TOKENS$1 = new Set([
1812
1899
  "lt2",
1813
1900
  "dk2"
1814
1901
  ]);
1815
- const parseColor$1 = (value) => {
1816
- if (SCHEME_TOKENS$1.has(value)) return {
1902
+ /**
1903
+ * Normalizes an sRGB hex string to the canonical uppercase 6-digit form
1904
+ * (no `#`), or returns `null` if it isn't a 3- or 6-digit hex. The CSS-style
1905
+ * 3-digit shorthand (`#f00` → `FF0000`) is accepted because LLM authors reach
1906
+ * for it constantly; 4-/8-digit (alpha) forms are rejected rather than
1907
+ * silently dropping the alpha channel, which OOXML encodes separately.
1908
+ */
1909
+ const normalizeSrgbHex = (value) => {
1910
+ const hex = value.startsWith("#") ? value.slice(1) : value;
1911
+ if (/^[0-9A-Fa-f]{6}$/.test(hex)) return hex.toUpperCase();
1912
+ if (/^[0-9A-Fa-f]{3}$/.test(hex)) return Array.from(hex, (ch) => ch + ch).join("").toUpperCase();
1913
+ return null;
1914
+ };
1915
+ /**
1916
+ * Parses a user-supplied color string. Returns null on unrecognized input
1917
+ * so callers can decide whether to throw with a specific message.
1918
+ *
1919
+ * Scheme tokens are accepted both bare (`accent1`) and with the explicit
1920
+ * `scheme:` prefix (`scheme:accent1`). The prefixed form is what the getters
1921
+ * (`getShapeFillColor`, `getSlideBackground`, …) return, so accepting it here
1922
+ * is what makes `setX(getX(...))` round-trip instead of throwing.
1923
+ */
1924
+ const parseColor = (value) => {
1925
+ const token = value.startsWith("scheme:") ? value.slice(7) : value;
1926
+ if (SCHEME_TOKENS.has(token)) return {
1817
1927
  kind: "scheme",
1818
- token: value
1928
+ token
1819
1929
  };
1820
- const hex = value.startsWith("#") ? value.slice(1) : value;
1821
- if (/^[0-9A-Fa-f]{6}$/.test(hex)) return {
1930
+ if (value !== token) return null;
1931
+ const hex = normalizeSrgbHex(value);
1932
+ return hex === null ? null : {
1822
1933
  kind: "srgb",
1823
- hex: hex.toUpperCase()
1934
+ hex
1824
1935
  };
1825
- return null;
1826
1936
  };
1937
+ /**
1938
+ * Parses an sRGB hex color (`#RRGGBB`, `RRGGBB`, or the 3-digit `#RGB`
1939
+ * shorthand), returning the normalized uppercase 6-digit hex (no `#`).
1940
+ * Returns `null` for anything else — including scheme tokens, which sRGB-only
1941
+ * contexts (e.g. chart series fills) must reject rather than silently
1942
+ * emit as an invalid `<a:srgbClr val="accent1"/>`.
1943
+ */
1944
+ const parseSrgbHex = (value) => normalizeSrgbHex(value);
1945
+ /**
1946
+ * Returns the `<a:srgbClr>` or `<a:schemeClr>` element for `value`.
1947
+ * Throws on unrecognized colors.
1948
+ */
1949
+ const buildColorElement = (value) => {
1950
+ const parsed = parseColor(value);
1951
+ if (parsed === null) throw new Error(`unrecognized color: ${value}`);
1952
+ return parsed.kind === "srgb" ? elem(NAME_SRGB_CLR$4, { attrs: [attr(ATTR_VAL$8, parsed.hex)] }) : elem(NAME_SCHEME_CLR$2, { attrs: [attr(ATTR_VAL$8, parsed.token)] });
1953
+ };
1954
+ //#endregion
1955
+ //#region src/internal/drawingml/text-format.ts
1956
+ NS.dml;
1957
+ const NAME_RPR$5 = qname("a", "rPr", NS.dml);
1958
+ const NAME_LATIN = qname("a", "latin", NS.dml);
1959
+ NS.dml;
1960
+ NS.dml;
1961
+ const NAME_SOLID_FILL$6 = qname("a", "solidFill", NS.dml);
1962
+ const NAME_SRGB_CLR$3 = qname("a", "srgbClr", NS.dml);
1963
+ const NAME_SCHEME_CLR$1 = qname("a", "schemeClr", NS.dml);
1964
+ const ATTR_SZ = qname("", "sz", "");
1965
+ const ATTR_B = qname("", "b", "");
1966
+ const ATTR_I = qname("", "i", "");
1967
+ const ATTR_U = qname("", "u", "");
1968
+ const ATTR_STRIKE = qname("", "strike", "");
1969
+ const ATTR_SPC = qname("", "spc", "");
1970
+ const ATTR_KERN = qname("", "kern", "");
1971
+ const ATTR_BASELINE = qname("", "baseline", "");
1972
+ const ATTR_CAP = qname("", "cap", "");
1973
+ const ATTR_TYPEFACE$1 = qname("", "typeface", "");
1974
+ const ATTR_VAL$7 = qname("", "val", "");
1975
+ const NAME_HIGHLIGHT = qname("a", "highlight", NS.dml);
1976
+ const RPR_CHILD_RANK = {
1977
+ ln: 0,
1978
+ noFill: 1,
1979
+ solidFill: 1,
1980
+ gradFill: 1,
1981
+ blipFill: 1,
1982
+ pattFill: 1,
1983
+ grpFill: 1,
1984
+ effectLst: 2,
1985
+ effectDag: 2,
1986
+ highlight: 3,
1987
+ uLnTx: 4,
1988
+ uLn: 4,
1989
+ uFillTx: 5,
1990
+ uFill: 5,
1991
+ latin: 6,
1992
+ ea: 7,
1993
+ cs: 8,
1994
+ sym: 9,
1995
+ hlinkClick: 10,
1996
+ hlinkMouseOver: 11,
1997
+ rtl: 12,
1998
+ extLst: 13
1999
+ };
2000
+ const rprChildRank = (el) => el.name.namespaceURI === NS.dml ? RPR_CHILD_RANK[el.name.localName] ?? 99 : 99;
1827
2001
  const setOrRemoveAttr = (attrs, name, value) => {
1828
2002
  const filtered = attrs.filter((a) => a.name.localName !== name.localName);
1829
2003
  if (value !== null) filtered.push(attr(name, value));
@@ -1832,29 +2006,27 @@ const setOrRemoveAttr = (attrs, name, value) => {
1832
2006
  const setSolidFill$1 = (rPr, value) => {
1833
2007
  rPr.children = rPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "solidFill"));
1834
2008
  if (value === null) return;
1835
- const parsed = parseColor$1(value);
2009
+ const parsed = parseColor(value);
1836
2010
  if (parsed === null) throw new Error(`unrecognized color: ${value}`);
1837
- const fill = elem(NAME_SOLID_FILL$6, { children: [parsed.kind === "srgb" ? elem(NAME_SRGB_CLR$4, { attrs: [attr(ATTR_VAL$7, parsed.hex)] }) : elem(NAME_SCHEME_CLR$1, { attrs: [attr(ATTR_VAL$7, parsed.token)] })] });
1838
- rPr.children.unshift(fill);
2011
+ insertChildByRank(rPr, elem(NAME_SOLID_FILL$6, { children: [parsed.kind === "srgb" ? elem(NAME_SRGB_CLR$3, { attrs: [attr(ATTR_VAL$7, parsed.hex)] }) : elem(NAME_SCHEME_CLR$1, { attrs: [attr(ATTR_VAL$7, parsed.token)] })] }), rprChildRank);
1839
2012
  };
1840
2013
  const setLatin = (rPr, font) => {
1841
2014
  rPr.children = rPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "latin"));
1842
2015
  if (font === null) return;
1843
- rPr.children.push(elem(NAME_LATIN, { attrs: [attr(ATTR_TYPEFACE$1, font)] }));
2016
+ insertChildByRank(rPr, elem(NAME_LATIN, { attrs: [attr(ATTR_TYPEFACE$1, font)] }), rprChildRank);
1844
2017
  };
1845
2018
  const setHighlight = (rPr, value) => {
1846
2019
  rPr.children = rPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "highlight"));
1847
2020
  if (value === null) return;
1848
- const parsed = parseColor$1(value);
2021
+ const parsed = parseColor(value);
1849
2022
  if (parsed === null) throw new Error(`unrecognized highlight color: ${value}`);
1850
- const inner = parsed.kind === "srgb" ? elem(NAME_SRGB_CLR$4, { attrs: [attr(ATTR_VAL$7, parsed.hex)] }) : elem(NAME_SCHEME_CLR$1, { attrs: [attr(ATTR_VAL$7, parsed.token)] });
1851
- rPr.children.unshift(elem(NAME_HIGHLIGHT, { children: [inner] }));
2023
+ insertChildByRank(rPr, elem(NAME_HIGHLIGHT, { children: [parsed.kind === "srgb" ? elem(NAME_SRGB_CLR$3, { attrs: [attr(ATTR_VAL$7, parsed.hex)] }) : elem(NAME_SCHEME_CLR$1, { attrs: [attr(ATTR_VAL$7, parsed.token)] })] }), rprChildRank);
1852
2024
  };
1853
2025
  /** Mutates `rPr` in place per `format`. */
1854
2026
  const applyRunFormat = (rPr, format) => {
1855
2027
  let attrs = rPr.attrs;
1856
2028
  if (format.size !== void 0) {
1857
- const sz = Math.round(format.size * 100);
2029
+ const sz = fontSizeHundredthPt(format.size * 100, "setShapeRunFormat: size");
1858
2030
  attrs = setOrRemoveAttr(attrs, ATTR_SZ, String(sz));
1859
2031
  }
1860
2032
  if (format.bold !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_B, format.bold ? "1" : "0");
@@ -1867,7 +2039,10 @@ const applyRunFormat = (rPr, format) => {
1867
2039
  const value = format.strike === false ? "noStrike" : format.strike === true ? "sngStrike" : format.strike;
1868
2040
  attrs = setOrRemoveAttr(attrs, ATTR_STRIKE, value);
1869
2041
  }
1870
- if (format.spc !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_SPC, String(Math.round(format.spc)));
2042
+ if (format.spc !== void 0) {
2043
+ const spc = textPointSpacing(format.spc, "setShapeRunFormat: spc");
2044
+ attrs = setOrRemoveAttr(attrs, ATTR_SPC, String(spc));
2045
+ }
1871
2046
  if (format.kern !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_KERN, String(Math.round(format.kern)));
1872
2047
  if (format.baseline !== void 0) {
1873
2048
  const pct = Math.round(format.baseline * 1e5);
@@ -1899,66 +2074,6 @@ const applyFormatToAllRuns = (txBody, format) => {
1899
2074
  }
1900
2075
  };
1901
2076
  //#endregion
1902
- //#region src/internal/drawingml/color.ts
1903
- const NAME_SRGB_CLR$3 = qname("a", "srgbClr", NS.dml);
1904
- const NAME_SCHEME_CLR = qname("a", "schemeClr", NS.dml);
1905
- const ATTR_VAL$6 = qname("", "val", "");
1906
- const SCHEME_TOKENS = new Set([
1907
- "bg1",
1908
- "tx1",
1909
- "bg2",
1910
- "tx2",
1911
- "accent1",
1912
- "accent2",
1913
- "accent3",
1914
- "accent4",
1915
- "accent5",
1916
- "accent6",
1917
- "hlink",
1918
- "folHlink",
1919
- "phClr",
1920
- "lt1",
1921
- "dk1",
1922
- "lt2",
1923
- "dk2"
1924
- ]);
1925
- /**
1926
- * Parses a user-supplied color string. Returns null on unrecognized input
1927
- * so callers can decide whether to throw with a specific message.
1928
- */
1929
- const parseColor = (value) => {
1930
- if (SCHEME_TOKENS.has(value)) return {
1931
- kind: "scheme",
1932
- token: value
1933
- };
1934
- const hex = value.startsWith("#") ? value.slice(1) : value;
1935
- if (/^[0-9A-Fa-f]{6}$/.test(hex)) return {
1936
- kind: "srgb",
1937
- hex: hex.toUpperCase()
1938
- };
1939
- return null;
1940
- };
1941
- /**
1942
- * Parses an sRGB hex color (`#RRGGBB` or `RRGGBB`), returning the
1943
- * normalized uppercase 6-digit hex (no `#`). Returns `null` for anything
1944
- * that isn't a 6-digit hex — including scheme tokens, which sRGB-only
1945
- * contexts (e.g. chart series fills) must reject rather than silently
1946
- * emit as an invalid `<a:srgbClr val="accent1"/>`.
1947
- */
1948
- const parseSrgbHex = (value) => {
1949
- const hex = value.startsWith("#") ? value.slice(1) : value;
1950
- return /^[0-9A-Fa-f]{6}$/.test(hex) ? hex.toUpperCase() : null;
1951
- };
1952
- /**
1953
- * Returns the `<a:srgbClr>` or `<a:schemeClr>` element for `value`.
1954
- * Throws on unrecognized colors.
1955
- */
1956
- const buildColorElement = (value) => {
1957
- const parsed = parseColor(value);
1958
- if (parsed === null) throw new Error(`unrecognized color: ${value}`);
1959
- return parsed.kind === "srgb" ? elem(NAME_SRGB_CLR$3, { attrs: [attr(ATTR_VAL$6, parsed.hex)] }) : elem(NAME_SCHEME_CLR, { attrs: [attr(ATTR_VAL$6, parsed.token)] });
1960
- };
1961
- //#endregion
1962
2077
  //#region src/internal/drawingml/fill.ts
1963
2078
  const NAME_SOLID_FILL$5 = qname("a", "solidFill", NS.dml);
1964
2079
  const NAME_NO_FILL$2 = qname("a", "noFill", NS.dml);
@@ -1966,6 +2081,9 @@ const NAME_GRAD_FILL = qname("a", "gradFill", NS.dml);
1966
2081
  const NAME_GS_LST = qname("a", "gsLst", NS.dml);
1967
2082
  const NAME_GS = qname("a", "gs", NS.dml);
1968
2083
  const NAME_LIN = qname("a", "lin", NS.dml);
2084
+ const NAME_PATH = qname("a", "path", NS.dml);
2085
+ const NAME_FILL_TO_RECT = qname("a", "fillToRect", NS.dml);
2086
+ const ATTR_PATH = qname("", "path", "");
1969
2087
  const ATTR_POS = qname("", "pos", "");
1970
2088
  const ATTR_ANG = qname("", "ang", "");
1971
2089
  const ATTR_SCALED = qname("", "scaled", "");
@@ -2020,6 +2138,63 @@ const setNoFill = (host) => {
2020
2138
  const clearFill = (host) => {
2021
2139
  removeAnyFill(host);
2022
2140
  };
2141
+ /** Every `ST_PresetPatternVal` token (ECMA-376 dml-main.xsd). */
2142
+ const PATTERN_PRESETS = [
2143
+ "pct5",
2144
+ "pct10",
2145
+ "pct20",
2146
+ "pct25",
2147
+ "pct30",
2148
+ "pct40",
2149
+ "pct50",
2150
+ "pct60",
2151
+ "pct70",
2152
+ "pct75",
2153
+ "pct80",
2154
+ "pct90",
2155
+ "horz",
2156
+ "vert",
2157
+ "ltHorz",
2158
+ "ltVert",
2159
+ "dkHorz",
2160
+ "dkVert",
2161
+ "narHorz",
2162
+ "narVert",
2163
+ "dashHorz",
2164
+ "dashVert",
2165
+ "cross",
2166
+ "dnDiag",
2167
+ "upDiag",
2168
+ "ltDnDiag",
2169
+ "ltUpDiag",
2170
+ "dkDnDiag",
2171
+ "dkUpDiag",
2172
+ "wdDnDiag",
2173
+ "wdUpDiag",
2174
+ "dashDnDiag",
2175
+ "dashUpDiag",
2176
+ "diagCross",
2177
+ "smCheck",
2178
+ "lgCheck",
2179
+ "smGrid",
2180
+ "lgGrid",
2181
+ "dotGrid",
2182
+ "smConfetti",
2183
+ "lgConfetti",
2184
+ "horzBrick",
2185
+ "diagBrick",
2186
+ "solidDmnd",
2187
+ "openDmnd",
2188
+ "dotDmnd",
2189
+ "plaid",
2190
+ "sphere",
2191
+ "weave",
2192
+ "divot",
2193
+ "shingle",
2194
+ "wave",
2195
+ "trellis",
2196
+ "zigZag"
2197
+ ];
2023
2198
  const NAME_PATT_FILL = qname("a", "pattFill", NS.dml);
2024
2199
  const NAME_FG_CLR = qname("a", "fgClr", NS.dml);
2025
2200
  const NAME_BG_CLR = qname("a", "bgClr", NS.dml);
@@ -2031,7 +2206,7 @@ const ATTR_PRST$4 = qname("", "prst", "");
2031
2206
  const setPatternFill = (host, options) => {
2032
2207
  removeAnyFill(host);
2033
2208
  const pattFill = elem(NAME_PATT_FILL, {
2034
- attrs: [attr(ATTR_PRST$4, options.preset)],
2209
+ attrs: [attr(ATTR_PRST$4, oneOf(options.preset, PATTERN_PRESETS, "setShapePatternFill: preset"))],
2035
2210
  children: [elem(NAME_FG_CLR, { children: [buildColorElement(options.foreground)] }), elem(NAME_BG_CLR, { children: [buildColorElement(options.background)] })]
2036
2211
  });
2037
2212
  host.children.splice(fillInsertionIndex(host), 0, pattFill);
@@ -2047,11 +2222,22 @@ const setGradientFill = (host, options) => {
2047
2222
  children: [buildColorElement(s.color)]
2048
2223
  });
2049
2224
  });
2050
- const norm = ((options.angleDeg ?? 90) % 360 + 360) % 360;
2051
- const angleAttr = String(Math.round(norm * 6e4));
2225
+ const pct = (n) => String(Math.round(n * 1e5));
2226
+ const directionEl = options.path === void 0 || options.path === "linear" ? (() => {
2227
+ const norm = ((options.angleDeg ?? 90) % 360 + 360) % 360;
2228
+ return elem(NAME_LIN, { attrs: [attr(ATTR_ANG, String(Math.round(norm * 6e4))), attr(ATTR_SCALED, "0")] });
2229
+ })() : elem(NAME_PATH, {
2230
+ attrs: [attr(ATTR_PATH, options.path)],
2231
+ children: options.focus === void 0 ? [] : [elem(NAME_FILL_TO_RECT, { attrs: [
2232
+ attr(qname("", "l", ""), pct(options.focus.left)),
2233
+ attr(qname("", "t", ""), pct(options.focus.top)),
2234
+ attr(qname("", "r", ""), pct(options.focus.right)),
2235
+ attr(qname("", "b", ""), pct(options.focus.bottom))
2236
+ ] })]
2237
+ });
2052
2238
  const grad = elem(NAME_GRAD_FILL, {
2053
2239
  attrs: [attr(ATTR_FLIP, "none"), attr(ATTR_ROT_WITH_SHAPE$1, "1")],
2054
- children: [elem(NAME_GS_LST, { children: stops }), elem(NAME_LIN, { attrs: [attr(ATTR_ANG, angleAttr), attr(ATTR_SCALED, "0")] })]
2240
+ children: [elem(NAME_GS_LST, { children: stops }), directionEl]
2055
2241
  });
2056
2242
  host.children.splice(fillInsertionIndex(host), 0, grad);
2057
2243
  };
@@ -2067,7 +2253,7 @@ const ATTR_DIR$1 = qname("", "dir", "");
2067
2253
  const ATTR_ALGN = qname("", "algn", "");
2068
2254
  const ATTR_ROT_WITH_SHAPE = qname("", "rotWithShape", "");
2069
2255
  const ATTR_RAD = qname("", "rad", "");
2070
- const ATTR_VAL$5 = qname("", "val", "");
2256
+ const ATTR_VAL$6 = qname("", "val", "");
2071
2257
  /**
2072
2258
  * Computes the index inside `host.children` where an `<a:effectLst>`
2073
2259
  * should be inserted to satisfy the spec's child ordering on
@@ -2089,7 +2275,7 @@ const colorWithAlpha = (color, opacity) => {
2089
2275
  const base = buildColorElement(color);
2090
2276
  if (opacity !== void 0 && opacity >= 0 && opacity < 1) {
2091
2277
  const amt = Math.round(opacity * 1e5);
2092
- base.children.push(elem(NAME_ALPHA, { attrs: [attr(ATTR_VAL$5, String(amt))] }));
2278
+ base.children.push(elem(NAME_ALPHA, { attrs: [attr(ATTR_VAL$6, String(amt))] }));
2093
2279
  }
2094
2280
  return base;
2095
2281
  };
@@ -2101,8 +2287,8 @@ const colorWithAlpha = (color, opacity) => {
2101
2287
  const setShadow = (host, options = {}) => {
2102
2288
  removeEffectLst(host);
2103
2289
  const color = options.color ?? "#000000";
2104
- const blur = options.blurEmu ?? 50800;
2105
- const dist = options.offsetEmu ?? 38100;
2290
+ const blur = emuExtent(options.blurEmu ?? 50800, "setShapeShadow: blurEmu");
2291
+ const dist = emuExtent(options.offsetEmu ?? 38100, "setShapeShadow: offsetEmu");
2106
2292
  const angleDeg = options.angleDeg ?? 45;
2107
2293
  const dir = String(Math.round((angleDeg % 360 + 360) % 360 * 6e4));
2108
2294
  const effectLst = elem(NAME_EFFECT_LST, { children: [elem(NAME_OUTER_SHDW, {
@@ -2124,7 +2310,7 @@ const setShadow = (host, options = {}) => {
2124
2310
  const setGlow = (host, options) => {
2125
2311
  removeEffectLst(host);
2126
2312
  const effectLst = elem(NAME_EFFECT_LST, { children: [elem(NAME_GLOW, {
2127
- attrs: [attr(ATTR_RAD, String(options.radiusEmu ?? 63500))],
2313
+ attrs: [attr(ATTR_RAD, String(emuExtent(options.radiusEmu ?? 63500, "setShapeGlow: radiusEmu")))],
2128
2314
  children: [buildColorElement(options.color)]
2129
2315
  })] });
2130
2316
  host.children.splice(effectInsertionIndex(host), 0, effectLst);
@@ -2145,6 +2331,22 @@ const FILL_LOCALS = new Set([
2145
2331
  "gradFill",
2146
2332
  "pattFill"
2147
2333
  ]);
2334
+ const LN_CHILD_RANK = {
2335
+ noFill: 0,
2336
+ solidFill: 0,
2337
+ gradFill: 0,
2338
+ pattFill: 0,
2339
+ prstDash: 1,
2340
+ custDash: 1,
2341
+ round: 2,
2342
+ bevel: 2,
2343
+ miter: 2,
2344
+ headEnd: 3,
2345
+ tailEnd: 4,
2346
+ extLst: 5
2347
+ };
2348
+ const lnChildRank = (el) => el.name.namespaceURI === NS.dml ? LN_CHILD_RANK[el.name.localName] ?? 99 : 99;
2349
+ const insertLnChild = (ln, el) => insertChildByRank(ln, el, lnChildRank);
2148
2350
  const removeChildrenIn = (host, names) => {
2149
2351
  host.children = host.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && names.has(c.name.localName)));
2150
2352
  };
@@ -2173,23 +2375,23 @@ const setSolidStroke = (spPr, options) => {
2173
2375
  const ln = ensureLn(spPr);
2174
2376
  if (options.widthEmu !== void 0) {
2175
2377
  ln.attrs = ln.attrs.filter((a) => a.name.localName !== "w");
2176
- ln.attrs.push(attr(ATTR_W$3, String(Math.round(options.widthEmu))));
2378
+ ln.attrs.push(attr(ATTR_W$3, String(lineWidthEmu(options.widthEmu, "setShapeStroke: widthEmu"))));
2177
2379
  }
2178
2380
  removeChildrenIn(ln, FILL_LOCALS);
2179
- if (options.color !== void 0) ln.children.unshift(elem(NAME_SOLID_FILL$4, { children: [buildColorElement(options.color)] }));
2381
+ if (options.color !== void 0) insertLnChild(ln, elem(NAME_SOLID_FILL$4, { children: [buildColorElement(options.color)] }));
2180
2382
  };
2181
2383
  /** Sets an explicit "no outline" on a shape's spPr. */
2182
2384
  const setNoStroke = (spPr) => {
2183
2385
  const ln = ensureLn(spPr);
2184
2386
  removeChildrenIn(ln, FILL_LOCALS);
2185
- ln.children.unshift(elem(NAME_NO_FILL$1));
2387
+ insertLnChild(ln, elem(NAME_NO_FILL$1));
2186
2388
  };
2187
2389
  /** Removes any `<a:ln>` from a shape's spPr (restores inheritance). */
2188
2390
  const clearStroke = (spPr) => {
2189
2391
  spPr.children = spPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "ln"));
2190
2392
  };
2191
2393
  const NAME_PRST_DASH = qname("a", "prstDash", NS.dml);
2192
- const ATTR_VAL$4 = qname("", "val", "");
2394
+ const ATTR_VAL$5 = qname("", "val", "");
2193
2395
  /**
2194
2396
  * Sets `<a:prstDash val="..."/>` inside the shape's `<a:ln>`. Creates
2195
2397
  * `<a:ln>` if absent. Replacing the dash choice on subsequent calls.
@@ -2197,7 +2399,7 @@ const ATTR_VAL$4 = qname("", "val", "");
2197
2399
  const setStrokeDash = (spPr, dash) => {
2198
2400
  const ln = ensureLn(spPr);
2199
2401
  ln.children = ln.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "prstDash"));
2200
- ln.children.push(elem(NAME_PRST_DASH, { attrs: [attr(ATTR_VAL$4, dash)] }));
2402
+ insertLnChild(ln, elem(NAME_PRST_DASH, { attrs: [attr(ATTR_VAL$5, dash)] }));
2201
2403
  };
2202
2404
  const ATTR_TYPE$5 = qname("", "type", "");
2203
2405
  const ATTR_LEN = qname("", "len", "");
@@ -2218,7 +2420,7 @@ const setStrokeArrow = (spPr, end, options) => {
2218
2420
  const attrs = [attr(ATTR_TYPE$5, options.type)];
2219
2421
  if (options.width !== void 0) attrs.push(attr(ATTR_W$3, options.width));
2220
2422
  if (options.length !== void 0) attrs.push(attr(ATTR_LEN, options.length));
2221
- ln.children.push(elem(qname("a", localName, NS.dml), { attrs }));
2423
+ insertLnChild(ln, elem(qname("a", localName, NS.dml), { attrs }));
2222
2424
  };
2223
2425
  /** Sets `<a:ln cap="…"/>`. Pass `null` to clear the attribute. */
2224
2426
  const setStrokeCap = (spPr, cap) => {
@@ -2235,7 +2437,7 @@ const JOIN_LOCALS = new Set([
2235
2437
  const setStrokeJoin = (spPr, join) => {
2236
2438
  const ln = ensureLn(spPr);
2237
2439
  removeChildrenIn(ln, JOIN_LOCALS);
2238
- if (join !== null) ln.children.push(elem(qname("a", join, NS.dml)));
2440
+ if (join !== null) insertLnChild(ln, elem(qname("a", join, NS.dml)));
2239
2441
  };
2240
2442
  /** Sets `<a:ln cmpd="…"/>`. Pass `null` to clear the attribute. */
2241
2443
  const setStrokeCompound = (spPr, cmpd) => {
@@ -2679,7 +2881,7 @@ const setPosition = (shape, kind, x, y) => {
2679
2881
  off = elem(NAME_OFF$6);
2680
2882
  xfrm.children.unshift(off);
2681
2883
  }
2682
- off.attrs = [attr(ATTR_X$6, String(x)), attr(ATTR_Y$6, String(y))];
2884
+ off.attrs = [attr(ATTR_X$6, String(emuCoordinate(x, "setShapePosition: x"))), attr(ATTR_Y$6, String(emuCoordinate(y, "setShapePosition: y")))];
2683
2885
  };
2684
2886
  /** Sets the shape's `<a:ext>` to `(w, h)` in EMU. */
2685
2887
  const setSize = (shape, kind, w, h) => {
@@ -2691,7 +2893,7 @@ const setSize = (shape, kind, w, h) => {
2691
2893
  if (offIdx >= 0) xfrm.children.splice(offIdx + 1, 0, ext);
2692
2894
  else xfrm.children.push(ext);
2693
2895
  }
2694
- ext.attrs = [attr(ATTR_CX$6, String(w)), attr(ATTR_CY$6, String(h))];
2896
+ ext.attrs = [attr(ATTR_CX$6, String(emuExtent(w, "setShapeSize: w"))), attr(ATTR_CY$6, String(emuExtent(h, "setShapeSize: h")))];
2695
2897
  };
2696
2898
  const ATTR_ROT = qname("", "rot", "");
2697
2899
  const ATTR_FLIP_H$1 = qname("", "flipH", "");
@@ -2738,7 +2940,7 @@ const NAME_TX_BODY$9 = qname("p", "txBody", NS.pml);
2738
2940
  const ATTR_ID$11 = qname("", "id", "");
2739
2941
  const ATTR_NAME$9 = qname("", "name", "");
2740
2942
  const ATTR_TYPE$4 = qname("", "type", "");
2741
- const ATTR_IDX$5 = qname("", "idx", "");
2943
+ const ATTR_IDX$6 = qname("", "idx", "");
2742
2944
  const NV_BY_KIND = {
2743
2945
  shape: NAME_NV_SP_PR$4,
2744
2946
  picture: NAME_NV_PIC_PR$1,
@@ -2776,7 +2978,7 @@ const extractShape = (element, kind) => {
2776
2978
  const ph = firstChildElement(nvPr, NAME_PH$2);
2777
2979
  if (ph !== null) {
2778
2980
  placeholderType = getAttrValue(ph, ATTR_TYPE$4);
2779
- const idxRaw = getAttrValue(ph, ATTR_IDX$5);
2981
+ const idxRaw = getAttrValue(ph, ATTR_IDX$6);
2780
2982
  if (idxRaw !== null) placeholderIdx = Number.parseInt(idxRaw, 10);
2781
2983
  }
2782
2984
  }
@@ -2896,7 +3098,7 @@ const NAME_SP_LOCKS$1 = qname("a", "spLocks", NS.dml);
2896
3098
  const ATTR_ID$10 = qname("", "id", "");
2897
3099
  const ATTR_NAME$7 = qname("", "name", "");
2898
3100
  const ATTR_TYPE$2 = qname("", "type", "");
2899
- const ATTR_IDX$4 = qname("", "idx", "");
3101
+ const ATTR_IDX$5 = qname("", "idx", "");
2900
3102
  const ATTR_NO_GRP$2 = qname("", "noGrp", "");
2901
3103
  /**
2902
3104
  * Builds a `<p:sld>` document containing the canonical slide-root group
@@ -2920,7 +3122,7 @@ const buildSlideFromLayout = (layoutSpTree) => {
2920
3122
  if (ph === null) continue;
2921
3123
  placeholders.push({
2922
3124
  type: getAttrValue(ph, ATTR_TYPE$2),
2923
- idx: getAttrValue(ph, ATTR_IDX$4)
3125
+ idx: getAttrValue(ph, ATTR_IDX$5)
2924
3126
  });
2925
3127
  }
2926
3128
  let nextShapeId = 2;
@@ -2962,7 +3164,7 @@ const buildGrpSpPr = () => elem(NAME_GRP_SP_PR$1);
2962
3164
  const buildPlaceholderStub = (id, phType, phIdx) => {
2963
3165
  const phAttrs = [];
2964
3166
  if (phType !== null) phAttrs.push(attr(ATTR_TYPE$2, phType));
2965
- if (phIdx !== null) phAttrs.push(attr(ATTR_IDX$4, phIdx));
3167
+ if (phIdx !== null) phAttrs.push(attr(ATTR_IDX$5, phIdx));
2966
3168
  const nvPr = elem(NAME_NV_PR$7, { children: [elem(NAME_PH$1, { attrs: phAttrs })] });
2967
3169
  const cNvSpPr = elem(NAME_C_NV_SP_PR$3, { children: [elem(NAME_SP_LOCKS$1, { attrs: [attr(ATTR_NO_GRP$2, "1")] })] });
2968
3170
  const name = inferPlaceholderName(id, phType);
@@ -3047,7 +3249,7 @@ const buildTextBox = (opts) => {
3047
3249
  elem(NAME_NV_PR$6)
3048
3250
  ] });
3049
3251
  const spPr = elem(NAME_SP_PR$4, { children: [
3050
- elem(NAME_A_XFRM$3, { children: [elem(NAME_OFF$5, { attrs: [attr(ATTR_X$5, String(Math.round(opts.x))), attr(ATTR_Y$5, String(Math.round(opts.y)))] }), elem(NAME_EXT$5, { attrs: [attr(ATTR_CX$5, String(Math.round(opts.w))), attr(ATTR_CY$5, String(Math.round(opts.h)))] })] }),
3252
+ elem(NAME_A_XFRM$3, { children: [elem(NAME_OFF$5, { attrs: [attr(ATTR_X$5, String(emuCoordinate(opts.x, "addSlideTextBox: x"))), attr(ATTR_Y$5, String(emuCoordinate(opts.y, "addSlideTextBox: y")))] }), elem(NAME_EXT$5, { attrs: [attr(ATTR_CX$5, String(emuExtent(opts.w, "addSlideTextBox: w"))), attr(ATTR_CY$5, String(emuExtent(opts.h, "addSlideTextBox: h")))] })] }),
3051
3253
  elem(NAME_PRST_GEOM$3, {
3052
3254
  attrs: [attr(ATTR_PRST$3, "rect")],
3053
3255
  children: [elem(NAME_AV_LST$3)]
@@ -3123,7 +3325,7 @@ const buildShape = (opts) => {
3123
3325
  elem(NAME_C_NV_PR$4, { attrs: [attr(ATTR_ID$8, String(opts.id)), attr(ATTR_NAME$5, name)] }),
3124
3326
  elem(NAME_C_NV_SP_PR$1),
3125
3327
  elem(NAME_NV_PR$5)
3126
- ] }), elem(NAME_SP_PR$3, { children: [elem(NAME_A_XFRM$2, { children: [elem(NAME_OFF$4, { attrs: [attr(ATTR_X$4, String(Math.round(opts.x))), attr(ATTR_Y$4, String(Math.round(opts.y)))] }), elem(NAME_EXT$4, { attrs: [attr(ATTR_CX$4, String(Math.round(opts.w))), attr(ATTR_CY$4, String(Math.round(opts.h)))] })] }), elem(NAME_PRST_GEOM$2, {
3328
+ ] }), elem(NAME_SP_PR$3, { children: [elem(NAME_A_XFRM$2, { children: [elem(NAME_OFF$4, { attrs: [attr(ATTR_X$4, String(emuCoordinate(opts.x, "addSlideShape: x"))), attr(ATTR_Y$4, String(emuCoordinate(opts.y, "addSlideShape: y")))] }), elem(NAME_EXT$4, { attrs: [attr(ATTR_CX$4, String(emuExtent(opts.w, "addSlideShape: w"))), attr(ATTR_CY$4, String(emuExtent(opts.h, "addSlideShape: h")))] })] }), elem(NAME_PRST_GEOM$2, {
3127
3329
  attrs: [attr(ATTR_PRST$2, opts.preset)],
3128
3330
  children: [elem(NAME_AV_LST$2)]
3129
3331
  })] })];
@@ -3146,6 +3348,14 @@ const NAME_PRST_GEOM$1 = qname("a", "prstGeom", NS.dml);
3146
3348
  const NAME_AV_LST$1 = qname("a", "avLst", NS.dml);
3147
3349
  const NAME_LN = qname("a", "ln", NS.dml);
3148
3350
  const NAME_SOLID_FILL$3 = qname("a", "solidFill", NS.dml);
3351
+ const NAME_STYLE = qname("p", "style", NS.pml);
3352
+ const NAME_LN_REF = qname("a", "lnRef", NS.dml);
3353
+ const NAME_FILL_REF = qname("a", "fillRef", NS.dml);
3354
+ const NAME_EFFECT_REF = qname("a", "effectRef", NS.dml);
3355
+ const NAME_FONT_REF = qname("a", "fontRef", NS.dml);
3356
+ const NAME_SCHEME_CLR = qname("a", "schemeClr", NS.dml);
3357
+ const ATTR_IDX$4 = qname("", "idx", "");
3358
+ const ATTR_VAL$4 = qname("", "val", "");
3149
3359
  const ATTR_ID$7 = qname("", "id", "");
3150
3360
  const ATTR_NAME$4 = qname("", "name", "");
3151
3361
  const ATTR_X$3 = qname("", "x", "");
@@ -3173,21 +3383,37 @@ const buildConnector = (opts) => {
3173
3383
  const xfrmAttrs = [];
3174
3384
  if (flipH) xfrmAttrs.push(attr(ATTR_FLIP_H, "1"));
3175
3385
  if (flipV) xfrmAttrs.push(attr(ATTR_FLIP_V, "1"));
3176
- const spPrChildren = [elem(NAME_A_XFRM$1, {
3386
+ const xfrm = elem(NAME_A_XFRM$1, {
3177
3387
  attrs: xfrmAttrs,
3178
- children: [elem(NAME_OFF$3, { attrs: [attr(ATTR_X$3, String(Math.round(x))), attr(ATTR_Y$3, String(Math.round(y)))] }), elem(NAME_EXT$3, { attrs: [attr(ATTR_CX$3, String(Math.round(cx))), attr(ATTR_CY$3, String(Math.round(cy)))] })]
3179
- }), elem(NAME_PRST_GEOM$1, {
3388
+ children: [elem(NAME_OFF$3, { attrs: [attr(ATTR_X$3, String(emuCoordinate(x, "addSlideLine: x"))), attr(ATTR_Y$3, String(emuCoordinate(y, "addSlideLine: y")))] }), elem(NAME_EXT$3, { attrs: [attr(ATTR_CX$3, String(emuExtent(cx, "addSlideLine: width"))), attr(ATTR_CY$3, String(emuExtent(cy, "addSlideLine: height")))] })]
3389
+ });
3390
+ const prstGeom = elem(NAME_PRST_GEOM$1, {
3180
3391
  attrs: [attr(ATTR_PRST$1, "line")],
3181
3392
  children: [elem(NAME_AV_LST$1)]
3182
- })];
3183
- if (opts.color !== void 0 || opts.widthEmu !== void 0) {
3393
+ });
3394
+ const hasExplicitLine = opts.color !== void 0 || opts.widthEmu !== void 0;
3395
+ const spPrChildren = [xfrm, prstGeom];
3396
+ if (hasExplicitLine) {
3184
3397
  const ln = elem(NAME_LN, {
3185
- attrs: opts.widthEmu !== void 0 ? [attr(ATTR_W$1, String(Math.round(opts.widthEmu)))] : [],
3398
+ attrs: opts.widthEmu !== void 0 ? [attr(ATTR_W$1, String(lineWidthEmu(opts.widthEmu, "addSlideLine: widthEmu")))] : [],
3186
3399
  children: opts.color !== void 0 ? [elem(NAME_SOLID_FILL$3, { children: [buildColorElement(opts.color)] })] : []
3187
3400
  });
3188
3401
  spPrChildren.push(ln);
3189
3402
  }
3190
- return elem(NAME_CXN_SP, { children: [nvCxnSpPr, elem(NAME_SP_PR$2, { children: spPrChildren })] });
3403
+ const children = [nvCxnSpPr, elem(NAME_SP_PR$2, { children: spPrChildren })];
3404
+ if (!hasExplicitLine) {
3405
+ const styleRef = (name, idx, clr) => elem(name, {
3406
+ attrs: [attr(ATTR_IDX$4, idx)],
3407
+ children: [elem(NAME_SCHEME_CLR, { attrs: [attr(ATTR_VAL$4, clr)] })]
3408
+ });
3409
+ children.push(elem(NAME_STYLE, { children: [
3410
+ styleRef(NAME_LN_REF, "1", "accent1"),
3411
+ styleRef(NAME_FILL_REF, "0", "accent1"),
3412
+ styleRef(NAME_EFFECT_REF, "0", "accent1"),
3413
+ styleRef(NAME_FONT_REF, "minor", "tx1")
3414
+ ] }));
3415
+ }
3416
+ return elem(NAME_CXN_SP, { children });
3191
3417
  };
3192
3418
  //#endregion
3193
3419
  //#region src/internal/presentationml/picture-builder.ts
@@ -3227,7 +3453,7 @@ const buildPicture = (opts) => {
3227
3453
  elem(NAME_NV_PR$3)
3228
3454
  ] }),
3229
3455
  elem(NAME_BLIP_FILL, { children: [elem(NAME_BLIP, { attrs: [attr(ATTR_R_EMBED, opts.rEmbed)] }), elem(NAME_STRETCH, { children: [elem(NAME_FILL_RECT)] })] }),
3230
- elem(NAME_SP_PR$1, { children: [elem(NAME_A_XFRM, { children: [elem(NAME_OFF$2, { attrs: [attr(ATTR_X$2, String(Math.round(opts.x))), attr(ATTR_Y$2, String(Math.round(opts.y)))] }), elem(NAME_EXT$2, { attrs: [attr(ATTR_CX$2, String(Math.round(opts.w))), attr(ATTR_CY$2, String(Math.round(opts.h)))] })] }), elem(NAME_PRST_GEOM, {
3456
+ elem(NAME_SP_PR$1, { children: [elem(NAME_A_XFRM, { children: [elem(NAME_OFF$2, { attrs: [attr(ATTR_X$2, String(emuCoordinate(opts.x, "addSlideImage: x"))), attr(ATTR_Y$2, String(emuCoordinate(opts.y, "addSlideImage: y")))] }), elem(NAME_EXT$2, { attrs: [attr(ATTR_CX$2, String(emuExtent(opts.w, "addSlideImage: w"))), attr(ATTR_CY$2, String(emuExtent(opts.h, "addSlideImage: h")))] })] }), elem(NAME_PRST_GEOM, {
3231
3457
  attrs: [attr(ATTR_PRST, "rect")],
3232
3458
  children: [elem(NAME_AV_LST)]
3233
3459
  })] })
@@ -3286,7 +3512,6 @@ const ATTR_H = qname("", "h", "");
3286
3512
  const ATTR_FIRST_ROW = qname("", "firstRow", "");
3287
3513
  const ATTR_BAND_ROW = qname("", "bandRow", "");
3288
3514
  const ATTR_LANG$1 = qname("", "lang", "");
3289
- const ATTR_XML_SPACE = qname("xml", "space", NS.xml);
3290
3515
  const buildCellRunProps = (textColorHex) => {
3291
3516
  const langAttr = attr(ATTR_LANG$1, "en-US");
3292
3517
  if (textColorHex === void 0) return elem(NAME_RPR$1, { attrs: [langAttr] });
@@ -3296,20 +3521,20 @@ const buildCellRunProps = (textColorHex) => {
3296
3521
  children: [solidFill]
3297
3522
  });
3298
3523
  };
3299
- const buildTextCellBody = (value, textColorHex) => {
3300
- const t = elem(NAME_T$2, {
3301
- attrs: value.length > 0 && (value.startsWith(" ") || value.endsWith(" ") || /[\t\n]/.test(value)) ? [attr(ATTR_XML_SPACE, "preserve")] : [],
3302
- children: value.length > 0 ? [text(value)] : []
3303
- });
3304
- const r = elem(NAME_R$1, { children: [buildCellRunProps(textColorHex), t] });
3305
- const p = elem(NAME_P$1, { children: [elem(NAME_PPR, {
3524
+ const buildCellParagraph = (line, textColorHex) => {
3525
+ const pPr = elem(NAME_PPR, {
3306
3526
  attrs: [attr(ATTR_MAR_L, "0"), attr(ATTR_INDENT, "0")],
3307
3527
  children: [elem(NAME_BU_NONE)]
3308
- }), r] });
3528
+ });
3529
+ const t = elem(NAME_T$2, { children: line.length > 0 ? [text(line)] : [] });
3530
+ return elem(NAME_P$1, { children: [pPr, elem(NAME_R$1, { children: [buildCellRunProps(textColorHex), t] })] });
3531
+ };
3532
+ const buildTextCellBody = (value, textColorHex) => {
3533
+ const paragraphs = (value.length === 0 ? [""] : value.split("\n")).map((line) => buildCellParagraph(line, textColorHex));
3309
3534
  return elem(NAME_TX_BODY$5, { children: [
3310
3535
  elem(NAME_BODY_PR$1),
3311
3536
  elem(NAME_LST_STYLE$1),
3312
- p
3537
+ ...paragraphs
3313
3538
  ] });
3314
3539
  };
3315
3540
  const buildCellProps = () => elem(NAME_TC_PR, { attrs: [
@@ -3324,7 +3549,7 @@ const buildTableCell = (value, textColorHex) => {
3324
3549
  };
3325
3550
  /** @internal — used by row-mutation paths in the public API. */
3326
3551
  const buildTableRow = (cells, h, textColorHex) => elem(NAME_TR, {
3327
- attrs: [attr(ATTR_H, String(Math.round(h)))],
3552
+ attrs: [attr(ATTR_H, String(emuExtent(h, "addSlideTable: row height")))],
3328
3553
  children: cells.map((value) => buildTableCell(value, textColorHex))
3329
3554
  });
3330
3555
  const equalShares = (total, n) => {
@@ -3354,14 +3579,14 @@ const buildTable = (opts) => {
3354
3579
  elem(NAME_C_NV_GRAPHIC_FRAME_PR$1, { children: [elem(NAME_GRAPHIC_FRAME_LOCKS, { attrs: [attr(ATTR_NO_GRP$1, "1")] })] }),
3355
3580
  elem(NAME_NV_PR$2)
3356
3581
  ] });
3357
- const xfrm = elem(NAME_P_XFRM, { children: [elem(NAME_OFF$1, { attrs: [attr(ATTR_X$1, String(Math.round(opts.x))), attr(ATTR_Y$1, String(Math.round(opts.y)))] }), elem(NAME_EXT$1, { attrs: [attr(ATTR_CX$1, String(Math.round(opts.w))), attr(ATTR_CY$1, String(Math.round(opts.h)))] })] });
3358
- const tableStyleId = elem(NAME_TABLE_STYLE_ID, { children: [text(opts.styleId ?? DEFAULT_TABLE_STYLE_ID)] });
3582
+ const xfrm = elem(NAME_P_XFRM, { children: [elem(NAME_OFF$1, { attrs: [attr(ATTR_X$1, String(emuCoordinate(opts.x, "addSlideTable: x"))), attr(ATTR_Y$1, String(emuCoordinate(opts.y, "addSlideTable: y")))] }), elem(NAME_EXT$1, { attrs: [attr(ATTR_CX$1, String(emuExtent(opts.w, "addSlideTable: w"))), attr(ATTR_CY$1, String(emuExtent(opts.h, "addSlideTable: h")))] })] });
3583
+ const tableStyleId = elem(NAME_TABLE_STYLE_ID, { children: [text(opts.styleId === void 0 ? DEFAULT_TABLE_STYLE_ID : normalizeGuid(opts.styleId, "addSlideTable: styleId"))] });
3359
3584
  const tbl = elem(NAME_TBL, { children: [
3360
3585
  elem(NAME_TBL_PR, {
3361
3586
  attrs: [attr(ATTR_FIRST_ROW, opts.firstRow ?? true ? "1" : "0"), attr(ATTR_BAND_ROW, opts.bandRow ?? true ? "1" : "0")],
3362
3587
  children: [tableStyleId]
3363
3588
  }),
3364
- elem(NAME_TBL_GRID, { children: colWidths.map((w) => elem(NAME_GRID_COL, { attrs: [attr(ATTR_W, String(Math.round(w)))] })) }),
3589
+ elem(NAME_TBL_GRID, { children: colWidths.map((w) => elem(NAME_GRID_COL, { attrs: [attr(ATTR_W, String(emuExtent(w, "addSlideTable: column width")))] })) }),
3365
3590
  ...rows.map((row, i) => buildTableRow(row, rowHeights[i] ?? 0, opts.textColorHex))
3366
3591
  ] });
3367
3592
  return elem(NAME_GRAPHIC_FRAME$1, { children: [
@@ -3375,7 +3600,7 @@ const buildTable = (opts) => {
3375
3600
  };
3376
3601
  //#endregion
3377
3602
  //#region src/internal/presentationml/notes-slide-builder.ts
3378
- const NAME_NOTES_SLIDE = qname("p", "notesSlide", NS.pml);
3603
+ const NAME_NOTES_SLIDE = qname("p", "notes", NS.pml);
3379
3604
  const NAME_CSLD$1 = qname("p", "cSld", NS.pml);
3380
3605
  const NAME_SP_TREE$1 = qname("p", "spTree", NS.pml);
3381
3606
  const NAME_NV_GRP_SP_PR = qname("p", "nvGrpSpPr", NS.pml);
@@ -3448,7 +3673,7 @@ const buildNotesBodyPlaceholder = (id, notes) => {
3448
3673
  ] });
3449
3674
  };
3450
3675
  /**
3451
- * Returns a fresh `<p:notesSlide>` document with the given notes text in
3676
+ * Returns a fresh `<p:notes>` document with the given notes text in
3452
3677
  * the body placeholder. Designed for callers that need to create the
3453
3678
  * notesSlide part from scratch (no existing notes file yet for the
3454
3679
  * slide).
@@ -3489,12 +3714,71 @@ const ATTR_ADV_TM = qname("", "advTm", "");
3489
3714
  const ATTR_DIR = qname("", "dir", "");
3490
3715
  const ATTR_ORIENT = qname("", "orient", "");
3491
3716
  const ATTR_THRU_BLK = qname("", "thruBlk", "");
3717
+ const DIR_ORIENT = new Set(["horz", "vert"]);
3718
+ const DIR_SIDE = new Set([
3719
+ "l",
3720
+ "u",
3721
+ "r",
3722
+ "d"
3723
+ ]);
3724
+ const DIR_CORNER = new Set([
3725
+ "lu",
3726
+ "ru",
3727
+ "ld",
3728
+ "rd"
3729
+ ]);
3730
+ const DIR_EIGHT = new Set([...DIR_SIDE, ...DIR_CORNER]);
3731
+ const DIR_IN_OUT = new Set(["in", "out"]);
3732
+ const DIR_DOMAINS = {
3733
+ blinds: DIR_ORIENT,
3734
+ checker: DIR_ORIENT,
3735
+ comb: DIR_ORIENT,
3736
+ randomBar: DIR_ORIENT,
3737
+ push: DIR_SIDE,
3738
+ wipe: DIR_SIDE,
3739
+ cover: DIR_EIGHT,
3740
+ pull: DIR_EIGHT,
3741
+ strips: DIR_CORNER,
3742
+ zoom: DIR_IN_OUT,
3743
+ split: DIR_IN_OUT
3744
+ };
3745
+ const THRU_BLK_EFFECTS = new Set(["fade", "cut"]);
3746
+ const TRANSITION_EFFECTS = [
3747
+ "blinds",
3748
+ "checker",
3749
+ "circle",
3750
+ "dissolve",
3751
+ "comb",
3752
+ "cover",
3753
+ "cut",
3754
+ "diamond",
3755
+ "fade",
3756
+ "newsflash",
3757
+ "plus",
3758
+ "pull",
3759
+ "push",
3760
+ "random",
3761
+ "randomBar",
3762
+ "split",
3763
+ "strips",
3764
+ "wedge",
3765
+ "wheel",
3766
+ "wipe",
3767
+ "zoom"
3768
+ ];
3492
3769
  const buildEffectElement = (opts) => {
3493
- const name = qname("p", opts.effect, NS.pml);
3770
+ if (opts.effect === "none") return null;
3771
+ const name = qname("p", oneOf(opts.effect, TRANSITION_EFFECTS, "setSlideTransition: effect"), NS.pml);
3494
3772
  const attrs = [];
3495
- if (opts.direction !== void 0) attrs.push(attr(ATTR_DIR, opts.direction));
3496
- if (opts.orientation !== void 0) attrs.push(attr(ATTR_ORIENT, opts.orientation));
3497
- if (opts.thruBlack) attrs.push(attr(ATTR_THRU_BLK, "1"));
3773
+ if (opts.direction !== void 0) {
3774
+ const domain = DIR_DOMAINS[opts.effect];
3775
+ if (domain !== void 0) {
3776
+ if (!domain.has(opts.direction)) throw new Error(`setSlideTransition: direction "${opts.direction}" is not valid for effect "${opts.effect}" (allowed: ${[...domain].join(", ")})`);
3777
+ attrs.push(attr(ATTR_DIR, opts.direction));
3778
+ }
3779
+ }
3780
+ if (opts.orientation !== void 0 && opts.effect === "split") attrs.push(attr(ATTR_ORIENT, opts.orientation));
3781
+ if (opts.thruBlack && THRU_BLK_EFFECTS.has(opts.effect)) attrs.push(attr(ATTR_THRU_BLK, "1"));
3498
3782
  return elem(name, { attrs });
3499
3783
  };
3500
3784
  /** Returns a complete `<p:transition>` element. */
@@ -3502,10 +3786,14 @@ const buildTransition = (opts) => {
3502
3786
  const attrs = [];
3503
3787
  if (opts.speed !== void 0) attrs.push(attr(ATTR_SPD, opts.speed));
3504
3788
  if (opts.advanceOnClick === false) attrs.push(attr(ATTR_ADV_CLICK, "0"));
3505
- if (opts.advanceAfterMs !== void 0) attrs.push(attr(ATTR_ADV_TM, String(Math.round(opts.advanceAfterMs))));
3789
+ if (opts.advanceAfterMs !== void 0) {
3790
+ const advTm = unsignedIntMs(opts.advanceAfterMs, "setSlideTransition: advanceAfterMs");
3791
+ attrs.push(attr(ATTR_ADV_TM, String(advTm)));
3792
+ }
3793
+ const effect = buildEffectElement(opts);
3506
3794
  return elem(NAME_TRANSITION, {
3507
3795
  attrs,
3508
- children: [buildEffectElement(opts)]
3796
+ children: effect === null ? [] : [effect]
3509
3797
  });
3510
3798
  };
3511
3799
  //#endregion
@@ -3635,7 +3923,7 @@ const buildOpacityAnim = (spid, durationMs, fadeIn) => {
3635
3923
  */
3636
3924
  const buildSingleEffectTiming = (spid, opts) => {
3637
3925
  const preset = PRESETS[opts.effect];
3638
- const duration = opts.durationMs ?? 500;
3926
+ const duration = opts.durationMs === void 0 ? 500 : unsignedIntMs(opts.durationMs, "setShapeAnimation: durationMs");
3639
3927
  const isFade = opts.effect === "fadeIn" || opts.effect === "fadeOut";
3640
3928
  const isEntrance = preset.presetClass === "entr";
3641
3929
  const effectChildren = [];
@@ -4697,11 +4985,11 @@ const DEFAULT_ACCENT_COLORS = [
4697
4985
  "5B9BD5",
4698
4986
  "70AD47"
4699
4987
  ];
4700
- const seriesSpPr = (color, lineWidthEmu, lineDash) => {
4988
+ const seriesSpPr = (color, lineWidthEmu$1, lineDash) => {
4701
4989
  const lnChildren = [elem(a("solidFill"), { children: [elem(a("srgbClr"), { attrs: [attr(qname("", "val", ""), color)] })] })];
4702
4990
  if (lineDash !== void 0) lnChildren.push(elem(a("prstDash"), { attrs: [attr(qname("", "val", ""), lineDash)] }));
4703
- const ln = lineWidthEmu !== void 0 ? elem(a("ln"), {
4704
- attrs: [attr(qname("", "w", ""), String(lineWidthEmu))],
4991
+ const ln = lineWidthEmu$1 !== void 0 ? elem(a("ln"), {
4992
+ attrs: [attr(qname("", "w", ""), String(lineWidthEmu(lineWidthEmu$1, "chart series: lineWidthEmu")))],
4705
4993
  children: lnChildren
4706
4994
  }) : elem(a("ln"), { children: lnChildren });
4707
4995
  return elem(c("spPr"), { children: [elem(a("solidFill"), { children: [elem(a("srgbClr"), { attrs: [attr(qname("", "val", ""), color)] })] }), ln] });
@@ -4765,17 +5053,18 @@ const seriesElement = (spec, seriesIdx, sheet) => {
4765
5053
  ];
4766
5054
  if (spec.kind === "line" || series.lineWidthEmu !== void 0 || series.lineDash !== void 0) children.push(seriesSpPr(color, series.lineWidthEmu, series.lineDash));
4767
5055
  else children.push(solidFillSpPr(color));
4768
- if (series.invertIfNegative === true) children.push(valNode(c("invertIfNegative"), "1"));
4769
- const mk = markerElement(series.markerSymbol, series.markerSizePt);
4770
- if (mk !== null) children.push(mk);
5056
+ if (series.invertIfNegative === true && (spec.kind === "bar" || spec.kind === "column")) children.push(valNode(c("invertIfNegative"), "1"));
5057
+ if (spec.kind === "line" || spec.kind === "scatter" || spec.kind === "radar") {
5058
+ const mk = markerElement(series.markerSymbol, series.markerSizePt);
5059
+ if (mk !== null) children.push(mk);
5060
+ }
4771
5061
  for (const dPt of dPtElements(series.pointColors, series.pointExplosions)) children.push(dPt);
4772
5062
  const serDLbls = buildDLblsFromLabels(series.dataLabels);
4773
5063
  if (serDLbls !== null) children.push(serDLbls);
4774
- if (series.trendline) children.push(trendlineElement(series.trendline));
5064
+ if (series.trendline && spec.kind !== "pie" && spec.kind !== "doughnut" && spec.kind !== "radar") children.push(trendlineElement(series.trendline));
4775
5065
  children.push(elem(c("cat"), { children: [strRef(catRange, spec.categories)] }));
4776
5066
  children.push(elem(c("val"), { children: [numRef(valRange, paddedValues)] }));
4777
5067
  if (spec.kind === "line") children.push(valNode(c("smooth"), series.smooth === true ? "1" : "0"));
4778
- else if (series.smooth === true) children.push(valNode(c("smooth"), "1"));
4779
5068
  return elem(c("ser"), { children });
4780
5069
  };
4781
5070
  const CAT_AX_ID = 111111111;
@@ -4828,8 +5117,8 @@ const valAxis = (spec) => {
4828
5117
  const scalingChildren = [];
4829
5118
  if (spec.valueAxis?.logBase !== void 0) scalingChildren.push(valNode(c("logBase"), spec.valueAxis.logBase));
4830
5119
  scalingChildren.push(valNode(c("orientation"), spec.valueAxisOrientation ?? "minMax"));
4831
- if (spec.valueAxis?.min !== void 0) scalingChildren.push(valNode(c("min"), spec.valueAxis.min));
4832
5120
  if (spec.valueAxis?.max !== void 0) scalingChildren.push(valNode(c("max"), spec.valueAxis.max));
5121
+ if (spec.valueAxis?.min !== void 0) scalingChildren.push(valNode(c("min"), spec.valueAxis.min));
4833
5122
  const children = [
4834
5123
  valNode(c("axId"), VAL_AX_ID),
4835
5124
  elem(c("scaling"), { children: scalingChildren }),
@@ -4880,9 +5169,9 @@ const buildBarChart = (spec, sheet, direction) => {
4880
5169
  ...ser,
4881
5170
  ...dl ? [dl] : []
4882
5171
  ];
4883
- if (spec.gapWidthPct !== void 0) children.push(valNode(c("gapWidth"), spec.gapWidthPct));
5172
+ if (spec.gapWidthPct !== void 0) children.push(valNode(c("gapWidth"), gapAmountPercent(spec.gapWidthPct, "chart: gapWidthPct")));
4884
5173
  const overlapPct = spec.overlapPct ?? (grouping === "stacked" || grouping === "percentStacked" ? 100 : void 0);
4885
- if (overlapPct !== void 0) children.push(valNode(c("overlap"), overlapPct));
5174
+ if (overlapPct !== void 0) children.push(valNode(c("overlap"), overlapPercent(overlapPct, "chart: overlapPct")));
4886
5175
  children.push(valNode(c("axId"), CAT_AX_ID), valNode(c("axId"), VAL_AX_ID));
4887
5176
  return elem(c(direction === "col" ? "barChart" : "barChart"), { children });
4888
5177
  };
@@ -4909,7 +5198,7 @@ const buildPieChart = (spec, sheet) => {
4909
5198
  ser,
4910
5199
  ...dl ? [dl] : []
4911
5200
  ];
4912
- if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), Math.round(spec.firstSliceAngleDeg)));
5201
+ if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), firstSliceAngle(spec.firstSliceAngleDeg, "chart: firstSliceAngleDeg")));
4913
5202
  return elem(c("pieChart"), { children });
4914
5203
  };
4915
5204
  const buildDoughnutChart = (spec, sheet) => {
@@ -4921,8 +5210,8 @@ const buildDoughnutChart = (spec, sheet) => {
4921
5210
  ser,
4922
5211
  ...dl ? [dl] : []
4923
5212
  ];
4924
- if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), Math.round(spec.firstSliceAngleDeg)));
4925
- children.push(valNode(c("holeSize"), spec.holeSizePct ?? 50));
5213
+ if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), firstSliceAngle(spec.firstSliceAngleDeg, "chart: firstSliceAngleDeg")));
5214
+ children.push(valNode(c("holeSize"), holeSizePercent(spec.holeSizePct ?? 50, "chart: holeSizePct")));
4926
5215
  return elem(c("doughnutChart"), { children });
4927
5216
  };
4928
5217
  const buildAreaChart = (spec, sheet) => {
@@ -7248,7 +7537,7 @@ const buildChartGraphicFrame = (opts) => {
7248
7537
  elem(NAME_C_NV_GRAPHIC_FRAME_PR),
7249
7538
  elem(NAME_NV_PR)
7250
7539
  ] });
7251
- const xfrm = elem(NAME_XFRM, { children: [elem(NAME_OFF, { attrs: [attr(qname("", "x", ""), String(Math.round(opts.x))), attr(qname("", "y", ""), String(Math.round(opts.y)))] }), elem(NAME_EXT, { attrs: [attr(qname("", "cx", ""), String(Math.round(opts.w))), attr(qname("", "cy", ""), String(Math.round(opts.h)))] })] });
7540
+ const xfrm = elem(NAME_XFRM, { children: [elem(NAME_OFF, { attrs: [attr(qname("", "x", ""), String(emuCoordinate(opts.x, "addSlideChart: x"))), attr(qname("", "y", ""), String(emuCoordinate(opts.y, "addSlideChart: y")))] }), elem(NAME_EXT, { attrs: [attr(qname("", "cx", ""), String(emuExtent(opts.w, "addSlideChart: w"))), attr(qname("", "cy", ""), String(emuExtent(opts.h, "addSlideChart: h")))] })] });
7252
7541
  const chartRef = elem(NAME_C_CHART, {
7253
7542
  prefixDecls: new Map([["c", NS.chart], ["r", NS.officeDocRels]]),
7254
7543
  attrs: [attr(qname("r", "id", NS.officeDocRels), opts.rEmbed)]
@@ -7545,7 +7834,7 @@ const findChartsWithTrendlines = (slide) => {
7545
7834
  */
7546
7835
  const findChartsWithDataLabels = (slide) => {
7547
7836
  const out = [];
7548
- const hasLabel = (dl) => dl !== void 0 && (dl.showValue || dl.showCategory || dl.showSeriesName || dl.showPercent);
7837
+ const hasLabel = (dl) => dl !== void 0 && Boolean(dl.showValue || dl.showCategory || dl.showSeriesName || dl.showPercent);
7549
7838
  for (const chart of getSlideCharts(slide)) {
7550
7839
  if (chart.spec === null) continue;
7551
7840
  if (hasLabel(chart.spec.dataLabels)) {
@@ -8695,7 +8984,10 @@ const setTableStyleId = (table, styleId) => {
8695
8984
  if (!tbl) throw new Error("setTableStyleId: shape is not a table graphic frame");
8696
8985
  const tblPr = ensureTblPr(tbl);
8697
8986
  tblPr.children = tblPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "tableStyleId"));
8698
- if (styleId !== null) tblPr.children.push(elem(qname("a", "tableStyleId", NS.dml), { children: [text(styleId)] }));
8987
+ if (styleId !== null) {
8988
+ const guid = normalizeGuid(styleId, "setTableStyleId: styleId");
8989
+ tblPr.children.push(elem(qname("a", "tableStyleId", NS.dml), { children: [text(guid)] }));
8990
+ }
8699
8991
  commitSlideData(table[SHAPE_SLIDE]);
8700
8992
  refreshSlideData(table[SHAPE_SLIDE]);
8701
8993
  };
@@ -8858,7 +9150,7 @@ const setTableColumnWidth = (table, col, width) => {
8858
9150
  const target = cols[col];
8859
9151
  if (!target) throw new RangeError(`table column ${col} out of range (have ${cols.length})`);
8860
9152
  target.attrs = target.attrs.filter((a) => !(a.name.namespaceURI === "" && a.name.localName === "w"));
8861
- target.attrs.push(attr(ATTR_W_TBL, String(Math.round(width))));
9153
+ target.attrs.push(attr(ATTR_W_TBL, String(emuExtent(width, "setTableColumnWidth: width"))));
8862
9154
  commitSlideData(table[SHAPE_SLIDE]);
8863
9155
  refreshSlideData(table[SHAPE_SLIDE]);
8864
9156
  };
@@ -8872,7 +9164,7 @@ const setTableRowHeight = (table, row, height) => {
8872
9164
  const target = rows[row];
8873
9165
  if (!target) throw new RangeError(`table row ${row} out of range (have ${rows.length})`);
8874
9166
  target.attrs = target.attrs.filter((a) => !(a.name.namespaceURI === "" && a.name.localName === "h"));
8875
- target.attrs.push(attr(ATTR_H_TBL, String(Math.round(height))));
9167
+ target.attrs.push(attr(ATTR_H_TBL, String(emuExtent(height, "setTableRowHeight: height"))));
8876
9168
  commitSlideData(table[SHAPE_SLIDE]);
8877
9169
  refreshSlideData(table[SHAPE_SLIDE]);
8878
9170
  };
@@ -9071,18 +9363,39 @@ const BORDER_SIDE_LOCALS = {
9071
9363
  tlToBr: "lnTlToBr",
9072
9364
  blToTr: "lnBlToTr"
9073
9365
  };
9366
+ const TCPR_CHILD_RANK = {
9367
+ lnL: 0,
9368
+ lnR: 1,
9369
+ lnT: 2,
9370
+ lnB: 3,
9371
+ lnTlToBr: 4,
9372
+ lnBlToTr: 5,
9373
+ cell3D: 6,
9374
+ noFill: 7,
9375
+ solidFill: 7,
9376
+ gradFill: 7,
9377
+ blipFill: 7,
9378
+ pattFill: 7,
9379
+ grpFill: 7,
9380
+ headers: 8,
9381
+ extLst: 9
9382
+ };
9383
+ const tcPrChildRank = (el) => el.name.namespaceURI === NS.dml ? TCPR_CHILD_RANK[el.name.localName] ?? 99 : 99;
9074
9384
  const writeBorderLn = (tcPr, local, border) => {
9075
9385
  tcPr.children = tcPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === local));
9076
9386
  if (border === null) return;
9077
9387
  const lnAttrs = [];
9078
- if (border.widthEmu !== null && border.widthEmu !== void 0) lnAttrs.push(attr(qname("", "w", ""), String(Math.round(border.widthEmu))));
9388
+ if (border.widthEmu !== null && border.widthEmu !== void 0) {
9389
+ const w = lineWidthEmu(border.widthEmu, "setTableCellBorders: widthEmu");
9390
+ lnAttrs.push(attr(qname("", "w", ""), String(w)));
9391
+ }
9079
9392
  const children = [];
9080
9393
  if (border.color !== null && border.color !== void 0) children.push(elem(qname("a", "solidFill", NS.dml), { children: [buildColorElement(border.color)] }));
9081
9394
  if (border.dash !== null && border.dash !== void 0) children.push(elem(qname("a", "prstDash", NS.dml), { attrs: [attr(qname("", "val", ""), border.dash)] }));
9082
- tcPr.children.push(elem(qname("a", local, NS.dml), {
9395
+ insertChildByRank(tcPr, elem(qname("a", local, NS.dml), {
9083
9396
  attrs: lnAttrs,
9084
9397
  children
9085
- }));
9398
+ }), tcPrChildRank);
9086
9399
  };
9087
9400
  /**
9088
9401
  * Sets one or more side borders on a cell. Sides listed with `null` are
@@ -9211,7 +9524,10 @@ const setTableCellMargins = (cell, margins) => {
9211
9524
  ["marT", margins.top],
9212
9525
  ["marB", margins.bottom]
9213
9526
  ];
9214
- for (const [name, val] of pairs) if (val !== null && val !== void 0) tcPr.attrs.push(attr(qname("", name, ""), String(Math.round(val))));
9527
+ for (const [name, val] of pairs) if (val !== null && val !== void 0) {
9528
+ const emu = emuCoordinate32(val, `setTableCellMargins: ${name}`);
9529
+ tcPr.attrs.push(attr(qname("", name, ""), String(emu)));
9530
+ }
9215
9531
  }
9216
9532
  commitTableCell(cell);
9217
9533
  };
@@ -9724,7 +10040,8 @@ const listPackageParts = (pres) => pres[INTERNAL_PACKAGE].parts.map((p) => ({
9724
10040
  * (e.g. parsing custom extension parts).
9725
10041
  */
9726
10042
  const readPackagePart = (pres, name) => {
9727
- return pres[INTERNAL_PACKAGE].parts.find((p) => p.name === name)?.data ?? null;
10043
+ const target = name.toLowerCase();
10044
+ return pres[INTERNAL_PACKAGE].parts.find((p) => p.name.toLowerCase() === target)?.data ?? null;
9728
10045
  };
9729
10046
  /**
9730
10047
  * Returns the total size of the package's parts in bytes
@@ -9781,13 +10098,13 @@ const getOrphanMediaPartNames = (pres) => {
9781
10098
  if (!sourceRels) continue;
9782
10099
  for (const rel of sourceRels.items) {
9783
10100
  if (rel.targetMode === "External") continue;
9784
- referenced.add(resolve(sourceName, rel.target));
10101
+ referenced.add(resolve(sourceName, rel.target).toLowerCase());
9785
10102
  }
9786
10103
  }
9787
10104
  const out = [];
9788
10105
  for (const part of pkg.parts) {
9789
10106
  if (!part.name.startsWith("/ppt/media/")) continue;
9790
- if (!referenced.has(part.name)) out.push(part.name);
10107
+ if (!referenced.has(part.name.toLowerCase())) out.push(part.name);
9791
10108
  }
9792
10109
  return out;
9793
10110
  };
@@ -9874,14 +10191,14 @@ const compactPackage = (pres) => {
9874
10191
  if (!rels) continue;
9875
10192
  for (const rel of rels.items) {
9876
10193
  if (rel.targetMode === "External") continue;
9877
- referenced.add(resolve(sourceName, rel.target));
10194
+ referenced.add(resolve(sourceName, rel.target).toLowerCase());
9878
10195
  }
9879
10196
  }
9880
10197
  const removed = [];
9881
10198
  const orphans = [];
9882
10199
  for (const part of pkg.parts) {
9883
10200
  if (!part.name.startsWith("/ppt/media/")) continue;
9884
- if (!referenced.has(part.name)) orphans.push(part.name);
10201
+ if (!referenced.has(part.name.toLowerCase())) orphans.push(part.name);
9885
10202
  }
9886
10203
  for (const name of orphans) {
9887
10204
  pkg.removePart(partName(name));
@@ -9900,7 +10217,8 @@ const compactPackage = (pres) => {
9900
10217
  * already point at this part name.
9901
10218
  */
9902
10219
  const setMediaPartBytes = (pres, partName, bytes) => {
9903
- const part = pres[INTERNAL_PACKAGE].parts.find((p) => p.name === partName);
10220
+ const target = partName.toLowerCase();
10221
+ const part = pres[INTERNAL_PACKAGE].parts.find((p) => p.name.toLowerCase() === target);
9904
10222
  if (!part) return false;
9905
10223
  part.data = bytes;
9906
10224
  return true;
@@ -10987,93 +11305,84 @@ const getShapeImageCrop = (shape) => {
10987
11305
  bottom: parseSide("b")
10988
11306
  };
10989
11307
  };
11308
+ const NAME_LUM = qname("a", "lum", NS.dml);
11309
+ const requirePictureBlip = (shape, fnName) => {
11310
+ if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`${fnName} only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11311
+ const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11312
+ if (!blipFill) throw new Error("picture has no <p:blipFill>");
11313
+ const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11314
+ if (!blip) throw new Error("picture <p:blipFill> has no <a:blip>");
11315
+ return blip;
11316
+ };
11317
+ const setLumAttr = (blip, local, value) => {
11318
+ let lum = firstChildElement(blip, NAME_LUM);
11319
+ if (lum) lum.attrs = lum.attrs.filter((a) => !(a.name.namespaceURI === "" && a.name.localName === local));
11320
+ if (value !== null && value !== 0) {
11321
+ if (!lum) {
11322
+ lum = elem(NAME_LUM);
11323
+ blip.children.push(lum);
11324
+ }
11325
+ lum.attrs.push(attr(qname("", local, ""), String(Math.round(value * 1e5))));
11326
+ }
11327
+ if (lum && lum.attrs.length === 0) blip.children = blip.children.filter((c) => c !== lum);
11328
+ };
11329
+ const getLumAttr = (shape, local) => {
11330
+ if (shape[SHAPE_SNAPSHOT].kind !== "picture") return null;
11331
+ const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11332
+ if (!blipFill) return null;
11333
+ const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11334
+ if (!blip) return null;
11335
+ const lum = firstChildElement(blip, NAME_LUM);
11336
+ if (!lum) return null;
11337
+ const v = getAttrValue(lum, qname("", local, ""));
11338
+ if (v === null) return null;
11339
+ const n = Number.parseInt(v, 10);
11340
+ return Number.isFinite(n) ? n / 1e5 : null;
11341
+ };
10990
11342
  /**
10991
- * Adjusts the picture's brightness by writing `<a:lumOff val="…"/>`
10992
- * inside `<a:blip>`. The value is a -1..1 fraction:
11343
+ * Adjusts the picture's brightness via `<a:blip><a:lum bright="…"/>`. The value
11344
+ * is a -1..1 fraction:
10993
11345
  *
10994
11346
  * - `1` → +100% brightness
10995
- * - `0` or `null` → no offset (any prior `<a:lumOff>` is removed)
11347
+ * - `0` or `null` → no brightness change (the `bright` attribute is removed)
10996
11348
  * - `-1` → -100% brightness
10997
11349
  *
10998
- * Throws for non-picture shapes and on values outside [-1, 1].
10999
- *
11000
- * Note: PowerPoint's "Picture Format › Corrections" UI couples this
11001
- * with `<a:lumMod>` for some presets; this primitive sets only
11002
- * `lumOff` to keep the surface honest. Read it back via
11003
- * `getShapeImageBrightness`.
11350
+ * Brightness and contrast share the one `<a:lum>` element, so setting one keeps
11351
+ * the other. Throws for non-picture shapes and on values outside [-1, 1].
11004
11352
  */
11005
11353
  const setShapeImageBrightness = (shape, value) => {
11006
- if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`setShapeImageBrightness only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11007
- const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11008
- if (!blipFill) throw new Error("picture has no <p:blipFill>");
11009
- const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11010
- if (!blip) throw new Error("picture <p:blipFill> has no <a:blip>");
11011
- blip.children = blip.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "lumOff"));
11012
- if (value !== null && value !== 0) {
11013
- if (!Number.isFinite(value) || value < -1 || value > 1) throw new RangeError(`brightness must be in [-1, 1], got ${value}`);
11014
- blip.children.push(elem(qname("a", "lumOff", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(value * 1e5)))] }));
11015
- }
11354
+ const blip = requirePictureBlip(shape, "setShapeImageBrightness");
11355
+ if (value !== null && value !== 0 && (!Number.isFinite(value) || value < -1 || value > 1)) throw new RangeError(`brightness must be in [-1, 1], got ${value}`);
11356
+ setLumAttr(blip, "bright", value);
11016
11357
  commitAndRefresh(shape);
11017
11358
  };
11018
11359
  /**
11019
- * Adjusts the picture's contrast by writing `<a:lumMod val="…"/>` on
11020
- * `<a:blip>`. The value is a 0..2 fraction:
11360
+ * Adjusts the picture's contrast via `<a:blip><a:lum contrast="…"/>`. The value
11361
+ * is a -1..1 fraction (ECMA-376 `ST_FixedPercentage`):
11021
11362
  *
11022
- * - `1` or `null` → no modulation (any prior `<a:lumMod>` is removed)
11023
- * - `0.5` → 50% of original luminance variance (washed out)
11024
- * - `1.5` 150% (boosted contrast; PowerPoint clamps to
11025
- * what the renderer supports)
11363
+ * - `0` or `null` → no contrast change (the `contrast` attribute is removed)
11364
+ * - `0.5` → +50% contrast (boosted)
11365
+ * - `-0.5` -50% contrast (washed out)
11026
11366
  *
11027
- * Throws on non-picture shapes and on values outside `[0, 2]`. The
11028
- * primitive maps directly to `ST_PositiveFixedPercentage` × 100000.
11367
+ * Brightness and contrast share the one `<a:lum>` element, so setting one keeps
11368
+ * the other. Throws on non-picture shapes and on values outside [-1, 1].
11029
11369
  */
11030
11370
  const setShapeImageContrast = (shape, value) => {
11031
- if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`setShapeImageContrast only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11032
- const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11033
- if (!blipFill) throw new Error("picture has no <p:blipFill>");
11034
- const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11035
- if (!blip) throw new Error("picture <p:blipFill> has no <a:blip>");
11036
- blip.children = blip.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "lumMod"));
11037
- if (value !== null && value !== 1) {
11038
- if (!Number.isFinite(value) || value < 0 || value > 2) throw new RangeError(`contrast must be in [0, 2], got ${value}`);
11039
- blip.children.push(elem(qname("a", "lumMod", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(value * 1e5)))] }));
11040
- }
11371
+ const blip = requirePictureBlip(shape, "setShapeImageContrast");
11372
+ if (value !== null && value !== 0 && (!Number.isFinite(value) || value < -1 || value > 1)) throw new RangeError(`contrast must be in [-1, 1], got ${value}`);
11373
+ setLumAttr(blip, "contrast", value);
11041
11374
  commitAndRefresh(shape);
11042
11375
  };
11043
11376
  /**
11044
- * Reads the picture's contrast modulation (the `<a:lumMod>` fraction
11045
- * in [0, 2]). Returns `null` when no `<a:lumMod>` is present.
11377
+ * Reads the picture's contrast (the `<a:lum contrast>` fraction in [-1, 1]).
11378
+ * Returns `null` when no contrast adjustment is present.
11046
11379
  */
11047
- const getShapeImageContrast = (shape) => {
11048
- if (shape[SHAPE_SNAPSHOT].kind !== "picture") return null;
11049
- const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11050
- if (!blipFill) return null;
11051
- const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11052
- if (!blip) return null;
11053
- const lumMod = firstChildElement(blip, qname("a", "lumMod", NS.dml));
11054
- if (!lumMod) return null;
11055
- const v = getAttrValue(lumMod, qname("", "val", ""));
11056
- if (v === null) return null;
11057
- const n = Number.parseInt(v, 10);
11058
- return Number.isFinite(n) ? n / 1e5 : null;
11059
- };
11380
+ const getShapeImageContrast = (shape) => getLumAttr(shape, "contrast");
11060
11381
  /**
11061
- * Reads the picture's brightness offset (the `<a:lumOff>` fraction
11062
- * in [-1, 1]). Returns `null` when no `<a:lumOff>` is present.
11382
+ * Reads the picture's brightness (the `<a:lum bright>` fraction in [-1, 1]).
11383
+ * Returns `null` when no brightness adjustment is present.
11063
11384
  */
11064
- const getShapeImageBrightness = (shape) => {
11065
- if (shape[SHAPE_SNAPSHOT].kind !== "picture") return null;
11066
- const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11067
- if (!blipFill) return null;
11068
- const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11069
- if (!blip) return null;
11070
- const lumOff = firstChildElement(blip, qname("a", "lumOff", NS.dml));
11071
- if (!lumOff) return null;
11072
- const v = getAttrValue(lumOff, qname("", "val", ""));
11073
- if (v === null) return null;
11074
- const n = Number.parseInt(v, 10);
11075
- return Number.isFinite(n) ? n / 1e5 : null;
11076
- };
11385
+ const getShapeImageBrightness = (shape) => getLumAttr(shape, "bright");
11077
11386
  const setShapeImageOpacity = (shape, opacity) => {
11078
11387
  if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`setShapeImageOpacity only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11079
11388
  const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
@@ -11136,17 +11445,99 @@ const setShapeImageCrop = (shape, crop) => {
11136
11445
  //#endregion
11137
11446
  //#region src/api/fn/shape-animation.ts
11138
11447
  NS.pml;
11448
+ const ATTR_ID_FN = qname("", "id", "");
11139
11449
  const removeExistingTiming = (slide) => {
11140
11450
  slide[SLIDE_DOCUMENT].root.children = slide[SLIDE_DOCUMENT].root.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.pml && c.name.localName === "timing"));
11141
11451
  };
11452
+ const findTiming = (slide) => slide[SLIDE_DOCUMENT].root.children.find((c) => c.kind === "element" && c.name.namespaceURI === NS.pml && c.name.localName === "timing") ?? null;
11142
11453
  const insertTimingAtEnd = (slide, timing) => {
11143
11454
  slide[SLIDE_DOCUMENT].root.children.push(timing);
11144
11455
  };
11456
+ const findDescendant = (el, pred) => {
11457
+ if (pred(el)) return el;
11458
+ for (const c of el.children) if (c.kind === "element") {
11459
+ const found = findDescendant(c, pred);
11460
+ if (found) return found;
11461
+ }
11462
+ return null;
11463
+ };
11464
+ const isPml = (el, local) => el.name.namespaceURI === NS.pml && el.name.localName === local;
11465
+ const maxCTnId = (el) => {
11466
+ let max = 0;
11467
+ const walk = (e) => {
11468
+ if (isPml(e, "cTn")) {
11469
+ const n = Number.parseInt(getAttrValue(e, ATTR_ID_FN) ?? "", 10);
11470
+ if (Number.isFinite(n) && n > max) max = n;
11471
+ }
11472
+ for (const c of e.children) if (c.kind === "element") walk(c);
11473
+ };
11474
+ walk(el);
11475
+ return max;
11476
+ };
11477
+ const shiftCTnIds = (el, offset) => {
11478
+ const walk = (e) => {
11479
+ if (isPml(e, "cTn")) {
11480
+ const raw = getAttrValue(e, ATTR_ID_FN);
11481
+ const n = raw === null ? NaN : Number.parseInt(raw, 10);
11482
+ if (Number.isFinite(n)) e.attrs = e.attrs.map((a) => a.name.namespaceURI === "" && a.name.localName === "id" ? {
11483
+ ...a,
11484
+ value: String(n + offset)
11485
+ } : a);
11486
+ }
11487
+ for (const c of e.children) if (c.kind === "element") walk(c);
11488
+ };
11489
+ walk(el);
11490
+ };
11491
+ const maxGrpId = (el) => {
11492
+ let max = -1;
11493
+ const walk = (e) => {
11494
+ const raw = getAttrValue(e, qname("", "grpId", ""));
11495
+ if (raw !== null) {
11496
+ const n = Number.parseInt(raw, 10);
11497
+ if (Number.isFinite(n) && n > max) max = n;
11498
+ }
11499
+ for (const c of e.children) if (c.kind === "element") walk(c);
11500
+ };
11501
+ walk(el);
11502
+ return max;
11503
+ };
11504
+ const setGrpId = (el, grpId) => {
11505
+ el.attrs = el.attrs.map((a) => a.name.namespaceURI === "" && a.name.localName === "grpId" ? {
11506
+ ...a,
11507
+ value: grpId
11508
+ } : a);
11509
+ };
11510
+ const mergeEffectInto = (existing, fresh) => {
11511
+ const existingMainSeqChildTnLst = (() => {
11512
+ const mainSeq = findDescendant(existing, (e) => isPml(e, "cTn") && getAttrValue(e, qname("", "nodeType", "")) === "mainSeq");
11513
+ return mainSeq ? firstChildElement(mainSeq, qname("p", "childTnLst", NS.pml)) : null;
11514
+ })();
11515
+ if (!existingMainSeqChildTnLst) return false;
11516
+ const freshMainSeq = findDescendant(fresh, (e) => isPml(e, "cTn") && getAttrValue(e, qname("", "nodeType", "")) === "mainSeq");
11517
+ const freshChildTnLst = freshMainSeq ? firstChildElement(freshMainSeq, qname("p", "childTnLst", NS.pml)) : null;
11518
+ const newPar = freshChildTnLst ? freshChildTnLst.children.find((c) => c.kind === "element" && isPml(c, "par")) : null;
11519
+ const freshBldP = findDescendant(fresh, (e) => isPml(e, "bldP"));
11520
+ if (!newPar || !freshBldP) return false;
11521
+ const offset = maxCTnId(existing) - 2;
11522
+ if (offset > 0) shiftCTnIds(newPar, offset);
11523
+ const newGrpId = String(maxGrpId(existing) + 1);
11524
+ const effectCTn = findDescendant(newPar, (e) => getAttrValue(e, qname("", "presetID", "")) !== null);
11525
+ if (effectCTn) setGrpId(effectCTn, newGrpId);
11526
+ setGrpId(freshBldP, newGrpId);
11527
+ existingMainSeqChildTnLst.children.push(newPar);
11528
+ const existingBldLst = findDescendant(existing, (e) => isPml(e, "bldLst"));
11529
+ if (existingBldLst) existingBldLst.children.push(freshBldP);
11530
+ else existing.children.push(elem(qname("p", "bldLst", NS.pml), { children: [freshBldP] }));
11531
+ return true;
11532
+ };
11145
11533
  /**
11146
11534
  * Sets a single click-triggered animation effect on the given shape.
11147
- * Replaces any existing `<p:timing>` block on the slide — v1 supports
11148
- * exactly one effect per slide. Calling this on a second shape replaces
11149
- * the first.
11535
+ *
11536
+ * The effect is *merged* into any existing `<p:timing>` on the slide rather
11537
+ * than replacing it: animating a second shape (or re-running on a template that
11538
+ * already has authored animations) preserves the existing effects and appends
11539
+ * this one as the next click stop, with cTn ids renumbered to stay unique. To
11540
+ * clear every animation first, call `clearSlideAnimations`.
11150
11541
  *
11151
11542
  * Supported `effect` tokens:
11152
11543
  *
@@ -11160,9 +11551,11 @@ const insertTimingAtEnd = (slide, timing) => {
11160
11551
  */
11161
11552
  const setShapeAnimation = (shape, opts) => {
11162
11553
  const slide = shape[SHAPE_SLIDE];
11163
- removeExistingTiming(slide);
11164
11554
  const spid = shape[SHAPE_SNAPSHOT].id;
11165
- insertTimingAtEnd(slide, buildSingleEffectTiming(spid, opts));
11555
+ const fresh = buildSingleEffectTiming(spid, opts);
11556
+ const existing = findTiming(slide);
11557
+ if (existing === null) insertTimingAtEnd(slide, fresh);
11558
+ else if (!mergeEffectInto(existing, fresh)) throw new Error("setShapeAnimation: the slide already has an animation timing tree this single-effect API cannot safely extend. Call clearSlideAnimations(slide) first to reset it.");
11166
11559
  commitSlideData(slide);
11167
11560
  refreshSlideData(slide);
11168
11561
  };
@@ -11618,6 +12011,25 @@ const getParagraphLevel = (shape, paragraphIndex) => {
11618
12011
  const n = Number.parseInt(v, 10);
11619
12012
  return Number.isFinite(n) ? n : 0;
11620
12013
  };
12014
+ const PPR_CHILD_RANK = {
12015
+ lnSpc: 0,
12016
+ spcBef: 1,
12017
+ spcAft: 2,
12018
+ buClrTx: 3,
12019
+ buClr: 3,
12020
+ buSzTx: 4,
12021
+ buSzPct: 4,
12022
+ buSzPts: 4,
12023
+ buFontTx: 5,
12024
+ buFont: 5,
12025
+ buNone: 6,
12026
+ buAutoNum: 6,
12027
+ buChar: 6,
12028
+ tabLst: 7,
12029
+ defRPr: 8,
12030
+ extLst: 9
12031
+ };
12032
+ const pPrChildRank = (el) => el.name.namespaceURI === NS.dml ? PPR_CHILD_RANK[el.name.localName] ?? 99 : 99;
11621
12033
  /**
11622
12034
  * Sets the spacing before and/or after a paragraph, in points (where
11623
12035
  * a "point" is 1/72 inch). PowerPoint stores these as hundredths of a
@@ -11636,8 +12048,7 @@ const setParagraphSpacing = (shape, paragraphIndex, opts) => {
11636
12048
  pPr.children = pPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === localName));
11637
12049
  if (value === null) return;
11638
12050
  if (!Number.isFinite(value) || value < 0) throw new RangeError(`paragraph ${localName} must be a non-negative number, got ${value}`);
11639
- const spcEl = elem(qname("a", localName, NS.dml), { children: [elem(qname("a", "spcPts", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(value * 100)))] })] });
11640
- pPr.children.push(spcEl);
12051
+ insertChildByRank(pPr, elem(qname("a", localName, NS.dml), { children: [elem(qname("a", "spcPts", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(value * 100)))] })] }), pPrChildRank);
11641
12052
  };
11642
12053
  writeSide("spcBef", opts.beforePts);
11643
12054
  writeSide("spcAft", opts.afterPts);
@@ -11744,6 +12155,27 @@ const getParagraphLineSpacing = (shape, paragraphIndex) => {
11744
12155
  return null;
11745
12156
  };
11746
12157
  /**
12158
+ * Sets a paragraph's line spacing — the writer counterpart to
12159
+ * `getParagraphLineSpacing`. Two modes (mirroring `<a:lnSpc>`):
12160
+ *
12161
+ * - `{ kind: 'pct', value }` — a multiple of single spacing
12162
+ * (`1` = single, `1.5` = 150%, `2` = double) → `<a:spcPct>`.
12163
+ * - `{ kind: 'pts', value }` — a fixed leading in points → `<a:spcPts>`.
12164
+ *
12165
+ * Pass `null` to clear the override (the paragraph then inherits line
12166
+ * spacing from the layout / master).
12167
+ */
12168
+ const setParagraphLineSpacing = (shape, paragraphIndex, spacing) => {
12169
+ const pPr = ensurePPr(requireParagraph(shape, paragraphIndex));
12170
+ pPr.children = pPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "lnSpc"));
12171
+ if (spacing !== null) {
12172
+ if (!Number.isFinite(spacing.value) || spacing.value < 0) throw new RangeError(`line spacing value must be a non-negative number, got ${spacing.value}`);
12173
+ const inner = spacing.kind === "pct" ? elem(qname("a", "spcPct", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(spacing.value * 1e5)))] }) : elem(qname("a", "spcPts", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(spacing.value * 100)))] });
12174
+ insertChildByRank(pPr, elem(qname("a", "lnSpc", NS.dml), { children: [inner] }), pPrChildRank);
12175
+ }
12176
+ commitAndRefresh(shape);
12177
+ };
12178
+ /**
11747
12179
  * Reads back the bullet style on a single paragraph, or `null` when
11748
12180
  * no `<a:buChar>` / `<a:buAutoNum>` / `<a:buNone>` is present (the
11749
12181
  * paragraph inherits its bullet from the layout / master).
@@ -11983,6 +12415,8 @@ const hslToRgb = (h, s, l) => {
11983
12415
  hueToRgb(p, q, h - 1 / 3)
11984
12416
  ];
11985
12417
  };
12418
+ const srgbToLinear = (c) => c <= .04045 ? c / 12.92 : ((c + .055) / 1.055) ** 2.4;
12419
+ const linearToSrgb = (c) => c <= .0031308 ? c * 12.92 : 1.055 * c ** (1 / 2.4) - .055;
11986
12420
  const applyColorTransforms = (hex, transforms) => {
11987
12421
  if (transforms.length === 0) return hex;
11988
12422
  let [r, g, b] = hexToRgb01(hex);
@@ -12001,14 +12435,14 @@ const applyColorTransforms = (hex, transforms) => {
12001
12435
  break;
12002
12436
  }
12003
12437
  case "shade":
12004
- r *= t.val;
12005
- g *= t.val;
12006
- b *= t.val;
12438
+ r = linearToSrgb(srgbToLinear(r) * t.val);
12439
+ g = linearToSrgb(srgbToLinear(g) * t.val);
12440
+ b = linearToSrgb(srgbToLinear(b) * t.val);
12007
12441
  break;
12008
12442
  case "tint":
12009
- r = r * t.val + (1 - t.val);
12010
- g = g * t.val + (1 - t.val);
12011
- b = b * t.val + (1 - t.val);
12443
+ r = linearToSrgb(srgbToLinear(r) * t.val + (1 - t.val));
12444
+ g = linearToSrgb(srgbToLinear(g) * t.val + (1 - t.val));
12445
+ b = linearToSrgb(srgbToLinear(b) * t.val + (1 - t.val));
12012
12446
  break;
12013
12447
  case "lumMod":
12014
12448
  case "lumOff": {
@@ -14337,8 +14771,8 @@ const getShapeTextColumns = (shape) => {
14337
14771
  * Sets the multi-column layout on the shape's text body — writes
14338
14772
  * `<a:bodyPr numCol="N" [spcCol="EMU"]/>`. Pass `null` to clear both
14339
14773
  * attributes so the text body falls back to PowerPoint's default
14340
- * single column. `count` must be `>= 2` (PowerPoint clamps higher
14341
- * values silently; OOXML allows up to 16). `gapEmu`, when omitted,
14774
+ * single column. `count` must be in `2..16` (ST_TextColumnCount caps at
14775
+ * 16, and single column is the `null` default). `gapEmu`, when omitted,
14342
14776
  * removes any prior `spcCol`. Throws for non-text-bearing shape kinds.
14343
14777
  */
14344
14778
  const setShapeTextColumns = (shape, columns) => {
@@ -14346,8 +14780,12 @@ const setShapeTextColumns = (shape, columns) => {
14346
14780
  bodyPr.attrs = bodyPr.attrs.filter((a) => !(a.name.namespaceURI === "" && (a.name.localName === "numCol" || a.name.localName === "spcCol")));
14347
14781
  if (columns !== null) {
14348
14782
  if (columns.count < 2) throw new Error(`setShapeTextColumns: count must be >= 2 (single column is the default — pass null instead). Got ${columns.count}.`);
14349
- bodyPr.attrs.push(attr(qname("", "numCol", ""), String(columns.count)));
14350
- if (columns.gapEmu !== void 0) bodyPr.attrs.push(attr(qname("", "spcCol", ""), String(Math.round(columns.gapEmu))));
14783
+ const numCol = textColumnCount(columns.count, "setShapeTextColumns: count");
14784
+ bodyPr.attrs.push(attr(qname("", "numCol", ""), String(numCol)));
14785
+ if (columns.gapEmu !== void 0) {
14786
+ const spcCol = emuPositiveCoordinate32(columns.gapEmu, "setShapeTextColumns: gapEmu");
14787
+ bodyPr.attrs.push(attr(qname("", "spcCol", ""), String(spcCol)));
14788
+ }
14351
14789
  }
14352
14790
  commitAndRefresh(shape);
14353
14791
  };
@@ -14384,7 +14822,10 @@ const getShapeTextBodyRotationDeg = (shape) => {
14384
14822
  const setShapeTextBodyRotationDeg = (shape, rotationDeg) => {
14385
14823
  const bodyPr = requireBodyPr(shape);
14386
14824
  bodyPr.attrs = bodyPr.attrs.filter((a) => !(a.name.namespaceURI === "" && a.name.localName === "rot"));
14387
- if (rotationDeg !== null && rotationDeg !== 0) bodyPr.attrs.push(attr(qname("", "rot", ""), String(Math.round(rotationDeg * 6e4))));
14825
+ if (rotationDeg !== null && rotationDeg !== 0) {
14826
+ const rot = angle60000(rotationDeg * 6e4, "setShapeTextBodyRotationDeg: rotationDeg");
14827
+ bodyPr.attrs.push(attr(qname("", "rot", ""), String(rot)));
14828
+ }
14388
14829
  commitAndRefresh(shape);
14389
14830
  };
14390
14831
  /**
@@ -14582,7 +15023,10 @@ const setShapeTextMargins = (shape, margins) => {
14582
15023
  });
14583
15024
  const localsToClear = new Set(writes.map((w) => w.name));
14584
15025
  bodyPr.attrs = bodyPr.attrs.filter((a) => !(a.name.namespaceURI === "" && localsToClear.has(a.name.localName)));
14585
- for (const w of writes) bodyPr.attrs.push(attr(qname("", w.name, ""), String(Math.round(w.value))));
15026
+ for (const w of writes) {
15027
+ const emu = emuCoordinate32(w.value, `setShapeTextMargins: ${w.name}`);
15028
+ bodyPr.attrs.push(attr(qname("", w.name, ""), String(emu)));
15029
+ }
14586
15030
  commitAndRefresh(shape);
14587
15031
  };
14588
15032
  /** Sets the bullet style on every paragraph in the shape's text body. */
@@ -15927,6 +16371,22 @@ const duplicateSlideAt = (pres, atIndex, slide) => {
15927
16371
  const slides = getSlides(pres);
15928
16372
  return slides[Math.max(0, Math.min(atIndex, slides.length - 1))];
15929
16373
  };
16374
+ const collectRelRefs = (el, into) => {
16375
+ for (const a of el.attrs) if (a.name.namespaceURI === NS.officeDocRels) into.add(a.value);
16376
+ for (const c of el.children) if (c.kind === "element") collectRelRefs(c, into);
16377
+ };
16378
+ const pruneDanglingGraphicFrames = (el, keptRelIds) => {
16379
+ el.children = el.children.filter((c) => {
16380
+ if (c.kind !== "element") return true;
16381
+ if (c.name.namespaceURI === NS.pml && c.name.localName === "graphicFrame") {
16382
+ const refs = /* @__PURE__ */ new Set();
16383
+ collectRelRefs(c, refs);
16384
+ for (const id of refs) if (!keptRelIds.has(id)) return false;
16385
+ }
16386
+ return true;
16387
+ });
16388
+ for (const c of el.children) if (c.kind === "element") pruneDanglingGraphicFrames(c, keptRelIds);
16389
+ };
15930
16390
  /**
15931
16391
  * Imports a slide from another presentation into `targetPres`. The
15932
16392
  * slide's part bytes are copied verbatim; image rels are followed and
@@ -15962,8 +16422,9 @@ const importSlide = (targetPres, sourceSlide, targetLayout) => {
15962
16422
  const newRels = emptyRels();
15963
16423
  const layoutPartName = targetLayout[LAYOUT_PART_NAME];
15964
16424
  if (targetPkg.getPart(layoutPartName) === null) throw new Error(`importSlide: layout ${layoutPartName} not in target package`);
16425
+ const layoutRelId = nextRelId(sourceRels?.items.map((r) => r.id) ?? []);
15965
16426
  newRels.items.push({
15966
- id: "rId1",
16427
+ id: layoutRelId,
15967
16428
  type: REL_TYPES.slideLayout,
15968
16429
  target: `../slideLayouts/${basename(layoutPartName)}`,
15969
16430
  targetMode: "Internal"
@@ -16003,6 +16464,22 @@ const importSlide = (targetPres, sourceSlide, targetLayout) => {
16003
16464
  }
16004
16465
  }
16005
16466
  targetPkg.setRels(newSlidePartName, newRels);
16467
+ const newPart = targetPkg.getPart(newSlidePartName);
16468
+ if (newPart) {
16469
+ const keptRelIds = new Set(newRels.items.map((r) => r.id));
16470
+ const bodyDoc = parseXml(decode$1(newPart.data));
16471
+ const bodyRefs = /* @__PURE__ */ new Set();
16472
+ collectRelRefs(bodyDoc.root, bodyRefs);
16473
+ let hasDangling = false;
16474
+ for (const id of bodyRefs) if (!keptRelIds.has(id)) {
16475
+ hasDangling = true;
16476
+ break;
16477
+ }
16478
+ if (hasDangling) {
16479
+ pruneDanglingGraphicFrames(bodyDoc.root, keptRelIds);
16480
+ newPart.data = encode$1(serializeXml(bodyDoc));
16481
+ }
16482
+ }
16006
16483
  const presRels = targetPkg.getRels(PRES_PART_NAME) ?? emptyRels();
16007
16484
  const newRId = nextRelId(presRels.items.map((r) => r.id));
16008
16485
  presRels.items.push({
@@ -16045,8 +16522,8 @@ const mergePresentations = (targetPres, sourcePres, targetLayout) => {
16045
16522
  };
16046
16523
  //#endregion
16047
16524
  //#region src/api/index.ts
16048
- const VERSION = "0.7.0";
16525
+ const VERSION = "0.9.0";
16049
16526
  //#endregion
16050
- export { addSlideLine as $, getTableRowHeights as $a, getAllTables as $i, getUnusedSlideMasters as $n, findChartsWithDataLabels as $o, setParagraphSpacing as $r, getSlideCommentAuthors as $s, getShapeStrokeWidth as $t, getShapeAt as A, getSlideMediaPartNames as Aa, hasShapeText as Ai, getMaxShapeIdInPresentation as An, setCoreProperties as Ao, setShapeStrokeJoin as Ar, setSlideBackgroundImage as As, setShapeTextFormat as At, getSlideXmlString as B, getTableCellAlignment as Ba, setSlideSize as Bi, getShapeKind as Bn, getSlideLayoutType as Bo, getParagraphSpacing as Br, findCommentsByAuthor as Bs, getShapeGradientFill as Bt, findSlidesByText as C, setSlideTransition as Ca, getShapeImageDuotone as Ci, translateShapes as Cn, removeThumbnail as Co, setShapeRotation as Cr, getSlideLayoutShapes as Cs, setShapeBullets as Ct, getPresentationText as D, getOrphanMediaPartNames as Da, getShapeImageOpacity as Di, getGroupChildren as Dn, getPresentationCreated as Do, setShapeStrokeCap as Dr, getSlideMasterBackgroundPatternFill as Ds, setShapeTextBodyRotationDeg as Dt, getPresentationShapeCountsBySlide as E, getMediaParts as Ea, getShapeImageLinkUrl as Ei, findShapesInRect as En, getExtendedProperties as Eo, setShapeStrokeArrow as Er, getSlideMasterBackgroundImageBytes as Es, setShapeTextAutoFit as Et, getSlideLayoutCount as F, validatePresentation as Fa, setShapeImageOpacity as Fi, getShapeCenter as Fn, findSlideLayoutByPartName as Fo, getParagraphBulletImageBytes as Fr, clearAllSlideComments as Fs, getShapeEffect as Ft, replaceTextInPresentation as G, getTableCellParagraphs as Ga, findSlidesByHyperlink as Gi, getShapePreset as Gn, getParagraphPropertiesEffective as Go, getShapeRunCount as Gr, getCommentDate as Gs, getShapeFillEffective as Gt, getSlidesByLayout as H, getTableCellBorders as Ha, clearAllHyperlinks as Hi, getShapePlaceholderIdx as Hn, getSlideLayoutUsageCountsByType as Ho, getShapeParagraphCount as Hr, findSlidesWithCommentsByAuthor as Hs, getShapeFill as Ht, getSlideOutline as I, clearTableCellFill as Ia, SLIDE_SIZE_16_10 as Ii, getShapeCustomGeometry as In, findSlideLayoutByType as Io, getParagraphBulletStyle as Ir, clearSlideComments as Is, getShapeEffects as It, replaceTokensInPresentation as J, getTableCellText as Ja, getAllCharts as Ji, getShapeText as Jn, setShapeHyperlink as Jo, getShapeRunText as Jr, getCommentText as Js, getShapeStrokeColor as Jt, replaceTextInSlide as K, getTableCellPosition as Ka, findSlidesWithChartKind as Ki, getShapeRotation as Kn, getShapeHyperlink as Ko, getShapeRunHyperlink as Kr, getCommentPosition as Ks, getShapeStroke as Kt, getSlidePartName as L, getPresentationTableCountsBySlide as La, SLIDE_SIZE_16_9 as Li, getShapeDescription as Ln, getSlideLayoutName as Lo, getParagraphIndent as Lr, findCommentAuthorByName as Ls, getShapeEffectsEffective as Lt, getSlideCount as M, readPackagePart as Ma, setShapeImageBrightness as Mi, getShapeAltTitle as Mn, touchModified as Mo, resolveDrawingColor as Mr, setShapeClickAction as Ms, setShapeTextWrap as Mt, getSlideIndex as N, setMediaPartBytes as Na, setShapeImageContrast as Ni, getShapeBounds as Nn, findLayoutsWithPlaceholderType as No, getParagraphAlignment as Nr, setShapeImage as Ns, clearShapeEffects as Nt, getPresentationTextLength as O, getPackageSize as Oa, getShapeImagePartName as Oi, getGroupTransform as On, getPresentationModified as Oo, setShapeStrokeCompound as Or, getSlideMasterShapes as Os, setShapeTextColumns as Ot, getSlideInfo as P, slidesUsingMediaPart as Pa, setShapeImageCrop as Pi, getShapeBoundsResolved as Pn, findSlideLayout as Po, getParagraphBullet as Pr, addSlideComment as Ps, findShapesByEffect as Pt, addSlideImage as Q, getTableDimensions as Qa, getAllNotes as Qi, getSlideMasterUsageCounts as Qn, findChartsBySeriesName as Qo, setParagraphLevel as Qr, getPresentationCommenters as Qs, getShapeStrokeJoin as Qt, getSlideText as R, getSlideTables as Ra, SLIDE_SIZE_4_3 as Ri, getShapeFlip as Rn, getSlideLayoutPartName as Ro, getParagraphLevel as Rr, findCommentsAfter as Rs, setShapeGlow as Rt, findSlidesByNotes as S, getSlideTransition as Sa, getShapeImageCrop as Si, setSlideLayout as Sn, getThumbnail as So, setShapePosition as Sr, getSlideLayoutBackgroundShapes as Ss, setShapeAlignment as St, getOutlineText as T, compactPackage as Ta, getShapeImageFormat as Ti, findShapesAtPoint as Tn, getCoreProperties as To, setShapeStroke as Tr, getSlideMasterBackgroundGradientFill as Ts, setShapeTextAnchor as Tt, isSlideHidden as U, getTableCellFill as Ua, clearAllSlideNotes as Ui, getShapePlaceholderType as Un, getSlideLayouts as Uo, getShapeParagraphElements as Ur, getCommentAuthor as Us, getShapeFillColor as Ut, getSlides as V, getTableCellAnchor as Va, appendSlideNotes as Vi, getShapeName as Vn, getSlideLayoutUsageCounts as Vo, getShapeHyperlinkTooltip as Vr, findCommentsByText as Vs, getShapeGradientFillEffective as Vt, replaceTextInNotes as W, getTableCellMargins as Wa, clearSlideHyperlinks as Wi, getShapePosition as Wn, getUnusedSlideLayouts as Wo, getShapeRunClickAction as Wr, getCommentAuthors as Ws, getShapeFillColorResolved as Wt, setSlideHidden as X, getTableCells as Xa, getAllHyperlinks as Xi, getSlideMasterPartName as Xn, addSlideChart as Xo, setParagraphAlignment as Xr, getPresentationCommentCountsByAuthor as Xs, getShapeStrokeCompound as Xt, searchSlides as Y, getTableCellTextDirection as Ya, getAllComments as Yi, getSlideMasterCount as Yn, setShapeRunFormat as Yo, isParagraphBulletPicture as Yr, getCommentsSortedByDate as Ys, getShapeStrokeColorResolved as Yt, slideHasAnimations as Z, getTableColumnWidths as Za, getAllImages as Zi, getSlideMasterPartNames as Zn, findChartByKind as Zo, setParagraphBullet as Zr, getPresentationCommentCountsBySlide as Zs, getShapeStrokeEffective as Zt, getSlideSections as _, hasSlideNotes as _a, getPresentationImageCountsBySlide as _i, getShapesBounds as _n, setTableCellTextFormat as _o, setShapeGradientFill as _r, getSlideColorMapOverride as _s, getShapeTextBodyRotationDeg as _t, addSlide as a, getPresentationNotesLengthsBySlide as aa, loadPresentation as ac, setSlidePlaceholders as ai, findShapesByHyperlink as an, isChartShape as ao, setShapeAltTitle as ar, getShapeChartSeriesNames as as, clearSlideShapes as at, findSlideByText as b, setSlideNotes as ba, getShapeImageBytes as bi, getSlidesWithEmptyPlaceholders as bn, setTableStyleFlags as bo, setShapeNoStroke as br, getSlideLayoutBackgroundImageBytes as bs, getShapeTextMargins as bt, duplicateSlide as c, getSlideNotesLength as ca, emu as cc, findShapesWithAnimation as ci, findShapesByPreset as cn, removeTableColumn as co, setShapeHidden as cr, getSlideCharts as cs, removeShape as ct, mergePresentations as d, getSlidesWithHyperlinks as da, pt as dc, findFlippedShapes as di, findSlidePlaceholder as dn, setTableCellAnchor as do, clearShapeStroke as dr, resolveDeckBodyTextColor as ds, setShapeZIndex as dt, getDistinctHyperlinkUrls as ea, getSlideComments as ec, setShapeRunHyperlink as ei, findEmptyPlaceholders as en, getTableSize as eo, isShapeHidden as er, findChartsWithTrendlines as es, addSlideShape as et, moveSlide as f, getSlidesWithImages as fa, findOverlappingShapePairs as fi, findSlidePlaceholderByIdx as fn, setTableCellBorders as fo, getShapePatternFill as fr, clearSlideBackground as fs, appendShapeText as ft, swapSlides as g, getVisibleSlides as ga, findSlidesByLayoutType as gi, getShapeXmlString as gn, setTableCellTextDirection as go, setShapeFlip as gr, getSlideBackgroundPatternFill as gs, getShapeTextAutoFitParams as gt, sortSlides as h, getSlidesWithTables as ha, findSlidesByLayoutPartName as hi, getShapeSlide as hn, setTableCellText as ho, setShapeFill as hr, getSlideBackgroundImageBytes as hs, getShapeTextAutoFit as ht, addSectionHeaderSlide as i, getPresentationNotesLength as ia, createPresentation as ic, setSlideBody as ii, findShapeInPresentation as in, insertTableRow as io, renameShape as ir, getShapeChartKind as is, bringShapeToFront as it, getSlideAt as j, listPackageParts as ja, isShapeImageGrayscale as ji, getShapeAdjustValues as jn, setExtendedProperties as jo, getShapeRunFormat as jr, getShapeClickAction as js, setShapeTextMargins as jt, getPresentationTextLengthsBySlide as k, getPresentationSummary as ka, hasShapeImage as ki, getMaxShapeId as kn, incrementRevision as ko, setShapeStrokeDash as kr, setSlideBackground as ks, setShapeTextDirection as kt, duplicateSlideAt as l, getSlidesWithCharts as la, inches as lc, getShapeAnimation as li, findShapesByText as ln, removeTableRow as lo, shapesOverlap as lr, setChartSpec as ls, sendShapeBackward as lt, reverseSlides as m, getSlidesWithOverlap as ma, findSlidesByLayoutName as mi, getShapeIndex as mn, setTableCellMargins as mo, getShapeStrokeDash as mr, getSlideBackgroundGradientFill as ms, getShapeTextAnchor as mt, addBlankSlide as n, getHiddenSlides as na, getPresentationFonts as nc, getSlideBody as ni, findShapeByName as nn, getTableStyleId as no, isShapeTextBox as nr, getPresentationChartKindCounts as ns, addSlideTextBox as nt, addSlideAt as o, getPresentationNotesText as oa, savePresentation as oc, setSlideTitle as oi, findShapesByKind as on, isTableShape as oo, setShapeBounds as or, getShapeChartSeriesValues as os, copyShape as ot, removeSlide as p, getSlidesWithNotes as pa, findShapesOutsideCanvas as pi, findSlidePlaceholders as pn, setTableCellFill as po, getShapeStrokeArrow as pr, getSlideBackground as ps, getShapeBodyPrEffective as pt, replaceTextInSlideNotes as q, getTableCellSpan as qa, findSlidesWithChartTrendlines as qi, getShapeSize as qn, getShapeRunFormatEffective as qo, getShapeRunHyperlinkTooltip as qr, getCommentSlide as qs, getShapeStrokeCap as qt, addContentSlide as r, getPresentationHyperlinkCountsBySlide as ra, getPresentationTheme as rc, getSlideTitle as ri, findShapeByText as rn, insertTableColumn as ro, pointInShape as rr, getShapeChartCategories as rs, bringShapeForward as rt, addTitleSlide as s, getSlideNotes as sa, cm as sc, clearSlideAnimations as si, findShapesByName as sn, mergeTableCells as so, setShapeDescription as sr, getShapeChartSpec as ss, getShapeZIndex as st, VERSION as t, getEmptySlides as ta, removeSlideComment as tc, setShapeRunText as ti, findShapeById as tn, getTableStyleFlags as to, isShapePlaceholder as tr, getPresentationChartCountsBySlide as ts, addSlideTable as tt, importSlide as u, getSlidesWithComments as ua, mm as uc, setShapeAnimation as ui, findShapesWithHyperlinks as un, setTableCellAlignment as uo, clearShapeFill as ur, getEffectiveColorMap as us, sendShapeToBack as ut, setSlideSections as v, removeSlideNotes as va, getShapeImageBiLevelThreshold as vi, getSlideLayout as vn, setTableColumnWidth as vo, setShapeImageFill as vr, getSlideLayoutBackground as vs, getShapeTextColumns as vt, getAllShapes as w, _internalPackageOf as wa, getShapeImageFillBytes as wi, centerShapeOnSlide as wn, setThumbnail as wo, setShapeSize as wr, getSlideMasterBackground as ws, setShapeText as wt, findSlideByTitle as x, clearSlideTransition as xa, getShapeImageContrast as xi, replaceTokensInSlide as xn, setTableStyleId as xo, setShapePatternFill as xr, getSlideLayoutBackgroundPatternFill as xs, getShapeTextWrap as xt, findSlideByPartName as y, replaceHyperlink as ya, getShapeImageBrightness as yi, getSlideShapes as yn, setTableRowHeight as yo, setShapeNoFill as yr, getSlideLayoutBackgroundGradientFill as ys, getShapeTextDirection as yt, getSlideTextLength as z, getTableCell as za, getSlideSize as zi, getShapeId as zn, getSlideLayoutPlaceholders as zo, getParagraphLineSpacing as zr, findCommentsBefore as zs, setShapeShadow as zt };
16527
+ export { addSlideLine as $, getTableDimensions as $a, getAllNotes as $i, getUnusedSlideMasters as $n, findChartsBySeriesName as $o, setParagraphLineSpacing as $r, getPresentationCommenters as $s, getShapeStrokeWidth as $t, getShapeAt as A, getPresentationSummary as Aa, hasShapeImage as Ai, getMaxShapeIdInPresentation as An, incrementRevision as Ao, setShapeStrokeJoin as Ar, setSlideBackground as As, setShapeTextFormat as At, getSlideXmlString as B, getTableCell as Ba, getSlideSize as Bi, getShapeKind as Bn, getSlideLayoutPlaceholders as Bo, getParagraphSpacing as Br, findCommentsBefore as Bs, getShapeGradientFill as Bt, findSlidesByText as C, getSlideTransition as Ca, getShapeImageCrop as Ci, translateShapes as Cn, getThumbnail as Co, setShapeRotation as Cr, getSlideLayoutBackgroundShapes as Cs, setShapeBullets as Ct, getPresentationText as D, getMediaParts as Da, getShapeImageLinkUrl as Di, getGroupChildren as Dn, getExtendedProperties as Do, setShapeStrokeCap as Dr, getSlideMasterBackgroundImageBytes as Ds, setShapeTextBodyRotationDeg as Dt, getPresentationShapeCountsBySlide as E, compactPackage as Ea, getShapeImageFormat as Ei, findShapesInRect as En, getCoreProperties as Eo, setShapeStrokeArrow as Er, getSlideMasterBackgroundGradientFill as Es, setShapeTextAutoFit as Et, getSlideLayoutCount as F, slidesUsingMediaPart as Fa, setShapeImageCrop as Fi, getShapeCenter as Fn, findSlideLayout as Fo, getParagraphBulletImageBytes as Fr, addSlideComment as Fs, getShapeEffect as Ft, replaceTextInPresentation as G, getTableCellMargins as Ga, clearSlideHyperlinks as Gi, getShapePreset as Gn, getUnusedSlideLayouts as Go, getShapeRunCount as Gr, getCommentAuthors as Gs, getShapeFillEffective as Gt, getSlidesByLayout as H, getTableCellAnchor as Ha, appendSlideNotes as Hi, getShapePlaceholderIdx as Hn, getSlideLayoutUsageCounts as Ho, getShapeParagraphCount as Hr, findCommentsByText as Hs, getShapeFill as Ht, getSlideOutline as I, validatePresentation as Ia, setShapeImageOpacity as Ii, getShapeCustomGeometry as In, findSlideLayoutByPartName as Io, getParagraphBulletStyle as Ir, clearAllSlideComments as Is, getShapeEffects as It, replaceTokensInPresentation as J, getTableCellSpan as Ja, findSlidesWithChartTrendlines as Ji, getShapeText as Jn, getShapeRunFormatEffective as Jo, getShapeRunText as Jr, getCommentSlide as Js, getShapeStrokeColor as Jt, replaceTextInSlide as K, getTableCellParagraphs as Ka, findSlidesByHyperlink as Ki, getShapeRotation as Kn, getParagraphPropertiesEffective as Ko, getShapeRunHyperlink as Kr, getCommentDate as Ks, getShapeStroke as Kt, getSlidePartName as L, clearTableCellFill as La, SLIDE_SIZE_16_10 as Li, getShapeDescription as Ln, findSlideLayoutByType as Lo, getParagraphIndent as Lr, clearSlideComments as Ls, getShapeEffectsEffective as Lt, getSlideCount as M, listPackageParts as Ma, isShapeImageGrayscale as Mi, getShapeAltTitle as Mn, setExtendedProperties as Mo, resolveDrawingColor as Mr, getShapeClickAction as Ms, setShapeTextWrap as Mt, getSlideIndex as N, readPackagePart as Na, setShapeImageBrightness as Ni, getShapeBounds as Nn, touchModified as No, getParagraphAlignment as Nr, setShapeClickAction as Ns, clearShapeEffects as Nt, getPresentationTextLength as O, getOrphanMediaPartNames as Oa, getShapeImageOpacity as Oi, getGroupTransform as On, getPresentationCreated as Oo, setShapeStrokeCompound as Or, getSlideMasterBackgroundPatternFill as Os, setShapeTextColumns as Ot, getSlideInfo as P, setMediaPartBytes as Pa, setShapeImageContrast as Pi, getShapeBoundsResolved as Pn, findLayoutsWithPlaceholderType as Po, getParagraphBullet as Pr, setShapeImage as Ps, findShapesByEffect as Pt, addSlideImage as Q, getTableColumnWidths as Qa, getAllImages as Qi, getSlideMasterUsageCounts as Qn, findChartByKind as Qo, setParagraphLevel as Qr, getPresentationCommentCountsBySlide as Qs, getShapeStrokeJoin as Qt, getSlideText as R, getPresentationTableCountsBySlide as Ra, SLIDE_SIZE_16_9 as Ri, getShapeFlip as Rn, getSlideLayoutName as Ro, getParagraphLevel as Rr, findCommentAuthorByName as Rs, setShapeGlow as Rt, findSlidesByNotes as S, clearSlideTransition as Sa, getShapeImageContrast as Si, setSlideLayout as Sn, setTableStyleId as So, setShapePosition as Sr, getSlideLayoutBackgroundPatternFill as Ss, setShapeAlignment as St, getOutlineText as T, _internalPackageOf as Ta, getShapeImageFillBytes as Ti, findShapesAtPoint as Tn, setThumbnail as To, setShapeStroke as Tr, getSlideMasterBackground as Ts, setShapeTextAnchor as Tt, isSlideHidden as U, getTableCellBorders as Ua, clearAllHyperlinks as Ui, getShapePlaceholderType as Un, getSlideLayoutUsageCountsByType as Uo, getShapeParagraphElements as Ur, findSlidesWithCommentsByAuthor as Us, getShapeFillColor as Ut, getSlides as V, getTableCellAlignment as Va, setSlideSize as Vi, getShapeName as Vn, getSlideLayoutType as Vo, getShapeHyperlinkTooltip as Vr, findCommentsByAuthor as Vs, getShapeGradientFillEffective as Vt, replaceTextInNotes as W, getTableCellFill as Wa, clearAllSlideNotes as Wi, getShapePosition as Wn, getSlideLayouts as Wo, getShapeRunClickAction as Wr, getCommentAuthor as Ws, getShapeFillColorResolved as Wt, setSlideHidden as X, getTableCellTextDirection as Xa, getAllComments as Xi, getSlideMasterPartName as Xn, setShapeRunFormat as Xo, setParagraphAlignment as Xr, getCommentsSortedByDate as Xs, getShapeStrokeCompound as Xt, searchSlides as Y, getTableCellText as Ya, getAllCharts as Yi, getSlideMasterCount as Yn, setShapeHyperlink as Yo, isParagraphBulletPicture as Yr, getCommentText as Ys, getShapeStrokeColorResolved as Yt, slideHasAnimations as Z, getTableCells as Za, getAllHyperlinks as Zi, getSlideMasterPartNames as Zn, addSlideChart as Zo, setParagraphBullet as Zr, getPresentationCommentCountsByAuthor as Zs, getShapeStrokeEffective as Zt, getSlideSections as _, getVisibleSlides as _a, findSlidesByLayoutType as _i, getShapesBounds as _n, setTableCellTextDirection as _o, setShapeGradientFill as _r, getSlideBackgroundPatternFill as _s, getShapeTextBodyRotationDeg as _t, addSlide as a, getPresentationNotesLength as aa, createPresentation as ac, setSlideBody as ai, findShapesByHyperlink as an, insertTableRow as ao, setShapeAltTitle as ar, getShapeChartKind as as, clearSlideShapes as at, findSlideByText as b, replaceHyperlink as ba, getShapeImageBrightness as bi, getSlidesWithEmptyPlaceholders as bn, setTableRowHeight as bo, setShapeNoStroke as br, getSlideLayoutBackgroundGradientFill as bs, getShapeTextMargins as bt, duplicateSlide as c, getSlideNotes as ca, cm as cc, clearSlideAnimations as ci, findShapesByPreset as cn, mergeTableCells as co, setShapeHidden as cr, getShapeChartSpec as cs, removeShape as ct, mergePresentations as d, getSlidesWithComments as da, mm as dc, setShapeAnimation as di, findSlidePlaceholder as dn, setTableCellAlignment as do, clearShapeStroke as dr, getEffectiveColorMap as ds, setShapeZIndex as dt, getAllTables as ea, getSlideCommentAuthors as ec, setParagraphSpacing as ei, findEmptyPlaceholders as en, getTableRowHeights as eo, isShapeHidden as er, findChartsWithDataLabels as es, addSlideShape as et, moveSlide as f, getSlidesWithHyperlinks as fa, pt as fc, findFlippedShapes as fi, findSlidePlaceholderByIdx as fn, setTableCellAnchor as fo, getShapePatternFill as fr, resolveDeckBodyTextColor as fs, appendShapeText as ft, swapSlides as g, getSlidesWithTables as ga, findSlidesByLayoutPartName as gi, getShapeXmlString as gn, setTableCellText as go, setShapeFlip as gr, getSlideBackgroundImageBytes as gs, getShapeTextAutoFitParams as gt, sortSlides as h, getSlidesWithOverlap as ha, findSlidesByLayoutName as hi, getShapeSlide as hn, setTableCellMargins as ho, setShapeFill as hr, getSlideBackgroundGradientFill as hs, getShapeTextAutoFit as ht, addSectionHeaderSlide as i, getPresentationHyperlinkCountsBySlide as ia, getPresentationTheme as ic, getSlideTitle as ii, findShapeInPresentation as in, insertTableColumn as io, renameShape as ir, getShapeChartCategories as is, bringShapeToFront as it, getSlideAt as j, getSlideMediaPartNames as ja, hasShapeText as ji, getShapeAdjustValues as jn, setCoreProperties as jo, getShapeRunFormat as jr, setSlideBackgroundImage as js, setShapeTextMargins as jt, getPresentationTextLengthsBySlide as k, getPackageSize as ka, getShapeImagePartName as ki, getMaxShapeId as kn, getPresentationModified as ko, setShapeStrokeDash as kr, getSlideMasterShapes as ks, setShapeTextDirection as kt, duplicateSlideAt as l, getSlideNotesLength as la, emu as lc, findShapesWithAnimation as li, findShapesByText as ln, removeTableColumn as lo, shapesOverlap as lr, getSlideCharts as ls, sendShapeBackward as lt, reverseSlides as m, getSlidesWithNotes as ma, findShapesOutsideCanvas as mi, getShapeIndex as mn, setTableCellFill as mo, getShapeStrokeDash as mr, getSlideBackground as ms, getShapeTextAnchor as mt, addBlankSlide as n, getEmptySlides as na, removeSlideComment as nc, setShapeRunText as ni, findShapeByName as nn, getTableStyleFlags as no, isShapeTextBox as nr, getPresentationChartCountsBySlide as ns, addSlideTextBox as nt, addSlideAt as o, getPresentationNotesLengthsBySlide as oa, loadPresentation as oc, setSlidePlaceholders as oi, findShapesByKind as on, isChartShape as oo, setShapeBounds as or, getShapeChartSeriesNames as os, copyShape as ot, removeSlide as p, getSlidesWithImages as pa, findOverlappingShapePairs as pi, findSlidePlaceholders as pn, setTableCellBorders as po, getShapeStrokeArrow as pr, clearSlideBackground as ps, getShapeBodyPrEffective as pt, replaceTextInSlideNotes as q, getTableCellPosition as qa, findSlidesWithChartKind as qi, getShapeSize as qn, getShapeHyperlink as qo, getShapeRunHyperlinkTooltip as qr, getCommentPosition as qs, getShapeStrokeCap as qt, addContentSlide as r, getHiddenSlides as ra, getPresentationFonts as rc, getSlideBody as ri, findShapeByText as rn, getTableStyleId as ro, pointInShape as rr, getPresentationChartKindCounts as rs, bringShapeForward as rt, addTitleSlide as s, getPresentationNotesText as sa, savePresentation as sc, setSlideTitle as si, findShapesByName as sn, isTableShape as so, setShapeDescription as sr, getShapeChartSeriesValues as ss, getShapeZIndex as st, VERSION as t, getDistinctHyperlinkUrls as ta, getSlideComments as tc, setShapeRunHyperlink as ti, findShapeById as tn, getTableSize as to, isShapePlaceholder as tr, findChartsWithTrendlines as ts, addSlideTable as tt, importSlide as u, getSlidesWithCharts as ua, inches as uc, getShapeAnimation as ui, findShapesWithHyperlinks as un, removeTableRow as uo, clearShapeFill as ur, setChartSpec as us, sendShapeToBack as ut, setSlideSections as v, hasSlideNotes as va, getPresentationImageCountsBySlide as vi, getSlideLayout as vn, setTableCellTextFormat as vo, setShapeImageFill as vr, getSlideColorMapOverride as vs, getShapeTextColumns as vt, getAllShapes as w, setSlideTransition as wa, getShapeImageDuotone as wi, centerShapeOnSlide as wn, removeThumbnail as wo, setShapeSize as wr, getSlideLayoutShapes as ws, setShapeText as wt, findSlideByTitle as x, setSlideNotes as xa, getShapeImageBytes as xi, replaceTokensInSlide as xn, setTableStyleFlags as xo, setShapePatternFill as xr, getSlideLayoutBackgroundImageBytes as xs, getShapeTextWrap as xt, findSlideByPartName as y, removeSlideNotes as ya, getShapeImageBiLevelThreshold as yi, getSlideShapes as yn, setTableColumnWidth as yo, setShapeNoFill as yr, getSlideLayoutBackground as ys, getShapeTextDirection as yt, getSlideTextLength as z, getSlideTables as za, SLIDE_SIZE_4_3 as zi, getShapeId as zn, getSlideLayoutPartName as zo, getParagraphLineSpacing as zr, findCommentsAfter as zs, setShapeShadow as zt };
16051
16528
 
16052
- //# sourceMappingURL=api-DJkYUL_0.js.map
16529
+ //# sourceMappingURL=api-Irqm9KrN.js.map