@extend-ai/react-pptx 0.2.3 → 0.2.5

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.
package/dist/index.js CHANGED
@@ -42,6 +42,92 @@ function throwIfAborted(signal) {
42
42
  }
43
43
  }
44
44
 
45
+ // ../../node_modules/.pnpm/@extend-ai+office-fonts@https+++github.com+extend-hq+rust-office+releases+download+office-fon_7r4y6vimjxvcmpreabk5ezevri/node_modules/@extend-ai/office-fonts/families.js
46
+ var families = [
47
+ { id: "carlito", family: "Carlito", original: "Calibri", load: () => import('./carlito-data-LDQ4YMUR.js') },
48
+ { id: "arimo", family: "Arimo", original: "Arial", load: () => import('./arimo-data-4NQ7UA57.js') },
49
+ { id: "tinos", family: "Tinos", original: "Times New Roman", load: () => import('./tinos-data-IPPHZ4Y6.js') },
50
+ { id: "cousine", family: "Cousine", original: "Courier New", load: () => import('./cousine-data-IPO23HJ5.js') },
51
+ { id: "intos", family: "Intos", original: "Aptos", load: () => import('./intos-data-55TEPAXO.js') },
52
+ { id: "intos-narrow", family: "Intos Narrow", original: "Aptos Narrow", load: () => import('./intos-narrow-data-FHJNOFRV.js') }
53
+ ];
54
+
55
+ // ../../node_modules/.pnpm/@extend-ai+office-fonts@https+++github.com+extend-hq+rust-office+releases+download+office-fon_7r4y6vimjxvcmpreabk5ezevri/node_modules/@extend-ai/office-fonts/runtime.js
56
+ var registry = /* @__PURE__ */ Symbol.for("@extend-ai/office-fonts/loads/v2");
57
+ var loads = globalThis[registry] ??= /* @__PURE__ */ new WeakMap();
58
+ var normalize = (family) => family.trim().replace(/^["']|["']$/g, "").toLowerCase();
59
+ var primary = (family) => family.split(",")[0];
60
+ var lookup = new Map(families.flatMap((family) => [family.original, family.family].map((name) => [normalize(name), family])));
61
+ var variants = [
62
+ { style: "normal", weight: "400", suffix: "" },
63
+ { style: "normal", weight: "700", suffix: " Bold" },
64
+ { style: "italic", weight: "400", suffix: " Italic" },
65
+ { style: "italic", weight: "700", suffix: " Bold Italic" }
66
+ ];
67
+ function matches(face, family, variant) {
68
+ const weight = face.weight === "normal" ? "400" : face.weight === "bold" ? "700" : face.weight;
69
+ const range = weight.split(/\s+/).map(Number);
70
+ return normalize(face.family) === normalize(family) && face.style === variant.style && Number(variant.weight) >= range[0] && Number(variant.weight) <= (range[1] ?? range[0]);
71
+ }
72
+ async function loadOfficeFonts(target = globalThis.document, requestedFamilies = ["Calibri"]) {
73
+ const FontFaceClass = target?.defaultView?.FontFace ?? globalThis.FontFace;
74
+ if (!target?.fonts || !FontFaceClass) return;
75
+ const fonts = target.fonts;
76
+ let entries = loads.get(fonts);
77
+ if (!entries) loads.set(fonts, entries = /* @__PURE__ */ new Map());
78
+ const selected = new Set([...requestedFamilies].map((name) => normalize(primary(name))));
79
+ await Promise.all([...selected].map(async (key) => {
80
+ const definition = lookup.get(key);
81
+ if (!definition) return;
82
+ const previous = entries.get(key);
83
+ if (previous && (!previous.ready || previous.faces.every((face) => fonts.has(face)))) return previous.promise;
84
+ const family = key === normalize(definition.original) ? definition.original : definition.family;
85
+ const state = { ready: false, faces: [], promise: void 0 };
86
+ state.promise = (async () => {
87
+ const added = [];
88
+ try {
89
+ const results = await Promise.allSettled(variants.map(async (variant, index) => {
90
+ const existing = [...fonts].filter((face2) => matches(face2, family, variant) && face2.status !== "error");
91
+ if (existing.length) {
92
+ const loaded = await Promise.allSettled(existing.map((face2) => face2.load()));
93
+ const available = loaded.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
94
+ if (available.length) return available;
95
+ }
96
+ let face;
97
+ if (family === definition.original) {
98
+ try {
99
+ face = await new FontFaceClass(family, `local("${family}${variant.suffix}")`, variant).load();
100
+ } catch {
101
+ face = void 0;
102
+ }
103
+ }
104
+ if (!face) {
105
+ const { faces: assets } = await definition.load();
106
+ face = new FontFaceClass(family, `url("${assets[index].source}")`, variant);
107
+ fonts.add(face);
108
+ added.push(face);
109
+ await face.load();
110
+ } else {
111
+ fonts.add(face);
112
+ added.push(face);
113
+ }
114
+ return [face];
115
+ }));
116
+ const failure = results.find((result) => result.status === "rejected");
117
+ if (failure) throw failure.reason;
118
+ state.faces = results.flatMap((result) => result.value);
119
+ state.ready = true;
120
+ } catch (error) {
121
+ for (const face of added) fonts.delete(face);
122
+ entries.delete(key);
123
+ throw error;
124
+ }
125
+ })();
126
+ entries.set(key, state);
127
+ return state.promise;
128
+ }));
129
+ }
130
+
45
131
  // src/fonts.ts
46
132
  var GENERIC_FAMILIES = /* @__PURE__ */ new Set([
47
133
  "serif",
@@ -58,17 +144,18 @@ var GENERIC_FAMILIES = /* @__PURE__ */ new Set([
58
144
  "fangsong"
59
145
  ]);
60
146
  var OFFICE_FONT_FALLBACKS = {
61
- aptos: ["Aptos", "Segoe UI", "Arial", "sans-serif"],
147
+ aptos: ["Aptos", "Intos", "Segoe UI", "Arial", "sans-serif"],
148
+ "aptos narrow": ["Aptos Narrow", "Intos Narrow", "Arial", "sans-serif"],
62
149
  "aptos display": ["Aptos Display", "Segoe UI", "Arial", "sans-serif"],
63
150
  calibri: ["Calibri", "Carlito", "Arial", "sans-serif"],
64
151
  "calibri light": ["Calibri Light", "Carlito", "Arial", "sans-serif"],
65
152
  cambria: ["Cambria", "Caladea", "Georgia", "serif"],
66
153
  "cambria math": ["Cambria Math", "STIX Two Math", "STIXGeneral", "math"],
67
- arial: ["Arial", "Liberation Sans", "Helvetica", "sans-serif"],
154
+ arial: ["Arial", "Arimo", "Liberation Sans", "Helvetica", "sans-serif"],
68
155
  "arial narrow": ["Arial Narrow", "Liberation Sans Narrow", "Arial", "sans-serif"],
69
156
  "arial unicode ms": ["Arial Unicode MS", "Noto Sans", "Segoe UI Symbol", "sans-serif"],
70
- "times new roman": ["Times New Roman", "Liberation Serif", "Times", "serif"],
71
- "courier new": ["Courier New", "Liberation Mono", "Courier", "monospace"],
157
+ "times new roman": ["Times New Roman", "Tinos", "Liberation Serif", "Times", "serif"],
158
+ "courier new": ["Courier New", "Cousine", "Liberation Mono", "Courier", "monospace"],
72
159
  consolas: ["Consolas", "Cascadia Mono", "Liberation Mono", "monospace"],
73
160
  "century gothic": ["Century Gothic", "Avenir Next", "Futura", "Arial", "sans-serif"],
74
161
  "franklin gothic medium": ["Franklin Gothic Medium", "Arial", "sans-serif"],
@@ -142,9 +229,9 @@ function serializeFamily(family) {
142
229
  if (GENERIC_FAMILIES.has(family.toLowerCase())) return family;
143
230
  return `"${family.replaceAll('"', '\\"')}"`;
144
231
  }
145
- function uniqueFamilies(families) {
232
+ function uniqueFamilies(families2) {
146
233
  const seen = /* @__PURE__ */ new Set();
147
- return families.filter((family) => {
234
+ return families2.filter((family) => {
148
235
  const key = normalizeFamily(family).toLowerCase();
149
236
  if (!key || seen.has(key)) return false;
150
237
  seen.add(key);
@@ -153,14 +240,14 @@ function uniqueFamilies(families) {
153
240
  }
154
241
  function resolvePptxFontFamily(fontFamily2, options = {}) {
155
242
  const requested = parseFamilyList(fontFamily2);
156
- const primary = requested[0] ?? "";
157
- const configured = options.fallbacks?.[primary] ?? options.fallbacks?.[primary.toLowerCase()];
243
+ const primary2 = requested[0] ?? "";
244
+ const configured = options.fallbacks?.[primary2] ?? options.fallbacks?.[primary2.toLowerCase()];
158
245
  const configuredList = typeof configured === "string" ? [configured] : configured ?? [];
159
- const office = options.useOfficeFallbacks === false ? [] : OFFICE_FONT_FALLBACKS[primary.toLowerCase()] ?? [];
160
- const lower = primary.toLowerCase();
246
+ const office = options.useOfficeFallbacks === false ? [] : OFFICE_FONT_FALLBACKS[primary2.toLowerCase()] ?? [];
247
+ const lower = primary2.toLowerCase();
161
248
  const generic = /serif|times|cambria|mincho|ming|song|batang|david|garamond|palatino/.test(lower) ? ["Noto Serif", "Noto Serif CJK SC", "serif"] : [...UNIVERSAL_SANS_FALLBACKS];
162
249
  return uniqueFamilies([
163
- ...primary ? [primary] : [],
250
+ ...primary2 ? [primary2] : [],
164
251
  ...configuredList,
165
252
  ...office,
166
253
  ...requested.slice(1),
@@ -269,6 +356,27 @@ var PptxFontManager = class {
269
356
  message: `The supplied font \u201C${family}\u201D could not be loaded; a compatible fallback will be used.`
270
357
  });
271
358
  });
359
+ if (this.options.useOfficeFallbacks !== false) {
360
+ const families2 = /* @__PURE__ */ new Set(["Calibri"]);
361
+ const seen = /* @__PURE__ */ new Set();
362
+ const collect = (value) => {
363
+ if (!value || typeof value !== "object" || seen.has(value)) return;
364
+ seen.add(value);
365
+ for (const [key, child] of Object.entries(value)) {
366
+ if (/fontFamily$/i.test(key) && typeof child === "string") families2.add(child);
367
+ else if (child && typeof child === "object") collect(child);
368
+ }
369
+ };
370
+ collect(presentation.slides);
371
+ collect(presentation.masters);
372
+ collect(presentation.layouts);
373
+ for (const theme of presentation.themes) {
374
+ for (const family of [...Object.values(theme.majorFonts ?? {}), ...Object.values(theme.minorFonts ?? {})]) {
375
+ if (family) families2.add(family);
376
+ }
377
+ }
378
+ await loadOfficeFonts(document, families2).catch(() => void 0);
379
+ }
272
380
  if (document.fonts && this.options.waitForFonts !== false) {
273
381
  await timeout(
274
382
  Promise.resolve(document.fonts.ready).then(() => void 0),
@@ -285,21 +393,21 @@ var PptxFontManager = class {
285
393
  for (const element of elements2) {
286
394
  const raw = (element instanceof HTMLElement || element instanceof SVGElement ? element.style.fontFamily : "") || element.getAttribute("font-family");
287
395
  if (!raw) continue;
288
- const primary = parseFamilyList(raw)[0];
289
- if (!primary || primary.startsWith("+") || GENERIC_FAMILIES.has(primary.toLowerCase()))
396
+ const primary2 = parseFamilyList(raw)[0];
397
+ if (!primary2 || primary2.startsWith("+") || GENERIC_FAMILIES.has(primary2.toLowerCase()))
290
398
  continue;
291
399
  if (element instanceof HTMLElement || element instanceof SVGElement) {
292
400
  element.style.fontFamily = resolvePptxFontFamily(raw, this.options);
293
401
  }
294
- if (this.options.reportMissingFonts === false || this.loadedFamilies.has(primary.toLowerCase()) || browserHasFont(primary)) {
402
+ if (this.options.reportMissingFonts === false || this.loadedFamilies.has(primary2.toLowerCase()) || browserHasFont(primary2)) {
295
403
  continue;
296
404
  }
297
405
  this.warn({
298
406
  code: "missing-font",
299
407
  severity: "warning",
300
- feature: primary,
408
+ feature: primary2,
301
409
  ...slideIndex === void 0 ? {} : { slideIndex },
302
- message: `Font \u201C${primary}\u201D is not available in this browser; the configured fallback stack is being used.`
410
+ message: `Font \u201C${primary2}\u201D is not available in this browser; the configured fallback stack is being used.`
303
411
  });
304
412
  }
305
413
  }
@@ -3377,11 +3485,11 @@ function getCategoryLabels(chart) {
3377
3485
  return series.categories.every((value) => normalizeCategoryLabel(value).length === 0);
3378
3486
  }) || !hasAnyExplicitCategory;
3379
3487
  return Array.from({ length: categoryCount }, (_, categoryIndex) => {
3380
- const primary = primaryCategories[categoryIndex];
3381
- if (primary != null) {
3382
- const normalizedPrimary = normalizeCategoryLabel(primary);
3488
+ const primary2 = primaryCategories[categoryIndex];
3489
+ if (primary2 != null) {
3490
+ const normalizedPrimary = normalizeCategoryLabel(primary2);
3383
3491
  if (normalizedPrimary.length > 0) {
3384
- return formatCategoryLabel(chart, primary, normalizedPrimary);
3492
+ return formatCategoryLabel(chart, primary2, normalizedPrimary);
3385
3493
  }
3386
3494
  }
3387
3495
  const fallback = chart.series.map((series) => series.categories[categoryIndex]).find((value) => normalizeCategoryLabel(value).length > 0);
@@ -9507,10 +9615,10 @@ function runFontFamily(run) {
9507
9615
  run.complexScriptFontFamily,
9508
9616
  run.symbolFontFamily
9509
9617
  ];
9510
- const families = ordered.filter(
9618
+ const families2 = ordered.filter(
9511
9619
  (family, index) => Boolean(family) && ordered.indexOf(family) === index
9512
9620
  );
9513
- return families.length > 0 ? families.join(", ") : void 0;
9621
+ return families2.length > 0 ? families2.join(", ") : void 0;
9514
9622
  }
9515
9623
  function createTextRunElement(run, paragraph, fontScale) {
9516
9624
  const href = safeHyperlink(run.hyperlink);
@@ -9787,6 +9895,26 @@ function applyTextOrientation(element, textRotation, verticalText, rotationAsVer
9787
9895
  function allowsTextOverflow(value) {
9788
9896
  return value === void 0 || /overflow/i.test(value);
9789
9897
  }
9898
+ function applyPicturePaintBounds(image, bounds, allowZeroLayout = false) {
9899
+ if (!bounds || ![
9900
+ bounds.xPx,
9901
+ bounds.yPx,
9902
+ bounds.widthPx,
9903
+ bounds.heightPx,
9904
+ bounds.layoutWidthPx,
9905
+ bounds.layoutHeightPx
9906
+ ].every(Number.isFinite) || bounds.widthPx <= 0 || bounds.heightPx <= 0 || (allowZeroLayout ? bounds.layoutWidthPx < 0 : bounds.layoutWidthPx <= 0) || (allowZeroLayout ? bounds.layoutHeightPx < 0 : bounds.layoutHeightPx <= 0))
9907
+ return;
9908
+ const width = bounds.layoutWidthPx || 1;
9909
+ const height = bounds.layoutHeightPx || 1;
9910
+ image.style.position = "absolute";
9911
+ image.style.left = `${bounds.xPx / width * 100}%`;
9912
+ image.style.top = `${bounds.yPx / height * 100}%`;
9913
+ image.style.width = `${bounds.widthPx / width * 100}%`;
9914
+ image.style.height = `${bounds.heightPx / height * 100}%`;
9915
+ image.style.maxWidth = "none";
9916
+ image.style.maxHeight = "none";
9917
+ }
9790
9918
  function applyCroppedImage(image, crop) {
9791
9919
  const horizontal = Math.max(1e-6, 1 - crop.left - crop.right);
9792
9920
  const vertical = Math.max(1e-6, 1 - crop.top - crop.bottom);
@@ -10347,22 +10475,24 @@ var NormalizedPresentationViewer = class {
10347
10475
  return chart;
10348
10476
  }
10349
10477
  createNode(node, coordinate) {
10478
+ const paintedPicture = node.type === "image" && !!node.pictureSvg;
10479
+ const paintedShape = node.type === "shape" && !!node.shapeSvg;
10350
10480
  const href = safeHyperlink(node.hyperlink);
10351
10481
  const element = document.createElement(href ? "a" : "div");
10352
10482
  element.dataset.rpvNodeId = node.id;
10353
10483
  element.style.position = "absolute";
10354
10484
  element.style.left = `${(node.transform.x - coordinate.x) / coordinate.width * 100}%`;
10355
10485
  element.style.top = `${(node.transform.y - coordinate.y) / coordinate.height * 100}%`;
10356
- element.style.width = `${node.transform.width / coordinate.width * 100}%`;
10357
- element.style.height = `${node.transform.height / coordinate.height * 100}%`;
10486
+ element.style.width = `${(paintedShape && node.transform.width === 0 ? EMU_PER_CSS_PIXEL / (coordinate.scaleX || 1) : node.transform.width) / coordinate.width * 100}%`;
10487
+ element.style.height = `${(paintedShape && node.transform.height === 0 ? EMU_PER_CSS_PIXEL / (coordinate.scaleY || 1) : node.transform.height) / coordinate.height * 100}%`;
10358
10488
  element.style.boxSizing = "border-box";
10359
10489
  const transforms = [`rotate(${node.transform.rotation ?? 0}deg)`];
10360
10490
  if (node.transform.flipHorizontal) transforms.push("scaleX(-1)");
10361
10491
  if (node.transform.flipVertical) transforms.push("scaleY(-1)");
10362
- element.style.transform = transforms.join(" ");
10492
+ element.style.transform = paintedPicture || paintedShape ? "" : transforms.join(" ");
10363
10493
  element.style.transformOrigin = "center";
10364
10494
  if (node.hidden) element.hidden = true;
10365
- if (node.opacity !== void 0) element.style.opacity = String(node.opacity);
10495
+ if (!paintedPicture && node.opacity !== void 0) element.style.opacity = String(node.opacity);
10366
10496
  if (node.altText) element.setAttribute("aria-label", node.altText);
10367
10497
  if (href && element instanceof HTMLAnchorElement) {
10368
10498
  element.href = href;
@@ -10373,7 +10503,21 @@ var NormalizedPresentationViewer = class {
10373
10503
  }
10374
10504
  if (node.type === "shape") {
10375
10505
  const presetPath = normalizedPresetGeometryPath(node.geometry.preset);
10376
- if (node.geometry.path || presetPath) {
10506
+ if (node.shapeSvg) {
10507
+ const paint = document.createElement("img");
10508
+ paint.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(node.shapeSvg)}`;
10509
+ paint.alt = "";
10510
+ paint.setAttribute("aria-hidden", "true");
10511
+ paint.style.position = "absolute";
10512
+ paint.style.left = "0";
10513
+ paint.style.top = "0";
10514
+ paint.style.width = "100%";
10515
+ paint.style.height = "100%";
10516
+ paint.style.objectFit = "fill";
10517
+ paint.style.pointerEvents = "none";
10518
+ applyPicturePaintBounds(paint, node.paintBounds, true);
10519
+ element.append(paint);
10520
+ } else if (node.geometry.path || presetPath) {
10377
10521
  element.append(this.createCustomGeometry(node, node.geometry.path ?? presetPath));
10378
10522
  } else {
10379
10523
  this.applyFill(element, node.fill, node.id);
@@ -10382,7 +10526,7 @@ var NormalizedPresentationViewer = class {
10382
10526
  }
10383
10527
  const shapeAutofit = node.autofit?.mode === "shape";
10384
10528
  const verticalText = Boolean(node.verticalText && node.verticalText.toLowerCase() !== "horz");
10385
- const growsToFitText = shapeAutofit && !verticalText;
10529
+ const growsToFitText = shapeAutofit && !verticalText && !node.textTransform;
10386
10530
  if (growsToFitText) {
10387
10531
  const minimumHeight = element.style.height;
10388
10532
  element.style.height = "auto";
@@ -10390,8 +10534,10 @@ var NormalizedPresentationViewer = class {
10390
10534
  element.style.display = "flex";
10391
10535
  element.style.flexDirection = "column";
10392
10536
  }
10393
- element.style.overflowX = shapeAutofit || allowsTextOverflow(node.horizontalOverflow) ? "visible" : "clip";
10394
- element.style.overflowY = shapeAutofit || allowsTextOverflow(node.verticalOverflow) ? "visible" : "clip";
10537
+ const horizontalOverflow = shapeAutofit || allowsTextOverflow(node.horizontalOverflow) ? "visible" : "clip";
10538
+ const verticalOverflow = shapeAutofit || allowsTextOverflow(node.verticalOverflow) ? "visible" : "clip";
10539
+ element.style.overflowX = paintedShape ? "visible" : horizontalOverflow;
10540
+ element.style.overflowY = paintedShape ? "visible" : verticalOverflow;
10395
10541
  if (node.paragraphs) {
10396
10542
  const textBody = document.createElement("div");
10397
10543
  textBody.dataset.rpvTextBody = "";
@@ -10429,19 +10575,58 @@ var NormalizedPresentationViewer = class {
10429
10575
  ...node.spaceFirstLastParagraph !== void 0 ? { spaceFirstLastParagraph: node.spaceFirstLastParagraph } : {}
10430
10576
  });
10431
10577
  textBody.append(textContent);
10432
- element.append(textBody);
10578
+ if (paintedShape || node.textTransform) {
10579
+ const textFrame = document.createElement("div");
10580
+ textFrame.style.position = growsToFitText ? "relative" : "absolute";
10581
+ if (!growsToFitText) textFrame.style.inset = "0";
10582
+ textFrame.style.width = "100%";
10583
+ textFrame.style.height = growsToFitText ? "auto" : "100%";
10584
+ if (growsToFitText) textFrame.style.flex = "1 0 auto";
10585
+ textFrame.style.transform = paintedShape ? transforms.join(" ") : "";
10586
+ textFrame.style.transformOrigin = "center";
10587
+ textFrame.style.overflowX = node.textTransform ? "visible" : horizontalOverflow;
10588
+ textFrame.style.overflowY = node.textTransform ? "visible" : verticalOverflow;
10589
+ if (node.textTransform && node.transform.width > 0 && node.transform.height > 0) {
10590
+ const saved = node.textTransform;
10591
+ const savedFrame = document.createElement("div");
10592
+ savedFrame.dataset.rpvIndependentTextFrame = "";
10593
+ savedFrame.style.position = "absolute";
10594
+ savedFrame.style.left = `${(saved.x - node.transform.x) / node.transform.width * 100}%`;
10595
+ savedFrame.style.top = `${(saved.y - node.transform.y) / node.transform.height * 100}%`;
10596
+ savedFrame.style.width = `${saved.width / node.transform.width * 100}%`;
10597
+ savedFrame.style.height = `${saved.height / node.transform.height * 100}%`;
10598
+ savedFrame.style.transformOrigin = "center";
10599
+ savedFrame.style.transform = `rotate(${saved.rotation ?? 0}deg) scale(${saved.flipHorizontal ? -1 : 1}, ${saved.flipVertical ? -1 : 1})`;
10600
+ savedFrame.style.overflowX = horizontalOverflow;
10601
+ savedFrame.style.overflowY = verticalOverflow;
10602
+ savedFrame.append(textBody);
10603
+ textFrame.append(savedFrame);
10604
+ } else {
10605
+ textFrame.append(textBody);
10606
+ }
10607
+ element.append(textFrame);
10608
+ } else {
10609
+ element.append(textBody);
10610
+ }
10433
10611
  }
10434
10612
  } else if (node.type === "image") {
10435
10613
  const image = document.createElement("img");
10436
- this.applyAsset(node.assetId, (url) => image.src = url, node.id);
10437
10614
  image.alt = node.altText ?? node.name ?? "";
10438
10615
  image.style.display = "block";
10439
10616
  image.style.width = "100%";
10440
10617
  image.style.height = "100%";
10441
- image.style.objectFit = node.preserveAspectRatio === false ? "fill" : "contain";
10442
- element.style.overflow = "hidden";
10443
- if (node.crop) applyCroppedImage(image, node.crop);
10444
- this.applyImageEffects(image, node.effects, element);
10618
+ if (node.pictureSvg) {
10619
+ image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(node.pictureSvg)}`;
10620
+ image.style.objectFit = "fill";
10621
+ applyPicturePaintBounds(image, node.paintBounds);
10622
+ element.style.overflow = "visible";
10623
+ } else {
10624
+ this.applyAsset(node.assetId, (url) => image.src = url, node.id);
10625
+ image.style.objectFit = node.preserveAspectRatio === false ? "fill" : "contain";
10626
+ element.style.overflow = "hidden";
10627
+ if (node.crop) applyCroppedImage(image, node.crop);
10628
+ this.applyImageEffects(image, node.effects, element);
10629
+ }
10445
10630
  element.append(image);
10446
10631
  } else if (node.type === "group") {
10447
10632
  const childCoordinate = node.childTransform ?? {
@@ -10450,7 +10635,16 @@ var NormalizedPresentationViewer = class {
10450
10635
  width: node.transform.width,
10451
10636
  height: node.transform.height
10452
10637
  };
10453
- for (const child of node.children) element.append(this.createNode(child, childCoordinate));
10638
+ const scaleX = (coordinate.scaleX ?? 1) * node.transform.width / childCoordinate.width;
10639
+ const scaleY = (coordinate.scaleY ?? 1) * node.transform.height / childCoordinate.height;
10640
+ for (const child of node.children)
10641
+ element.append(
10642
+ this.createNode(child, {
10643
+ ...childCoordinate,
10644
+ scaleX: Number.isFinite(scaleX) && scaleX > 0 ? scaleX : coordinate.scaleX ?? 1,
10645
+ scaleY: Number.isFinite(scaleY) && scaleY > 0 ? scaleY : coordinate.scaleY ?? 1
10646
+ })
10647
+ );
10454
10648
  } else if (node.type === "table") {
10455
10649
  const table = document.createElement("table");
10456
10650
  table.style.width = "100%";
@@ -11197,7 +11391,7 @@ var configuredWorkerSource;
11197
11391
  var runtimePromise;
11198
11392
  var initialized = false;
11199
11393
  async function loadRuntime() {
11200
- runtimePromise ??= import('./dist-NDTOVNYD.js');
11394
+ runtimePromise ??= import('./dist-KIHNMEH5.js');
11201
11395
  return runtimePromise;
11202
11396
  }
11203
11397
  function setWasmSource(source) {
@@ -11265,7 +11459,7 @@ function parserFailure(error) {
11265
11459
  async function parseWithWasm(bytes, options) {
11266
11460
  try {
11267
11461
  if (canUseConfiguredSourceInWorker() && typeof window !== "undefined" && typeof Worker !== "undefined") {
11268
- const result2 = await parseInWorker(bytes, options?.signal, configuredWorkerSource);
11462
+ const result2 = await parseInWorker(bytes, options?.signal, configuredWorkerSource, { include3dModels: options?.include3dModels ?? false });
11269
11463
  return isPresentationDocument(result2) ? result2 : null;
11270
11464
  }
11271
11465
  await initWasm();
@@ -11273,8 +11467,7 @@ async function parseWithWasm(bytes, options) {
11273
11467
  const parse = runtime.parsePresentation ?? runtime.parse_presentation;
11274
11468
  if (!parse) return null;
11275
11469
  const result = await parse(bytes, {
11276
- formatHint: options?.formatHint,
11277
- signal: options?.signal
11470
+ include3dModels: options?.include3dModels
11278
11471
  });
11279
11472
  const value = typeof result === "string" ? JSON.parse(result) : result;
11280
11473
  return isPresentationDocument(value) ? value : null;
@@ -11286,7 +11479,7 @@ async function parseWithWasm(bytes, options) {
11286
11479
  }
11287
11480
  }
11288
11481
  var workerRequestId = 0;
11289
- async function parseInWorker(bytes, signal, wasmSource) {
11482
+ async function parseInWorker(bytes, signal, wasmSource, parserOptions) {
11290
11483
  if (signal?.aborted) throw new DOMException("Parsing was aborted.", "AbortError");
11291
11484
  const worker = new Worker(new URL("./native-parser-worker.js", import.meta.url), {
11292
11485
  type: "module",
@@ -11334,7 +11527,7 @@ async function parseInWorker(bytes, signal, wasmSource) {
11334
11527
  return;
11335
11528
  }
11336
11529
  try {
11337
- worker.postMessage({ id, bytes: owned, wasmSource }, [owned]);
11530
+ worker.postMessage({ id, bytes: owned, wasmSource, parserOptions }, [owned]);
11338
11531
  } catch (error) {
11339
11532
  settle(() => reject(error));
11340
11533
  }
@@ -11448,6 +11641,7 @@ async function parsePresentation(source, options = {}) {
11448
11641
  const parsingStartedAt = performanceNow();
11449
11642
  const nativeDocument = await parseWithWasm(bytes, {
11450
11643
  formatHint: format,
11644
+ ...options.include3dModels !== void 0 ? { include3dModels: options.include3dModels } : {},
11451
11645
  ...options.signal ? { signal: options.signal } : {}
11452
11646
  });
11453
11647
  options.onPerformanceMeasurement?.(performanceMeasurement("wasm-parsing", parsingStartedAt));
@@ -11465,7 +11659,8 @@ async function parsePresentation(source, options = {}) {
11465
11659
  };
11466
11660
  }
11467
11661
  var presentationParsingDefaults = Object.freeze({
11468
- maxInputBytes: DEFAULT_MAX_INPUT_BYTES
11662
+ maxInputBytes: DEFAULT_MAX_INPUT_BYTES,
11663
+ include3dModels: false
11469
11664
  });
11470
11665
  var THUMBNAIL_ROW_ESTIMATE = 123;
11471
11666
  var THUMBNAIL_OVERSCAN = 1;
@@ -11720,6 +11915,7 @@ var ReactPptxViewer = forwardRef(
11720
11915
  const batchSize = virtualizationOptions.batchSize ?? 3;
11721
11916
  const scrollElement = virtualizationOptions.scrollElement ?? null;
11722
11917
  const parseFormatHint = parseOptions?.formatHint;
11918
+ const parseInclude3dModels = parseOptions?.include3dModels;
11723
11919
  const parseMaxInputBytes = parseOptions?.maxInputBytes;
11724
11920
  const parseFetchInit = parseOptions?.fetchInit;
11725
11921
  const parseFetchInitKey = requestInitKey(parseFetchInit);
@@ -11856,6 +12052,7 @@ var ReactPptxViewer = forwardRef(
11856
12052
  void parsePresentation(source, {
11857
12053
  signal: abort.signal,
11858
12054
  ...parseFormatHint ? { formatHint: parseFormatHint } : {},
12055
+ ...parseInclude3dModels !== void 0 ? { include3dModels: parseInclude3dModels } : {},
11859
12056
  ...parseMaxInputBytes !== void 0 ? { maxInputBytes: parseMaxInputBytes } : {},
11860
12057
  ...parseFetchInit ? { fetchInit: parseFetchInit } : {},
11861
12058
  onPerformanceMeasurement: (measurement) => latestPropsRef.current.onPerformanceMeasurement?.(measurement)
@@ -11877,7 +12074,7 @@ var ReactPptxViewer = forwardRef(
11877
12074
  if (!abort.signal.aborted) setLoading(false);
11878
12075
  });
11879
12076
  return () => abort.abort();
11880
- }, [source, parseFormatHint, parseMaxInputBytes, parseFetchInitKey]);
12077
+ }, [source, parseFormatHint, parseInclude3dModels, parseMaxInputBytes, parseFetchInitKey]);
11881
12078
  useEffect(() => {
11882
12079
  const viewport = viewportRef.current;
11883
12080
  if (viewport) onViewportReady?.(viewport);
@@ -12226,7 +12423,7 @@ function usePptxPresentation(source, options = EMPTY_PARSE_OPTIONS) {
12226
12423
  }
12227
12424
  });
12228
12425
  return () => abort.abort();
12229
- }, [source, options.fetchInit, options.formatHint, options.maxInputBytes]);
12426
+ }, [source, options.fetchInit, options.formatHint, options.maxInputBytes, options.include3dModels]);
12230
12427
  return state;
12231
12428
  }
12232
12429
  var usePptxModel = usePptxPresentation;