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
@@ -4696,13 +4696,14 @@ var init_SlideBuilder = __esm({
4696
4696
  "pptx/core/builders/sdk/SlideBuilder.ts"() {
4697
4697
  init_ElementFactory();
4698
4698
  exports.SlideBuilder = class {
4699
- slide;
4700
4699
  /**
4701
4700
  * @param slideNumber - 1-based slide number.
4702
4701
  * @param layoutPath - Optional layout archive path.
4703
4702
  * @param layoutName - Optional layout display name.
4703
+ * @param handler - Loaded deck context for placeholder geometry and text styles.
4704
4704
  */
4705
- constructor(slideNumber, layoutPath, layoutName) {
4705
+ constructor(slideNumber, layoutPath, layoutName, handler) {
4706
+ this.handler = handler;
4706
4707
  this.slide = {
4707
4708
  id: `slide${slideNumber}`,
4708
4709
  rId: `rId${slideNumber + 1}`,
@@ -4712,11 +4713,52 @@ var init_SlideBuilder = __esm({
4712
4713
  layoutName: layoutName ?? "Title Slide"
4713
4714
  };
4714
4715
  }
4716
+ handler;
4717
+ slide;
4715
4718
  /** Add a text box to the slide. */
4716
4719
  addText(text2, options) {
4717
4720
  this.slide.elements.push(createTextElement(text2, options));
4718
4721
  return this;
4719
4722
  }
4723
+ /**
4724
+ * Fill a layout placeholder, inheriting its frame and text styles.
4725
+ *
4726
+ * Unlike addText, this writes a real p:ph binding, not a free text box.
4727
+ * Use idx to select repeated slots (for example, Two Content's 1 and 2).
4728
+ * Explicit frame fields override the layout; all other fields inherit.
4729
+ * A standalone builder requires the fourth constructor argument (a loaded
4730
+ * handler), even with an explicit frame, so text styles resolve consistently.
4731
+ * Missing slots without a complete frame throw instead of creating a text box.
4732
+ * Master frames requiring compatible-role fallback are materialized locally
4733
+ * for new content only, keeping existing-deck loading unchanged.
4734
+ *
4735
+ * @example
4736
+ * ```ts
4737
+ * createSlide('Title Slide')
4738
+ * .addPlaceholder('ctrTitle', 'Quarterly review')
4739
+ * .addPlaceholder('subTitle', 'October 2026');
4740
+ * createSlide('Two Content').addPlaceholder('body', 'Right column', { idx: 2 });
4741
+ * ```
4742
+ */
4743
+ addPlaceholder(type, text2, options = {}) {
4744
+ const input = createTextElement(text2);
4745
+ const context = `Slide ${this.slide.slideNumber} (${this.slide.id}), placeholder ${type} idx=${options.idx ?? "auto"}, layout ${this.slide.layoutName} (${this.slide.layoutPath})`;
4746
+ try {
4747
+ if (!this.handler) {
4748
+ throw new Error(
4749
+ "addPlaceholder requires a loaded handler as the fourth SlideBuilder constructor argument"
4750
+ );
4751
+ }
4752
+ this.slide.elements.push(
4753
+ this.handler.createPlaceholderElement(this.slide.layoutPath, input, type, options)
4754
+ );
4755
+ } catch (error) {
4756
+ throw new Error(`${context}: ${error instanceof Error ? error.message : String(error)}`, {
4757
+ cause: error
4758
+ });
4759
+ }
4760
+ return this;
4761
+ }
4720
4762
  /** Add a shape to the slide. */
4721
4763
  addShape(shapeType, options) {
4722
4764
  this.slide.elements.push(createShapeElement(shapeType, options));
@@ -4956,6 +4998,466 @@ var init_SlideBuilder = __esm({
4956
4998
  };
4957
4999
  }
4958
5000
  });
5001
+ function isSafePartName(name) {
5002
+ if (name.includes("\0") || name.includes("\\")) return false;
5003
+ if (/^[A-Za-z]:/u.test(name)) return false;
5004
+ const body = name.startsWith("/") ? name.slice(1) : name;
5005
+ if (body.startsWith("/")) return false;
5006
+ return !body.split("/").some((segment) => segment === "..");
5007
+ }
5008
+ function declaredEntrySize(entry2) {
5009
+ const data = entry2._data;
5010
+ const size = Number(data?.uncompressedSize ?? 0);
5011
+ return Number.isFinite(size) && size > 0 ? size : 0;
5012
+ }
5013
+ function resolveLimits(limits) {
5014
+ const create = limits.createError;
5015
+ return {
5016
+ maxEntries: limits.maxEntries ?? DEFAULT_ZIP_LIMITS.maxEntries,
5017
+ maxEntryBytes: limits.maxEntryBytes ?? DEFAULT_ZIP_LIMITS.maxEntryBytes,
5018
+ maxTotalBytes: limits.maxTotalBytes ?? DEFAULT_ZIP_LIMITS.maxTotalBytes,
5019
+ label: limits.label ?? "ZIP",
5020
+ fail: (message, limit) => create ? create(message, { limit }) : new ZipLimitError(message, { limit })
5021
+ };
5022
+ }
5023
+ function inflateEntryGuarded(entry2, alreadyRead, limits) {
5024
+ const r = resolveLimits(limits);
5025
+ const declared = declaredEntrySize(entry2);
5026
+ return new Promise((resolvePromise, reject) => {
5027
+ const chunks = [];
5028
+ let size = 0;
5029
+ let done = false;
5030
+ const stream = entry2.internalStream("uint8array");
5031
+ const abort = (error) => {
5032
+ if (done) return;
5033
+ done = true;
5034
+ stream.pause();
5035
+ chunks.length = 0;
5036
+ reject(error);
5037
+ };
5038
+ stream.on("data", (chunk2) => {
5039
+ if (done) return;
5040
+ size += chunk2.byteLength;
5041
+ if (size > declared || size > r.maxEntryBytes)
5042
+ return abort(
5043
+ r.fail(`${r.label} part ${entry2.name} inflates past its declared size`, r.maxEntryBytes)
5044
+ );
5045
+ if (alreadyRead + size > r.maxTotalBytes)
5046
+ return abort(
5047
+ r.fail(
5048
+ `${r.label} package exceeds the ${mib(r.maxTotalBytes)} MiB uncompressed content limit`,
5049
+ r.maxTotalBytes
5050
+ )
5051
+ );
5052
+ chunks.push(chunk2);
5053
+ });
5054
+ stream.on("error", (error) => abort(error));
5055
+ stream.on("end", () => {
5056
+ if (done) return;
5057
+ done = true;
5058
+ if (chunks.length === 1 && chunks[0]) return resolvePromise(chunks[0]);
5059
+ const out = new Uint8Array(size);
5060
+ let offset = 0;
5061
+ for (const chunk2 of chunks) {
5062
+ out.set(chunk2, offset);
5063
+ offset += chunk2.byteLength;
5064
+ }
5065
+ resolvePromise(out);
5066
+ });
5067
+ stream.resume();
5068
+ });
5069
+ }
5070
+ function toBase64(bytes) {
5071
+ let binary = "";
5072
+ for (let i2 = 0; i2 < bytes.length; i2 += 32768)
5073
+ binary += String.fromCharCode(...bytes.subarray(i2, i2 + 32768));
5074
+ return btoa(binary);
5075
+ }
5076
+ function guardZip(zip, limits = {}) {
5077
+ const r = resolveLimits(limits);
5078
+ const entries = Object.values(zip.files);
5079
+ if (entries.length > r.maxEntries)
5080
+ throw r.fail(
5081
+ `${r.label} package exceeds the ${r.maxEntries.toLocaleString("en-US")} part limit`,
5082
+ r.maxEntries
5083
+ );
5084
+ let declared = 0;
5085
+ for (const entry2 of entries) {
5086
+ const original = entry2.unsafeOriginalName;
5087
+ if (!isSafePartName(entry2.name) || original !== void 0 && !isSafePartName(original))
5088
+ throw r.fail(`${r.label} package has an unsafe part name`, r.maxEntries);
5089
+ if (entry2.dir) continue;
5090
+ const size = declaredEntrySize(entry2);
5091
+ if (size > r.maxEntryBytes)
5092
+ throw r.fail(
5093
+ `${r.label} part ${entry2.name} exceeds the uncompressed part size limit`,
5094
+ r.maxEntryBytes
5095
+ );
5096
+ declared += size;
5097
+ }
5098
+ if (declared > r.maxTotalBytes)
5099
+ throw r.fail(
5100
+ `${r.label} package exceeds the ${mib(r.maxTotalBytes)} MiB uncompressed content limit`,
5101
+ r.maxTotalBytes
5102
+ );
5103
+ const produced = /* @__PURE__ */ new Map();
5104
+ let total = 0;
5105
+ for (const entry2 of entries) {
5106
+ if (entry2.dir) continue;
5107
+ const inflateOriginal = entry2.async.bind(entry2);
5108
+ entry2.async = async (type, onUpdate) => {
5109
+ const previous = produced.get(entry2.name) ?? 0;
5110
+ const bytes = await inflateEntryGuarded(entry2, total - previous, limits);
5111
+ if (bytes.byteLength > previous) {
5112
+ total += bytes.byteLength - previous;
5113
+ produced.set(entry2.name, bytes.byteLength);
5114
+ }
5115
+ switch (type) {
5116
+ case "uint8array":
5117
+ return bytes;
5118
+ case "string":
5119
+ case "text":
5120
+ return new TextDecoder("utf-8", { ignoreBOM: true }).decode(bytes);
5121
+ case "arraybuffer":
5122
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
5123
+ case "base64":
5124
+ return toBase64(bytes);
5125
+ default:
5126
+ return inflateOriginal(type, onUpdate);
5127
+ }
5128
+ };
5129
+ }
5130
+ return zip;
5131
+ }
5132
+ async function openZip(input, limits = {}) {
5133
+ const r = resolveLimits(limits);
5134
+ const maxInput = limits.maxInputBytes ?? DEFAULT_ZIP_LIMITS.maxInputBytes;
5135
+ const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
5136
+ if (bytes.byteLength > maxInput)
5137
+ throw r.fail(
5138
+ `${r.label} package exceeds the ${mib(maxInput)} MiB compressed input limit`,
5139
+ maxInput
5140
+ );
5141
+ return guardZip(await JSZip__default.default.loadAsync(bytes), limits);
5142
+ }
5143
+ var DEFAULT_ZIP_LIMITS, ZipLimitError, mib;
5144
+ var init_zip_limits = __esm({
5145
+ "opc/zip-limits.ts"() {
5146
+ DEFAULT_ZIP_LIMITS = {
5147
+ maxInputBytes: 100 * 1024 * 1024,
5148
+ maxEntries: 1e4,
5149
+ maxEntryBytes: 100 * 1024 * 1024,
5150
+ maxTotalBytes: 100 * 1024 * 1024
5151
+ };
5152
+ ZipLimitError = class extends Error {
5153
+ code = "ZIP_BOMB";
5154
+ limit;
5155
+ constructor(message, details) {
5156
+ super(message);
5157
+ this.name = "ZipLimitError";
5158
+ this.limit = details.limit;
5159
+ }
5160
+ };
5161
+ mib = (bytes) => Math.round(bytes / 1048576);
5162
+ }
5163
+ });
5164
+
5165
+ // pptx/core/core/types.ts
5166
+ exports.DEFAULT_MAX_UNCOMPRESSED_BYTES = void 0; exports.MAX_ZIP_ENTRY_COUNT = void 0; exports.ZipBombError = void 0;
5167
+ var init_types2 = __esm({
5168
+ "pptx/core/core/types.ts"() {
5169
+ exports.DEFAULT_MAX_UNCOMPRESSED_BYTES = 500 * 1024 * 1024;
5170
+ exports.MAX_ZIP_ENTRY_COUNT = 65536;
5171
+ exports.ZipBombError = class extends Error {
5172
+ code = "ZIP_BOMB";
5173
+ uncompressedBytes;
5174
+ limit;
5175
+ entryCount;
5176
+ constructor(message, details) {
5177
+ super(message);
5178
+ this.name = "ZipBombError";
5179
+ this.uncompressedBytes = details.uncompressedBytes;
5180
+ this.limit = details.limit;
5181
+ this.entryCount = details.entryCount;
5182
+ }
5183
+ };
5184
+ }
5185
+ });
5186
+
5187
+ // pptx/core/utils/zip-open.ts
5188
+ function openPptxZip(bytes) {
5189
+ return openZip(bytes, {
5190
+ label: "PPTX",
5191
+ maxInputBytes: exports.DEFAULT_MAX_UNCOMPRESSED_BYTES,
5192
+ maxEntries: exports.MAX_ZIP_ENTRY_COUNT,
5193
+ maxEntryBytes: exports.DEFAULT_MAX_UNCOMPRESSED_BYTES,
5194
+ maxTotalBytes: exports.DEFAULT_MAX_UNCOMPRESSED_BYTES,
5195
+ createError
5196
+ });
5197
+ }
5198
+ function openNestedZip(bytes) {
5199
+ return openZip(bytes, { label: "Embedded", createError });
5200
+ }
5201
+ var createError;
5202
+ var init_zip_open = __esm({
5203
+ "pptx/core/utils/zip-open.ts"() {
5204
+ init_zip_limits();
5205
+ init_types2();
5206
+ createError = (message, details) => new exports.ZipBombError(message, details);
5207
+ }
5208
+ });
5209
+
5210
+ // pptx/core/builders/sdk/layout-operations.ts
5211
+ function pxToEmu(px3) {
5212
+ return Math.round(px3 * EMU_PER_PIXEL2);
5213
+ }
5214
+ function placeholderSpXml(ph, shapeId) {
5215
+ const name = ph.name ?? `${ph.type.charAt(0).toUpperCase() + ph.type.slice(1)} Placeholder ${shapeId - 1}`;
5216
+ const x = pxToEmu(ph.x);
5217
+ const y = pxToEmu(ph.y);
5218
+ const cx = pxToEmu(ph.width);
5219
+ const cy = pxToEmu(ph.height);
5220
+ const idxAttr = ph.idx !== void 0 ? ` idx="${Math.max(0, Math.round(ph.idx))}"` : "";
5221
+ return ` <p:sp>
5222
+ <p:nvSpPr>
5223
+ <p:cNvPr id="${shapeId}" name="${escAttr(name)}"/>
5224
+ <p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr>
5225
+ <p:nvPr><p:ph type="${escAttr(ph.type)}"${idxAttr}/></p:nvPr>
5226
+ </p:nvSpPr>
5227
+ <p:spPr>
5228
+ <a:xfrm><a:off x="${x}" y="${y}"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>
5229
+ </p:spPr>
5230
+ <p:txBody>
5231
+ <a:bodyPr/>
5232
+ <a:lstStyle/>
5233
+ <a:p><a:endParaRPr lang="en-US"/></a:p>
5234
+ </p:txBody>
5235
+ </p:sp>`;
5236
+ }
5237
+ function normalizeSrgbHex(color2) {
5238
+ if (!color2) {
5239
+ return void 0;
5240
+ }
5241
+ const raw = color2.trim().replace(/^#/, "").toUpperCase();
5242
+ if (/^[0-9A-F]{6}$/.test(raw)) {
5243
+ return raw;
5244
+ }
5245
+ if (/^[0-9A-F]{3}$/.test(raw)) {
5246
+ return raw.replace(/./g, (ch) => ch + ch);
5247
+ }
5248
+ return void 0;
5249
+ }
5250
+ function generateLayoutXml(definition) {
5251
+ const layoutType = definition.type ?? "obj";
5252
+ const placeholders = definition.placeholders ?? [];
5253
+ const phShapes = placeholders.map((ph, i2) => placeholderSpXml(ph, i2 + 2)).join("\n");
5254
+ let bgXml = "";
5255
+ const hex3 = normalizeSrgbHex(definition.backgroundColor);
5256
+ if (hex3) {
5257
+ bgXml = ` <p:bg><p:bgPr><a:solidFill><a:srgbClr val="${hex3}"/></a:solidFill><a:effectLst/></p:bgPr></p:bg>
5258
+ `;
5259
+ }
5260
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
5261
+ <p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
5262
+ xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
5263
+ xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
5264
+ type="${escAttr(layoutType)}" preserve="1">
5265
+ <p:cSld name="${escAttr(definition.name)}">
5266
+ ${bgXml} <p:spTree>
5267
+ <p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>
5268
+ <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>
5269
+ ${phShapes}
5270
+ </p:spTree>
5271
+ </p:cSld>
5272
+ <p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr>
5273
+ </p:sldLayout>`;
5274
+ }
5275
+ function layoutRelsXml(masterIndex = 1) {
5276
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
5277
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
5278
+ <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster${masterIndex}.xml"/>
5279
+ </Relationships>`;
5280
+ }
5281
+ function countExistingLayouts(zip) {
5282
+ let count = 0;
5283
+ zip.forEach((relativePath) => {
5284
+ if (/^ppt\/slideLayouts\/slideLayout\d+\.xml$/.test(relativePath)) {
5285
+ count++;
5286
+ }
5287
+ });
5288
+ return count;
5289
+ }
5290
+ async function addLayoutToSlideMaster(zip, layoutIndex2, masterIndex = 1) {
5291
+ const masterRelsPath = `ppt/slideMasters/_rels/slideMaster${masterIndex}.xml.rels`;
5292
+ const masterRelsContent = await zip.file(masterRelsPath)?.async("string");
5293
+ if (!masterRelsContent) {
5294
+ throw new Error(`Slide master rels not found at ${masterRelsPath}`);
5295
+ }
5296
+ const rIdMatches = [...masterRelsContent.matchAll(/rId(\d+)/g)];
5297
+ const maxRId = rIdMatches.reduce((max, m) => Math.max(max, parseInt(m[1], 10)), 0);
5298
+ const newRId = `rId${maxRId + 1}`;
5299
+ const newRel = ` <Relationship Id="${newRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout${layoutIndex2}.xml"/>`;
5300
+ const updatedRels = masterRelsContent.replace("</Relationships>", `${newRel}
5301
+ </Relationships>`);
5302
+ zip.file(masterRelsPath, updatedRels);
5303
+ const masterPath = `ppt/slideMasters/slideMaster${masterIndex}.xml`;
5304
+ const masterContent = await zip.file(masterPath)?.async("string");
5305
+ if (!masterContent) {
5306
+ throw new Error(`Slide master not found at ${masterPath}`);
5307
+ }
5308
+ const idMatches = [...masterContent.matchAll(/sldLayoutId\s+id="(\d+)"/g)];
5309
+ const maxLayoutId = idMatches.reduce((max, m) => Math.max(max, parseInt(m[1], 10)), 2147483648);
5310
+ const newLayoutId = maxLayoutId + 1;
5311
+ const newLayoutIdEntry = ` <p:sldLayoutId id="${newLayoutId}" r:id="${newRId}"/>`;
5312
+ const updatedMaster = masterContent.replace(
5313
+ "</p:sldLayoutIdLst>",
5314
+ `${newLayoutIdEntry}
5315
+ </p:sldLayoutIdLst>`
5316
+ );
5317
+ zip.file(masterPath, updatedMaster);
5318
+ }
5319
+ async function addLayoutContentType(zip, layoutIndex2) {
5320
+ const ctPath = "[Content_Types].xml";
5321
+ const ctContent = await zip.file(ctPath)?.async("string");
5322
+ if (!ctContent) {
5323
+ throw new Error("Content types file not found");
5324
+ }
5325
+ const override = ` <Override PartName="/ppt/slideLayouts/slideLayout${layoutIndex2}.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/>`;
5326
+ const updatedCt = ctContent.replace("</Types>", `${override}
5327
+ </Types>`);
5328
+ zip.file(ctPath, updatedCt);
5329
+ }
5330
+ async function createLayout(handler, data, definition, masterIndex = 1) {
5331
+ const bytes = await handler.save(data.slides);
5332
+ const zip = await openPptxZip(bytes);
5333
+ const existingCount = countExistingLayouts(zip);
5334
+ const newIndex = existingCount + 1;
5335
+ const layoutPath = `ppt/slideLayouts/slideLayout${newIndex}.xml`;
5336
+ zip.file(layoutPath, generateLayoutXml(definition));
5337
+ zip.file(`ppt/slideLayouts/_rels/slideLayout${newIndex}.xml.rels`, layoutRelsXml(masterIndex));
5338
+ await addLayoutToSlideMaster(zip, newIndex, masterIndex);
5339
+ await addLayoutContentType(zip, newIndex);
5340
+ const updatedBuffer = await zip.generateAsync({ type: "arraybuffer" });
5341
+ const newHandler = new exports.PptxHandler();
5342
+ const newData = await newHandler.load(updatedBuffer);
5343
+ return {
5344
+ layoutPath,
5345
+ layoutName: definition.name,
5346
+ handler: newHandler,
5347
+ data: newData
5348
+ };
5349
+ }
5350
+ async function createLayouts(handler, data, definitions, masterIndex = 1) {
5351
+ if (definitions.length === 0) {
5352
+ return { layoutPaths: [], handler, data };
5353
+ }
5354
+ const bytes = await handler.save(data.slides);
5355
+ const zip = await openPptxZip(bytes);
5356
+ const existingCount = countExistingLayouts(zip);
5357
+ const layoutPaths = [];
5358
+ for (let i2 = 0; i2 < definitions.length; i2++) {
5359
+ const def = definitions[i2];
5360
+ const newIndex = existingCount + i2 + 1;
5361
+ const layoutPath = `ppt/slideLayouts/slideLayout${newIndex}.xml`;
5362
+ zip.file(layoutPath, generateLayoutXml(def));
5363
+ zip.file(`ppt/slideLayouts/_rels/slideLayout${newIndex}.xml.rels`, layoutRelsXml(masterIndex));
5364
+ await addLayoutToSlideMaster(zip, newIndex, masterIndex);
5365
+ await addLayoutContentType(zip, newIndex);
5366
+ layoutPaths.push(layoutPath);
5367
+ }
5368
+ const updatedBuffer = await zip.generateAsync({ type: "arraybuffer" });
5369
+ const newHandler = new exports.PptxHandler();
5370
+ const newData = await newHandler.load(updatedBuffer);
5371
+ return { layoutPaths, handler: newHandler, data: newData };
5372
+ }
5373
+ function findLayoutByName(data, name) {
5374
+ const lowerName = name.toLowerCase();
5375
+ const fromOptions = data.layoutOptions?.find((l) => l.name.toLowerCase() === lowerName);
5376
+ if (fromOptions) {
5377
+ return fromOptions;
5378
+ }
5379
+ if (data.slideMasters) {
5380
+ for (const master of data.slideMasters) {
5381
+ const layout = master.layouts?.find((l) => l.name?.toLowerCase() === lowerName);
5382
+ if (layout) {
5383
+ return { path: layout.path, name: layout.name ?? name };
5384
+ }
5385
+ }
5386
+ }
5387
+ return void 0;
5388
+ }
5389
+ function findLayoutByType(data, type) {
5390
+ const fromOptions = data.layoutOptions?.find((l) => l.type === type);
5391
+ if (fromOptions) {
5392
+ return fromOptions;
5393
+ }
5394
+ return void 0;
5395
+ }
5396
+ var EMU_PER_PIXEL2;
5397
+ var init_layout_operations = __esm({
5398
+ "pptx/core/builders/sdk/layout-operations.ts"() {
5399
+ init_zip_open();
5400
+ init_xml_utils();
5401
+ init_PptxHandler();
5402
+ EMU_PER_PIXEL2 = 9525;
5403
+ }
5404
+ });
5405
+
5406
+ // pptx/core/builders/sdk/standard-layout-placeholders.ts
5407
+ function standardLayoutPlaceholders(type, width, height) {
5408
+ if (type === "blank") return [];
5409
+ const box = (type2, idx, x, y, w, h2) => ({
5410
+ type: type2,
5411
+ idx,
5412
+ x: x * width,
5413
+ y: y * height,
5414
+ width: w * width,
5415
+ height: h2 * height
5416
+ });
5417
+ const title = box("title", 0, 0.05, 0.04, 0.9, 0.15);
5418
+ const content2 = box("obj", 1, 0.05, 0.23, 0.9, 0.64);
5419
+ let slots;
5420
+ switch (type) {
5421
+ case "title":
5422
+ slots = [
5423
+ box("ctrTitle", 0, 0.08, 0.24, 0.84, 0.22),
5424
+ box("subTitle", 1, 0.12, 0.49, 0.76, 0.2)
5425
+ ];
5426
+ break;
5427
+ case "secHead":
5428
+ slots = [box("title", 0, 0.05, 0.37, 0.9, 0.2), box("body", 1, 0.05, 0.6, 0.9, 0.23)];
5429
+ break;
5430
+ case "twoObj":
5431
+ case "twoTxTwoObj":
5432
+ slots = [title, box("obj", 1, 0.05, 0.27, 0.43, 0.6), box("obj", 2, 0.52, 0.27, 0.43, 0.6)];
5433
+ if (type === "twoTxTwoObj")
5434
+ slots.push(box("body", 3, 0.05, 0.2, 0.43, 0.07), box("body", 4, 0.52, 0.2, 0.43, 0.07));
5435
+ break;
5436
+ case "titleOnly":
5437
+ slots = [title];
5438
+ break;
5439
+ case "objTx":
5440
+ case "picTx":
5441
+ slots = [
5442
+ title,
5443
+ box(type === "picTx" ? "pic" : "obj", 1, 0.36, 0.23, 0.59, 0.64),
5444
+ box("body", 2, 0.05, 0.23, 0.27, 0.64)
5445
+ ];
5446
+ break;
5447
+ default:
5448
+ slots = [title, content2];
5449
+ }
5450
+ return [
5451
+ ...slots,
5452
+ box("dt", 10, 0.05, 0.92, 0.25, 0.04),
5453
+ box("ftr", 11, 0.33, 0.92, 0.34, 0.04),
5454
+ box("sldNum", 12, 0.75, 0.92, 0.2, 0.04)
5455
+ ];
5456
+ }
5457
+ var init_standard_layout_placeholders = __esm({
5458
+ "pptx/core/builders/sdk/standard-layout-placeholders.ts"() {
5459
+ }
5460
+ });
4959
5461
 
4960
5462
  // pptx/core/builders/sdk/PresentationBuilder.ts
4961
5463
  var PresentationBuilder_exports = {};
@@ -4964,7 +5466,7 @@ __export(PresentationBuilder_exports, {
4964
5466
  STANDARD_LAYOUTS: () => STANDARD_LAYOUTS,
4965
5467
  buildBlankPresentationArchive: () => buildBlankPresentationArchive
4966
5468
  });
4967
- function normalizeSrgbHex(color2) {
5469
+ function normalizeSrgbHex2(color2) {
4968
5470
  if (!color2) {
4969
5471
  return void 0;
4970
5472
  }
@@ -4980,7 +5482,7 @@ function normalizeSrgbHex(color2) {
4980
5482
  function resolveThemeColors(overrides28) {
4981
5483
  const resolved = {};
4982
5484
  for (const [key2, fallback] of Object.entries(DEFAULT_COLORS)) {
4983
- resolved[key2] = normalizeSrgbHex(overrides28?.[key2]) ?? normalizeSrgbHex(fallback) ?? "000000";
5485
+ resolved[key2] = normalizeSrgbHex2(overrides28?.[key2]) ?? normalizeSrgbHex2(fallback) ?? "000000";
4984
5486
  }
4985
5487
  return resolved;
4986
5488
  }
@@ -5120,21 +5622,6 @@ ${layoutRels}
5120
5622
  <Relationship Id="rId${layoutCount + 1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="../theme/theme1.xml"/>
5121
5623
  </Relationships>`;
5122
5624
  }
5123
- function slideLayoutXml(name, layoutType) {
5124
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
5125
- <p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
5126
- xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
5127
- xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
5128
- type="${escAttr(layoutType)}" preserve="1">
5129
- <p:cSld name="${escAttr(name)}">
5130
- <p:spTree>
5131
- <p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>
5132
- <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>
5133
- </p:spTree>
5134
- </p:cSld>
5135
- <p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr>
5136
- </p:sldLayout>`;
5137
- }
5138
5625
  function slideLayoutRelsXml() {
5139
5626
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
5140
5627
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
@@ -5283,7 +5770,14 @@ async function buildBlankPresentationArchive(options) {
5283
5770
  zip.file("ppt/slideMasters/_rels/slideMaster1.xml.rels", slideMasterRelsXml(layoutCount));
5284
5771
  for (let i2 = 0; i2 < layoutCount; i2++) {
5285
5772
  const layout = STANDARD_LAYOUTS[i2];
5286
- zip.file(`ppt/slideLayouts/slideLayout${i2 + 1}.xml`, slideLayoutXml(layout.name, layout.type));
5773
+ zip.file(
5774
+ `ppt/slideLayouts/slideLayout${i2 + 1}.xml`,
5775
+ generateLayoutXml({
5776
+ name: layout.name,
5777
+ type: layout.type,
5778
+ placeholders: standardLayoutPlaceholders(layout.type, width / 9525, height / 9525)
5779
+ })
5780
+ );
5287
5781
  zip.file(`ppt/slideLayouts/_rels/slideLayout${i2 + 1}.xml.rels`, slideLayoutRelsXml());
5288
5782
  }
5289
5783
  for (let i2 = 0; i2 < initialSlideCount; i2++) {
@@ -5304,6 +5798,8 @@ var init_PresentationBuilder = __esm({
5304
5798
  init_xml_utils();
5305
5799
  init_PptxHandler();
5306
5800
  init_SlideBuilder();
5801
+ init_layout_operations();
5802
+ init_standard_layout_placeholders();
5307
5803
  DEFAULT_WIDTH = 12192e3;
5308
5804
  DEFAULT_HEIGHT = 6858e3;
5309
5805
  DEFAULT_COLORS = {
@@ -5361,7 +5857,7 @@ var init_PresentationBuilder = __esm({
5361
5857
  const layoutIdx = STANDARD_LAYOUTS.findIndex((l) => l.name === layoutName) + 1 || 7;
5362
5858
  const layoutPath = `ppt/slideLayouts/slideLayout${layoutIdx}.xml`;
5363
5859
  const resolvedName = layoutName ?? STANDARD_LAYOUTS[layoutIdx - 1]?.name ?? "Blank";
5364
- return new exports.SlideBuilder(slideNum, layoutPath, resolvedName);
5860
+ return new exports.SlideBuilder(slideNum, layoutPath, resolvedName, handler);
5365
5861
  };
5366
5862
  return { handler, data, createSlide };
5367
5863
  }
@@ -22935,214 +23431,6 @@ var init_ole_embedded_replace = __esm({
22935
23431
  CONTENTS_STREAM2 = "CONTENTS";
22936
23432
  }
22937
23433
  });
22938
- function isSafePartName(name) {
22939
- if (name.includes("\0") || name.includes("\\")) return false;
22940
- if (/^[A-Za-z]:/u.test(name)) return false;
22941
- const body = name.startsWith("/") ? name.slice(1) : name;
22942
- if (body.startsWith("/")) return false;
22943
- return !body.split("/").some((segment) => segment === "..");
22944
- }
22945
- function declaredEntrySize(entry2) {
22946
- const data = entry2._data;
22947
- const size = Number(data?.uncompressedSize ?? 0);
22948
- return Number.isFinite(size) && size > 0 ? size : 0;
22949
- }
22950
- function resolveLimits(limits) {
22951
- const create = limits.createError;
22952
- return {
22953
- maxEntries: limits.maxEntries ?? DEFAULT_ZIP_LIMITS.maxEntries,
22954
- maxEntryBytes: limits.maxEntryBytes ?? DEFAULT_ZIP_LIMITS.maxEntryBytes,
22955
- maxTotalBytes: limits.maxTotalBytes ?? DEFAULT_ZIP_LIMITS.maxTotalBytes,
22956
- label: limits.label ?? "ZIP",
22957
- fail: (message, limit) => create ? create(message, { limit }) : new ZipLimitError(message, { limit })
22958
- };
22959
- }
22960
- function inflateEntryGuarded(entry2, alreadyRead, limits) {
22961
- const r = resolveLimits(limits);
22962
- const declared = declaredEntrySize(entry2);
22963
- return new Promise((resolvePromise, reject) => {
22964
- const chunks = [];
22965
- let size = 0;
22966
- let done = false;
22967
- const stream = entry2.internalStream("uint8array");
22968
- const abort = (error) => {
22969
- if (done) return;
22970
- done = true;
22971
- stream.pause();
22972
- chunks.length = 0;
22973
- reject(error);
22974
- };
22975
- stream.on("data", (chunk2) => {
22976
- if (done) return;
22977
- size += chunk2.byteLength;
22978
- if (size > declared || size > r.maxEntryBytes)
22979
- return abort(
22980
- r.fail(`${r.label} part ${entry2.name} inflates past its declared size`, r.maxEntryBytes)
22981
- );
22982
- if (alreadyRead + size > r.maxTotalBytes)
22983
- return abort(
22984
- r.fail(
22985
- `${r.label} package exceeds the ${mib(r.maxTotalBytes)} MiB uncompressed content limit`,
22986
- r.maxTotalBytes
22987
- )
22988
- );
22989
- chunks.push(chunk2);
22990
- });
22991
- stream.on("error", (error) => abort(error));
22992
- stream.on("end", () => {
22993
- if (done) return;
22994
- done = true;
22995
- if (chunks.length === 1 && chunks[0]) return resolvePromise(chunks[0]);
22996
- const out = new Uint8Array(size);
22997
- let offset = 0;
22998
- for (const chunk2 of chunks) {
22999
- out.set(chunk2, offset);
23000
- offset += chunk2.byteLength;
23001
- }
23002
- resolvePromise(out);
23003
- });
23004
- stream.resume();
23005
- });
23006
- }
23007
- function toBase64(bytes) {
23008
- let binary = "";
23009
- for (let i2 = 0; i2 < bytes.length; i2 += 32768)
23010
- binary += String.fromCharCode(...bytes.subarray(i2, i2 + 32768));
23011
- return btoa(binary);
23012
- }
23013
- function guardZip(zip, limits = {}) {
23014
- const r = resolveLimits(limits);
23015
- const entries = Object.values(zip.files);
23016
- if (entries.length > r.maxEntries)
23017
- throw r.fail(
23018
- `${r.label} package exceeds the ${r.maxEntries.toLocaleString("en-US")} part limit`,
23019
- r.maxEntries
23020
- );
23021
- let declared = 0;
23022
- for (const entry2 of entries) {
23023
- const original = entry2.unsafeOriginalName;
23024
- if (!isSafePartName(entry2.name) || original !== void 0 && !isSafePartName(original))
23025
- throw r.fail(`${r.label} package has an unsafe part name`, r.maxEntries);
23026
- if (entry2.dir) continue;
23027
- const size = declaredEntrySize(entry2);
23028
- if (size > r.maxEntryBytes)
23029
- throw r.fail(
23030
- `${r.label} part ${entry2.name} exceeds the uncompressed part size limit`,
23031
- r.maxEntryBytes
23032
- );
23033
- declared += size;
23034
- }
23035
- if (declared > r.maxTotalBytes)
23036
- throw r.fail(
23037
- `${r.label} package exceeds the ${mib(r.maxTotalBytes)} MiB uncompressed content limit`,
23038
- r.maxTotalBytes
23039
- );
23040
- const produced = /* @__PURE__ */ new Map();
23041
- let total = 0;
23042
- for (const entry2 of entries) {
23043
- if (entry2.dir) continue;
23044
- const inflateOriginal = entry2.async.bind(entry2);
23045
- entry2.async = async (type, onUpdate) => {
23046
- const previous = produced.get(entry2.name) ?? 0;
23047
- const bytes = await inflateEntryGuarded(entry2, total - previous, limits);
23048
- if (bytes.byteLength > previous) {
23049
- total += bytes.byteLength - previous;
23050
- produced.set(entry2.name, bytes.byteLength);
23051
- }
23052
- switch (type) {
23053
- case "uint8array":
23054
- return bytes;
23055
- case "string":
23056
- case "text":
23057
- return new TextDecoder("utf-8", { ignoreBOM: true }).decode(bytes);
23058
- case "arraybuffer":
23059
- return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
23060
- case "base64":
23061
- return toBase64(bytes);
23062
- default:
23063
- return inflateOriginal(type, onUpdate);
23064
- }
23065
- };
23066
- }
23067
- return zip;
23068
- }
23069
- async function openZip(input, limits = {}) {
23070
- const r = resolveLimits(limits);
23071
- const maxInput = limits.maxInputBytes ?? DEFAULT_ZIP_LIMITS.maxInputBytes;
23072
- const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
23073
- if (bytes.byteLength > maxInput)
23074
- throw r.fail(
23075
- `${r.label} package exceeds the ${mib(maxInput)} MiB compressed input limit`,
23076
- maxInput
23077
- );
23078
- return guardZip(await JSZip__default.default.loadAsync(bytes), limits);
23079
- }
23080
- var DEFAULT_ZIP_LIMITS, ZipLimitError, mib;
23081
- var init_zip_limits = __esm({
23082
- "opc/zip-limits.ts"() {
23083
- DEFAULT_ZIP_LIMITS = {
23084
- maxInputBytes: 100 * 1024 * 1024,
23085
- maxEntries: 1e4,
23086
- maxEntryBytes: 100 * 1024 * 1024,
23087
- maxTotalBytes: 100 * 1024 * 1024
23088
- };
23089
- ZipLimitError = class extends Error {
23090
- code = "ZIP_BOMB";
23091
- limit;
23092
- constructor(message, details) {
23093
- super(message);
23094
- this.name = "ZipLimitError";
23095
- this.limit = details.limit;
23096
- }
23097
- };
23098
- mib = (bytes) => Math.round(bytes / 1048576);
23099
- }
23100
- });
23101
-
23102
- // pptx/core/core/types.ts
23103
- exports.DEFAULT_MAX_UNCOMPRESSED_BYTES = void 0; exports.MAX_ZIP_ENTRY_COUNT = void 0; exports.ZipBombError = void 0;
23104
- var init_types2 = __esm({
23105
- "pptx/core/core/types.ts"() {
23106
- exports.DEFAULT_MAX_UNCOMPRESSED_BYTES = 500 * 1024 * 1024;
23107
- exports.MAX_ZIP_ENTRY_COUNT = 65536;
23108
- exports.ZipBombError = class extends Error {
23109
- code = "ZIP_BOMB";
23110
- uncompressedBytes;
23111
- limit;
23112
- entryCount;
23113
- constructor(message, details) {
23114
- super(message);
23115
- this.name = "ZipBombError";
23116
- this.uncompressedBytes = details.uncompressedBytes;
23117
- this.limit = details.limit;
23118
- this.entryCount = details.entryCount;
23119
- }
23120
- };
23121
- }
23122
- });
23123
-
23124
- // pptx/core/utils/zip-open.ts
23125
- function openPptxZip(bytes) {
23126
- return openZip(bytes, {
23127
- label: "PPTX",
23128
- maxInputBytes: exports.DEFAULT_MAX_UNCOMPRESSED_BYTES,
23129
- maxEntries: exports.MAX_ZIP_ENTRY_COUNT,
23130
- maxEntryBytes: exports.DEFAULT_MAX_UNCOMPRESSED_BYTES,
23131
- maxTotalBytes: exports.DEFAULT_MAX_UNCOMPRESSED_BYTES,
23132
- createError
23133
- });
23134
- }
23135
- function openNestedZip(bytes) {
23136
- return openZip(bytes, { label: "Embedded", createError });
23137
- }
23138
- var createError;
23139
- var init_zip_open = __esm({
23140
- "pptx/core/utils/zip-open.ts"() {
23141
- init_zip_limits();
23142
- init_types2();
23143
- createError = (message, details) => new exports.ZipBombError(message, details);
23144
- }
23145
- });
23146
23434
 
23147
23435
  // pptx/core/utils/ole-payload-kind.ts
23148
23436
  function isZipMagic(bytes) {
@@ -74610,6 +74898,165 @@ var init_inherited_shape_transform = __esm({
74610
74898
  }
74611
74899
  });
74612
74900
 
74901
+ // pptx/core/utils/placeholder-xml.ts
74902
+ function findNonVisualProps(rawXml) {
74903
+ for (const container2 of ["p:nvSpPr", "p:nvPicPr", "p:nvGraphicFramePr"]) {
74904
+ const parent = rawXml[container2];
74905
+ const nvPr = parent?.["p:nvPr"];
74906
+ if (nvPr) {
74907
+ return nvPr;
74908
+ }
74909
+ }
74910
+ return void 0;
74911
+ }
74912
+ function retargetPlaceholder(rawXml, target) {
74913
+ const nvPr = findNonVisualProps(rawXml);
74914
+ if (!nvPr) {
74915
+ return;
74916
+ }
74917
+ const ph = nvPr["p:ph"] ?? {};
74918
+ nvPr["p:ph"] = ph;
74919
+ if (target.type) {
74920
+ ph["@_type"] = target.type;
74921
+ } else {
74922
+ delete ph["@_type"];
74923
+ }
74924
+ if (target.idx !== void 0) {
74925
+ ph["@_idx"] = target.idx;
74926
+ } else {
74927
+ delete ph["@_idx"];
74928
+ }
74929
+ }
74930
+ function setRawXmlTransform(rawXml, xEmu, yEmu, cxEmu, cyEmu) {
74931
+ const spPr = rawXml["p:spPr"];
74932
+ if (!spPr) {
74933
+ return;
74934
+ }
74935
+ const xfrm = spPr["a:xfrm"] ?? {};
74936
+ spPr["a:xfrm"] = xfrm;
74937
+ const off = xfrm["a:off"] ?? {};
74938
+ xfrm["a:off"] = off;
74939
+ off["@_x"] = String(xEmu);
74940
+ off["@_y"] = String(yEmu);
74941
+ const ext = xfrm["a:ext"] ?? {};
74942
+ xfrm["a:ext"] = ext;
74943
+ ext["@_cx"] = String(cxEmu);
74944
+ ext["@_cy"] = String(cyEmu);
74945
+ }
74946
+ function createEmptyPlaceholderElement(target, xEmu, yEmu, cxEmu, cyEmu, uniqueId) {
74947
+ if (cxEmu <= 0 || cyEmu <= 0) {
74948
+ return null;
74949
+ }
74950
+ const phNode = {};
74951
+ if (target.type) {
74952
+ phNode["@_type"] = target.type;
74953
+ }
74954
+ if (target.idx !== void 0) {
74955
+ phNode["@_idx"] = target.idx;
74956
+ }
74957
+ const rawXml = {
74958
+ "p:nvSpPr": {
74959
+ "p:cNvPr": {
74960
+ "@_id": uniqueId,
74961
+ "@_name": `Placeholder ${target.type || "content"}`
74962
+ },
74963
+ "p:cNvSpPr": {
74964
+ "a:spLocks": { "@_noGrp": "1" }
74965
+ },
74966
+ "p:nvPr": {
74967
+ "p:ph": phNode
74968
+ }
74969
+ },
74970
+ "p:spPr": {
74971
+ "a:xfrm": {
74972
+ "a:off": { "@_x": String(xEmu), "@_y": String(yEmu) },
74973
+ "a:ext": { "@_cx": String(cxEmu), "@_cy": String(cyEmu) }
74974
+ }
74975
+ },
74976
+ "p:txBody": {
74977
+ "a:bodyPr": {},
74978
+ "a:lstStyle": {},
74979
+ "a:p": { "a:endParaRPr": { "@_lang": "en-US" } }
74980
+ }
74981
+ };
74982
+ return {
74983
+ type: "text",
74984
+ id: `ph-${target.type || "content"}-${target.idx ?? "0"}-${uniqueId}`,
74985
+ x: Math.round(xEmu / exports.EMU_PER_PX),
74986
+ y: Math.round(yEmu / exports.EMU_PER_PX),
74987
+ width: Math.round(cxEmu / exports.EMU_PER_PX),
74988
+ height: Math.round(cyEmu / exports.EMU_PER_PX),
74989
+ text: "",
74990
+ rawXml
74991
+ };
74992
+ }
74993
+ var init_placeholder_xml = __esm({
74994
+ "pptx/core/utils/placeholder-xml.ts"() {
74995
+ init_constants2();
74996
+ }
74997
+ });
74998
+
74999
+ // pptx/core/core/runtime/save-geometry-validation.ts
75000
+ function omitsInheritedFrame(element) {
75001
+ if (!["text", "shape", "picture", "media"].includes(element.type) || !element.rawXml)
75002
+ return false;
75003
+ if (!xmlHasChild(findNonVisualProps(element.rawXml), "p:ph")) return false;
75004
+ if (xmlHasChild(xmlChild(element.rawXml, "p:spPr"), "a:xfrm") || xmlHasChild(element.rawXml, "p:xfrm"))
75005
+ return false;
75006
+ const baseline = element.inheritedTransform;
75007
+ if (!baseline) return FRAME_FIELDS.every((key2) => element[key2] === void 0);
75008
+ return FRAME_FIELDS.every(
75009
+ (key2) => Number.isFinite(baseline[key2]) && (element[key2] === void 0 || element[key2] === baseline[key2])
75010
+ ) && ["rotation", "skewX", "skewY", "flipHorizontal", "flipVertical"].every(
75011
+ (key2) => (element[key2] ?? 0) === (baseline[key2] ?? 0)
75012
+ );
75013
+ }
75014
+ function validateElementGeometry(element, context, emuPerPx = 9525) {
75015
+ const inherited = omitsInheritedFrame(element);
75016
+ const record2 = element;
75017
+ const fields = [...inherited ? [] : FRAME_FIELDS, ...OPTIONAL_FIELDS];
75018
+ for (const field of fields) {
75019
+ const value = record2[field];
75020
+ if (OPTIONAL_FIELDS.includes(field) && value === void 0) continue;
75021
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isFinite(value * emuPerPx)) {
75022
+ throw new Error(
75023
+ `${context}: element '${element.id}' (${element.name ?? "unnamed"}, type=${element.type}) has invalid ${field}=${String(value)}; expected a finite number`
75024
+ );
75025
+ }
75026
+ }
75027
+ if (element.type === "group") {
75028
+ for (const child32 of element.children) validateElementGeometry(child32, context, emuPerPx);
75029
+ }
75030
+ }
75031
+ function validateSlideGeometry(slides) {
75032
+ for (const slide of slides) {
75033
+ for (const element of slide.elements) {
75034
+ validateElementGeometry(element, `Slide ${slide.slideNumber} (${slide.id})`);
75035
+ }
75036
+ }
75037
+ }
75038
+ var FRAME_FIELDS, OPTIONAL_FIELDS;
75039
+ var init_save_geometry_validation = __esm({
75040
+ "pptx/core/core/runtime/save-geometry-validation.ts"() {
75041
+ init_placeholder_xml();
75042
+ init_xml_access();
75043
+ FRAME_FIELDS = ["x", "y", "width", "height"];
75044
+ OPTIONAL_FIELDS = [
75045
+ "xEmu",
75046
+ "yEmu",
75047
+ "widthEmu",
75048
+ "heightEmu",
75049
+ "rotation",
75050
+ "skewX",
75051
+ "skewY",
75052
+ "chOffXEmu",
75053
+ "chOffYEmu",
75054
+ "chExtWidthEmu",
75055
+ "chExtHeightEmu"
75056
+ ];
75057
+ }
75058
+ });
75059
+
74613
75060
  // pptx/core/core/builders/PptxElementTransformUpdater.ts
74614
75061
  exports.PptxElementTransformUpdater = void 0;
74615
75062
  var init_PptxElementTransformUpdater = __esm({
@@ -74619,6 +75066,7 @@ var init_PptxElementTransformUpdater = __esm({
74619
75066
  init_xml_access();
74620
75067
  init_group_tight_rewrap();
74621
75068
  init_inherited_shape_transform();
75069
+ init_save_geometry_validation();
74622
75070
  exports.PptxElementTransformUpdater = class {
74623
75071
  applyTransform(shape, element, emuPerPx, enclosingGroupChildSpace) {
74624
75072
  const transform7 = shape["p:spPr"]?.["a:xfrm"] || shape["p:xfrm"] || // A group's child geometry uses a different frame from the load-time baseline.
@@ -74626,6 +75074,7 @@ var init_PptxElementTransformUpdater = __esm({
74626
75074
  if (!transform7) {
74627
75075
  return;
74628
75076
  }
75077
+ validateElementGeometry(element, "Transform writer", emuPerPx);
74629
75078
  if (!transform7["a:off"]) {
74630
75079
  transform7["a:off"] = {};
74631
75080
  }
@@ -77660,7 +78109,7 @@ function parseBorderSide(side) {
77660
78109
  }
77661
78110
  const widthEmu = parseInt(String(ln["@_w"] || "0"), 10);
77662
78111
  if (widthEmu > 0) {
77663
- border.width = Math.max(1, Math.round(widthEmu / EMU_PER_PIXEL2));
78112
+ border.width = Math.max(1, Math.round(widthEmu / EMU_PER_PIXEL3));
77664
78113
  has2 = true;
77665
78114
  }
77666
78115
  const prstDash = ln["a:prstDash"];
@@ -77717,12 +78166,12 @@ function parseTableStyleSectionCell3D(tcStyle) {
77717
78166
  if (bevel2) {
77718
78167
  const bevelWidth = parseInt(String(bevel2["@_w"] || "0"), 10);
77719
78168
  if (bevelWidth > 0) {
77720
- cell3D.bevelWidth = Math.round(bevelWidth / EMU_PER_PIXEL2);
78169
+ cell3D.bevelWidth = Math.round(bevelWidth / EMU_PER_PIXEL3);
77721
78170
  hasStyle = true;
77722
78171
  }
77723
78172
  const bevelHeight = parseInt(String(bevel2["@_h"] || "0"), 10);
77724
78173
  if (bevelHeight > 0) {
77725
- cell3D.bevelHeight = Math.round(bevelHeight / EMU_PER_PIXEL2);
78174
+ cell3D.bevelHeight = Math.round(bevelHeight / EMU_PER_PIXEL3);
77726
78175
  hasStyle = true;
77727
78176
  }
77728
78177
  const bevelPreset = String(bevel2["@_prst"] || "").trim();
@@ -77746,11 +78195,11 @@ function parseTableStyleSectionCell3D(tcStyle) {
77746
78195
  }
77747
78196
  return hasStyle ? cell3D : void 0;
77748
78197
  }
77749
- var EMU_PER_PIXEL2, BORDER_SIDES;
78198
+ var EMU_PER_PIXEL3, BORDER_SIDES;
77750
78199
  var init_table_style_border_parse = __esm({
77751
78200
  "pptx/core/core/runtime/table-style-border-parse.ts"() {
77752
78201
  init_color_primitives();
77753
- EMU_PER_PIXEL2 = 9525;
78202
+ EMU_PER_PIXEL3 = 9525;
77754
78203
  BORDER_SIDES = [
77755
78204
  "left",
77756
78205
  "right",
@@ -107323,6 +107772,80 @@ var init_factories = __esm({
107323
107772
  }
107324
107773
  });
107325
107774
 
107775
+ // pptx/core/utils/placeholder-remap.ts
107776
+ function placeholderContentRole(type) {
107777
+ const declared = (type ?? "").trim().toLowerCase() || "body";
107778
+ if (TITLE_ROLE.has(declared)) {
107779
+ return "title";
107780
+ }
107781
+ if (CONTENT_ROLE.has(declared)) {
107782
+ return "content";
107783
+ }
107784
+ return declared;
107785
+ }
107786
+ function preferredPlaceholderTypes(element) {
107787
+ switch (element.type) {
107788
+ case "image":
107789
+ case "picture":
107790
+ return ["pic", "obj", "body"];
107791
+ case "chart":
107792
+ return ["chart", "obj", "body"];
107793
+ case "table":
107794
+ return ["tbl", "obj", "body"];
107795
+ case "media":
107796
+ case "model3d":
107797
+ return ["media", "pic", "obj", "body"];
107798
+ case "smartArt":
107799
+ return ["dgm", "obj", "body"];
107800
+ case "text":
107801
+ return ["body", "subtitle", "obj"];
107802
+ default:
107803
+ return ["obj", "body"];
107804
+ }
107805
+ }
107806
+ function scorePlaceholderMatch(element, source, target) {
107807
+ if (placeholderContentRole(source.type) !== placeholderContentRole(target.type)) {
107808
+ return -1;
107809
+ }
107810
+ const sourceType = normalizeType(source.type);
107811
+ const targetType = normalizeType(target.type);
107812
+ let score = 1;
107813
+ if (source.idx !== void 0 && source.idx === target.idx) {
107814
+ score += 100;
107815
+ }
107816
+ if (sourceType === targetType) {
107817
+ score += 50;
107818
+ }
107819
+ const preferred = preferredPlaceholderTypes(element).indexOf(targetType);
107820
+ if (preferred >= 0) {
107821
+ score += 30 - preferred * 5;
107822
+ }
107823
+ if (targetType === "obj") {
107824
+ score += 10;
107825
+ }
107826
+ return score;
107827
+ }
107828
+ function normalizeType(type) {
107829
+ return (type ?? "").trim().toLowerCase() || "body";
107830
+ }
107831
+ var TITLE_ROLE, CONTENT_ROLE;
107832
+ var init_placeholder_remap = __esm({
107833
+ "pptx/core/utils/placeholder-remap.ts"() {
107834
+ TITLE_ROLE = /* @__PURE__ */ new Set(["title", "ctrtitle"]);
107835
+ CONTENT_ROLE = /* @__PURE__ */ new Set([
107836
+ "body",
107837
+ "obj",
107838
+ "subtitle",
107839
+ "pic",
107840
+ "chart",
107841
+ "tbl",
107842
+ "media",
107843
+ "clipart",
107844
+ "dgm"
107845
+ ]);
107846
+ }
107847
+ });
107848
+
107326
107849
  // pptx/core/core/runtime/master-save-helpers.ts
107327
107850
  function applyHeaderFooterFlagsToNode(root, flags) {
107328
107851
  if (!flags || Object.keys(flags).length === 0) {
@@ -126916,178 +127439,6 @@ var init_chart_user_shapes_serializer = __esm({
126916
127439
  }
126917
127440
  });
126918
127441
 
126919
- // pptx/core/utils/placeholder-remap.ts
126920
- function placeholderContentRole(type) {
126921
- const declared = (type ?? "").trim().toLowerCase() || "body";
126922
- if (TITLE_ROLE.has(declared)) {
126923
- return "title";
126924
- }
126925
- if (CONTENT_ROLE.has(declared)) {
126926
- return "content";
126927
- }
126928
- return declared;
126929
- }
126930
- function preferredPlaceholderTypes(element) {
126931
- switch (element.type) {
126932
- case "image":
126933
- case "picture":
126934
- return ["pic", "obj", "body"];
126935
- case "chart":
126936
- return ["chart", "obj", "body"];
126937
- case "table":
126938
- return ["tbl", "obj", "body"];
126939
- case "media":
126940
- case "model3d":
126941
- return ["media", "pic", "obj", "body"];
126942
- case "smartArt":
126943
- return ["dgm", "obj", "body"];
126944
- case "text":
126945
- return ["body", "subtitle", "obj"];
126946
- default:
126947
- return ["obj", "body"];
126948
- }
126949
- }
126950
- function scorePlaceholderMatch(element, source, target) {
126951
- if (placeholderContentRole(source.type) !== placeholderContentRole(target.type)) {
126952
- return -1;
126953
- }
126954
- const sourceType = normalizeType(source.type);
126955
- const targetType = normalizeType(target.type);
126956
- let score = 1;
126957
- if (source.idx !== void 0 && source.idx === target.idx) {
126958
- score += 100;
126959
- }
126960
- if (sourceType === targetType) {
126961
- score += 50;
126962
- }
126963
- const preferred = preferredPlaceholderTypes(element).indexOf(targetType);
126964
- if (preferred >= 0) {
126965
- score += 30 - preferred * 5;
126966
- }
126967
- if (targetType === "obj") {
126968
- score += 10;
126969
- }
126970
- return score;
126971
- }
126972
- function normalizeType(type) {
126973
- return (type ?? "").trim().toLowerCase() || "body";
126974
- }
126975
- var TITLE_ROLE, CONTENT_ROLE;
126976
- var init_placeholder_remap = __esm({
126977
- "pptx/core/utils/placeholder-remap.ts"() {
126978
- TITLE_ROLE = /* @__PURE__ */ new Set(["title", "ctrtitle"]);
126979
- CONTENT_ROLE = /* @__PURE__ */ new Set([
126980
- "body",
126981
- "obj",
126982
- "subtitle",
126983
- "pic",
126984
- "chart",
126985
- "tbl",
126986
- "media",
126987
- "clipart",
126988
- "dgm"
126989
- ]);
126990
- }
126991
- });
126992
-
126993
- // pptx/core/utils/placeholder-xml.ts
126994
- function findNonVisualProps(rawXml) {
126995
- for (const container2 of ["p:nvSpPr", "p:nvPicPr", "p:nvGraphicFramePr"]) {
126996
- const parent = rawXml[container2];
126997
- const nvPr = parent?.["p:nvPr"];
126998
- if (nvPr) {
126999
- return nvPr;
127000
- }
127001
- }
127002
- return void 0;
127003
- }
127004
- function retargetPlaceholder(rawXml, target) {
127005
- const nvPr = findNonVisualProps(rawXml);
127006
- if (!nvPr) {
127007
- return;
127008
- }
127009
- const ph = nvPr["p:ph"] ?? {};
127010
- nvPr["p:ph"] = ph;
127011
- if (target.type) {
127012
- ph["@_type"] = target.type;
127013
- } else {
127014
- delete ph["@_type"];
127015
- }
127016
- if (target.idx !== void 0) {
127017
- ph["@_idx"] = target.idx;
127018
- } else {
127019
- delete ph["@_idx"];
127020
- }
127021
- }
127022
- function setRawXmlTransform(rawXml, xEmu, yEmu, cxEmu, cyEmu) {
127023
- const spPr = rawXml["p:spPr"];
127024
- if (!spPr) {
127025
- return;
127026
- }
127027
- const xfrm = spPr["a:xfrm"] ?? {};
127028
- spPr["a:xfrm"] = xfrm;
127029
- const off = xfrm["a:off"] ?? {};
127030
- xfrm["a:off"] = off;
127031
- off["@_x"] = String(xEmu);
127032
- off["@_y"] = String(yEmu);
127033
- const ext = xfrm["a:ext"] ?? {};
127034
- xfrm["a:ext"] = ext;
127035
- ext["@_cx"] = String(cxEmu);
127036
- ext["@_cy"] = String(cyEmu);
127037
- }
127038
- function createEmptyPlaceholderElement(target, xEmu, yEmu, cxEmu, cyEmu, uniqueId) {
127039
- if (cxEmu <= 0 || cyEmu <= 0) {
127040
- return null;
127041
- }
127042
- const phNode = {};
127043
- if (target.type) {
127044
- phNode["@_type"] = target.type;
127045
- }
127046
- if (target.idx !== void 0) {
127047
- phNode["@_idx"] = target.idx;
127048
- }
127049
- const rawXml = {
127050
- "p:nvSpPr": {
127051
- "p:cNvPr": {
127052
- "@_id": uniqueId,
127053
- "@_name": `Placeholder ${target.type || "content"}`
127054
- },
127055
- "p:cNvSpPr": {
127056
- "a:spLocks": { "@_noGrp": "1" }
127057
- },
127058
- "p:nvPr": {
127059
- "p:ph": phNode
127060
- }
127061
- },
127062
- "p:spPr": {
127063
- "a:xfrm": {
127064
- "a:off": { "@_x": String(xEmu), "@_y": String(yEmu) },
127065
- "a:ext": { "@_cx": String(cxEmu), "@_cy": String(cyEmu) }
127066
- }
127067
- },
127068
- "p:txBody": {
127069
- "a:bodyPr": {},
127070
- "a:lstStyle": {},
127071
- "a:p": { "a:endParaRPr": { "@_lang": "en-US" } }
127072
- }
127073
- };
127074
- return {
127075
- type: "text",
127076
- id: `ph-${target.type || "content"}-${target.idx ?? "0"}-${uniqueId}`,
127077
- x: Math.round(xEmu / exports.EMU_PER_PX),
127078
- y: Math.round(yEmu / exports.EMU_PER_PX),
127079
- width: Math.round(cxEmu / exports.EMU_PER_PX),
127080
- height: Math.round(cyEmu / exports.EMU_PER_PX),
127081
- text: "",
127082
- rawXml
127083
- };
127084
- }
127085
- var init_placeholder_xml = __esm({
127086
- "pptx/core/utils/placeholder-xml.ts"() {
127087
- init_constants2();
127088
- }
127089
- });
127090
-
127091
127442
  // pptx/core/utils/text-fill-blip.ts
127092
127443
  function resolveTextFillBlip(blipFill, lookupTarget, resolveArchivePath, allowExternal) {
127093
127444
  const blip = blipFill["a:blip"];
@@ -146991,8 +147342,8 @@ function mergeBorderSideXml(border, existingSide) {
146991
147342
  const ln = ensureChild2(existing, "a:ln");
146992
147343
  if (border.width !== void 0) {
146993
147344
  const currentEmu = parseInt(String(ln["@_w"] || "0"), 10);
146994
- if (currentEmu <= 0 || Math.max(1, Math.round(currentEmu / EMU_PER_PIXEL3)) !== border.width) {
146995
- ln["@_w"] = String(Math.round(border.width * EMU_PER_PIXEL3));
147345
+ if (currentEmu <= 0 || Math.max(1, Math.round(currentEmu / EMU_PER_PIXEL4)) !== border.width) {
147346
+ ln["@_w"] = String(Math.round(border.width * EMU_PER_PIXEL4));
146996
147347
  }
146997
147348
  }
146998
147349
  if (border.dash) {
@@ -147048,10 +147399,10 @@ function writeTableStyleSectionCell3D(section, cell3D) {
147048
147399
  if (cell3D.bevelWidth !== void 0 || cell3D.bevelHeight !== void 0 || cell3D.bevelPreset !== void 0) {
147049
147400
  const bevel2 = {};
147050
147401
  if (cell3D.bevelWidth !== void 0) {
147051
- bevel2["@_w"] = String(Math.round(cell3D.bevelWidth * EMU_PER_PIXEL3));
147402
+ bevel2["@_w"] = String(Math.round(cell3D.bevelWidth * EMU_PER_PIXEL4));
147052
147403
  }
147053
147404
  if (cell3D.bevelHeight !== void 0) {
147054
- bevel2["@_h"] = String(Math.round(cell3D.bevelHeight * EMU_PER_PIXEL3));
147405
+ bevel2["@_h"] = String(Math.round(cell3D.bevelHeight * EMU_PER_PIXEL4));
147055
147406
  }
147056
147407
  if (cell3D.bevelPreset) {
147057
147408
  bevel2["@_prst"] = cell3D.bevelPreset;
@@ -147070,12 +147421,12 @@ function writeTableStyleSectionCell3D(section, cell3D) {
147070
147421
  }
147071
147422
  tcStyle["a:cell3D"] = node;
147072
147423
  }
147073
- var EMU_PER_PIXEL3, BORDER_SIDE_ORDER, LN_CHILD_ORDER, LN_FILL_KEYS;
147424
+ var EMU_PER_PIXEL4, BORDER_SIDE_ORDER, LN_CHILD_ORDER, LN_FILL_KEYS;
147074
147425
  var init_table_style_border_write = __esm({
147075
147426
  "pptx/core/core/runtime/table-style-border-write.ts"() {
147076
147427
  init_xml_reorder();
147077
147428
  init_table_style_xml_helpers();
147078
- EMU_PER_PIXEL3 = 9525;
147429
+ EMU_PER_PIXEL4 = 9525;
147079
147430
  BORDER_SIDE_ORDER = [
147080
147431
  "a:left",
147081
147432
  "a:right",
@@ -148013,6 +148364,7 @@ var init_PptxHandlerRuntimeSavePipeline = __esm({
148013
148364
  init_header_footer_parts();
148014
148365
  init_pptx_print_properties();
148015
148366
  init_PptxHandlerRuntimeSaveStructuralIds();
148367
+ init_save_geometry_validation();
148016
148368
  PptxHandlerRuntime54 = class _PptxHandlerRuntime extends PptxHandlerRuntime53 {
148017
148369
  /**
148018
148370
  * Resolve the effective conformance class for this save operation.
@@ -148027,6 +148379,19 @@ var init_PptxHandlerRuntimeSavePipeline = __esm({
148027
148379
  return this.isStrictOoxml ? "strict" : "transitional";
148028
148380
  }
148029
148381
  async save(slides, options) {
148382
+ validateSlideGeometry(slides);
148383
+ const templates = [
148384
+ ...options?.slideMasters ?? [],
148385
+ ...options?.slideLayouts ?? [],
148386
+ ...options?.slideMasters?.flatMap((master) => master.layouts ?? []) ?? [],
148387
+ ...options?.notesMaster ? [options.notesMaster] : [],
148388
+ ...options?.handoutMaster ? [options.handoutMaster] : []
148389
+ ];
148390
+ for (const template of templates) {
148391
+ for (const element of template.elements ?? []) {
148392
+ validateElementGeometry(element, `Template (${template.path})`);
148393
+ }
148394
+ }
148030
148395
  if (options?.outputFormat === "ppt") {
148031
148396
  return this.saveAsLegacyPpt(
148032
148397
  slides,
@@ -148994,8 +149359,7 @@ var init_PptxHandlerRuntimePlaceholderLookup = __esm({
148994
149359
  return this.scanPlaceholderBuckets(spTree, (info) => info?.type === type);
148995
149360
  }
148996
149361
  /** The layout and master counterparts of a placeholder, unmerged. */
148997
- findPlaceholderContexts(slidePath, expected) {
148998
- const layoutPath = this.resolveLayoutPathForSlide(slidePath);
149362
+ findPlaceholderContexts(slidePath, expected, layoutPath = this.resolveLayoutPathForSlide(slidePath)) {
148999
149363
  if (!layoutPath) {
149000
149364
  return {};
149001
149365
  }
@@ -149007,10 +149371,11 @@ var init_PptxHandlerRuntimePlaceholderLookup = __esm({
149007
149371
  const master = this.findPlaceholderInShapeTree(masterSpTree, expected) ?? this.findSingletonPlaceholderInShapeTree(masterSpTree, expected);
149008
149372
  return { layout, master };
149009
149373
  }
149010
- findPlaceholderContext(slidePath, expected) {
149374
+ findPlaceholderContext(slidePath, expected, layoutPath) {
149011
149375
  const { layout: layoutContext, master: masterContext } = this.findPlaceholderContexts(
149012
149376
  slidePath,
149013
- expected
149377
+ expected,
149378
+ layoutPath
149014
149379
  );
149015
149380
  if (!layoutContext) {
149016
149381
  return masterContext;
@@ -149036,8 +149401,8 @@ var init_PptxHandlerRuntimePlaceholderLookup = __esm({
149036
149401
  * a master `p:sp`), so the layout keeps winning exactly as it does when
149037
149402
  * both are shapes.
149038
149403
  */
149039
- findPlaceholderNode(slidePath, expected) {
149040
- const { layout, master } = this.findPlaceholderContexts(slidePath, expected);
149404
+ findPlaceholderNode(slidePath, expected, layoutPath) {
149405
+ const { layout, master } = this.findPlaceholderContexts(slidePath, expected, layoutPath);
149041
149406
  const firstNode2 = (context) => context?.shape ?? context?.picture ?? context?.graphicFrame;
149042
149407
  const layoutNode = firstNode2(layout);
149043
149408
  const masterNode = firstNode2(master);
@@ -149078,8 +149443,7 @@ var init_PptxHandlerRuntimePlaceholderLookup = __esm({
149078
149443
  * reference. Checks the layout cache first, then the master cache, and
149079
149444
  * merges them so that layout values take priority over master values.
149080
149445
  */
149081
- lookupPlaceholderDefaults(slidePath, phInfo) {
149082
- const layoutPath = this.resolveLayoutPathForSlide(slidePath);
149446
+ lookupPlaceholderDefaults(slidePath, phInfo, layoutPath = this.resolveLayoutPathForSlide(slidePath)) {
149083
149447
  if (!layoutPath) {
149084
149448
  return void 0;
149085
149449
  }
@@ -151258,14 +151622,14 @@ var init_PptxHandlerRuntimeShapeParsing = __esm({
151258
151622
  init_element_paragraph_geometry();
151259
151623
  init_PptxHandlerRuntimeShapeParagraphContentParsing();
151260
151624
  PptxHandlerRuntime67 = class _PptxHandlerRuntime extends PptxHandlerRuntime66 {
151261
- parseShape(shape, id, slidePath) {
151625
+ parseShape(shape, id, slidePath, layoutPath) {
151262
151626
  try {
151263
151627
  const spPr = shape["p:spPr"];
151264
151628
  const slideRelationshipMap = slidePath ? this.slideRelsMap.get(slidePath) : void 0;
151265
151629
  const placeholderInfo = this.extractPlaceholderInfo(
151266
151630
  shape?.["p:nvSpPr"]?.["p:nvPr"]
151267
151631
  );
151268
- const inheritedPlaceholder = slidePath && placeholderInfo ? this.findPlaceholderContext(slidePath, placeholderInfo) : void 0;
151632
+ const inheritedPlaceholder = (slidePath || layoutPath) && placeholderInfo ? this.findPlaceholderContext(slidePath ?? "", placeholderInfo, layoutPath) : void 0;
151269
151633
  const inheritedSpPr = inheritedPlaceholder?.shape?.["p:spPr"] || inheritedPlaceholder?.picture?.["p:spPr"];
151270
151634
  const effectiveSpPr = spPr ? {
151271
151635
  ...spPr,
@@ -151391,7 +151755,7 @@ var init_PptxHandlerRuntimeShapeParsing = __esm({
151391
151755
  );
151392
151756
  const linkedTxbxId = bodyPropResult.linkedTxbxId;
151393
151757
  const linkedTxbxSeq = bodyPropResult.linkedTxbxSeq;
151394
- const phDefaults = slidePath && placeholderInfo ? this.lookupPlaceholderDefaults(slidePath, placeholderInfo) : void 0;
151758
+ const phDefaults = (slidePath || layoutPath) && placeholderInfo ? this.lookupPlaceholderDefaults(slidePath ?? "", placeholderInfo, layoutPath) : void 0;
151395
151759
  if (phDefaults) {
151396
151760
  this.applyPlaceholderBodyDefaults(textStyle, phDefaults);
151397
151761
  }
@@ -160754,14 +161118,199 @@ var init_PptxHandlerRuntimeBackgroundStyles = __esm({
160754
161118
  };
160755
161119
  }
160756
161120
  });
161121
+
161122
+ // pptx/core/core/runtime/sdk-placeholder.ts
161123
+ function selectTextPlaceholder(input, type, options, slots) {
161124
+ if (!TEXT_PLACEHOLDER_TYPES.has(type.toLowerCase())) {
161125
+ throw new Error(`Unsupported text placeholder type: ${type}`);
161126
+ }
161127
+ if (options.idx !== void 0 && (!Number.isInteger(options.idx) || options.idx < 0 || options.idx > 4294967295)) {
161128
+ throw new Error("Placeholder idx must be an unsigned 32-bit integer");
161129
+ }
161130
+ const source = {
161131
+ type: type.toLowerCase(),
161132
+ ...options.idx !== void 0 ? { idx: String(options.idx) } : {}
161133
+ };
161134
+ let best;
161135
+ let bestScore = 0;
161136
+ for (const slot of slots) {
161137
+ if (!TEXT_PLACEHOLDER_TYPES.has(slot.phInfo.type ?? "obj")) continue;
161138
+ if (source.idx !== void 0 && source.idx !== (slot.phInfo.idx ?? "0")) continue;
161139
+ const score = scorePlaceholderMatch(input, source, slot.phInfo);
161140
+ if (score > bestScore) {
161141
+ best = slot;
161142
+ bestScore = score;
161143
+ }
161144
+ }
161145
+ return best ? { type: canonicalPlaceholderType(best.phInfo.type ?? "obj"), idx: best.phInfo.idx } : { type: canonicalPlaceholderType(source.type), idx: source.idx };
161146
+ }
161147
+ function withoutFallbackLanguage(properties) {
161148
+ const { "@_lang": language, ...rest } = properties;
161149
+ if (language !== "en-US") return properties;
161150
+ const keys = Object.keys(rest);
161151
+ return keys.length === 0 || keys.length === 1 && rest["@_dirty"] === "0" ? void 0 : rest;
161152
+ }
161153
+ function stripFallbackLanguage(node, key2) {
161154
+ const properties = node[key2];
161155
+ if (!properties || typeof properties !== "object") return node;
161156
+ const next = withoutFallbackLanguage(properties);
161157
+ if (next === properties) return node;
161158
+ const result = {};
161159
+ for (const [name, value] of Object.entries(node)) {
161160
+ if (name !== key2) result[name] = value;
161161
+ else if (next) result[name] = next;
161162
+ }
161163
+ return result;
161164
+ }
161165
+ function withoutFallbackLanguages(paragraphs) {
161166
+ return paragraphs.map((paragraph) => {
161167
+ const next = { ...stripFallbackLanguage(paragraph, "a:endParaRPr") };
161168
+ for (const child32 of ["a:r", "a:br", "a:fld"]) {
161169
+ const nodes = next[child32];
161170
+ if (nodes === void 0) continue;
161171
+ next[child32] = Array.isArray(nodes) ? nodes.map((node) => stripFallbackLanguage(node, "a:rPr")) : stripFallbackLanguage(nodes, "a:rPr");
161172
+ }
161173
+ return next;
161174
+ });
161175
+ }
161176
+ function placeholderShape2(identity, paragraphs) {
161177
+ paragraphs = withoutFallbackLanguages(paragraphs);
161178
+ return {
161179
+ "p:nvSpPr": {
161180
+ "p:cNvPr": { "@_id": "2", "@_name": `Placeholder ${identity.type}` },
161181
+ "p:cNvSpPr": { "a:spLocks": { "@_noGrp": "1" } },
161182
+ "p:nvPr": {
161183
+ "p:ph": {
161184
+ "@_type": identity.type,
161185
+ ...identity.idx !== void 0 ? { "@_idx": identity.idx } : {}
161186
+ }
161187
+ }
161188
+ },
161189
+ "p:spPr": {},
161190
+ "p:txBody": { "a:bodyPr": {}, "a:lstStyle": {}, "a:p": paragraphs }
161191
+ };
161192
+ }
161193
+ function applyPlaceholderFrame(shape, inherited, options, emuPerPx, materializeFrame = false) {
161194
+ for (const key2 of ["x", "y", "width", "height"]) {
161195
+ if (options[key2] !== void 0 && !Number.isFinite(options[key2])) {
161196
+ throw new Error(`Invalid placeholder frame for ${key2}: expected a finite number`);
161197
+ }
161198
+ }
161199
+ const off = xmlPath(inherited, "p:spPr", "a:xfrm", "a:off");
161200
+ const ext = xmlPath(inherited, "p:spPr", "a:xfrm", "a:ext");
161201
+ const frame2 = {
161202
+ x: options.x ?? (off?.["@_x"] !== void 0 ? Number(off["@_x"]) / emuPerPx : void 0),
161203
+ y: options.y ?? (off?.["@_y"] !== void 0 ? Number(off["@_y"]) / emuPerPx : void 0),
161204
+ width: options.width ?? (ext?.["@_cx"] !== void 0 ? Number(ext["@_cx"]) / emuPerPx : void 0),
161205
+ height: options.height ?? (ext?.["@_cy"] !== void 0 ? Number(ext["@_cy"]) / emuPerPx : void 0)
161206
+ };
161207
+ for (const [key2, value] of Object.entries(frame2)) {
161208
+ if (!Number.isFinite(value)) {
161209
+ throw new Error(
161210
+ `No matching placeholder frame for ${key2}; supply a complete explicit frame or choose a layout containing this slot`
161211
+ );
161212
+ }
161213
+ }
161214
+ if (materializeFrame || ["x", "y", "width", "height"].some((key2) => options[key2] !== void 0)) {
161215
+ setRawXmlTransform(
161216
+ shape,
161217
+ ...["x", "y", "width", "height"].map(
161218
+ (key2) => Math.round(frame2[key2] * emuPerPx)
161219
+ )
161220
+ );
161221
+ }
161222
+ }
161223
+ var TEXT_PLACEHOLDER_TYPES;
161224
+ var init_sdk_placeholder = __esm({
161225
+ "pptx/core/core/runtime/sdk-placeholder.ts"() {
161226
+ init_placeholder_remap();
161227
+ init_placeholder_xml();
161228
+ init_placeholder_validation();
161229
+ init_xml_access();
161230
+ TEXT_PLACEHOLDER_TYPES = /* @__PURE__ */ new Set([
161231
+ "title",
161232
+ "ctrtitle",
161233
+ "subtitle",
161234
+ "body",
161235
+ "obj",
161236
+ "dt",
161237
+ "ftr",
161238
+ "hdr",
161239
+ "sldnum"
161240
+ ]);
161241
+ }
161242
+ });
161243
+
161244
+ // pptx/core/core/runtime/PptxHandlerRuntimeSdkPlaceholders.ts
160757
161245
  var PptxHandlerRuntime103;
161246
+ var init_PptxHandlerRuntimeSdkPlaceholders = __esm({
161247
+ "pptx/core/core/runtime/PptxHandlerRuntimeSdkPlaceholders.ts"() {
161248
+ init_placeholder_remap();
161249
+ init_xml_access();
161250
+ init_PptxHandlerRuntimeBackgroundStyles();
161251
+ init_sdk_placeholder();
161252
+ PptxHandlerRuntime103 = class _PptxHandlerRuntime extends PptxHandlerRuntime102 {
161253
+ createPlaceholderElement(layoutPath, input, type, options) {
161254
+ if (input.type !== "text") throw new Error("Placeholder input must be text");
161255
+ const layout = this.layoutXmlMap.get(layoutPath);
161256
+ if (!layout) throw new Error(`Unknown layout: ${layoutPath}`);
161257
+ const identity = selectTextPlaceholder(
161258
+ input,
161259
+ type,
161260
+ options,
161261
+ this.extractLayoutPlaceholders(layout, layoutPath)
161262
+ );
161263
+ const shape = placeholderShape2(
161264
+ identity,
161265
+ this.createParagraphsFromTextContent(input.text, void 0, input.textSegments)
161266
+ );
161267
+ const inherited = this.findPlaceholderNode(
161268
+ "",
161269
+ { type: identity.type.toLowerCase(), idx: identity.idx },
161270
+ layoutPath
161271
+ );
161272
+ const fallback = this.sdkMasterFrame(layoutPath, identity.type, identity.idx, inherited);
161273
+ applyPlaceholderFrame(
161274
+ shape,
161275
+ fallback ?? inherited,
161276
+ options,
161277
+ _PptxHandlerRuntime.EMU_PER_PX,
161278
+ fallback !== void 0
161279
+ );
161280
+ const element = this.parseShape(shape, input.id, void 0, layoutPath);
161281
+ if (!element) throw new Error("Unable to resolve placeholder content");
161282
+ if ((element.type === "text" || element.type === "shape") && !element.textStyle && element.textSegments?.[0]?.style) {
161283
+ element.textStyle = { ...element.textSegments[0].style };
161284
+ }
161285
+ return element;
161286
+ }
161287
+ sdkMasterFrame(layoutPath, type, idx, inherited) {
161288
+ if (!inherited) return void 0;
161289
+ if (xmlPath(inherited, "p:spPr", "a:xfrm", "a:off") && xmlPath(inherited, "p:spPr", "a:xfrm", "a:ext"))
161290
+ return void 0;
161291
+ const masterPath = this.resolveMasterPathForLayout(layoutPath);
161292
+ const tree = masterPath ? xmlPath(this.masterXmlMap.get(masterPath), "p:sldMaster", "p:cSld", "p:spTree") : void 0;
161293
+ const role = placeholderContentRole(type.toLowerCase());
161294
+ const candidates = this.ensureArray(tree?.["p:sp"]).filter((shape) => {
161295
+ const info = this.extractPlaceholderInfo(xmlPath(shape, "p:nvSpPr", "p:nvPr"));
161296
+ return info && placeholderContentRole(info.type) === role;
161297
+ });
161298
+ const master = candidates.find(
161299
+ (shape) => this.extractPlaceholderInfo(xmlPath(shape, "p:nvSpPr", "p:nvPr"))?.idx === idx
161300
+ ) ?? candidates[0];
161301
+ return master ? this.mergeXmlObjects(master, inherited) : void 0;
161302
+ }
161303
+ };
161304
+ }
161305
+ });
161306
+ var PptxHandlerRuntime104;
160758
161307
  var init_PptxHandlerRuntimeImplementation = __esm({
160759
161308
  "pptx/core/core/runtime/PptxHandlerRuntimeImplementation.ts"() {
160760
161309
  init_PptxElementXmlBuilder();
160761
161310
  init_builders();
160762
161311
  init_factories();
160763
- init_PptxHandlerRuntimeBackgroundStyles();
160764
- PptxHandlerRuntime103 = class _PptxHandlerRuntime extends PptxHandlerRuntime102 {
161312
+ init_PptxHandlerRuntimeSdkPlaceholders();
161313
+ PptxHandlerRuntime104 = class _PptxHandlerRuntime extends PptxHandlerRuntime103 {
160765
161314
  constructor(dependencyFactory = new exports.PptxRuntimeDependencyFactory()) {
160766
161315
  super();
160767
161316
  this.dependencyFactory = dependencyFactory;
@@ -160905,7 +161454,7 @@ exports.PptxHandlerRuntime = void 0;
160905
161454
  var init_PptxHandlerRuntime = __esm({
160906
161455
  "pptx/core/core/PptxHandlerRuntime.ts"() {
160907
161456
  init_PptxHandlerRuntimeImplementation();
160908
- exports.PptxHandlerRuntime = class extends PptxHandlerRuntime103 {
161457
+ exports.PptxHandlerRuntime = class extends PptxHandlerRuntime104 {
160909
161458
  };
160910
161459
  }
160911
161460
  });
@@ -163669,7 +164218,7 @@ function slideMasterXml2(deck, ctx) {
163669
164218
  </p:txStyles>
163670
164219
  </p:sldMaster>`;
163671
164220
  }
163672
- function slideLayoutXml2() {
164221
+ function slideLayoutXml() {
163673
164222
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
163674
164223
  <p:sldLayout ${XMLNS2} type="blank" preserve="1">
163675
164224
  <p:cSld name="Blank">
@@ -163989,7 +164538,7 @@ async function buildPptxPackage(deck) {
163989
164538
  ${masterRels.join("\n")}
163990
164539
  </Relationships>`
163991
164540
  );
163992
- zip.file("ppt/slideLayouts/slideLayout1.xml", slideLayoutXml2());
164541
+ zip.file("ppt/slideLayouts/slideLayout1.xml", slideLayoutXml());
163993
164542
  zip.file(
163994
164543
  "ppt/slideLayouts/_rels/slideLayout1.xml.rels",
163995
164544
  `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -164207,6 +164756,13 @@ var init_PptxHandlerCore = __esm({
164207
164756
  getLayoutOptions() {
164208
164757
  return this.runtime.getLayoutOptions();
164209
164758
  }
164759
+ /** Resolve a text placeholder in this loaded deck, preserving layout inheritance. */
164760
+ createPlaceholderElement(layoutPath, input, type, options = {}) {
164761
+ if (!this.runtime.createPlaceholderElement) {
164762
+ throw new Error("This runtime does not support creating layout placeholders");
164763
+ }
164764
+ return this.runtime.createPlaceholderElement(layoutPath, input, type, options);
164765
+ }
164210
164766
  /**
164211
164767
  * Build the artwork thumbnails backing the New Slide / Layout galleries.
164212
164768
  *
@@ -166292,7 +166848,9 @@ var Presentation = class _Presentation {
166292
166848
  data,
166293
166849
  createSlide: (layoutName) => {
166294
166850
  const slideNum = data.slides.length + 1;
166295
- return new exports.SlideBuilder(slideNum, void 0, layoutName);
166851
+ const layouts = handler.getLayoutOptions();
166852
+ const layout = layouts.find((item) => item.name === layoutName) ?? layouts.find((item) => item.name === "Blank") ?? layouts[0];
166853
+ return new exports.SlideBuilder(slideNum, layout?.path, layout?.name ?? layoutName, handler);
166296
166854
  }
166297
166855
  });
166298
166856
  }
@@ -167419,199 +167977,12 @@ function addChartUserShapeGroupChild(element, groupPath, child32) {
167419
167977
  });
167420
167978
  }
167421
167979
 
167422
- // pptx/core/builders/sdk/layout-operations.ts
167423
- init_zip_open();
167424
- init_xml_utils();
167425
- init_PptxHandler();
167426
- var EMU_PER_PIXEL4 = 9525;
167427
- function pxToEmu(px3) {
167428
- return Math.round(px3 * EMU_PER_PIXEL4);
167429
- }
167430
- function placeholderSpXml(ph, shapeId) {
167431
- const name = ph.name ?? `${ph.type.charAt(0).toUpperCase() + ph.type.slice(1)} Placeholder ${shapeId - 1}`;
167432
- const x = pxToEmu(ph.x);
167433
- const y = pxToEmu(ph.y);
167434
- const cx = pxToEmu(ph.width);
167435
- const cy = pxToEmu(ph.height);
167436
- const idxAttr = ph.idx !== void 0 ? ` idx="${Math.max(0, Math.round(ph.idx))}"` : "";
167437
- return ` <p:sp>
167438
- <p:nvSpPr>
167439
- <p:cNvPr id="${shapeId}" name="${escAttr(name)}"/>
167440
- <p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr>
167441
- <p:nvPr><p:ph type="${escAttr(ph.type)}"${idxAttr}/></p:nvPr>
167442
- </p:nvSpPr>
167443
- <p:spPr>
167444
- <a:xfrm><a:off x="${x}" y="${y}"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>
167445
- </p:spPr>
167446
- <p:txBody>
167447
- <a:bodyPr/>
167448
- <a:lstStyle/>
167449
- <a:p><a:endParaRPr lang="en-US"/></a:p>
167450
- </p:txBody>
167451
- </p:sp>`;
167452
- }
167453
- function normalizeSrgbHex2(color2) {
167454
- if (!color2) {
167455
- return void 0;
167456
- }
167457
- const raw = color2.trim().replace(/^#/, "").toUpperCase();
167458
- if (/^[0-9A-F]{6}$/.test(raw)) {
167459
- return raw;
167460
- }
167461
- if (/^[0-9A-F]{3}$/.test(raw)) {
167462
- return raw.replace(/./g, (ch) => ch + ch);
167463
- }
167464
- return void 0;
167465
- }
167466
- function generateLayoutXml(definition) {
167467
- const layoutType = definition.type ?? "obj";
167468
- const placeholders = definition.placeholders ?? [];
167469
- const phShapes = placeholders.map((ph, i2) => placeholderSpXml(ph, i2 + 2)).join("\n");
167470
- let bgXml = "";
167471
- const hex3 = normalizeSrgbHex2(definition.backgroundColor);
167472
- if (hex3) {
167473
- bgXml = ` <p:bg><p:bgPr><a:solidFill><a:srgbClr val="${hex3}"/></a:solidFill><a:effectLst/></p:bgPr></p:bg>
167474
- `;
167475
- }
167476
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
167477
- <p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
167478
- xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
167479
- xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
167480
- type="${escAttr(layoutType)}" preserve="1">
167481
- <p:cSld name="${escAttr(definition.name)}">
167482
- ${bgXml} <p:spTree>
167483
- <p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>
167484
- <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>
167485
- ${phShapes}
167486
- </p:spTree>
167487
- </p:cSld>
167488
- <p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr>
167489
- </p:sldLayout>`;
167490
- }
167491
- function layoutRelsXml(masterIndex = 1) {
167492
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
167493
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
167494
- <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster${masterIndex}.xml"/>
167495
- </Relationships>`;
167496
- }
167497
- function countExistingLayouts(zip) {
167498
- let count = 0;
167499
- zip.forEach((relativePath) => {
167500
- if (/^ppt\/slideLayouts\/slideLayout\d+\.xml$/.test(relativePath)) {
167501
- count++;
167502
- }
167503
- });
167504
- return count;
167505
- }
167506
- async function addLayoutToSlideMaster(zip, layoutIndex2, masterIndex = 1) {
167507
- const masterRelsPath = `ppt/slideMasters/_rels/slideMaster${masterIndex}.xml.rels`;
167508
- const masterRelsContent = await zip.file(masterRelsPath)?.async("string");
167509
- if (!masterRelsContent) {
167510
- throw new Error(`Slide master rels not found at ${masterRelsPath}`);
167511
- }
167512
- const rIdMatches = [...masterRelsContent.matchAll(/rId(\d+)/g)];
167513
- const maxRId = rIdMatches.reduce((max, m) => Math.max(max, parseInt(m[1], 10)), 0);
167514
- const newRId = `rId${maxRId + 1}`;
167515
- const newRel = ` <Relationship Id="${newRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout${layoutIndex2}.xml"/>`;
167516
- const updatedRels = masterRelsContent.replace("</Relationships>", `${newRel}
167517
- </Relationships>`);
167518
- zip.file(masterRelsPath, updatedRels);
167519
- const masterPath = `ppt/slideMasters/slideMaster${masterIndex}.xml`;
167520
- const masterContent = await zip.file(masterPath)?.async("string");
167521
- if (!masterContent) {
167522
- throw new Error(`Slide master not found at ${masterPath}`);
167523
- }
167524
- const idMatches = [...masterContent.matchAll(/sldLayoutId\s+id="(\d+)"/g)];
167525
- const maxLayoutId = idMatches.reduce((max, m) => Math.max(max, parseInt(m[1], 10)), 2147483648);
167526
- const newLayoutId = maxLayoutId + 1;
167527
- const newLayoutIdEntry = ` <p:sldLayoutId id="${newLayoutId}" r:id="${newRId}"/>`;
167528
- const updatedMaster = masterContent.replace(
167529
- "</p:sldLayoutIdLst>",
167530
- `${newLayoutIdEntry}
167531
- </p:sldLayoutIdLst>`
167532
- );
167533
- zip.file(masterPath, updatedMaster);
167534
- }
167535
- async function addLayoutContentType(zip, layoutIndex2) {
167536
- const ctPath = "[Content_Types].xml";
167537
- const ctContent = await zip.file(ctPath)?.async("string");
167538
- if (!ctContent) {
167539
- throw new Error("Content types file not found");
167540
- }
167541
- const override = ` <Override PartName="/ppt/slideLayouts/slideLayout${layoutIndex2}.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/>`;
167542
- const updatedCt = ctContent.replace("</Types>", `${override}
167543
- </Types>`);
167544
- zip.file(ctPath, updatedCt);
167545
- }
167546
- async function createLayout(handler, data, definition, masterIndex = 1) {
167547
- const bytes = await handler.save(data.slides);
167548
- const zip = await openPptxZip(bytes);
167549
- const existingCount = countExistingLayouts(zip);
167550
- const newIndex = existingCount + 1;
167551
- const layoutPath = `ppt/slideLayouts/slideLayout${newIndex}.xml`;
167552
- zip.file(layoutPath, generateLayoutXml(definition));
167553
- zip.file(`ppt/slideLayouts/_rels/slideLayout${newIndex}.xml.rels`, layoutRelsXml(masterIndex));
167554
- await addLayoutToSlideMaster(zip, newIndex, masterIndex);
167555
- await addLayoutContentType(zip, newIndex);
167556
- const updatedBuffer = await zip.generateAsync({ type: "arraybuffer" });
167557
- const newHandler = new exports.PptxHandler();
167558
- const newData = await newHandler.load(updatedBuffer);
167559
- return {
167560
- layoutPath,
167561
- layoutName: definition.name,
167562
- handler: newHandler,
167563
- data: newData
167564
- };
167565
- }
167566
- async function createLayouts(handler, data, definitions, masterIndex = 1) {
167567
- if (definitions.length === 0) {
167568
- return { layoutPaths: [], handler, data };
167569
- }
167570
- const bytes = await handler.save(data.slides);
167571
- const zip = await openPptxZip(bytes);
167572
- const existingCount = countExistingLayouts(zip);
167573
- const layoutPaths = [];
167574
- for (let i2 = 0; i2 < definitions.length; i2++) {
167575
- const def = definitions[i2];
167576
- const newIndex = existingCount + i2 + 1;
167577
- const layoutPath = `ppt/slideLayouts/slideLayout${newIndex}.xml`;
167578
- zip.file(layoutPath, generateLayoutXml(def));
167579
- zip.file(`ppt/slideLayouts/_rels/slideLayout${newIndex}.xml.rels`, layoutRelsXml(masterIndex));
167580
- await addLayoutToSlideMaster(zip, newIndex, masterIndex);
167581
- await addLayoutContentType(zip, newIndex);
167582
- layoutPaths.push(layoutPath);
167583
- }
167584
- const updatedBuffer = await zip.generateAsync({ type: "arraybuffer" });
167585
- const newHandler = new exports.PptxHandler();
167586
- const newData = await newHandler.load(updatedBuffer);
167587
- return { layoutPaths, handler: newHandler, data: newData };
167588
- }
167589
- function findLayoutByName(data, name) {
167590
- const lowerName = name.toLowerCase();
167591
- const fromOptions = data.layoutOptions?.find((l) => l.name.toLowerCase() === lowerName);
167592
- if (fromOptions) {
167593
- return fromOptions;
167594
- }
167595
- if (data.slideMasters) {
167596
- for (const master of data.slideMasters) {
167597
- const layout = master.layouts?.find((l) => l.name?.toLowerCase() === lowerName);
167598
- if (layout) {
167599
- return { path: layout.path, name: layout.name ?? name };
167600
- }
167601
- }
167602
- }
167603
- return void 0;
167604
- }
167605
- function findLayoutByType(data, type) {
167606
- const fromOptions = data.layoutOptions?.find((l) => l.type === type);
167607
- if (fromOptions) {
167608
- return fromOptions;
167609
- }
167610
- return void 0;
167611
- }
167980
+ // pptx/core/builders/sdk/index.ts
167981
+ init_layout_operations();
167612
167982
 
167613
167983
  // pptx/core/builders/sdk/master-layout-crud-layout.ts
167614
167984
  init_PptxHandler();
167985
+ init_layout_operations();
167615
167986
 
167616
167987
  // pptx/core/builders/sdk/master-layout-crud-lookup.ts
167617
167988
  var NOT_FOUND = { ok: false, reason: "notFound" };
@@ -167915,6 +168286,7 @@ async function insertLayout(handler, data, masterId, definition) {
167915
168286
 
167916
168287
  // pptx/core/builders/sdk/master-layout-crud-master.ts
167917
168288
  init_PptxHandler();
168289
+ init_layout_operations();
167918
168290
  init_PresentationBuilder();
167919
168291
  async function duplicateSlideMaster(handler, data, masterId) {
167920
168292
  const source = findMaster(data, masterId);