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
@@ -11410,12 +11410,21 @@ function hexToRgbChannels(color2) {
11410
11410
  b: Number.parseInt(normalized.slice(4, 6), 16)
11411
11411
  };
11412
11412
  }
11413
- function parseDrawingPercent(value) {
11414
- const parsed = Number.parseFloat(String(value ?? "").trim());
11415
- if (!Number.isFinite(parsed)) {
11413
+ function percentDivisorFor(text2) {
11414
+ return text2.endsWith("%") ? 100 : 1e5;
11415
+ }
11416
+ function parseOoxmlPercent(value) {
11417
+ const text2 = String(value ?? "").trim();
11418
+ const divisor = percentDivisorFor(text2);
11419
+ const magnitude = Number.parseFloat(divisor === 100 ? text2.slice(0, -1) : text2);
11420
+ if (!Number.isFinite(magnitude)) {
11416
11421
  return void 0;
11417
11422
  }
11418
- return clampUnitInterval(parsed / 1e5);
11423
+ return magnitude / divisor;
11424
+ }
11425
+ function parseDrawingPercent(value) {
11426
+ const parsed = parseOoxmlPercent(value);
11427
+ return parsed === void 0 ? void 0 : clampUnitInterval(parsed);
11419
11428
  }
11420
11429
  function scrgbLinearToSrgb8(linear) {
11421
11430
  const l = Math.min(1, Math.max(0, linear));
@@ -11494,11 +11503,7 @@ function hslToRgb(h, s, l) {
11494
11503
  };
11495
11504
  }
11496
11505
  function parseDrawingFraction(value) {
11497
- const parsed = Number.parseFloat(String(value ?? "").trim());
11498
- if (!Number.isFinite(parsed)) {
11499
- return void 0;
11500
- }
11501
- return parsed / 1e5;
11506
+ return parseOoxmlPercent(value);
11502
11507
  }
11503
11508
  function parseDrawingHueDegrees(value) {
11504
11509
  const parsed = Number.parseFloat(String(value ?? "").trim());
@@ -19336,6 +19341,25 @@ var PptxXmlLookupService = class {
19336
19341
  }
19337
19342
  return void 0;
19338
19343
  }
19344
+ /**
19345
+ * Report whether `parent` declares a child with this local name, regardless
19346
+ * of what the child parsed to.
19347
+ *
19348
+ * Valueless elements such as `a:noFill` or `a:buNone` carry their whole
19349
+ * meaning in being present, and the parser represents them as an empty
19350
+ * string rather than an object, so the child accessors above return
19351
+ * `undefined` for them. Presence has to be asked for directly.
19352
+ */
19353
+ hasChildByLocalName(parent, localName22) {
19354
+ if (!parent) {
19355
+ return false;
19356
+ }
19357
+ if (Object.hasOwn(parent, localName22)) {
19358
+ return true;
19359
+ }
19360
+ const suffix = `:${localName22}`;
19361
+ return Object.keys(parent).some((key) => key.endsWith(suffix));
19362
+ }
19339
19363
  toXmlArray(value) {
19340
19364
  if (Array.isArray(value)) {
19341
19365
  return value.filter((entry2) => this.isXmlObject(entry2));
@@ -37730,16 +37754,20 @@ function parseParagraphSpacingPx(spacingNode) {
37730
37754
  }
37731
37755
  return void 0;
37732
37756
  }
37757
+ function parseBulletSizePercent(buSzPct) {
37758
+ const fraction = parseOoxmlPercent(buSzPct?.["@_val"]);
37759
+ return fraction === void 0 ? void 0 : fraction * 100;
37760
+ }
37733
37761
  function parseLineSpacingMultiplier(lineSpacingNode) {
37734
37762
  if (!lineSpacingNode) {
37735
37763
  return void 0;
37736
37764
  }
37737
37765
  const spcPct = lineSpacingNode["a:spcPct"];
37738
- const raw = Number.parseInt(String(spcPct?.["@_val"] || ""), 10);
37739
- if (Number.isFinite(raw)) {
37740
- return Math.max(0.1, Math.min(5, raw / 1e5));
37766
+ const multiplier = parseOoxmlPercent(spcPct?.["@_val"]);
37767
+ if (multiplier === void 0) {
37768
+ return void 0;
37741
37769
  }
37742
- return void 0;
37770
+ return Math.max(0.1, Math.min(5, multiplier));
37743
37771
  }
37744
37772
  function parseLineSpacingExactPt(lineSpacingNode) {
37745
37773
  if (!lineSpacingNode) {
@@ -37852,14 +37880,7 @@ function parseBulletInfo(pPr, paragraphIndex = 0) {
37852
37880
  }
37853
37881
  const buFont = pPr["a:buFont"];
37854
37882
  const fontFamily = buFont?.["@_typeface"] ? String(buFont["@_typeface"]) : void 0;
37855
- const buSzPct = pPr["a:buSzPct"];
37856
- let sizePercent;
37857
- if (buSzPct?.["@_val"] !== void 0) {
37858
- const pctRaw = Number.parseInt(String(buSzPct["@_val"]), 10);
37859
- if (Number.isFinite(pctRaw)) {
37860
- sizePercent = pctRaw / 1e3;
37861
- }
37862
- }
37883
+ const sizePercent = parseBulletSizePercent(pPr["a:buSzPct"]);
37863
37884
  const buSzPts = pPr["a:buSzPts"];
37864
37885
  let sizePts;
37865
37886
  if (buSzPts?.["@_val"] !== void 0) {
@@ -42092,7 +42113,15 @@ function getLinkedTextBoxSegments(element, allElements) {
42092
42113
  return segmentMap.get(element.id);
42093
42114
  }
42094
42115
  var FONT_SUBSTITUTION_MAP = {
42095
- // Microsoft Office default fonts
42116
+ // Microsoft Office default fonts. The Aptos family became the Office
42117
+ // default and its metrics were drawn to sit close to Calibri, so falling
42118
+ // back through Calibri keeps authored line counts; the generic sans-serif
42119
+ // chain is wider and re-wraps one-line titles.
42120
+ Aptos: ["Calibri", "Carlito", "Liberation Sans", "Arial", "sans-serif"],
42121
+ "Aptos Display": ["Calibri Light", "Calibri", "Carlito", "Arial", "sans-serif"],
42122
+ "Aptos Narrow": ["Calibri", "Liberation Sans Narrow", "Arial", "sans-serif"],
42123
+ "Aptos Serif": ["Cambria", "Caladea", "Liberation Serif", "Times New Roman", "serif"],
42124
+ "Aptos Mono": ["Consolas", "Liberation Mono", "Courier New", "monospace"],
42096
42125
  Calibri: ["Carlito", "Liberation Sans", "Arial", "sans-serif"],
42097
42126
  "Calibri Light": ["Carlito", "Liberation Sans", "Arial", "sans-serif"],
42098
42127
  Cambria: ["Caladea", "Liberation Serif", "Times New Roman", "serif"],
@@ -43859,6 +43888,15 @@ function buildModernAuthorPart(authors, rawRoot) {
43859
43888
  }
43860
43889
  };
43861
43890
  }
43891
+ function partRelsPath(partPath) {
43892
+ const lastSlash = partPath.lastIndexOf("/");
43893
+ if (lastSlash < 0) {
43894
+ return `_rels/${partPath}.rels`;
43895
+ }
43896
+ const directory = partPath.slice(0, lastSlash);
43897
+ const fileName = partPath.slice(lastSlash + 1);
43898
+ return `${directory}/_rels/${fileName}.rels`;
43899
+ }
43862
43900
  var unparsedNodesByRuntime = /* @__PURE__ */ new WeakMap();
43863
43901
  function rememberAuxiliaryMasterUnparsedNodes(runtime, partPath, nodesByTag) {
43864
43902
  let byPart = unparsedNodesByRuntime.get(runtime);
@@ -43871,6 +43909,26 @@ function rememberAuxiliaryMasterUnparsedNodes(runtime, partPath, nodesByTag) {
43871
43909
  function getAuxiliaryMasterUnparsedNodes(runtime, partPath) {
43872
43910
  return unparsedNodesByRuntime.get(runtime)?.get(partPath);
43873
43911
  }
43912
+ function createAutoNumberSequence() {
43913
+ return { levels: /* @__PURE__ */ new Map() };
43914
+ }
43915
+ function forgetFromLevel(sequence, level) {
43916
+ for (const recorded of sequence.levels.keys()) {
43917
+ if (recorded >= level) {
43918
+ sequence.levels.delete(recorded);
43919
+ }
43920
+ }
43921
+ }
43922
+ function breakAutoNumberRun(sequence, level) {
43923
+ forgetFromLevel(sequence, level);
43924
+ }
43925
+ function nextAutoNumber(sequence, level, scheme, startAt) {
43926
+ const running = sequence.levels.get(level);
43927
+ const ordinal = running && running.scheme === scheme ? running.ordinal + 1 : startAt;
43928
+ forgetFromLevel(sequence, level + 1);
43929
+ sequence.levels.set(level, { scheme, ordinal });
43930
+ return ordinal;
43931
+ }
43874
43932
  var CAMERA_PRESETS = /* @__PURE__ */ new Set([
43875
43933
  "legacyObliqueTopLeft",
43876
43934
  "legacyObliqueTop",
@@ -44155,6 +44213,18 @@ function applyTextBodyScene3d(bodyPr, style) {
44155
44213
  }
44156
44214
  bodyPr[existingKey ?? "a:scene3d"] = ordered(scene, ["camera", "lightRig", "backdrop", "extLst"]);
44157
44215
  }
44216
+ var TITLE_FAMILY = /* @__PURE__ */ new Set(["title", "ctrtitle"]);
44217
+ var BODY_FAMILY = /* @__PURE__ */ new Set(["body", "obj", "subtitle"]);
44218
+ function placeholderStyleFamily(type) {
44219
+ const declared = (type ?? "").trim().toLowerCase() || "body";
44220
+ if (TITLE_FAMILY.has(declared)) {
44221
+ return "title";
44222
+ }
44223
+ if (BODY_FAMILY.has(declared)) {
44224
+ return "body";
44225
+ }
44226
+ return declared;
44227
+ }
44158
44228
  var RELATIONSHIPS_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
44159
44229
  var ensureArray9 = (value) => value === void 0 ? [] : Array.isArray(value) ? value : [value];
44160
44230
  var resolvePartPath2 = (source, target) => {
@@ -48412,6 +48482,45 @@ var PptxHandlerRuntime = class {
48412
48482
  });
48413
48483
  }
48414
48484
  }
48485
+ /**
48486
+ * Read a package part's relationship file into {@link slideRelsMap} and
48487
+ * {@link externalRelsMap}, keyed by the part's own path.
48488
+ *
48489
+ * Lives at the root of the chain because relationships are needed by parts
48490
+ * loaded at very different times (slides, layouts, masters, notes) and by
48491
+ * mixins on both sides of the chain. A missing or empty `.rels` file is not
48492
+ * an error: plenty of parts have no relationships.
48493
+ *
48494
+ * @param partPath - The part whose relationships these are.
48495
+ * @param relsPath - Path of the `.rels` part; derived from `partPath` when omitted.
48496
+ */
48497
+ async loadPartRelationships(partPath, relsPath) {
48498
+ const relsXml = await this.zip.file(relsPath ?? partRelsPath(partPath))?.async("string");
48499
+ if (!relsXml) {
48500
+ return;
48501
+ }
48502
+ const relsData = this.parser.parse(relsXml);
48503
+ const relationships = relsData?.["Relationships"];
48504
+ const raw = relationships?.["Relationship"];
48505
+ const entries = Array.isArray(raw) ? raw : raw ? [raw] : [];
48506
+ const targets = /* @__PURE__ */ new Map();
48507
+ const externalIds = /* @__PURE__ */ new Set();
48508
+ for (const entry2 of entries) {
48509
+ const id = entry2["@_Id"];
48510
+ const target = entry2["@_Target"];
48511
+ if (!id || !target) {
48512
+ continue;
48513
+ }
48514
+ targets.set(String(id), String(target));
48515
+ if (String(entry2["@_TargetMode"] ?? "").toLowerCase() === "external") {
48516
+ externalIds.add(String(id));
48517
+ }
48518
+ }
48519
+ this.slideRelsMap.set(partPath, targets);
48520
+ if (externalIds.size > 0) {
48521
+ this.externalRelsMap.set(partPath, externalIds);
48522
+ }
48523
+ }
48415
48524
  /**
48416
48525
  * Restore the original (unwrapped) parser. Called during
48417
48526
  * `initializeLoadSession` to reset state for the next load.
@@ -50302,6 +50411,9 @@ var PptxHandlerRuntime9 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
50302
50411
  if (!this.layoutXmlMap.has(layoutPath)) {
50303
50412
  this.layoutXmlMap.set(layoutPath, data);
50304
50413
  }
50414
+ if (!this.slideRelsMap.has(layoutPath)) {
50415
+ await this.loadPartRelationships(layoutPath);
50416
+ }
50305
50417
  const layout = { path: layoutPath };
50306
50418
  const cSldName = (xmlAttr(xmlChild(sldLayout, "p:cSld"), "name") ?? "").trim();
50307
50419
  if (cSldName) {
@@ -50651,29 +50763,7 @@ var PptxHandlerRuntime11 = class extends PptxHandlerRuntime10 {
50651
50763
  return void 0;
50652
50764
  }
50653
50765
  async loadSlideRelationships(slidePath, relsPath) {
50654
- const relsXml = await this.zip.file(relsPath)?.async("string");
50655
- if (!relsXml) {
50656
- return;
50657
- }
50658
- const relsData = this.parser.parse(relsXml);
50659
- const relsMap = /* @__PURE__ */ new Map();
50660
- const externalIds = /* @__PURE__ */ new Set();
50661
- if (relsData?.Relationships?.Relationship) {
50662
- const rels = Array.isArray(relsData.Relationships.Relationship) ? relsData.Relationships.Relationship : [relsData.Relationships.Relationship];
50663
- rels.forEach((r) => {
50664
- if (r["@_Id"] && r["@_Target"]) {
50665
- const relId = String(r["@_Id"]);
50666
- relsMap.set(relId, String(r["@_Target"]));
50667
- if (String(r["@_TargetMode"] || "").toLowerCase() === "external") {
50668
- externalIds.add(relId);
50669
- }
50670
- }
50671
- });
50672
- }
50673
- this.slideRelsMap.set(slidePath, relsMap);
50674
- if (externalIds.size > 0) {
50675
- this.externalRelsMap.set(slidePath, externalIds);
50676
- }
50766
+ await this.loadPartRelationships(slidePath, relsPath);
50677
50767
  }
50678
50768
  async reconcilePresentationSlidesForSave(params) {
50679
50769
  return await this.presentationSlidesReconciler.reconcile({
@@ -53253,14 +53343,13 @@ var PptxHandlerRuntime21 = class extends PptxHandlerRuntime20 {
53253
53343
  // ── Placeholder matching key ────────────────────────────────────────
53254
53344
  /**
53255
53345
  * Build a matching key for a placeholder. Placeholders match primarily
53256
- * by type. When both have an idx, the idx must also match.
53346
+ * by the style family they belong to (so a `ctrTitle` slide placeholder can
53347
+ * take the target layout's `title` slot, and `obj` can take `body`'s). When
53348
+ * both carry an idx, the idx must also match.
53257
53349
  */
53258
53350
  buildPlaceholderMatchKey(phInfo) {
53259
- const type = phInfo.type || "body";
53260
- if (phInfo.idx !== void 0) {
53261
- return `${type}:${phInfo.idx}`;
53262
- }
53263
- return type;
53351
+ const family = placeholderStyleFamily(phInfo.type);
53352
+ return phInfo.idx !== void 0 ? `${family}:${phInfo.idx}` : family;
53264
53353
  }
53265
53354
  // ── Core layout switching logic ─────────────────────────────────────
53266
53355
  /**
@@ -53292,9 +53381,10 @@ var PptxHandlerRuntime21 = class extends PptxHandlerRuntime20 {
53292
53381
  const matchKey = this.buildPlaceholderMatchKey(phInfo);
53293
53382
  const layoutPh = layoutPhMap.get(matchKey);
53294
53383
  let resolvedLayoutPh = layoutPh;
53295
- if (!resolvedLayoutPh && phInfo.type) {
53384
+ if (!resolvedLayoutPh) {
53385
+ const family = placeholderStyleFamily(phInfo.type);
53296
53386
  for (const [, lp] of layoutPhMap.entries()) {
53297
- if (!lp.matched && lp.phInfo.type === phInfo.type) {
53387
+ if (!lp.matched && placeholderStyleFamily(lp.phInfo.type) === family) {
53298
53388
  resolvedLayoutPh = lp;
53299
53389
  break;
53300
53390
  }
@@ -62565,15 +62655,16 @@ var PptxHandlerRuntime56 = class extends PptxHandlerRuntime55 {
62565
62655
  };
62566
62656
  }
62567
62657
  /**
62568
- * Build a cache-map key for a placeholder. Prefers `idx` when present,
62569
- * otherwise falls back to `type`.
62658
+ * Build a cache-map key for a placeholder, combining the style family it
62659
+ * inherits from with `idx` when the reference carries one.
62660
+ *
62661
+ * Keying on the family rather than the raw attribute is what lets a slide's
62662
+ * `<p:ph idx="14"/>` find the layout's `type="obj" idx="14"` entry instead of
62663
+ * falling through to the master and losing the layout's own values.
62570
62664
  */
62571
62665
  buildPlaceholderDefaultsKey(phInfo) {
62572
- const normalizedType = phInfo.type === "ctrtitle" ? "title" : phInfo.type === "subtitle" ? "body" : phInfo.type;
62573
- if (phInfo.idx !== void 0) {
62574
- return normalizedType ? `${normalizedType}_${phInfo.idx}` : `_${phInfo.idx}`;
62575
- }
62576
- return normalizedType ?? "body";
62666
+ const family = placeholderStyleFamily(phInfo.type);
62667
+ return phInfo.idx !== void 0 ? `${family}_${phInfo.idx}` : family;
62577
62668
  }
62578
62669
  /**
62579
62670
  * Look up merged {@link PlaceholderDefaults} for a shape's placeholder
@@ -62591,8 +62682,8 @@ var PptxHandlerRuntime56 = class extends PptxHandlerRuntime55 {
62591
62682
  const masterPath = this.resolveMasterPathForLayout(layoutPath);
62592
62683
  const masterMap = masterPath ? this.masterPlaceholderDefaultsCache.get(masterPath) : void 0;
62593
62684
  const masterDefaults = masterMap?.get(phKey);
62594
- const normalizedType = this.buildPlaceholderDefaultsKey(phInfo).split("_")[0];
62595
- const masterTextStyleType = phInfo.type === "title" || phInfo.type === "ctrtitle" ? "title" : phInfo.type === "body" || phInfo.type === "obj" || phInfo.type === "subtitle" ? "body" : "other";
62685
+ const normalizedType = placeholderStyleFamily(phInfo.type);
62686
+ const masterTextStyleType = normalizedType === "title" ? "title" : normalizedType === "body" ? "body" : "other";
62596
62687
  const masterTextStyles = masterPath ? this.masterTxStylesCache.get(masterPath) : void 0;
62597
62688
  const masterTextLevels = masterTextStyleType === "title" ? masterTextStyles?.titleStyle : masterTextStyleType === "body" ? masterTextStyles?.bodyStyle : masterTextStyles?.otherStyle;
62598
62689
  const resolvedMasterDefaults = masterTextLevels ? {
@@ -63326,12 +63417,11 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
63326
63417
  if (Number.isFinite(spacingPointsRaw)) {
63327
63418
  return this.pointsToPixels(spacingPointsRaw / 100);
63328
63419
  }
63329
- const spacingPercentRaw = Number.parseInt(
63330
- String(spacingNode["a:spcPct"]?.["@_val"] || ""),
63331
- 10
63420
+ const spacingFraction = parseOoxmlPercent(
63421
+ spacingNode["a:spcPct"]?.["@_val"]
63332
63422
  );
63333
- if (Number.isFinite(spacingPercentRaw) && typeof basisFontSizePx === "number" && basisFontSizePx > 0) {
63334
- return spacingPercentRaw / 1e5 * basisFontSizePx;
63423
+ if (spacingFraction !== void 0 && typeof basisFontSizePx === "number" && basisFontSizePx > 0) {
63424
+ return spacingFraction * basisFontSizePx;
63335
63425
  }
63336
63426
  return void 0;
63337
63427
  }
@@ -63339,12 +63429,11 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
63339
63429
  if (!lineSpacingNode) {
63340
63430
  return void 0;
63341
63431
  }
63342
- const spacingPercentRaw = Number.parseInt(
63343
- String(lineSpacingNode["a:spcPct"]?.["@_val"] || ""),
63344
- 10
63432
+ const spacingFraction = parseOoxmlPercent(
63433
+ lineSpacingNode["a:spcPct"]?.["@_val"]
63345
63434
  );
63346
- if (Number.isFinite(spacingPercentRaw)) {
63347
- return Math.max(0.1, Math.min(5, spacingPercentRaw / 1e5));
63435
+ if (spacingFraction !== void 0) {
63436
+ return Math.max(0.1, Math.min(5, spacingFraction));
63348
63437
  }
63349
63438
  return void 0;
63350
63439
  }
@@ -63365,6 +63454,27 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
63365
63454
  }
63366
63455
  return void 0;
63367
63456
  }
63457
+ /**
63458
+ * Resolve an inherited level colour against the colour map that is active
63459
+ * now, rather than the one that was active when the level was cached.
63460
+ *
63461
+ * Layout and master text styles are cached once per part; slides are parsed
63462
+ * afterwards, each with its own `p:clrMapOvr`. Re-reading the authored
63463
+ * choice is what makes `tx1` come out white on a slide that maps it to the
63464
+ * light slot and black on one that does not.
63465
+ *
63466
+ * @param levelStyle - The inherited level style.
63467
+ * @returns The colour to inherit, or `undefined` when the level sets none.
63468
+ */
63469
+ resolveLevelStyleColor(levelStyle) {
63470
+ if (levelStyle.colorChoiceXml) {
63471
+ const remapped = this.parseColor(levelStyle.colorChoiceXml);
63472
+ if (remapped) {
63473
+ return remapped;
63474
+ }
63475
+ }
63476
+ return levelStyle.color;
63477
+ }
63368
63478
  /**
63369
63479
  * Apply level-specific {@link PlaceholderTextLevelStyle} properties to a
63370
63480
  * {@link TextStyle} as fallback values for paragraph-level fields.
@@ -63382,8 +63492,11 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
63382
63492
  if (textStyle.italic === void 0 && levelStyle.italic !== void 0) {
63383
63493
  textStyle.italic = levelStyle.italic;
63384
63494
  }
63385
- if (textStyle.color === void 0 && levelStyle.color !== void 0) {
63386
- textStyle.color = levelStyle.color;
63495
+ if (textStyle.color === void 0) {
63496
+ const inheritedColor = this.resolveLevelStyleColor(levelStyle);
63497
+ if (inheritedColor !== void 0) {
63498
+ textStyle.color = inheritedColor;
63499
+ }
63387
63500
  }
63388
63501
  if (textStyle.paragraphMarginLeft === void 0 && levelStyle.marginLeft !== void 0) {
63389
63502
  textStyle.paragraphMarginLeft = levelStyle.marginLeft;
@@ -63452,14 +63565,9 @@ var PptxHandlerRuntime60 = class extends PptxHandlerRuntime59 {
63452
63565
  const buFont = resolvedBulletProps["a:buFont"];
63453
63566
  const fontFamily = buFont?.["@_typeface"] ? String(buFont["@_typeface"]) : void 0;
63454
63567
  const fontInherit = resolvedBulletProps["a:buFontTx"] !== void 0;
63455
- const buSzPct = resolvedBulletProps["a:buSzPct"];
63456
- let sizePercent;
63457
- if (buSzPct?.["@_val"] !== void 0) {
63458
- const pctRaw = Number.parseInt(String(buSzPct["@_val"]), 10);
63459
- if (Number.isFinite(pctRaw)) {
63460
- sizePercent = pctRaw / 1e3;
63461
- }
63462
- }
63568
+ const sizePercent = parseBulletSizePercent(
63569
+ resolvedBulletProps["a:buSzPct"]
63570
+ );
63463
63571
  const buSzPts = resolvedBulletProps["a:buSzPts"];
63464
63572
  let sizePts;
63465
63573
  if (buSzPts?.["@_val"] !== void 0) {
@@ -64236,13 +64344,25 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
64236
64344
  ctx.slidePath,
64237
64345
  ctx.effectiveLevelStyles
64238
64346
  );
64347
+ const paragraphLevel = parseParagraphLevel(p["a:pPr"]);
64348
+ const autoNumScheme = paragraphBulletInfo && !paragraphBulletInfo.none && !paragraphBulletInfo.char ? paragraphBulletInfo.autoNumType : void 0;
64349
+ let autoNumOrdinal;
64350
+ if (autoNumScheme) {
64351
+ autoNumOrdinal = nextAutoNumber(
64352
+ ctx.autoNumbering,
64353
+ paragraphLevel,
64354
+ autoNumScheme,
64355
+ paragraphBulletInfo?.autoNumStartAt ?? 1
64356
+ );
64357
+ } else {
64358
+ breakAutoNumberRun(ctx.autoNumbering, paragraphLevel);
64359
+ }
64239
64360
  if (paragraphBulletInfo && !paragraphBulletInfo.none) {
64240
64361
  let bulletText;
64241
64362
  if (paragraphBulletInfo.char) {
64242
64363
  bulletText = `${paragraphBulletInfo.char} `;
64243
- } else if (paragraphBulletInfo.autoNumType) {
64244
- const startAt = paragraphBulletInfo.autoNumStartAt ?? 1;
64245
- bulletText = this.formatAutoNumber(paragraphBulletInfo.autoNumType, startAt + pIdx);
64364
+ } else if (autoNumScheme && autoNumOrdinal !== void 0) {
64365
+ bulletText = this.formatAutoNumber(autoNumScheme, autoNumOrdinal);
64246
64366
  } else if (paragraphBulletInfo.imageRelId) {
64247
64367
  bulletText = "\u{1F4CE} ";
64248
64368
  } else {
@@ -64750,7 +64870,8 @@ var PptxHandlerRuntime64 = class _PptxHandlerRuntime27 extends PptxHandlerRuntim
64750
64870
  slidePath,
64751
64871
  effectiveLevelStyles,
64752
64872
  styleFontRefColor,
64753
- styleFontRefTypeface
64873
+ styleFontRefTypeface,
64874
+ autoNumbering: createAutoNumberSequence()
64754
64875
  };
64755
64876
  paras.forEach((p, pIdx) => {
64756
64877
  const styleResult = this.resolveShapeParagraphStyle(p, textStyle, ctx);
@@ -66238,7 +66359,7 @@ var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
66238
66359
  try {
66239
66360
  const masterXmlObj = await this.resolveCachedMasterXml(masterPath);
66240
66361
  if (masterXmlObj) {
66241
- const masterRelsPath = `${masterPath.replace("slideMasters/", "slideMasters/_rels/")}.rels`;
66362
+ const masterRelsPath = partRelsPath(masterPath);
66242
66363
  await this.loadSlideRelationships(masterPath, masterRelsPath);
66243
66364
  return this.extractBackgroundImage(masterXmlObj, masterPath, "p:sldMaster");
66244
66365
  }
@@ -66261,7 +66382,7 @@ var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
66261
66382
  try {
66262
66383
  const layoutXmlObj = await this.resolveCachedLayoutXml(layoutPath);
66263
66384
  if (layoutXmlObj) {
66264
- const layoutRelsPath = `${layoutPath.replace("slideLayouts/", "slideLayouts/_rels/")}.rels`;
66385
+ const layoutRelsPath = partRelsPath(layoutPath);
66265
66386
  await this.loadSlideRelationships(layoutPath, layoutRelsPath);
66266
66387
  const bg = this.extractBackgroundImage(layoutXmlObj, layoutPath, "p:sldLayout");
66267
66388
  if (bg) {
@@ -66431,7 +66552,7 @@ var PptxHandlerRuntime71 = class extends PptxHandlerRuntime70 {
66431
66552
  return;
66432
66553
  }
66433
66554
  if (!this.slideRelsMap.has(layoutPath)) {
66434
- const layoutRelsPath = `${layoutPath.replace("slideLayouts/", "slideLayouts/_rels/")}.rels`;
66555
+ const layoutRelsPath = partRelsPath(layoutPath);
66435
66556
  try {
66436
66557
  await this.loadSlideRelationships(layoutPath, layoutRelsPath);
66437
66558
  } catch {
@@ -66715,12 +66836,11 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime31 extends PptxHandlerRuntim
66715
66836
  if (buFont?.["@_typeface"]) {
66716
66837
  style.bulletFontFamily = String(buFont["@_typeface"]);
66717
66838
  }
66718
- const buSzPct = levelProps["a:buSzPct"];
66719
- if (buSzPct?.["@_val"] !== void 0) {
66720
- const pctRaw = Number.parseInt(String(buSzPct["@_val"]), 10);
66721
- if (Number.isFinite(pctRaw)) {
66722
- style.bulletSizePercent = pctRaw / 1e3;
66723
- }
66839
+ const bulletSizePercent = parseBulletSizePercent(
66840
+ levelProps["a:buSzPct"]
66841
+ );
66842
+ if (bulletSizePercent !== void 0) {
66843
+ style.bulletSizePercent = bulletSizePercent;
66724
66844
  }
66725
66845
  const buClr = levelProps["a:buClr"];
66726
66846
  if (buClr) {
@@ -66753,10 +66873,14 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime31 extends PptxHandlerRuntim
66753
66873
  if (defRPr["@_i"] !== void 0) {
66754
66874
  style.italic = defRPr["@_i"] === "1";
66755
66875
  }
66756
- const color2 = this.parseColor(defRPr["a:solidFill"]);
66876
+ const solidFill3 = defRPr["a:solidFill"];
66877
+ const color2 = this.parseColor(solidFill3);
66757
66878
  if (color2) {
66758
66879
  style.color = color2;
66759
66880
  }
66881
+ if (solidFill3) {
66882
+ style.colorChoiceXml = solidFill3;
66883
+ }
66760
66884
  const latin = defRPr["a:latin"];
66761
66885
  if (latin?.["@_typeface"]) {
66762
66886
  const typeface = String(latin["@_typeface"]);
@@ -67075,7 +67199,7 @@ var PptxHandlerRuntime74 = class extends PptxHandlerRuntime73 {
67075
67199
  }
67076
67200
  const masterXmlObj = this.parser.parse(masterXmlStr);
67077
67201
  this.masterXmlMap.set(masterPath, masterXmlObj);
67078
- const masterRelsPath = `${masterPath.replace("slideMasters/", "slideMasters/_rels/")}.rels`;
67202
+ const masterRelsPath = partRelsPath(masterPath);
67079
67203
  await this.loadSlideRelationships(masterPath, masterRelsPath);
67080
67204
  const spTree = masterXmlObj["p:sldMaster"]?.["p:cSld"]?.["p:spTree"];
67081
67205
  if (!spTree) {
@@ -67293,7 +67417,7 @@ var PptxHandlerRuntime76 = class extends PptxHandlerRuntime75 {
67293
67417
  }
67294
67418
  const layoutXmlObj = this.parser.parse(layoutXmlStr);
67295
67419
  this.layoutXmlMap.set(layoutPath, layoutXmlObj);
67296
- const layoutRelsPath = `${layoutPath.replace("slideLayouts/", "slideLayouts/_rels/")}.rels`;
67420
+ const layoutRelsPath = partRelsPath(layoutPath);
67297
67421
  await this.loadSlideRelationships(layoutPath, layoutRelsPath);
67298
67422
  const layoutClrMapOverride = this.parseLayoutClrMapOverride(layoutXmlObj);
67299
67423
  const prevClrMapOverride = this.currentSlideClrMapOverride;
@@ -69211,6 +69335,15 @@ var PptxHandlerRuntime83 = class extends PptxHandlerRuntime82 {
69211
69335
  };
69212
69336
  function extractDrawingShapeFill(spPr, deps) {
69213
69337
  const result = {};
69338
+ if (deps.hasChild(spPr, "noFill")) {
69339
+ result.fillNone = true;
69340
+ const noFillShadowColor = deps.extractShadowColor(spPr);
69341
+ if (noFillShadowColor) {
69342
+ result.hasShadow = true;
69343
+ result.shadowColor = noFillShadowColor;
69344
+ }
69345
+ return result;
69346
+ }
69214
69347
  const solidFill3 = deps.getChild(spPr, "solidFill");
69215
69348
  if (solidFill3) {
69216
69349
  result.fillColor = deps.parseColor(solidFill3) ?? void 0;
@@ -69522,6 +69655,7 @@ var PptxHandlerRuntime84 = class _PptxHandlerRuntime35 extends PptxHandlerRuntim
69522
69655
  drawingShapeStyleDeps() {
69523
69656
  return {
69524
69657
  getChild: (node, local) => this.xmlLookupService.getChildByLocalName(node, local),
69658
+ hasChild: (node, local) => this.xmlLookupService.hasChildByLocalName(node, local),
69525
69659
  getChildren: (node, local) => this.xmlLookupService.getChildrenArrayByLocalName(node, local),
69526
69660
  parseColor: (node) => this.parseColor(node),
69527
69661
  extractGradientStops: (gradFill) => this.extractGradientStops(gradFill),
@@ -108034,19 +108168,21 @@ function childrenPair(a, b) {
108034
108168
  }
108035
108169
  return boxOverlapRatio(a, b) >= CHILD_OVERLAP_RATIO;
108036
108170
  }
108037
- function childrenCorrespond(a, b) {
108171
+ function correspondingChildren(a, b) {
108038
108172
  if (a.length !== b.length || a.length === 0) {
108039
- return false;
108173
+ return void 0;
108040
108174
  }
108041
108175
  const unclaimed = b.map((child22) => child22);
108176
+ const paired = [];
108042
108177
  for (const child22 of a) {
108043
108178
  const index = unclaimed.findIndex((candidate) => childrenPair(child22, candidate));
108044
108179
  if (index < 0) {
108045
- return false;
108180
+ return void 0;
108046
108181
  }
108182
+ paired.push([child22, unclaimed[index]]);
108047
108183
  unclaimed.splice(index, 1);
108048
108184
  }
108049
- return true;
108185
+ return paired;
108050
108186
  }
108051
108187
  function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
108052
108188
  const out = [];
@@ -108055,7 +108191,7 @@ function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
108055
108191
  if (children8 && containsMorphNamedDescendant(element)) {
108056
108192
  const twin = correspondingGroup(element, counterpart);
108057
108193
  const twinChildren = twin ? groupChildren(twin) ?? [] : void 0;
108058
- if (twinChildren && childrenCorrespond(children8, twinChildren)) {
108194
+ if (twinChildren && correspondingChildren(children8, twinChildren)) {
108059
108195
  out.push(
108060
108196
  ...flattenMorphElements(children8, twinChildren, offsetX + element.x, offsetY + element.y)
108061
108197
  );
@@ -108066,6 +108202,29 @@ function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
108066
108202
  }
108067
108203
  return out;
108068
108204
  }
108205
+ function morphGroupChildPairs(elements, counterpart) {
108206
+ const pairs2 = /* @__PURE__ */ new Map();
108207
+ collectGroupChildPairs(elements, counterpart, pairs2);
108208
+ return pairs2;
108209
+ }
108210
+ function collectGroupChildPairs(elements, counterpart, into) {
108211
+ for (const element of elements) {
108212
+ const children8 = groupChildren(element);
108213
+ if (!children8 || !containsMorphNamedDescendant(element)) {
108214
+ continue;
108215
+ }
108216
+ const twin = correspondingGroup(element, counterpart);
108217
+ const twinChildren = twin ? groupChildren(twin) ?? [] : void 0;
108218
+ const corresponded = twinChildren ? correspondingChildren(children8, twinChildren) : void 0;
108219
+ if (!corresponded) {
108220
+ continue;
108221
+ }
108222
+ for (const [child22, twinChild] of corresponded) {
108223
+ into.set(child22.id, twinChild.id);
108224
+ }
108225
+ collectGroupChildPairs(children8, twinChildren ?? [], into);
108226
+ }
108227
+ }
108069
108228
  var OUTLINE_SAMPLE_COUNT = 64;
108070
108229
  var ELLIPSE_SAMPLE_COUNT = 48;
108071
108230
  function resolveLength(token2, axis) {
@@ -108532,6 +108691,23 @@ function matchMorphElementsFull(fromSlide, toSlide) {
108532
108691
  }
108533
108692
  }
108534
108693
  }
108694
+ const groupChildPairs = morphGroupChildPairs(fromSlide.elements, toSlide.elements);
108695
+ if (groupChildPairs.size > 0) {
108696
+ const toById = new Map(toElements.map((el) => [el.id, el]));
108697
+ for (const fromEl of fromElements) {
108698
+ if (usedFrom.has(fromEl.id)) {
108699
+ continue;
108700
+ }
108701
+ const toId = groupChildPairs.get(fromEl.id);
108702
+ const toEl = toId === void 0 ? void 0 : toById.get(toId);
108703
+ if (!toEl || usedTo.has(toEl.id) || fromEl.type !== toEl.type) {
108704
+ continue;
108705
+ }
108706
+ pairs2.push({ fromElement: fromEl, toElement: toEl });
108707
+ usedFrom.add(fromEl.id);
108708
+ usedTo.add(toEl.id);
108709
+ }
108710
+ }
108535
108711
  for (const fromEl of fromElements) {
108536
108712
  if (usedFrom.has(fromEl.id) || !fromEl.shapeId) {
108537
108713
  continue;
@@ -108638,7 +108814,7 @@ function buildMorphMergedOrder(outgoing, incoming, pairs2) {
108638
108814
  flushOutgoingBelow(outgoing.length);
108639
108815
  return rank;
108640
108816
  }
108641
- function resolveMorphOverlayArrivals(outgoing, incoming, pairs2, holdingGhostIds) {
108817
+ function resolveMorphOverlayArrivals(outgoing, incoming, pairs2, holdingGhostIds, dissolvingInIds = /* @__PURE__ */ new Set()) {
108642
108818
  const rank = buildMorphMergedOrder(outgoing, incoming, pairs2);
108643
108819
  const matched = new Set(pairs2.map((pair) => pair.toElement.id));
108644
108820
  const counterpart = new Map(pairs2.map((pair) => [pair.fromElement.id, pair.toElement]));
@@ -108648,7 +108824,7 @@ function resolveMorphOverlayArrivals(outgoing, incoming, pairs2, holdingGhostIds
108648
108824
  }));
108649
108825
  const lifted = /* @__PURE__ */ new Set();
108650
108826
  for (const element of incoming) {
108651
- if (matched.has(element.id)) {
108827
+ if (matched.has(element.id) && !dissolvingInIds.has(element.id)) {
108652
108828
  continue;
108653
108829
  }
108654
108830
  const mine = rank.get(element.id) ?? 0;
@@ -108713,6 +108889,21 @@ function tokenizeText(element, mode) {
108713
108889
  }
108714
108890
  return tokens;
108715
108891
  }
108892
+ var SAME_SLOT_OVERLAP = 0.5;
108893
+ function ownText(element) {
108894
+ return (element.text ?? "").replace(/\s+/gu, " ").trim();
108895
+ }
108896
+ function morphTextReplacedInSlot(fromElement, toElement) {
108897
+ if (fromElement.type !== "text" || toElement.type !== "text") {
108898
+ return false;
108899
+ }
108900
+ const from = ownText(fromElement);
108901
+ const to = ownText(toElement);
108902
+ if (from === "" || to === "" || from === to) {
108903
+ return false;
108904
+ }
108905
+ return boxOverlapRatio(fromElement, toElement) >= SAME_SLOT_OVERLAP;
108906
+ }
108716
108907
  function diffTokens(fromTokens, toTokens) {
108717
108908
  const n = fromTokens.length;
108718
108909
  const m = toTokens.length;
@@ -108911,6 +109102,9 @@ function resolveMorphGhostIds(outgoingElements, pairs2) {
108911
109102
  }
108912
109103
  return painted;
108913
109104
  }
109105
+ function morphPairIncomingFadesIn(fromElement, toElement, ghosted = true) {
109106
+ return !(ghosted && isInertMorphPair(fromElement, toElement)) && morphPairNeedsCrossfade(fromElement, toElement) && crossfadeIncomingMayFadeIn(toElement);
109107
+ }
108914
109108
  function crossfadeIncomingMayFadeIn(element) {
108915
109109
  const image = element;
108916
109110
  if (image.imagePath || image.svgPath) {
@@ -108941,17 +109135,18 @@ function generateMorphAnimations(pairs2, durationMs, _mode = "object", ghostIds)
108941
109135
  continue;
108942
109136
  }
108943
109137
  const safeName = `pptx-morph-${index}-${toElement.id.replace(/[^a-zA-Z0-9]/gu, "")}`;
108944
- const dx = fromElement.x + fromElement.width / 2 - (toElement.x + toElement.width / 2);
108945
- const dy = fromElement.y + fromElement.height / 2 - (toElement.y + toElement.height / 2);
108946
- const sx = Math.max(fromElement.width, 1) / Math.max(toElement.width, 1);
108947
- const sy = Math.max(fromElement.height, 1) / Math.max(toElement.height, 1);
109138
+ const inSlot = morphTextReplacedInSlot(fromElement, toElement);
109139
+ const dx = inSlot ? 0 : fromElement.x + fromElement.width / 2 - (toElement.x + toElement.width / 2);
109140
+ const dy = inSlot ? 0 : fromElement.y + fromElement.height / 2 - (toElement.y + toElement.height / 2);
109141
+ const sx = inSlot ? 1 : Math.max(fromElement.width, 1) / Math.max(toElement.width, 1);
109142
+ const sy = inSlot ? 1 : Math.max(fromElement.height, 1) / Math.max(toElement.height, 1);
108948
109143
  const fromOpacity = fromElement.opacity ?? 1;
108949
109144
  const toOpacity = toElement.opacity ?? 1;
108950
109145
  const toRot = toElement.rotation ?? 0;
108951
- const fromRot = shortestRotationTarget(toRot, fromElement.rotation ?? 0);
109146
+ const fromRot = inSlot ? toRot : shortestRotationTarget(toRot, fromElement.rotation ?? 0);
108952
109147
  const flips = `${toElement.flipHorizontal ? " scaleX(-1)" : ""}${toElement.flipVertical ? " scaleY(-1)" : ""}`;
108953
109148
  const inert = ghosted && isInertMorphPair(fromElement, toElement);
108954
- const crossfadesIn = !inert && morphPairNeedsCrossfade(fromElement, toElement) && crossfadeIncomingMayFadeIn(toElement);
109149
+ const crossfadesIn = morphPairIncomingFadesIn(fromElement, toElement, ghosted);
108955
109150
  const fromProps = [
108956
109151
  ` transform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${fromRot}deg)${flips};`
108957
109152
  ];
@@ -109004,14 +109199,18 @@ function generateMorphGhostAnimations(pairs2, durationMs, startIndex, ghostIds)
109004
109199
  if (ghostIds && !ghostIds.has(fromElement.id)) {
109005
109200
  continue;
109006
109201
  }
109202
+ if (isInertMorphPair(fromElement, toElement)) {
109203
+ continue;
109204
+ }
109007
109205
  const fadesOut = morphPairNeedsCrossfade(fromElement, toElement);
109008
109206
  const safeName = `pptx-morph-ghost-${startIndex + index}-${fromElement.id.replace(/[^a-zA-Z0-9]/gu, "")}`;
109009
- const dx = toElement.x + toElement.width / 2 - (fromElement.x + fromElement.width / 2);
109010
- const dy = toElement.y + toElement.height / 2 - (fromElement.y + fromElement.height / 2);
109011
- const sx = Math.max(toElement.width, 1) / Math.max(fromElement.width, 1);
109012
- const sy = Math.max(toElement.height, 1) / Math.max(fromElement.height, 1);
109207
+ const inSlot = morphTextReplacedInSlot(fromElement, toElement);
109208
+ const dx = inSlot ? 0 : toElement.x + toElement.width / 2 - (fromElement.x + fromElement.width / 2);
109209
+ const dy = inSlot ? 0 : toElement.y + toElement.height / 2 - (fromElement.y + fromElement.height / 2);
109210
+ const sx = inSlot ? 1 : Math.max(toElement.width, 1) / Math.max(fromElement.width, 1);
109211
+ const sy = inSlot ? 1 : Math.max(toElement.height, 1) / Math.max(fromElement.height, 1);
109013
109212
  const fromRot = fromElement.rotation ?? 0;
109014
- const toRot = shortestRotationTarget(fromRot, toElement.rotation ?? 0);
109213
+ const toRot = inSlot ? fromRot : shortestRotationTarget(fromRot, toElement.rotation ?? 0);
109015
109214
  const flips = `${fromElement.flipHorizontal ? " scaleX(-1)" : ""}${fromElement.flipVertical ? " scaleY(-1)" : ""}`;
109016
109215
  const opacity2 = fromElement.opacity ?? 1;
109017
109216
  const keyframes = `
@@ -109209,6 +109408,7 @@ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = "object
109209
109408
  const animations = generateFullMorphTransition(fromSlide, toSlide, durationMs, mode);
109210
109409
  const flattenedOutgoing = flattenMorphElements(fromSlide.elements, toSlide.elements);
109211
109410
  const outgoingIds = new Set(flattenedOutgoing.map((element) => element.id));
109411
+ const ghostIds = resolveMorphGhostIds(flattenedOutgoing, match.pairs);
109212
109412
  const incomingAnimations = /* @__PURE__ */ new Map();
109213
109413
  const outgoingAnimations = /* @__PURE__ */ new Map();
109214
109414
  const incomingImageAnimations = /* @__PURE__ */ new Map();
@@ -109220,20 +109420,28 @@ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = "object
109220
109420
  const target = animation.target === "image" ? isOutgoing ? outgoingImageAnimations : incomingImageAnimations : isOutgoing ? outgoingAnimations : incomingAnimations;
109221
109421
  target.set(animation.elementId, animation.animation);
109222
109422
  }
109223
- const outgoingElements = flattenedOutgoing.filter(
109224
- (element) => outgoingAnimations.has(element.id)
109225
- );
109423
+ const outgoingElements = flattenedOutgoing.filter((element) => ghostIds.has(element.id));
109226
109424
  const flattenedIncoming = flattenMorphElements(toSlide.elements, fromSlide.elements);
109227
109425
  const holdingGhostIds = new Set(
109228
109426
  match.pairs.filter(
109229
- (candidate) => outgoingAnimations.has(candidate.fromElement.id) && !morphPairNeedsCrossfade(candidate.fromElement, candidate.toElement)
109427
+ (candidate) => ghostIds.has(candidate.fromElement.id) && !morphPairNeedsCrossfade(candidate.fromElement, candidate.toElement)
109230
109428
  ).map((candidate) => candidate.fromElement.id)
109231
109429
  );
109430
+ const dissolvingInIds = new Set(
109431
+ match.pairs.filter(
109432
+ (candidate) => morphPairIncomingFadesIn(
109433
+ candidate.fromElement,
109434
+ candidate.toElement,
109435
+ ghostIds.has(candidate.fromElement.id)
109436
+ )
109437
+ ).map((candidate) => candidate.toElement.id)
109438
+ );
109232
109439
  const lifted = resolveMorphOverlayArrivals(
109233
109440
  flattenedOutgoing,
109234
109441
  flattenedIncoming,
109235
109442
  match.pairs,
109236
- holdingGhostIds
109443
+ holdingGhostIds,
109444
+ dissolvingInIds
109237
109445
  );
109238
109446
  const overlayIncomingAnimations = /* @__PURE__ */ new Map();
109239
109447
  for (const id of lifted) {