ooxml-core 1.19.2 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +12 -1
  2. package/dist/{PptxHandler-2V4PQL6O.mjs → PptxHandler-FYD7IYXT.mjs} +2 -2
  3. package/dist/PptxHandler-SITN3K3F.mjs +4 -0
  4. package/dist/{PptxHandler-6TNIQ7S5.cjs → PptxHandler-TEKISCJO.cjs} +3 -3
  5. package/dist/{PresentationBuilder-HQ6C7L4V.mjs → PresentationBuilder-EYI6Z2JP.mjs} +2 -2
  6. package/dist/{PresentationBuilder-G7MPEGXJ.mjs → PresentationBuilder-IMB4DVRN.mjs} +2 -2
  7. package/dist/{PresentationBuilder-RM52LCVN.cjs → PresentationBuilder-NCKASKXU.cjs} +5 -5
  8. package/dist/automation/index.cjs +257 -30
  9. package/dist/automation/index.mjs +256 -31
  10. package/dist/automation/xlsx-read.d.ts +56 -0
  11. package/dist/automation/xlsx-read.d.ts.map +1 -0
  12. package/dist/automation/xlsx.d.ts +105 -4
  13. package/dist/automation/xlsx.d.ts.map +1 -1
  14. package/dist/{chunk-M6GDBVQ7.mjs → chunk-GQYQQ3GA.mjs} +1 -1
  15. package/dist/{chunk-SLNQNVQM.mjs → chunk-LEV2SVMK.mjs} +1 -1
  16. package/dist/{chunk-JUABSM7C.mjs → chunk-LVM3IZJ2.mjs} +1 -1
  17. package/dist/{chunk-TJPUAUWL.mjs → chunk-MN27HKHM.mjs} +8 -194
  18. package/dist/{chunk-4FTUAD2B.mjs → chunk-MNXKRXFB.mjs} +715 -200
  19. package/dist/{chunk-R5FIHHGB.cjs → chunk-NXKATFM5.cjs} +1598 -1204
  20. package/dist/{chunk-ZJ2OKIJN.mjs → chunk-WXY5EDGT.mjs} +592 -198
  21. package/dist/index.cjs +25 -0
  22. package/dist/index.mjs +25 -0
  23. package/dist/pptx/automation/index.cjs +887 -453
  24. package/dist/pptx/automation/index.d.ts +2 -2
  25. package/dist/pptx/automation/index.mjs +5 -5
  26. package/dist/pptx/chunks/{index-Bqm-jFG-.d.ts → index-CgFX0T7b.d.ts} +7573 -7508
  27. package/dist/pptx/chunks/index-CgFX0T7b.d.ts.map +1 -0
  28. package/dist/pptx/chunks/{index-B9x557hr.d.ts → index-qwVYoFn6.d.ts} +2 -2
  29. package/dist/pptx/chunks/{index-B9x557hr.d.ts.map → index-qwVYoFn6.d.ts.map} +1 -1
  30. package/dist/pptx/cli/index.cjs +654 -221
  31. package/dist/pptx/cli/index.mjs +4 -4
  32. package/dist/pptx/converter/index.d.ts +1 -1
  33. package/dist/pptx/converter/index.mjs +2 -2
  34. package/dist/pptx/editor/render/find-replace.cjs +14 -14
  35. package/dist/pptx/editor/render/find-replace.d.ts +1 -1
  36. package/dist/pptx/editor/render/find-replace.mjs +1 -1
  37. package/dist/pptx/editor/render/slide-operations.cjs +8 -8
  38. package/dist/pptx/editor/render/slide-operations.mjs +2 -2
  39. package/dist/pptx/index.cjs +991 -619
  40. package/dist/pptx/index.d.ts +3 -3
  41. package/dist/pptx/index.mjs +5 -5
  42. package/dist/visio/index.cjs +61 -7
  43. package/dist/visio/index.mjs +61 -7
  44. package/dist/visio/ui/contract.d.ts +2 -1
  45. package/dist/visio/ui/contract.d.ts.map +1 -1
  46. package/dist/visio/ui/index.cjs +62 -7
  47. package/dist/visio/ui/index.mjs +62 -7
  48. package/dist/xlsx/edit/dimensions.d.ts.map +1 -1
  49. package/dist/xlsx/edit/history-rows.d.ts +7 -0
  50. package/dist/xlsx/edit/history-rows.d.ts.map +1 -0
  51. package/dist/xlsx/edit/history.d.ts +11 -1
  52. package/dist/xlsx/edit/history.d.ts.map +1 -1
  53. package/dist/xlsx/edit/outline.d.ts.map +1 -1
  54. package/dist/xlsx/edit/row-autofit.d.ts.map +1 -1
  55. package/dist/xlsx/index.cjs +90 -16
  56. package/dist/xlsx/index.mjs +90 -16
  57. package/dist/xlsx/load/index.cjs +61 -7
  58. package/dist/xlsx/load/index.mjs +61 -7
  59. package/dist/xlsx/numfmt/format.d.ts +8 -0
  60. package/dist/xlsx/numfmt/format.d.ts.map +1 -1
  61. package/dist/xlsx/read/sheet-data-source.d.ts.map +1 -1
  62. package/dist/xlsx/ui/index.cjs +138 -16
  63. package/dist/xlsx/ui/index.d.ts +1 -0
  64. package/dist/xlsx/ui/index.d.ts.map +1 -1
  65. package/dist/xlsx/ui/index.mjs +138 -17
  66. package/dist/xlsx/ui/selection-format.d.ts +13 -0
  67. package/dist/xlsx/ui/selection-format.d.ts.map +1 -0
  68. package/dist/xml/index.cjs +25 -0
  69. package/dist/xml/index.mjs +25 -0
  70. package/dist/xml/lite.d.ts.map +1 -1
  71. package/package.json +1 -1
  72. package/dist/PptxHandler-HSPKEP5E.mjs +0 -4
  73. package/dist/pptx/chunks/index-Bqm-jFG-.d.ts.map +0 -1
  74. /package/dist/{chunk-NYTR4UZ5.cjs → chunk-3IENHIFD.cjs} +0 -0
  75. /package/dist/{chunk-XTSHZGSM.mjs → chunk-CC5UNZOO.mjs} +0 -0
@@ -4180,13 +4180,14 @@ var init_SlideBuilder = __esm({
4180
4180
  "pptx/core/builders/sdk/SlideBuilder.ts"() {
4181
4181
  init_ElementFactory();
4182
4182
  SlideBuilder = class {
4183
- slide;
4184
4183
  /**
4185
4184
  * @param slideNumber - 1-based slide number.
4186
4185
  * @param layoutPath - Optional layout archive path.
4187
4186
  * @param layoutName - Optional layout display name.
4187
+ * @param handler - Loaded deck context for placeholder geometry and text styles.
4188
4188
  */
4189
- constructor(slideNumber, layoutPath, layoutName) {
4189
+ constructor(slideNumber, layoutPath, layoutName, handler) {
4190
+ this.handler = handler;
4190
4191
  this.slide = {
4191
4192
  id: `slide${slideNumber}`,
4192
4193
  rId: `rId${slideNumber + 1}`,
@@ -4196,11 +4197,52 @@ var init_SlideBuilder = __esm({
4196
4197
  layoutName: layoutName ?? "Title Slide"
4197
4198
  };
4198
4199
  }
4200
+ handler;
4201
+ slide;
4199
4202
  /** Add a text box to the slide. */
4200
4203
  addText(text2, options) {
4201
4204
  this.slide.elements.push(createTextElement(text2, options));
4202
4205
  return this;
4203
4206
  }
4207
+ /**
4208
+ * Fill a layout placeholder, inheriting its frame and text styles.
4209
+ *
4210
+ * Unlike addText, this writes a real p:ph binding, not a free text box.
4211
+ * Use idx to select repeated slots (for example, Two Content's 1 and 2).
4212
+ * Explicit frame fields override the layout; all other fields inherit.
4213
+ * A standalone builder requires the fourth constructor argument (a loaded
4214
+ * handler), even with an explicit frame, so text styles resolve consistently.
4215
+ * Missing slots without a complete frame throw instead of creating a text box.
4216
+ * Master frames requiring compatible-role fallback are materialized locally
4217
+ * for new content only, keeping existing-deck loading unchanged.
4218
+ *
4219
+ * @example
4220
+ * ```ts
4221
+ * createSlide('Title Slide')
4222
+ * .addPlaceholder('ctrTitle', 'Quarterly review')
4223
+ * .addPlaceholder('subTitle', 'October 2026');
4224
+ * createSlide('Two Content').addPlaceholder('body', 'Right column', { idx: 2 });
4225
+ * ```
4226
+ */
4227
+ addPlaceholder(type, text2, options = {}) {
4228
+ const input = createTextElement(text2);
4229
+ const context = `Slide ${this.slide.slideNumber} (${this.slide.id}), placeholder ${type} idx=${options.idx ?? "auto"}, layout ${this.slide.layoutName} (${this.slide.layoutPath})`;
4230
+ try {
4231
+ if (!this.handler) {
4232
+ throw new Error(
4233
+ "addPlaceholder requires a loaded handler as the fourth SlideBuilder constructor argument"
4234
+ );
4235
+ }
4236
+ this.slide.elements.push(
4237
+ this.handler.createPlaceholderElement(this.slide.layoutPath, input, type, options)
4238
+ );
4239
+ } catch (error) {
4240
+ throw new Error(`${context}: ${error instanceof Error ? error.message : String(error)}`, {
4241
+ cause: error
4242
+ });
4243
+ }
4244
+ return this;
4245
+ }
4204
4246
  /** Add a shape to the slide. */
4205
4247
  addShape(shapeType, options) {
4206
4248
  this.slide.elements.push(createShapeElement(shapeType, options));
@@ -4440,6 +4482,242 @@ var init_SlideBuilder = __esm({
4440
4482
  };
4441
4483
  }
4442
4484
  });
4485
+ function isSafePartName(name) {
4486
+ if (name.includes("\0") || name.includes("\\")) return false;
4487
+ if (/^[A-Za-z]:/u.test(name)) return false;
4488
+ const body = name.startsWith("/") ? name.slice(1) : name;
4489
+ if (body.startsWith("/")) return false;
4490
+ return !body.split("/").some((segment) => segment === "..");
4491
+ }
4492
+ function declaredEntrySize(entry2) {
4493
+ const data = entry2._data;
4494
+ const size = Number(data?.uncompressedSize ?? 0);
4495
+ return Number.isFinite(size) && size > 0 ? size : 0;
4496
+ }
4497
+ function resolveLimits(limits) {
4498
+ const create = limits.createError;
4499
+ return {
4500
+ maxEntries: limits.maxEntries ?? DEFAULT_ZIP_LIMITS.maxEntries,
4501
+ maxEntryBytes: limits.maxEntryBytes ?? DEFAULT_ZIP_LIMITS.maxEntryBytes,
4502
+ maxTotalBytes: limits.maxTotalBytes ?? DEFAULT_ZIP_LIMITS.maxTotalBytes,
4503
+ label: limits.label ?? "ZIP",
4504
+ fail: (message, limit) => create ? create(message, { limit }) : new ZipLimitError(message, { limit })
4505
+ };
4506
+ }
4507
+ function inflateEntryGuarded(entry2, alreadyRead, limits) {
4508
+ const r = resolveLimits(limits);
4509
+ const declared = declaredEntrySize(entry2);
4510
+ return new Promise((resolvePromise, reject) => {
4511
+ const chunks = [];
4512
+ let size = 0;
4513
+ let done = false;
4514
+ const stream = entry2.internalStream("uint8array");
4515
+ const abort = (error) => {
4516
+ if (done) return;
4517
+ done = true;
4518
+ stream.pause();
4519
+ chunks.length = 0;
4520
+ reject(error);
4521
+ };
4522
+ stream.on("data", (chunk2) => {
4523
+ if (done) return;
4524
+ size += chunk2.byteLength;
4525
+ if (size > declared || size > r.maxEntryBytes)
4526
+ return abort(
4527
+ r.fail(`${r.label} part ${entry2.name} inflates past its declared size`, r.maxEntryBytes)
4528
+ );
4529
+ if (alreadyRead + size > r.maxTotalBytes)
4530
+ return abort(
4531
+ r.fail(
4532
+ `${r.label} package exceeds the ${mib(r.maxTotalBytes)} MiB uncompressed content limit`,
4533
+ r.maxTotalBytes
4534
+ )
4535
+ );
4536
+ chunks.push(chunk2);
4537
+ });
4538
+ stream.on("error", (error) => abort(error));
4539
+ stream.on("end", () => {
4540
+ if (done) return;
4541
+ done = true;
4542
+ if (chunks.length === 1 && chunks[0]) return resolvePromise(chunks[0]);
4543
+ const out = new Uint8Array(size);
4544
+ let offset = 0;
4545
+ for (const chunk2 of chunks) {
4546
+ out.set(chunk2, offset);
4547
+ offset += chunk2.byteLength;
4548
+ }
4549
+ resolvePromise(out);
4550
+ });
4551
+ stream.resume();
4552
+ });
4553
+ }
4554
+ function toBase64(bytes) {
4555
+ let binary = "";
4556
+ for (let i2 = 0; i2 < bytes.length; i2 += 32768)
4557
+ binary += String.fromCharCode(...bytes.subarray(i2, i2 + 32768));
4558
+ return btoa(binary);
4559
+ }
4560
+ function guardZip(zip, limits = {}) {
4561
+ const r = resolveLimits(limits);
4562
+ const entries = Object.values(zip.files);
4563
+ if (entries.length > r.maxEntries)
4564
+ throw r.fail(
4565
+ `${r.label} package exceeds the ${r.maxEntries.toLocaleString("en-US")} part limit`,
4566
+ r.maxEntries
4567
+ );
4568
+ let declared = 0;
4569
+ for (const entry2 of entries) {
4570
+ const original = entry2.unsafeOriginalName;
4571
+ if (!isSafePartName(entry2.name) || original !== void 0 && !isSafePartName(original))
4572
+ throw r.fail(`${r.label} package has an unsafe part name`, r.maxEntries);
4573
+ if (entry2.dir) continue;
4574
+ const size = declaredEntrySize(entry2);
4575
+ if (size > r.maxEntryBytes)
4576
+ throw r.fail(
4577
+ `${r.label} part ${entry2.name} exceeds the uncompressed part size limit`,
4578
+ r.maxEntryBytes
4579
+ );
4580
+ declared += size;
4581
+ }
4582
+ if (declared > r.maxTotalBytes)
4583
+ throw r.fail(
4584
+ `${r.label} package exceeds the ${mib(r.maxTotalBytes)} MiB uncompressed content limit`,
4585
+ r.maxTotalBytes
4586
+ );
4587
+ const produced = /* @__PURE__ */ new Map();
4588
+ let total = 0;
4589
+ for (const entry2 of entries) {
4590
+ if (entry2.dir) continue;
4591
+ const inflateOriginal = entry2.async.bind(entry2);
4592
+ entry2.async = async (type, onUpdate) => {
4593
+ const previous = produced.get(entry2.name) ?? 0;
4594
+ const bytes = await inflateEntryGuarded(entry2, total - previous, limits);
4595
+ if (bytes.byteLength > previous) {
4596
+ total += bytes.byteLength - previous;
4597
+ produced.set(entry2.name, bytes.byteLength);
4598
+ }
4599
+ switch (type) {
4600
+ case "uint8array":
4601
+ return bytes;
4602
+ case "string":
4603
+ case "text":
4604
+ return new TextDecoder("utf-8", { ignoreBOM: true }).decode(bytes);
4605
+ case "arraybuffer":
4606
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
4607
+ case "base64":
4608
+ return toBase64(bytes);
4609
+ default:
4610
+ return inflateOriginal(type, onUpdate);
4611
+ }
4612
+ };
4613
+ }
4614
+ return zip;
4615
+ }
4616
+ async function openZip(input, limits = {}) {
4617
+ const r = resolveLimits(limits);
4618
+ const maxInput = limits.maxInputBytes ?? DEFAULT_ZIP_LIMITS.maxInputBytes;
4619
+ const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
4620
+ if (bytes.byteLength > maxInput)
4621
+ throw r.fail(
4622
+ `${r.label} package exceeds the ${mib(maxInput)} MiB compressed input limit`,
4623
+ maxInput
4624
+ );
4625
+ return guardZip(await JSZip__default.default.loadAsync(bytes), limits);
4626
+ }
4627
+ var DEFAULT_ZIP_LIMITS, ZipLimitError, mib;
4628
+ var init_zip_limits = __esm({
4629
+ "opc/zip-limits.ts"() {
4630
+ DEFAULT_ZIP_LIMITS = {
4631
+ maxInputBytes: 100 * 1024 * 1024,
4632
+ maxEntries: 1e4,
4633
+ maxEntryBytes: 100 * 1024 * 1024,
4634
+ maxTotalBytes: 100 * 1024 * 1024
4635
+ };
4636
+ ZipLimitError = class extends Error {
4637
+ code = "ZIP_BOMB";
4638
+ limit;
4639
+ constructor(message, details) {
4640
+ super(message);
4641
+ this.name = "ZipLimitError";
4642
+ this.limit = details.limit;
4643
+ }
4644
+ };
4645
+ mib = (bytes) => Math.round(bytes / 1048576);
4646
+ }
4647
+ });
4648
+
4649
+ // pptx/core/core/types.ts
4650
+ var DEFAULT_MAX_UNCOMPRESSED_BYTES, MAX_ZIP_ENTRY_COUNT, ZipBombError;
4651
+ var init_types2 = __esm({
4652
+ "pptx/core/core/types.ts"() {
4653
+ DEFAULT_MAX_UNCOMPRESSED_BYTES = 500 * 1024 * 1024;
4654
+ MAX_ZIP_ENTRY_COUNT = 65536;
4655
+ ZipBombError = class extends Error {
4656
+ code = "ZIP_BOMB";
4657
+ uncompressedBytes;
4658
+ limit;
4659
+ entryCount;
4660
+ constructor(message, details) {
4661
+ super(message);
4662
+ this.name = "ZipBombError";
4663
+ this.uncompressedBytes = details.uncompressedBytes;
4664
+ this.limit = details.limit;
4665
+ this.entryCount = details.entryCount;
4666
+ }
4667
+ };
4668
+ }
4669
+ });
4670
+
4671
+ // pptx/core/utils/zip-open.ts
4672
+ function openPptxZip(bytes) {
4673
+ return openZip(bytes, {
4674
+ label: "PPTX",
4675
+ maxInputBytes: DEFAULT_MAX_UNCOMPRESSED_BYTES,
4676
+ maxEntries: MAX_ZIP_ENTRY_COUNT,
4677
+ maxEntryBytes: DEFAULT_MAX_UNCOMPRESSED_BYTES,
4678
+ maxTotalBytes: DEFAULT_MAX_UNCOMPRESSED_BYTES,
4679
+ createError
4680
+ });
4681
+ }
4682
+ function openNestedZip(bytes) {
4683
+ return openZip(bytes, { label: "Embedded", createError });
4684
+ }
4685
+ var createError;
4686
+ var init_zip_open = __esm({
4687
+ "pptx/core/utils/zip-open.ts"() {
4688
+ init_zip_limits();
4689
+ init_types2();
4690
+ createError = (message, details) => new ZipBombError(message, details);
4691
+ }
4692
+ });
4693
+
4694
+ // pptx/core/builders/sdk/layout-operations.ts
4695
+ function pxToEmu(px2) {
4696
+ return Math.round(px2 * EMU_PER_PIXEL2);
4697
+ }
4698
+ function placeholderSpXml(ph, shapeId) {
4699
+ const name = ph.name ?? `${ph.type.charAt(0).toUpperCase() + ph.type.slice(1)} Placeholder ${shapeId - 1}`;
4700
+ const x = pxToEmu(ph.x);
4701
+ const y = pxToEmu(ph.y);
4702
+ const cx = pxToEmu(ph.width);
4703
+ const cy = pxToEmu(ph.height);
4704
+ const idxAttr = ph.idx !== void 0 ? ` idx="${Math.max(0, Math.round(ph.idx))}"` : "";
4705
+ return ` <p:sp>
4706
+ <p:nvSpPr>
4707
+ <p:cNvPr id="${shapeId}" name="${escAttr(name)}"/>
4708
+ <p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr>
4709
+ <p:nvPr><p:ph type="${escAttr(ph.type)}"${idxAttr}/></p:nvPr>
4710
+ </p:nvSpPr>
4711
+ <p:spPr>
4712
+ <a:xfrm><a:off x="${x}" y="${y}"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>
4713
+ </p:spPr>
4714
+ <p:txBody>
4715
+ <a:bodyPr/>
4716
+ <a:lstStyle/>
4717
+ <a:p><a:endParaRPr lang="en-US"/></a:p>
4718
+ </p:txBody>
4719
+ </p:sp>`;
4720
+ }
4443
4721
  function normalizeSrgbHex(color2) {
4444
4722
  if (!color2) {
4445
4723
  return void 0;
@@ -4453,10 +4731,134 @@ function normalizeSrgbHex(color2) {
4453
4731
  }
4454
4732
  return void 0;
4455
4733
  }
4734
+ function generateLayoutXml(definition) {
4735
+ const layoutType = definition.type ?? "obj";
4736
+ const placeholders = definition.placeholders ?? [];
4737
+ const phShapes = placeholders.map((ph, i2) => placeholderSpXml(ph, i2 + 2)).join("\n");
4738
+ let bgXml = "";
4739
+ const hex3 = normalizeSrgbHex(definition.backgroundColor);
4740
+ if (hex3) {
4741
+ bgXml = ` <p:bg><p:bgPr><a:solidFill><a:srgbClr val="${hex3}"/></a:solidFill><a:effectLst/></p:bgPr></p:bg>
4742
+ `;
4743
+ }
4744
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
4745
+ <p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
4746
+ xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
4747
+ xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
4748
+ type="${escAttr(layoutType)}" preserve="1">
4749
+ <p:cSld name="${escAttr(definition.name)}">
4750
+ ${bgXml} <p:spTree>
4751
+ <p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>
4752
+ <p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr>
4753
+ ${phShapes}
4754
+ </p:spTree>
4755
+ </p:cSld>
4756
+ <p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr>
4757
+ </p:sldLayout>`;
4758
+ }
4759
+ function findLayoutByName(data, name) {
4760
+ const lowerName = name.toLowerCase();
4761
+ const fromOptions = data.layoutOptions?.find((l) => l.name.toLowerCase() === lowerName);
4762
+ if (fromOptions) {
4763
+ return fromOptions;
4764
+ }
4765
+ if (data.slideMasters) {
4766
+ for (const master of data.slideMasters) {
4767
+ const layout = master.layouts?.find((l) => l.name?.toLowerCase() === lowerName);
4768
+ if (layout) {
4769
+ return { path: layout.path, name: layout.name ?? name };
4770
+ }
4771
+ }
4772
+ }
4773
+ return void 0;
4774
+ }
4775
+ function findLayoutByType(data, type) {
4776
+ const fromOptions = data.layoutOptions?.find((l) => l.type === type);
4777
+ if (fromOptions) {
4778
+ return fromOptions;
4779
+ }
4780
+ return void 0;
4781
+ }
4782
+ var EMU_PER_PIXEL2;
4783
+ var init_layout_operations = __esm({
4784
+ "pptx/core/builders/sdk/layout-operations.ts"() {
4785
+ init_xml_utils();
4786
+ EMU_PER_PIXEL2 = 9525;
4787
+ }
4788
+ });
4789
+
4790
+ // pptx/core/builders/sdk/standard-layout-placeholders.ts
4791
+ function standardLayoutPlaceholders(type, width, height) {
4792
+ if (type === "blank") return [];
4793
+ const box = (type2, idx, x, y, w, h2) => ({
4794
+ type: type2,
4795
+ idx,
4796
+ x: x * width,
4797
+ y: y * height,
4798
+ width: w * width,
4799
+ height: h2 * height
4800
+ });
4801
+ const title = box("title", 0, 0.05, 0.04, 0.9, 0.15);
4802
+ const content2 = box("obj", 1, 0.05, 0.23, 0.9, 0.64);
4803
+ let slots;
4804
+ switch (type) {
4805
+ case "title":
4806
+ slots = [
4807
+ box("ctrTitle", 0, 0.08, 0.24, 0.84, 0.22),
4808
+ box("subTitle", 1, 0.12, 0.49, 0.76, 0.2)
4809
+ ];
4810
+ break;
4811
+ case "secHead":
4812
+ slots = [box("title", 0, 0.05, 0.37, 0.9, 0.2), box("body", 1, 0.05, 0.6, 0.9, 0.23)];
4813
+ break;
4814
+ case "twoObj":
4815
+ case "twoTxTwoObj":
4816
+ slots = [title, box("obj", 1, 0.05, 0.27, 0.43, 0.6), box("obj", 2, 0.52, 0.27, 0.43, 0.6)];
4817
+ if (type === "twoTxTwoObj")
4818
+ slots.push(box("body", 3, 0.05, 0.2, 0.43, 0.07), box("body", 4, 0.52, 0.2, 0.43, 0.07));
4819
+ break;
4820
+ case "titleOnly":
4821
+ slots = [title];
4822
+ break;
4823
+ case "objTx":
4824
+ case "picTx":
4825
+ slots = [
4826
+ title,
4827
+ box(type === "picTx" ? "pic" : "obj", 1, 0.36, 0.23, 0.59, 0.64),
4828
+ box("body", 2, 0.05, 0.23, 0.27, 0.64)
4829
+ ];
4830
+ break;
4831
+ default:
4832
+ slots = [title, content2];
4833
+ }
4834
+ return [
4835
+ ...slots,
4836
+ box("dt", 10, 0.05, 0.92, 0.25, 0.04),
4837
+ box("ftr", 11, 0.33, 0.92, 0.34, 0.04),
4838
+ box("sldNum", 12, 0.75, 0.92, 0.2, 0.04)
4839
+ ];
4840
+ }
4841
+ var init_standard_layout_placeholders = __esm({
4842
+ "pptx/core/builders/sdk/standard-layout-placeholders.ts"() {
4843
+ }
4844
+ });
4845
+ function normalizeSrgbHex2(color2) {
4846
+ if (!color2) {
4847
+ return void 0;
4848
+ }
4849
+ const raw = color2.trim().replace(/^#/, "").toUpperCase();
4850
+ if (/^[0-9A-F]{6}$/.test(raw)) {
4851
+ return raw;
4852
+ }
4853
+ if (/^[0-9A-F]{3}$/.test(raw)) {
4854
+ return raw.replace(/./g, (ch) => ch + ch);
4855
+ }
4856
+ return void 0;
4857
+ }
4456
4858
  function resolveThemeColors(overrides) {
4457
4859
  const resolved = {};
4458
4860
  for (const [key2, fallback] of Object.entries(DEFAULT_COLORS)) {
4459
- resolved[key2] = normalizeSrgbHex(overrides?.[key2]) ?? normalizeSrgbHex(fallback) ?? "000000";
4861
+ resolved[key2] = normalizeSrgbHex2(overrides?.[key2]) ?? normalizeSrgbHex2(fallback) ?? "000000";
4460
4862
  }
4461
4863
  return resolved;
4462
4864
  }
@@ -4596,21 +4998,6 @@ ${layoutRels}
4596
4998
  <Relationship Id="rId${layoutCount + 1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="../theme/theme1.xml"/>
4597
4999
  </Relationships>`;
4598
5000
  }
4599
- function slideLayoutXml(name, layoutType) {
4600
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
4601
- <p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
4602
- xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
4603
- xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
4604
- type="${escAttr(layoutType)}" preserve="1">
4605
- <p:cSld name="${escAttr(name)}">
4606
- <p:spTree>
4607
- <p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>
4608
- <p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr>
4609
- </p:spTree>
4610
- </p:cSld>
4611
- <p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr>
4612
- </p:sldLayout>`;
4613
- }
4614
5001
  function slideLayoutRelsXml() {
4615
5002
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
4616
5003
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
@@ -4759,7 +5146,14 @@ async function buildBlankPresentationArchive(options) {
4759
5146
  zip.file("ppt/slideMasters/_rels/slideMaster1.xml.rels", slideMasterRelsXml(layoutCount));
4760
5147
  for (let i2 = 0; i2 < layoutCount; i2++) {
4761
5148
  const layout = STANDARD_LAYOUTS[i2];
4762
- zip.file(`ppt/slideLayouts/slideLayout${i2 + 1}.xml`, slideLayoutXml(layout.name, layout.type));
5149
+ zip.file(
5150
+ `ppt/slideLayouts/slideLayout${i2 + 1}.xml`,
5151
+ generateLayoutXml({
5152
+ name: layout.name,
5153
+ type: layout.type,
5154
+ placeholders: standardLayoutPlaceholders(layout.type, width / 9525, height / 9525)
5155
+ })
5156
+ );
4763
5157
  zip.file(`ppt/slideLayouts/_rels/slideLayout${i2 + 1}.xml.rels`, slideLayoutRelsXml());
4764
5158
  }
4765
5159
  for (let i2 = 0; i2 < initialSlideCount; i2++) {
@@ -4780,6 +5174,8 @@ var init_PresentationBuilder = __esm({
4780
5174
  init_xml_utils();
4781
5175
  init_PptxHandler();
4782
5176
  init_SlideBuilder();
5177
+ init_layout_operations();
5178
+ init_standard_layout_placeholders();
4783
5179
  DEFAULT_WIDTH = 12192e3;
4784
5180
  DEFAULT_HEIGHT = 6858e3;
4785
5181
  DEFAULT_COLORS = {
@@ -4837,7 +5233,7 @@ var init_PresentationBuilder = __esm({
4837
5233
  const layoutIdx = STANDARD_LAYOUTS.findIndex((l) => l.name === layoutName) + 1 || 7;
4838
5234
  const layoutPath = `ppt/slideLayouts/slideLayout${layoutIdx}.xml`;
4839
5235
  const resolvedName = layoutName ?? STANDARD_LAYOUTS[layoutIdx - 1]?.name ?? "Blank";
4840
- return new SlideBuilder(slideNum, layoutPath, resolvedName);
5236
+ return new SlideBuilder(slideNum, layoutPath, resolvedName, handler);
4841
5237
  };
4842
5238
  return { handler, data, createSlide };
4843
5239
  }
@@ -17239,214 +17635,6 @@ var init_ole_embedded_replace = __esm({
17239
17635
  CONTENTS_STREAM2 = "CONTENTS";
17240
17636
  }
17241
17637
  });
17242
- function isSafePartName(name) {
17243
- if (name.includes("\0") || name.includes("\\")) return false;
17244
- if (/^[A-Za-z]:/u.test(name)) return false;
17245
- const body = name.startsWith("/") ? name.slice(1) : name;
17246
- if (body.startsWith("/")) return false;
17247
- return !body.split("/").some((segment) => segment === "..");
17248
- }
17249
- function declaredEntrySize(entry2) {
17250
- const data = entry2._data;
17251
- const size = Number(data?.uncompressedSize ?? 0);
17252
- return Number.isFinite(size) && size > 0 ? size : 0;
17253
- }
17254
- function resolveLimits(limits) {
17255
- const create = limits.createError;
17256
- return {
17257
- maxEntries: limits.maxEntries ?? DEFAULT_ZIP_LIMITS.maxEntries,
17258
- maxEntryBytes: limits.maxEntryBytes ?? DEFAULT_ZIP_LIMITS.maxEntryBytes,
17259
- maxTotalBytes: limits.maxTotalBytes ?? DEFAULT_ZIP_LIMITS.maxTotalBytes,
17260
- label: limits.label ?? "ZIP",
17261
- fail: (message, limit) => create ? create(message, { limit }) : new ZipLimitError(message, { limit })
17262
- };
17263
- }
17264
- function inflateEntryGuarded(entry2, alreadyRead, limits) {
17265
- const r = resolveLimits(limits);
17266
- const declared = declaredEntrySize(entry2);
17267
- return new Promise((resolvePromise, reject) => {
17268
- const chunks = [];
17269
- let size = 0;
17270
- let done = false;
17271
- const stream = entry2.internalStream("uint8array");
17272
- const abort = (error) => {
17273
- if (done) return;
17274
- done = true;
17275
- stream.pause();
17276
- chunks.length = 0;
17277
- reject(error);
17278
- };
17279
- stream.on("data", (chunk2) => {
17280
- if (done) return;
17281
- size += chunk2.byteLength;
17282
- if (size > declared || size > r.maxEntryBytes)
17283
- return abort(
17284
- r.fail(`${r.label} part ${entry2.name} inflates past its declared size`, r.maxEntryBytes)
17285
- );
17286
- if (alreadyRead + size > r.maxTotalBytes)
17287
- return abort(
17288
- r.fail(
17289
- `${r.label} package exceeds the ${mib(r.maxTotalBytes)} MiB uncompressed content limit`,
17290
- r.maxTotalBytes
17291
- )
17292
- );
17293
- chunks.push(chunk2);
17294
- });
17295
- stream.on("error", (error) => abort(error));
17296
- stream.on("end", () => {
17297
- if (done) return;
17298
- done = true;
17299
- if (chunks.length === 1 && chunks[0]) return resolvePromise(chunks[0]);
17300
- const out = new Uint8Array(size);
17301
- let offset = 0;
17302
- for (const chunk2 of chunks) {
17303
- out.set(chunk2, offset);
17304
- offset += chunk2.byteLength;
17305
- }
17306
- resolvePromise(out);
17307
- });
17308
- stream.resume();
17309
- });
17310
- }
17311
- function toBase64(bytes) {
17312
- let binary = "";
17313
- for (let i2 = 0; i2 < bytes.length; i2 += 32768)
17314
- binary += String.fromCharCode(...bytes.subarray(i2, i2 + 32768));
17315
- return btoa(binary);
17316
- }
17317
- function guardZip(zip, limits = {}) {
17318
- const r = resolveLimits(limits);
17319
- const entries = Object.values(zip.files);
17320
- if (entries.length > r.maxEntries)
17321
- throw r.fail(
17322
- `${r.label} package exceeds the ${r.maxEntries.toLocaleString("en-US")} part limit`,
17323
- r.maxEntries
17324
- );
17325
- let declared = 0;
17326
- for (const entry2 of entries) {
17327
- const original = entry2.unsafeOriginalName;
17328
- if (!isSafePartName(entry2.name) || original !== void 0 && !isSafePartName(original))
17329
- throw r.fail(`${r.label} package has an unsafe part name`, r.maxEntries);
17330
- if (entry2.dir) continue;
17331
- const size = declaredEntrySize(entry2);
17332
- if (size > r.maxEntryBytes)
17333
- throw r.fail(
17334
- `${r.label} part ${entry2.name} exceeds the uncompressed part size limit`,
17335
- r.maxEntryBytes
17336
- );
17337
- declared += size;
17338
- }
17339
- if (declared > r.maxTotalBytes)
17340
- throw r.fail(
17341
- `${r.label} package exceeds the ${mib(r.maxTotalBytes)} MiB uncompressed content limit`,
17342
- r.maxTotalBytes
17343
- );
17344
- const produced = /* @__PURE__ */ new Map();
17345
- let total = 0;
17346
- for (const entry2 of entries) {
17347
- if (entry2.dir) continue;
17348
- const inflateOriginal = entry2.async.bind(entry2);
17349
- entry2.async = async (type, onUpdate) => {
17350
- const previous = produced.get(entry2.name) ?? 0;
17351
- const bytes = await inflateEntryGuarded(entry2, total - previous, limits);
17352
- if (bytes.byteLength > previous) {
17353
- total += bytes.byteLength - previous;
17354
- produced.set(entry2.name, bytes.byteLength);
17355
- }
17356
- switch (type) {
17357
- case "uint8array":
17358
- return bytes;
17359
- case "string":
17360
- case "text":
17361
- return new TextDecoder("utf-8", { ignoreBOM: true }).decode(bytes);
17362
- case "arraybuffer":
17363
- return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
17364
- case "base64":
17365
- return toBase64(bytes);
17366
- default:
17367
- return inflateOriginal(type, onUpdate);
17368
- }
17369
- };
17370
- }
17371
- return zip;
17372
- }
17373
- async function openZip(input, limits = {}) {
17374
- const r = resolveLimits(limits);
17375
- const maxInput = limits.maxInputBytes ?? DEFAULT_ZIP_LIMITS.maxInputBytes;
17376
- const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
17377
- if (bytes.byteLength > maxInput)
17378
- throw r.fail(
17379
- `${r.label} package exceeds the ${mib(maxInput)} MiB compressed input limit`,
17380
- maxInput
17381
- );
17382
- return guardZip(await JSZip__default.default.loadAsync(bytes), limits);
17383
- }
17384
- var DEFAULT_ZIP_LIMITS, ZipLimitError, mib;
17385
- var init_zip_limits = __esm({
17386
- "opc/zip-limits.ts"() {
17387
- DEFAULT_ZIP_LIMITS = {
17388
- maxInputBytes: 100 * 1024 * 1024,
17389
- maxEntries: 1e4,
17390
- maxEntryBytes: 100 * 1024 * 1024,
17391
- maxTotalBytes: 100 * 1024 * 1024
17392
- };
17393
- ZipLimitError = class extends Error {
17394
- code = "ZIP_BOMB";
17395
- limit;
17396
- constructor(message, details) {
17397
- super(message);
17398
- this.name = "ZipLimitError";
17399
- this.limit = details.limit;
17400
- }
17401
- };
17402
- mib = (bytes) => Math.round(bytes / 1048576);
17403
- }
17404
- });
17405
-
17406
- // pptx/core/core/types.ts
17407
- var DEFAULT_MAX_UNCOMPRESSED_BYTES, MAX_ZIP_ENTRY_COUNT, ZipBombError;
17408
- var init_types2 = __esm({
17409
- "pptx/core/core/types.ts"() {
17410
- DEFAULT_MAX_UNCOMPRESSED_BYTES = 500 * 1024 * 1024;
17411
- MAX_ZIP_ENTRY_COUNT = 65536;
17412
- ZipBombError = class extends Error {
17413
- code = "ZIP_BOMB";
17414
- uncompressedBytes;
17415
- limit;
17416
- entryCount;
17417
- constructor(message, details) {
17418
- super(message);
17419
- this.name = "ZipBombError";
17420
- this.uncompressedBytes = details.uncompressedBytes;
17421
- this.limit = details.limit;
17422
- this.entryCount = details.entryCount;
17423
- }
17424
- };
17425
- }
17426
- });
17427
-
17428
- // pptx/core/utils/zip-open.ts
17429
- function openPptxZip(bytes) {
17430
- return openZip(bytes, {
17431
- label: "PPTX",
17432
- maxInputBytes: DEFAULT_MAX_UNCOMPRESSED_BYTES,
17433
- maxEntries: MAX_ZIP_ENTRY_COUNT,
17434
- maxEntryBytes: DEFAULT_MAX_UNCOMPRESSED_BYTES,
17435
- maxTotalBytes: DEFAULT_MAX_UNCOMPRESSED_BYTES,
17436
- createError
17437
- });
17438
- }
17439
- function openNestedZip(bytes) {
17440
- return openZip(bytes, { label: "Embedded", createError });
17441
- }
17442
- var createError;
17443
- var init_zip_open = __esm({
17444
- "pptx/core/utils/zip-open.ts"() {
17445
- init_zip_limits();
17446
- init_types2();
17447
- createError = (message, details) => new ZipBombError(message, details);
17448
- }
17449
- });
17450
17638
 
17451
17639
  // pptx/core/utils/ole-payload-kind.ts
17452
17640
  function isZipMagic(bytes) {
@@ -61672,6 +61860,165 @@ var init_inherited_shape_transform = __esm({
61672
61860
  }
61673
61861
  });
61674
61862
 
61863
+ // pptx/core/utils/placeholder-xml.ts
61864
+ function findNonVisualProps(rawXml) {
61865
+ for (const container2 of ["p:nvSpPr", "p:nvPicPr", "p:nvGraphicFramePr"]) {
61866
+ const parent = rawXml[container2];
61867
+ const nvPr = parent?.["p:nvPr"];
61868
+ if (nvPr) {
61869
+ return nvPr;
61870
+ }
61871
+ }
61872
+ return void 0;
61873
+ }
61874
+ function retargetPlaceholder(rawXml, target) {
61875
+ const nvPr = findNonVisualProps(rawXml);
61876
+ if (!nvPr) {
61877
+ return;
61878
+ }
61879
+ const ph = nvPr["p:ph"] ?? {};
61880
+ nvPr["p:ph"] = ph;
61881
+ if (target.type) {
61882
+ ph["@_type"] = target.type;
61883
+ } else {
61884
+ delete ph["@_type"];
61885
+ }
61886
+ if (target.idx !== void 0) {
61887
+ ph["@_idx"] = target.idx;
61888
+ } else {
61889
+ delete ph["@_idx"];
61890
+ }
61891
+ }
61892
+ function setRawXmlTransform(rawXml, xEmu, yEmu, cxEmu, cyEmu) {
61893
+ const spPr = rawXml["p:spPr"];
61894
+ if (!spPr) {
61895
+ return;
61896
+ }
61897
+ const xfrm = spPr["a:xfrm"] ?? {};
61898
+ spPr["a:xfrm"] = xfrm;
61899
+ const off = xfrm["a:off"] ?? {};
61900
+ xfrm["a:off"] = off;
61901
+ off["@_x"] = String(xEmu);
61902
+ off["@_y"] = String(yEmu);
61903
+ const ext = xfrm["a:ext"] ?? {};
61904
+ xfrm["a:ext"] = ext;
61905
+ ext["@_cx"] = String(cxEmu);
61906
+ ext["@_cy"] = String(cyEmu);
61907
+ }
61908
+ function createEmptyPlaceholderElement(target, xEmu, yEmu, cxEmu, cyEmu, uniqueId) {
61909
+ if (cxEmu <= 0 || cyEmu <= 0) {
61910
+ return null;
61911
+ }
61912
+ const phNode = {};
61913
+ if (target.type) {
61914
+ phNode["@_type"] = target.type;
61915
+ }
61916
+ if (target.idx !== void 0) {
61917
+ phNode["@_idx"] = target.idx;
61918
+ }
61919
+ const rawXml = {
61920
+ "p:nvSpPr": {
61921
+ "p:cNvPr": {
61922
+ "@_id": uniqueId,
61923
+ "@_name": `Placeholder ${target.type || "content"}`
61924
+ },
61925
+ "p:cNvSpPr": {
61926
+ "a:spLocks": { "@_noGrp": "1" }
61927
+ },
61928
+ "p:nvPr": {
61929
+ "p:ph": phNode
61930
+ }
61931
+ },
61932
+ "p:spPr": {
61933
+ "a:xfrm": {
61934
+ "a:off": { "@_x": String(xEmu), "@_y": String(yEmu) },
61935
+ "a:ext": { "@_cx": String(cxEmu), "@_cy": String(cyEmu) }
61936
+ }
61937
+ },
61938
+ "p:txBody": {
61939
+ "a:bodyPr": {},
61940
+ "a:lstStyle": {},
61941
+ "a:p": { "a:endParaRPr": { "@_lang": "en-US" } }
61942
+ }
61943
+ };
61944
+ return {
61945
+ type: "text",
61946
+ id: `ph-${target.type || "content"}-${target.idx ?? "0"}-${uniqueId}`,
61947
+ x: Math.round(xEmu / EMU_PER_PX),
61948
+ y: Math.round(yEmu / EMU_PER_PX),
61949
+ width: Math.round(cxEmu / EMU_PER_PX),
61950
+ height: Math.round(cyEmu / EMU_PER_PX),
61951
+ text: "",
61952
+ rawXml
61953
+ };
61954
+ }
61955
+ var init_placeholder_xml = __esm({
61956
+ "pptx/core/utils/placeholder-xml.ts"() {
61957
+ init_constants2();
61958
+ }
61959
+ });
61960
+
61961
+ // pptx/core/core/runtime/save-geometry-validation.ts
61962
+ function omitsInheritedFrame(element) {
61963
+ if (!["text", "shape", "picture", "media"].includes(element.type) || !element.rawXml)
61964
+ return false;
61965
+ if (!xmlHasChild(findNonVisualProps(element.rawXml), "p:ph")) return false;
61966
+ if (xmlHasChild(xmlChild(element.rawXml, "p:spPr"), "a:xfrm") || xmlHasChild(element.rawXml, "p:xfrm"))
61967
+ return false;
61968
+ const baseline = element.inheritedTransform;
61969
+ if (!baseline) return FRAME_FIELDS.every((key2) => element[key2] === void 0);
61970
+ return FRAME_FIELDS.every(
61971
+ (key2) => Number.isFinite(baseline[key2]) && (element[key2] === void 0 || element[key2] === baseline[key2])
61972
+ ) && ["rotation", "skewX", "skewY", "flipHorizontal", "flipVertical"].every(
61973
+ (key2) => (element[key2] ?? 0) === (baseline[key2] ?? 0)
61974
+ );
61975
+ }
61976
+ function validateElementGeometry(element, context, emuPerPx = 9525) {
61977
+ const inherited = omitsInheritedFrame(element);
61978
+ const record2 = element;
61979
+ const fields = [...inherited ? [] : FRAME_FIELDS, ...OPTIONAL_FIELDS];
61980
+ for (const field of fields) {
61981
+ const value = record2[field];
61982
+ if (OPTIONAL_FIELDS.includes(field) && value === void 0) continue;
61983
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isFinite(value * emuPerPx)) {
61984
+ throw new Error(
61985
+ `${context}: element '${element.id}' (${element.name ?? "unnamed"}, type=${element.type}) has invalid ${field}=${String(value)}; expected a finite number`
61986
+ );
61987
+ }
61988
+ }
61989
+ if (element.type === "group") {
61990
+ for (const child31 of element.children) validateElementGeometry(child31, context, emuPerPx);
61991
+ }
61992
+ }
61993
+ function validateSlideGeometry(slides) {
61994
+ for (const slide of slides) {
61995
+ for (const element of slide.elements) {
61996
+ validateElementGeometry(element, `Slide ${slide.slideNumber} (${slide.id})`);
61997
+ }
61998
+ }
61999
+ }
62000
+ var FRAME_FIELDS, OPTIONAL_FIELDS;
62001
+ var init_save_geometry_validation = __esm({
62002
+ "pptx/core/core/runtime/save-geometry-validation.ts"() {
62003
+ init_placeholder_xml();
62004
+ init_xml_access();
62005
+ FRAME_FIELDS = ["x", "y", "width", "height"];
62006
+ OPTIONAL_FIELDS = [
62007
+ "xEmu",
62008
+ "yEmu",
62009
+ "widthEmu",
62010
+ "heightEmu",
62011
+ "rotation",
62012
+ "skewX",
62013
+ "skewY",
62014
+ "chOffXEmu",
62015
+ "chOffYEmu",
62016
+ "chExtWidthEmu",
62017
+ "chExtHeightEmu"
62018
+ ];
62019
+ }
62020
+ });
62021
+
61675
62022
  // pptx/core/core/builders/PptxElementTransformUpdater.ts
61676
62023
  var PptxElementTransformUpdater;
61677
62024
  var init_PptxElementTransformUpdater = __esm({
@@ -61681,6 +62028,7 @@ var init_PptxElementTransformUpdater = __esm({
61681
62028
  init_xml_access();
61682
62029
  init_group_tight_rewrap();
61683
62030
  init_inherited_shape_transform();
62031
+ init_save_geometry_validation();
61684
62032
  PptxElementTransformUpdater = class {
61685
62033
  applyTransform(shape, element, emuPerPx, enclosingGroupChildSpace) {
61686
62034
  const transform7 = shape["p:spPr"]?.["a:xfrm"] || shape["p:xfrm"] || // A group's child geometry uses a different frame from the load-time baseline.
@@ -61688,6 +62036,7 @@ var init_PptxElementTransformUpdater = __esm({
61688
62036
  if (!transform7) {
61689
62037
  return;
61690
62038
  }
62039
+ validateElementGeometry(element, "Transform writer", emuPerPx);
61691
62040
  if (!transform7["a:off"]) {
61692
62041
  transform7["a:off"] = {};
61693
62042
  }
@@ -64722,7 +65071,7 @@ function parseBorderSide(side) {
64722
65071
  }
64723
65072
  const widthEmu = parseInt(String(ln["@_w"] || "0"), 10);
64724
65073
  if (widthEmu > 0) {
64725
- border.width = Math.max(1, Math.round(widthEmu / EMU_PER_PIXEL2));
65074
+ border.width = Math.max(1, Math.round(widthEmu / EMU_PER_PIXEL3));
64726
65075
  has2 = true;
64727
65076
  }
64728
65077
  const prstDash = ln["a:prstDash"];
@@ -64779,12 +65128,12 @@ function parseTableStyleSectionCell3D(tcStyle) {
64779
65128
  if (bevel2) {
64780
65129
  const bevelWidth = parseInt(String(bevel2["@_w"] || "0"), 10);
64781
65130
  if (bevelWidth > 0) {
64782
- cell3D.bevelWidth = Math.round(bevelWidth / EMU_PER_PIXEL2);
65131
+ cell3D.bevelWidth = Math.round(bevelWidth / EMU_PER_PIXEL3);
64783
65132
  hasStyle = true;
64784
65133
  }
64785
65134
  const bevelHeight = parseInt(String(bevel2["@_h"] || "0"), 10);
64786
65135
  if (bevelHeight > 0) {
64787
- cell3D.bevelHeight = Math.round(bevelHeight / EMU_PER_PIXEL2);
65136
+ cell3D.bevelHeight = Math.round(bevelHeight / EMU_PER_PIXEL3);
64788
65137
  hasStyle = true;
64789
65138
  }
64790
65139
  const bevelPreset = String(bevel2["@_prst"] || "").trim();
@@ -64808,11 +65157,11 @@ function parseTableStyleSectionCell3D(tcStyle) {
64808
65157
  }
64809
65158
  return hasStyle ? cell3D : void 0;
64810
65159
  }
64811
- var EMU_PER_PIXEL2, BORDER_SIDES;
65160
+ var EMU_PER_PIXEL3, BORDER_SIDES;
64812
65161
  var init_table_style_border_parse = __esm({
64813
65162
  "pptx/core/core/runtime/table-style-border-parse.ts"() {
64814
65163
  init_color_primitives();
64815
- EMU_PER_PIXEL2 = 9525;
65164
+ EMU_PER_PIXEL3 = 9525;
64816
65165
  BORDER_SIDES = [
64817
65166
  "left",
64818
65167
  "right",
@@ -93865,6 +94214,80 @@ var init_factories = __esm({
93865
94214
  }
93866
94215
  });
93867
94216
 
94217
+ // pptx/core/utils/placeholder-remap.ts
94218
+ function placeholderContentRole(type) {
94219
+ const declared = (type ?? "").trim().toLowerCase() || "body";
94220
+ if (TITLE_ROLE.has(declared)) {
94221
+ return "title";
94222
+ }
94223
+ if (CONTENT_ROLE.has(declared)) {
94224
+ return "content";
94225
+ }
94226
+ return declared;
94227
+ }
94228
+ function preferredPlaceholderTypes(element) {
94229
+ switch (element.type) {
94230
+ case "image":
94231
+ case "picture":
94232
+ return ["pic", "obj", "body"];
94233
+ case "chart":
94234
+ return ["chart", "obj", "body"];
94235
+ case "table":
94236
+ return ["tbl", "obj", "body"];
94237
+ case "media":
94238
+ case "model3d":
94239
+ return ["media", "pic", "obj", "body"];
94240
+ case "smartArt":
94241
+ return ["dgm", "obj", "body"];
94242
+ case "text":
94243
+ return ["body", "subtitle", "obj"];
94244
+ default:
94245
+ return ["obj", "body"];
94246
+ }
94247
+ }
94248
+ function scorePlaceholderMatch(element, source, target) {
94249
+ if (placeholderContentRole(source.type) !== placeholderContentRole(target.type)) {
94250
+ return -1;
94251
+ }
94252
+ const sourceType = normalizeType(source.type);
94253
+ const targetType = normalizeType(target.type);
94254
+ let score = 1;
94255
+ if (source.idx !== void 0 && source.idx === target.idx) {
94256
+ score += 100;
94257
+ }
94258
+ if (sourceType === targetType) {
94259
+ score += 50;
94260
+ }
94261
+ const preferred = preferredPlaceholderTypes(element).indexOf(targetType);
94262
+ if (preferred >= 0) {
94263
+ score += 30 - preferred * 5;
94264
+ }
94265
+ if (targetType === "obj") {
94266
+ score += 10;
94267
+ }
94268
+ return score;
94269
+ }
94270
+ function normalizeType(type) {
94271
+ return (type ?? "").trim().toLowerCase() || "body";
94272
+ }
94273
+ var TITLE_ROLE, CONTENT_ROLE;
94274
+ var init_placeholder_remap = __esm({
94275
+ "pptx/core/utils/placeholder-remap.ts"() {
94276
+ TITLE_ROLE = /* @__PURE__ */ new Set(["title", "ctrtitle"]);
94277
+ CONTENT_ROLE = /* @__PURE__ */ new Set([
94278
+ "body",
94279
+ "obj",
94280
+ "subtitle",
94281
+ "pic",
94282
+ "chart",
94283
+ "tbl",
94284
+ "media",
94285
+ "clipart",
94286
+ "dgm"
94287
+ ]);
94288
+ }
94289
+ });
94290
+
93868
94291
  // pptx/core/core/runtime/master-save-helpers.ts
93869
94292
  function applyHeaderFooterFlagsToNode(root, flags) {
93870
94293
  if (!flags || Object.keys(flags).length === 0) {
@@ -113444,178 +113867,6 @@ var init_chart_user_shapes_serializer = __esm({
113444
113867
  }
113445
113868
  });
113446
113869
 
113447
- // pptx/core/utils/placeholder-remap.ts
113448
- function placeholderContentRole(type) {
113449
- const declared = (type ?? "").trim().toLowerCase() || "body";
113450
- if (TITLE_ROLE.has(declared)) {
113451
- return "title";
113452
- }
113453
- if (CONTENT_ROLE.has(declared)) {
113454
- return "content";
113455
- }
113456
- return declared;
113457
- }
113458
- function preferredPlaceholderTypes(element) {
113459
- switch (element.type) {
113460
- case "image":
113461
- case "picture":
113462
- return ["pic", "obj", "body"];
113463
- case "chart":
113464
- return ["chart", "obj", "body"];
113465
- case "table":
113466
- return ["tbl", "obj", "body"];
113467
- case "media":
113468
- case "model3d":
113469
- return ["media", "pic", "obj", "body"];
113470
- case "smartArt":
113471
- return ["dgm", "obj", "body"];
113472
- case "text":
113473
- return ["body", "subtitle", "obj"];
113474
- default:
113475
- return ["obj", "body"];
113476
- }
113477
- }
113478
- function scorePlaceholderMatch(element, source, target) {
113479
- if (placeholderContentRole(source.type) !== placeholderContentRole(target.type)) {
113480
- return -1;
113481
- }
113482
- const sourceType = normalizeType(source.type);
113483
- const targetType = normalizeType(target.type);
113484
- let score = 1;
113485
- if (source.idx !== void 0 && source.idx === target.idx) {
113486
- score += 100;
113487
- }
113488
- if (sourceType === targetType) {
113489
- score += 50;
113490
- }
113491
- const preferred = preferredPlaceholderTypes(element).indexOf(targetType);
113492
- if (preferred >= 0) {
113493
- score += 30 - preferred * 5;
113494
- }
113495
- if (targetType === "obj") {
113496
- score += 10;
113497
- }
113498
- return score;
113499
- }
113500
- function normalizeType(type) {
113501
- return (type ?? "").trim().toLowerCase() || "body";
113502
- }
113503
- var TITLE_ROLE, CONTENT_ROLE;
113504
- var init_placeholder_remap = __esm({
113505
- "pptx/core/utils/placeholder-remap.ts"() {
113506
- TITLE_ROLE = /* @__PURE__ */ new Set(["title", "ctrtitle"]);
113507
- CONTENT_ROLE = /* @__PURE__ */ new Set([
113508
- "body",
113509
- "obj",
113510
- "subtitle",
113511
- "pic",
113512
- "chart",
113513
- "tbl",
113514
- "media",
113515
- "clipart",
113516
- "dgm"
113517
- ]);
113518
- }
113519
- });
113520
-
113521
- // pptx/core/utils/placeholder-xml.ts
113522
- function findNonVisualProps(rawXml) {
113523
- for (const container2 of ["p:nvSpPr", "p:nvPicPr", "p:nvGraphicFramePr"]) {
113524
- const parent = rawXml[container2];
113525
- const nvPr = parent?.["p:nvPr"];
113526
- if (nvPr) {
113527
- return nvPr;
113528
- }
113529
- }
113530
- return void 0;
113531
- }
113532
- function retargetPlaceholder(rawXml, target) {
113533
- const nvPr = findNonVisualProps(rawXml);
113534
- if (!nvPr) {
113535
- return;
113536
- }
113537
- const ph = nvPr["p:ph"] ?? {};
113538
- nvPr["p:ph"] = ph;
113539
- if (target.type) {
113540
- ph["@_type"] = target.type;
113541
- } else {
113542
- delete ph["@_type"];
113543
- }
113544
- if (target.idx !== void 0) {
113545
- ph["@_idx"] = target.idx;
113546
- } else {
113547
- delete ph["@_idx"];
113548
- }
113549
- }
113550
- function setRawXmlTransform(rawXml, xEmu, yEmu, cxEmu, cyEmu) {
113551
- const spPr = rawXml["p:spPr"];
113552
- if (!spPr) {
113553
- return;
113554
- }
113555
- const xfrm = spPr["a:xfrm"] ?? {};
113556
- spPr["a:xfrm"] = xfrm;
113557
- const off = xfrm["a:off"] ?? {};
113558
- xfrm["a:off"] = off;
113559
- off["@_x"] = String(xEmu);
113560
- off["@_y"] = String(yEmu);
113561
- const ext = xfrm["a:ext"] ?? {};
113562
- xfrm["a:ext"] = ext;
113563
- ext["@_cx"] = String(cxEmu);
113564
- ext["@_cy"] = String(cyEmu);
113565
- }
113566
- function createEmptyPlaceholderElement(target, xEmu, yEmu, cxEmu, cyEmu, uniqueId) {
113567
- if (cxEmu <= 0 || cyEmu <= 0) {
113568
- return null;
113569
- }
113570
- const phNode = {};
113571
- if (target.type) {
113572
- phNode["@_type"] = target.type;
113573
- }
113574
- if (target.idx !== void 0) {
113575
- phNode["@_idx"] = target.idx;
113576
- }
113577
- const rawXml = {
113578
- "p:nvSpPr": {
113579
- "p:cNvPr": {
113580
- "@_id": uniqueId,
113581
- "@_name": `Placeholder ${target.type || "content"}`
113582
- },
113583
- "p:cNvSpPr": {
113584
- "a:spLocks": { "@_noGrp": "1" }
113585
- },
113586
- "p:nvPr": {
113587
- "p:ph": phNode
113588
- }
113589
- },
113590
- "p:spPr": {
113591
- "a:xfrm": {
113592
- "a:off": { "@_x": String(xEmu), "@_y": String(yEmu) },
113593
- "a:ext": { "@_cx": String(cxEmu), "@_cy": String(cyEmu) }
113594
- }
113595
- },
113596
- "p:txBody": {
113597
- "a:bodyPr": {},
113598
- "a:lstStyle": {},
113599
- "a:p": { "a:endParaRPr": { "@_lang": "en-US" } }
113600
- }
113601
- };
113602
- return {
113603
- type: "text",
113604
- id: `ph-${target.type || "content"}-${target.idx ?? "0"}-${uniqueId}`,
113605
- x: Math.round(xEmu / EMU_PER_PX),
113606
- y: Math.round(yEmu / EMU_PER_PX),
113607
- width: Math.round(cxEmu / EMU_PER_PX),
113608
- height: Math.round(cyEmu / EMU_PER_PX),
113609
- text: "",
113610
- rawXml
113611
- };
113612
- }
113613
- var init_placeholder_xml = __esm({
113614
- "pptx/core/utils/placeholder-xml.ts"() {
113615
- init_constants2();
113616
- }
113617
- });
113618
-
113619
113870
  // pptx/core/utils/text-fill-blip.ts
113620
113871
  function resolveTextFillBlip(blipFill, lookupTarget, resolveArchivePath, allowExternal) {
113621
113872
  const blip = blipFill["a:blip"];
@@ -133180,8 +133431,8 @@ function mergeBorderSideXml(border, existingSide) {
133180
133431
  const ln = ensureChild2(existing, "a:ln");
133181
133432
  if (border.width !== void 0) {
133182
133433
  const currentEmu = parseInt(String(ln["@_w"] || "0"), 10);
133183
- if (currentEmu <= 0 || Math.max(1, Math.round(currentEmu / EMU_PER_PIXEL3)) !== border.width) {
133184
- ln["@_w"] = String(Math.round(border.width * EMU_PER_PIXEL3));
133434
+ if (currentEmu <= 0 || Math.max(1, Math.round(currentEmu / EMU_PER_PIXEL4)) !== border.width) {
133435
+ ln["@_w"] = String(Math.round(border.width * EMU_PER_PIXEL4));
133185
133436
  }
133186
133437
  }
133187
133438
  if (border.dash) {
@@ -133237,10 +133488,10 @@ function writeTableStyleSectionCell3D(section, cell3D) {
133237
133488
  if (cell3D.bevelWidth !== void 0 || cell3D.bevelHeight !== void 0 || cell3D.bevelPreset !== void 0) {
133238
133489
  const bevel2 = {};
133239
133490
  if (cell3D.bevelWidth !== void 0) {
133240
- bevel2["@_w"] = String(Math.round(cell3D.bevelWidth * EMU_PER_PIXEL3));
133491
+ bevel2["@_w"] = String(Math.round(cell3D.bevelWidth * EMU_PER_PIXEL4));
133241
133492
  }
133242
133493
  if (cell3D.bevelHeight !== void 0) {
133243
- bevel2["@_h"] = String(Math.round(cell3D.bevelHeight * EMU_PER_PIXEL3));
133494
+ bevel2["@_h"] = String(Math.round(cell3D.bevelHeight * EMU_PER_PIXEL4));
133244
133495
  }
133245
133496
  if (cell3D.bevelPreset) {
133246
133497
  bevel2["@_prst"] = cell3D.bevelPreset;
@@ -133259,12 +133510,12 @@ function writeTableStyleSectionCell3D(section, cell3D) {
133259
133510
  }
133260
133511
  tcStyle["a:cell3D"] = node;
133261
133512
  }
133262
- var EMU_PER_PIXEL3, BORDER_SIDE_ORDER, LN_CHILD_ORDER, LN_FILL_KEYS;
133513
+ var EMU_PER_PIXEL4, BORDER_SIDE_ORDER, LN_CHILD_ORDER, LN_FILL_KEYS;
133263
133514
  var init_table_style_border_write = __esm({
133264
133515
  "pptx/core/core/runtime/table-style-border-write.ts"() {
133265
133516
  init_xml_reorder();
133266
133517
  init_table_style_xml_helpers();
133267
- EMU_PER_PIXEL3 = 9525;
133518
+ EMU_PER_PIXEL4 = 9525;
133268
133519
  BORDER_SIDE_ORDER = [
133269
133520
  "a:left",
133270
133521
  "a:right",
@@ -134202,6 +134453,7 @@ var init_PptxHandlerRuntimeSavePipeline = __esm({
134202
134453
  init_header_footer_parts();
134203
134454
  init_pptx_print_properties();
134204
134455
  init_PptxHandlerRuntimeSaveStructuralIds();
134456
+ init_save_geometry_validation();
134205
134457
  PptxHandlerRuntime54 = class _PptxHandlerRuntime extends PptxHandlerRuntime53 {
134206
134458
  /**
134207
134459
  * Resolve the effective conformance class for this save operation.
@@ -134216,6 +134468,19 @@ var init_PptxHandlerRuntimeSavePipeline = __esm({
134216
134468
  return this.isStrictOoxml ? "strict" : "transitional";
134217
134469
  }
134218
134470
  async save(slides, options) {
134471
+ validateSlideGeometry(slides);
134472
+ const templates = [
134473
+ ...options?.slideMasters ?? [],
134474
+ ...options?.slideLayouts ?? [],
134475
+ ...options?.slideMasters?.flatMap((master) => master.layouts ?? []) ?? [],
134476
+ ...options?.notesMaster ? [options.notesMaster] : [],
134477
+ ...options?.handoutMaster ? [options.handoutMaster] : []
134478
+ ];
134479
+ for (const template of templates) {
134480
+ for (const element of template.elements ?? []) {
134481
+ validateElementGeometry(element, `Template (${template.path})`);
134482
+ }
134483
+ }
134219
134484
  if (options?.outputFormat === "ppt") {
134220
134485
  return this.saveAsLegacyPpt(
134221
134486
  slides,
@@ -135183,8 +135448,7 @@ var init_PptxHandlerRuntimePlaceholderLookup = __esm({
135183
135448
  return this.scanPlaceholderBuckets(spTree, (info) => info?.type === type);
135184
135449
  }
135185
135450
  /** The layout and master counterparts of a placeholder, unmerged. */
135186
- findPlaceholderContexts(slidePath, expected) {
135187
- const layoutPath = this.resolveLayoutPathForSlide(slidePath);
135451
+ findPlaceholderContexts(slidePath, expected, layoutPath = this.resolveLayoutPathForSlide(slidePath)) {
135188
135452
  if (!layoutPath) {
135189
135453
  return {};
135190
135454
  }
@@ -135196,10 +135460,11 @@ var init_PptxHandlerRuntimePlaceholderLookup = __esm({
135196
135460
  const master = this.findPlaceholderInShapeTree(masterSpTree, expected) ?? this.findSingletonPlaceholderInShapeTree(masterSpTree, expected);
135197
135461
  return { layout, master };
135198
135462
  }
135199
- findPlaceholderContext(slidePath, expected) {
135463
+ findPlaceholderContext(slidePath, expected, layoutPath) {
135200
135464
  const { layout: layoutContext, master: masterContext } = this.findPlaceholderContexts(
135201
135465
  slidePath,
135202
- expected
135466
+ expected,
135467
+ layoutPath
135203
135468
  );
135204
135469
  if (!layoutContext) {
135205
135470
  return masterContext;
@@ -135225,8 +135490,8 @@ var init_PptxHandlerRuntimePlaceholderLookup = __esm({
135225
135490
  * a master `p:sp`), so the layout keeps winning exactly as it does when
135226
135491
  * both are shapes.
135227
135492
  */
135228
- findPlaceholderNode(slidePath, expected) {
135229
- const { layout, master } = this.findPlaceholderContexts(slidePath, expected);
135493
+ findPlaceholderNode(slidePath, expected, layoutPath) {
135494
+ const { layout, master } = this.findPlaceholderContexts(slidePath, expected, layoutPath);
135230
135495
  const firstNode2 = (context) => context?.shape ?? context?.picture ?? context?.graphicFrame;
135231
135496
  const layoutNode = firstNode2(layout);
135232
135497
  const masterNode = firstNode2(master);
@@ -135267,8 +135532,7 @@ var init_PptxHandlerRuntimePlaceholderLookup = __esm({
135267
135532
  * reference. Checks the layout cache first, then the master cache, and
135268
135533
  * merges them so that layout values take priority over master values.
135269
135534
  */
135270
- lookupPlaceholderDefaults(slidePath, phInfo) {
135271
- const layoutPath = this.resolveLayoutPathForSlide(slidePath);
135535
+ lookupPlaceholderDefaults(slidePath, phInfo, layoutPath = this.resolveLayoutPathForSlide(slidePath)) {
135272
135536
  if (!layoutPath) {
135273
135537
  return void 0;
135274
135538
  }
@@ -137447,14 +137711,14 @@ var init_PptxHandlerRuntimeShapeParsing = __esm({
137447
137711
  init_element_paragraph_geometry();
137448
137712
  init_PptxHandlerRuntimeShapeParagraphContentParsing();
137449
137713
  PptxHandlerRuntime67 = class _PptxHandlerRuntime extends PptxHandlerRuntime66 {
137450
- parseShape(shape, id, slidePath) {
137714
+ parseShape(shape, id, slidePath, layoutPath) {
137451
137715
  try {
137452
137716
  const spPr = shape["p:spPr"];
137453
137717
  const slideRelationshipMap = slidePath ? this.slideRelsMap.get(slidePath) : void 0;
137454
137718
  const placeholderInfo = this.extractPlaceholderInfo(
137455
137719
  shape?.["p:nvSpPr"]?.["p:nvPr"]
137456
137720
  );
137457
- const inheritedPlaceholder = slidePath && placeholderInfo ? this.findPlaceholderContext(slidePath, placeholderInfo) : void 0;
137721
+ const inheritedPlaceholder = (slidePath || layoutPath) && placeholderInfo ? this.findPlaceholderContext(slidePath ?? "", placeholderInfo, layoutPath) : void 0;
137458
137722
  const inheritedSpPr = inheritedPlaceholder?.shape?.["p:spPr"] || inheritedPlaceholder?.picture?.["p:spPr"];
137459
137723
  const effectiveSpPr = spPr ? {
137460
137724
  ...spPr,
@@ -137580,7 +137844,7 @@ var init_PptxHandlerRuntimeShapeParsing = __esm({
137580
137844
  );
137581
137845
  const linkedTxbxId = bodyPropResult.linkedTxbxId;
137582
137846
  const linkedTxbxSeq = bodyPropResult.linkedTxbxSeq;
137583
- const phDefaults = slidePath && placeholderInfo ? this.lookupPlaceholderDefaults(slidePath, placeholderInfo) : void 0;
137847
+ const phDefaults = (slidePath || layoutPath) && placeholderInfo ? this.lookupPlaceholderDefaults(slidePath ?? "", placeholderInfo, layoutPath) : void 0;
137584
137848
  if (phDefaults) {
137585
137849
  this.applyPlaceholderBodyDefaults(textStyle, phDefaults);
137586
137850
  }
@@ -146943,14 +147207,199 @@ var init_PptxHandlerRuntimeBackgroundStyles = __esm({
146943
147207
  };
146944
147208
  }
146945
147209
  });
147210
+
147211
+ // pptx/core/core/runtime/sdk-placeholder.ts
147212
+ function selectTextPlaceholder(input, type, options, slots) {
147213
+ if (!TEXT_PLACEHOLDER_TYPES.has(type.toLowerCase())) {
147214
+ throw new Error(`Unsupported text placeholder type: ${type}`);
147215
+ }
147216
+ if (options.idx !== void 0 && (!Number.isInteger(options.idx) || options.idx < 0 || options.idx > 4294967295)) {
147217
+ throw new Error("Placeholder idx must be an unsigned 32-bit integer");
147218
+ }
147219
+ const source = {
147220
+ type: type.toLowerCase(),
147221
+ ...options.idx !== void 0 ? { idx: String(options.idx) } : {}
147222
+ };
147223
+ let best;
147224
+ let bestScore = 0;
147225
+ for (const slot of slots) {
147226
+ if (!TEXT_PLACEHOLDER_TYPES.has(slot.phInfo.type ?? "obj")) continue;
147227
+ if (source.idx !== void 0 && source.idx !== (slot.phInfo.idx ?? "0")) continue;
147228
+ const score = scorePlaceholderMatch(input, source, slot.phInfo);
147229
+ if (score > bestScore) {
147230
+ best = slot;
147231
+ bestScore = score;
147232
+ }
147233
+ }
147234
+ return best ? { type: canonicalPlaceholderType(best.phInfo.type ?? "obj"), idx: best.phInfo.idx } : { type: canonicalPlaceholderType(source.type), idx: source.idx };
147235
+ }
147236
+ function withoutFallbackLanguage(properties) {
147237
+ const { "@_lang": language, ...rest } = properties;
147238
+ if (language !== "en-US") return properties;
147239
+ const keys = Object.keys(rest);
147240
+ return keys.length === 0 || keys.length === 1 && rest["@_dirty"] === "0" ? void 0 : rest;
147241
+ }
147242
+ function stripFallbackLanguage(node, key2) {
147243
+ const properties = node[key2];
147244
+ if (!properties || typeof properties !== "object") return node;
147245
+ const next = withoutFallbackLanguage(properties);
147246
+ if (next === properties) return node;
147247
+ const result = {};
147248
+ for (const [name, value] of Object.entries(node)) {
147249
+ if (name !== key2) result[name] = value;
147250
+ else if (next) result[name] = next;
147251
+ }
147252
+ return result;
147253
+ }
147254
+ function withoutFallbackLanguages(paragraphs) {
147255
+ return paragraphs.map((paragraph) => {
147256
+ const next = { ...stripFallbackLanguage(paragraph, "a:endParaRPr") };
147257
+ for (const child31 of ["a:r", "a:br", "a:fld"]) {
147258
+ const nodes = next[child31];
147259
+ if (nodes === void 0) continue;
147260
+ next[child31] = Array.isArray(nodes) ? nodes.map((node) => stripFallbackLanguage(node, "a:rPr")) : stripFallbackLanguage(nodes, "a:rPr");
147261
+ }
147262
+ return next;
147263
+ });
147264
+ }
147265
+ function placeholderShape2(identity, paragraphs) {
147266
+ paragraphs = withoutFallbackLanguages(paragraphs);
147267
+ return {
147268
+ "p:nvSpPr": {
147269
+ "p:cNvPr": { "@_id": "2", "@_name": `Placeholder ${identity.type}` },
147270
+ "p:cNvSpPr": { "a:spLocks": { "@_noGrp": "1" } },
147271
+ "p:nvPr": {
147272
+ "p:ph": {
147273
+ "@_type": identity.type,
147274
+ ...identity.idx !== void 0 ? { "@_idx": identity.idx } : {}
147275
+ }
147276
+ }
147277
+ },
147278
+ "p:spPr": {},
147279
+ "p:txBody": { "a:bodyPr": {}, "a:lstStyle": {}, "a:p": paragraphs }
147280
+ };
147281
+ }
147282
+ function applyPlaceholderFrame(shape, inherited, options, emuPerPx, materializeFrame = false) {
147283
+ for (const key2 of ["x", "y", "width", "height"]) {
147284
+ if (options[key2] !== void 0 && !Number.isFinite(options[key2])) {
147285
+ throw new Error(`Invalid placeholder frame for ${key2}: expected a finite number`);
147286
+ }
147287
+ }
147288
+ const off = xmlPath(inherited, "p:spPr", "a:xfrm", "a:off");
147289
+ const ext = xmlPath(inherited, "p:spPr", "a:xfrm", "a:ext");
147290
+ const frame2 = {
147291
+ x: options.x ?? (off?.["@_x"] !== void 0 ? Number(off["@_x"]) / emuPerPx : void 0),
147292
+ y: options.y ?? (off?.["@_y"] !== void 0 ? Number(off["@_y"]) / emuPerPx : void 0),
147293
+ width: options.width ?? (ext?.["@_cx"] !== void 0 ? Number(ext["@_cx"]) / emuPerPx : void 0),
147294
+ height: options.height ?? (ext?.["@_cy"] !== void 0 ? Number(ext["@_cy"]) / emuPerPx : void 0)
147295
+ };
147296
+ for (const [key2, value] of Object.entries(frame2)) {
147297
+ if (!Number.isFinite(value)) {
147298
+ throw new Error(
147299
+ `No matching placeholder frame for ${key2}; supply a complete explicit frame or choose a layout containing this slot`
147300
+ );
147301
+ }
147302
+ }
147303
+ if (materializeFrame || ["x", "y", "width", "height"].some((key2) => options[key2] !== void 0)) {
147304
+ setRawXmlTransform(
147305
+ shape,
147306
+ ...["x", "y", "width", "height"].map(
147307
+ (key2) => Math.round(frame2[key2] * emuPerPx)
147308
+ )
147309
+ );
147310
+ }
147311
+ }
147312
+ var TEXT_PLACEHOLDER_TYPES;
147313
+ var init_sdk_placeholder = __esm({
147314
+ "pptx/core/core/runtime/sdk-placeholder.ts"() {
147315
+ init_placeholder_remap();
147316
+ init_placeholder_xml();
147317
+ init_placeholder_validation();
147318
+ init_xml_access();
147319
+ TEXT_PLACEHOLDER_TYPES = /* @__PURE__ */ new Set([
147320
+ "title",
147321
+ "ctrtitle",
147322
+ "subtitle",
147323
+ "body",
147324
+ "obj",
147325
+ "dt",
147326
+ "ftr",
147327
+ "hdr",
147328
+ "sldnum"
147329
+ ]);
147330
+ }
147331
+ });
147332
+
147333
+ // pptx/core/core/runtime/PptxHandlerRuntimeSdkPlaceholders.ts
146946
147334
  var PptxHandlerRuntime103;
147335
+ var init_PptxHandlerRuntimeSdkPlaceholders = __esm({
147336
+ "pptx/core/core/runtime/PptxHandlerRuntimeSdkPlaceholders.ts"() {
147337
+ init_placeholder_remap();
147338
+ init_xml_access();
147339
+ init_PptxHandlerRuntimeBackgroundStyles();
147340
+ init_sdk_placeholder();
147341
+ PptxHandlerRuntime103 = class _PptxHandlerRuntime extends PptxHandlerRuntime102 {
147342
+ createPlaceholderElement(layoutPath, input, type, options) {
147343
+ if (input.type !== "text") throw new Error("Placeholder input must be text");
147344
+ const layout = this.layoutXmlMap.get(layoutPath);
147345
+ if (!layout) throw new Error(`Unknown layout: ${layoutPath}`);
147346
+ const identity = selectTextPlaceholder(
147347
+ input,
147348
+ type,
147349
+ options,
147350
+ this.extractLayoutPlaceholders(layout, layoutPath)
147351
+ );
147352
+ const shape = placeholderShape2(
147353
+ identity,
147354
+ this.createParagraphsFromTextContent(input.text, void 0, input.textSegments)
147355
+ );
147356
+ const inherited = this.findPlaceholderNode(
147357
+ "",
147358
+ { type: identity.type.toLowerCase(), idx: identity.idx },
147359
+ layoutPath
147360
+ );
147361
+ const fallback = this.sdkMasterFrame(layoutPath, identity.type, identity.idx, inherited);
147362
+ applyPlaceholderFrame(
147363
+ shape,
147364
+ fallback ?? inherited,
147365
+ options,
147366
+ _PptxHandlerRuntime.EMU_PER_PX,
147367
+ fallback !== void 0
147368
+ );
147369
+ const element = this.parseShape(shape, input.id, void 0, layoutPath);
147370
+ if (!element) throw new Error("Unable to resolve placeholder content");
147371
+ if ((element.type === "text" || element.type === "shape") && !element.textStyle && element.textSegments?.[0]?.style) {
147372
+ element.textStyle = { ...element.textSegments[0].style };
147373
+ }
147374
+ return element;
147375
+ }
147376
+ sdkMasterFrame(layoutPath, type, idx, inherited) {
147377
+ if (!inherited) return void 0;
147378
+ if (xmlPath(inherited, "p:spPr", "a:xfrm", "a:off") && xmlPath(inherited, "p:spPr", "a:xfrm", "a:ext"))
147379
+ return void 0;
147380
+ const masterPath = this.resolveMasterPathForLayout(layoutPath);
147381
+ const tree = masterPath ? xmlPath(this.masterXmlMap.get(masterPath), "p:sldMaster", "p:cSld", "p:spTree") : void 0;
147382
+ const role = placeholderContentRole(type.toLowerCase());
147383
+ const candidates = this.ensureArray(tree?.["p:sp"]).filter((shape) => {
147384
+ const info = this.extractPlaceholderInfo(xmlPath(shape, "p:nvSpPr", "p:nvPr"));
147385
+ return info && placeholderContentRole(info.type) === role;
147386
+ });
147387
+ const master = candidates.find(
147388
+ (shape) => this.extractPlaceholderInfo(xmlPath(shape, "p:nvSpPr", "p:nvPr"))?.idx === idx
147389
+ ) ?? candidates[0];
147390
+ return master ? this.mergeXmlObjects(master, inherited) : void 0;
147391
+ }
147392
+ };
147393
+ }
147394
+ });
147395
+ var PptxHandlerRuntime104;
146947
147396
  var init_PptxHandlerRuntimeImplementation = __esm({
146948
147397
  "pptx/core/core/runtime/PptxHandlerRuntimeImplementation.ts"() {
146949
147398
  init_PptxElementXmlBuilder();
146950
147399
  init_builders();
146951
147400
  init_factories();
146952
- init_PptxHandlerRuntimeBackgroundStyles();
146953
- PptxHandlerRuntime103 = class _PptxHandlerRuntime extends PptxHandlerRuntime102 {
147401
+ init_PptxHandlerRuntimeSdkPlaceholders();
147402
+ PptxHandlerRuntime104 = class _PptxHandlerRuntime extends PptxHandlerRuntime103 {
146954
147403
  constructor(dependencyFactory = new PptxRuntimeDependencyFactory()) {
146955
147404
  super();
146956
147405
  this.dependencyFactory = dependencyFactory;
@@ -147090,11 +147539,11 @@ var init_PptxHandlerRuntimeImplementation = __esm({
147090
147539
  });
147091
147540
 
147092
147541
  // pptx/core/core/PptxHandlerRuntime.ts
147093
- var PptxHandlerRuntime104;
147542
+ var PptxHandlerRuntime105;
147094
147543
  var init_PptxHandlerRuntime = __esm({
147095
147544
  "pptx/core/core/PptxHandlerRuntime.ts"() {
147096
147545
  init_PptxHandlerRuntimeImplementation();
147097
- PptxHandlerRuntime104 = class extends PptxHandlerRuntime103 {
147546
+ PptxHandlerRuntime105 = class extends PptxHandlerRuntime104 {
147098
147547
  };
147099
147548
  }
147100
147549
  });
@@ -147104,7 +147553,7 @@ var createDefaultPptxHandlerRuntime;
147104
147553
  var init_PptxHandlerRuntimeFactory = __esm({
147105
147554
  "pptx/core/core/PptxHandlerRuntimeFactory.ts"() {
147106
147555
  init_PptxHandlerRuntime();
147107
- createDefaultPptxHandlerRuntime = () => new PptxHandlerRuntime104();
147556
+ createDefaultPptxHandlerRuntime = () => new PptxHandlerRuntime105();
147108
147557
  }
147109
147558
  });
147110
147559
 
@@ -149741,7 +150190,7 @@ function slideMasterXml2(deck, ctx) {
149741
150190
  </p:txStyles>
149742
150191
  </p:sldMaster>`;
149743
150192
  }
149744
- function slideLayoutXml2() {
150193
+ function slideLayoutXml() {
149745
150194
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
149746
150195
  <p:sldLayout ${XMLNS2} type="blank" preserve="1">
149747
150196
  <p:cSld name="Blank">
@@ -150061,7 +150510,7 @@ async function buildPptxPackage(deck) {
150061
150510
  ${masterRels.join("\n")}
150062
150511
  </Relationships>`
150063
150512
  );
150064
- zip.file("ppt/slideLayouts/slideLayout1.xml", slideLayoutXml2());
150513
+ zip.file("ppt/slideLayouts/slideLayout1.xml", slideLayoutXml());
150065
150514
  zip.file(
150066
150515
  "ppt/slideLayouts/_rels/slideLayout1.xml.rels",
150067
150516
  `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -150278,6 +150727,13 @@ var init_PptxHandlerCore = __esm({
150278
150727
  getLayoutOptions() {
150279
150728
  return this.runtime.getLayoutOptions();
150280
150729
  }
150730
+ /** Resolve a text placeholder in this loaded deck, preserving layout inheritance. */
150731
+ createPlaceholderElement(layoutPath, input, type, options = {}) {
150732
+ if (!this.runtime.createPlaceholderElement) {
150733
+ throw new Error("This runtime does not support creating layout placeholders");
150734
+ }
150735
+ return this.runtime.createPlaceholderElement(layoutPath, input, type, options);
150736
+ }
150281
150737
  /**
150282
150738
  * Build the artwork thumbnails backing the New Slide / Layout galleries.
150283
150739
  *
@@ -152071,30 +152527,8 @@ function removeChartUserShape(element, index) {
152071
152527
  element.chartData.userShapes = shapes.filter((_, i2) => i2 !== index);
152072
152528
  }
152073
152529
 
152074
- // pptx/core/builders/sdk/layout-operations.ts
152075
- function findLayoutByName(data, name) {
152076
- const lowerName = name.toLowerCase();
152077
- const fromOptions = data.layoutOptions?.find((l) => l.name.toLowerCase() === lowerName);
152078
- if (fromOptions) {
152079
- return fromOptions;
152080
- }
152081
- if (data.slideMasters) {
152082
- for (const master of data.slideMasters) {
152083
- const layout = master.layouts?.find((l) => l.name?.toLowerCase() === lowerName);
152084
- if (layout) {
152085
- return { path: layout.path, name: layout.name ?? name };
152086
- }
152087
- }
152088
- }
152089
- return void 0;
152090
- }
152091
- function findLayoutByType(data, type) {
152092
- const fromOptions = data.layoutOptions?.find((l) => l.type === type);
152093
- if (fromOptions) {
152094
- return fromOptions;
152095
- }
152096
- return void 0;
152097
- }
152530
+ // pptx/core/builders/sdk/index.ts
152531
+ init_layout_operations();
152098
152532
 
152099
152533
  // pptx/core/builders/sdk/shape-operations.ts
152100
152534
  function replaceShapeGeometry(element, newShapeType, adjustments) {