pptx-kit 0.8.0 → 0.10.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;";
@@ -787,7 +824,7 @@ const emptyContentTypes = () => ({
787
824
  const REL_NS = NS.relationships;
788
825
  const NAME_RELATIONSHIPS = qname("", "Relationships", REL_NS);
789
826
  const NAME_RELATIONSHIP = qname("", "Relationship", REL_NS);
790
- const ATTR_ID$13 = qname("", "Id", "");
827
+ const ATTR_ID$14 = qname("", "Id", "");
791
828
  const ATTR_TYPE$7 = qname("", "Type", "");
792
829
  const ATTR_TARGET = qname("", "Target", "");
793
830
  const ATTR_TARGET_MODE = qname("", "TargetMode", "");
@@ -825,7 +862,7 @@ const serializeRels = (rels) => {
825
862
  const children = rels.items.map((r) => {
826
863
  const attrs = [
827
864
  {
828
- name: ATTR_ID$13,
865
+ name: ATTR_ID$14,
829
866
  value: r.id
830
867
  },
831
868
  {
@@ -1393,10 +1430,10 @@ const NAME_NOTES_MASTER_ID_LST = qname("p", "notesMasterIdLst", NS.pml);
1393
1430
  const NAME_NOTES_MASTER_ID = qname("p", "notesMasterId", NS.pml);
1394
1431
  const NAME_SLD_SZ = qname("p", "sldSz", NS.pml);
1395
1432
  const NAME_NOTES_SZ = qname("p", "notesSz", NS.pml);
1396
- const ATTR_ID$12 = qname("", "id", "");
1433
+ const ATTR_ID$13 = qname("", "id", "");
1397
1434
  const ATTR_R_ID$3 = qname("r", "id", NS.officeDocRels);
1398
- const ATTR_CX$8 = qname("", "cx", "");
1399
- const ATTR_CY$8 = qname("", "cy", "");
1435
+ const ATTR_CX$9 = qname("", "cx", "");
1436
+ const ATTR_CY$9 = qname("", "cy", "");
1400
1437
  const ATTR_TYPE$6 = qname("", "type", "");
1401
1438
  const requireRId = (element, context) => {
1402
1439
  const value = getAttrValue(element, ATTR_R_ID$3);
@@ -1406,8 +1443,8 @@ const requireRId = (element, context) => {
1406
1443
  const readSize$1 = (parent, name) => {
1407
1444
  const el = firstChildElement(parent, name);
1408
1445
  if (el === null) return null;
1409
- const cxRaw = getAttrValue(el, ATTR_CX$8);
1410
- const cyRaw = getAttrValue(el, ATTR_CY$8);
1446
+ const cxRaw = getAttrValue(el, ATTR_CX$9);
1447
+ const cyRaw = getAttrValue(el, ATTR_CY$9);
1411
1448
  if (cxRaw === null || cyRaw === null) throw new Error(`<${name.localName}>: missing cx/cy attribute`);
1412
1449
  const type = getAttrValue(el, ATTR_TYPE$6);
1413
1450
  return {
@@ -1425,7 +1462,7 @@ const readPresentationPart = (root) => {
1425
1462
  const sldMasters = [];
1426
1463
  const sldMasterLst = firstChildElement(root, NAME_SLD_MASTER_ID_LST$1);
1427
1464
  if (sldMasterLst !== null) for (const item of allChildElements(sldMasterLst, NAME_SLD_MASTER_ID)) {
1428
- const idRaw = getAttrValue(item, ATTR_ID$12);
1465
+ const idRaw = getAttrValue(item, ATTR_ID$13);
1429
1466
  if (idRaw === null) throw new Error("<p:sldMasterId>: missing id attribute");
1430
1467
  sldMasters.push({
1431
1468
  id: Number.parseInt(idRaw, 10),
@@ -1435,7 +1472,7 @@ const readPresentationPart = (root) => {
1435
1472
  const slides = [];
1436
1473
  const sldLst = firstChildElement(root, NAME_SLD_ID_LST$2);
1437
1474
  if (sldLst !== null) for (const item of allChildElements(sldLst, NAME_SLD_ID$2)) {
1438
- const idRaw = getAttrValue(item, ATTR_ID$12);
1475
+ const idRaw = getAttrValue(item, ATTR_ID$13);
1439
1476
  if (idRaw === null) throw new Error("<p:sldId>: missing id attribute");
1440
1477
  slides.push({
1441
1478
  id: Number.parseInt(idRaw, 10),
@@ -1505,7 +1542,7 @@ const NAME_BU_FONT = qname("a", "buFont", NS.dml);
1505
1542
  const ATTR_CHAR = qname("", "char", "");
1506
1543
  const ATTR_BU_TYPE = qname("", "type", "");
1507
1544
  const ATTR_START_AT = qname("", "startAt", "");
1508
- const ATTR_TYPEFACE$2 = qname("", "typeface", "");
1545
+ const ATTR_TYPEFACE$3 = qname("", "typeface", "");
1509
1546
  const NAME_P$5 = qname("a", "p", NS.dml);
1510
1547
  const NAME_R$4 = qname("a", "r", NS.dml);
1511
1548
  const NAME_T$5 = qname("a", "t", NS.dml);
@@ -1736,7 +1773,7 @@ const applyBulletToParagraph = (paragraph, style) => {
1736
1773
  if (!hasAttr(pPr, "marL")) pPr.attrs.push(attr(ATTR_MAR_L$1, String(marL)));
1737
1774
  if (!hasAttr(pPr, "indent")) pPr.attrs.push(attr(ATTR_INDENT$1, String(indent)));
1738
1775
  }
1739
- if (normalizeBulletStyle(style).kind === "autoNum") pPr.children.push(elem(NAME_BU_FONT, { attrs: [attr(ATTR_TYPEFACE$2, "+mj-lt")] }));
1776
+ if (normalizeBulletStyle(style).kind === "autoNum") pPr.children.push(elem(NAME_BU_FONT, { attrs: [attr(ATTR_TYPEFACE$3, "+mj-lt")] }));
1740
1777
  pPr.children.push(buildBulletElement(style));
1741
1778
  };
1742
1779
  /**
@@ -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$9 = 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$9, parsed.hex)] }) : elem(NAME_SCHEME_CLR$2, { attrs: [attr(ATTR_VAL$9, 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
+ const NAME_EA = qname("a", "ea", 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$2 = qname("", "typeface", "");
1974
+ const ATTR_VAL$8 = 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,32 @@ 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$8, parsed.hex)] }) : elem(NAME_SCHEME_CLR$1, { attrs: [attr(ATTR_VAL$8, 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$2, font)] }), rprChildRank);
2017
+ };
2018
+ const setEastAsian = (rPr, font) => {
2019
+ rPr.children = rPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "ea"));
2020
+ if (font === null) return;
2021
+ insertChildByRank(rPr, elem(NAME_EA, { attrs: [attr(ATTR_TYPEFACE$2, font)] }), rprChildRank);
1848
2022
  };
1849
2023
  const setHighlight = (rPr, value) => {
1850
2024
  rPr.children = rPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "highlight"));
1851
2025
  if (value === null) return;
1852
- const parsed = parseColor$1(value);
2026
+ const parsed = parseColor(value);
1853
2027
  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] }));
2028
+ insertChildByRank(rPr, elem(NAME_HIGHLIGHT, { children: [parsed.kind === "srgb" ? elem(NAME_SRGB_CLR$3, { attrs: [attr(ATTR_VAL$8, parsed.hex)] }) : elem(NAME_SCHEME_CLR$1, { attrs: [attr(ATTR_VAL$8, parsed.token)] })] }), rprChildRank);
1856
2029
  };
1857
2030
  /** Mutates `rPr` in place per `format`. */
1858
2031
  const applyRunFormat = (rPr, format) => {
1859
2032
  let attrs = rPr.attrs;
1860
2033
  if (format.size !== void 0) {
1861
- const sz = Math.round(format.size * 100);
2034
+ const sz = fontSizeHundredthPt(format.size * 100, "setShapeRunFormat: size");
1862
2035
  attrs = setOrRemoveAttr(attrs, ATTR_SZ, String(sz));
1863
2036
  }
1864
2037
  if (format.bold !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_B, format.bold ? "1" : "0");
@@ -1871,7 +2044,10 @@ const applyRunFormat = (rPr, format) => {
1871
2044
  const value = format.strike === false ? "noStrike" : format.strike === true ? "sngStrike" : format.strike;
1872
2045
  attrs = setOrRemoveAttr(attrs, ATTR_STRIKE, value);
1873
2046
  }
1874
- if (format.spc !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_SPC, String(Math.round(format.spc)));
2047
+ if (format.spc !== void 0) {
2048
+ const spc = textPointSpacing(format.spc, "setShapeRunFormat: spc");
2049
+ attrs = setOrRemoveAttr(attrs, ATTR_SPC, String(spc));
2050
+ }
1875
2051
  if (format.kern !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_KERN, String(Math.round(format.kern)));
1876
2052
  if (format.baseline !== void 0) {
1877
2053
  const pct = Math.round(format.baseline * 1e5);
@@ -1880,6 +2056,7 @@ const applyRunFormat = (rPr, format) => {
1880
2056
  if (format.cap !== void 0) attrs = setOrRemoveAttr(attrs, ATTR_CAP, format.cap);
1881
2057
  rPr.attrs = attrs;
1882
2058
  if (format.font !== void 0) setLatin(rPr, format.font);
2059
+ if (format.fontEastAsian !== void 0) setEastAsian(rPr, format.fontEastAsian);
1883
2060
  if (format.color !== void 0) setSolidFill$1(rPr, format.color);
1884
2061
  if (format.highlight !== void 0) setHighlight(rPr, format.highlight);
1885
2062
  };
@@ -1903,66 +2080,6 @@ const applyFormatToAllRuns = (txBody, format) => {
1903
2080
  }
1904
2081
  };
1905
2082
  //#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
2083
  //#region src/internal/drawingml/fill.ts
1967
2084
  const NAME_SOLID_FILL$5 = qname("a", "solidFill", NS.dml);
1968
2085
  const NAME_NO_FILL$2 = qname("a", "noFill", NS.dml);
@@ -1970,6 +2087,9 @@ const NAME_GRAD_FILL = qname("a", "gradFill", NS.dml);
1970
2087
  const NAME_GS_LST = qname("a", "gsLst", NS.dml);
1971
2088
  const NAME_GS = qname("a", "gs", NS.dml);
1972
2089
  const NAME_LIN = qname("a", "lin", NS.dml);
2090
+ const NAME_PATH = qname("a", "path", NS.dml);
2091
+ const NAME_FILL_TO_RECT = qname("a", "fillToRect", NS.dml);
2092
+ const ATTR_PATH = qname("", "path", "");
1973
2093
  const ATTR_POS = qname("", "pos", "");
1974
2094
  const ATTR_ANG = qname("", "ang", "");
1975
2095
  const ATTR_SCALED = qname("", "scaled", "");
@@ -2024,6 +2144,63 @@ const setNoFill = (host) => {
2024
2144
  const clearFill = (host) => {
2025
2145
  removeAnyFill(host);
2026
2146
  };
2147
+ /** Every `ST_PresetPatternVal` token (ECMA-376 dml-main.xsd). */
2148
+ const PATTERN_PRESETS = [
2149
+ "pct5",
2150
+ "pct10",
2151
+ "pct20",
2152
+ "pct25",
2153
+ "pct30",
2154
+ "pct40",
2155
+ "pct50",
2156
+ "pct60",
2157
+ "pct70",
2158
+ "pct75",
2159
+ "pct80",
2160
+ "pct90",
2161
+ "horz",
2162
+ "vert",
2163
+ "ltHorz",
2164
+ "ltVert",
2165
+ "dkHorz",
2166
+ "dkVert",
2167
+ "narHorz",
2168
+ "narVert",
2169
+ "dashHorz",
2170
+ "dashVert",
2171
+ "cross",
2172
+ "dnDiag",
2173
+ "upDiag",
2174
+ "ltDnDiag",
2175
+ "ltUpDiag",
2176
+ "dkDnDiag",
2177
+ "dkUpDiag",
2178
+ "wdDnDiag",
2179
+ "wdUpDiag",
2180
+ "dashDnDiag",
2181
+ "dashUpDiag",
2182
+ "diagCross",
2183
+ "smCheck",
2184
+ "lgCheck",
2185
+ "smGrid",
2186
+ "lgGrid",
2187
+ "dotGrid",
2188
+ "smConfetti",
2189
+ "lgConfetti",
2190
+ "horzBrick",
2191
+ "diagBrick",
2192
+ "solidDmnd",
2193
+ "openDmnd",
2194
+ "dotDmnd",
2195
+ "plaid",
2196
+ "sphere",
2197
+ "weave",
2198
+ "divot",
2199
+ "shingle",
2200
+ "wave",
2201
+ "trellis",
2202
+ "zigZag"
2203
+ ];
2027
2204
  const NAME_PATT_FILL = qname("a", "pattFill", NS.dml);
2028
2205
  const NAME_FG_CLR = qname("a", "fgClr", NS.dml);
2029
2206
  const NAME_BG_CLR = qname("a", "bgClr", NS.dml);
@@ -2035,7 +2212,7 @@ const ATTR_PRST$4 = qname("", "prst", "");
2035
2212
  const setPatternFill = (host, options) => {
2036
2213
  removeAnyFill(host);
2037
2214
  const pattFill = elem(NAME_PATT_FILL, {
2038
- attrs: [attr(ATTR_PRST$4, options.preset)],
2215
+ attrs: [attr(ATTR_PRST$4, oneOf(options.preset, PATTERN_PRESETS, "setShapePatternFill: preset"))],
2039
2216
  children: [elem(NAME_FG_CLR, { children: [buildColorElement(options.foreground)] }), elem(NAME_BG_CLR, { children: [buildColorElement(options.background)] })]
2040
2217
  });
2041
2218
  host.children.splice(fillInsertionIndex(host), 0, pattFill);
@@ -2051,11 +2228,22 @@ const setGradientFill = (host, options) => {
2051
2228
  children: [buildColorElement(s.color)]
2052
2229
  });
2053
2230
  });
2054
- const norm = ((options.angleDeg ?? 90) % 360 + 360) % 360;
2055
- const angleAttr = String(Math.round(norm * 6e4));
2231
+ const pct = (n) => String(Math.round(n * 1e5));
2232
+ const directionEl = options.path === void 0 || options.path === "linear" ? (() => {
2233
+ const norm = ((options.angleDeg ?? 90) % 360 + 360) % 360;
2234
+ return elem(NAME_LIN, { attrs: [attr(ATTR_ANG, String(Math.round(norm * 6e4))), attr(ATTR_SCALED, "0")] });
2235
+ })() : elem(NAME_PATH, {
2236
+ attrs: [attr(ATTR_PATH, options.path)],
2237
+ children: options.focus === void 0 ? [] : [elem(NAME_FILL_TO_RECT, { attrs: [
2238
+ attr(qname("", "l", ""), pct(options.focus.left)),
2239
+ attr(qname("", "t", ""), pct(options.focus.top)),
2240
+ attr(qname("", "r", ""), pct(options.focus.right)),
2241
+ attr(qname("", "b", ""), pct(options.focus.bottom))
2242
+ ] })]
2243
+ });
2056
2244
  const grad = elem(NAME_GRAD_FILL, {
2057
2245
  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")] })]
2246
+ children: [elem(NAME_GS_LST, { children: stops }), directionEl]
2059
2247
  });
2060
2248
  host.children.splice(fillInsertionIndex(host), 0, grad);
2061
2249
  };
@@ -2071,7 +2259,7 @@ const ATTR_DIR$1 = qname("", "dir", "");
2071
2259
  const ATTR_ALGN = qname("", "algn", "");
2072
2260
  const ATTR_ROT_WITH_SHAPE = qname("", "rotWithShape", "");
2073
2261
  const ATTR_RAD = qname("", "rad", "");
2074
- const ATTR_VAL$5 = qname("", "val", "");
2262
+ const ATTR_VAL$7 = qname("", "val", "");
2075
2263
  /**
2076
2264
  * Computes the index inside `host.children` where an `<a:effectLst>`
2077
2265
  * should be inserted to satisfy the spec's child ordering on
@@ -2093,7 +2281,7 @@ const colorWithAlpha = (color, opacity) => {
2093
2281
  const base = buildColorElement(color);
2094
2282
  if (opacity !== void 0 && opacity >= 0 && opacity < 1) {
2095
2283
  const amt = Math.round(opacity * 1e5);
2096
- base.children.push(elem(NAME_ALPHA, { attrs: [attr(ATTR_VAL$5, String(amt))] }));
2284
+ base.children.push(elem(NAME_ALPHA, { attrs: [attr(ATTR_VAL$7, String(amt))] }));
2097
2285
  }
2098
2286
  return base;
2099
2287
  };
@@ -2105,8 +2293,8 @@ const colorWithAlpha = (color, opacity) => {
2105
2293
  const setShadow = (host, options = {}) => {
2106
2294
  removeEffectLst(host);
2107
2295
  const color = options.color ?? "#000000";
2108
- const blur = options.blurEmu ?? 50800;
2109
- const dist = options.offsetEmu ?? 38100;
2296
+ const blur = emuExtent(options.blurEmu ?? 50800, "setShapeShadow: blurEmu");
2297
+ const dist = emuExtent(options.offsetEmu ?? 38100, "setShapeShadow: offsetEmu");
2110
2298
  const angleDeg = options.angleDeg ?? 45;
2111
2299
  const dir = String(Math.round((angleDeg % 360 + 360) % 360 * 6e4));
2112
2300
  const effectLst = elem(NAME_EFFECT_LST, { children: [elem(NAME_OUTER_SHDW, {
@@ -2128,7 +2316,7 @@ const setShadow = (host, options = {}) => {
2128
2316
  const setGlow = (host, options) => {
2129
2317
  removeEffectLst(host);
2130
2318
  const effectLst = elem(NAME_EFFECT_LST, { children: [elem(NAME_GLOW, {
2131
- attrs: [attr(ATTR_RAD, String(options.radiusEmu ?? 63500))],
2319
+ attrs: [attr(ATTR_RAD, String(emuExtent(options.radiusEmu ?? 63500, "setShapeGlow: radiusEmu")))],
2132
2320
  children: [buildColorElement(options.color)]
2133
2321
  })] });
2134
2322
  host.children.splice(effectInsertionIndex(host), 0, effectLst);
@@ -2149,6 +2337,22 @@ const FILL_LOCALS = new Set([
2149
2337
  "gradFill",
2150
2338
  "pattFill"
2151
2339
  ]);
2340
+ const LN_CHILD_RANK = {
2341
+ noFill: 0,
2342
+ solidFill: 0,
2343
+ gradFill: 0,
2344
+ pattFill: 0,
2345
+ prstDash: 1,
2346
+ custDash: 1,
2347
+ round: 2,
2348
+ bevel: 2,
2349
+ miter: 2,
2350
+ headEnd: 3,
2351
+ tailEnd: 4,
2352
+ extLst: 5
2353
+ };
2354
+ const lnChildRank = (el) => el.name.namespaceURI === NS.dml ? LN_CHILD_RANK[el.name.localName] ?? 99 : 99;
2355
+ const insertLnChild = (ln, el) => insertChildByRank(ln, el, lnChildRank);
2152
2356
  const removeChildrenIn = (host, names) => {
2153
2357
  host.children = host.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && names.has(c.name.localName)));
2154
2358
  };
@@ -2177,23 +2381,23 @@ const setSolidStroke = (spPr, options) => {
2177
2381
  const ln = ensureLn(spPr);
2178
2382
  if (options.widthEmu !== void 0) {
2179
2383
  ln.attrs = ln.attrs.filter((a) => a.name.localName !== "w");
2180
- ln.attrs.push(attr(ATTR_W$3, String(Math.round(options.widthEmu))));
2384
+ ln.attrs.push(attr(ATTR_W$3, String(lineWidthEmu(options.widthEmu, "setShapeStroke: widthEmu"))));
2181
2385
  }
2182
2386
  removeChildrenIn(ln, FILL_LOCALS);
2183
- if (options.color !== void 0) ln.children.unshift(elem(NAME_SOLID_FILL$4, { children: [buildColorElement(options.color)] }));
2387
+ if (options.color !== void 0) insertLnChild(ln, elem(NAME_SOLID_FILL$4, { children: [buildColorElement(options.color)] }));
2184
2388
  };
2185
2389
  /** Sets an explicit "no outline" on a shape's spPr. */
2186
2390
  const setNoStroke = (spPr) => {
2187
2391
  const ln = ensureLn(spPr);
2188
2392
  removeChildrenIn(ln, FILL_LOCALS);
2189
- ln.children.unshift(elem(NAME_NO_FILL$1));
2393
+ insertLnChild(ln, elem(NAME_NO_FILL$1));
2190
2394
  };
2191
2395
  /** Removes any `<a:ln>` from a shape's spPr (restores inheritance). */
2192
2396
  const clearStroke = (spPr) => {
2193
2397
  spPr.children = spPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "ln"));
2194
2398
  };
2195
2399
  const NAME_PRST_DASH = qname("a", "prstDash", NS.dml);
2196
- const ATTR_VAL$4 = qname("", "val", "");
2400
+ const ATTR_VAL$6 = qname("", "val", "");
2197
2401
  /**
2198
2402
  * Sets `<a:prstDash val="..."/>` inside the shape's `<a:ln>`. Creates
2199
2403
  * `<a:ln>` if absent. Replacing the dash choice on subsequent calls.
@@ -2201,7 +2405,7 @@ const ATTR_VAL$4 = qname("", "val", "");
2201
2405
  const setStrokeDash = (spPr, dash) => {
2202
2406
  const ln = ensureLn(spPr);
2203
2407
  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)] }));
2408
+ insertLnChild(ln, elem(NAME_PRST_DASH, { attrs: [attr(ATTR_VAL$6, dash)] }));
2205
2409
  };
2206
2410
  const ATTR_TYPE$5 = qname("", "type", "");
2207
2411
  const ATTR_LEN = qname("", "len", "");
@@ -2222,7 +2426,7 @@ const setStrokeArrow = (spPr, end, options) => {
2222
2426
  const attrs = [attr(ATTR_TYPE$5, options.type)];
2223
2427
  if (options.width !== void 0) attrs.push(attr(ATTR_W$3, options.width));
2224
2428
  if (options.length !== void 0) attrs.push(attr(ATTR_LEN, options.length));
2225
- ln.children.push(elem(qname("a", localName, NS.dml), { attrs }));
2429
+ insertLnChild(ln, elem(qname("a", localName, NS.dml), { attrs }));
2226
2430
  };
2227
2431
  /** Sets `<a:ln cap="…"/>`. Pass `null` to clear the attribute. */
2228
2432
  const setStrokeCap = (spPr, cap) => {
@@ -2239,7 +2443,7 @@ const JOIN_LOCALS = new Set([
2239
2443
  const setStrokeJoin = (spPr, join) => {
2240
2444
  const ln = ensureLn(spPr);
2241
2445
  removeChildrenIn(ln, JOIN_LOCALS);
2242
- if (join !== null) ln.children.push(elem(qname("a", join, NS.dml)));
2446
+ if (join !== null) insertLnChild(ln, elem(qname("a", join, NS.dml)));
2243
2447
  };
2244
2448
  /** Sets `<a:ln cmpd="…"/>`. Pass `null` to clear the attribute. */
2245
2449
  const setStrokeCompound = (spPr, cmpd) => {
@@ -2257,10 +2461,10 @@ const setStrokeCompound = (spPr, cmpd) => {
2257
2461
  * while letting any genuine programming error propagate.
2258
2462
  */
2259
2463
  var GeomEvalError = class extends Error {};
2260
- const ATTR_NAME$10 = qname("", "name", "");
2464
+ const ATTR_NAME$12 = qname("", "name", "");
2261
2465
  const ATTR_FMLA = qname("", "fmla", "");
2262
- const ATTR_X$8 = qname("", "x", "");
2263
- const ATTR_Y$8 = qname("", "y", "");
2466
+ const ATTR_X$9 = qname("", "x", "");
2467
+ const ATTR_Y$9 = qname("", "y", "");
2264
2468
  const ATTR_W$2 = qname("", "w", "");
2265
2469
  const ATTR_H$1 = qname("", "h", "");
2266
2470
  const ATTR_WR = qname("", "wR", "");
@@ -2384,15 +2588,15 @@ const dmlChildren = (parent, localName) => {
2384
2588
  const evalGuideList = (parent, guides) => {
2385
2589
  if (parent === null) return;
2386
2590
  for (const c of dmlChildren(parent, "gd")) {
2387
- const name = getAttrValue(c, ATTR_NAME$10);
2591
+ const name = getAttrValue(c, ATTR_NAME$12);
2388
2592
  const fmla = getAttrValue(c, ATTR_FMLA);
2389
2593
  if (name === null || fmla === null) continue;
2390
2594
  guides.set(name, evalFormula(fmla, guides));
2391
2595
  }
2392
2596
  };
2393
2597
  const resolvePt = (pt, guides) => ({
2394
- x: resolveToken(getAttrValue(pt, ATTR_X$8) ?? "0", guides),
2395
- y: resolveToken(getAttrValue(pt, ATTR_Y$8) ?? "0", guides)
2598
+ x: resolveToken(getAttrValue(pt, ATTR_X$9) ?? "0", guides),
2599
+ y: resolveToken(getAttrValue(pt, ATTR_Y$9) ?? "0", guides)
2396
2600
  });
2397
2601
  const parsePoint = (el, guides) => {
2398
2602
  const pt = firstDmlChild(el, qname("a", "pt", NS.dml));
@@ -2557,15 +2761,15 @@ const getPictureEmbedRId = (picElement) => {
2557
2761
  //#endregion
2558
2762
  //#region src/internal/drawingml/geometry.ts
2559
2763
  const NAME_SP_PR$7 = qname("p", "spPr", NS.pml);
2560
- const NAME_GRP_SP_PR$3 = qname("p", "grpSpPr", NS.pml);
2561
- const NAME_A_XFRM$5 = qname("a", "xfrm", NS.dml);
2764
+ const NAME_GRP_SP_PR$4 = qname("p", "grpSpPr", NS.pml);
2765
+ const NAME_A_XFRM$6 = qname("a", "xfrm", NS.dml);
2562
2766
  const NAME_P_XFRM$2 = qname("p", "xfrm", NS.pml);
2563
- const NAME_OFF$7 = qname("a", "off", NS.dml);
2564
- const NAME_EXT$7 = qname("a", "ext", NS.dml);
2565
- const ATTR_X$7 = qname("", "x", "");
2566
- const ATTR_Y$7 = qname("", "y", "");
2567
- const ATTR_CX$7 = qname("", "cx", "");
2568
- const ATTR_CY$7 = qname("", "cy", "");
2767
+ const NAME_OFF$8 = qname("a", "off", NS.dml);
2768
+ const NAME_EXT$8 = qname("a", "ext", NS.dml);
2769
+ const ATTR_X$8 = qname("", "x", "");
2770
+ const ATTR_Y$8 = qname("", "y", "");
2771
+ const ATTR_CX$8 = qname("", "cx", "");
2772
+ const ATTR_CY$8 = qname("", "cy", "");
2569
2773
  const parseIntOr = (raw) => raw === null ? null : Number.isFinite(Number.parseInt(raw, 10)) ? Number.parseInt(raw, 10) : null;
2570
2774
  const findTransform = (shape, kind) => {
2571
2775
  switch (kind) {
@@ -2574,12 +2778,12 @@ const findTransform = (shape, kind) => {
2574
2778
  case "connector": {
2575
2779
  const spPr = firstChildElement(shape, NAME_SP_PR$7);
2576
2780
  if (spPr === null) return null;
2577
- return firstChildElement(spPr, NAME_A_XFRM$5);
2781
+ return firstChildElement(spPr, NAME_A_XFRM$6);
2578
2782
  }
2579
2783
  case "group": {
2580
- const grpSpPr = firstChildElement(shape, NAME_GRP_SP_PR$3);
2784
+ const grpSpPr = firstChildElement(shape, NAME_GRP_SP_PR$4);
2581
2785
  if (grpSpPr === null) return null;
2582
- return firstChildElement(grpSpPr, NAME_A_XFRM$5);
2786
+ return firstChildElement(grpSpPr, NAME_A_XFRM$6);
2583
2787
  }
2584
2788
  case "graphicFrame": return firstChildElement(shape, NAME_P_XFRM$2);
2585
2789
  }
@@ -2588,10 +2792,10 @@ const findTransform = (shape, kind) => {
2588
2792
  const readPosition = (shape, kind) => {
2589
2793
  const xfrm = findTransform(shape, kind);
2590
2794
  if (xfrm === null) return null;
2591
- const off = firstChildElement(xfrm, NAME_OFF$7);
2795
+ const off = firstChildElement(xfrm, NAME_OFF$8);
2592
2796
  if (off === null) return null;
2593
- const x = parseIntOr(getAttrValue(off, ATTR_X$7));
2594
- const y = parseIntOr(getAttrValue(off, ATTR_Y$7));
2797
+ const x = parseIntOr(getAttrValue(off, ATTR_X$8));
2798
+ const y = parseIntOr(getAttrValue(off, ATTR_Y$8));
2595
2799
  if (x === null || y === null) return null;
2596
2800
  return {
2597
2801
  x,
@@ -2602,10 +2806,10 @@ const readPosition = (shape, kind) => {
2602
2806
  const readSize = (shape, kind) => {
2603
2807
  const xfrm = findTransform(shape, kind);
2604
2808
  if (xfrm === null) return null;
2605
- const ext = firstChildElement(xfrm, NAME_EXT$7);
2809
+ const ext = firstChildElement(xfrm, NAME_EXT$8);
2606
2810
  if (ext === null) return null;
2607
- const w = parseIntOr(getAttrValue(ext, ATTR_CX$7));
2608
- const h = parseIntOr(getAttrValue(ext, ATTR_CY$7));
2811
+ const w = parseIntOr(getAttrValue(ext, ATTR_CX$8));
2812
+ const h = parseIntOr(getAttrValue(ext, ATTR_CY$8));
2609
2813
  if (w === null || h === null) return null;
2610
2814
  return {
2611
2815
  w,
@@ -2638,15 +2842,15 @@ const readFlip = (shape, kind) => {
2638
2842
  //#endregion
2639
2843
  //#region src/internal/drawingml/geometry-mutation.ts
2640
2844
  const NAME_SP_PR$6 = qname("p", "spPr", NS.pml);
2641
- const NAME_GRP_SP_PR$2 = qname("p", "grpSpPr", NS.pml);
2642
- const NAME_A_XFRM$4 = qname("a", "xfrm", NS.dml);
2845
+ const NAME_GRP_SP_PR$3 = qname("p", "grpSpPr", NS.pml);
2846
+ const NAME_A_XFRM$5 = qname("a", "xfrm", NS.dml);
2643
2847
  const NAME_P_XFRM$1 = qname("p", "xfrm", NS.pml);
2644
- const NAME_OFF$6 = qname("a", "off", NS.dml);
2645
- const NAME_EXT$6 = qname("a", "ext", NS.dml);
2646
- const ATTR_X$6 = qname("", "x", "");
2647
- const ATTR_Y$6 = qname("", "y", "");
2648
- const ATTR_CX$6 = qname("", "cx", "");
2649
- const ATTR_CY$6 = qname("", "cy", "");
2848
+ const NAME_OFF$7 = qname("a", "off", NS.dml);
2849
+ const NAME_EXT$7 = qname("a", "ext", NS.dml);
2850
+ const ATTR_X$7 = qname("", "x", "");
2851
+ const ATTR_Y$7 = qname("", "y", "");
2852
+ const ATTR_CX$7 = qname("", "cx", "");
2853
+ const ATTR_CY$7 = qname("", "cy", "");
2650
2854
  /**
2651
2855
  * Ensures the shape has an `<a:xfrm>` (or `<p:xfrm>` for graphic frames)
2652
2856
  * to write into, creating the host element and its parent if absent.
@@ -2662,15 +2866,15 @@ const ensureTransform = (shape, kind) => {
2662
2866
  }
2663
2867
  return xfrm;
2664
2868
  }
2665
- const hostName = kind === "group" ? NAME_GRP_SP_PR$2 : NAME_SP_PR$6;
2869
+ const hostName = kind === "group" ? NAME_GRP_SP_PR$3 : NAME_SP_PR$6;
2666
2870
  let host = firstChildElement(shape, hostName);
2667
2871
  if (host === null) {
2668
2872
  host = elem(hostName);
2669
2873
  shape.children.push(host);
2670
2874
  }
2671
- let xfrm = firstChildElement(host, NAME_A_XFRM$4);
2875
+ let xfrm = firstChildElement(host, NAME_A_XFRM$5);
2672
2876
  if (xfrm === null) {
2673
- xfrm = elem(NAME_A_XFRM$4);
2877
+ xfrm = elem(NAME_A_XFRM$5);
2674
2878
  host.children.unshift(xfrm);
2675
2879
  }
2676
2880
  return xfrm;
@@ -2678,24 +2882,24 @@ const ensureTransform = (shape, kind) => {
2678
2882
  /** Sets the shape's `<a:off>` to `(x, y)` in EMU. */
2679
2883
  const setPosition = (shape, kind, x, y) => {
2680
2884
  const xfrm = ensureTransform(shape, kind);
2681
- let off = firstChildElement(xfrm, NAME_OFF$6);
2885
+ let off = firstChildElement(xfrm, NAME_OFF$7);
2682
2886
  if (off === null) {
2683
- off = elem(NAME_OFF$6);
2887
+ off = elem(NAME_OFF$7);
2684
2888
  xfrm.children.unshift(off);
2685
2889
  }
2686
- off.attrs = [attr(ATTR_X$6, String(x)), attr(ATTR_Y$6, String(y))];
2890
+ off.attrs = [attr(ATTR_X$7, String(emuCoordinate(x, "setShapePosition: x"))), attr(ATTR_Y$7, String(emuCoordinate(y, "setShapePosition: y")))];
2687
2891
  };
2688
2892
  /** Sets the shape's `<a:ext>` to `(w, h)` in EMU. */
2689
2893
  const setSize = (shape, kind, w, h) => {
2690
2894
  const xfrm = ensureTransform(shape, kind);
2691
- let ext = firstChildElement(xfrm, NAME_EXT$6);
2895
+ let ext = firstChildElement(xfrm, NAME_EXT$7);
2692
2896
  if (ext === null) {
2693
- ext = elem(NAME_EXT$6);
2897
+ ext = elem(NAME_EXT$7);
2694
2898
  const offIdx = xfrm.children.findIndex((c) => c.kind === "element" && c.name.localName === "off" && c.name.namespaceURI === NS.dml);
2695
2899
  if (offIdx >= 0) xfrm.children.splice(offIdx + 1, 0, ext);
2696
2900
  else xfrm.children.push(ext);
2697
2901
  }
2698
- ext.attrs = [attr(ATTR_CX$6, String(w)), attr(ATTR_CY$6, String(h))];
2902
+ ext.attrs = [attr(ATTR_CX$7, String(emuExtent(w, "setShapeSize: w"))), attr(ATTR_CY$7, String(emuExtent(h, "setShapeSize: h")))];
2699
2903
  };
2700
2904
  const ATTR_ROT = qname("", "rot", "");
2701
2905
  const ATTR_FLIP_H$1 = qname("", "flipH", "");
@@ -2732,21 +2936,21 @@ const NAME_CSLD$4 = qname("p", "cSld", NS.pml);
2732
2936
  const NAME_SP_TREE$3 = qname("p", "spTree", NS.pml);
2733
2937
  const NAME_NV_SP_PR$4 = qname("p", "nvSpPr", NS.pml);
2734
2938
  const NAME_NV_PIC_PR$1 = qname("p", "nvPicPr", NS.pml);
2735
- const NAME_NV_GRP_SP_PR$2 = qname("p", "nvGrpSpPr", NS.pml);
2939
+ const NAME_NV_GRP_SP_PR$3 = qname("p", "nvGrpSpPr", NS.pml);
2736
2940
  const NAME_NV_GRAPHIC_FRAME_PR$2 = qname("p", "nvGraphicFramePr", NS.pml);
2737
2941
  const NAME_NV_CXN_SP_PR$1 = qname("p", "nvCxnSpPr", NS.pml);
2738
- const NAME_C_NV_PR$7 = qname("p", "cNvPr", NS.pml);
2739
- const NAME_NV_PR$8 = qname("p", "nvPr", NS.pml);
2942
+ const NAME_C_NV_PR$8 = qname("p", "cNvPr", NS.pml);
2943
+ const NAME_NV_PR$9 = qname("p", "nvPr", NS.pml);
2740
2944
  const NAME_PH$2 = qname("p", "ph", NS.pml);
2741
2945
  const NAME_TX_BODY$9 = qname("p", "txBody", NS.pml);
2742
- const ATTR_ID$11 = qname("", "id", "");
2743
- const ATTR_NAME$9 = qname("", "name", "");
2946
+ const ATTR_ID$12 = qname("", "id", "");
2947
+ const ATTR_NAME$11 = qname("", "name", "");
2744
2948
  const ATTR_TYPE$4 = qname("", "type", "");
2745
- const ATTR_IDX$5 = qname("", "idx", "");
2949
+ const ATTR_IDX$6 = qname("", "idx", "");
2746
2950
  const NV_BY_KIND = {
2747
2951
  shape: NAME_NV_SP_PR$4,
2748
2952
  picture: NAME_NV_PIC_PR$1,
2749
- group: NAME_NV_GRP_SP_PR$2,
2953
+ group: NAME_NV_GRP_SP_PR$3,
2750
2954
  graphicFrame: NAME_NV_GRAPHIC_FRAME_PR$2,
2751
2955
  connector: NAME_NV_CXN_SP_PR$1
2752
2956
  };
@@ -2768,19 +2972,19 @@ const extractShape = (element, kind) => {
2768
2972
  let placeholderType = null;
2769
2973
  let placeholderIdx = null;
2770
2974
  if (nvContainer !== null) {
2771
- const cNvPr = firstChildElement(nvContainer, NAME_C_NV_PR$7);
2975
+ const cNvPr = firstChildElement(nvContainer, NAME_C_NV_PR$8);
2772
2976
  if (cNvPr !== null) {
2773
- const idRaw = getAttrValue(cNvPr, ATTR_ID$11);
2977
+ const idRaw = getAttrValue(cNvPr, ATTR_ID$12);
2774
2978
  if (idRaw !== null) id = Number.parseInt(idRaw, 10);
2775
- const nameRaw = getAttrValue(cNvPr, ATTR_NAME$9);
2979
+ const nameRaw = getAttrValue(cNvPr, ATTR_NAME$11);
2776
2980
  if (nameRaw !== null) name = nameRaw;
2777
2981
  }
2778
- const nvPr = firstChildElement(nvContainer, NAME_NV_PR$8);
2982
+ const nvPr = firstChildElement(nvContainer, NAME_NV_PR$9);
2779
2983
  if (nvPr !== null) {
2780
2984
  const ph = firstChildElement(nvPr, NAME_PH$2);
2781
2985
  if (ph !== null) {
2782
2986
  placeholderType = getAttrValue(ph, ATTR_TYPE$4);
2783
- const idxRaw = getAttrValue(ph, ATTR_IDX$5);
2987
+ const idxRaw = getAttrValue(ph, ATTR_IDX$6);
2784
2988
  if (idxRaw !== null) placeholderIdx = Number.parseInt(idxRaw, 10);
2785
2989
  }
2786
2990
  }
@@ -2862,13 +3066,13 @@ const slideText = (slide, joiner = "\n") => slide.shapes.map((s) => s.text).filt
2862
3066
  //#endregion
2863
3067
  //#region src/internal/presentationml/slide-layout-part.ts
2864
3068
  const NAME_CSLD$3 = qname("p", "cSld", NS.pml);
2865
- const ATTR_NAME$8 = qname("", "name", "");
3069
+ const ATTR_NAME$10 = qname("", "name", "");
2866
3070
  const ATTR_TYPE$3 = qname("", "type", "");
2867
3071
  /** Parses a `<p:sldLayout>` root element. */
2868
3072
  const readSlideLayoutPart = (root, options = {}) => {
2869
3073
  const { shapes } = readShapeTreeFromCsldRoot(root, "sldLayout", options);
2870
3074
  const cSld = firstChildElement(root, NAME_CSLD$3);
2871
- const name = cSld !== null ? getAttrValue(cSld, ATTR_NAME$8) : null;
3075
+ const name = cSld !== null ? getAttrValue(cSld, ATTR_NAME$10) : null;
2872
3076
  const layoutType = getAttrValue(root, ATTR_TYPE$3);
2873
3077
  return {
2874
3078
  name: name ?? "",
@@ -2882,11 +3086,11 @@ const readSlideLayoutPart = (root, options = {}) => {
2882
3086
  const NAME_SLD = qname("p", "sld", NS.pml);
2883
3087
  const NAME_CSLD$2 = qname("p", "cSld", NS.pml);
2884
3088
  const NAME_SP_TREE$2 = qname("p", "spTree", NS.pml);
2885
- const NAME_NV_GRP_SP_PR$1 = qname("p", "nvGrpSpPr", NS.pml);
2886
- const NAME_C_NV_PR$6 = qname("p", "cNvPr", NS.pml);
2887
- const NAME_C_NV_GRP_SP_PR$1 = qname("p", "cNvGrpSpPr", NS.pml);
2888
- const NAME_NV_PR$7 = qname("p", "nvPr", NS.pml);
2889
- const NAME_GRP_SP_PR$1 = qname("p", "grpSpPr", NS.pml);
3089
+ const NAME_NV_GRP_SP_PR$2 = qname("p", "nvGrpSpPr", NS.pml);
3090
+ const NAME_C_NV_PR$7 = qname("p", "cNvPr", NS.pml);
3091
+ const NAME_C_NV_GRP_SP_PR$2 = qname("p", "cNvGrpSpPr", NS.pml);
3092
+ const NAME_NV_PR$8 = qname("p", "nvPr", NS.pml);
3093
+ const NAME_GRP_SP_PR$2 = qname("p", "grpSpPr", NS.pml);
2890
3094
  const NAME_SP$3 = qname("p", "sp", NS.pml);
2891
3095
  const NAME_NV_SP_PR$3 = qname("p", "nvSpPr", NS.pml);
2892
3096
  const NAME_C_NV_SP_PR$3 = qname("p", "cNvSpPr", NS.pml);
@@ -2897,10 +3101,10 @@ const NAME_BODY_PR$4 = qname("a", "bodyPr", NS.dml);
2897
3101
  const NAME_LST_STYLE$4 = qname("a", "lstStyle", NS.dml);
2898
3102
  const NAME_P$4 = qname("a", "p", NS.dml);
2899
3103
  const NAME_SP_LOCKS$1 = qname("a", "spLocks", NS.dml);
2900
- const ATTR_ID$10 = qname("", "id", "");
2901
- const ATTR_NAME$7 = qname("", "name", "");
3104
+ const ATTR_ID$11 = qname("", "id", "");
3105
+ const ATTR_NAME$9 = qname("", "name", "");
2902
3106
  const ATTR_TYPE$2 = qname("", "type", "");
2903
- const ATTR_IDX$4 = qname("", "idx", "");
3107
+ const ATTR_IDX$5 = qname("", "idx", "");
2904
3108
  const ATTR_NO_GRP$2 = qname("", "noGrp", "");
2905
3109
  /**
2906
3110
  * Builds a `<p:sld>` document containing the canonical slide-root group
@@ -2918,13 +3122,13 @@ const buildSlideFromLayout = (layoutSpTree) => {
2918
3122
  if (child.name.namespaceURI !== NS.pml || child.name.localName !== "sp") continue;
2919
3123
  const nvSpPr = firstChildElement(child, NAME_NV_SP_PR$3);
2920
3124
  if (nvSpPr === null) continue;
2921
- const nvPr = firstChildElement(nvSpPr, NAME_NV_PR$7);
3125
+ const nvPr = firstChildElement(nvSpPr, NAME_NV_PR$8);
2922
3126
  if (nvPr === null) continue;
2923
3127
  const ph = firstChildElement(nvPr, NAME_PH$1);
2924
3128
  if (ph === null) continue;
2925
3129
  placeholders.push({
2926
3130
  type: getAttrValue(ph, ATTR_TYPE$2),
2927
- idx: getAttrValue(ph, ATTR_IDX$4)
3131
+ idx: getAttrValue(ph, ATTR_IDX$5)
2928
3132
  });
2929
3133
  }
2930
3134
  let nextShapeId = 2;
@@ -2957,22 +3161,22 @@ const buildSlideFromLayout = (layoutSpTree) => {
2957
3161
  epilog: []
2958
3162
  };
2959
3163
  };
2960
- const buildNvGrpSpPr = (id) => elem(NAME_NV_GRP_SP_PR$1, { children: [
2961
- elem(NAME_C_NV_PR$6, { attrs: [attr(ATTR_ID$10, String(id)), attr(ATTR_NAME$7, "")] }),
2962
- elem(NAME_C_NV_GRP_SP_PR$1),
2963
- elem(NAME_NV_PR$7)
3164
+ const buildNvGrpSpPr = (id) => elem(NAME_NV_GRP_SP_PR$2, { children: [
3165
+ elem(NAME_C_NV_PR$7, { attrs: [attr(ATTR_ID$11, String(id)), attr(ATTR_NAME$9, "")] }),
3166
+ elem(NAME_C_NV_GRP_SP_PR$2),
3167
+ elem(NAME_NV_PR$8)
2964
3168
  ] });
2965
- const buildGrpSpPr = () => elem(NAME_GRP_SP_PR$1);
3169
+ const buildGrpSpPr = () => elem(NAME_GRP_SP_PR$2);
2966
3170
  const buildPlaceholderStub = (id, phType, phIdx) => {
2967
3171
  const phAttrs = [];
2968
3172
  if (phType !== null) phAttrs.push(attr(ATTR_TYPE$2, phType));
2969
- if (phIdx !== null) phAttrs.push(attr(ATTR_IDX$4, phIdx));
2970
- const nvPr = elem(NAME_NV_PR$7, { children: [elem(NAME_PH$1, { attrs: phAttrs })] });
3173
+ if (phIdx !== null) phAttrs.push(attr(ATTR_IDX$5, phIdx));
3174
+ const nvPr = elem(NAME_NV_PR$8, { children: [elem(NAME_PH$1, { attrs: phAttrs })] });
2971
3175
  const cNvSpPr = elem(NAME_C_NV_SP_PR$3, { children: [elem(NAME_SP_LOCKS$1, { attrs: [attr(ATTR_NO_GRP$2, "1")] })] });
2972
3176
  const name = inferPlaceholderName(id, phType);
2973
3177
  return elem(NAME_SP$3, { children: [
2974
3178
  elem(NAME_NV_SP_PR$3, { children: [
2975
- elem(NAME_C_NV_PR$6, { attrs: [attr(ATTR_ID$10, String(id)), attr(ATTR_NAME$7, name)] }),
3179
+ elem(NAME_C_NV_PR$7, { attrs: [attr(ATTR_ID$11, String(id)), attr(ATTR_NAME$9, name)] }),
2976
3180
  cNvSpPr,
2977
3181
  nvPr
2978
3182
  ] }),
@@ -3008,14 +3212,14 @@ const inferPlaceholderName = (id, phType) => {
3008
3212
  //#region src/internal/presentationml/text-box-builder.ts
3009
3213
  const NAME_SP$2 = qname("p", "sp", NS.pml);
3010
3214
  const NAME_NV_SP_PR$2 = qname("p", "nvSpPr", NS.pml);
3011
- const NAME_C_NV_PR$5 = qname("p", "cNvPr", NS.pml);
3215
+ const NAME_C_NV_PR$6 = qname("p", "cNvPr", NS.pml);
3012
3216
  const NAME_C_NV_SP_PR$2 = qname("p", "cNvSpPr", NS.pml);
3013
- const NAME_NV_PR$6 = qname("p", "nvPr", NS.pml);
3217
+ const NAME_NV_PR$7 = qname("p", "nvPr", NS.pml);
3014
3218
  const NAME_SP_PR$4 = qname("p", "spPr", NS.pml);
3015
3219
  const NAME_TX_BODY$7 = qname("p", "txBody", NS.pml);
3016
- const NAME_A_XFRM$3 = qname("a", "xfrm", NS.dml);
3017
- const NAME_OFF$5 = qname("a", "off", NS.dml);
3018
- const NAME_EXT$5 = qname("a", "ext", NS.dml);
3220
+ const NAME_A_XFRM$4 = qname("a", "xfrm", NS.dml);
3221
+ const NAME_OFF$6 = qname("a", "off", NS.dml);
3222
+ const NAME_EXT$6 = qname("a", "ext", NS.dml);
3019
3223
  const NAME_PRST_GEOM$3 = qname("a", "prstGeom", NS.dml);
3020
3224
  const NAME_AV_LST$3 = qname("a", "avLst", NS.dml);
3021
3225
  const NAME_NO_FILL = qname("a", "noFill", NS.dml);
@@ -3025,13 +3229,13 @@ const NAME_P$3 = qname("a", "p", NS.dml);
3025
3229
  const NAME_R$3 = qname("a", "r", NS.dml);
3026
3230
  const NAME_RPR$3 = qname("a", "rPr", NS.dml);
3027
3231
  const NAME_T$4 = qname("a", "t", NS.dml);
3028
- const ATTR_ID$9 = qname("", "id", "");
3029
- const ATTR_NAME$6 = qname("", "name", "");
3232
+ const ATTR_ID$10 = qname("", "id", "");
3233
+ const ATTR_NAME$8 = qname("", "name", "");
3030
3234
  const ATTR_TX_BOX$1 = qname("", "txBox", "");
3031
- const ATTR_X$5 = qname("", "x", "");
3032
- const ATTR_Y$5 = qname("", "y", "");
3033
- const ATTR_CX$5 = qname("", "cx", "");
3034
- const ATTR_CY$5 = qname("", "cy", "");
3235
+ const ATTR_X$6 = qname("", "x", "");
3236
+ const ATTR_Y$6 = qname("", "y", "");
3237
+ const ATTR_CX$6 = qname("", "cx", "");
3238
+ const ATTR_CY$6 = qname("", "cy", "");
3035
3239
  const ATTR_PRST$3 = qname("", "prst", "");
3036
3240
  const ATTR_WRAP$1 = qname("", "wrap", "");
3037
3241
  const ATTR_RTL_COL$1 = qname("", "rtlCol", "");
@@ -3046,12 +3250,12 @@ NS.xml;
3046
3250
  const buildTextBox = (opts) => {
3047
3251
  const name = opts.name ?? `TextBox ${opts.id}`;
3048
3252
  const nvSpPr = elem(NAME_NV_SP_PR$2, { children: [
3049
- elem(NAME_C_NV_PR$5, { attrs: [attr(ATTR_ID$9, String(opts.id)), attr(ATTR_NAME$6, name)] }),
3253
+ elem(NAME_C_NV_PR$6, { attrs: [attr(ATTR_ID$10, String(opts.id)), attr(ATTR_NAME$8, name)] }),
3050
3254
  elem(NAME_C_NV_SP_PR$2, { attrs: [attr(ATTR_TX_BOX$1, "1")] }),
3051
- elem(NAME_NV_PR$6)
3255
+ elem(NAME_NV_PR$7)
3052
3256
  ] });
3053
3257
  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)))] })] }),
3258
+ elem(NAME_A_XFRM$4, { children: [elem(NAME_OFF$6, { attrs: [attr(ATTR_X$6, String(emuCoordinate(opts.x, "addSlideTextBox: x"))), attr(ATTR_Y$6, String(emuCoordinate(opts.y, "addSlideTextBox: y")))] }), elem(NAME_EXT$6, { attrs: [attr(ATTR_CX$6, String(emuExtent(opts.w, "addSlideTextBox: w"))), attr(ATTR_CY$6, String(emuExtent(opts.h, "addSlideTextBox: h")))] })] }),
3055
3259
  elem(NAME_PRST_GEOM$3, {
3056
3260
  attrs: [attr(ATTR_PRST$3, "rect")],
3057
3261
  children: [elem(NAME_AV_LST$3)]
@@ -3076,14 +3280,14 @@ const buildTextBox = (opts) => {
3076
3280
  //#region src/internal/presentationml/shape-builder.ts
3077
3281
  const NAME_SP$1 = qname("p", "sp", NS.pml);
3078
3282
  const NAME_NV_SP_PR$1 = qname("p", "nvSpPr", NS.pml);
3079
- const NAME_C_NV_PR$4 = qname("p", "cNvPr", NS.pml);
3283
+ const NAME_C_NV_PR$5 = qname("p", "cNvPr", NS.pml);
3080
3284
  const NAME_C_NV_SP_PR$1 = qname("p", "cNvSpPr", NS.pml);
3081
- const NAME_NV_PR$5 = qname("p", "nvPr", NS.pml);
3285
+ const NAME_NV_PR$6 = qname("p", "nvPr", NS.pml);
3082
3286
  const NAME_SP_PR$3 = qname("p", "spPr", NS.pml);
3083
3287
  const NAME_TX_BODY$6 = qname("p", "txBody", NS.pml);
3084
- const NAME_A_XFRM$2 = qname("a", "xfrm", NS.dml);
3085
- const NAME_OFF$4 = qname("a", "off", NS.dml);
3086
- const NAME_EXT$4 = qname("a", "ext", NS.dml);
3288
+ const NAME_A_XFRM$3 = qname("a", "xfrm", NS.dml);
3289
+ const NAME_OFF$5 = qname("a", "off", NS.dml);
3290
+ const NAME_EXT$5 = qname("a", "ext", NS.dml);
3087
3291
  const NAME_PRST_GEOM$2 = qname("a", "prstGeom", NS.dml);
3088
3292
  const NAME_AV_LST$2 = qname("a", "avLst", NS.dml);
3089
3293
  const NAME_BODY_PR$2 = qname("a", "bodyPr", NS.dml);
@@ -3092,12 +3296,12 @@ const NAME_P$2 = qname("a", "p", NS.dml);
3092
3296
  const NAME_R$2 = qname("a", "r", NS.dml);
3093
3297
  const NAME_RPR$2 = qname("a", "rPr", NS.dml);
3094
3298
  const NAME_T$3 = qname("a", "t", NS.dml);
3095
- const ATTR_ID$8 = qname("", "id", "");
3096
- const ATTR_NAME$5 = qname("", "name", "");
3097
- const ATTR_X$4 = qname("", "x", "");
3098
- const ATTR_Y$4 = qname("", "y", "");
3099
- const ATTR_CX$4 = qname("", "cx", "");
3100
- const ATTR_CY$4 = qname("", "cy", "");
3299
+ const ATTR_ID$9 = qname("", "id", "");
3300
+ const ATTR_NAME$7 = qname("", "name", "");
3301
+ const ATTR_X$5 = qname("", "x", "");
3302
+ const ATTR_Y$5 = qname("", "y", "");
3303
+ const ATTR_CX$5 = qname("", "cx", "");
3304
+ const ATTR_CY$5 = qname("", "cy", "");
3101
3305
  const ATTR_PRST$2 = qname("", "prst", "");
3102
3306
  const ATTR_WRAP = qname("", "wrap", "");
3103
3307
  const ATTR_RTL_COL = qname("", "rtlCol", "");
@@ -3124,10 +3328,10 @@ const buildShape = (opts) => {
3124
3328
  const name = opts.name ?? `${opts.preset} ${opts.id}`;
3125
3329
  const anchor = opts.textAnchor ?? "ctr";
3126
3330
  const children = [elem(NAME_NV_SP_PR$1, { children: [
3127
- elem(NAME_C_NV_PR$4, { attrs: [attr(ATTR_ID$8, String(opts.id)), attr(ATTR_NAME$5, name)] }),
3331
+ elem(NAME_C_NV_PR$5, { attrs: [attr(ATTR_ID$9, String(opts.id)), attr(ATTR_NAME$7, name)] }),
3128
3332
  elem(NAME_C_NV_SP_PR$1),
3129
- 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, {
3333
+ elem(NAME_NV_PR$6)
3334
+ ] }), elem(NAME_SP_PR$3, { children: [elem(NAME_A_XFRM$3, { children: [elem(NAME_OFF$5, { attrs: [attr(ATTR_X$5, String(emuCoordinate(opts.x, "addSlideShape: x"))), attr(ATTR_Y$5, String(emuCoordinate(opts.y, "addSlideShape: y")))] }), elem(NAME_EXT$5, { attrs: [attr(ATTR_CX$5, String(emuExtent(opts.w, "addSlideShape: w"))), attr(ATTR_CY$5, String(emuExtent(opts.h, "addSlideShape: h")))] })] }), elem(NAME_PRST_GEOM$2, {
3131
3335
  attrs: [attr(ATTR_PRST$2, opts.preset)],
3132
3336
  children: [elem(NAME_AV_LST$2)]
3133
3337
  })] })];
@@ -3139,23 +3343,31 @@ const buildShape = (opts) => {
3139
3343
  //#region src/internal/presentationml/connector-builder.ts
3140
3344
  const NAME_CXN_SP = qname("p", "cxnSp", NS.pml);
3141
3345
  const NAME_NV_CXN_SP_PR = qname("p", "nvCxnSpPr", NS.pml);
3142
- const NAME_C_NV_PR$3 = qname("p", "cNvPr", NS.pml);
3346
+ const NAME_C_NV_PR$4 = qname("p", "cNvPr", NS.pml);
3143
3347
  const NAME_C_NV_CXN_SP_PR = qname("p", "cNvCxnSpPr", NS.pml);
3144
- const NAME_NV_PR$4 = qname("p", "nvPr", NS.pml);
3348
+ const NAME_NV_PR$5 = qname("p", "nvPr", NS.pml);
3145
3349
  const NAME_SP_PR$2 = qname("p", "spPr", NS.pml);
3146
- const NAME_A_XFRM$1 = qname("a", "xfrm", NS.dml);
3147
- const NAME_OFF$3 = qname("a", "off", NS.dml);
3148
- const NAME_EXT$3 = qname("a", "ext", NS.dml);
3350
+ const NAME_A_XFRM$2 = qname("a", "xfrm", NS.dml);
3351
+ const NAME_OFF$4 = qname("a", "off", NS.dml);
3352
+ const NAME_EXT$4 = qname("a", "ext", NS.dml);
3149
3353
  const NAME_PRST_GEOM$1 = qname("a", "prstGeom", NS.dml);
3150
3354
  const NAME_AV_LST$1 = qname("a", "avLst", NS.dml);
3151
3355
  const NAME_LN = qname("a", "ln", NS.dml);
3152
3356
  const NAME_SOLID_FILL$3 = qname("a", "solidFill", NS.dml);
3153
- const ATTR_ID$7 = qname("", "id", "");
3154
- const ATTR_NAME$4 = qname("", "name", "");
3155
- const ATTR_X$3 = qname("", "x", "");
3156
- const ATTR_Y$3 = qname("", "y", "");
3157
- const ATTR_CX$3 = qname("", "cx", "");
3158
- const ATTR_CY$3 = qname("", "cy", "");
3357
+ const NAME_STYLE = qname("p", "style", NS.pml);
3358
+ const NAME_LN_REF = qname("a", "lnRef", NS.dml);
3359
+ const NAME_FILL_REF = qname("a", "fillRef", NS.dml);
3360
+ const NAME_EFFECT_REF = qname("a", "effectRef", NS.dml);
3361
+ const NAME_FONT_REF = qname("a", "fontRef", NS.dml);
3362
+ const NAME_SCHEME_CLR = qname("a", "schemeClr", NS.dml);
3363
+ const ATTR_IDX$4 = qname("", "idx", "");
3364
+ const ATTR_VAL$5 = qname("", "val", "");
3365
+ const ATTR_ID$8 = qname("", "id", "");
3366
+ const ATTR_NAME$6 = qname("", "name", "");
3367
+ const ATTR_X$4 = qname("", "x", "");
3368
+ const ATTR_Y$4 = qname("", "y", "");
3369
+ const ATTR_CX$4 = qname("", "cx", "");
3370
+ const ATTR_CY$4 = qname("", "cy", "");
3159
3371
  const ATTR_PRST$1 = qname("", "prst", "");
3160
3372
  const ATTR_W$1 = qname("", "w", "");
3161
3373
  const ATTR_FLIP_H = qname("", "flipH", "");
@@ -3164,9 +3376,9 @@ const ATTR_FLIP_V = qname("", "flipV", "");
3164
3376
  const buildConnector = (opts) => {
3165
3377
  const name = opts.name ?? `Straight Connector ${opts.id}`;
3166
3378
  const nvCxnSpPr = elem(NAME_NV_CXN_SP_PR, { children: [
3167
- elem(NAME_C_NV_PR$3, { attrs: [attr(ATTR_ID$7, String(opts.id)), attr(ATTR_NAME$4, name)] }),
3379
+ elem(NAME_C_NV_PR$4, { attrs: [attr(ATTR_ID$8, String(opts.id)), attr(ATTR_NAME$6, name)] }),
3168
3380
  elem(NAME_C_NV_CXN_SP_PR),
3169
- elem(NAME_NV_PR$4)
3381
+ elem(NAME_NV_PR$5)
3170
3382
  ] });
3171
3383
  const x = Math.min(opts.from.x, opts.to.x);
3172
3384
  const y = Math.min(opts.from.y, opts.to.y);
@@ -3177,21 +3389,79 @@ const buildConnector = (opts) => {
3177
3389
  const xfrmAttrs = [];
3178
3390
  if (flipH) xfrmAttrs.push(attr(ATTR_FLIP_H, "1"));
3179
3391
  if (flipV) xfrmAttrs.push(attr(ATTR_FLIP_V, "1"));
3180
- const spPrChildren = [elem(NAME_A_XFRM$1, {
3392
+ const xfrm = elem(NAME_A_XFRM$2, {
3181
3393
  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, {
3394
+ children: [elem(NAME_OFF$4, { attrs: [attr(ATTR_X$4, String(emuCoordinate(x, "addSlideLine: x"))), attr(ATTR_Y$4, String(emuCoordinate(y, "addSlideLine: y")))] }), elem(NAME_EXT$4, { attrs: [attr(ATTR_CX$4, String(emuExtent(cx, "addSlideLine: width"))), attr(ATTR_CY$4, String(emuExtent(cy, "addSlideLine: height")))] })]
3395
+ });
3396
+ const prstGeom = elem(NAME_PRST_GEOM$1, {
3184
3397
  attrs: [attr(ATTR_PRST$1, "line")],
3185
3398
  children: [elem(NAME_AV_LST$1)]
3186
- })];
3187
- if (opts.color !== void 0 || opts.widthEmu !== void 0) {
3399
+ });
3400
+ const hasExplicitLine = opts.color !== void 0 || opts.widthEmu !== void 0;
3401
+ const spPrChildren = [xfrm, prstGeom];
3402
+ if (hasExplicitLine) {
3188
3403
  const ln = elem(NAME_LN, {
3189
- attrs: opts.widthEmu !== void 0 ? [attr(ATTR_W$1, String(Math.round(opts.widthEmu)))] : [],
3404
+ attrs: opts.widthEmu !== void 0 ? [attr(ATTR_W$1, String(lineWidthEmu(opts.widthEmu, "addSlideLine: widthEmu")))] : [],
3190
3405
  children: opts.color !== void 0 ? [elem(NAME_SOLID_FILL$3, { children: [buildColorElement(opts.color)] })] : []
3191
3406
  });
3192
3407
  spPrChildren.push(ln);
3193
3408
  }
3194
- return elem(NAME_CXN_SP, { children: [nvCxnSpPr, elem(NAME_SP_PR$2, { children: spPrChildren })] });
3409
+ const children = [nvCxnSpPr, elem(NAME_SP_PR$2, { children: spPrChildren })];
3410
+ if (!hasExplicitLine) {
3411
+ const styleRef = (name, idx, clr) => elem(name, {
3412
+ attrs: [attr(ATTR_IDX$4, idx)],
3413
+ children: [elem(NAME_SCHEME_CLR, { attrs: [attr(ATTR_VAL$5, clr)] })]
3414
+ });
3415
+ children.push(elem(NAME_STYLE, { children: [
3416
+ styleRef(NAME_LN_REF, "1", "accent1"),
3417
+ styleRef(NAME_FILL_REF, "0", "accent1"),
3418
+ styleRef(NAME_EFFECT_REF, "0", "accent1"),
3419
+ styleRef(NAME_FONT_REF, "minor", "tx1")
3420
+ ] }));
3421
+ }
3422
+ return elem(NAME_CXN_SP, { children });
3423
+ };
3424
+ //#endregion
3425
+ //#region src/internal/presentationml/group-builder.ts
3426
+ const NAME_GRP_SP = qname("p", "grpSp", NS.pml);
3427
+ const NAME_NV_GRP_SP_PR$1 = qname("p", "nvGrpSpPr", NS.pml);
3428
+ const NAME_C_NV_PR$3 = qname("p", "cNvPr", NS.pml);
3429
+ const NAME_C_NV_GRP_SP_PR$1 = qname("p", "cNvGrpSpPr", NS.pml);
3430
+ const NAME_NV_PR$4 = qname("p", "nvPr", NS.pml);
3431
+ const NAME_GRP_SP_PR$1 = qname("p", "grpSpPr", NS.pml);
3432
+ const NAME_A_XFRM$1 = qname("a", "xfrm", NS.dml);
3433
+ const NAME_OFF$3 = qname("a", "off", NS.dml);
3434
+ const NAME_EXT$3 = qname("a", "ext", NS.dml);
3435
+ const NAME_CH_OFF = qname("a", "chOff", NS.dml);
3436
+ const NAME_CH_EXT = qname("a", "chExt", NS.dml);
3437
+ const ATTR_ID$7 = qname("", "id", "");
3438
+ const ATTR_NAME$5 = qname("", "name", "");
3439
+ const ATTR_X$3 = qname("", "x", "");
3440
+ const ATTR_Y$3 = qname("", "y", "");
3441
+ const ATTR_CX$3 = qname("", "cx", "");
3442
+ const ATTR_CY$3 = qname("", "cy", "");
3443
+ /** Returns a `<p:grpSp>` wrapping `opts.children` under one transform. */
3444
+ const buildGroup = (opts) => {
3445
+ const name = opts.name ?? `Group ${opts.id}`;
3446
+ const nvGrpSpPr = elem(NAME_NV_GRP_SP_PR$1, { children: [
3447
+ elem(NAME_C_NV_PR$3, { attrs: [attr(ATTR_ID$7, String(opts.id)), attr(ATTR_NAME$5, name)] }),
3448
+ elem(NAME_C_NV_GRP_SP_PR$1),
3449
+ elem(NAME_NV_PR$4)
3450
+ ] });
3451
+ const x = emuCoordinate(opts.x, "groupShapes: x");
3452
+ const y = emuCoordinate(opts.y, "groupShapes: y");
3453
+ const cx = emuExtent(opts.w, "groupShapes: w");
3454
+ const cy = emuExtent(opts.h, "groupShapes: h");
3455
+ return elem(NAME_GRP_SP, { children: [
3456
+ nvGrpSpPr,
3457
+ elem(NAME_GRP_SP_PR$1, { children: [elem(NAME_A_XFRM$1, { children: [
3458
+ elem(NAME_OFF$3, { attrs: [attr(ATTR_X$3, String(x)), attr(ATTR_Y$3, String(y))] }),
3459
+ elem(NAME_EXT$3, { attrs: [attr(ATTR_CX$3, String(cx)), attr(ATTR_CY$3, String(cy))] }),
3460
+ elem(NAME_CH_OFF, { attrs: [attr(ATTR_X$3, String(x)), attr(ATTR_Y$3, String(y))] }),
3461
+ elem(NAME_CH_EXT, { attrs: [attr(ATTR_CX$3, String(cx)), attr(ATTR_CY$3, String(cy))] })
3462
+ ] })] }),
3463
+ ...opts.children
3464
+ ] });
3195
3465
  };
3196
3466
  //#endregion
3197
3467
  //#region src/internal/presentationml/picture-builder.ts
@@ -3212,7 +3482,7 @@ const NAME_PRST_GEOM = qname("a", "prstGeom", NS.dml);
3212
3482
  const NAME_AV_LST = qname("a", "avLst", NS.dml);
3213
3483
  const NAME_PIC_LOCKS = qname("a", "picLocks", NS.dml);
3214
3484
  const ATTR_ID$6 = qname("", "id", "");
3215
- const ATTR_NAME$3 = qname("", "name", "");
3485
+ const ATTR_NAME$4 = qname("", "name", "");
3216
3486
  const ATTR_X$2 = qname("", "x", "");
3217
3487
  const ATTR_Y$2 = qname("", "y", "");
3218
3488
  const ATTR_CX$2 = qname("", "cx", "");
@@ -3226,12 +3496,12 @@ const buildPicture = (opts) => {
3226
3496
  const cNvPicPr = elem(NAME_C_NV_PIC_PR, { children: [elem(NAME_PIC_LOCKS, { attrs: opts.lockAspect ?? true ? [attr(ATTR_NO_CHANGE_ASPECT$1, "1")] : [] })] });
3227
3497
  return elem(NAME_PIC, { children: [
3228
3498
  elem(NAME_NV_PIC_PR, { children: [
3229
- elem(NAME_C_NV_PR$2, { attrs: [attr(ATTR_ID$6, String(opts.id)), attr(ATTR_NAME$3, name)] }),
3499
+ elem(NAME_C_NV_PR$2, { attrs: [attr(ATTR_ID$6, String(opts.id)), attr(ATTR_NAME$4, name)] }),
3230
3500
  cNvPicPr,
3231
3501
  elem(NAME_NV_PR$3)
3232
3502
  ] }),
3233
3503
  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, {
3504
+ 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
3505
  attrs: [attr(ATTR_PRST, "rect")],
3236
3506
  children: [elem(NAME_AV_LST)]
3237
3507
  })] })
@@ -3271,14 +3541,14 @@ const NAME_SRGB_CLR$2 = qname("a", "srgbClr", NS.dml);
3271
3541
  const NAME_T$2 = qname("a", "t", NS.dml);
3272
3542
  const NAME_PPR = qname("a", "pPr", NS.dml);
3273
3543
  const NAME_BU_NONE = qname("a", "buNone", NS.dml);
3274
- const ATTR_VAL$3 = qname("", "val", "");
3544
+ const ATTR_VAL$4 = qname("", "val", "");
3275
3545
  const ATTR_MAR_L = qname("", "marL", "");
3276
3546
  const ATTR_MAR_R = qname("", "marR", "");
3277
3547
  const ATTR_MAR_T = qname("", "marT", "");
3278
3548
  const ATTR_MAR_B = qname("", "marB", "");
3279
3549
  const ATTR_INDENT = qname("", "indent", "");
3280
3550
  const ATTR_ID$5 = qname("", "id", "");
3281
- const ATTR_NAME$2 = qname("", "name", "");
3551
+ const ATTR_NAME$3 = qname("", "name", "");
3282
3552
  const ATTR_NO_GRP$1 = qname("", "noGrp", "");
3283
3553
  const ATTR_X$1 = qname("", "x", "");
3284
3554
  const ATTR_Y$1 = qname("", "y", "");
@@ -3290,30 +3560,29 @@ const ATTR_H = qname("", "h", "");
3290
3560
  const ATTR_FIRST_ROW = qname("", "firstRow", "");
3291
3561
  const ATTR_BAND_ROW = qname("", "bandRow", "");
3292
3562
  const ATTR_LANG$1 = qname("", "lang", "");
3293
- const ATTR_XML_SPACE = qname("xml", "space", NS.xml);
3294
3563
  const buildCellRunProps = (textColorHex) => {
3295
3564
  const langAttr = attr(ATTR_LANG$1, "en-US");
3296
3565
  if (textColorHex === void 0) return elem(NAME_RPR$1, { attrs: [langAttr] });
3297
- const solidFill = elem(NAME_SOLID_FILL$2, { children: [elem(NAME_SRGB_CLR$2, { attrs: [attr(ATTR_VAL$3, (textColorHex.startsWith("#") ? textColorHex.slice(1) : textColorHex).toUpperCase())] })] });
3566
+ const solidFill = elem(NAME_SOLID_FILL$2, { children: [elem(NAME_SRGB_CLR$2, { attrs: [attr(ATTR_VAL$4, (textColorHex.startsWith("#") ? textColorHex.slice(1) : textColorHex).toUpperCase())] })] });
3298
3567
  return elem(NAME_RPR$1, {
3299
3568
  attrs: [langAttr],
3300
3569
  children: [solidFill]
3301
3570
  });
3302
3571
  };
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, {
3572
+ const buildCellParagraph = (line, textColorHex) => {
3573
+ const pPr = elem(NAME_PPR, {
3310
3574
  attrs: [attr(ATTR_MAR_L, "0"), attr(ATTR_INDENT, "0")],
3311
3575
  children: [elem(NAME_BU_NONE)]
3312
- }), r] });
3576
+ });
3577
+ const t = elem(NAME_T$2, { children: line.length > 0 ? [text(line)] : [] });
3578
+ return elem(NAME_P$1, { children: [pPr, elem(NAME_R$1, { children: [buildCellRunProps(textColorHex), t] })] });
3579
+ };
3580
+ const buildTextCellBody = (value, textColorHex) => {
3581
+ const paragraphs = (value.length === 0 ? [""] : value.split("\n")).map((line) => buildCellParagraph(line, textColorHex));
3313
3582
  return elem(NAME_TX_BODY$5, { children: [
3314
3583
  elem(NAME_BODY_PR$1),
3315
3584
  elem(NAME_LST_STYLE$1),
3316
- p
3585
+ ...paragraphs
3317
3586
  ] });
3318
3587
  };
3319
3588
  const buildCellProps = () => elem(NAME_TC_PR, { attrs: [
@@ -3328,7 +3597,7 @@ const buildTableCell = (value, textColorHex) => {
3328
3597
  };
3329
3598
  /** @internal — used by row-mutation paths in the public API. */
3330
3599
  const buildTableRow = (cells, h, textColorHex) => elem(NAME_TR, {
3331
- attrs: [attr(ATTR_H, String(Math.round(h)))],
3600
+ attrs: [attr(ATTR_H, String(emuExtent(h, "addSlideTable: row height")))],
3332
3601
  children: cells.map((value) => buildTableCell(value, textColorHex))
3333
3602
  });
3334
3603
  const equalShares = (total, n) => {
@@ -3354,18 +3623,18 @@ const buildTable = (opts) => {
3354
3623
  if (rowHeights.length !== rows.length) throw new Error(`addSlideTable: rowHeights has ${rowHeights.length} entries; expected ${rows.length}`);
3355
3624
  const name = opts.name ?? `Table ${opts.id}`;
3356
3625
  const nvGraphicFramePr = elem(NAME_NV_GRAPHIC_FRAME_PR$1, { children: [
3357
- elem(NAME_C_NV_PR$1, { attrs: [attr(ATTR_ID$5, String(opts.id)), attr(ATTR_NAME$2, name)] }),
3626
+ elem(NAME_C_NV_PR$1, { attrs: [attr(ATTR_ID$5, String(opts.id)), attr(ATTR_NAME$3, name)] }),
3358
3627
  elem(NAME_C_NV_GRAPHIC_FRAME_PR$1, { children: [elem(NAME_GRAPHIC_FRAME_LOCKS, { attrs: [attr(ATTR_NO_GRP$1, "1")] })] }),
3359
3628
  elem(NAME_NV_PR$2)
3360
3629
  ] });
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)] });
3630
+ 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")))] })] });
3631
+ const tableStyleId = elem(NAME_TABLE_STYLE_ID, { children: [text(opts.styleId === void 0 ? DEFAULT_TABLE_STYLE_ID : normalizeGuid(opts.styleId, "addSlideTable: styleId"))] });
3363
3632
  const tbl = elem(NAME_TBL, { children: [
3364
3633
  elem(NAME_TBL_PR, {
3365
3634
  attrs: [attr(ATTR_FIRST_ROW, opts.firstRow ?? true ? "1" : "0"), attr(ATTR_BAND_ROW, opts.bandRow ?? true ? "1" : "0")],
3366
3635
  children: [tableStyleId]
3367
3636
  }),
3368
- elem(NAME_TBL_GRID, { children: colWidths.map((w) => elem(NAME_GRID_COL, { attrs: [attr(ATTR_W, String(Math.round(w)))] })) }),
3637
+ elem(NAME_TBL_GRID, { children: colWidths.map((w) => elem(NAME_GRID_COL, { attrs: [attr(ATTR_W, String(emuExtent(w, "addSlideTable: column width")))] })) }),
3369
3638
  ...rows.map((row, i) => buildTableRow(row, rowHeights[i] ?? 0, opts.textColorHex))
3370
3639
  ] });
3371
3640
  return elem(NAME_GRAPHIC_FRAME$1, { children: [
@@ -3379,7 +3648,7 @@ const buildTable = (opts) => {
3379
3648
  };
3380
3649
  //#endregion
3381
3650
  //#region src/internal/presentationml/notes-slide-builder.ts
3382
- const NAME_NOTES_SLIDE = qname("p", "notesSlide", NS.pml);
3651
+ const NAME_NOTES_SLIDE = qname("p", "notes", NS.pml);
3383
3652
  const NAME_CSLD$1 = qname("p", "cSld", NS.pml);
3384
3653
  const NAME_SP_TREE$1 = qname("p", "spTree", NS.pml);
3385
3654
  const NAME_NV_GRP_SP_PR = qname("p", "nvGrpSpPr", NS.pml);
@@ -3403,7 +3672,7 @@ const NAME_RPR = qname("a", "rPr", NS.dml);
3403
3672
  const NAME_T$1 = qname("a", "t", NS.dml);
3404
3673
  const NAME_SP_LOCKS = qname("a", "spLocks", NS.dml);
3405
3674
  const ATTR_ID$4 = qname("", "id", "");
3406
- const ATTR_NAME$1 = qname("", "name", "");
3675
+ const ATTR_NAME$2 = qname("", "name", "");
3407
3676
  const ATTR_NO_GRP = qname("", "noGrp", "");
3408
3677
  const ATTR_NO_ROT = qname("", "noRot", "");
3409
3678
  const ATTR_NO_CHANGE_ASPECT = qname("", "noChangeAspect", "");
@@ -3412,14 +3681,14 @@ const ATTR_IDX$3 = qname("", "idx", "");
3412
3681
  const ATTR_LANG = qname("", "lang", "");
3413
3682
  const buildRootGroup = () => {
3414
3683
  return elem(NAME_NV_GRP_SP_PR, { children: [
3415
- elem(NAME_C_NV_PR, { attrs: [attr(ATTR_ID$4, "1"), attr(ATTR_NAME$1, "")] }),
3684
+ elem(NAME_C_NV_PR, { attrs: [attr(ATTR_ID$4, "1"), attr(ATTR_NAME$2, "")] }),
3416
3685
  elem(NAME_C_NV_GRP_SP_PR),
3417
3686
  elem(NAME_NV_PR$1)
3418
3687
  ] });
3419
3688
  };
3420
3689
  const buildSldImgPlaceholder = (id) => {
3421
3690
  return elem(NAME_SP, { children: [elem(NAME_NV_SP_PR, { children: [
3422
- elem(NAME_C_NV_PR, { attrs: [attr(ATTR_ID$4, String(id)), attr(ATTR_NAME$1, `Slide Image Placeholder ${id - 1}`)] }),
3691
+ elem(NAME_C_NV_PR, { attrs: [attr(ATTR_ID$4, String(id)), attr(ATTR_NAME$2, `Slide Image Placeholder ${id - 1}`)] }),
3423
3692
  elem(NAME_C_NV_SP_PR, { children: [elem(NAME_SP_LOCKS, { attrs: [
3424
3693
  attr(ATTR_NO_GRP, "1"),
3425
3694
  attr(ATTR_NO_ROT, "1"),
@@ -3436,7 +3705,7 @@ const buildNotesParagraphs = (notes) => {
3436
3705
  };
3437
3706
  const buildNotesBodyPlaceholder = (id, notes) => {
3438
3707
  const nvSpPr = elem(NAME_NV_SP_PR, { children: [
3439
- elem(NAME_C_NV_PR, { attrs: [attr(ATTR_ID$4, String(id)), attr(ATTR_NAME$1, `Notes Placeholder ${id - 1}`)] }),
3708
+ elem(NAME_C_NV_PR, { attrs: [attr(ATTR_ID$4, String(id)), attr(ATTR_NAME$2, `Notes Placeholder ${id - 1}`)] }),
3440
3709
  elem(NAME_C_NV_SP_PR, { children: [elem(NAME_SP_LOCKS, { attrs: [attr(ATTR_NO_GRP, "1")] })] }),
3441
3710
  elem(NAME_NV_PR$1, { children: [elem(NAME_PH, { attrs: [attr(ATTR_TYPE$1, "body"), attr(ATTR_IDX$3, "1")] })] })
3442
3711
  ] });
@@ -3452,7 +3721,7 @@ const buildNotesBodyPlaceholder = (id, notes) => {
3452
3721
  ] });
3453
3722
  };
3454
3723
  /**
3455
- * Returns a fresh `<p:notesSlide>` document with the given notes text in
3724
+ * Returns a fresh `<p:notes>` document with the given notes text in
3456
3725
  * the body placeholder. Designed for callers that need to create the
3457
3726
  * notesSlide part from scratch (no existing notes file yet for the
3458
3727
  * slide).
@@ -3493,12 +3762,71 @@ const ATTR_ADV_TM = qname("", "advTm", "");
3493
3762
  const ATTR_DIR = qname("", "dir", "");
3494
3763
  const ATTR_ORIENT = qname("", "orient", "");
3495
3764
  const ATTR_THRU_BLK = qname("", "thruBlk", "");
3765
+ const DIR_ORIENT = new Set(["horz", "vert"]);
3766
+ const DIR_SIDE = new Set([
3767
+ "l",
3768
+ "u",
3769
+ "r",
3770
+ "d"
3771
+ ]);
3772
+ const DIR_CORNER = new Set([
3773
+ "lu",
3774
+ "ru",
3775
+ "ld",
3776
+ "rd"
3777
+ ]);
3778
+ const DIR_EIGHT = new Set([...DIR_SIDE, ...DIR_CORNER]);
3779
+ const DIR_IN_OUT = new Set(["in", "out"]);
3780
+ const DIR_DOMAINS = {
3781
+ blinds: DIR_ORIENT,
3782
+ checker: DIR_ORIENT,
3783
+ comb: DIR_ORIENT,
3784
+ randomBar: DIR_ORIENT,
3785
+ push: DIR_SIDE,
3786
+ wipe: DIR_SIDE,
3787
+ cover: DIR_EIGHT,
3788
+ pull: DIR_EIGHT,
3789
+ strips: DIR_CORNER,
3790
+ zoom: DIR_IN_OUT,
3791
+ split: DIR_IN_OUT
3792
+ };
3793
+ const THRU_BLK_EFFECTS = new Set(["fade", "cut"]);
3794
+ const TRANSITION_EFFECTS = [
3795
+ "blinds",
3796
+ "checker",
3797
+ "circle",
3798
+ "dissolve",
3799
+ "comb",
3800
+ "cover",
3801
+ "cut",
3802
+ "diamond",
3803
+ "fade",
3804
+ "newsflash",
3805
+ "plus",
3806
+ "pull",
3807
+ "push",
3808
+ "random",
3809
+ "randomBar",
3810
+ "split",
3811
+ "strips",
3812
+ "wedge",
3813
+ "wheel",
3814
+ "wipe",
3815
+ "zoom"
3816
+ ];
3496
3817
  const buildEffectElement = (opts) => {
3497
- const name = qname("p", opts.effect, NS.pml);
3818
+ if (opts.effect === "none") return null;
3819
+ const name = qname("p", oneOf(opts.effect, TRANSITION_EFFECTS, "setSlideTransition: effect"), NS.pml);
3498
3820
  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"));
3821
+ if (opts.direction !== void 0) {
3822
+ const domain = DIR_DOMAINS[opts.effect];
3823
+ if (domain !== void 0) {
3824
+ if (!domain.has(opts.direction)) throw new Error(`setSlideTransition: direction "${opts.direction}" is not valid for effect "${opts.effect}" (allowed: ${[...domain].join(", ")})`);
3825
+ attrs.push(attr(ATTR_DIR, opts.direction));
3826
+ }
3827
+ }
3828
+ if (opts.orientation !== void 0 && opts.effect === "split") attrs.push(attr(ATTR_ORIENT, opts.orientation));
3829
+ if (opts.thruBlack && THRU_BLK_EFFECTS.has(opts.effect)) attrs.push(attr(ATTR_THRU_BLK, "1"));
3502
3830
  return elem(name, { attrs });
3503
3831
  };
3504
3832
  /** Returns a complete `<p:transition>` element. */
@@ -3506,10 +3834,14 @@ const buildTransition = (opts) => {
3506
3834
  const attrs = [];
3507
3835
  if (opts.speed !== void 0) attrs.push(attr(ATTR_SPD, opts.speed));
3508
3836
  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))));
3837
+ if (opts.advanceAfterMs !== void 0) {
3838
+ const advTm = unsignedIntMs(opts.advanceAfterMs, "setSlideTransition: advanceAfterMs");
3839
+ attrs.push(attr(ATTR_ADV_TM, String(advTm)));
3840
+ }
3841
+ const effect = buildEffectElement(opts);
3510
3842
  return elem(NAME_TRANSITION, {
3511
3843
  attrs,
3512
- children: [buildEffectElement(opts)]
3844
+ children: effect === null ? [] : [effect]
3513
3845
  });
3514
3846
  };
3515
3847
  //#endregion
@@ -3554,7 +3886,7 @@ const ATTR_CONCURRENT = qname("", "concurrent", "");
3554
3886
  const ATTR_NEXT_AC = qname("", "nextAc", "");
3555
3887
  const ATTR_SPID = qname("", "spid", "");
3556
3888
  const ATTR_EVT = qname("", "evt", "");
3557
- const ATTR_VAL$2 = qname("", "val", "");
3889
+ const ATTR_VAL$3 = qname("", "val", "");
3558
3890
  const ATTR_CALCMODE = qname("", "calcmode", "");
3559
3891
  const ATTR_VALUE_TYPE = qname("", "valueType", "");
3560
3892
  const ATTR_ADDITIVE = qname("", "additive", "");
@@ -3598,7 +3930,7 @@ const buildSetVisibility = (spid, visible) => {
3598
3930
  }),
3599
3931
  tgt,
3600
3932
  attrName
3601
- ] }), elem(NAME_TO, { children: [elem(NAME_STR_VAL, { attrs: [attr(ATTR_VAL$2, visible ? "visible" : "hidden")] })] })] });
3933
+ ] }), elem(NAME_TO, { children: [elem(NAME_STR_VAL, { attrs: [attr(ATTR_VAL$3, visible ? "visible" : "hidden")] })] })] });
3602
3934
  };
3603
3935
  const buildOpacityAnim = (spid, durationMs, fadeIn) => {
3604
3936
  const tgt = elem(NAME_TGT_EL, { children: [elem(NAME_SP_TGT, { attrs: [attr(ATTR_SPID, String(spid))] })] });
@@ -3623,10 +3955,10 @@ const buildOpacityAnim = (spid, durationMs, fadeIn) => {
3623
3955
  const toVal = fadeIn ? "1" : "0";
3624
3956
  const tavLst = elem(NAME_TAV_LST, { children: [elem(NAME_TAV, {
3625
3957
  attrs: [attr(ATTR_TM, "0")],
3626
- children: [elem(NAME_VAL$1, { children: [elem(NAME_FLT_VAL, { attrs: [attr(ATTR_VAL$2, fromVal)] })] })]
3958
+ children: [elem(NAME_VAL$1, { children: [elem(NAME_FLT_VAL, { attrs: [attr(ATTR_VAL$3, fromVal)] })] })]
3627
3959
  }), elem(NAME_TAV, {
3628
3960
  attrs: [attr(ATTR_TM, "100000")],
3629
- children: [elem(NAME_VAL$1, { children: [elem(NAME_FLT_VAL, { attrs: [attr(ATTR_VAL$2, toVal)] })] })]
3961
+ children: [elem(NAME_VAL$1, { children: [elem(NAME_FLT_VAL, { attrs: [attr(ATTR_VAL$3, toVal)] })] })]
3630
3962
  })] });
3631
3963
  return elem(NAME_ANIM, {
3632
3964
  attrs: [attr(ATTR_CALCMODE, "lin"), attr(ATTR_VALUE_TYPE, "num")],
@@ -3639,7 +3971,7 @@ const buildOpacityAnim = (spid, durationMs, fadeIn) => {
3639
3971
  */
3640
3972
  const buildSingleEffectTiming = (spid, opts) => {
3641
3973
  const preset = PRESETS[opts.effect];
3642
- const duration = opts.durationMs ?? 500;
3974
+ const duration = opts.durationMs === void 0 ? 500 : unsignedIntMs(opts.durationMs, "setShapeAnimation: durationMs");
3643
3975
  const isFade = opts.effect === "fadeIn" || opts.effect === "fadeOut";
3644
3976
  const isEntrance = preset.presetClass === "entr";
3645
3977
  const effectChildren = [];
@@ -3708,7 +4040,7 @@ const NAME_CM = qname("p", "cm", NS.pml);
3708
4040
  const NAME_POS = qname("p", "pos", NS.pml);
3709
4041
  const NAME_TEXT = qname("p", "text", NS.pml);
3710
4042
  const ATTR_ID$2 = qname("", "id", "");
3711
- const ATTR_NAME = qname("", "name", "");
4043
+ const ATTR_NAME$1 = qname("", "name", "");
3712
4044
  const ATTR_INITIALS = qname("", "initials", "");
3713
4045
  const ATTR_LAST_IDX = qname("", "lastIdx", "");
3714
4046
  const ATTR_CLR_IDX = qname("", "clrIdx", "");
@@ -3722,7 +4054,7 @@ const readCommentAuthorList = (root) => {
3722
4054
  const authors = [];
3723
4055
  for (const el of allChildElements(root, NAME_CM_AUTHOR)) {
3724
4056
  const idRaw = getAttrValue(el, ATTR_ID$2);
3725
- const nameVal = getAttrValue(el, ATTR_NAME);
4057
+ const nameVal = getAttrValue(el, ATTR_NAME$1);
3726
4058
  const initialsVal = getAttrValue(el, ATTR_INITIALS);
3727
4059
  const lastIdxRaw = getAttrValue(el, ATTR_LAST_IDX);
3728
4060
  const clrIdxRaw = getAttrValue(el, ATTR_CLR_IDX);
@@ -3782,7 +4114,7 @@ const readCommentList = (root) => {
3782
4114
  const commentAuthorElement = (a) => {
3783
4115
  return elem(NAME_CM_AUTHOR, { attrs: [
3784
4116
  attr(ATTR_ID$2, String(a.id)),
3785
- attr(ATTR_NAME, a.name),
4117
+ attr(ATTR_NAME$1, a.name),
3786
4118
  attr(ATTR_INITIALS, a.initials),
3787
4119
  attr(ATTR_LAST_IDX, String(a.lastIdx)),
3788
4120
  attr(ATTR_CLR_IDX, String(a.clrIdx ?? 0))
@@ -3940,6 +4272,23 @@ const NAME_THEME_ELEMENTS = qname("a", "themeElements", NS.dml);
3940
4272
  const NAME_CLR_SCHEME = qname("a", "clrScheme", NS.dml);
3941
4273
  const NAME_SRGB_CLR$1 = qname("a", "srgbClr", NS.dml);
3942
4274
  const NAME_SYS_CLR = qname("a", "sysClr", NS.dml);
4275
+ const ATTR_VAL$2 = qname("", "val", "");
4276
+ const ATTR_NAME = qname("", "name", "");
4277
+ const ATTR_TYPEFACE$1 = qname("", "typeface", "");
4278
+ const CLR_SCHEME_SLOTS = [
4279
+ ["dark1", "dk1"],
4280
+ ["light1", "lt1"],
4281
+ ["dark2", "dk2"],
4282
+ ["light2", "lt2"],
4283
+ ["accent1", "accent1"],
4284
+ ["accent2", "accent2"],
4285
+ ["accent3", "accent3"],
4286
+ ["accent4", "accent4"],
4287
+ ["accent5", "accent5"],
4288
+ ["accent6", "accent6"],
4289
+ ["hyperlink", "hlink"],
4290
+ ["followedHyperlink", "folHlink"]
4291
+ ];
3943
4292
  const readSchemeSlot = (parent, local) => {
3944
4293
  const slot = firstChildElement(parent, qname("a", local, NS.dml));
3945
4294
  if (!slot) return "";
@@ -3966,6 +4315,13 @@ const readSchemeSlot = (parent, local) => {
3966
4315
  */
3967
4316
  const getPresentationTheme = (pres) => themeFromPackage(pres[INTERNAL_PACKAGE]);
3968
4317
  /**
4318
+ * Returns the package's first theme part (by part name, alphabetical),
4319
+ * matching the "first theme wins" v1 semantics documented on
4320
+ * {@link getPresentationTheme}. Shared by every theme reader/writer so
4321
+ * they agree on which theme a multi-master deck exposes.
4322
+ */
4323
+ const firstThemePart = (pkg) => pkg.parts.filter((p) => p.contentType === THEME_CONTENT_TYPE).sort((a, b) => a.name.localeCompare(b.name))[0];
4324
+ /**
3969
4325
  * Package-level theme reader behind {@link getPresentationTheme}. Exposed so
3970
4326
  * helpers holding only a package handle (e.g. color baking off a `SlideData`)
3971
4327
  * can read the theme without a `PresentationData`.
@@ -3973,7 +4329,7 @@ const getPresentationTheme = (pres) => themeFromPackage(pres[INTERNAL_PACKAGE]);
3973
4329
  * @internal
3974
4330
  */
3975
4331
  const themeFromPackage = (pkg) => {
3976
- const themePart = pkg.parts.filter((p) => p.contentType === THEME_CONTENT_TYPE).sort((a, b) => a.name.localeCompare(b.name))[0];
4332
+ const themePart = firstThemePart(pkg);
3977
4333
  if (!themePart) return null;
3978
4334
  const root = parseXml(decode$1(themePart.data)).root;
3979
4335
  const themeElements = firstChildElement(root, NAME_THEME_ELEMENTS);
@@ -4011,7 +4367,8 @@ const readTypeface = (parent, local) => {
4011
4367
  * name); per-master font lookup will land if needed.
4012
4368
  */
4013
4369
  const getPresentationFonts = (pres) => {
4014
- const themePart = pres[INTERNAL_PACKAGE].parts.filter((p) => p.contentType === THEME_CONTENT_TYPE).sort((a, b) => a.name.localeCompare(b.name))[0];
4370
+ const pkg = pres[INTERNAL_PACKAGE];
4371
+ const themePart = firstThemePart(pkg);
4015
4372
  if (!themePart) return null;
4016
4373
  const root = parseXml(decode$1(themePart.data)).root;
4017
4374
  const themeElements = firstChildElement(root, NAME_THEME_ELEMENTS);
@@ -4029,6 +4386,80 @@ const getPresentationFonts = (pres) => {
4029
4386
  minorComplexScript: readTypeface(minorFont, "cs")
4030
4387
  };
4031
4388
  };
4389
+ /**
4390
+ * Overwrites the named slots of the package's first theme's color
4391
+ * scheme (`<a:clrScheme>`), leaving every other slot untouched. Slot
4392
+ * values are `#RRGGBB` (or 3-digit `#RGB`) strings; every branded
4393
+ * `srgbClr`/`sysClr` slot is normalized to a plain `<a:srgbClr>` on
4394
+ * write, since a theme slot is never a scheme-color reference.
4395
+ *
4396
+ * As with `getPresentationTheme`, multi-master decks are branded via
4397
+ * their first theme part only — call this once per theme part if a
4398
+ * deck's masters carry different themes.
4399
+ *
4400
+ * Throws if the presentation has no theme part, or if a provided color
4401
+ * isn't a valid `#RRGGBB` string.
4402
+ */
4403
+ const setPresentationTheme = (pres, theme) => {
4404
+ const pkg = pres[INTERNAL_PACKAGE];
4405
+ const themePart = firstThemePart(pkg);
4406
+ if (!themePart) throw new Error("setPresentationTheme: presentation has no theme part");
4407
+ const doc = parseXml(decode$1(themePart.data));
4408
+ const themeElements = firstChildElement(doc.root, NAME_THEME_ELEMENTS);
4409
+ if (!themeElements) throw new Error("setPresentationTheme: theme part has no <a:themeElements>");
4410
+ const clrScheme = firstChildElement(themeElements, NAME_CLR_SCHEME);
4411
+ if (!clrScheme) throw new Error("setPresentationTheme: theme part has no <a:clrScheme>");
4412
+ if (theme.name !== void 0) {
4413
+ clrScheme.attrs = clrScheme.attrs.filter((a) => a.name.localName !== "name");
4414
+ clrScheme.attrs.push(attr(ATTR_NAME, theme.name));
4415
+ }
4416
+ for (const [field, local] of CLR_SCHEME_SLOTS) {
4417
+ const value = theme[field];
4418
+ if (value === void 0) continue;
4419
+ const hex = parseSrgbHex(value);
4420
+ if (hex === null) throw new Error(`setPresentationTheme: "${field}" must be a #RRGGBB or #RGB color, got ${JSON.stringify(value)}`);
4421
+ const slotName = qname("a", local, NS.dml);
4422
+ const idx = clrScheme.children.findIndex((c) => c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === local);
4423
+ if (idx < 0) throw new Error(`setPresentationTheme: clrScheme is missing <a:${local}>`);
4424
+ clrScheme.children[idx] = elem(slotName, { children: [elem(NAME_SRGB_CLR$1, { attrs: [attr(ATTR_VAL$2, hex)] })] });
4425
+ }
4426
+ themePart.data = encode$1(serializeXml(doc));
4427
+ };
4428
+ const setTypeface = (fontCollection, local, typeface) => {
4429
+ const el = firstChildElement(fontCollection, qname("a", local, NS.dml));
4430
+ if (!el) throw new Error(`setPresentationFonts: fontScheme is missing <a:${local}>`);
4431
+ el.attrs = el.attrs.filter((a) => a.name.localName !== "typeface");
4432
+ el.attrs.push(attr(ATTR_TYPEFACE$1, typeface));
4433
+ };
4434
+ /**
4435
+ * Overwrites the named typefaces of the package's first theme's font
4436
+ * scheme (major = headings, minor = body), leaving unset fields
4437
+ * untouched. As with `setPresentationTheme`, only the first theme part
4438
+ * is branded.
4439
+ *
4440
+ * Throws if the presentation has no theme part.
4441
+ */
4442
+ const setPresentationFonts = (pres, fonts) => {
4443
+ const pkg = pres[INTERNAL_PACKAGE];
4444
+ const themePart = firstThemePart(pkg);
4445
+ if (!themePart) throw new Error("setPresentationFonts: presentation has no theme part");
4446
+ const doc = parseXml(decode$1(themePart.data));
4447
+ const themeElements = firstChildElement(doc.root, NAME_THEME_ELEMENTS);
4448
+ if (!themeElements) throw new Error("setPresentationFonts: theme part has no <a:themeElements>");
4449
+ const fontScheme = firstChildElement(themeElements, qname("a", "fontScheme", NS.dml));
4450
+ if (!fontScheme) throw new Error("setPresentationFonts: theme part has no <a:fontScheme>");
4451
+ const majorFont = firstChildElement(fontScheme, qname("a", "majorFont", NS.dml));
4452
+ if (!majorFont) throw new Error("setPresentationFonts: fontScheme has no <a:majorFont>");
4453
+ const minorFont = firstChildElement(fontScheme, qname("a", "minorFont", NS.dml));
4454
+ if (!minorFont) throw new Error("setPresentationFonts: fontScheme has no <a:minorFont>");
4455
+ if (fonts.majorLatin !== void 0) setTypeface(majorFont, "latin", fonts.majorLatin);
4456
+ if (fonts.majorEastAsian !== void 0) setTypeface(majorFont, "ea", fonts.majorEastAsian);
4457
+ if (fonts.majorComplexScript !== void 0) setTypeface(majorFont, "cs", fonts.majorComplexScript);
4458
+ if (fonts.minorLatin !== void 0) setTypeface(minorFont, "latin", fonts.minorLatin);
4459
+ if (fonts.minorEastAsian !== void 0) setTypeface(minorFont, "ea", fonts.minorEastAsian);
4460
+ if (fonts.minorComplexScript !== void 0) setTypeface(minorFont, "cs", fonts.minorComplexScript);
4461
+ themePart.data = encode$1(serializeXml(doc));
4462
+ };
4032
4463
  //#endregion
4033
4464
  //#region src/api/fn/comments.ts
4034
4465
  const COMMENT_AUTHORS_PART_NAME = partName("/ppt/commentAuthors.xml");
@@ -4701,11 +5132,11 @@ const DEFAULT_ACCENT_COLORS = [
4701
5132
  "5B9BD5",
4702
5133
  "70AD47"
4703
5134
  ];
4704
- const seriesSpPr = (color, lineWidthEmu, lineDash) => {
5135
+ const seriesSpPr = (color, lineWidthEmu$1, lineDash) => {
4705
5136
  const lnChildren = [elem(a("solidFill"), { children: [elem(a("srgbClr"), { attrs: [attr(qname("", "val", ""), color)] })] })];
4706
5137
  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))],
5138
+ const ln = lineWidthEmu$1 !== void 0 ? elem(a("ln"), {
5139
+ attrs: [attr(qname("", "w", ""), String(lineWidthEmu(lineWidthEmu$1, "chart series: lineWidthEmu")))],
4709
5140
  children: lnChildren
4710
5141
  }) : elem(a("ln"), { children: lnChildren });
4711
5142
  return elem(c("spPr"), { children: [elem(a("solidFill"), { children: [elem(a("srgbClr"), { attrs: [attr(qname("", "val", ""), color)] })] }), ln] });
@@ -4769,17 +5200,18 @@ const seriesElement = (spec, seriesIdx, sheet) => {
4769
5200
  ];
4770
5201
  if (spec.kind === "line" || series.lineWidthEmu !== void 0 || series.lineDash !== void 0) children.push(seriesSpPr(color, series.lineWidthEmu, series.lineDash));
4771
5202
  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);
5203
+ if (series.invertIfNegative === true && (spec.kind === "bar" || spec.kind === "column")) children.push(valNode(c("invertIfNegative"), "1"));
5204
+ if (spec.kind === "line" || spec.kind === "scatter" || spec.kind === "radar") {
5205
+ const mk = markerElement(series.markerSymbol, series.markerSizePt);
5206
+ if (mk !== null) children.push(mk);
5207
+ }
4775
5208
  for (const dPt of dPtElements(series.pointColors, series.pointExplosions)) children.push(dPt);
4776
5209
  const serDLbls = buildDLblsFromLabels(series.dataLabels);
4777
5210
  if (serDLbls !== null) children.push(serDLbls);
4778
- if (series.trendline) children.push(trendlineElement(series.trendline));
5211
+ if (series.trendline && spec.kind !== "pie" && spec.kind !== "doughnut" && spec.kind !== "radar") children.push(trendlineElement(series.trendline));
4779
5212
  children.push(elem(c("cat"), { children: [strRef(catRange, spec.categories)] }));
4780
5213
  children.push(elem(c("val"), { children: [numRef(valRange, paddedValues)] }));
4781
5214
  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
5215
  return elem(c("ser"), { children });
4784
5216
  };
4785
5217
  const CAT_AX_ID = 111111111;
@@ -4832,8 +5264,8 @@ const valAxis = (spec) => {
4832
5264
  const scalingChildren = [];
4833
5265
  if (spec.valueAxis?.logBase !== void 0) scalingChildren.push(valNode(c("logBase"), spec.valueAxis.logBase));
4834
5266
  scalingChildren.push(valNode(c("orientation"), spec.valueAxisOrientation ?? "minMax"));
4835
- if (spec.valueAxis?.min !== void 0) scalingChildren.push(valNode(c("min"), spec.valueAxis.min));
4836
5267
  if (spec.valueAxis?.max !== void 0) scalingChildren.push(valNode(c("max"), spec.valueAxis.max));
5268
+ if (spec.valueAxis?.min !== void 0) scalingChildren.push(valNode(c("min"), spec.valueAxis.min));
4837
5269
  const children = [
4838
5270
  valNode(c("axId"), VAL_AX_ID),
4839
5271
  elem(c("scaling"), { children: scalingChildren }),
@@ -4884,9 +5316,9 @@ const buildBarChart = (spec, sheet, direction) => {
4884
5316
  ...ser,
4885
5317
  ...dl ? [dl] : []
4886
5318
  ];
4887
- if (spec.gapWidthPct !== void 0) children.push(valNode(c("gapWidth"), spec.gapWidthPct));
5319
+ if (spec.gapWidthPct !== void 0) children.push(valNode(c("gapWidth"), gapAmountPercent(spec.gapWidthPct, "chart: gapWidthPct")));
4888
5320
  const overlapPct = spec.overlapPct ?? (grouping === "stacked" || grouping === "percentStacked" ? 100 : void 0);
4889
- if (overlapPct !== void 0) children.push(valNode(c("overlap"), overlapPct));
5321
+ if (overlapPct !== void 0) children.push(valNode(c("overlap"), overlapPercent(overlapPct, "chart: overlapPct")));
4890
5322
  children.push(valNode(c("axId"), CAT_AX_ID), valNode(c("axId"), VAL_AX_ID));
4891
5323
  return elem(c(direction === "col" ? "barChart" : "barChart"), { children });
4892
5324
  };
@@ -4913,7 +5345,7 @@ const buildPieChart = (spec, sheet) => {
4913
5345
  ser,
4914
5346
  ...dl ? [dl] : []
4915
5347
  ];
4916
- if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), Math.round(spec.firstSliceAngleDeg)));
5348
+ if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), firstSliceAngle(spec.firstSliceAngleDeg, "chart: firstSliceAngleDeg")));
4917
5349
  return elem(c("pieChart"), { children });
4918
5350
  };
4919
5351
  const buildDoughnutChart = (spec, sheet) => {
@@ -4925,8 +5357,8 @@ const buildDoughnutChart = (spec, sheet) => {
4925
5357
  ser,
4926
5358
  ...dl ? [dl] : []
4927
5359
  ];
4928
- if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), Math.round(spec.firstSliceAngleDeg)));
4929
- children.push(valNode(c("holeSize"), spec.holeSizePct ?? 50));
5360
+ if (spec.firstSliceAngleDeg !== void 0) children.push(valNode(c("firstSliceAng"), firstSliceAngle(spec.firstSliceAngleDeg, "chart: firstSliceAngleDeg")));
5361
+ children.push(valNode(c("holeSize"), holeSizePercent(spec.holeSizePct ?? 50, "chart: holeSizePct")));
4930
5362
  return elem(c("doughnutChart"), { children });
4931
5363
  };
4932
5364
  const buildAreaChart = (spec, sheet) => {
@@ -7252,7 +7684,7 @@ const buildChartGraphicFrame = (opts) => {
7252
7684
  elem(NAME_C_NV_GRAPHIC_FRAME_PR),
7253
7685
  elem(NAME_NV_PR)
7254
7686
  ] });
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)))] })] });
7687
+ 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
7688
  const chartRef = elem(NAME_C_CHART, {
7257
7689
  prefixDecls: new Map([["c", NS.chart], ["r", NS.officeDocRels]]),
7258
7690
  attrs: [attr(qname("r", "id", NS.officeDocRels), opts.rEmbed)]
@@ -7549,7 +7981,7 @@ const findChartsWithTrendlines = (slide) => {
7549
7981
  */
7550
7982
  const findChartsWithDataLabels = (slide) => {
7551
7983
  const out = [];
7552
- const hasLabel = (dl) => dl !== void 0 && (dl.showValue || dl.showCategory || dl.showSeriesName || dl.showPercent);
7984
+ const hasLabel = (dl) => dl !== void 0 && Boolean(dl.showValue || dl.showCategory || dl.showSeriesName || dl.showPercent);
7553
7985
  for (const chart of getSlideCharts(slide)) {
7554
7986
  if (chart.spec === null) continue;
7555
7987
  if (hasLabel(chart.spec.dataLabels)) {
@@ -7641,6 +8073,7 @@ const NAME_P_BODY_STYLE = qname("p", "bodyStyle", NS.pml);
7641
8073
  const NAME_P_OTHER_STYLE = qname("p", "otherStyle", NS.pml);
7642
8074
  const mergeRPrLayer = (base, layer) => {
7643
8075
  if (base.font === void 0 && layer.font !== void 0) base.font = layer.font;
8076
+ if (base.fontEastAsian === void 0 && layer.fontEastAsian !== void 0) base.fontEastAsian = layer.fontEastAsian;
7644
8077
  if (base.size === void 0 && layer.size !== void 0) base.size = layer.size;
7645
8078
  if (base.color === void 0 && layer.color !== void 0) base.color = layer.color;
7646
8079
  if (base.bold === void 0 && layer.bold !== void 0) base.bold = layer.bold;
@@ -7796,6 +8229,14 @@ const getShapeRunFormatEffective = (pres, shape, paragraphIndex, runIndex) => {
7796
8229
  const fallback = phType === "title" || phType === "ctrTitle" ? fonts.majorLatin : fonts.minorLatin;
7797
8230
  if (fallback) result.font = fallback;
7798
8231
  }
8232
+ if (typeof result.fontEastAsian === "string" && result.fontEastAsian.startsWith("+")) {
8233
+ const resolved = resolveThemeToken(result.fontEastAsian);
8234
+ if (resolved) result.fontEastAsian = resolved;
8235
+ }
8236
+ if (result.fontEastAsian === void 0) {
8237
+ const fallback = phType === "title" || phType === "ctrTitle" ? fonts.majorEastAsian : fonts.minorEastAsian;
8238
+ if (fallback) result.fontEastAsian = fallback;
8239
+ }
7799
8240
  }
7800
8241
  return result;
7801
8242
  };
@@ -8699,7 +9140,10 @@ const setTableStyleId = (table, styleId) => {
8699
9140
  if (!tbl) throw new Error("setTableStyleId: shape is not a table graphic frame");
8700
9141
  const tblPr = ensureTblPr(tbl);
8701
9142
  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)] }));
9143
+ if (styleId !== null) {
9144
+ const guid = normalizeGuid(styleId, "setTableStyleId: styleId");
9145
+ tblPr.children.push(elem(qname("a", "tableStyleId", NS.dml), { children: [text(guid)] }));
9146
+ }
8703
9147
  commitSlideData(table[SHAPE_SLIDE]);
8704
9148
  refreshSlideData(table[SHAPE_SLIDE]);
8705
9149
  };
@@ -8862,7 +9306,7 @@ const setTableColumnWidth = (table, col, width) => {
8862
9306
  const target = cols[col];
8863
9307
  if (!target) throw new RangeError(`table column ${col} out of range (have ${cols.length})`);
8864
9308
  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))));
9309
+ target.attrs.push(attr(ATTR_W_TBL, String(emuExtent(width, "setTableColumnWidth: width"))));
8866
9310
  commitSlideData(table[SHAPE_SLIDE]);
8867
9311
  refreshSlideData(table[SHAPE_SLIDE]);
8868
9312
  };
@@ -8876,7 +9320,7 @@ const setTableRowHeight = (table, row, height) => {
8876
9320
  const target = rows[row];
8877
9321
  if (!target) throw new RangeError(`table row ${row} out of range (have ${rows.length})`);
8878
9322
  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))));
9323
+ target.attrs.push(attr(ATTR_H_TBL, String(emuExtent(height, "setTableRowHeight: height"))));
8880
9324
  commitSlideData(table[SHAPE_SLIDE]);
8881
9325
  refreshSlideData(table[SHAPE_SLIDE]);
8882
9326
  };
@@ -9075,18 +9519,39 @@ const BORDER_SIDE_LOCALS = {
9075
9519
  tlToBr: "lnTlToBr",
9076
9520
  blToTr: "lnBlToTr"
9077
9521
  };
9522
+ const TCPR_CHILD_RANK = {
9523
+ lnL: 0,
9524
+ lnR: 1,
9525
+ lnT: 2,
9526
+ lnB: 3,
9527
+ lnTlToBr: 4,
9528
+ lnBlToTr: 5,
9529
+ cell3D: 6,
9530
+ noFill: 7,
9531
+ solidFill: 7,
9532
+ gradFill: 7,
9533
+ blipFill: 7,
9534
+ pattFill: 7,
9535
+ grpFill: 7,
9536
+ headers: 8,
9537
+ extLst: 9
9538
+ };
9539
+ const tcPrChildRank = (el) => el.name.namespaceURI === NS.dml ? TCPR_CHILD_RANK[el.name.localName] ?? 99 : 99;
9078
9540
  const writeBorderLn = (tcPr, local, border) => {
9079
9541
  tcPr.children = tcPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === local));
9080
9542
  if (border === null) return;
9081
9543
  const lnAttrs = [];
9082
- if (border.widthEmu !== null && border.widthEmu !== void 0) lnAttrs.push(attr(qname("", "w", ""), String(Math.round(border.widthEmu))));
9544
+ if (border.widthEmu !== null && border.widthEmu !== void 0) {
9545
+ const w = lineWidthEmu(border.widthEmu, "setTableCellBorders: widthEmu");
9546
+ lnAttrs.push(attr(qname("", "w", ""), String(w)));
9547
+ }
9083
9548
  const children = [];
9084
9549
  if (border.color !== null && border.color !== void 0) children.push(elem(qname("a", "solidFill", NS.dml), { children: [buildColorElement(border.color)] }));
9085
9550
  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), {
9551
+ insertChildByRank(tcPr, elem(qname("a", local, NS.dml), {
9087
9552
  attrs: lnAttrs,
9088
9553
  children
9089
- }));
9554
+ }), tcPrChildRank);
9090
9555
  };
9091
9556
  /**
9092
9557
  * Sets one or more side borders on a cell. Sides listed with `null` are
@@ -9215,7 +9680,10 @@ const setTableCellMargins = (cell, margins) => {
9215
9680
  ["marT", margins.top],
9216
9681
  ["marB", margins.bottom]
9217
9682
  ];
9218
- for (const [name, val] of pairs) if (val !== null && val !== void 0) tcPr.attrs.push(attr(qname("", name, ""), String(Math.round(val))));
9683
+ for (const [name, val] of pairs) if (val !== null && val !== void 0) {
9684
+ const emu = emuCoordinate32(val, `setTableCellMargins: ${name}`);
9685
+ tcPr.attrs.push(attr(qname("", name, ""), String(emu)));
9686
+ }
9219
9687
  }
9220
9688
  commitTableCell(cell);
9221
9689
  };
@@ -9728,7 +10196,8 @@ const listPackageParts = (pres) => pres[INTERNAL_PACKAGE].parts.map((p) => ({
9728
10196
  * (e.g. parsing custom extension parts).
9729
10197
  */
9730
10198
  const readPackagePart = (pres, name) => {
9731
- return pres[INTERNAL_PACKAGE].parts.find((p) => p.name === name)?.data ?? null;
10199
+ const target = name.toLowerCase();
10200
+ return pres[INTERNAL_PACKAGE].parts.find((p) => p.name.toLowerCase() === target)?.data ?? null;
9732
10201
  };
9733
10202
  /**
9734
10203
  * Returns the total size of the package's parts in bytes
@@ -9785,13 +10254,13 @@ const getOrphanMediaPartNames = (pres) => {
9785
10254
  if (!sourceRels) continue;
9786
10255
  for (const rel of sourceRels.items) {
9787
10256
  if (rel.targetMode === "External") continue;
9788
- referenced.add(resolve(sourceName, rel.target));
10257
+ referenced.add(resolve(sourceName, rel.target).toLowerCase());
9789
10258
  }
9790
10259
  }
9791
10260
  const out = [];
9792
10261
  for (const part of pkg.parts) {
9793
10262
  if (!part.name.startsWith("/ppt/media/")) continue;
9794
- if (!referenced.has(part.name)) out.push(part.name);
10263
+ if (!referenced.has(part.name.toLowerCase())) out.push(part.name);
9795
10264
  }
9796
10265
  return out;
9797
10266
  };
@@ -9878,14 +10347,14 @@ const compactPackage = (pres) => {
9878
10347
  if (!rels) continue;
9879
10348
  for (const rel of rels.items) {
9880
10349
  if (rel.targetMode === "External") continue;
9881
- referenced.add(resolve(sourceName, rel.target));
10350
+ referenced.add(resolve(sourceName, rel.target).toLowerCase());
9882
10351
  }
9883
10352
  }
9884
10353
  const removed = [];
9885
10354
  const orphans = [];
9886
10355
  for (const part of pkg.parts) {
9887
10356
  if (!part.name.startsWith("/ppt/media/")) continue;
9888
- if (!referenced.has(part.name)) orphans.push(part.name);
10357
+ if (!referenced.has(part.name.toLowerCase())) orphans.push(part.name);
9889
10358
  }
9890
10359
  for (const name of orphans) {
9891
10360
  pkg.removePart(partName(name));
@@ -9904,7 +10373,8 @@ const compactPackage = (pres) => {
9904
10373
  * already point at this part name.
9905
10374
  */
9906
10375
  const setMediaPartBytes = (pres, partName, bytes) => {
9907
- const part = pres[INTERNAL_PACKAGE].parts.find((p) => p.name === partName);
10376
+ const target = partName.toLowerCase();
10377
+ const part = pres[INTERNAL_PACKAGE].parts.find((p) => p.name.toLowerCase() === target);
9908
10378
  if (!part) return false;
9909
10379
  part.data = bytes;
9910
10380
  return true;
@@ -10991,93 +11461,84 @@ const getShapeImageCrop = (shape) => {
10991
11461
  bottom: parseSide("b")
10992
11462
  };
10993
11463
  };
11464
+ const NAME_LUM = qname("a", "lum", NS.dml);
11465
+ const requirePictureBlip = (shape, fnName) => {
11466
+ if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`${fnName} only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11467
+ const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11468
+ if (!blipFill) throw new Error("picture has no <p:blipFill>");
11469
+ const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11470
+ if (!blip) throw new Error("picture <p:blipFill> has no <a:blip>");
11471
+ return blip;
11472
+ };
11473
+ const setLumAttr = (blip, local, value) => {
11474
+ let lum = firstChildElement(blip, NAME_LUM);
11475
+ if (lum) lum.attrs = lum.attrs.filter((a) => !(a.name.namespaceURI === "" && a.name.localName === local));
11476
+ if (value !== null && value !== 0) {
11477
+ if (!lum) {
11478
+ lum = elem(NAME_LUM);
11479
+ blip.children.push(lum);
11480
+ }
11481
+ lum.attrs.push(attr(qname("", local, ""), String(Math.round(value * 1e5))));
11482
+ }
11483
+ if (lum && lum.attrs.length === 0) blip.children = blip.children.filter((c) => c !== lum);
11484
+ };
11485
+ const getLumAttr = (shape, local) => {
11486
+ if (shape[SHAPE_SNAPSHOT].kind !== "picture") return null;
11487
+ const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
11488
+ if (!blipFill) return null;
11489
+ const blip = firstChildElement(blipFill, qname("a", "blip", NS.dml));
11490
+ if (!blip) return null;
11491
+ const lum = firstChildElement(blip, NAME_LUM);
11492
+ if (!lum) return null;
11493
+ const v = getAttrValue(lum, qname("", local, ""));
11494
+ if (v === null) return null;
11495
+ const n = Number.parseInt(v, 10);
11496
+ return Number.isFinite(n) ? n / 1e5 : null;
11497
+ };
10994
11498
  /**
10995
- * Adjusts the picture's brightness by writing `<a:lumOff val="…"/>`
10996
- * inside `<a:blip>`. The value is a -1..1 fraction:
11499
+ * Adjusts the picture's brightness via `<a:blip><a:lum bright="…"/>`. The value
11500
+ * is a -1..1 fraction:
10997
11501
  *
10998
11502
  * - `1` → +100% brightness
10999
- * - `0` or `null` → no offset (any prior `<a:lumOff>` is removed)
11503
+ * - `0` or `null` → no brightness change (the `bright` attribute is removed)
11000
11504
  * - `-1` → -100% brightness
11001
11505
  *
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`.
11506
+ * Brightness and contrast share the one `<a:lum>` element, so setting one keeps
11507
+ * the other. Throws for non-picture shapes and on values outside [-1, 1].
11008
11508
  */
11009
11509
  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
- }
11510
+ const blip = requirePictureBlip(shape, "setShapeImageBrightness");
11511
+ if (value !== null && value !== 0 && (!Number.isFinite(value) || value < -1 || value > 1)) throw new RangeError(`brightness must be in [-1, 1], got ${value}`);
11512
+ setLumAttr(blip, "bright", value);
11020
11513
  commitAndRefresh(shape);
11021
11514
  };
11022
11515
  /**
11023
- * Adjusts the picture's contrast by writing `<a:lumMod val="…"/>` on
11024
- * `<a:blip>`. The value is a 0..2 fraction:
11516
+ * Adjusts the picture's contrast via `<a:blip><a:lum contrast="…"/>`. The value
11517
+ * is a -1..1 fraction (ECMA-376 `ST_FixedPercentage`):
11025
11518
  *
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)
11519
+ * - `0` or `null` → no contrast change (the `contrast` attribute is removed)
11520
+ * - `0.5` → +50% contrast (boosted)
11521
+ * - `-0.5` -50% contrast (washed out)
11030
11522
  *
11031
- * Throws on non-picture shapes and on values outside `[0, 2]`. The
11032
- * primitive maps directly to `ST_PositiveFixedPercentage` × 100000.
11523
+ * Brightness and contrast share the one `<a:lum>` element, so setting one keeps
11524
+ * the other. Throws on non-picture shapes and on values outside [-1, 1].
11033
11525
  */
11034
11526
  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
- }
11527
+ const blip = requirePictureBlip(shape, "setShapeImageContrast");
11528
+ if (value !== null && value !== 0 && (!Number.isFinite(value) || value < -1 || value > 1)) throw new RangeError(`contrast must be in [-1, 1], got ${value}`);
11529
+ setLumAttr(blip, "contrast", value);
11045
11530
  commitAndRefresh(shape);
11046
11531
  };
11047
11532
  /**
11048
- * Reads the picture's contrast modulation (the `<a:lumMod>` fraction
11049
- * in [0, 2]). Returns `null` when no `<a:lumMod>` is present.
11533
+ * Reads the picture's contrast (the `<a:lum contrast>` fraction in [-1, 1]).
11534
+ * Returns `null` when no contrast adjustment is present.
11050
11535
  */
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
- };
11536
+ const getShapeImageContrast = (shape) => getLumAttr(shape, "contrast");
11064
11537
  /**
11065
- * Reads the picture's brightness offset (the `<a:lumOff>` fraction
11066
- * in [-1, 1]). Returns `null` when no `<a:lumOff>` is present.
11538
+ * Reads the picture's brightness (the `<a:lum bright>` fraction in [-1, 1]).
11539
+ * Returns `null` when no brightness adjustment is present.
11067
11540
  */
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
- };
11541
+ const getShapeImageBrightness = (shape) => getLumAttr(shape, "bright");
11081
11542
  const setShapeImageOpacity = (shape, opacity) => {
11082
11543
  if (shape[SHAPE_SNAPSHOT].kind !== "picture") throw new Error(`setShapeImageOpacity only works on picture shapes; ${shape[SHAPE_SNAPSHOT].kind} is not one`);
11083
11544
  const blipFill = firstChildElement(shape[SHAPE_ELEMENT], qname("p", "blipFill", NS.pml));
@@ -11140,17 +11601,99 @@ const setShapeImageCrop = (shape, crop) => {
11140
11601
  //#endregion
11141
11602
  //#region src/api/fn/shape-animation.ts
11142
11603
  NS.pml;
11604
+ const ATTR_ID_FN = qname("", "id", "");
11143
11605
  const removeExistingTiming = (slide) => {
11144
11606
  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
11607
  };
11608
+ const findTiming = (slide) => slide[SLIDE_DOCUMENT].root.children.find((c) => c.kind === "element" && c.name.namespaceURI === NS.pml && c.name.localName === "timing") ?? null;
11146
11609
  const insertTimingAtEnd = (slide, timing) => {
11147
11610
  slide[SLIDE_DOCUMENT].root.children.push(timing);
11148
11611
  };
11612
+ const findDescendant = (el, pred) => {
11613
+ if (pred(el)) return el;
11614
+ for (const c of el.children) if (c.kind === "element") {
11615
+ const found = findDescendant(c, pred);
11616
+ if (found) return found;
11617
+ }
11618
+ return null;
11619
+ };
11620
+ const isPml = (el, local) => el.name.namespaceURI === NS.pml && el.name.localName === local;
11621
+ const maxCTnId = (el) => {
11622
+ let max = 0;
11623
+ const walk = (e) => {
11624
+ if (isPml(e, "cTn")) {
11625
+ const n = Number.parseInt(getAttrValue(e, ATTR_ID_FN) ?? "", 10);
11626
+ if (Number.isFinite(n) && n > max) max = n;
11627
+ }
11628
+ for (const c of e.children) if (c.kind === "element") walk(c);
11629
+ };
11630
+ walk(el);
11631
+ return max;
11632
+ };
11633
+ const shiftCTnIds = (el, offset) => {
11634
+ const walk = (e) => {
11635
+ if (isPml(e, "cTn")) {
11636
+ const raw = getAttrValue(e, ATTR_ID_FN);
11637
+ const n = raw === null ? NaN : Number.parseInt(raw, 10);
11638
+ if (Number.isFinite(n)) e.attrs = e.attrs.map((a) => a.name.namespaceURI === "" && a.name.localName === "id" ? {
11639
+ ...a,
11640
+ value: String(n + offset)
11641
+ } : a);
11642
+ }
11643
+ for (const c of e.children) if (c.kind === "element") walk(c);
11644
+ };
11645
+ walk(el);
11646
+ };
11647
+ const maxGrpId = (el) => {
11648
+ let max = -1;
11649
+ const walk = (e) => {
11650
+ const raw = getAttrValue(e, qname("", "grpId", ""));
11651
+ if (raw !== null) {
11652
+ const n = Number.parseInt(raw, 10);
11653
+ if (Number.isFinite(n) && n > max) max = n;
11654
+ }
11655
+ for (const c of e.children) if (c.kind === "element") walk(c);
11656
+ };
11657
+ walk(el);
11658
+ return max;
11659
+ };
11660
+ const setGrpId = (el, grpId) => {
11661
+ el.attrs = el.attrs.map((a) => a.name.namespaceURI === "" && a.name.localName === "grpId" ? {
11662
+ ...a,
11663
+ value: grpId
11664
+ } : a);
11665
+ };
11666
+ const mergeEffectInto = (existing, fresh) => {
11667
+ const existingMainSeqChildTnLst = (() => {
11668
+ const mainSeq = findDescendant(existing, (e) => isPml(e, "cTn") && getAttrValue(e, qname("", "nodeType", "")) === "mainSeq");
11669
+ return mainSeq ? firstChildElement(mainSeq, qname("p", "childTnLst", NS.pml)) : null;
11670
+ })();
11671
+ if (!existingMainSeqChildTnLst) return false;
11672
+ const freshMainSeq = findDescendant(fresh, (e) => isPml(e, "cTn") && getAttrValue(e, qname("", "nodeType", "")) === "mainSeq");
11673
+ const freshChildTnLst = freshMainSeq ? firstChildElement(freshMainSeq, qname("p", "childTnLst", NS.pml)) : null;
11674
+ const newPar = freshChildTnLst ? freshChildTnLst.children.find((c) => c.kind === "element" && isPml(c, "par")) : null;
11675
+ const freshBldP = findDescendant(fresh, (e) => isPml(e, "bldP"));
11676
+ if (!newPar || !freshBldP) return false;
11677
+ const offset = maxCTnId(existing) - 2;
11678
+ if (offset > 0) shiftCTnIds(newPar, offset);
11679
+ const newGrpId = String(maxGrpId(existing) + 1);
11680
+ const effectCTn = findDescendant(newPar, (e) => getAttrValue(e, qname("", "presetID", "")) !== null);
11681
+ if (effectCTn) setGrpId(effectCTn, newGrpId);
11682
+ setGrpId(freshBldP, newGrpId);
11683
+ existingMainSeqChildTnLst.children.push(newPar);
11684
+ const existingBldLst = findDescendant(existing, (e) => isPml(e, "bldLst"));
11685
+ if (existingBldLst) existingBldLst.children.push(freshBldP);
11686
+ else existing.children.push(elem(qname("p", "bldLst", NS.pml), { children: [freshBldP] }));
11687
+ return true;
11688
+ };
11149
11689
  /**
11150
11690
  * 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.
11691
+ *
11692
+ * The effect is *merged* into any existing `<p:timing>` on the slide rather
11693
+ * than replacing it: animating a second shape (or re-running on a template that
11694
+ * already has authored animations) preserves the existing effects and appends
11695
+ * this one as the next click stop, with cTn ids renumbered to stay unique. To
11696
+ * clear every animation first, call `clearSlideAnimations`.
11154
11697
  *
11155
11698
  * Supported `effect` tokens:
11156
11699
  *
@@ -11164,9 +11707,11 @@ const insertTimingAtEnd = (slide, timing) => {
11164
11707
  */
11165
11708
  const setShapeAnimation = (shape, opts) => {
11166
11709
  const slide = shape[SHAPE_SLIDE];
11167
- removeExistingTiming(slide);
11168
11710
  const spid = shape[SHAPE_SNAPSHOT].id;
11169
- insertTimingAtEnd(slide, buildSingleEffectTiming(spid, opts));
11711
+ const fresh = buildSingleEffectTiming(spid, opts);
11712
+ const existing = findTiming(slide);
11713
+ if (existing === null) insertTimingAtEnd(slide, fresh);
11714
+ 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
11715
  commitSlideData(slide);
11171
11716
  refreshSlideData(slide);
11172
11717
  };
@@ -11622,6 +12167,25 @@ const getParagraphLevel = (shape, paragraphIndex) => {
11622
12167
  const n = Number.parseInt(v, 10);
11623
12168
  return Number.isFinite(n) ? n : 0;
11624
12169
  };
12170
+ const PPR_CHILD_RANK = {
12171
+ lnSpc: 0,
12172
+ spcBef: 1,
12173
+ spcAft: 2,
12174
+ buClrTx: 3,
12175
+ buClr: 3,
12176
+ buSzTx: 4,
12177
+ buSzPct: 4,
12178
+ buSzPts: 4,
12179
+ buFontTx: 5,
12180
+ buFont: 5,
12181
+ buNone: 6,
12182
+ buAutoNum: 6,
12183
+ buChar: 6,
12184
+ tabLst: 7,
12185
+ defRPr: 8,
12186
+ extLst: 9
12187
+ };
12188
+ const pPrChildRank = (el) => el.name.namespaceURI === NS.dml ? PPR_CHILD_RANK[el.name.localName] ?? 99 : 99;
11625
12189
  /**
11626
12190
  * Sets the spacing before and/or after a paragraph, in points (where
11627
12191
  * a "point" is 1/72 inch). PowerPoint stores these as hundredths of a
@@ -11640,8 +12204,7 @@ const setParagraphSpacing = (shape, paragraphIndex, opts) => {
11640
12204
  pPr.children = pPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === localName));
11641
12205
  if (value === null) return;
11642
12206
  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);
12207
+ 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
12208
  };
11646
12209
  writeSide("spcBef", opts.beforePts);
11647
12210
  writeSide("spcAft", opts.afterPts);
@@ -11748,6 +12311,27 @@ const getParagraphLineSpacing = (shape, paragraphIndex) => {
11748
12311
  return null;
11749
12312
  };
11750
12313
  /**
12314
+ * Sets a paragraph's line spacing — the writer counterpart to
12315
+ * `getParagraphLineSpacing`. Two modes (mirroring `<a:lnSpc>`):
12316
+ *
12317
+ * - `{ kind: 'pct', value }` — a multiple of single spacing
12318
+ * (`1` = single, `1.5` = 150%, `2` = double) → `<a:spcPct>`.
12319
+ * - `{ kind: 'pts', value }` — a fixed leading in points → `<a:spcPts>`.
12320
+ *
12321
+ * Pass `null` to clear the override (the paragraph then inherits line
12322
+ * spacing from the layout / master).
12323
+ */
12324
+ const setParagraphLineSpacing = (shape, paragraphIndex, spacing) => {
12325
+ const pPr = ensurePPr(requireParagraph(shape, paragraphIndex));
12326
+ pPr.children = pPr.children.filter((c) => !(c.kind === "element" && c.name.namespaceURI === NS.dml && c.name.localName === "lnSpc"));
12327
+ if (spacing !== null) {
12328
+ if (!Number.isFinite(spacing.value) || spacing.value < 0) throw new RangeError(`line spacing value must be a non-negative number, got ${spacing.value}`);
12329
+ 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)))] });
12330
+ insertChildByRank(pPr, elem(qname("a", "lnSpc", NS.dml), { children: [inner] }), pPrChildRank);
12331
+ }
12332
+ commitAndRefresh(shape);
12333
+ };
12334
+ /**
11751
12335
  * Reads back the bullet style on a single paragraph, or `null` when
11752
12336
  * no `<a:buChar>` / `<a:buAutoNum>` / `<a:buNone>` is present (the
11753
12337
  * paragraph inherits its bullet from the layout / master).
@@ -11987,6 +12571,8 @@ const hslToRgb = (h, s, l) => {
11987
12571
  hueToRgb(p, q, h - 1 / 3)
11988
12572
  ];
11989
12573
  };
12574
+ const srgbToLinear = (c) => c <= .04045 ? c / 12.92 : ((c + .055) / 1.055) ** 2.4;
12575
+ const linearToSrgb = (c) => c <= .0031308 ? c * 12.92 : 1.055 * c ** (1 / 2.4) - .055;
11990
12576
  const applyColorTransforms = (hex, transforms) => {
11991
12577
  if (transforms.length === 0) return hex;
11992
12578
  let [r, g, b] = hexToRgb01(hex);
@@ -12005,14 +12591,14 @@ const applyColorTransforms = (hex, transforms) => {
12005
12591
  break;
12006
12592
  }
12007
12593
  case "shade":
12008
- r *= t.val;
12009
- g *= t.val;
12010
- b *= t.val;
12594
+ r = linearToSrgb(srgbToLinear(r) * t.val);
12595
+ g = linearToSrgb(srgbToLinear(g) * t.val);
12596
+ b = linearToSrgb(srgbToLinear(b) * t.val);
12011
12597
  break;
12012
12598
  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);
12599
+ r = linearToSrgb(srgbToLinear(r) * t.val + (1 - t.val));
12600
+ g = linearToSrgb(srgbToLinear(g) * t.val + (1 - t.val));
12601
+ b = linearToSrgb(srgbToLinear(b) * t.val + (1 - t.val));
12016
12602
  break;
12017
12603
  case "lumMod":
12018
12604
  case "lumOff": {
@@ -12198,6 +12784,11 @@ const parseRPrLikeElement = (rPr, ctx) => {
12198
12784
  const t = getAttrValue(latin, qname("", "typeface", ""));
12199
12785
  if (t !== null) out.font = t;
12200
12786
  }
12787
+ const ea = firstChildElement(rPr, qname("a", "ea", NS.dml));
12788
+ if (ea !== null) {
12789
+ const t = getAttrValue(ea, qname("", "typeface", ""));
12790
+ if (t !== null) out.fontEastAsian = t;
12791
+ }
12201
12792
  return out;
12202
12793
  };
12203
12794
  /**
@@ -14341,8 +14932,8 @@ const getShapeTextColumns = (shape) => {
14341
14932
  * Sets the multi-column layout on the shape's text body — writes
14342
14933
  * `<a:bodyPr numCol="N" [spcCol="EMU"]/>`. Pass `null` to clear both
14343
14934
  * 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,
14935
+ * single column. `count` must be in `2..16` (ST_TextColumnCount caps at
14936
+ * 16, and single column is the `null` default). `gapEmu`, when omitted,
14346
14937
  * removes any prior `spcCol`. Throws for non-text-bearing shape kinds.
14347
14938
  */
14348
14939
  const setShapeTextColumns = (shape, columns) => {
@@ -14350,8 +14941,12 @@ const setShapeTextColumns = (shape, columns) => {
14350
14941
  bodyPr.attrs = bodyPr.attrs.filter((a) => !(a.name.namespaceURI === "" && (a.name.localName === "numCol" || a.name.localName === "spcCol")));
14351
14942
  if (columns !== null) {
14352
14943
  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))));
14944
+ const numCol = textColumnCount(columns.count, "setShapeTextColumns: count");
14945
+ bodyPr.attrs.push(attr(qname("", "numCol", ""), String(numCol)));
14946
+ if (columns.gapEmu !== void 0) {
14947
+ const spcCol = emuPositiveCoordinate32(columns.gapEmu, "setShapeTextColumns: gapEmu");
14948
+ bodyPr.attrs.push(attr(qname("", "spcCol", ""), String(spcCol)));
14949
+ }
14355
14950
  }
14356
14951
  commitAndRefresh(shape);
14357
14952
  };
@@ -14388,7 +14983,10 @@ const getShapeTextBodyRotationDeg = (shape) => {
14388
14983
  const setShapeTextBodyRotationDeg = (shape, rotationDeg) => {
14389
14984
  const bodyPr = requireBodyPr(shape);
14390
14985
  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))));
14986
+ if (rotationDeg !== null && rotationDeg !== 0) {
14987
+ const rot = angle60000(rotationDeg * 6e4, "setShapeTextBodyRotationDeg: rotationDeg");
14988
+ bodyPr.attrs.push(attr(qname("", "rot", ""), String(rot)));
14989
+ }
14392
14990
  commitAndRefresh(shape);
14393
14991
  };
14394
14992
  /**
@@ -14586,7 +15184,10 @@ const setShapeTextMargins = (shape, margins) => {
14586
15184
  });
14587
15185
  const localsToClear = new Set(writes.map((w) => w.name));
14588
15186
  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))));
15187
+ for (const w of writes) {
15188
+ const emu = emuCoordinate32(w.value, `setShapeTextMargins: ${w.name}`);
15189
+ bodyPr.attrs.push(attr(qname("", w.name, ""), String(emu)));
15190
+ }
14590
15191
  commitAndRefresh(shape);
14591
15192
  };
14592
15193
  /** Sets the bullet style on every paragraph in the shape's text body. */
@@ -15931,6 +16532,22 @@ const duplicateSlideAt = (pres, atIndex, slide) => {
15931
16532
  const slides = getSlides(pres);
15932
16533
  return slides[Math.max(0, Math.min(atIndex, slides.length - 1))];
15933
16534
  };
16535
+ const collectRelRefs = (el, into) => {
16536
+ for (const a of el.attrs) if (a.name.namespaceURI === NS.officeDocRels) into.add(a.value);
16537
+ for (const c of el.children) if (c.kind === "element") collectRelRefs(c, into);
16538
+ };
16539
+ const pruneDanglingGraphicFrames = (el, keptRelIds) => {
16540
+ el.children = el.children.filter((c) => {
16541
+ if (c.kind !== "element") return true;
16542
+ if (c.name.namespaceURI === NS.pml && c.name.localName === "graphicFrame") {
16543
+ const refs = /* @__PURE__ */ new Set();
16544
+ collectRelRefs(c, refs);
16545
+ for (const id of refs) if (!keptRelIds.has(id)) return false;
16546
+ }
16547
+ return true;
16548
+ });
16549
+ for (const c of el.children) if (c.kind === "element") pruneDanglingGraphicFrames(c, keptRelIds);
16550
+ };
15934
16551
  /**
15935
16552
  * Imports a slide from another presentation into `targetPres`. The
15936
16553
  * slide's part bytes are copied verbatim; image rels are followed and
@@ -15966,8 +16583,9 @@ const importSlide = (targetPres, sourceSlide, targetLayout) => {
15966
16583
  const newRels = emptyRels();
15967
16584
  const layoutPartName = targetLayout[LAYOUT_PART_NAME];
15968
16585
  if (targetPkg.getPart(layoutPartName) === null) throw new Error(`importSlide: layout ${layoutPartName} not in target package`);
16586
+ const layoutRelId = nextRelId(sourceRels?.items.map((r) => r.id) ?? []);
15969
16587
  newRels.items.push({
15970
- id: "rId1",
16588
+ id: layoutRelId,
15971
16589
  type: REL_TYPES.slideLayout,
15972
16590
  target: `../slideLayouts/${basename(layoutPartName)}`,
15973
16591
  targetMode: "Internal"
@@ -16007,6 +16625,22 @@ const importSlide = (targetPres, sourceSlide, targetLayout) => {
16007
16625
  }
16008
16626
  }
16009
16627
  targetPkg.setRels(newSlidePartName, newRels);
16628
+ const newPart = targetPkg.getPart(newSlidePartName);
16629
+ if (newPart) {
16630
+ const keptRelIds = new Set(newRels.items.map((r) => r.id));
16631
+ const bodyDoc = parseXml(decode$1(newPart.data));
16632
+ const bodyRefs = /* @__PURE__ */ new Set();
16633
+ collectRelRefs(bodyDoc.root, bodyRefs);
16634
+ let hasDangling = false;
16635
+ for (const id of bodyRefs) if (!keptRelIds.has(id)) {
16636
+ hasDangling = true;
16637
+ break;
16638
+ }
16639
+ if (hasDangling) {
16640
+ pruneDanglingGraphicFrames(bodyDoc.root, keptRelIds);
16641
+ newPart.data = encode$1(serializeXml(bodyDoc));
16642
+ }
16643
+ }
16010
16644
  const presRels = targetPkg.getRels(PRES_PART_NAME) ?? emptyRels();
16011
16645
  const newRId = nextRelId(presRels.items.map((r) => r.id));
16012
16646
  presRels.items.push({
@@ -16048,9 +16682,120 @@ const mergePresentations = (targetPres, sourcePres, targetLayout) => {
16048
16682
  return out;
16049
16683
  };
16050
16684
  //#endregion
16685
+ //#region src/api/fn/shape-grouping.ts
16686
+ /**
16687
+ * Groups two or more top-level shapes into a single `<p:grpSp>`,
16688
+ * returning the new group as a `SlideShapeData`. The group's
16689
+ * slide-space bounds are the union of its members' bounds; the members
16690
+ * keep their own relative position/size (nothing is rescaled). The
16691
+ * target slide is taken from the first shape — every shape must belong
16692
+ * to the same slide.
16693
+ *
16694
+ * Every shape must:
16695
+ * - belong to the same slide as the others,
16696
+ * - be a direct child of the slide's shape tree (not already nested
16697
+ * inside another group — ungroup first, then re-group),
16698
+ * - have an explicit `<a:xfrm>` (placeholders that inherit position
16699
+ * from the layout have none and can't be grouped),
16700
+ * - appear at most once in `shapes` (grouping the same shape twice
16701
+ * would duplicate its id).
16702
+ *
16703
+ * The group replaces its members at the position of the earliest one in
16704
+ * z-order, so grouping doesn't change how the selection stacks against
16705
+ * shapes that weren't part of it.
16706
+ */
16707
+ const groupShapes = (shapes, opts = {}) => {
16708
+ if (shapes.length < 2) throw new Error("groupShapes: at least 2 shapes are required");
16709
+ const slide = shapes[0][SHAPE_SLIDE];
16710
+ const spTree = requireSpTree(slide);
16711
+ const elements = [];
16712
+ const seen = /* @__PURE__ */ new Set();
16713
+ let minX = Number.POSITIVE_INFINITY;
16714
+ let minY = Number.POSITIVE_INFINITY;
16715
+ let maxX = Number.NEGATIVE_INFINITY;
16716
+ let maxY = Number.NEGATIVE_INFINITY;
16717
+ for (const shape of shapes) {
16718
+ if (shape[SHAPE_SLIDE] !== slide) throw new Error("groupShapes: all shapes must belong to the same slide");
16719
+ const el = shape[SHAPE_ELEMENT];
16720
+ if (seen.has(el)) throw new Error(`groupShapes: shape "${shape[SHAPE_SNAPSHOT].name}" was passed twice`);
16721
+ seen.add(el);
16722
+ if (!spTree.children.includes(el)) throw new Error(`groupShapes: shape "${shape[SHAPE_SNAPSHOT].name}" is not a direct child of the slide (it may already be inside a group)`);
16723
+ const kind = shape[SHAPE_SNAPSHOT].kind;
16724
+ const pos = readPosition(el, kind);
16725
+ const size = readSize(el, kind);
16726
+ if (pos === null || size === null) throw new Error(`groupShapes: shape "${shape[SHAPE_SNAPSHOT].name}" has no explicit position/size (placeholders that inherit geometry from the layout can't be grouped)`);
16727
+ elements.push(el);
16728
+ minX = Math.min(minX, pos.x);
16729
+ minY = Math.min(minY, pos.y);
16730
+ maxX = Math.max(maxX, pos.x + size.w);
16731
+ maxY = Math.max(maxY, pos.y + size.h);
16732
+ }
16733
+ const grp = buildGroup({
16734
+ id: nextShapeId(slide),
16735
+ ...opts.name !== void 0 ? { name: opts.name } : {},
16736
+ x: minX,
16737
+ y: minY,
16738
+ w: maxX - minX,
16739
+ h: maxY - minY,
16740
+ children: elements
16741
+ });
16742
+ const insertAt = Math.min(...elements.map((el) => spTree.children.indexOf(el)));
16743
+ spTree.children = spTree.children.filter((c) => c.kind !== "element" || !seen.has(c));
16744
+ spTree.children.splice(insertAt, 0, grp);
16745
+ commitSlideData(slide);
16746
+ rebuildShapesFromDocument(slide);
16747
+ const created = slide[SLIDE_SHAPES].find((s) => s[SHAPE_ELEMENT] === grp);
16748
+ if (!created) throw new Error("groupShapes: post-condition failed");
16749
+ return created;
16750
+ };
16751
+ /**
16752
+ * Reverses `groupShapes`: removes the `<p:grpSp>` and re-inserts its
16753
+ * immediate children as top-level shapes at the group's former position,
16754
+ * rescaling each child's own transform so it keeps its on-slide position
16755
+ * and size (matters when the group was moved/resized after creation, so
16756
+ * its `off`/`ext` diverged from its `chOff`/`chExt`). Returns the
16757
+ * children as fresh `SlideShapeData` handles, in their original order.
16758
+ *
16759
+ * Throws if `group` isn't a group shape, or its `<p:grpSpPr>` carries no
16760
+ * `<a:xfrm>` (malformed — every authored group has one).
16761
+ */
16762
+ const ungroupShapes = (group) => {
16763
+ if (group[SHAPE_SNAPSHOT].kind !== "group") throw new Error("ungroupShapes: shape is not a group");
16764
+ const transform = getGroupTransform(group);
16765
+ if (!transform) throw new Error("ungroupShapes: group has no <a:xfrm> on <p:grpSpPr>");
16766
+ const { outer, inner } = transform;
16767
+ const scaleX = inner.w === 0 ? 1 : outer.w / inner.w;
16768
+ const scaleY = inner.h === 0 ? 1 : outer.h / inner.h;
16769
+ const slide = group[SHAPE_SLIDE];
16770
+ const spTree = requireSpTree(slide);
16771
+ const groupEl = group[SHAPE_ELEMENT];
16772
+ const idx = spTree.children.indexOf(groupEl);
16773
+ if (idx < 0) throw new Error("ungroupShapes: group is not attached to the slide");
16774
+ const childElements = readGroupChildren(groupEl).map((child) => {
16775
+ const pos = readPosition(child.element, child.kind);
16776
+ const size = readSize(child.element, child.kind);
16777
+ if (pos !== null && size !== null) {
16778
+ const newX = Math.round(outer.x + (pos.x - inner.x) * scaleX);
16779
+ const newY = Math.round(outer.y + (pos.y - inner.y) * scaleY);
16780
+ setPosition(child.element, child.kind, newX, newY);
16781
+ setSize(child.element, child.kind, Math.round(size.w * scaleX), Math.round(size.h * scaleY));
16782
+ }
16783
+ return child.element;
16784
+ });
16785
+ spTree.children.splice(idx, 1, ...childElements);
16786
+ commitSlideData(slide);
16787
+ rebuildShapesFromDocument(slide);
16788
+ const byElement = new Map(slide[SLIDE_SHAPES].map((s) => [s[SHAPE_ELEMENT], s]));
16789
+ return childElements.map((el) => {
16790
+ const found = byElement.get(el);
16791
+ if (!found) throw new Error("ungroupShapes: post-condition failed");
16792
+ return found;
16793
+ });
16794
+ };
16795
+ //#endregion
16051
16796
  //#region src/api/index.ts
16052
- const VERSION = "0.8.0";
16797
+ const VERSION = "0.10.0";
16053
16798
  //#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 };
16799
+ export { slideHasAnimations as $, getTableCells as $a, getAllHyperlinks as $i, getSlideMasterPartNames as $n, addSlideChart as $o, setParagraphBullet as $r, getPresentationCommentCountsByAuthor as $s, getShapeStrokeEffective as $t, getPresentationTextLength as A, getOrphanMediaPartNames as Aa, getShapeImageOpacity as Ai, getGroupTransform as An, getPresentationCreated as Ao, setShapeStrokeCompound as Ar, getSlideMasterBackgroundPatternFill as As, setShapeTextColumns as At, getSlideText as B, getPresentationTableCountsBySlide as Ba, SLIDE_SIZE_16_9 as Bi, getShapeFlip as Bn, getSlideLayoutName as Bo, getParagraphLevel as Br, findCommentAuthorByName as Bs, setShapeGlow as Bt, findSlideByTitle as C, setSlideNotes as Ca, getShapeImageBytes as Ci, replaceTokensInSlide as Cn, setTableStyleFlags as Co, setShapePatternFill as Cr, getSlideLayoutBackgroundImageBytes as Cs, getShapeTextWrap as Ct, getOutlineText as D, _internalPackageOf as Da, getShapeImageFillBytes as Di, findShapesAtPoint as Dn, setThumbnail as Do, setShapeStroke as Dr, getSlideMasterBackground as Ds, setShapeTextAnchor as Dt, getAllShapes as E, setSlideTransition as Ea, getShapeImageDuotone as Ei, centerShapeOnSlide as En, removeThumbnail as Eo, setShapeSize as Er, getSlideLayoutShapes as Es, setShapeText as Et, getSlideIndex as F, readPackagePart as Fa, setShapeImageBrightness as Fi, getShapeBounds as Fn, touchModified as Fo, getParagraphAlignment as Fr, setShapeClickAction as Fs, clearShapeEffects as Ft, isSlideHidden as G, getTableCellBorders as Ga, clearAllHyperlinks as Gi, getShapePlaceholderType as Gn, getSlideLayoutUsageCountsByType as Go, getShapeParagraphElements as Gr, findSlidesWithCommentsByAuthor as Gs, getShapeFillColor as Gt, getSlideXmlString as H, getTableCell as Ha, getSlideSize as Hi, getShapeKind as Hn, getSlideLayoutPlaceholders as Ho, getParagraphSpacing as Hr, findCommentsBefore as Hs, getShapeGradientFill as Ht, getSlideInfo as I, setMediaPartBytes as Ia, setShapeImageContrast as Ii, getShapeBoundsResolved as In, findLayoutsWithPlaceholderType as Io, getParagraphBullet as Ir, setShapeImage as Is, findShapesByEffect as It, replaceTextInSlide as J, getTableCellParagraphs as Ja, findSlidesByHyperlink as Ji, getShapeRotation as Jn, getParagraphPropertiesEffective as Jo, getShapeRunHyperlink as Jr, getCommentDate as Js, getShapeStroke as Jt, replaceTextInNotes as K, getTableCellFill as Ka, clearAllSlideNotes as Ki, getShapePosition as Kn, getSlideLayouts as Ko, getShapeRunClickAction as Kr, getCommentAuthor as Ks, getShapeFillColorResolved as Kt, getSlideLayoutCount as L, slidesUsingMediaPart as La, setShapeImageCrop as Li, getShapeCenter as Ln, findSlideLayout as Lo, getParagraphBulletImageBytes as Lr, addSlideComment as Ls, getShapeEffect as Lt, getShapeAt as M, getPresentationSummary as Ma, hasShapeImage as Mi, getMaxShapeIdInPresentation as Mn, incrementRevision as Mo, setShapeStrokeJoin as Mr, setSlideBackground as Ms, setShapeTextFormat as Mt, getSlideAt as N, getSlideMediaPartNames as Na, hasShapeText as Ni, getShapeAdjustValues as Nn, setCoreProperties as No, getShapeRunFormat as Nr, setSlideBackgroundImage as Ns, setShapeTextMargins as Nt, getPresentationShapeCountsBySlide as O, compactPackage as Oa, getShapeImageFormat as Oi, findShapesInRect as On, getCoreProperties as Oo, setShapeStrokeArrow as Or, getSlideMasterBackgroundGradientFill as Os, setShapeTextAutoFit as Ot, getSlideCount as P, listPackageParts as Pa, isShapeImageGrayscale as Pi, getShapeAltTitle as Pn, setExtendedProperties as Po, resolveDrawingColor as Pr, getShapeClickAction as Ps, setShapeTextWrap as Pt, setSlideHidden as Q, getTableCellTextDirection as Qa, getAllComments as Qi, getSlideMasterPartName as Qn, setShapeRunFormat as Qo, setParagraphAlignment as Qr, getCommentsSortedByDate as Qs, getShapeStrokeCompound as Qt, getSlideOutline as R, validatePresentation as Ra, setShapeImageOpacity as Ri, getShapeCustomGeometry as Rn, findSlideLayoutByPartName as Ro, getParagraphBulletStyle as Rr, clearAllSlideComments as Rs, getShapeEffects as Rt, findSlideByText as S, replaceHyperlink as Sa, getShapeImageBrightness as Si, getSlidesWithEmptyPlaceholders as Sn, setTableRowHeight as So, setShapeNoStroke as Sr, getSlideLayoutBackgroundGradientFill as Ss, getShapeTextMargins as St, findSlidesByText as T, getSlideTransition as Ta, getShapeImageCrop as Ti, translateShapes as Tn, getThumbnail as To, setShapeRotation as Tr, getSlideLayoutBackgroundShapes as Ts, setShapeBullets as Tt, getSlides as U, getTableCellAlignment as Ua, setSlideSize as Ui, getShapeName as Un, getSlideLayoutType as Uo, getShapeHyperlinkTooltip as Ur, findCommentsByAuthor as Us, getShapeGradientFillEffective as Ut, getSlideTextLength as V, getSlideTables as Va, SLIDE_SIZE_4_3 as Vi, getShapeId as Vn, getSlideLayoutPartName as Vo, getParagraphLineSpacing as Vr, findCommentsAfter as Vs, setShapeShadow as Vt, getSlidesByLayout as W, getTableCellAnchor as Wa, appendSlideNotes as Wi, getShapePlaceholderIdx as Wn, getSlideLayoutUsageCounts as Wo, getShapeParagraphCount as Wr, findCommentsByText as Ws, getShapeFill as Wt, replaceTokensInPresentation as X, getTableCellSpan as Xa, findSlidesWithChartTrendlines as Xi, getShapeText as Xn, getShapeRunFormatEffective as Xo, getShapeRunText as Xr, getCommentSlide as Xs, getShapeStrokeColor as Xt, replaceTextInSlideNotes as Y, getTableCellPosition as Ya, findSlidesWithChartKind as Yi, getShapeSize as Yn, getShapeHyperlink as Yo, getShapeRunHyperlinkTooltip as Yr, getCommentPosition as Ys, getShapeStrokeCap as Yt, searchSlides as Z, getTableCellText as Za, getAllCharts as Zi, getSlideMasterCount as Zn, setShapeHyperlink as Zo, isParagraphBulletPicture as Zr, getCommentText as Zs, getShapeStrokeColorResolved as Zt, sortSlides as _, getSlidesWithOverlap as _a, findSlidesByLayoutName as _i, getShapeSlide as _n, setTableCellMargins as _o, setShapeFill as _r, getSlideBackgroundGradientFill as _s, getShapeTextAutoFit as _t, addContentSlide as a, getHiddenSlides as aa, getPresentationFonts as ac, getSlideBody as ai, findShapeByText as an, getTableStyleId as ao, pointInShape as ar, getPresentationChartKindCounts as as, bringShapeForward as at, setSlideSections as b, hasSlideNotes as ba, getPresentationImageCountsBySlide as bi, getSlideLayout as bn, setTableCellTextFormat as bo, setShapeImageFill as br, getSlideColorMapOverride as bs, getShapeTextColumns as bt, addSlideAt as c, getPresentationNotesLengthsBySlide as ca, setPresentationTheme as cc, setSlidePlaceholders as ci, findShapesByKind as cn, isChartShape as co, setShapeBounds as cr, getShapeChartSeriesNames as cs, copyShape as ct, duplicateSlideAt as d, getSlideNotesLength as da, savePresentation as dc, findShapesWithAnimation as di, findShapesByText as dn, removeTableColumn as do, shapesOverlap as dr, getSlideCharts as ds, sendShapeBackward as dt, getAllImages as ea, getPresentationCommentCountsBySlide as ec, setParagraphLevel as ei, getShapeStrokeJoin as en, getTableColumnWidths as eo, getSlideMasterUsageCounts as er, findChartByKind as es, addSlideImage as et, importSlide as f, getSlidesWithCharts as fa, cm as fc, getShapeAnimation as fi, findShapesWithHyperlinks as fn, removeTableRow as fo, clearShapeFill as fr, setChartSpec as fs, sendShapeToBack as ft, reverseSlides as g, getSlidesWithNotes as ga, pt as gc, findShapesOutsideCanvas as gi, getShapeIndex as gn, setTableCellFill as go, getShapeStrokeDash as gr, getSlideBackground as gs, getShapeTextAnchor as gt, removeSlide as h, getSlidesWithImages as ha, mm as hc, findOverlappingShapePairs as hi, findSlidePlaceholders as hn, setTableCellBorders as ho, getShapeStrokeArrow as hr, clearSlideBackground as hs, getShapeBodyPrEffective as ht, addBlankSlide as i, getEmptySlides as ia, removeSlideComment as ic, setShapeRunText as ii, findShapeByName as in, getTableStyleFlags as io, isShapeTextBox as ir, getPresentationChartCountsBySlide as is, addSlideTextBox as it, getPresentationTextLengthsBySlide as j, getPackageSize as ja, getShapeImagePartName as ji, getMaxShapeId as jn, getPresentationModified as jo, setShapeStrokeDash as jr, getSlideMasterShapes as js, setShapeTextDirection as jt, getPresentationText as k, getMediaParts as ka, getShapeImageLinkUrl as ki, getGroupChildren as kn, getExtendedProperties as ko, setShapeStrokeCap as kr, getSlideMasterBackgroundImageBytes as ks, setShapeTextBodyRotationDeg as kt, addTitleSlide as l, getPresentationNotesText as la, createPresentation as lc, setSlideTitle as li, findShapesByName as ln, isTableShape as lo, setShapeDescription as lr, getShapeChartSeriesValues as ls, getShapeZIndex as lt, moveSlide as m, getSlidesWithHyperlinks as ma, inches as mc, findFlippedShapes as mi, findSlidePlaceholderByIdx as mn, setTableCellAnchor as mo, getShapePatternFill as mr, resolveDeckBodyTextColor as ms, appendShapeText as mt, groupShapes as n, getAllTables as na, getSlideCommentAuthors as nc, setParagraphSpacing as ni, findEmptyPlaceholders as nn, getTableRowHeights as no, isShapeHidden as nr, findChartsWithDataLabels as ns, addSlideShape as nt, addSectionHeaderSlide as o, getPresentationHyperlinkCountsBySlide as oa, getPresentationTheme as oc, getSlideTitle as oi, findShapeInPresentation as on, insertTableColumn as oo, renameShape as or, getShapeChartCategories as os, bringShapeToFront as ot, mergePresentations as p, getSlidesWithComments as pa, emu as pc, setShapeAnimation as pi, findSlidePlaceholder as pn, setTableCellAlignment as po, clearShapeStroke as pr, getEffectiveColorMap as ps, setShapeZIndex as pt, replaceTextInPresentation as q, getTableCellMargins as qa, clearSlideHyperlinks as qi, getShapePreset as qn, getUnusedSlideLayouts as qo, getShapeRunCount as qr, getCommentAuthors as qs, getShapeFillEffective as qt, ungroupShapes as r, getDistinctHyperlinkUrls as ra, getSlideComments as rc, setShapeRunHyperlink as ri, findShapeById as rn, getTableSize as ro, isShapePlaceholder as rr, findChartsWithTrendlines as rs, addSlideTable as rt, addSlide as s, getPresentationNotesLength as sa, setPresentationFonts as sc, setSlideBody as si, findShapesByHyperlink as sn, insertTableRow as so, setShapeAltTitle as sr, getShapeChartKind as ss, clearSlideShapes as st, VERSION as t, getAllNotes as ta, getPresentationCommenters as tc, setParagraphLineSpacing as ti, getShapeStrokeWidth as tn, getTableDimensions as to, getUnusedSlideMasters as tr, findChartsBySeriesName as ts, addSlideLine as tt, duplicateSlide as u, getSlideNotes as ua, loadPresentation as uc, clearSlideAnimations as ui, findShapesByPreset as un, mergeTableCells as uo, setShapeHidden as ur, getShapeChartSpec as us, removeShape as ut, swapSlides as v, getSlidesWithTables as va, findSlidesByLayoutPartName as vi, getShapeXmlString as vn, setTableCellText as vo, setShapeFlip as vr, getSlideBackgroundImageBytes as vs, getShapeTextAutoFitParams as vt, findSlidesByNotes as w, clearSlideTransition as wa, getShapeImageContrast as wi, setSlideLayout as wn, setTableStyleId as wo, setShapePosition as wr, getSlideLayoutBackgroundPatternFill as ws, setShapeAlignment as wt, findSlideByPartName as x, removeSlideNotes as xa, getShapeImageBiLevelThreshold as xi, getSlideShapes as xn, setTableColumnWidth as xo, setShapeNoFill as xr, getSlideLayoutBackground as xs, getShapeTextDirection as xt, getSlideSections as y, getVisibleSlides as ya, findSlidesByLayoutType as yi, getShapesBounds as yn, setTableCellTextDirection as yo, setShapeGradientFill as yr, getSlideBackgroundPatternFill as ys, getShapeTextBodyRotationDeg as yt, getSlidePartName as z, clearTableCellFill as za, SLIDE_SIZE_16_10 as zi, getShapeDescription as zn, findSlideLayoutByType as zo, getParagraphIndent as zr, clearSlideComments as zs, getShapeEffectsEffective as zt };
16055
16800
 
16056
- //# sourceMappingURL=api-284n4GCu.js.map
16801
+ //# sourceMappingURL=api-grq54JcQ.js.map