pptx-kit 0.8.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;";
@@ -1776,28 +1813,74 @@ const setTextBody = (txBody, value) => {
1776
1813
  }
1777
1814
  };
1778
1815
  //#endregion
1779
- //#region src/internal/drawingml/text-format.ts
1780
- NS.dml;
1781
- const NAME_RPR$5 = qname("a", "rPr", NS.dml);
1782
- const NAME_LATIN = qname("a", "latin", NS.dml);
1783
- NS.dml;
1784
- NS.dml;
1785
- 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
1786
1880
  const NAME_SRGB_CLR$4 = qname("a", "srgbClr", NS.dml);
1787
- const NAME_SCHEME_CLR$1 = qname("a", "schemeClr", NS.dml);
1788
- const ATTR_SZ = qname("", "sz", "");
1789
- const ATTR_B = qname("", "b", "");
1790
- const ATTR_I = qname("", "i", "");
1791
- const ATTR_U = qname("", "u", "");
1792
- const ATTR_STRIKE = qname("", "strike", "");
1793
- const ATTR_SPC = qname("", "spc", "");
1794
- const ATTR_KERN = qname("", "kern", "");
1795
- const ATTR_BASELINE = qname("", "baseline", "");
1796
- const ATTR_CAP = qname("", "cap", "");
1797
- const ATTR_TYPEFACE$1 = qname("", "typeface", "");
1798
- const ATTR_VAL$7 = qname("", "val", "");
1799
- const NAME_HIGHLIGHT = qname("a", "highlight", NS.dml);
1800
- 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([
1801
1884
  "bg1",
1802
1885
  "tx1",
1803
1886
  "bg2",
@@ -1816,18 +1899,105 @@ const SCHEME_TOKENS$1 = new Set([
1816
1899
  "lt2",
1817
1900
  "dk2"
1818
1901
  ]);
1819
- const parseColor$1 = (value) => {
1820
- 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 {
1821
1927
  kind: "scheme",
1822
- token: value
1928
+ token
1823
1929
  };
1824
- const hex = value.startsWith("#") ? value.slice(1) : value;
1825
- 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 : {
1826
1933
  kind: "srgb",
1827
- hex: hex.toUpperCase()
1934
+ hex
1828
1935
  };
1829
- return null;
1830
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;
1831
2001
  const setOrRemoveAttr = (attrs, name, value) => {
1832
2002
  const filtered = attrs.filter((a) => a.name.localName !== name.localName);
1833
2003
  if (value !== null) filtered.push(attr(name, value));
@@ -1836,29 +2006,27 @@ const setOrRemoveAttr = (attrs, name, value) => {
1836
2006
  const setSolidFill$1 = (rPr, value) => {
1837
2007
  rPr.children = rPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "solidFill"));
1838
2008
  if (value === null) return;
1839
- const parsed = parseColor$1(value);
2009
+ const parsed = parseColor(value);
1840
2010
  if (parsed === null) throw new Error(`unrecognized color: ${value}`);
1841
- 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)] })] });
1842
- 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);
1843
2012
  };
1844
2013
  const setLatin = (rPr, font) => {
1845
2014
  rPr.children = rPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "latin"));
1846
2015
  if (font === null) return;
1847
- 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);
1848
2017
  };
1849
2018
  const setHighlight = (rPr, value) => {
1850
2019
  rPr.children = rPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "highlight"));
1851
2020
  if (value === null) return;
1852
- const parsed = parseColor$1(value);
2021
+ const parsed = parseColor(value);
1853
2022
  if (parsed === null) throw new Error(`unrecognized highlight color: ${value}`);
1854
- 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)] });
1855
- 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);
1856
2024
  };
1857
2025
  /** Mutates `rPr` in place per `format`. */
1858
2026
  const applyRunFormat = (rPr, format) => {
1859
2027
  let attrs = rPr.attrs;
1860
2028
  if (format.size !== void 0) {
1861
- const sz = Math.round(format.size * 100);
2029
+ const sz = fontSizeHundredthPt(format.size * 100, "setShapeRunFormat: size");
1862
2030
  attrs = setOrRemoveAttr(attrs, ATTR_SZ, String(sz));
1863
2031
  }
1864
2032
  if (format.bold !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_B, format.bold ? "1" : "0");
@@ -1871,7 +2039,10 @@ const applyRunFormat = (rPr, format) => {
1871
2039
  const value = format.strike === false ? "noStrike" : format.strike === true ? "sngStrike" : format.strike;
1872
2040
  attrs = setOrRemoveAttr(attrs, ATTR_STRIKE, value);
1873
2041
  }
1874
- 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
+ }
1875
2046
  if (format.kern !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_KERN, String(Math.round(format.kern)));
1876
2047
  if (format.baseline !== void 0) {
1877
2048
  const pct = Math.round(format.baseline * 1e5);
@@ -1903,66 +2074,6 @@ const applyFormatToAllRuns = (txBody, format) => {
1903
2074
  }
1904
2075
  };
1905
2076
  //#endregion
1906
- //#region src/internal/drawingml/color.ts
1907
- const NAME_SRGB_CLR$3 = qname("a", "srgbClr", NS.dml);
1908
- const NAME_SCHEME_CLR = qname("a", "schemeClr", NS.dml);
1909
- const ATTR_VAL$6 = qname("", "val", "");
1910
- const SCHEME_TOKENS = new Set([
1911
- "bg1",
1912
- "tx1",
1913
- "bg2",
1914
- "tx2",
1915
- "accent1",
1916
- "accent2",
1917
- "accent3",
1918
- "accent4",
1919
- "accent5",
1920
- "accent6",
1921
- "hlink",
1922
- "folHlink",
1923
- "phClr",
1924
- "lt1",
1925
- "dk1",
1926
- "lt2",
1927
- "dk2"
1928
- ]);
1929
- /**
1930
- * Parses a user-supplied color string. Returns null on unrecognized input
1931
- * so callers can decide whether to throw with a specific message.
1932
- */
1933
- const parseColor = (value) => {
1934
- if (SCHEME_TOKENS.has(value)) return {
1935
- kind: "scheme",
1936
- token: value
1937
- };
1938
- const hex = value.startsWith("#") ? value.slice(1) : value;
1939
- if (/^[0-9A-Fa-f]{6}$/.test(hex)) return {
1940
- kind: "srgb",
1941
- hex: hex.toUpperCase()
1942
- };
1943
- return null;
1944
- };
1945
- /**
1946
- * Parses an sRGB hex color (`#RRGGBB` or `RRGGBB`), returning the
1947
- * normalized uppercase 6-digit hex (no `#`). Returns `null` for anything
1948
- * that isn't a 6-digit hex — including scheme tokens, which sRGB-only
1949
- * contexts (e.g. chart series fills) must reject rather than silently
1950
- * emit as an invalid `<a:srgbClr val="accent1"/>`.
1951
- */
1952
- const parseSrgbHex = (value) => {
1953
- const hex = value.startsWith("#") ? value.slice(1) : value;
1954
- return /^[0-9A-Fa-f]{6}$/.test(hex) ? hex.toUpperCase() : null;
1955
- };
1956
- /**
1957
- * Returns the `<a:srgbClr>` or `<a:schemeClr>` element for `value`.
1958
- * Throws on unrecognized colors.
1959
- */
1960
- const buildColorElement = (value) => {
1961
- const parsed = parseColor(value);
1962
- if (parsed === null) throw new Error(`unrecognized color: ${value}`);
1963
- 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)] });
1964
- };
1965
- //#endregion
1966
2077
  //#region src/internal/drawingml/fill.ts
1967
2078
  const NAME_SOLID_FILL$5 = qname("a", "solidFill", NS.dml);
1968
2079
  const NAME_NO_FILL$2 = qname("a", "noFill", NS.dml);
@@ -1970,6 +2081,9 @@ const NAME_GRAD_FILL = qname("a", "gradFill", NS.dml);
1970
2081
  const NAME_GS_LST = qname("a", "gsLst", NS.dml);
1971
2082
  const NAME_GS = qname("a", "gs", NS.dml);
1972
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", "");
1973
2087
  const ATTR_POS = qname("", "pos", "");
1974
2088
  const ATTR_ANG = qname("", "ang", "");
1975
2089
  const ATTR_SCALED = qname("", "scaled", "");
@@ -2024,6 +2138,63 @@ const setNoFill = (host) => {
2024
2138
  const clearFill = (host) => {
2025
2139
  removeAnyFill(host);
2026
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
+ ];
2027
2198
  const NAME_PATT_FILL = qname("a", "pattFill", NS.dml);
2028
2199
  const NAME_FG_CLR = qname("a", "fgClr", NS.dml);
2029
2200
  const NAME_BG_CLR = qname("a", "bgClr", NS.dml);
@@ -2035,7 +2206,7 @@ const ATTR_PRST$4 = qname("", "prst", "");
2035
2206
  const setPatternFill = (host, options) => {
2036
2207
  removeAnyFill(host);
2037
2208
  const pattFill = elem(NAME_PATT_FILL, {
2038
- attrs: [attr(ATTR_PRST$4, options.preset)],
2209
+ attrs: [attr(ATTR_PRST$4, oneOf(options.preset, PATTERN_PRESETS, "setShapePatternFill: preset"))],
2039
2210
  children: [elem(NAME_FG_CLR, { children: [buildColorElement(options.foreground)] }), elem(NAME_BG_CLR, { children: [buildColorElement(options.background)] })]
2040
2211
  });
2041
2212
  host.children.splice(fillInsertionIndex(host), 0, pattFill);
@@ -2051,11 +2222,22 @@ const setGradientFill = (host, options) => {
2051
2222
  children: [buildColorElement(s.color)]
2052
2223
  });
2053
2224
  });
2054
- const norm = ((options.angleDeg ?? 90) % 360 + 360) % 360;
2055
- 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
+ });
2056
2238
  const grad = elem(NAME_GRAD_FILL, {
2057
2239
  attrs: [attr(ATTR_FLIP, "none"), attr(ATTR_ROT_WITH_SHAPE$1, "1")],
2058
- 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]
2059
2241
  });
2060
2242
  host.children.splice(fillInsertionIndex(host), 0, grad);
2061
2243
  };
@@ -2071,7 +2253,7 @@ const ATTR_DIR$1 = qname("", "dir", "");
2071
2253
  const ATTR_ALGN = qname("", "algn", "");
2072
2254
  const ATTR_ROT_WITH_SHAPE = qname("", "rotWithShape", "");
2073
2255
  const ATTR_RAD = qname("", "rad", "");
2074
- const ATTR_VAL$5 = qname("", "val", "");
2256
+ const ATTR_VAL$6 = qname("", "val", "");
2075
2257
  /**
2076
2258
  * Computes the index inside `host.children` where an `<a:effectLst>`
2077
2259
  * should be inserted to satisfy the spec's child ordering on
@@ -2093,7 +2275,7 @@ const colorWithAlpha = (color, opacity) => {
2093
2275
  const base = buildColorElement(color);
2094
2276
  if (opacity !== void 0 && opacity >= 0 && opacity < 1) {
2095
2277
  const amt = Math.round(opacity * 1e5);
2096
- 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))] }));
2097
2279
  }
2098
2280
  return base;
2099
2281
  };
@@ -2105,8 +2287,8 @@ const colorWithAlpha = (color, opacity) => {
2105
2287
  const setShadow = (host, options = {}) => {
2106
2288
  removeEffectLst(host);
2107
2289
  const color = options.color ?? "#000000";
2108
- const blur = options.blurEmu ?? 50800;
2109
- const dist = options.offsetEmu ?? 38100;
2290
+ const blur = emuExtent(options.blurEmu ?? 50800, "setShapeShadow: blurEmu");
2291
+ const dist = emuExtent(options.offsetEmu ?? 38100, "setShapeShadow: offsetEmu");
2110
2292
  const angleDeg = options.angleDeg ?? 45;
2111
2293
  const dir = String(Math.round((angleDeg % 360 + 360) % 360 * 6e4));
2112
2294
  const effectLst = elem(NAME_EFFECT_LST, { children: [elem(NAME_OUTER_SHDW, {
@@ -2128,7 +2310,7 @@ const setShadow = (host, options = {}) => {
2128
2310
  const setGlow = (host, options) => {
2129
2311
  removeEffectLst(host);
2130
2312
  const effectLst = elem(NAME_EFFECT_LST, { children: [elem(NAME_GLOW, {
2131
- attrs: [attr(ATTR_RAD, String(options.radiusEmu ?? 63500))],
2313
+ attrs: [attr(ATTR_RAD, String(emuExtent(options.radiusEmu ?? 63500, "setShapeGlow: radiusEmu")))],
2132
2314
  children: [buildColorElement(options.color)]
2133
2315
  })] });
2134
2316
  host.children.splice(effectInsertionIndex(host), 0, effectLst);
@@ -2149,6 +2331,22 @@ const FILL_LOCALS = new Set([
2149
2331
  "gradFill",
2150
2332
  "pattFill"
2151
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);
2152
2350
  const removeChildrenIn = (host, names) => {
2153
2351
  host.children = host.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && names.has(c.name.localName)));
2154
2352
  };
@@ -2177,23 +2375,23 @@ const setSolidStroke = (spPr, options) => {
2177
2375
  const ln = ensureLn(spPr);
2178
2376
  if (options.widthEmu !== void 0) {
2179
2377
  ln.attrs = ln.attrs.filter((a) => a.name.localName !== "w");
2180
- 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"))));
2181
2379
  }
2182
2380
  removeChildrenIn(ln, FILL_LOCALS);
2183
- 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)] }));
2184
2382
  };
2185
2383
  /** Sets an explicit "no outline" on a shape's spPr. */
2186
2384
  const setNoStroke = (spPr) => {
2187
2385
  const ln = ensureLn(spPr);
2188
2386
  removeChildrenIn(ln, FILL_LOCALS);
2189
- ln.children.unshift(elem(NAME_NO_FILL$1));
2387
+ insertLnChild(ln, elem(NAME_NO_FILL$1));
2190
2388
  };
2191
2389
  /** Removes any `<a:ln>` from a shape's spPr (restores inheritance). */
2192
2390
  const clearStroke = (spPr) => {
2193
2391
  spPr.children = spPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "ln"));
2194
2392
  };
2195
2393
  const NAME_PRST_DASH = qname("a", "prstDash", NS.dml);
2196
- const ATTR_VAL$4 = qname("", "val", "");
2394
+ const ATTR_VAL$5 = qname("", "val", "");
2197
2395
  /**
2198
2396
  * Sets `<a:prstDash val="..."/>` inside the shape's `<a:ln>`. Creates
2199
2397
  * `<a:ln>` if absent. Replacing the dash choice on subsequent calls.
@@ -2201,7 +2399,7 @@ const ATTR_VAL$4 = qname("", "val", "");
2201
2399
  const setStrokeDash = (spPr, dash) => {
2202
2400
  const ln = ensureLn(spPr);
2203
2401
  ln.children = ln.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "prstDash"));
2204
- 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)] }));
2205
2403
  };
2206
2404
  const ATTR_TYPE$5 = qname("", "type", "");
2207
2405
  const ATTR_LEN = qname("", "len", "");
@@ -2222,7 +2420,7 @@ const setStrokeArrow = (spPr, end, options) => {
2222
2420
  const attrs = [attr(ATTR_TYPE$5, options.type)];
2223
2421
  if (options.width !== void 0) attrs.push(attr(ATTR_W$3, options.width));
2224
2422
  if (options.length !== void 0) attrs.push(attr(ATTR_LEN, options.length));
2225
- ln.children.push(elem(qname("a", localName, NS.dml), { attrs }));
2423
+ insertLnChild(ln, elem(qname("a", localName, NS.dml), { attrs }));
2226
2424
  };
2227
2425
  /** Sets `<a:ln cap="…"/>`. Pass `null` to clear the attribute. */
2228
2426
  const setStrokeCap = (spPr, cap) => {
@@ -2239,7 +2437,7 @@ const JOIN_LOCALS = new Set([
2239
2437
  const setStrokeJoin = (spPr, join) => {
2240
2438
  const ln = ensureLn(spPr);
2241
2439
  removeChildrenIn(ln, JOIN_LOCALS);
2242
- if (join !== null) ln.children.push(elem(qname("a", join, NS.dml)));
2440
+ if (join !== null) insertLnChild(ln, elem(qname("a", join, NS.dml)));
2243
2441
  };
2244
2442
  /** Sets `<a:ln cmpd="…"/>`. Pass `null` to clear the attribute. */
2245
2443
  const setStrokeCompound = (spPr, cmpd) => {
@@ -2683,7 +2881,7 @@ const setPosition = (shape, kind, x, y) => {
2683
2881
  off = elem(NAME_OFF$6);
2684
2882
  xfrm.children.unshift(off);
2685
2883
  }
2686
- 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")))];
2687
2885
  };
2688
2886
  /** Sets the shape's `<a:ext>` to `(w, h)` in EMU. */
2689
2887
  const setSize = (shape, kind, w, h) => {
@@ -2695,7 +2893,7 @@ const setSize = (shape, kind, w, h) => {
2695
2893
  if (offIdx >= 0) xfrm.children.splice(offIdx + 1, 0, ext);
2696
2894
  else xfrm.children.push(ext);
2697
2895
  }
2698
- 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")))];
2699
2897
  };
2700
2898
  const ATTR_ROT = qname("", "rot", "");
2701
2899
  const ATTR_FLIP_H$1 = qname("", "flipH", "");
@@ -2742,7 +2940,7 @@ const NAME_TX_BODY$9 = qname("p", "txBody", NS.pml);
2742
2940
  const ATTR_ID$11 = qname("", "id", "");
2743
2941
  const ATTR_NAME$9 = qname("", "name", "");
2744
2942
  const ATTR_TYPE$4 = qname("", "type", "");
2745
- const ATTR_IDX$5 = qname("", "idx", "");
2943
+ const ATTR_IDX$6 = qname("", "idx", "");
2746
2944
  const NV_BY_KIND = {
2747
2945
  shape: NAME_NV_SP_PR$4,
2748
2946
  picture: NAME_NV_PIC_PR$1,
@@ -2780,7 +2978,7 @@ const extractShape = (element, kind) => {
2780
2978
  const ph = firstChildElement(nvPr, NAME_PH$2);
2781
2979
  if (ph !== null) {
2782
2980
  placeholderType = getAttrValue(ph, ATTR_TYPE$4);
2783
- const idxRaw = getAttrValue(ph, ATTR_IDX$5);
2981
+ const idxRaw = getAttrValue(ph, ATTR_IDX$6);
2784
2982
  if (idxRaw !== null) placeholderIdx = Number.parseInt(idxRaw, 10);
2785
2983
  }
2786
2984
  }
@@ -2900,7 +3098,7 @@ const NAME_SP_LOCKS$1 = qname("a", "spLocks", NS.dml);
2900
3098
  const ATTR_ID$10 = qname("", "id", "");
2901
3099
  const ATTR_NAME$7 = qname("", "name", "");
2902
3100
  const ATTR_TYPE$2 = qname("", "type", "");
2903
- const ATTR_IDX$4 = qname("", "idx", "");
3101
+ const ATTR_IDX$5 = qname("", "idx", "");
2904
3102
  const ATTR_NO_GRP$2 = qname("", "noGrp", "");
2905
3103
  /**
2906
3104
  * Builds a `<p:sld>` document containing the canonical slide-root group
@@ -2924,7 +3122,7 @@ const buildSlideFromLayout = (layoutSpTree) => {
2924
3122
  if (ph === null) continue;
2925
3123
  placeholders.push({
2926
3124
  type: getAttrValue(ph, ATTR_TYPE$2),
2927
- idx: getAttrValue(ph, ATTR_IDX$4)
3125
+ idx: getAttrValue(ph, ATTR_IDX$5)
2928
3126
  });
2929
3127
  }
2930
3128
  let nextShapeId = 2;
@@ -2966,7 +3164,7 @@ const buildGrpSpPr = () => elem(NAME_GRP_SP_PR$1);
2966
3164
  const buildPlaceholderStub = (id, phType, phIdx) => {
2967
3165
  const phAttrs = [];
2968
3166
  if (phType !== null) phAttrs.push(attr(ATTR_TYPE$2, phType));
2969
- if (phIdx !== null) phAttrs.push(attr(ATTR_IDX$4, phIdx));
3167
+ if (phIdx !== null) phAttrs.push(attr(ATTR_IDX$5, phIdx));
2970
3168
  const nvPr = elem(NAME_NV_PR$7, { children: [elem(NAME_PH$1, { attrs: phAttrs })] });
2971
3169
  const cNvSpPr = elem(NAME_C_NV_SP_PR$3, { children: [elem(NAME_SP_LOCKS$1, { attrs: [attr(ATTR_NO_GRP$2, "1")] })] });
2972
3170
  const name = inferPlaceholderName(id, phType);
@@ -3051,7 +3249,7 @@ const buildTextBox = (opts) => {
3051
3249
  elem(NAME_NV_PR$6)
3052
3250
  ] });
3053
3251
  const spPr = elem(NAME_SP_PR$4, { children: [
3054
- 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")))] })] }),
3055
3253
  elem(NAME_PRST_GEOM$3, {
3056
3254
  attrs: [attr(ATTR_PRST$3, "rect")],
3057
3255
  children: [elem(NAME_AV_LST$3)]
@@ -3127,7 +3325,7 @@ const buildShape = (opts) => {
3127
3325
  elem(NAME_C_NV_PR$4, { attrs: [attr(ATTR_ID$8, String(opts.id)), attr(ATTR_NAME$5, name)] }),
3128
3326
  elem(NAME_C_NV_SP_PR$1),
3129
3327
  elem(NAME_NV_PR$5)
3130
- ] }), 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, {
3131
3329
  attrs: [attr(ATTR_PRST$2, opts.preset)],
3132
3330
  children: [elem(NAME_AV_LST$2)]
3133
3331
  })] })];
@@ -3150,6 +3348,14 @@ const NAME_PRST_GEOM$1 = qname("a", "prstGeom", NS.dml);
3150
3348
  const NAME_AV_LST$1 = qname("a", "avLst", NS.dml);
3151
3349
  const NAME_LN = qname("a", "ln", NS.dml);
3152
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", "");
3153
3359
  const ATTR_ID$7 = qname("", "id", "");
3154
3360
  const ATTR_NAME$4 = qname("", "name", "");
3155
3361
  const ATTR_X$3 = qname("", "x", "");
@@ -3177,21 +3383,37 @@ const buildConnector = (opts) => {
3177
3383
  const xfrmAttrs = [];
3178
3384
  if (flipH) xfrmAttrs.push(attr(ATTR_FLIP_H, "1"));
3179
3385
  if (flipV) xfrmAttrs.push(attr(ATTR_FLIP_V, "1"));
3180
- const spPrChildren = [elem(NAME_A_XFRM$1, {
3386
+ const xfrm = elem(NAME_A_XFRM$1, {
3181
3387
  attrs: xfrmAttrs,
3182
- 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)))] })]
3183
- }), 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, {
3184
3391
  attrs: [attr(ATTR_PRST$1, "line")],
3185
3392
  children: [elem(NAME_AV_LST$1)]
3186
- })];
3187
- 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) {
3188
3397
  const ln = elem(NAME_LN, {
3189
- 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")))] : [],
3190
3399
  children: opts.color !== void 0 ? [elem(NAME_SOLID_FILL$3, { children: [buildColorElement(opts.color)] })] : []
3191
3400
  });
3192
3401
  spPrChildren.push(ln);
3193
3402
  }
3194
- 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 });
3195
3417
  };
3196
3418
  //#endregion
3197
3419
  //#region src/internal/presentationml/picture-builder.ts
@@ -3231,7 +3453,7 @@ const buildPicture = (opts) => {
3231
3453
  elem(NAME_NV_PR$3)
3232
3454
  ] }),
3233
3455
  elem(NAME_BLIP_FILL, { children: [elem(NAME_BLIP, { attrs: [attr(ATTR_R_EMBED, opts.rEmbed)] }), elem(NAME_STRETCH, { children: [elem(NAME_FILL_RECT)] })] }),
3234
- 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, {
3235
3457
  attrs: [attr(ATTR_PRST, "rect")],
3236
3458
  children: [elem(NAME_AV_LST)]
3237
3459
  })] })
@@ -3290,7 +3512,6 @@ const ATTR_H = qname("", "h", "");
3290
3512
  const ATTR_FIRST_ROW = qname("", "firstRow", "");
3291
3513
  const ATTR_BAND_ROW = qname("", "bandRow", "");
3292
3514
  const ATTR_LANG$1 = qname("", "lang", "");
3293
- const ATTR_XML_SPACE = qname("xml", "space", NS.xml);
3294
3515
  const buildCellRunProps = (textColorHex) => {
3295
3516
  const langAttr = attr(ATTR_LANG$1, "en-US");
3296
3517
  if (textColorHex === void 0) return elem(NAME_RPR$1, { attrs: [langAttr] });
@@ -3300,20 +3521,20 @@ const buildCellRunProps = (textColorHex) => {
3300
3521
  children: [solidFill]
3301
3522
  });
3302
3523
  };
3303
- const buildTextCellBody = (value, textColorHex) => {
3304
- const t = elem(NAME_T$2, {
3305
- attrs: value.length > 0 && (value.startsWith(" ") || value.endsWith(" ") || /[\t\n]/.test(value)) ? [attr(ATTR_XML_SPACE, "preserve")] : [],
3306
- children: value.length > 0 ? [text(value)] : []
3307
- });
3308
- const r = elem(NAME_R$1, { children: [buildCellRunProps(textColorHex), t] });
3309
- const p = elem(NAME_P$1, { children: [elem(NAME_PPR, {
3524
+ const buildCellParagraph = (line, textColorHex) => {
3525
+ const pPr = elem(NAME_PPR, {
3310
3526
  attrs: [attr(ATTR_MAR_L, "0"), attr(ATTR_INDENT, "0")],
3311
3527
  children: [elem(NAME_BU_NONE)]
3312
- }), 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));
3313
3534
  return elem(NAME_TX_BODY$5, { children: [
3314
3535
  elem(NAME_BODY_PR$1),
3315
3536
  elem(NAME_LST_STYLE$1),
3316
- p
3537
+ ...paragraphs
3317
3538
  ] });
3318
3539
  };
3319
3540
  const buildCellProps = () => elem(NAME_TC_PR, { attrs: [
@@ -3328,7 +3549,7 @@ const buildTableCell = (value, textColorHex) => {
3328
3549
  };
3329
3550
  /** @internal — used by row-mutation paths in the public API. */
3330
3551
  const buildTableRow = (cells, h, textColorHex) => elem(NAME_TR, {
3331
- attrs: [attr(ATTR_H, String(Math.round(h)))],
3552
+ attrs: [attr(ATTR_H, String(emuExtent(h, "addSlideTable: row height")))],
3332
3553
  children: cells.map((value) => buildTableCell(value, textColorHex))
3333
3554
  });
3334
3555
  const equalShares = (total, n) => {
@@ -3358,14 +3579,14 @@ const buildTable = (opts) => {
3358
3579
  elem(NAME_C_NV_GRAPHIC_FRAME_PR$1, { children: [elem(NAME_GRAPHIC_FRAME_LOCKS, { attrs: [attr(ATTR_NO_GRP$1, "1")] })] }),
3359
3580
  elem(NAME_NV_PR$2)
3360
3581
  ] });
3361
- 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)))] })] });
3362
- 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"))] });
3363
3584
  const tbl = elem(NAME_TBL, { children: [
3364
3585
  elem(NAME_TBL_PR, {
3365
3586
  attrs: [attr(ATTR_FIRST_ROW, opts.firstRow ?? true ? "1" : "0"), attr(ATTR_BAND_ROW, opts.bandRow ?? true ? "1" : "0")],
3366
3587
  children: [tableStyleId]
3367
3588
  }),
3368
- 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")))] })) }),
3369
3590
  ...rows.map((row, i) => buildTableRow(row, rowHeights[i] ?? 0, opts.textColorHex))
3370
3591
  ] });
3371
3592
  return elem(NAME_GRAPHIC_FRAME$1, { children: [
@@ -3379,7 +3600,7 @@ const buildTable = (opts) => {
3379
3600
  };
3380
3601
  //#endregion
3381
3602
  //#region src/internal/presentationml/notes-slide-builder.ts
3382
- const NAME_NOTES_SLIDE = qname("p", "notesSlide", NS.pml);
3603
+ const NAME_NOTES_SLIDE = qname("p", "notes", NS.pml);
3383
3604
  const NAME_CSLD$1 = qname("p", "cSld", NS.pml);
3384
3605
  const NAME_SP_TREE$1 = qname("p", "spTree", NS.pml);
3385
3606
  const NAME_NV_GRP_SP_PR = qname("p", "nvGrpSpPr", NS.pml);
@@ -3452,7 +3673,7 @@ const buildNotesBodyPlaceholder = (id, notes) => {
3452
3673
  ] });
3453
3674
  };
3454
3675
  /**
3455
- * 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
3456
3677
  * the body placeholder. Designed for callers that need to create the
3457
3678
  * notesSlide part from scratch (no existing notes file yet for the
3458
3679
  * slide).
@@ -3493,12 +3714,71 @@ const ATTR_ADV_TM = qname("", "advTm", "");
3493
3714
  const ATTR_DIR = qname("", "dir", "");
3494
3715
  const ATTR_ORIENT = qname("", "orient", "");
3495
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
+ ];
3496
3769
  const buildEffectElement = (opts) => {
3497
- 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);
3498
3772
  const attrs = [];
3499
- if (opts.direction !== void 0) attrs.push(attr(ATTR_DIR, opts.direction));
3500
- if (opts.orientation !== void 0) attrs.push(attr(ATTR_ORIENT, opts.orientation));
3501
- 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"));
3502
3782
  return elem(name, { attrs });
3503
3783
  };
3504
3784
  /** Returns a complete `<p:transition>` element. */
@@ -3506,10 +3786,14 @@ const buildTransition = (opts) => {
3506
3786
  const attrs = [];
3507
3787
  if (opts.speed !== void 0) attrs.push(attr(ATTR_SPD, opts.speed));
3508
3788
  if (opts.advanceOnClick === false) attrs.push(attr(ATTR_ADV_CLICK, "0"));
3509
- 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);
3510
3794
  return elem(NAME_TRANSITION, {
3511
3795
  attrs,
3512
- children: [buildEffectElement(opts)]
3796
+ children: effect === null ? [] : [effect]
3513
3797
  });
3514
3798
  };
3515
3799
  //#endregion
@@ -3639,7 +3923,7 @@ const buildOpacityAnim = (spid, durationMs, fadeIn) => {
3639
3923
  */
3640
3924
  const buildSingleEffectTiming = (spid, opts) => {
3641
3925
  const preset = PRESETS[opts.effect];
3642
- const duration = opts.durationMs ?? 500;
3926
+ const duration = opts.durationMs === void 0 ? 500 : unsignedIntMs(opts.durationMs, "setShapeAnimation: durationMs");
3643
3927
  const isFade = opts.effect === "fadeIn" || opts.effect === "fadeOut";
3644
3928
  const isEntrance = preset.presetClass === "entr";
3645
3929
  const effectChildren = [];
@@ -4701,11 +4985,11 @@ const DEFAULT_ACCENT_COLORS = [
4701
4985
  "5B9BD5",
4702
4986
  "70AD47"
4703
4987
  ];
4704
- const seriesSpPr = (color, lineWidthEmu, lineDash) => {
4988
+ const seriesSpPr = (color, lineWidthEmu$1, lineDash) => {
4705
4989
  const lnChildren = [elem(a("solidFill"), { children: [elem(a("srgbClr"), { attrs: [attr(qname("", "val", ""), color)] })] })];
4706
4990
  if (lineDash !== void 0) lnChildren.push(elem(a("prstDash"), { attrs: [attr(qname("", "val", ""), lineDash)] }));
4707
- const ln = lineWidthEmu !== void 0 ? elem(a("ln"), {
4708
- 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")))],
4709
4993
  children: lnChildren
4710
4994
  }) : elem(a("ln"), { children: lnChildren });
4711
4995
  return elem(c("spPr"), { children: [elem(a("solidFill"), { children: [elem(a("srgbClr"), { attrs: [attr(qname("", "val", ""), color)] })] }), ln] });
@@ -4769,17 +5053,18 @@ const seriesElement = (spec, seriesIdx, sheet) => {
4769
5053
  ];
4770
5054
  if (spec.kind === "line" || series.lineWidthEmu !== void 0 || series.lineDash !== void 0) children.push(seriesSpPr(color, series.lineWidthEmu, series.lineDash));
4771
5055
  else children.push(solidFillSpPr(color));
4772
- if (series.invertIfNegative === true) children.push(valNode(c("invertIfNegative"), "1"));
4773
- const mk = markerElement(series.markerSymbol, series.markerSizePt);
4774
- 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
+ }
4775
5061
  for (const dPt of dPtElements(series.pointColors, series.pointExplosions)) children.push(dPt);
4776
5062
  const serDLbls = buildDLblsFromLabels(series.dataLabels);
4777
5063
  if (serDLbls !== null) children.push(serDLbls);
4778
- 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));
4779
5065
  children.push(elem(c("cat"), { children: [strRef(catRange, spec.categories)] }));
4780
5066
  children.push(elem(c("val"), { children: [numRef(valRange, paddedValues)] }));
4781
5067
  if (spec.kind === "line") children.push(valNode(c("smooth"), series.smooth === true ? "1" : "0"));
4782
- else if (series.smooth === true) children.push(valNode(c("smooth"), "1"));
4783
5068
  return elem(c("ser"), { children });
4784
5069
  };
4785
5070
  const CAT_AX_ID = 111111111;
@@ -4832,8 +5117,8 @@ const valAxis = (spec) => {
4832
5117
  const scalingChildren = [];
4833
5118
  if (spec.valueAxis?.logBase !== void 0) scalingChildren.push(valNode(c("logBase"), spec.valueAxis.logBase));
4834
5119
  scalingChildren.push(valNode(c("orientation"), spec.valueAxisOrientation ?? "minMax"));
4835
- if (spec.valueAxis?.min !== void 0) scalingChildren.push(valNode(c("min"), spec.valueAxis.min));
4836
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));
4837
5122
  const children = [
4838
5123
  valNode(c("axId"), VAL_AX_ID),
4839
5124
  elem(c("scaling"), { children: scalingChildren }),
@@ -4884,9 +5169,9 @@ const buildBarChart = (spec, sheet, direction) => {
4884
5169
  ...ser,
4885
5170
  ...dl ? [dl] : []
4886
5171
  ];
4887
- 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")));
4888
5173
  const overlapPct = spec.overlapPct ?? (grouping === "stacked" || grouping === "percentStacked" ? 100 : void 0);
4889
- if (overlapPct !== void 0) children.push(valNode(c("overlap"), overlapPct));
5174
+ if (overlapPct !== void 0) children.push(valNode(c("overlap"), overlapPercent(overlapPct, "chart: overlapPct")));
4890
5175
  children.push(valNode(c("axId"), CAT_AX_ID), valNode(c("axId"), VAL_AX_ID));
4891
5176
  return elem(c(direction === "col" ? "barChart" : "barChart"), { children });
4892
5177
  };
@@ -4913,7 +5198,7 @@ const buildPieChart = (spec, sheet) => {
4913
5198
  ser,
4914
5199
  ...dl ? [dl] : []
4915
5200
  ];
4916
- 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")));
4917
5202
  return elem(c("pieChart"), { children });
4918
5203
  };
4919
5204
  const buildDoughnutChart = (spec, sheet) => {
@@ -4925,8 +5210,8 @@ const buildDoughnutChart = (spec, sheet) => {
4925
5210
  ser,
4926
5211
  ...dl ? [dl] : []
4927
5212
  ];
4928
- if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), Math.round(spec.firstSliceAngleDeg)));
4929
- 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")));
4930
5215
  return elem(c("doughnutChart"), { children });
4931
5216
  };
4932
5217
  const buildAreaChart = (spec, sheet) => {
@@ -7252,7 +7537,7 @@ const buildChartGraphicFrame = (opts) => {
7252
7537
  elem(NAME_C_NV_GRAPHIC_FRAME_PR),
7253
7538
  elem(NAME_NV_PR)
7254
7539
  ] });
7255
- 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")))] })] });
7256
7541
  const chartRef = elem(NAME_C_CHART, {
7257
7542
  prefixDecls: new Map([["c", NS.chart], ["r", NS.officeDocRels]]),
7258
7543
  attrs: [attr(qname("r", "id", NS.officeDocRels), opts.rEmbed)]
@@ -7549,7 +7834,7 @@ const findChartsWithTrendlines = (slide) => {
7549
7834
  */
7550
7835
  const findChartsWithDataLabels = (slide) => {
7551
7836
  const out = [];
7552
- 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);
7553
7838
  for (const chart of getSlideCharts(slide)) {
7554
7839
  if (chart.spec === null) continue;
7555
7840
  if (hasLabel(chart.spec.dataLabels)) {
@@ -8699,7 +8984,10 @@ const setTableStyleId = (table, styleId) => {
8699
8984
  if (!tbl) throw new Error("setTableStyleId: shape is not a table graphic frame");
8700
8985
  const tblPr = ensureTblPr(tbl);
8701
8986
  tblPr.children = tblPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "tableStyleId"));
8702
- 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
+ }
8703
8991
  commitSlideData(table[SHAPE_SLIDE]);
8704
8992
  refreshSlideData(table[SHAPE_SLIDE]);
8705
8993
  };
@@ -8862,7 +9150,7 @@ const setTableColumnWidth = (table, col, width) => {
8862
9150
  const target = cols[col];
8863
9151
  if (!target) throw new RangeError(`table column ${col} out of range (have ${cols.length})`);
8864
9152
  target.attrs = target.attrs.filter((a) => !(a.name.namespaceURI === "" && a.name.localName === "w"));
8865
- target.attrs.push(attr(ATTR_W_TBL, String(Math.round(width))));
9153
+ target.attrs.push(attr(ATTR_W_TBL, String(emuExtent(width, "setTableColumnWidth: width"))));
8866
9154
  commitSlideData(table[SHAPE_SLIDE]);
8867
9155
  refreshSlideData(table[SHAPE_SLIDE]);
8868
9156
  };
@@ -8876,7 +9164,7 @@ const setTableRowHeight = (table, row, height) => {
8876
9164
  const target = rows[row];
8877
9165
  if (!target) throw new RangeError(`table row ${row} out of range (have ${rows.length})`);
8878
9166
  target.attrs = target.attrs.filter((a) => !(a.name.namespaceURI === "" && a.name.localName === "h"));
8879
- target.attrs.push(attr(ATTR_H_TBL, String(Math.round(height))));
9167
+ target.attrs.push(attr(ATTR_H_TBL, String(emuExtent(height, "setTableRowHeight: height"))));
8880
9168
  commitSlideData(table[SHAPE_SLIDE]);
8881
9169
  refreshSlideData(table[SHAPE_SLIDE]);
8882
9170
  };
@@ -9075,18 +9363,39 @@ const BORDER_SIDE_LOCALS = {
9075
9363
  tlToBr: "lnTlToBr",
9076
9364
  blToTr: "lnBlToTr"
9077
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;
9078
9384
  const writeBorderLn = (tcPr, local, border) => {
9079
9385
  tcPr.children = tcPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === local));
9080
9386
  if (border === null) return;
9081
9387
  const lnAttrs = [];
9082
- 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
+ }
9083
9392
  const children = [];
9084
9393
  if (border.color !== null && border.color !== void 0) children.push(elem(qname("a", "solidFill", NS.dml), { children: [buildColorElement(border.color)] }));
9085
9394
  if (border.dash !== null && border.dash !== void 0) children.push(elem(qname("a", "prstDash", NS.dml), { attrs: [attr(qname("", "val", ""), border.dash)] }));
9086
- tcPr.children.push(elem(qname("a", local, NS.dml), {
9395
+ insertChildByRank(tcPr, elem(qname("a", local, NS.dml), {
9087
9396
  attrs: lnAttrs,
9088
9397
  children
9089
- }));
9398
+ }), tcPrChildRank);
9090
9399
  };
9091
9400
  /**
9092
9401
  * Sets one or more side borders on a cell. Sides listed with `null` are
@@ -9215,7 +9524,10 @@ const setTableCellMargins = (cell, margins) => {
9215
9524
  ["marT", margins.top],
9216
9525
  ["marB", margins.bottom]
9217
9526
  ];
9218
- 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
+ }
9219
9531
  }
9220
9532
  commitTableCell(cell);
9221
9533
  };
@@ -9728,7 +10040,8 @@ const listPackageParts = (pres) => pres[INTERNAL_PACKAGE].parts.map((p) => ({
9728
10040
  * (e.g. parsing custom extension parts).
9729
10041
  */
9730
10042
  const readPackagePart = (pres, name) => {
9731
- 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;
9732
10045
  };
9733
10046
  /**
9734
10047
  * Returns the total size of the package's parts in bytes
@@ -9785,13 +10098,13 @@ const getOrphanMediaPartNames = (pres) => {
9785
10098
  if (!sourceRels) continue;
9786
10099
  for (const rel of sourceRels.items) {
9787
10100
  if (rel.targetMode === "External") continue;
9788
- referenced.add(resolve(sourceName, rel.target));
10101
+ referenced.add(resolve(sourceName, rel.target).toLowerCase());
9789
10102
  }
9790
10103
  }
9791
10104
  const out = [];
9792
10105
  for (const part of pkg.parts) {
9793
10106
  if (!part.name.startsWith("/ppt/media/")) continue;
9794
- if (!referenced.has(part.name)) out.push(part.name);
10107
+ if (!referenced.has(part.name.toLowerCase())) out.push(part.name);
9795
10108
  }
9796
10109
  return out;
9797
10110
  };
@@ -9878,14 +10191,14 @@ const compactPackage = (pres) => {
9878
10191
  if (!rels) continue;
9879
10192
  for (const rel of rels.items) {
9880
10193
  if (rel.targetMode === "External") continue;
9881
- referenced.add(resolve(sourceName, rel.target));
10194
+ referenced.add(resolve(sourceName, rel.target).toLowerCase());
9882
10195
  }
9883
10196
  }
9884
10197
  const removed = [];
9885
10198
  const orphans = [];
9886
10199
  for (const part of pkg.parts) {
9887
10200
  if (!part.name.startsWith("/ppt/media/")) continue;
9888
- if (!referenced.has(part.name)) orphans.push(part.name);
10201
+ if (!referenced.has(part.name.toLowerCase())) orphans.push(part.name);
9889
10202
  }
9890
10203
  for (const name of orphans) {
9891
10204
  pkg.removePart(partName(name));
@@ -9904,7 +10217,8 @@ const compactPackage = (pres) => {
9904
10217
  * already point at this part name.
9905
10218
  */
9906
10219
  const setMediaPartBytes = (pres, partName, bytes) => {
9907
- 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);
9908
10222
  if (!part) return false;
9909
10223
  part.data = bytes;
9910
10224
  return true;
@@ -10991,93 +11305,84 @@ const getShapeImageCrop = (shape) => {
10991
11305
  bottom: parseSide("b")
10992
11306
  };
10993
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
+ };
10994
11342
  /**
10995
- * Adjusts the picture's brightness by writing `<a:lumOff val="…"/>`
10996
- * 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:
10997
11345
  *
10998
11346
  * - `1` → +100% brightness
10999
- * - `0` or `null` → no offset (any prior `<a:lumOff>` is removed)
11347
+ * - `0` or `null` → no brightness change (the `bright` attribute is removed)
11000
11348
  * - `-1` → -100% brightness
11001
11349
  *
11002
- * Throws for non-picture shapes and on values outside [-1, 1].
11003
- *
11004
- * Note: PowerPoint's "Picture Format › Corrections" UI couples this
11005
- * with `<a:lumMod>` for some presets; this primitive sets only
11006
- * `lumOff` to keep the surface honest. Read it back via
11007
- * `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].
11008
11352
  */
11009
11353
  const setShapeImageBrightness = (shape, value) => {
11010
- if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`setShapeImageBrightness only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11011
- const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11012
- if (!blipFill) throw new Error("picture has no <p:blipFill>");
11013
- const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11014
- if (!blip) throw new Error("picture <p:blipFill> has no <a:blip>");
11015
- blip.children = blip.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "lumOff"));
11016
- if (value !== null && value !== 0) {
11017
- if (!Number.isFinite(value) || value < -1 || value > 1) throw new RangeError(`brightness must be in [-1, 1], got ${value}`);
11018
- blip.children.push(elem(qname("a", "lumOff", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(value * 1e5)))] }));
11019
- }
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);
11020
11357
  commitAndRefresh(shape);
11021
11358
  };
11022
11359
  /**
11023
- * Adjusts the picture's contrast by writing `<a:lumMod val="…"/>` on
11024
- * `<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`):
11025
11362
  *
11026
- * - `1` or `null` → no modulation (any prior `<a:lumMod>` is removed)
11027
- * - `0.5` → 50% of original luminance variance (washed out)
11028
- * - `1.5` 150% (boosted contrast; PowerPoint clamps to
11029
- * 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)
11030
11366
  *
11031
- * Throws on non-picture shapes and on values outside `[0, 2]`. The
11032
- * 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].
11033
11369
  */
11034
11370
  const setShapeImageContrast = (shape, value) => {
11035
- if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`setShapeImageContrast only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11036
- const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11037
- if (!blipFill) throw new Error("picture has no <p:blipFill>");
11038
- const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11039
- if (!blip) throw new Error("picture <p:blipFill> has no <a:blip>");
11040
- blip.children = blip.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "lumMod"));
11041
- if (value !== null && value !== 1) {
11042
- if (!Number.isFinite(value) || value < 0 || value > 2) throw new RangeError(`contrast must be in [0, 2], got ${value}`);
11043
- blip.children.push(elem(qname("a", "lumMod", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(value * 1e5)))] }));
11044
- }
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);
11045
11374
  commitAndRefresh(shape);
11046
11375
  };
11047
11376
  /**
11048
- * Reads the picture's contrast modulation (the `<a:lumMod>` fraction
11049
- * 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.
11050
11379
  */
11051
- const getShapeImageContrast = (shape) => {
11052
- if (shape[SHAPE_SNAPSHOT].kind !== "picture") return null;
11053
- const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11054
- if (!blipFill) return null;
11055
- const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11056
- if (!blip) return null;
11057
- const lumMod = firstChildElement(blip, qname("a", "lumMod", NS.dml));
11058
- if (!lumMod) return null;
11059
- const v = getAttrValue(lumMod, qname("", "val", ""));
11060
- if (v === null) return null;
11061
- const n = Number.parseInt(v, 10);
11062
- return Number.isFinite(n) ? n / 1e5 : null;
11063
- };
11380
+ const getShapeImageContrast = (shape) => getLumAttr(shape, "contrast");
11064
11381
  /**
11065
- * Reads the picture's brightness offset (the `<a:lumOff>` fraction
11066
- * 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.
11067
11384
  */
11068
- const getShapeImageBrightness = (shape) => {
11069
- if (shape[SHAPE_SNAPSHOT].kind !== "picture") return null;
11070
- const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11071
- if (!blipFill) return null;
11072
- const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11073
- if (!blip) return null;
11074
- const lumOff = firstChildElement(blip, qname("a", "lumOff", NS.dml));
11075
- if (!lumOff) return null;
11076
- const v = getAttrValue(lumOff, qname("", "val", ""));
11077
- if (v === null) return null;
11078
- const n = Number.parseInt(v, 10);
11079
- return Number.isFinite(n) ? n / 1e5 : null;
11080
- };
11385
+ const getShapeImageBrightness = (shape) => getLumAttr(shape, "bright");
11081
11386
  const setShapeImageOpacity = (shape, opacity) => {
11082
11387
  if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`setShapeImageOpacity only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11083
11388
  const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
@@ -11140,17 +11445,99 @@ const setShapeImageCrop = (shape, crop) => {
11140
11445
  //#endregion
11141
11446
  //#region src/api/fn/shape-animation.ts
11142
11447
  NS.pml;
11448
+ const ATTR_ID_FN = qname("", "id", "");
11143
11449
  const removeExistingTiming = (slide) => {
11144
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"));
11145
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;
11146
11453
  const insertTimingAtEnd = (slide, timing) => {
11147
11454
  slide[SLIDE_DOCUMENT].root.children.push(timing);
11148
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
+ };
11149
11533
  /**
11150
11534
  * Sets a single click-triggered animation effect on the given shape.
11151
- * Replaces any existing `<p:timing>` block on the slide — v1 supports
11152
- * exactly one effect per slide. Calling this on a second shape replaces
11153
- * 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`.
11154
11541
  *
11155
11542
  * Supported `effect` tokens:
11156
11543
  *
@@ -11164,9 +11551,11 @@ const insertTimingAtEnd = (slide, timing) => {
11164
11551
  */
11165
11552
  const setShapeAnimation = (shape, opts) => {
11166
11553
  const slide = shape[SHAPE_SLIDE];
11167
- removeExistingTiming(slide);
11168
11554
  const spid = shape[SHAPE_SNAPSHOT].id;
11169
- 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.");
11170
11559
  commitSlideData(slide);
11171
11560
  refreshSlideData(slide);
11172
11561
  };
@@ -11622,6 +12011,25 @@ const getParagraphLevel = (shape, paragraphIndex) => {
11622
12011
  const n = Number.parseInt(v, 10);
11623
12012
  return Number.isFinite(n) ? n : 0;
11624
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;
11625
12033
  /**
11626
12034
  * Sets the spacing before and/or after a paragraph, in points (where
11627
12035
  * a "point" is 1/72 inch). PowerPoint stores these as hundredths of a
@@ -11640,8 +12048,7 @@ const setParagraphSpacing = (shape, paragraphIndex, opts) => {
11640
12048
  pPr.children = pPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === localName));
11641
12049
  if (value === null) return;
11642
12050
  if (!Number.isFinite(value) || value < 0) throw new RangeError(`paragraph ${localName} must be a non-negative number, got ${value}`);
11643
- const spcEl = elem(qname("a", localName, NS.dml), { children: [elem(qname("a", "spcPts", NS.dml), { attrs: [attr(qname("", "val", ""), String(Math.round(value * 100)))] })] });
11644
- 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);
11645
12052
  };
11646
12053
  writeSide("spcBef", opts.beforePts);
11647
12054
  writeSide("spcAft", opts.afterPts);
@@ -11748,6 +12155,27 @@ const getParagraphLineSpacing = (shape, paragraphIndex) => {
11748
12155
  return null;
11749
12156
  };
11750
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
+ /**
11751
12179
  * Reads back the bullet style on a single paragraph, or `null` when
11752
12180
  * no `<a:buChar>` / `<a:buAutoNum>` / `<a:buNone>` is present (the
11753
12181
  * paragraph inherits its bullet from the layout / master).
@@ -11987,6 +12415,8 @@ const hslToRgb = (h, s, l) => {
11987
12415
  hueToRgb(p, q, h - 1 / 3)
11988
12416
  ];
11989
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;
11990
12420
  const applyColorTransforms = (hex, transforms) => {
11991
12421
  if (transforms.length === 0) return hex;
11992
12422
  let [r, g, b] = hexToRgb01(hex);
@@ -12005,14 +12435,14 @@ const applyColorTransforms = (hex, transforms) => {
12005
12435
  break;
12006
12436
  }
12007
12437
  case "shade":
12008
- r *= t.val;
12009
- g *= t.val;
12010
- b *= t.val;
12438
+ r = linearToSrgb(srgbToLinear(r) * t.val);
12439
+ g = linearToSrgb(srgbToLinear(g) * t.val);
12440
+ b = linearToSrgb(srgbToLinear(b) * t.val);
12011
12441
  break;
12012
12442
  case "tint":
12013
- r = r * t.val + (1 - t.val);
12014
- g = g * t.val + (1 - t.val);
12015
- 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));
12016
12446
  break;
12017
12447
  case "lumMod":
12018
12448
  case "lumOff": {
@@ -14341,8 +14771,8 @@ const getShapeTextColumns = (shape) => {
14341
14771
  * Sets the multi-column layout on the shape's text body — writes
14342
14772
  * `<a:bodyPr numCol="N" [spcCol="EMU"]/>`. Pass `null` to clear both
14343
14773
  * attributes so the text body falls back to PowerPoint's default
14344
- * single column. `count` must be `>= 2` (PowerPoint clamps higher
14345
- * 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,
14346
14776
  * removes any prior `spcCol`. Throws for non-text-bearing shape kinds.
14347
14777
  */
14348
14778
  const setShapeTextColumns = (shape, columns) => {
@@ -14350,8 +14780,12 @@ const setShapeTextColumns = (shape, columns) => {
14350
14780
  bodyPr.attrs = bodyPr.attrs.filter((a) => !(a.name.namespaceURI === "" && (a.name.localName === "numCol" || a.name.localName === "spcCol")));
14351
14781
  if (columns !== null) {
14352
14782
  if (columns.count < 2) throw new Error(`setShapeTextColumns: count must be >= 2 (single column is the default — pass null instead). Got ${columns.count}.`);
14353
- bodyPr.attrs.push(attr(qname("", "numCol", ""), String(columns.count)));
14354
- 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
+ }
14355
14789
  }
14356
14790
  commitAndRefresh(shape);
14357
14791
  };
@@ -14388,7 +14822,10 @@ const getShapeTextBodyRotationDeg = (shape) => {
14388
14822
  const setShapeTextBodyRotationDeg = (shape, rotationDeg) => {
14389
14823
  const bodyPr = requireBodyPr(shape);
14390
14824
  bodyPr.attrs = bodyPr.attrs.filter((a) => !(a.name.namespaceURI === "" && a.name.localName === "rot"));
14391
- 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
+ }
14392
14829
  commitAndRefresh(shape);
14393
14830
  };
14394
14831
  /**
@@ -14586,7 +15023,10 @@ const setShapeTextMargins = (shape, margins) => {
14586
15023
  });
14587
15024
  const localsToClear = new Set(writes.map((w) => w.name));
14588
15025
  bodyPr.attrs = bodyPr.attrs.filter((a) => !(a.name.namespaceURI === "" && localsToClear.has(a.name.localName)));
14589
- 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
+ }
14590
15030
  commitAndRefresh(shape);
14591
15031
  };
14592
15032
  /** Sets the bullet style on every paragraph in the shape's text body. */
@@ -15931,6 +16371,22 @@ const duplicateSlideAt = (pres, atIndex, slide) => {
15931
16371
  const slides = getSlides(pres);
15932
16372
  return slides[Math.max(0, Math.min(atIndex, slides.length - 1))];
15933
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
+ };
15934
16390
  /**
15935
16391
  * Imports a slide from another presentation into `targetPres`. The
15936
16392
  * slide's part bytes are copied verbatim; image rels are followed and
@@ -15966,8 +16422,9 @@ const importSlide = (targetPres, sourceSlide, targetLayout) => {
15966
16422
  const newRels = emptyRels();
15967
16423
  const layoutPartName = targetLayout[LAYOUT_PART_NAME];
15968
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) ?? []);
15969
16426
  newRels.items.push({
15970
- id: "rId1",
16427
+ id: layoutRelId,
15971
16428
  type: REL_TYPES.slideLayout,
15972
16429
  target: `../slideLayouts/${basename(layoutPartName)}`,
15973
16430
  targetMode: "Internal"
@@ -16007,6 +16464,22 @@ const importSlide = (targetPres, sourceSlide, targetLayout) => {
16007
16464
  }
16008
16465
  }
16009
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
+ }
16010
16483
  const presRels = targetPkg.getRels(PRES_PART_NAME) ?? emptyRels();
16011
16484
  const newRId = nextRelId(presRels.items.map((r) => r.id));
16012
16485
  presRels.items.push({
@@ -16049,8 +16522,8 @@ const mergePresentations = (targetPres, sourcePres, targetLayout) => {
16049
16522
  };
16050
16523
  //#endregion
16051
16524
  //#region src/api/index.ts
16052
- const VERSION = "0.8.0";
16525
+ const VERSION = "0.9.0";
16053
16526
  //#endregion
16054
- 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 };
16055
16528
 
16056
- //# sourceMappingURL=api-284n4GCu.js.map
16529
+ //# sourceMappingURL=api-Irqm9KrN.js.map