pptx-react-viewer 2.16.3 → 2.16.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/{AiChatPanel-RGIINA3S.mjs → AiChatPanel-6B26AZGA.mjs} +3 -3
  3. package/dist/AiChatPanel-6B26AZGA.mjs.br +0 -0
  4. package/dist/AiChatPanel-6B26AZGA.mjs.gz +0 -0
  5. package/dist/{AiChatPanel-2WWE5U3X.js → AiChatPanel-FGEIZQCD.js} +22 -22
  6. package/dist/AiChatPanel-FGEIZQCD.js.br +0 -0
  7. package/dist/AiChatPanel-FGEIZQCD.js.gz +0 -0
  8. package/dist/{Model3DScene-D2ZJ5XGR.js → Model3DScene-2JX5CUPK.js} +2 -2
  9. package/dist/Model3DScene-2JX5CUPK.js.br +0 -0
  10. package/dist/Model3DScene-2JX5CUPK.js.gz +0 -0
  11. package/dist/{Model3DScene-2ZP3V2P2.mjs → Model3DScene-NKYNKUPP.mjs} +1 -1
  12. package/dist/Model3DScene-NKYNKUPP.mjs.br +0 -0
  13. package/dist/Model3DScene-NKYNKUPP.mjs.gz +0 -0
  14. package/dist/{SurfaceChart3DScene-DWQ3IP5C.js → SurfaceChart3DScene-AE5SKG7U.js} +2 -2
  15. package/dist/SurfaceChart3DScene-AE5SKG7U.js.br +0 -0
  16. package/dist/SurfaceChart3DScene-AE5SKG7U.js.gz +0 -0
  17. package/dist/{SurfaceChart3DScene-L7YPNZ7X.mjs → SurfaceChart3DScene-TTL2FTEG.mjs} +1 -1
  18. package/dist/SurfaceChart3DScene-TTL2FTEG.mjs.br +0 -0
  19. package/dist/SurfaceChart3DScene-TTL2FTEG.mjs.gz +0 -0
  20. package/dist/{chunk-KMT3SLZC.mjs → chunk-247XH4EN.mjs} +329 -121
  21. package/dist/chunk-247XH4EN.mjs.br +0 -0
  22. package/dist/chunk-247XH4EN.mjs.gz +0 -0
  23. package/dist/{chunk-EBLFH3R2.mjs → chunk-5YGTUHNO.mjs} +2 -2
  24. package/dist/chunk-5YGTUHNO.mjs.br +0 -0
  25. package/dist/chunk-5YGTUHNO.mjs.gz +0 -0
  26. package/dist/{chunk-2UVKMKRP.js → chunk-6QGTRYSC.js} +329 -121
  27. package/dist/chunk-6QGTRYSC.js.br +0 -0
  28. package/dist/chunk-6QGTRYSC.js.gz +0 -0
  29. package/dist/{chunk-FVWVEWUG.mjs → chunk-EFZ4K6V5.mjs} +7 -7
  30. package/dist/chunk-EFZ4K6V5.mjs.br +0 -0
  31. package/dist/chunk-EFZ4K6V5.mjs.gz +0 -0
  32. package/dist/{chunk-ZYBVQXLR.js → chunk-LCWZ4TD4.js} +1054 -1054
  33. package/dist/chunk-LCWZ4TD4.js.br +0 -0
  34. package/dist/chunk-LCWZ4TD4.js.gz +0 -0
  35. package/dist/{chunk-JHDAOYRQ.mjs → chunk-MZN2UIYT.mjs} +1 -1
  36. package/dist/chunk-MZN2UIYT.mjs.br +0 -0
  37. package/dist/chunk-MZN2UIYT.mjs.gz +0 -0
  38. package/dist/{chunk-KTWK3D6O.js → chunk-P65VL2I6.js} +255 -255
  39. package/dist/chunk-P65VL2I6.js.br +0 -0
  40. package/dist/chunk-P65VL2I6.js.gz +0 -0
  41. package/dist/{chunk-U7SASWG4.js → chunk-UNWU6D2M.js} +340 -340
  42. package/dist/chunk-UNWU6D2M.js.br +0 -0
  43. package/dist/chunk-UNWU6D2M.js.gz +0 -0
  44. package/dist/{chunk-LBP6BUD4.js → chunk-VZI35LEF.js} +3 -3
  45. package/dist/chunk-VZI35LEF.js.br +0 -0
  46. package/dist/chunk-VZI35LEF.js.gz +0 -0
  47. package/dist/{chunk-OZ3HGL6E.mjs → chunk-Y6W5LGTR.mjs} +2 -2
  48. package/dist/chunk-Y6W5LGTR.mjs.br +0 -0
  49. package/dist/chunk-Y6W5LGTR.mjs.gz +0 -0
  50. package/dist/index.d.ts +17 -0
  51. package/dist/index.js +39 -39
  52. package/dist/index.js.br +0 -0
  53. package/dist/index.js.gz +0 -0
  54. package/dist/index.mjs +5 -5
  55. package/dist/index.mjs.br +0 -0
  56. package/dist/index.mjs.gz +0 -0
  57. package/dist/internals.d.ts +27 -4
  58. package/dist/internals.js +78 -78
  59. package/dist/internals.js.br +0 -0
  60. package/dist/internals.js.gz +0 -0
  61. package/dist/internals.mjs +3 -3
  62. package/dist/internals.mjs.br +0 -0
  63. package/dist/internals.mjs.gz +0 -0
  64. package/dist/viewer/index.d.ts +17 -0
  65. package/dist/viewer/index.js +26 -26
  66. package/dist/viewer/index.js.br +0 -0
  67. package/dist/viewer/index.js.gz +0 -0
  68. package/dist/viewer/index.mjs +5 -5
  69. package/dist/viewer/index.mjs.br +0 -0
  70. package/dist/viewer/index.mjs.gz +0 -0
  71. package/package.json +2 -2
  72. package/dist/AiChatPanel-2WWE5U3X.js.br +0 -0
  73. package/dist/AiChatPanel-2WWE5U3X.js.gz +0 -0
  74. package/dist/AiChatPanel-RGIINA3S.mjs.br +0 -0
  75. package/dist/AiChatPanel-RGIINA3S.mjs.gz +0 -0
  76. package/dist/Model3DScene-2ZP3V2P2.mjs.br +0 -0
  77. package/dist/Model3DScene-2ZP3V2P2.mjs.gz +0 -0
  78. package/dist/Model3DScene-D2ZJ5XGR.js.br +0 -0
  79. package/dist/Model3DScene-D2ZJ5XGR.js.gz +0 -0
  80. package/dist/SurfaceChart3DScene-DWQ3IP5C.js.br +0 -0
  81. package/dist/SurfaceChart3DScene-DWQ3IP5C.js.gz +0 -0
  82. package/dist/SurfaceChart3DScene-L7YPNZ7X.mjs.br +0 -0
  83. package/dist/SurfaceChart3DScene-L7YPNZ7X.mjs.gz +0 -0
  84. package/dist/chunk-2UVKMKRP.js.br +0 -0
  85. package/dist/chunk-2UVKMKRP.js.gz +0 -0
  86. package/dist/chunk-EBLFH3R2.mjs.br +0 -0
  87. package/dist/chunk-EBLFH3R2.mjs.gz +0 -0
  88. package/dist/chunk-FVWVEWUG.mjs.br +0 -0
  89. package/dist/chunk-FVWVEWUG.mjs.gz +0 -0
  90. package/dist/chunk-JHDAOYRQ.mjs.br +0 -0
  91. package/dist/chunk-JHDAOYRQ.mjs.gz +0 -0
  92. package/dist/chunk-KMT3SLZC.mjs.br +0 -0
  93. package/dist/chunk-KMT3SLZC.mjs.gz +0 -0
  94. package/dist/chunk-KTWK3D6O.js.br +0 -0
  95. package/dist/chunk-KTWK3D6O.js.gz +0 -0
  96. package/dist/chunk-LBP6BUD4.js.br +0 -0
  97. package/dist/chunk-LBP6BUD4.js.gz +0 -0
  98. package/dist/chunk-OZ3HGL6E.mjs.br +0 -0
  99. package/dist/chunk-OZ3HGL6E.mjs.gz +0 -0
  100. package/dist/chunk-U7SASWG4.js.br +0 -0
  101. package/dist/chunk-U7SASWG4.js.gz +0 -0
  102. package/dist/chunk-ZYBVQXLR.js.br +0 -0
  103. package/dist/chunk-ZYBVQXLR.js.gz +0 -0
@@ -11403,12 +11403,21 @@ function hexToRgbChannels(color2) {
11403
11403
  b: Number.parseInt(normalized.slice(4, 6), 16)
11404
11404
  };
11405
11405
  }
11406
- function parseDrawingPercent(value) {
11407
- const parsed = Number.parseFloat(String(value ?? "").trim());
11408
- if (!Number.isFinite(parsed)) {
11406
+ function percentDivisorFor(text2) {
11407
+ return text2.endsWith("%") ? 100 : 1e5;
11408
+ }
11409
+ function parseOoxmlPercent(value) {
11410
+ const text2 = String(value ?? "").trim();
11411
+ const divisor = percentDivisorFor(text2);
11412
+ const magnitude = Number.parseFloat(divisor === 100 ? text2.slice(0, -1) : text2);
11413
+ if (!Number.isFinite(magnitude)) {
11409
11414
  return void 0;
11410
11415
  }
11411
- return clampUnitInterval(parsed / 1e5);
11416
+ return magnitude / divisor;
11417
+ }
11418
+ function parseDrawingPercent(value) {
11419
+ const parsed = parseOoxmlPercent(value);
11420
+ return parsed === void 0 ? void 0 : clampUnitInterval(parsed);
11412
11421
  }
11413
11422
  function scrgbLinearToSrgb8(linear) {
11414
11423
  const l = Math.min(1, Math.max(0, linear));
@@ -11487,11 +11496,7 @@ function hslToRgb(h, s, l) {
11487
11496
  };
11488
11497
  }
11489
11498
  function parseDrawingFraction(value) {
11490
- const parsed = Number.parseFloat(String(value ?? "").trim());
11491
- if (!Number.isFinite(parsed)) {
11492
- return void 0;
11493
- }
11494
- return parsed / 1e5;
11499
+ return parseOoxmlPercent(value);
11495
11500
  }
11496
11501
  function parseDrawingHueDegrees(value) {
11497
11502
  const parsed = Number.parseFloat(String(value ?? "").trim());
@@ -19329,6 +19334,25 @@ var PptxXmlLookupService = class {
19329
19334
  }
19330
19335
  return void 0;
19331
19336
  }
19337
+ /**
19338
+ * Report whether `parent` declares a child with this local name, regardless
19339
+ * of what the child parsed to.
19340
+ *
19341
+ * Valueless elements such as `a:noFill` or `a:buNone` carry their whole
19342
+ * meaning in being present, and the parser represents them as an empty
19343
+ * string rather than an object, so the child accessors above return
19344
+ * `undefined` for them. Presence has to be asked for directly.
19345
+ */
19346
+ hasChildByLocalName(parent, localName22) {
19347
+ if (!parent) {
19348
+ return false;
19349
+ }
19350
+ if (Object.hasOwn(parent, localName22)) {
19351
+ return true;
19352
+ }
19353
+ const suffix = `:${localName22}`;
19354
+ return Object.keys(parent).some((key) => key.endsWith(suffix));
19355
+ }
19332
19356
  toXmlArray(value) {
19333
19357
  if (Array.isArray(value)) {
19334
19358
  return value.filter((entry2) => this.isXmlObject(entry2));
@@ -37723,16 +37747,20 @@ function parseParagraphSpacingPx(spacingNode) {
37723
37747
  }
37724
37748
  return void 0;
37725
37749
  }
37750
+ function parseBulletSizePercent(buSzPct) {
37751
+ const fraction = parseOoxmlPercent(buSzPct?.["@_val"]);
37752
+ return fraction === void 0 ? void 0 : fraction * 100;
37753
+ }
37726
37754
  function parseLineSpacingMultiplier(lineSpacingNode) {
37727
37755
  if (!lineSpacingNode) {
37728
37756
  return void 0;
37729
37757
  }
37730
37758
  const spcPct = lineSpacingNode["a:spcPct"];
37731
- const raw = Number.parseInt(String(spcPct?.["@_val"] || ""), 10);
37732
- if (Number.isFinite(raw)) {
37733
- return Math.max(0.1, Math.min(5, raw / 1e5));
37759
+ const multiplier = parseOoxmlPercent(spcPct?.["@_val"]);
37760
+ if (multiplier === void 0) {
37761
+ return void 0;
37734
37762
  }
37735
- return void 0;
37763
+ return Math.max(0.1, Math.min(5, multiplier));
37736
37764
  }
37737
37765
  function parseLineSpacingExactPt(lineSpacingNode) {
37738
37766
  if (!lineSpacingNode) {
@@ -37845,14 +37873,7 @@ function parseBulletInfo(pPr, paragraphIndex = 0) {
37845
37873
  }
37846
37874
  const buFont = pPr["a:buFont"];
37847
37875
  const fontFamily = buFont?.["@_typeface"] ? String(buFont["@_typeface"]) : void 0;
37848
- const buSzPct = pPr["a:buSzPct"];
37849
- let sizePercent;
37850
- if (buSzPct?.["@_val"] !== void 0) {
37851
- const pctRaw = Number.parseInt(String(buSzPct["@_val"]), 10);
37852
- if (Number.isFinite(pctRaw)) {
37853
- sizePercent = pctRaw / 1e3;
37854
- }
37855
- }
37876
+ const sizePercent = parseBulletSizePercent(pPr["a:buSzPct"]);
37856
37877
  const buSzPts = pPr["a:buSzPts"];
37857
37878
  let sizePts;
37858
37879
  if (buSzPts?.["@_val"] !== void 0) {
@@ -42085,7 +42106,15 @@ function getLinkedTextBoxSegments(element, allElements) {
42085
42106
  return segmentMap.get(element.id);
42086
42107
  }
42087
42108
  var FONT_SUBSTITUTION_MAP = {
42088
- // Microsoft Office default fonts
42109
+ // Microsoft Office default fonts. The Aptos family became the Office
42110
+ // default and its metrics were drawn to sit close to Calibri, so falling
42111
+ // back through Calibri keeps authored line counts; the generic sans-serif
42112
+ // chain is wider and re-wraps one-line titles.
42113
+ Aptos: ["Calibri", "Carlito", "Liberation Sans", "Arial", "sans-serif"],
42114
+ "Aptos Display": ["Calibri Light", "Calibri", "Carlito", "Arial", "sans-serif"],
42115
+ "Aptos Narrow": ["Calibri", "Liberation Sans Narrow", "Arial", "sans-serif"],
42116
+ "Aptos Serif": ["Cambria", "Caladea", "Liberation Serif", "Times New Roman", "serif"],
42117
+ "Aptos Mono": ["Consolas", "Liberation Mono", "Courier New", "monospace"],
42089
42118
  Calibri: ["Carlito", "Liberation Sans", "Arial", "sans-serif"],
42090
42119
  "Calibri Light": ["Carlito", "Liberation Sans", "Arial", "sans-serif"],
42091
42120
  Cambria: ["Caladea", "Liberation Serif", "Times New Roman", "serif"],
@@ -43852,6 +43881,15 @@ function buildModernAuthorPart(authors, rawRoot) {
43852
43881
  }
43853
43882
  };
43854
43883
  }
43884
+ function partRelsPath(partPath) {
43885
+ const lastSlash = partPath.lastIndexOf("/");
43886
+ if (lastSlash < 0) {
43887
+ return `_rels/${partPath}.rels`;
43888
+ }
43889
+ const directory = partPath.slice(0, lastSlash);
43890
+ const fileName = partPath.slice(lastSlash + 1);
43891
+ return `${directory}/_rels/${fileName}.rels`;
43892
+ }
43855
43893
  var unparsedNodesByRuntime = /* @__PURE__ */ new WeakMap();
43856
43894
  function rememberAuxiliaryMasterUnparsedNodes(runtime, partPath, nodesByTag) {
43857
43895
  let byPart = unparsedNodesByRuntime.get(runtime);
@@ -43864,6 +43902,26 @@ function rememberAuxiliaryMasterUnparsedNodes(runtime, partPath, nodesByTag) {
43864
43902
  function getAuxiliaryMasterUnparsedNodes(runtime, partPath) {
43865
43903
  return unparsedNodesByRuntime.get(runtime)?.get(partPath);
43866
43904
  }
43905
+ function createAutoNumberSequence() {
43906
+ return { levels: /* @__PURE__ */ new Map() };
43907
+ }
43908
+ function forgetFromLevel(sequence, level) {
43909
+ for (const recorded of sequence.levels.keys()) {
43910
+ if (recorded >= level) {
43911
+ sequence.levels.delete(recorded);
43912
+ }
43913
+ }
43914
+ }
43915
+ function breakAutoNumberRun(sequence, level) {
43916
+ forgetFromLevel(sequence, level);
43917
+ }
43918
+ function nextAutoNumber(sequence, level, scheme, startAt) {
43919
+ const running = sequence.levels.get(level);
43920
+ const ordinal = running && running.scheme === scheme ? running.ordinal + 1 : startAt;
43921
+ forgetFromLevel(sequence, level + 1);
43922
+ sequence.levels.set(level, { scheme, ordinal });
43923
+ return ordinal;
43924
+ }
43867
43925
  var CAMERA_PRESETS = /* @__PURE__ */ new Set([
43868
43926
  "legacyObliqueTopLeft",
43869
43927
  "legacyObliqueTop",
@@ -44148,6 +44206,18 @@ function applyTextBodyScene3d(bodyPr, style) {
44148
44206
  }
44149
44207
  bodyPr[existingKey ?? "a:scene3d"] = ordered(scene, ["camera", "lightRig", "backdrop", "extLst"]);
44150
44208
  }
44209
+ var TITLE_FAMILY = /* @__PURE__ */ new Set(["title", "ctrtitle"]);
44210
+ var BODY_FAMILY = /* @__PURE__ */ new Set(["body", "obj", "subtitle"]);
44211
+ function placeholderStyleFamily(type) {
44212
+ const declared = (type ?? "").trim().toLowerCase() || "body";
44213
+ if (TITLE_FAMILY.has(declared)) {
44214
+ return "title";
44215
+ }
44216
+ if (BODY_FAMILY.has(declared)) {
44217
+ return "body";
44218
+ }
44219
+ return declared;
44220
+ }
44151
44221
  var RELATIONSHIPS_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
44152
44222
  var ensureArray9 = (value) => value === void 0 ? [] : Array.isArray(value) ? value : [value];
44153
44223
  var resolvePartPath2 = (source, target) => {
@@ -48405,6 +48475,45 @@ var PptxHandlerRuntime = class {
48405
48475
  });
48406
48476
  }
48407
48477
  }
48478
+ /**
48479
+ * Read a package part's relationship file into {@link slideRelsMap} and
48480
+ * {@link externalRelsMap}, keyed by the part's own path.
48481
+ *
48482
+ * Lives at the root of the chain because relationships are needed by parts
48483
+ * loaded at very different times (slides, layouts, masters, notes) and by
48484
+ * mixins on both sides of the chain. A missing or empty `.rels` file is not
48485
+ * an error: plenty of parts have no relationships.
48486
+ *
48487
+ * @param partPath - The part whose relationships these are.
48488
+ * @param relsPath - Path of the `.rels` part; derived from `partPath` when omitted.
48489
+ */
48490
+ async loadPartRelationships(partPath, relsPath) {
48491
+ const relsXml = await this.zip.file(relsPath ?? partRelsPath(partPath))?.async("string");
48492
+ if (!relsXml) {
48493
+ return;
48494
+ }
48495
+ const relsData = this.parser.parse(relsXml);
48496
+ const relationships = relsData?.["Relationships"];
48497
+ const raw = relationships?.["Relationship"];
48498
+ const entries = Array.isArray(raw) ? raw : raw ? [raw] : [];
48499
+ const targets = /* @__PURE__ */ new Map();
48500
+ const externalIds = /* @__PURE__ */ new Set();
48501
+ for (const entry2 of entries) {
48502
+ const id = entry2["@_Id"];
48503
+ const target = entry2["@_Target"];
48504
+ if (!id || !target) {
48505
+ continue;
48506
+ }
48507
+ targets.set(String(id), String(target));
48508
+ if (String(entry2["@_TargetMode"] ?? "").toLowerCase() === "external") {
48509
+ externalIds.add(String(id));
48510
+ }
48511
+ }
48512
+ this.slideRelsMap.set(partPath, targets);
48513
+ if (externalIds.size > 0) {
48514
+ this.externalRelsMap.set(partPath, externalIds);
48515
+ }
48516
+ }
48408
48517
  /**
48409
48518
  * Restore the original (unwrapped) parser. Called during
48410
48519
  * `initializeLoadSession` to reset state for the next load.
@@ -50295,6 +50404,9 @@ var PptxHandlerRuntime9 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
50295
50404
  if (!this.layoutXmlMap.has(layoutPath)) {
50296
50405
  this.layoutXmlMap.set(layoutPath, data);
50297
50406
  }
50407
+ if (!this.slideRelsMap.has(layoutPath)) {
50408
+ await this.loadPartRelationships(layoutPath);
50409
+ }
50298
50410
  const layout = { path: layoutPath };
50299
50411
  const cSldName = (xmlAttr(xmlChild(sldLayout, "p:cSld"), "name") ?? "").trim();
50300
50412
  if (cSldName) {
@@ -50644,29 +50756,7 @@ var PptxHandlerRuntime11 = class extends PptxHandlerRuntime10 {
50644
50756
  return void 0;
50645
50757
  }
50646
50758
  async loadSlideRelationships(slidePath, relsPath) {
50647
- const relsXml = await this.zip.file(relsPath)?.async("string");
50648
- if (!relsXml) {
50649
- return;
50650
- }
50651
- const relsData = this.parser.parse(relsXml);
50652
- const relsMap = /* @__PURE__ */ new Map();
50653
- const externalIds = /* @__PURE__ */ new Set();
50654
- if (relsData?.Relationships?.Relationship) {
50655
- const rels = Array.isArray(relsData.Relationships.Relationship) ? relsData.Relationships.Relationship : [relsData.Relationships.Relationship];
50656
- rels.forEach((r) => {
50657
- if (r["@_Id"] && r["@_Target"]) {
50658
- const relId = String(r["@_Id"]);
50659
- relsMap.set(relId, String(r["@_Target"]));
50660
- if (String(r["@_TargetMode"] || "").toLowerCase() === "external") {
50661
- externalIds.add(relId);
50662
- }
50663
- }
50664
- });
50665
- }
50666
- this.slideRelsMap.set(slidePath, relsMap);
50667
- if (externalIds.size > 0) {
50668
- this.externalRelsMap.set(slidePath, externalIds);
50669
- }
50759
+ await this.loadPartRelationships(slidePath, relsPath);
50670
50760
  }
50671
50761
  async reconcilePresentationSlidesForSave(params) {
50672
50762
  return await this.presentationSlidesReconciler.reconcile({
@@ -53246,14 +53336,13 @@ var PptxHandlerRuntime21 = class extends PptxHandlerRuntime20 {
53246
53336
  // ── Placeholder matching key ────────────────────────────────────────
53247
53337
  /**
53248
53338
  * Build a matching key for a placeholder. Placeholders match primarily
53249
- * by type. When both have an idx, the idx must also match.
53339
+ * by the style family they belong to (so a `ctrTitle` slide placeholder can
53340
+ * take the target layout's `title` slot, and `obj` can take `body`'s). When
53341
+ * both carry an idx, the idx must also match.
53250
53342
  */
53251
53343
  buildPlaceholderMatchKey(phInfo) {
53252
- const type = phInfo.type || "body";
53253
- if (phInfo.idx !== void 0) {
53254
- return `${type}:${phInfo.idx}`;
53255
- }
53256
- return type;
53344
+ const family = placeholderStyleFamily(phInfo.type);
53345
+ return phInfo.idx !== void 0 ? `${family}:${phInfo.idx}` : family;
53257
53346
  }
53258
53347
  // ── Core layout switching logic ─────────────────────────────────────
53259
53348
  /**
@@ -53285,9 +53374,10 @@ var PptxHandlerRuntime21 = class extends PptxHandlerRuntime20 {
53285
53374
  const matchKey = this.buildPlaceholderMatchKey(phInfo);
53286
53375
  const layoutPh = layoutPhMap.get(matchKey);
53287
53376
  let resolvedLayoutPh = layoutPh;
53288
- if (!resolvedLayoutPh && phInfo.type) {
53377
+ if (!resolvedLayoutPh) {
53378
+ const family = placeholderStyleFamily(phInfo.type);
53289
53379
  for (const [, lp] of layoutPhMap.entries()) {
53290
- if (!lp.matched && lp.phInfo.type === phInfo.type) {
53380
+ if (!lp.matched && placeholderStyleFamily(lp.phInfo.type) === family) {
53291
53381
  resolvedLayoutPh = lp;
53292
53382
  break;
53293
53383
  }
@@ -62558,15 +62648,16 @@ var PptxHandlerRuntime56 = class extends PptxHandlerRuntime55 {
62558
62648
  };
62559
62649
  }
62560
62650
  /**
62561
- * Build a cache-map key for a placeholder. Prefers `idx` when present,
62562
- * otherwise falls back to `type`.
62651
+ * Build a cache-map key for a placeholder, combining the style family it
62652
+ * inherits from with `idx` when the reference carries one.
62653
+ *
62654
+ * Keying on the family rather than the raw attribute is what lets a slide's
62655
+ * `<p:ph idx="14"/>` find the layout's `type="obj" idx="14"` entry instead of
62656
+ * falling through to the master and losing the layout's own values.
62563
62657
  */
62564
62658
  buildPlaceholderDefaultsKey(phInfo) {
62565
- const normalizedType = phInfo.type === "ctrtitle" ? "title" : phInfo.type === "subtitle" ? "body" : phInfo.type;
62566
- if (phInfo.idx !== void 0) {
62567
- return normalizedType ? `${normalizedType}_${phInfo.idx}` : `_${phInfo.idx}`;
62568
- }
62569
- return normalizedType ?? "body";
62659
+ const family = placeholderStyleFamily(phInfo.type);
62660
+ return phInfo.idx !== void 0 ? `${family}_${phInfo.idx}` : family;
62570
62661
  }
62571
62662
  /**
62572
62663
  * Look up merged {@link PlaceholderDefaults} for a shape's placeholder
@@ -62584,8 +62675,8 @@ var PptxHandlerRuntime56 = class extends PptxHandlerRuntime55 {
62584
62675
  const masterPath = this.resolveMasterPathForLayout(layoutPath);
62585
62676
  const masterMap = masterPath ? this.masterPlaceholderDefaultsCache.get(masterPath) : void 0;
62586
62677
  const masterDefaults = masterMap?.get(phKey);
62587
- const normalizedType = this.buildPlaceholderDefaultsKey(phInfo).split("_")[0];
62588
- const masterTextStyleType = phInfo.type === "title" || phInfo.type === "ctrtitle" ? "title" : phInfo.type === "body" || phInfo.type === "obj" || phInfo.type === "subtitle" ? "body" : "other";
62678
+ const normalizedType = placeholderStyleFamily(phInfo.type);
62679
+ const masterTextStyleType = normalizedType === "title" ? "title" : normalizedType === "body" ? "body" : "other";
62589
62680
  const masterTextStyles = masterPath ? this.masterTxStylesCache.get(masterPath) : void 0;
62590
62681
  const masterTextLevels = masterTextStyleType === "title" ? masterTextStyles?.titleStyle : masterTextStyleType === "body" ? masterTextStyles?.bodyStyle : masterTextStyles?.otherStyle;
62591
62682
  const resolvedMasterDefaults = masterTextLevels ? {
@@ -63319,12 +63410,11 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
63319
63410
  if (Number.isFinite(spacingPointsRaw)) {
63320
63411
  return this.pointsToPixels(spacingPointsRaw / 100);
63321
63412
  }
63322
- const spacingPercentRaw = Number.parseInt(
63323
- String(spacingNode["a:spcPct"]?.["@_val"] || ""),
63324
- 10
63413
+ const spacingFraction = parseOoxmlPercent(
63414
+ spacingNode["a:spcPct"]?.["@_val"]
63325
63415
  );
63326
- if (Number.isFinite(spacingPercentRaw) && typeof basisFontSizePx === "number" && basisFontSizePx > 0) {
63327
- return spacingPercentRaw / 1e5 * basisFontSizePx;
63416
+ if (spacingFraction !== void 0 && typeof basisFontSizePx === "number" && basisFontSizePx > 0) {
63417
+ return spacingFraction * basisFontSizePx;
63328
63418
  }
63329
63419
  return void 0;
63330
63420
  }
@@ -63332,12 +63422,11 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
63332
63422
  if (!lineSpacingNode) {
63333
63423
  return void 0;
63334
63424
  }
63335
- const spacingPercentRaw = Number.parseInt(
63336
- String(lineSpacingNode["a:spcPct"]?.["@_val"] || ""),
63337
- 10
63425
+ const spacingFraction = parseOoxmlPercent(
63426
+ lineSpacingNode["a:spcPct"]?.["@_val"]
63338
63427
  );
63339
- if (Number.isFinite(spacingPercentRaw)) {
63340
- return Math.max(0.1, Math.min(5, spacingPercentRaw / 1e5));
63428
+ if (spacingFraction !== void 0) {
63429
+ return Math.max(0.1, Math.min(5, spacingFraction));
63341
63430
  }
63342
63431
  return void 0;
63343
63432
  }
@@ -63358,6 +63447,27 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
63358
63447
  }
63359
63448
  return void 0;
63360
63449
  }
63450
+ /**
63451
+ * Resolve an inherited level colour against the colour map that is active
63452
+ * now, rather than the one that was active when the level was cached.
63453
+ *
63454
+ * Layout and master text styles are cached once per part; slides are parsed
63455
+ * afterwards, each with its own `p:clrMapOvr`. Re-reading the authored
63456
+ * choice is what makes `tx1` come out white on a slide that maps it to the
63457
+ * light slot and black on one that does not.
63458
+ *
63459
+ * @param levelStyle - The inherited level style.
63460
+ * @returns The colour to inherit, or `undefined` when the level sets none.
63461
+ */
63462
+ resolveLevelStyleColor(levelStyle) {
63463
+ if (levelStyle.colorChoiceXml) {
63464
+ const remapped = this.parseColor(levelStyle.colorChoiceXml);
63465
+ if (remapped) {
63466
+ return remapped;
63467
+ }
63468
+ }
63469
+ return levelStyle.color;
63470
+ }
63361
63471
  /**
63362
63472
  * Apply level-specific {@link PlaceholderTextLevelStyle} properties to a
63363
63473
  * {@link TextStyle} as fallback values for paragraph-level fields.
@@ -63375,8 +63485,11 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
63375
63485
  if (textStyle.italic === void 0 && levelStyle.italic !== void 0) {
63376
63486
  textStyle.italic = levelStyle.italic;
63377
63487
  }
63378
- if (textStyle.color === void 0 && levelStyle.color !== void 0) {
63379
- textStyle.color = levelStyle.color;
63488
+ if (textStyle.color === void 0) {
63489
+ const inheritedColor = this.resolveLevelStyleColor(levelStyle);
63490
+ if (inheritedColor !== void 0) {
63491
+ textStyle.color = inheritedColor;
63492
+ }
63380
63493
  }
63381
63494
  if (textStyle.paragraphMarginLeft === void 0 && levelStyle.marginLeft !== void 0) {
63382
63495
  textStyle.paragraphMarginLeft = levelStyle.marginLeft;
@@ -63445,14 +63558,9 @@ var PptxHandlerRuntime60 = class extends PptxHandlerRuntime59 {
63445
63558
  const buFont = resolvedBulletProps["a:buFont"];
63446
63559
  const fontFamily = buFont?.["@_typeface"] ? String(buFont["@_typeface"]) : void 0;
63447
63560
  const fontInherit = resolvedBulletProps["a:buFontTx"] !== void 0;
63448
- const buSzPct = resolvedBulletProps["a:buSzPct"];
63449
- let sizePercent;
63450
- if (buSzPct?.["@_val"] !== void 0) {
63451
- const pctRaw = Number.parseInt(String(buSzPct["@_val"]), 10);
63452
- if (Number.isFinite(pctRaw)) {
63453
- sizePercent = pctRaw / 1e3;
63454
- }
63455
- }
63561
+ const sizePercent = parseBulletSizePercent(
63562
+ resolvedBulletProps["a:buSzPct"]
63563
+ );
63456
63564
  const buSzPts = resolvedBulletProps["a:buSzPts"];
63457
63565
  let sizePts;
63458
63566
  if (buSzPts?.["@_val"] !== void 0) {
@@ -64229,13 +64337,25 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
64229
64337
  ctx.slidePath,
64230
64338
  ctx.effectiveLevelStyles
64231
64339
  );
64340
+ const paragraphLevel = parseParagraphLevel(p["a:pPr"]);
64341
+ const autoNumScheme = paragraphBulletInfo && !paragraphBulletInfo.none && !paragraphBulletInfo.char ? paragraphBulletInfo.autoNumType : void 0;
64342
+ let autoNumOrdinal;
64343
+ if (autoNumScheme) {
64344
+ autoNumOrdinal = nextAutoNumber(
64345
+ ctx.autoNumbering,
64346
+ paragraphLevel,
64347
+ autoNumScheme,
64348
+ paragraphBulletInfo?.autoNumStartAt ?? 1
64349
+ );
64350
+ } else {
64351
+ breakAutoNumberRun(ctx.autoNumbering, paragraphLevel);
64352
+ }
64232
64353
  if (paragraphBulletInfo && !paragraphBulletInfo.none) {
64233
64354
  let bulletText;
64234
64355
  if (paragraphBulletInfo.char) {
64235
64356
  bulletText = `${paragraphBulletInfo.char} `;
64236
- } else if (paragraphBulletInfo.autoNumType) {
64237
- const startAt = paragraphBulletInfo.autoNumStartAt ?? 1;
64238
- bulletText = this.formatAutoNumber(paragraphBulletInfo.autoNumType, startAt + pIdx);
64357
+ } else if (autoNumScheme && autoNumOrdinal !== void 0) {
64358
+ bulletText = this.formatAutoNumber(autoNumScheme, autoNumOrdinal);
64239
64359
  } else if (paragraphBulletInfo.imageRelId) {
64240
64360
  bulletText = "\u{1F4CE} ";
64241
64361
  } else {
@@ -64743,7 +64863,8 @@ var PptxHandlerRuntime64 = class _PptxHandlerRuntime27 extends PptxHandlerRuntim
64743
64863
  slidePath,
64744
64864
  effectiveLevelStyles,
64745
64865
  styleFontRefColor,
64746
- styleFontRefTypeface
64866
+ styleFontRefTypeface,
64867
+ autoNumbering: createAutoNumberSequence()
64747
64868
  };
64748
64869
  paras.forEach((p, pIdx) => {
64749
64870
  const styleResult = this.resolveShapeParagraphStyle(p, textStyle, ctx);
@@ -66231,7 +66352,7 @@ var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
66231
66352
  try {
66232
66353
  const masterXmlObj = await this.resolveCachedMasterXml(masterPath);
66233
66354
  if (masterXmlObj) {
66234
- const masterRelsPath = `${masterPath.replace("slideMasters/", "slideMasters/_rels/")}.rels`;
66355
+ const masterRelsPath = partRelsPath(masterPath);
66235
66356
  await this.loadSlideRelationships(masterPath, masterRelsPath);
66236
66357
  return this.extractBackgroundImage(masterXmlObj, masterPath, "p:sldMaster");
66237
66358
  }
@@ -66254,7 +66375,7 @@ var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
66254
66375
  try {
66255
66376
  const layoutXmlObj = await this.resolveCachedLayoutXml(layoutPath);
66256
66377
  if (layoutXmlObj) {
66257
- const layoutRelsPath = `${layoutPath.replace("slideLayouts/", "slideLayouts/_rels/")}.rels`;
66378
+ const layoutRelsPath = partRelsPath(layoutPath);
66258
66379
  await this.loadSlideRelationships(layoutPath, layoutRelsPath);
66259
66380
  const bg = this.extractBackgroundImage(layoutXmlObj, layoutPath, "p:sldLayout");
66260
66381
  if (bg) {
@@ -66424,7 +66545,7 @@ var PptxHandlerRuntime71 = class extends PptxHandlerRuntime70 {
66424
66545
  return;
66425
66546
  }
66426
66547
  if (!this.slideRelsMap.has(layoutPath)) {
66427
- const layoutRelsPath = `${layoutPath.replace("slideLayouts/", "slideLayouts/_rels/")}.rels`;
66548
+ const layoutRelsPath = partRelsPath(layoutPath);
66428
66549
  try {
66429
66550
  await this.loadSlideRelationships(layoutPath, layoutRelsPath);
66430
66551
  } catch {
@@ -66708,12 +66829,11 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime31 extends PptxHandlerRuntim
66708
66829
  if (buFont?.["@_typeface"]) {
66709
66830
  style.bulletFontFamily = String(buFont["@_typeface"]);
66710
66831
  }
66711
- const buSzPct = levelProps["a:buSzPct"];
66712
- if (buSzPct?.["@_val"] !== void 0) {
66713
- const pctRaw = Number.parseInt(String(buSzPct["@_val"]), 10);
66714
- if (Number.isFinite(pctRaw)) {
66715
- style.bulletSizePercent = pctRaw / 1e3;
66716
- }
66832
+ const bulletSizePercent = parseBulletSizePercent(
66833
+ levelProps["a:buSzPct"]
66834
+ );
66835
+ if (bulletSizePercent !== void 0) {
66836
+ style.bulletSizePercent = bulletSizePercent;
66717
66837
  }
66718
66838
  const buClr = levelProps["a:buClr"];
66719
66839
  if (buClr) {
@@ -66746,10 +66866,14 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime31 extends PptxHandlerRuntim
66746
66866
  if (defRPr["@_i"] !== void 0) {
66747
66867
  style.italic = defRPr["@_i"] === "1";
66748
66868
  }
66749
- const color2 = this.parseColor(defRPr["a:solidFill"]);
66869
+ const solidFill3 = defRPr["a:solidFill"];
66870
+ const color2 = this.parseColor(solidFill3);
66750
66871
  if (color2) {
66751
66872
  style.color = color2;
66752
66873
  }
66874
+ if (solidFill3) {
66875
+ style.colorChoiceXml = solidFill3;
66876
+ }
66753
66877
  const latin = defRPr["a:latin"];
66754
66878
  if (latin?.["@_typeface"]) {
66755
66879
  const typeface = String(latin["@_typeface"]);
@@ -67068,7 +67192,7 @@ var PptxHandlerRuntime74 = class extends PptxHandlerRuntime73 {
67068
67192
  }
67069
67193
  const masterXmlObj = this.parser.parse(masterXmlStr);
67070
67194
  this.masterXmlMap.set(masterPath, masterXmlObj);
67071
- const masterRelsPath = `${masterPath.replace("slideMasters/", "slideMasters/_rels/")}.rels`;
67195
+ const masterRelsPath = partRelsPath(masterPath);
67072
67196
  await this.loadSlideRelationships(masterPath, masterRelsPath);
67073
67197
  const spTree = masterXmlObj["p:sldMaster"]?.["p:cSld"]?.["p:spTree"];
67074
67198
  if (!spTree) {
@@ -67286,7 +67410,7 @@ var PptxHandlerRuntime76 = class extends PptxHandlerRuntime75 {
67286
67410
  }
67287
67411
  const layoutXmlObj = this.parser.parse(layoutXmlStr);
67288
67412
  this.layoutXmlMap.set(layoutPath, layoutXmlObj);
67289
- const layoutRelsPath = `${layoutPath.replace("slideLayouts/", "slideLayouts/_rels/")}.rels`;
67413
+ const layoutRelsPath = partRelsPath(layoutPath);
67290
67414
  await this.loadSlideRelationships(layoutPath, layoutRelsPath);
67291
67415
  const layoutClrMapOverride = this.parseLayoutClrMapOverride(layoutXmlObj);
67292
67416
  const prevClrMapOverride = this.currentSlideClrMapOverride;
@@ -69204,6 +69328,15 @@ var PptxHandlerRuntime83 = class extends PptxHandlerRuntime82 {
69204
69328
  };
69205
69329
  function extractDrawingShapeFill(spPr, deps) {
69206
69330
  const result = {};
69331
+ if (deps.hasChild(spPr, "noFill")) {
69332
+ result.fillNone = true;
69333
+ const noFillShadowColor = deps.extractShadowColor(spPr);
69334
+ if (noFillShadowColor) {
69335
+ result.hasShadow = true;
69336
+ result.shadowColor = noFillShadowColor;
69337
+ }
69338
+ return result;
69339
+ }
69207
69340
  const solidFill3 = deps.getChild(spPr, "solidFill");
69208
69341
  if (solidFill3) {
69209
69342
  result.fillColor = deps.parseColor(solidFill3) ?? void 0;
@@ -69515,6 +69648,7 @@ var PptxHandlerRuntime84 = class _PptxHandlerRuntime35 extends PptxHandlerRuntim
69515
69648
  drawingShapeStyleDeps() {
69516
69649
  return {
69517
69650
  getChild: (node, local) => this.xmlLookupService.getChildByLocalName(node, local),
69651
+ hasChild: (node, local) => this.xmlLookupService.hasChildByLocalName(node, local),
69518
69652
  getChildren: (node, local) => this.xmlLookupService.getChildrenArrayByLocalName(node, local),
69519
69653
  parseColor: (node) => this.parseColor(node),
69520
69654
  extractGradientStops: (gradFill) => this.extractGradientStops(gradFill),
@@ -108027,19 +108161,21 @@ function childrenPair(a, b) {
108027
108161
  }
108028
108162
  return boxOverlapRatio(a, b) >= CHILD_OVERLAP_RATIO;
108029
108163
  }
108030
- function childrenCorrespond(a, b) {
108164
+ function correspondingChildren(a, b) {
108031
108165
  if (a.length !== b.length || a.length === 0) {
108032
- return false;
108166
+ return void 0;
108033
108167
  }
108034
108168
  const unclaimed = b.map((child22) => child22);
108169
+ const paired = [];
108035
108170
  for (const child22 of a) {
108036
108171
  const index = unclaimed.findIndex((candidate) => childrenPair(child22, candidate));
108037
108172
  if (index < 0) {
108038
- return false;
108173
+ return void 0;
108039
108174
  }
108175
+ paired.push([child22, unclaimed[index]]);
108040
108176
  unclaimed.splice(index, 1);
108041
108177
  }
108042
- return true;
108178
+ return paired;
108043
108179
  }
108044
108180
  function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
108045
108181
  const out = [];
@@ -108048,7 +108184,7 @@ function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
108048
108184
  if (children8 && containsMorphNamedDescendant(element)) {
108049
108185
  const twin = correspondingGroup(element, counterpart);
108050
108186
  const twinChildren = twin ? groupChildren(twin) ?? [] : void 0;
108051
- if (twinChildren && childrenCorrespond(children8, twinChildren)) {
108187
+ if (twinChildren && correspondingChildren(children8, twinChildren)) {
108052
108188
  out.push(
108053
108189
  ...flattenMorphElements(children8, twinChildren, offsetX + element.x, offsetY + element.y)
108054
108190
  );
@@ -108059,6 +108195,29 @@ function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
108059
108195
  }
108060
108196
  return out;
108061
108197
  }
108198
+ function morphGroupChildPairs(elements, counterpart) {
108199
+ const pairs2 = /* @__PURE__ */ new Map();
108200
+ collectGroupChildPairs(elements, counterpart, pairs2);
108201
+ return pairs2;
108202
+ }
108203
+ function collectGroupChildPairs(elements, counterpart, into) {
108204
+ for (const element of elements) {
108205
+ const children8 = groupChildren(element);
108206
+ if (!children8 || !containsMorphNamedDescendant(element)) {
108207
+ continue;
108208
+ }
108209
+ const twin = correspondingGroup(element, counterpart);
108210
+ const twinChildren = twin ? groupChildren(twin) ?? [] : void 0;
108211
+ const corresponded = twinChildren ? correspondingChildren(children8, twinChildren) : void 0;
108212
+ if (!corresponded) {
108213
+ continue;
108214
+ }
108215
+ for (const [child22, twinChild] of corresponded) {
108216
+ into.set(child22.id, twinChild.id);
108217
+ }
108218
+ collectGroupChildPairs(children8, twinChildren ?? [], into);
108219
+ }
108220
+ }
108062
108221
  var OUTLINE_SAMPLE_COUNT = 64;
108063
108222
  var ELLIPSE_SAMPLE_COUNT = 48;
108064
108223
  function resolveLength(token2, axis) {
@@ -108525,6 +108684,23 @@ function matchMorphElementsFull(fromSlide, toSlide) {
108525
108684
  }
108526
108685
  }
108527
108686
  }
108687
+ const groupChildPairs = morphGroupChildPairs(fromSlide.elements, toSlide.elements);
108688
+ if (groupChildPairs.size > 0) {
108689
+ const toById = new Map(toElements.map((el) => [el.id, el]));
108690
+ for (const fromEl of fromElements) {
108691
+ if (usedFrom.has(fromEl.id)) {
108692
+ continue;
108693
+ }
108694
+ const toId = groupChildPairs.get(fromEl.id);
108695
+ const toEl = toId === void 0 ? void 0 : toById.get(toId);
108696
+ if (!toEl || usedTo.has(toEl.id) || fromEl.type !== toEl.type) {
108697
+ continue;
108698
+ }
108699
+ pairs2.push({ fromElement: fromEl, toElement: toEl });
108700
+ usedFrom.add(fromEl.id);
108701
+ usedTo.add(toEl.id);
108702
+ }
108703
+ }
108528
108704
  for (const fromEl of fromElements) {
108529
108705
  if (usedFrom.has(fromEl.id) || !fromEl.shapeId) {
108530
108706
  continue;
@@ -108631,7 +108807,7 @@ function buildMorphMergedOrder(outgoing, incoming, pairs2) {
108631
108807
  flushOutgoingBelow(outgoing.length);
108632
108808
  return rank;
108633
108809
  }
108634
- function resolveMorphOverlayArrivals(outgoing, incoming, pairs2, holdingGhostIds) {
108810
+ function resolveMorphOverlayArrivals(outgoing, incoming, pairs2, holdingGhostIds, dissolvingInIds = /* @__PURE__ */ new Set()) {
108635
108811
  const rank = buildMorphMergedOrder(outgoing, incoming, pairs2);
108636
108812
  const matched = new Set(pairs2.map((pair) => pair.toElement.id));
108637
108813
  const counterpart = new Map(pairs2.map((pair) => [pair.fromElement.id, pair.toElement]));
@@ -108641,7 +108817,7 @@ function resolveMorphOverlayArrivals(outgoing, incoming, pairs2, holdingGhostIds
108641
108817
  }));
108642
108818
  const lifted = /* @__PURE__ */ new Set();
108643
108819
  for (const element of incoming) {
108644
- if (matched.has(element.id)) {
108820
+ if (matched.has(element.id) && !dissolvingInIds.has(element.id)) {
108645
108821
  continue;
108646
108822
  }
108647
108823
  const mine = rank.get(element.id) ?? 0;
@@ -108706,6 +108882,21 @@ function tokenizeText(element, mode) {
108706
108882
  }
108707
108883
  return tokens;
108708
108884
  }
108885
+ var SAME_SLOT_OVERLAP = 0.5;
108886
+ function ownText(element) {
108887
+ return (element.text ?? "").replace(/\s+/gu, " ").trim();
108888
+ }
108889
+ function morphTextReplacedInSlot(fromElement, toElement) {
108890
+ if (fromElement.type !== "text" || toElement.type !== "text") {
108891
+ return false;
108892
+ }
108893
+ const from = ownText(fromElement);
108894
+ const to = ownText(toElement);
108895
+ if (from === "" || to === "" || from === to) {
108896
+ return false;
108897
+ }
108898
+ return boxOverlapRatio(fromElement, toElement) >= SAME_SLOT_OVERLAP;
108899
+ }
108709
108900
  function diffTokens(fromTokens, toTokens) {
108710
108901
  const n = fromTokens.length;
108711
108902
  const m = toTokens.length;
@@ -108904,6 +109095,9 @@ function resolveMorphGhostIds(outgoingElements, pairs2) {
108904
109095
  }
108905
109096
  return painted;
108906
109097
  }
109098
+ function morphPairIncomingFadesIn(fromElement, toElement, ghosted = true) {
109099
+ return !(ghosted && isInertMorphPair(fromElement, toElement)) && morphPairNeedsCrossfade(fromElement, toElement) && crossfadeIncomingMayFadeIn(toElement);
109100
+ }
108907
109101
  function crossfadeIncomingMayFadeIn(element) {
108908
109102
  const image = element;
108909
109103
  if (image.imagePath || image.svgPath) {
@@ -108934,17 +109128,18 @@ function generateMorphAnimations(pairs2, durationMs, _mode = "object", ghostIds)
108934
109128
  continue;
108935
109129
  }
108936
109130
  const safeName = `pptx-morph-${index}-${toElement.id.replace(/[^a-zA-Z0-9]/gu, "")}`;
108937
- const dx = fromElement.x + fromElement.width / 2 - (toElement.x + toElement.width / 2);
108938
- const dy = fromElement.y + fromElement.height / 2 - (toElement.y + toElement.height / 2);
108939
- const sx = Math.max(fromElement.width, 1) / Math.max(toElement.width, 1);
108940
- const sy = Math.max(fromElement.height, 1) / Math.max(toElement.height, 1);
109131
+ const inSlot = morphTextReplacedInSlot(fromElement, toElement);
109132
+ const dx = inSlot ? 0 : fromElement.x + fromElement.width / 2 - (toElement.x + toElement.width / 2);
109133
+ const dy = inSlot ? 0 : fromElement.y + fromElement.height / 2 - (toElement.y + toElement.height / 2);
109134
+ const sx = inSlot ? 1 : Math.max(fromElement.width, 1) / Math.max(toElement.width, 1);
109135
+ const sy = inSlot ? 1 : Math.max(fromElement.height, 1) / Math.max(toElement.height, 1);
108941
109136
  const fromOpacity = fromElement.opacity ?? 1;
108942
109137
  const toOpacity = toElement.opacity ?? 1;
108943
109138
  const toRot = toElement.rotation ?? 0;
108944
- const fromRot = shortestRotationTarget(toRot, fromElement.rotation ?? 0);
109139
+ const fromRot = inSlot ? toRot : shortestRotationTarget(toRot, fromElement.rotation ?? 0);
108945
109140
  const flips = `${toElement.flipHorizontal ? " scaleX(-1)" : ""}${toElement.flipVertical ? " scaleY(-1)" : ""}`;
108946
109141
  const inert = ghosted && isInertMorphPair(fromElement, toElement);
108947
- const crossfadesIn = !inert && morphPairNeedsCrossfade(fromElement, toElement) && crossfadeIncomingMayFadeIn(toElement);
109142
+ const crossfadesIn = morphPairIncomingFadesIn(fromElement, toElement, ghosted);
108948
109143
  const fromProps = [
108949
109144
  ` transform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${fromRot}deg)${flips};`
108950
109145
  ];
@@ -108997,14 +109192,18 @@ function generateMorphGhostAnimations(pairs2, durationMs, startIndex, ghostIds)
108997
109192
  if (ghostIds && !ghostIds.has(fromElement.id)) {
108998
109193
  continue;
108999
109194
  }
109195
+ if (isInertMorphPair(fromElement, toElement)) {
109196
+ continue;
109197
+ }
109000
109198
  const fadesOut = morphPairNeedsCrossfade(fromElement, toElement);
109001
109199
  const safeName = `pptx-morph-ghost-${startIndex + index}-${fromElement.id.replace(/[^a-zA-Z0-9]/gu, "")}`;
109002
- const dx = toElement.x + toElement.width / 2 - (fromElement.x + fromElement.width / 2);
109003
- const dy = toElement.y + toElement.height / 2 - (fromElement.y + fromElement.height / 2);
109004
- const sx = Math.max(toElement.width, 1) / Math.max(fromElement.width, 1);
109005
- const sy = Math.max(toElement.height, 1) / Math.max(fromElement.height, 1);
109200
+ const inSlot = morphTextReplacedInSlot(fromElement, toElement);
109201
+ const dx = inSlot ? 0 : toElement.x + toElement.width / 2 - (fromElement.x + fromElement.width / 2);
109202
+ const dy = inSlot ? 0 : toElement.y + toElement.height / 2 - (fromElement.y + fromElement.height / 2);
109203
+ const sx = inSlot ? 1 : Math.max(toElement.width, 1) / Math.max(fromElement.width, 1);
109204
+ const sy = inSlot ? 1 : Math.max(toElement.height, 1) / Math.max(fromElement.height, 1);
109006
109205
  const fromRot = fromElement.rotation ?? 0;
109007
- const toRot = shortestRotationTarget(fromRot, toElement.rotation ?? 0);
109206
+ const toRot = inSlot ? fromRot : shortestRotationTarget(fromRot, toElement.rotation ?? 0);
109008
109207
  const flips = `${fromElement.flipHorizontal ? " scaleX(-1)" : ""}${fromElement.flipVertical ? " scaleY(-1)" : ""}`;
109009
109208
  const opacity2 = fromElement.opacity ?? 1;
109010
109209
  const keyframes = `
@@ -109202,6 +109401,7 @@ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = "object
109202
109401
  const animations = generateFullMorphTransition(fromSlide, toSlide, durationMs, mode);
109203
109402
  const flattenedOutgoing = flattenMorphElements(fromSlide.elements, toSlide.elements);
109204
109403
  const outgoingIds = new Set(flattenedOutgoing.map((element) => element.id));
109404
+ const ghostIds = resolveMorphGhostIds(flattenedOutgoing, match.pairs);
109205
109405
  const incomingAnimations = /* @__PURE__ */ new Map();
109206
109406
  const outgoingAnimations = /* @__PURE__ */ new Map();
109207
109407
  const incomingImageAnimations = /* @__PURE__ */ new Map();
@@ -109213,20 +109413,28 @@ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = "object
109213
109413
  const target = animation.target === "image" ? isOutgoing ? outgoingImageAnimations : incomingImageAnimations : isOutgoing ? outgoingAnimations : incomingAnimations;
109214
109414
  target.set(animation.elementId, animation.animation);
109215
109415
  }
109216
- const outgoingElements = flattenedOutgoing.filter(
109217
- (element) => outgoingAnimations.has(element.id)
109218
- );
109416
+ const outgoingElements = flattenedOutgoing.filter((element) => ghostIds.has(element.id));
109219
109417
  const flattenedIncoming = flattenMorphElements(toSlide.elements, fromSlide.elements);
109220
109418
  const holdingGhostIds = new Set(
109221
109419
  match.pairs.filter(
109222
- (candidate) => outgoingAnimations.has(candidate.fromElement.id) && !morphPairNeedsCrossfade(candidate.fromElement, candidate.toElement)
109420
+ (candidate) => ghostIds.has(candidate.fromElement.id) && !morphPairNeedsCrossfade(candidate.fromElement, candidate.toElement)
109223
109421
  ).map((candidate) => candidate.fromElement.id)
109224
109422
  );
109423
+ const dissolvingInIds = new Set(
109424
+ match.pairs.filter(
109425
+ (candidate) => morphPairIncomingFadesIn(
109426
+ candidate.fromElement,
109427
+ candidate.toElement,
109428
+ ghostIds.has(candidate.fromElement.id)
109429
+ )
109430
+ ).map((candidate) => candidate.toElement.id)
109431
+ );
109225
109432
  const lifted = resolveMorphOverlayArrivals(
109226
109433
  flattenedOutgoing,
109227
109434
  flattenedIncoming,
109228
109435
  match.pairs,
109229
- holdingGhostIds
109436
+ holdingGhostIds,
109437
+ dissolvingInIds
109230
109438
  );
109231
109439
  const overlayIncomingAnimations = /* @__PURE__ */ new Map();
109232
109440
  for (const id of lifted) {