pptx-react-viewer 2.5.2 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/{AiChatPanel-OHSLJNYG.js → AiChatPanel-53W2JG6G.js} +22 -22
  3. package/dist/AiChatPanel-53W2JG6G.js.br +0 -0
  4. package/dist/AiChatPanel-53W2JG6G.js.gz +0 -0
  5. package/dist/{AiChatPanel-EMF3UYCE.mjs → AiChatPanel-L5IOO72H.mjs} +3 -3
  6. package/dist/AiChatPanel-L5IOO72H.mjs.br +0 -0
  7. package/dist/AiChatPanel-L5IOO72H.mjs.gz +0 -0
  8. package/dist/{Model3DScene-ULHIJPMU.js → Model3DScene-E7JGXNJN.js} +2 -2
  9. package/dist/Model3DScene-E7JGXNJN.js.br +0 -0
  10. package/dist/Model3DScene-E7JGXNJN.js.gz +0 -0
  11. package/dist/{Model3DScene-X6QJTWHV.mjs → Model3DScene-EW7OWRJK.mjs} +1 -1
  12. package/dist/Model3DScene-EW7OWRJK.mjs.br +0 -0
  13. package/dist/Model3DScene-EW7OWRJK.mjs.gz +0 -0
  14. package/dist/{SurfaceChart3DScene-K7Q5NYZ4.js → SurfaceChart3DScene-3QB6NVKD.js} +2 -2
  15. package/dist/SurfaceChart3DScene-3QB6NVKD.js.br +0 -0
  16. package/dist/SurfaceChart3DScene-3QB6NVKD.js.gz +0 -0
  17. package/dist/{SurfaceChart3DScene-PRCKQJQQ.mjs → SurfaceChart3DScene-64HI3U7Y.mjs} +1 -1
  18. package/dist/{SurfaceChart3DScene-PRCKQJQQ.mjs.br → SurfaceChart3DScene-64HI3U7Y.mjs.br} +0 -0
  19. package/dist/SurfaceChart3DScene-64HI3U7Y.mjs.gz +0 -0
  20. package/dist/{chunk-VOV2N3NY.mjs → chunk-34ZW32XK.mjs} +919 -65
  21. package/dist/chunk-34ZW32XK.mjs.br +0 -0
  22. package/dist/chunk-34ZW32XK.mjs.gz +0 -0
  23. package/dist/{chunk-TGVID6BB.mjs → chunk-DWQJW3UM.mjs} +19 -4
  24. package/dist/chunk-DWQJW3UM.mjs.br +0 -0
  25. package/dist/chunk-DWQJW3UM.mjs.gz +0 -0
  26. package/dist/{chunk-7Q7AEPO7.js → chunk-EJ24IFPL.js} +346 -315
  27. package/dist/chunk-EJ24IFPL.js.br +0 -0
  28. package/dist/chunk-EJ24IFPL.js.gz +0 -0
  29. package/dist/{chunk-NVH3RIN7.js → chunk-NXSAYLYI.js} +251 -236
  30. package/dist/chunk-NXSAYLYI.js.br +0 -0
  31. package/dist/chunk-NXSAYLYI.js.gz +0 -0
  32. package/dist/{chunk-WJKMTDXS.mjs → chunk-PENV7S7Z.mjs} +1 -1
  33. package/dist/chunk-PENV7S7Z.mjs.br +0 -0
  34. package/dist/{chunk-WJKMTDXS.mjs.gz → chunk-PENV7S7Z.mjs.gz} +0 -0
  35. package/dist/{chunk-HDKHZKSW.mjs → chunk-UO55N46T.mjs} +91 -13
  36. package/dist/chunk-UO55N46T.mjs.br +0 -0
  37. package/dist/chunk-UO55N46T.mjs.gz +0 -0
  38. package/dist/{chunk-LTEDT475.js → chunk-UVA55CRK.js} +921 -64
  39. package/dist/chunk-UVA55CRK.js.br +0 -0
  40. package/dist/chunk-UVA55CRK.js.gz +0 -0
  41. package/dist/{chunk-OSSVKJGF.js → chunk-V5XVTKFS.js} +925 -847
  42. package/dist/chunk-V5XVTKFS.js.br +0 -0
  43. package/dist/chunk-V5XVTKFS.js.gz +0 -0
  44. package/dist/{chunk-MJAEB43A.js → chunk-VBWWICDF.js} +3 -3
  45. package/dist/chunk-VBWWICDF.js.br +0 -0
  46. package/dist/chunk-VBWWICDF.js.gz +0 -0
  47. package/dist/{chunk-LIQGO45T.mjs → chunk-WCO3NEH5.mjs} +35 -4
  48. package/dist/chunk-WCO3NEH5.mjs.br +0 -0
  49. package/dist/chunk-WCO3NEH5.mjs.gz +0 -0
  50. package/dist/index.d.ts +15 -0
  51. package/dist/index.js +34 -34
  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 +42 -0
  58. package/dist/internals.d.ts.map +1 -1
  59. package/dist/internals.js +78 -78
  60. package/dist/internals.js.br +0 -0
  61. package/dist/internals.js.gz +0 -0
  62. package/dist/internals.mjs +3 -3
  63. package/dist/internals.mjs.br +0 -0
  64. package/dist/internals.mjs.gz +0 -0
  65. package/dist/pptx-viewer.css +1 -1
  66. package/dist/pptx-viewer.css.br +0 -0
  67. package/dist/pptx-viewer.css.gz +0 -0
  68. package/dist/viewer/index.d.ts +15 -0
  69. package/dist/viewer/index.js +21 -21
  70. package/dist/viewer/index.js.br +0 -0
  71. package/dist/viewer/index.js.gz +0 -0
  72. package/dist/viewer/index.mjs +5 -5
  73. package/dist/viewer/index.mjs.br +0 -0
  74. package/dist/viewer/index.mjs.gz +0 -0
  75. package/package.json +3 -3
  76. package/dist/AiChatPanel-EMF3UYCE.mjs.br +0 -0
  77. package/dist/AiChatPanel-EMF3UYCE.mjs.gz +0 -0
  78. package/dist/AiChatPanel-OHSLJNYG.js.br +0 -0
  79. package/dist/AiChatPanel-OHSLJNYG.js.gz +0 -0
  80. package/dist/Model3DScene-ULHIJPMU.js.br +0 -0
  81. package/dist/Model3DScene-ULHIJPMU.js.gz +0 -0
  82. package/dist/Model3DScene-X6QJTWHV.mjs.br +0 -0
  83. package/dist/Model3DScene-X6QJTWHV.mjs.gz +0 -0
  84. package/dist/SurfaceChart3DScene-K7Q5NYZ4.js.br +0 -0
  85. package/dist/SurfaceChart3DScene-K7Q5NYZ4.js.gz +0 -0
  86. package/dist/SurfaceChart3DScene-PRCKQJQQ.mjs.gz +0 -0
  87. package/dist/chunk-7Q7AEPO7.js.br +0 -0
  88. package/dist/chunk-7Q7AEPO7.js.gz +0 -0
  89. package/dist/chunk-HDKHZKSW.mjs.br +0 -0
  90. package/dist/chunk-HDKHZKSW.mjs.gz +0 -0
  91. package/dist/chunk-LIQGO45T.mjs.br +0 -0
  92. package/dist/chunk-LIQGO45T.mjs.gz +0 -0
  93. package/dist/chunk-LTEDT475.js.br +0 -0
  94. package/dist/chunk-LTEDT475.js.gz +0 -0
  95. package/dist/chunk-MJAEB43A.js.br +0 -0
  96. package/dist/chunk-MJAEB43A.js.gz +0 -0
  97. package/dist/chunk-NVH3RIN7.js.br +0 -0
  98. package/dist/chunk-NVH3RIN7.js.gz +0 -0
  99. package/dist/chunk-OSSVKJGF.js.br +0 -0
  100. package/dist/chunk-OSSVKJGF.js.gz +0 -0
  101. package/dist/chunk-TGVID6BB.mjs.br +0 -0
  102. package/dist/chunk-TGVID6BB.mjs.gz +0 -0
  103. package/dist/chunk-VOV2N3NY.mjs.br +0 -0
  104. package/dist/chunk-VOV2N3NY.mjs.gz +0 -0
  105. package/dist/chunk-WJKMTDXS.mjs.br +0 -0
@@ -1634,7 +1634,7 @@ function decompressEotFont(fontData, compressed, encrypted) {
1634
1634
  return decompressMtx(fontData, { encrypted});
1635
1635
  }
1636
1636
 
1637
- // ../../node_modules/.bun/emf-converter@2.0.0/node_modules/emf-converter/dist/index.mjs
1637
+ // ../../node_modules/.bun/emf-converter@2.0.2/node_modules/emf-converter/dist/index.mjs
1638
1638
  function colorRefToHex(r, g, b) {
1639
1639
  const toHex4 = (v) => v.toString(16).padStart(2, "0");
1640
1640
  return `#${toHex4(r & 255)}${toHex4(g & 255)}${toHex4(b & 255)}`;
@@ -2053,19 +2053,22 @@ function mapFontFamily(face, map) {
2053
2053
  }
2054
2054
  return resolved;
2055
2055
  }
2056
- function applyFont(ctx, state) {
2056
+ function fontSizePx(state, scale = 1) {
2057
+ return Math.max(Math.abs(state.fontHeight) * Math.abs(scale || 1), 8);
2058
+ }
2059
+ function applyFont(ctx, state, scale = 1) {
2057
2060
  const italic = state.fontItalic ? "italic " : "";
2058
2061
  const weight = cssFontWeight(state.fontWeight);
2059
2062
  const weightPart = weight ? `${weight} ` : "";
2060
- const size = Math.max(Math.abs(state.fontHeight), 8);
2063
+ const size = fontSizePx(state, scale);
2061
2064
  const family = mapFontFamily(state.fontFamily, state.fontFamilyMap);
2062
2065
  ctx.font = `${italic}${weightPart}${size}px ${family}`;
2063
2066
  }
2064
- function drawTextDecorations(ctx, state, x, y, width) {
2067
+ function drawTextDecorations(ctx, state, x, y, width, scale = 1) {
2065
2068
  if (!state.fontUnderline && !state.fontStrikeOut) {
2066
2069
  return;
2067
2070
  }
2068
- const size = Math.max(Math.abs(state.fontHeight), 8);
2071
+ const size = fontSizePx(state, scale);
2069
2072
  const thickness = Math.max(1, Math.round(size / 14));
2070
2073
  const prevFill = ctx.fillStyle;
2071
2074
  ctx.fillStyle = state.textColor;
@@ -3014,7 +3017,8 @@ function handleExtTextOutW(rCtx, offset, dataOff, recSize) {
3014
3017
  if (nChars > 0 && offString > 0 && offset + offString + nChars * 2 <= maxOffset) {
3015
3018
  const text2 = readUtf16LE(view, offset + offString, nChars);
3016
3019
  if (text2.length > 0) {
3017
- applyFont(ctx, state);
3020
+ const fontScale = Math.abs(gmh(rCtx, 1));
3021
+ applyFont(ctx, state, fontScale);
3018
3022
  ctx.fillStyle = state.textColor;
3019
3023
  const vAlign = state.textAlign & 24;
3020
3024
  const alignBaseline = vAlign === 24 ? "alphabetic" : vAlign === 8 ? "bottom" : "top";
@@ -3029,7 +3033,7 @@ function handleExtTextOutW(rCtx, offset, dataOff, recSize) {
3029
3033
  ctx.textAlign = alignHoriz;
3030
3034
  if (state.bkMode === 2) {
3031
3035
  const measured = ctx.measureText(text2);
3032
- const bgH = state.fontHeight || 12;
3036
+ const bgH = fontSizePx(state, fontScale);
3033
3037
  ctx.fillStyle = state.bkColor;
3034
3038
  ctx.fillRect(gmx(rCtx, refX), gmy(rCtx, refY) - bgH, measured.width, bgH);
3035
3039
  ctx.fillStyle = state.textColor;
@@ -3039,7 +3043,7 @@ function handleExtTextOutW(rCtx, offset, dataOff, recSize) {
3039
3043
  const w = ctx.measureText(text2).width;
3040
3044
  const baseX = gmx(rCtx, refX);
3041
3045
  const startX = alignHoriz === "center" ? baseX - w / 2 : alignHoriz === "right" ? baseX - w : baseX;
3042
- drawTextDecorations(ctx, state, startX, gmy(rCtx, refY), w);
3046
+ drawTextDecorations(ctx, state, startX, gmy(rCtx, refY), w, fontScale);
3043
3047
  }
3044
3048
  }
3045
3049
  }
@@ -6193,7 +6197,7 @@ function handleWmfDrawRecord(wCtx, recType, offset, dataOff, recSize) {
6193
6197
  if (txOff + 4 <= offset + recSize) {
6194
6198
  const ty2 = view.getInt16(txOff, true);
6195
6199
  const txCoord = view.getInt16(txOff + 2, true);
6196
- applyFont(ctx, state);
6200
+ applyFont(ctx, state, Math.abs(mh(1)));
6197
6201
  ctx.fillStyle = state.textColor;
6198
6202
  ctx.fillText(text2, mx(txCoord), my(ty2));
6199
6203
  }
@@ -6216,7 +6220,7 @@ function handleWmfDrawRecord(wCtx, recType, offset, dataOff, recSize) {
6216
6220
  }
6217
6221
  text2 += String.fromCharCode(ch);
6218
6222
  }
6219
- applyFont(ctx, state);
6223
+ applyFont(ctx, state, Math.abs(mh(1)));
6220
6224
  ctx.fillStyle = state.textColor;
6221
6225
  ctx.fillText(text2, mx(txCoord), my(ty2));
6222
6226
  }
@@ -12657,9 +12661,9 @@ var PptxEffectDagExtractor = class {
12657
12661
  if (Number.isFinite(endPos)) {
12658
12662
  style.reflectionEndPosition = endPos / 1e5;
12659
12663
  }
12660
- const dist = parseInt(String(refl["@_dist"] || ""), 10);
12661
- if (Number.isFinite(dist) && dist >= 0) {
12662
- style.reflectionDistance = dist / this.context.emuPerPx;
12664
+ const dist2 = parseInt(String(refl["@_dist"] || ""), 10);
12665
+ if (Number.isFinite(dist2) && dist2 >= 0) {
12666
+ style.reflectionDistance = dist2 / this.context.emuPerPx;
12663
12667
  }
12664
12668
  }
12665
12669
  extractDagBlur(dag, style) {
@@ -13806,10 +13810,7 @@ var PptxShapeStyleExtractor = class {
13806
13810
  }
13807
13811
  const lineNode = shapeProps["a:ln"];
13808
13812
  if (lineNode) {
13809
- const earlyReturn = applyLineProperties(lineNode, style, this.context);
13810
- if (earlyReturn) {
13811
- return style;
13812
- }
13813
+ applyLineProperties(lineNode, style, this.context);
13813
13814
  } else if (styleNode?.["a:lnRef"]) {
13814
13815
  this.context.resolveThemeLineRef(styleNode["a:lnRef"], style);
13815
13816
  }
@@ -20390,6 +20391,11 @@ var STANDARD_TRANSITION_TYPES = /* @__PURE__ */ new Set([
20390
20391
  ]);
20391
20392
  var SPEEDS = /* @__PURE__ */ new Set(["slow", "med", "fast"]);
20392
20393
  var UINT_MAX = 4294967295;
20394
+ var MORPH_OPTIONS = /* @__PURE__ */ new Set(["byObject", "byWord", "byChar"]);
20395
+ function normalizeMorphOption(value) {
20396
+ const candidate = token(value);
20397
+ return MORPH_OPTIONS.has(candidate) ? candidate : void 0;
20398
+ }
20393
20399
  function parseTransitionDetails(node, localName22) {
20394
20400
  const result = { type: "cut" };
20395
20401
  for (const [key, value] of Object.entries(node)) {
@@ -20405,6 +20411,11 @@ function parseTransitionDetails(node, localName22) {
20405
20411
  result.rawExtLst = value;
20406
20412
  continue;
20407
20413
  }
20414
+ if (name === "morph") {
20415
+ result.type = "morph";
20416
+ result.morphOption = normalizeMorphOption(value?.["@_option"]);
20417
+ continue;
20418
+ }
20408
20419
  if (STANDARD_TRANSITION_TYPES.has(name)) {
20409
20420
  result.type = name;
20410
20421
  }
@@ -20604,6 +20615,7 @@ var PptxSlideTransitionService = class {
20604
20615
  let transitionType = details.type;
20605
20616
  let { direction, orient, pattern } = details;
20606
20617
  const { spokes, thruBlk, rawSoundAction, rawExtLst } = details;
20618
+ let { morphOption } = details;
20607
20619
  if (rawExtLst && transitionType === "cut") {
20608
20620
  const p14Result = parseP14FromExtLst(rawExtLst, this.xmlLookupService, this.getXmlLocalName);
20609
20621
  const p15Result = p14Result ? void 0 : parseP15FromExtLst(rawExtLst, this.xmlLookupService, this.getXmlLocalName);
@@ -20620,8 +20632,12 @@ var PptxSlideTransitionService = class {
20620
20632
  }
20621
20633
  } else if (p15Result) {
20622
20634
  transitionType = p15Result.type;
20623
- } else if (this.parseMorphFromExtLst(rawExtLst)) {
20624
- transitionType = "morph";
20635
+ } else {
20636
+ const morphResult = this.parseMorphFromExtLst(rawExtLst);
20637
+ if (morphResult) {
20638
+ transitionType = "morph";
20639
+ morphOption = morphResult.morphOption;
20640
+ }
20625
20641
  }
20626
20642
  }
20627
20643
  const attributes = parseTransitionAttributes(transitionNode);
@@ -20634,6 +20650,7 @@ var PptxSlideTransitionService = class {
20634
20650
  spokes,
20635
20651
  pattern,
20636
20652
  thruBlk,
20653
+ morphOption,
20637
20654
  ...sound,
20638
20655
  rawSoundAction,
20639
20656
  rawExtLst,
@@ -20679,21 +20696,18 @@ var PptxSlideTransitionService = class {
20679
20696
  if (!ext) {
20680
20697
  continue;
20681
20698
  }
20682
- const uri = String(ext["@_uri"] || "").trim();
20683
- const matchesUri = uri.toUpperCase() === MORPH_EXT_URI.toUpperCase();
20684
- for (const key of Object.keys(ext)) {
20699
+ for (const [key, value] of Object.entries(ext)) {
20685
20700
  if (key.startsWith("@_")) {
20686
20701
  continue;
20687
20702
  }
20688
20703
  if (this.getXmlLocalName(key) === "morph") {
20689
- if (matchesUri || uri.length === 0) {
20690
- return true;
20691
- }
20692
- return true;
20704
+ return {
20705
+ morphOption: normalizeMorphOption(value?.["@_option"])
20706
+ };
20693
20707
  }
20694
20708
  }
20695
20709
  }
20696
- return false;
20710
+ return void 0;
20697
20711
  }
20698
20712
  buildSlideTransitionXml(transition) {
20699
20713
  if (!transition || transition.type === "none") {
@@ -20717,7 +20731,9 @@ var PptxSlideTransitionService = class {
20717
20731
  } else if (isP15Type) {
20718
20732
  node["p:extLst"] = transition.rawExtLst ?? buildP15ExtLst(transitionType);
20719
20733
  } else if (isMorphType) {
20720
- node["p:extLst"] = this.buildMorphExtLst(transition.rawExtLst);
20734
+ if (!this.hasDirectMorphChild(node)) {
20735
+ node["p:extLst"] = this.buildMorphExtLst(transition.rawExtLst, transition.morphOption);
20736
+ }
20721
20737
  } else {
20722
20738
  node[`p:${transitionType}`] = buildStandardTransitionChild(transition);
20723
20739
  }
@@ -20731,16 +20747,32 @@ var PptxSlideTransitionService = class {
20731
20747
  }
20732
20748
  return node;
20733
20749
  }
20750
+ /**
20751
+ * True when the (preserved) transition node already carries a `morph`
20752
+ * element as a direct child, in any namespace prefix.
20753
+ */
20754
+ hasDirectMorphChild(node) {
20755
+ for (const key of Object.keys(node)) {
20756
+ if (!key.startsWith("@_") && this.getXmlLocalName(key) === "morph") {
20757
+ return true;
20758
+ }
20759
+ }
20760
+ return false;
20761
+ }
20734
20762
  /**
20735
20763
  * Build the extLst XML node for a morph (p159) transition, preserving any
20736
20764
  * non-morph extensions from rawExtLst.
20737
20765
  */
20738
- buildMorphExtLst(rawExtLst) {
20766
+ buildMorphExtLst(rawExtLst, morphOption) {
20767
+ const morphNode = {
20768
+ "@_xmlns:p159": "http://schemas.microsoft.com/office/powerpoint/2015/09/main"
20769
+ };
20770
+ if (morphOption) {
20771
+ morphNode["@_option"] = morphOption;
20772
+ }
20739
20773
  const morphExt = {
20740
20774
  "@_uri": MORPH_EXT_URI,
20741
- "p159:morph": {
20742
- "@_xmlns:p159": "http://schemas.microsoft.com/office/powerpoint/2015/09/main"
20743
- }
20775
+ "p159:morph": morphNode
20744
20776
  };
20745
20777
  if (!rawExtLst) {
20746
20778
  return { "p:ext": morphExt };
@@ -40957,12 +40989,12 @@ function estimateTextBoxCapacity(element) {
40957
40989
  if (fontSizePt <= 0) {
40958
40990
  fontSizePt = DEFAULT_FONT_SIZE_PT;
40959
40991
  }
40960
- const fontSizePx = fontSizePt * (4 / 3);
40992
+ const fontSizePx2 = fontSizePt * (4 / 3);
40961
40993
  const lineHeightMultiplier = style?.lineSpacing ?? DEFAULT_LINE_HEIGHT_MULTIPLIER;
40962
- const lineHeightPx = fontSizePx * lineHeightMultiplier;
40994
+ const lineHeightPx = fontSizePx2 * lineHeightMultiplier;
40963
40995
  const charsPerLine = Math.max(
40964
40996
  1,
40965
- Math.floor(availableWidth / (fontSizePx * AVG_CHAR_WIDTH_RATIO))
40997
+ Math.floor(availableWidth / (fontSizePx2 * AVG_CHAR_WIDTH_RATIO))
40966
40998
  );
40967
40999
  const numLines = Math.max(1, Math.floor(availableHeight / lineHeightPx));
40968
41000
  return charsPerLine * numLines;
@@ -49661,17 +49693,17 @@ function buildShadowColorNode(hex10, opacity2) {
49661
49693
  };
49662
49694
  }
49663
49695
  function distAndDir(ox, oy) {
49664
- const dist = Math.sqrt(ox * ox + oy * oy);
49696
+ const dist2 = Math.sqrt(ox * ox + oy * oy);
49665
49697
  const dir = Math.atan2(oy, ox) * 180 / Math.PI;
49666
- return { dist, dir };
49698
+ return { dist: dist2, dir };
49667
49699
  }
49668
49700
  function buildOuterShadowNode(style) {
49669
49701
  const ox = style.textShadowOffsetX ?? 0;
49670
49702
  const oy = style.textShadowOffsetY ?? 0;
49671
- const { dist, dir } = distAndDir(ox, oy);
49703
+ const { dist: dist2, dir } = distAndDir(ox, oy);
49672
49704
  return {
49673
49705
  "@_blurRad": String(Math.round((style.textShadowBlur ?? 4) * EMU_PER_PX8)),
49674
- "@_dist": String(Math.round(dist * EMU_PER_PX8)),
49706
+ "@_dist": String(Math.round(dist2 * EMU_PER_PX8)),
49675
49707
  "@_dir": String(Math.round(dir * 6e4)),
49676
49708
  "a:srgbClr": buildShadowColorNode(style.textShadowColor || "#000000", style.textShadowOpacity)
49677
49709
  };
@@ -49679,10 +49711,10 @@ function buildOuterShadowNode(style) {
49679
49711
  function buildInnerShadowNode(style) {
49680
49712
  const ox = style.textInnerShadowOffsetX ?? 0;
49681
49713
  const oy = style.textInnerShadowOffsetY ?? 0;
49682
- const { dist, dir } = distAndDir(ox, oy);
49714
+ const { dist: dist2, dir } = distAndDir(ox, oy);
49683
49715
  return {
49684
49716
  "@_blurRad": String(Math.round((style.textInnerShadowBlur ?? 3) * EMU_PER_PX8)),
49685
- "@_dist": String(Math.round(dist * EMU_PER_PX8)),
49717
+ "@_dist": String(Math.round(dist2 * EMU_PER_PX8)),
49686
49718
  "@_dir": String(Math.round(dir * 6e4)),
49687
49719
  "a:srgbClr": buildShadowColorNode(
49688
49720
  style.textInnerShadowColor || "#000000",
@@ -51308,10 +51340,10 @@ var PptxHandlerRuntime18 = class extends PptxHandlerRuntime17 {
51308
51340
  const distRaw = Number.parseInt(String(outerShdw["@_dist"] || ""), 10);
51309
51341
  const dirRaw = Number.parseInt(String(outerShdw["@_dir"] || ""), 10);
51310
51342
  if (Number.isFinite(distRaw) && distRaw >= 0) {
51311
- const dist = distRaw / PptxHandlerRuntime17.EMU_PER_PX;
51343
+ const dist2 = distRaw / PptxHandlerRuntime17.EMU_PER_PX;
51312
51344
  const dirRad = (Number.isFinite(dirRaw) ? dirRaw / 6e4 : 0) * Math.PI / 180;
51313
- style.textShadowOffsetX = Math.round(Math.cos(dirRad) * dist * 100) / 100;
51314
- style.textShadowOffsetY = Math.round(Math.sin(dirRad) * dist * 100) / 100;
51345
+ style.textShadowOffsetX = Math.round(Math.cos(dirRad) * dist2 * 100) / 100;
51346
+ style.textShadowOffsetY = Math.round(Math.sin(dirRad) * dist2 * 100) / 100;
51315
51347
  }
51316
51348
  }
51317
51349
  const glowNode = runEffectList["a:glow"];
@@ -62901,6 +62933,12 @@ var PptxHandlerRuntime62 = class _PptxHandlerRuntime26 extends PptxHandlerRuntim
62901
62933
  ...endParagraphStyle,
62902
62934
  ...defaultRunStyle
62903
62935
  };
62936
+ if (mergedDefaultRunStyle.color === void 0 && ctx.styleFontRefColor !== void 0) {
62937
+ mergedDefaultRunStyle.color = ctx.styleFontRefColor;
62938
+ }
62939
+ if (mergedDefaultRunStyle.fontFamily === void 0 && ctx.styleFontRefTypeface !== void 0) {
62940
+ mergedDefaultRunStyle.fontFamily = ctx.styleFontRefTypeface;
62941
+ }
62904
62942
  if (ctx.effectiveLevelStyles) {
62905
62943
  const normalizedLevel = level === -1 ? -1 : Number.isFinite(level) ? Math.min(Math.max(level, 0), 8) : 0;
62906
62944
  const phLevel = ctx.effectiveLevelStyles[normalizedLevel] ?? ctx.effectiveLevelStyles[-1] ?? (normalizedLevel === -1 ? ctx.effectiveLevelStyles[0] : void 0);
@@ -62973,10 +63011,17 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
62973
63011
  } else {
62974
63012
  bulletText = "\u2022 ";
62975
63013
  }
63014
+ const bulletStyle = { ...mergedDefaultRunStyle };
63015
+ if (paragraphBulletInfo.sizePercent === void 0 && paragraphBulletInfo.sizePts === void 0) {
63016
+ const firstRunSize = this.resolveFirstRunFontSize(p, paraAlign, ctx);
63017
+ if (firstRunSize !== void 0) {
63018
+ bulletStyle.fontSize = firstRunSize;
63019
+ }
63020
+ }
62976
63021
  parts.push(bulletText);
62977
63022
  segments.push({
62978
63023
  text: bulletText,
62979
- style: { ...mergedDefaultRunStyle },
63024
+ style: bulletStyle,
62980
63025
  bulletInfo: paragraphBulletInfo
62981
63026
  });
62982
63027
  maybeSeed(mergedDefaultRunStyle);
@@ -63186,6 +63231,32 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
63186
63231
  }
63187
63232
  return { parts, segments, seedStyle };
63188
63233
  }
63234
+ /**
63235
+ * Font size (px) of the first text run in a paragraph, or `undefined` when
63236
+ * the paragraph has no run that declares one.
63237
+ *
63238
+ * Used to size an unsized bullet the way PowerPoint does: `a:buChar` /
63239
+ * `a:buAutoNum` with no `a:buSzPct`/`a:buSzPts` inherits the first run's
63240
+ * size. Only `a:r` and `a:fld` carry renderable text; `a:br` does not.
63241
+ */
63242
+ resolveFirstRunFontSize(p, paraAlign, ctx) {
63243
+ for (const key of ["a:r", "a:fld"]) {
63244
+ const node = p[key];
63245
+ if (!node) {
63246
+ continue;
63247
+ }
63248
+ const first = this.ensureArray(node)[0];
63249
+ const runProps = first?.["a:rPr"];
63250
+ if (!runProps) {
63251
+ continue;
63252
+ }
63253
+ const style = this.extractTextRunStyle(runProps, paraAlign, ctx.slideRelationshipMap);
63254
+ if (typeof style.fontSize === "number") {
63255
+ return style.fontSize;
63256
+ }
63257
+ }
63258
+ return void 0;
63259
+ }
63189
63260
  /**
63190
63261
  * Parse an `a:ruby` element into a {@link TextSegment} with ruby annotation metadata.
63191
63262
  *
@@ -63407,15 +63478,13 @@ var PptxHandlerRuntime64 = class _PptxHandlerRuntime27 extends PptxHandlerRuntim
63407
63478
  Object.assign(textStyle, bodyDefaultRunStyle);
63408
63479
  const fontRef = styleNode?.["a:fontRef"];
63409
63480
  const fontRefIdx = String(fontRef?.["@_idx"] || "").toLowerCase();
63410
- if (!textStyle.fontFamily && fontRefIdx.length > 0) {
63411
- const token2 = fontRefIdx.includes("minor") ? "+mn-lt" : "+mj-lt";
63412
- const resolved = this.resolveThemeTypeface(token2);
63413
- if (resolved) {
63414
- textStyle.fontFamily = resolved;
63415
- }
63481
+ const styleFontRefTypeface = fontRefIdx.length > 0 ? this.resolveThemeTypeface(fontRefIdx.includes("minor") ? "+mn-lt" : "+mj-lt") : void 0;
63482
+ const styleFontRefColor = fontRef ? this.parseColor(fontRef) : void 0;
63483
+ if (!textStyle.fontFamily && styleFontRefTypeface) {
63484
+ textStyle.fontFamily = styleFontRefTypeface;
63416
63485
  }
63417
63486
  if (!textStyle.color) {
63418
- textStyle.color = this.parseColor(fontRef);
63487
+ textStyle.color = styleFontRefColor;
63419
63488
  }
63420
63489
  const bodyPr = txBody?.["a:bodyPr"] || inheritedTxBody?.["a:bodyPr"];
63421
63490
  const bodyPropResult = this.applyBodyProperties(
@@ -63446,7 +63515,9 @@ var PptxHandlerRuntime64 = class _PptxHandlerRuntime27 extends PptxHandlerRuntim
63446
63515
  placeholderInfo: placeholderInfo ?? void 0,
63447
63516
  phDefaults,
63448
63517
  slidePath,
63449
- effectiveLevelStyles
63518
+ effectiveLevelStyles,
63519
+ styleFontRefColor,
63520
+ styleFontRefTypeface
63450
63521
  };
63451
63522
  paras.forEach((p, pIdx) => {
63452
63523
  const styleResult = this.resolveShapeParagraphStyle(p, textStyle, ctx);
@@ -66356,12 +66427,12 @@ var PptxHandlerRuntime77 = class _PptxHandlerRuntime33 extends PptxHandlerRuntim
66356
66427
  if (Number.isFinite(blurRad) && blurRad > 0) {
66357
66428
  result.shadowBlur = blurRad / _PptxHandlerRuntime33.EMU_PER_PX;
66358
66429
  }
66359
- const dist = parseInt(String(outerShdw["@_dist"] || "0"));
66430
+ const dist2 = parseInt(String(outerShdw["@_dist"] || "0"));
66360
66431
  const dir = parseInt(String(outerShdw["@_dir"] || "0"));
66361
- if (Number.isFinite(dist) && dist > 0 && Number.isFinite(dir)) {
66432
+ if (Number.isFinite(dist2) && dist2 > 0 && Number.isFinite(dir)) {
66362
66433
  const angleRad = dir / 6e4 * (Math.PI / 180);
66363
- result.shadowOffsetX = Math.cos(angleRad) * dist / _PptxHandlerRuntime33.EMU_PER_PX;
66364
- result.shadowOffsetY = Math.sin(angleRad) * dist / _PptxHandlerRuntime33.EMU_PER_PX;
66434
+ result.shadowOffsetX = Math.cos(angleRad) * dist2 / _PptxHandlerRuntime33.EMU_PER_PX;
66435
+ result.shadowOffsetY = Math.sin(angleRad) * dist2 / _PptxHandlerRuntime33.EMU_PER_PX;
66365
66436
  }
66366
66437
  }
66367
66438
  const innerShdw = effectLst["a:innerShdw"];
@@ -66372,12 +66443,12 @@ var PptxHandlerRuntime77 = class _PptxHandlerRuntime33 extends PptxHandlerRuntim
66372
66443
  if (Number.isFinite(blurRad) && blurRad > 0) {
66373
66444
  result.innerShadowBlur = blurRad / _PptxHandlerRuntime33.EMU_PER_PX;
66374
66445
  }
66375
- const dist = parseInt(String(innerShdw["@_dist"] || "0"));
66446
+ const dist2 = parseInt(String(innerShdw["@_dist"] || "0"));
66376
66447
  const dir = parseInt(String(innerShdw["@_dir"] || "0"));
66377
- if (Number.isFinite(dist) && dist > 0 && Number.isFinite(dir)) {
66448
+ if (Number.isFinite(dist2) && dist2 > 0 && Number.isFinite(dir)) {
66378
66449
  const angleRad = dir / 6e4 * (Math.PI / 180);
66379
- result.innerShadowOffsetX = Math.cos(angleRad) * dist / _PptxHandlerRuntime33.EMU_PER_PX;
66380
- result.innerShadowOffsetY = Math.sin(angleRad) * dist / _PptxHandlerRuntime33.EMU_PER_PX;
66450
+ result.innerShadowOffsetX = Math.cos(angleRad) * dist2 / _PptxHandlerRuntime33.EMU_PER_PX;
66451
+ result.innerShadowOffsetY = Math.sin(angleRad) * dist2 / _PptxHandlerRuntime33.EMU_PER_PX;
66381
66452
  }
66382
66453
  }
66383
66454
  const glow = effectLst["a:glow"];
@@ -66422,9 +66493,9 @@ var PptxHandlerRuntime77 = class _PptxHandlerRuntime33 extends PptxHandlerRuntim
66422
66493
  if (Number.isFinite(rot)) {
66423
66494
  result.reflectionRotation = rot / 6e4;
66424
66495
  }
66425
- const dist = parseInt(String(reflection["@_dist"] || "0"));
66426
- if (Number.isFinite(dist) && dist >= 0) {
66427
- result.reflectionDistance = dist / _PptxHandlerRuntime33.EMU_PER_PX;
66496
+ const dist2 = parseInt(String(reflection["@_dist"] || "0"));
66497
+ if (Number.isFinite(dist2) && dist2 >= 0) {
66498
+ result.reflectionDistance = dist2 / _PptxHandlerRuntime33.EMU_PER_PX;
66428
66499
  }
66429
66500
  }
66430
66501
  const scene3dNode = es["a:scene3d"];
@@ -97944,6 +98015,789 @@ function sanitizeMathMl(markup) {
97944
98015
  }
97945
98016
  return sanitized;
97946
98017
  }
98018
+ function resolveParagraphStrutFontSize(segments, bodyFontSize) {
98019
+ let largest;
98020
+ for (const segment of segments) {
98021
+ if (segment.bulletInfo) {
98022
+ continue;
98023
+ }
98024
+ const size = segment.style?.fontSize;
98025
+ if (typeof size !== "number" || !Number.isFinite(size) || size <= 0) {
98026
+ continue;
98027
+ }
98028
+ if (largest === void 0 || size > largest) {
98029
+ largest = size;
98030
+ }
98031
+ }
98032
+ if (largest === void 0) {
98033
+ return void 0;
98034
+ }
98035
+ if (typeof bodyFontSize === "number" && Math.abs(largest - bodyFontSize) < 0.01) {
98036
+ return void 0;
98037
+ }
98038
+ return largest;
98039
+ }
98040
+ function parseHexColor(hex10) {
98041
+ if (!hex10 || typeof hex10 !== "string") {
98042
+ return null;
98043
+ }
98044
+ let cleaned = hex10.replace(/^#/u, "");
98045
+ if (cleaned.length === 3) {
98046
+ cleaned = cleaned[0] + cleaned[0] + cleaned[1] + cleaned[1] + cleaned[2] + cleaned[2];
98047
+ } else if (cleaned.length === 4) {
98048
+ cleaned = cleaned[0] + cleaned[0] + cleaned[1] + cleaned[1] + cleaned[2] + cleaned[2] + cleaned[3] + cleaned[3];
98049
+ }
98050
+ if (cleaned.length !== 6 && cleaned.length !== 8) {
98051
+ return null;
98052
+ }
98053
+ const r = Number.parseInt(cleaned.slice(0, 2), 16);
98054
+ const g = Number.parseInt(cleaned.slice(2, 4), 16);
98055
+ const b = Number.parseInt(cleaned.slice(4, 6), 16);
98056
+ const a = cleaned.length === 8 ? Number.parseInt(cleaned.slice(6, 8), 16) / 255 : 1;
98057
+ if ([r, g, b].some((v) => Number.isNaN(v))) {
98058
+ return null;
98059
+ }
98060
+ return { r, g, b, a: Number.isNaN(a) ? 1 : a };
98061
+ }
98062
+ function lerpColor2(from, to, t) {
98063
+ const clamped = Math.max(0, Math.min(1, t));
98064
+ const r = Math.round(from.r + (to.r - from.r) * clamped);
98065
+ const g = Math.round(from.g + (to.g - from.g) * clamped);
98066
+ const b = Math.round(from.b + (to.b - from.b) * clamped);
98067
+ const a = Number((from.a + (to.a - from.a) * clamped).toFixed(3));
98068
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
98069
+ }
98070
+ var OUTLINE_SAMPLE_COUNT = 64;
98071
+ var ELLIPSE_SAMPLE_COUNT = 48;
98072
+ function resolveLength(token2, axis) {
98073
+ const trimmed = token2.trim();
98074
+ if (trimmed.endsWith("%")) {
98075
+ const pct = Number.parseFloat(trimmed.slice(0, -1));
98076
+ return Number.isFinite(pct) ? pct / 100 * axis : 0;
98077
+ }
98078
+ const px3 = Number.parseFloat(trimmed.replace(/px$/u, ""));
98079
+ return Number.isFinite(px3) ? px3 : 0;
98080
+ }
98081
+ function polygonClipToPoints(value, width, height) {
98082
+ const inner = value.slice(value.indexOf("(") + 1, value.lastIndexOf(")"));
98083
+ const points3 = [];
98084
+ for (const pairStr of inner.split(",")) {
98085
+ const parts = pairStr.trim().split(/\s+/u);
98086
+ if (parts.length < 2) {
98087
+ continue;
98088
+ }
98089
+ points3.push({
98090
+ x: resolveLength(parts[0], width),
98091
+ y: resolveLength(parts[1], height)
98092
+ });
98093
+ }
98094
+ return points3;
98095
+ }
98096
+ function insetClipToPoints(value, width, height) {
98097
+ const inner = value.slice(value.indexOf("(") + 1, value.lastIndexOf(")"));
98098
+ const tokens = inner.split(/round/u)[0].trim().split(/\s+/u);
98099
+ const top = resolveLength(tokens[0] ?? "0", height);
98100
+ const right = resolveLength(tokens[1] ?? tokens[0] ?? "0", width);
98101
+ const bottom = resolveLength(tokens[2] ?? tokens[0] ?? "0", height);
98102
+ const left = resolveLength(tokens[3] ?? tokens[1] ?? tokens[0] ?? "0", width);
98103
+ return [
98104
+ { x: left, y: top },
98105
+ { x: width - right, y: top },
98106
+ { x: width - right, y: height - bottom },
98107
+ { x: left, y: height - bottom }
98108
+ ];
98109
+ }
98110
+ function ellipseClipToPoints(value, width, height) {
98111
+ const isCircle = value.startsWith("circle");
98112
+ const inner = value.slice(value.indexOf("(") + 1, value.lastIndexOf(")"));
98113
+ const [radii, position2] = inner.split(/\s+at\s+/u);
98114
+ const radiusTokens = radii.trim().split(/\s+/u).filter(Boolean);
98115
+ let rx = width / 2;
98116
+ let ry = height / 2;
98117
+ if (isCircle) {
98118
+ const r = resolveLength(radiusTokens[0] ?? "50%", Math.min(width, height));
98119
+ rx = r;
98120
+ ry = r;
98121
+ } else {
98122
+ rx = resolveLength(radiusTokens[0] ?? "50%", width);
98123
+ ry = resolveLength(radiusTokens[1] ?? radiusTokens[0] ?? "50%", height);
98124
+ }
98125
+ let cx = width / 2;
98126
+ let cy = height / 2;
98127
+ if (position2) {
98128
+ const posTokens = position2.trim().split(/\s+/u);
98129
+ cx = resolveLength(posTokens[0] ?? "50%", width);
98130
+ cy = resolveLength(posTokens[1] ?? posTokens[0] ?? "50%", height);
98131
+ }
98132
+ const points3 = [];
98133
+ for (let i = 0; i < ELLIPSE_SAMPLE_COUNT; i++) {
98134
+ const a = i / ELLIPSE_SAMPLE_COUNT * Math.PI * 2;
98135
+ points3.push({ x: cx + Math.cos(a) * rx, y: cy + Math.sin(a) * ry });
98136
+ }
98137
+ return points3;
98138
+ }
98139
+ function clipPathToPolygon(value, width, height) {
98140
+ const v = value.trim();
98141
+ if (v.startsWith("polygon")) {
98142
+ return polygonClipToPoints(v, width, height);
98143
+ }
98144
+ if (v.startsWith("inset")) {
98145
+ return insetClipToPoints(v, width, height);
98146
+ }
98147
+ if (v.startsWith("ellipse") || v.startsWith("circle")) {
98148
+ return ellipseClipToPoints(v, width, height);
98149
+ }
98150
+ if (v.startsWith("path")) {
98151
+ const start = v.indexOf("'") >= 0 ? v.indexOf("'") : v.indexOf('"');
98152
+ const end = v.lastIndexOf("'") >= 0 ? v.lastIndexOf("'") : v.lastIndexOf('"');
98153
+ if (start >= 0 && end > start) {
98154
+ const d = v.slice(start + 1, end);
98155
+ const polys = svgPathToPolygons(d);
98156
+ if (polys.length === 0) {
98157
+ return [];
98158
+ }
98159
+ return polys.reduce((a, b) => b.length > a.length ? b : a);
98160
+ }
98161
+ }
98162
+ return [];
98163
+ }
98164
+ function resolveElementOutline(element) {
98165
+ const width = Math.max(element.width, 1);
98166
+ const height = Math.max(element.height, 1);
98167
+ const shapeType = element.shapeType;
98168
+ const adjustments = element.shapeAdjustments;
98169
+ const clip = getResolvedShapeClipPathFor(shapeType, width, height, adjustments);
98170
+ if (clip) {
98171
+ const poly = clipPathToPolygon(clip, width, height);
98172
+ if (poly.length >= 3) {
98173
+ return poly;
98174
+ }
98175
+ }
98176
+ return [
98177
+ { x: 0, y: 0 },
98178
+ { x: width, y: 0 },
98179
+ { x: width, y: height },
98180
+ { x: 0, y: height }
98181
+ ];
98182
+ }
98183
+ function dist(a, b) {
98184
+ return Math.hypot(a.x - b.x, a.y - b.y);
98185
+ }
98186
+ function resamplePolygon(poly, count) {
98187
+ if (poly.length < 2) {
98188
+ return Array.from({ length: count }, () => ({ x: poly[0]?.x ?? 0, y: poly[0]?.y ?? 0 }));
98189
+ }
98190
+ const ring = [...poly, poly[0]];
98191
+ const segLen = [];
98192
+ let total = 0;
98193
+ for (let i = 0; i < ring.length - 1; i++) {
98194
+ const d = dist(ring[i], ring[i + 1]);
98195
+ segLen.push(d);
98196
+ total += d;
98197
+ }
98198
+ if (total === 0) {
98199
+ return Array.from({ length: count }, () => ({ x: poly[0].x, y: poly[0].y }));
98200
+ }
98201
+ const result = [];
98202
+ const step = total / count;
98203
+ let seg = 0;
98204
+ let segStart = 0;
98205
+ for (let i = 0; i < count; i++) {
98206
+ const target = i * step;
98207
+ while (seg < segLen.length - 1 && segStart + segLen[seg] < target) {
98208
+ segStart += segLen[seg];
98209
+ seg++;
98210
+ }
98211
+ const within = segLen[seg] > 0 ? (target - segStart) / segLen[seg] : 0;
98212
+ const a = ring[seg];
98213
+ const b = ring[seg + 1];
98214
+ result.push({ x: a.x + (b.x - a.x) * within, y: a.y + (b.y - a.y) * within });
98215
+ }
98216
+ return result;
98217
+ }
98218
+ function signedArea2(poly) {
98219
+ let area = 0;
98220
+ for (let i = 0; i < poly.length; i++) {
98221
+ const a = poly[i];
98222
+ const b = poly[(i + 1) % poly.length];
98223
+ area += a.x * b.y - b.x * a.y;
98224
+ }
98225
+ return area / 2;
98226
+ }
98227
+ function rotateRing(poly, offset) {
98228
+ const n = poly.length;
98229
+ const o = (offset % n + n) % n;
98230
+ return poly.slice(o).concat(poly.slice(0, o));
98231
+ }
98232
+ function bestRotation(from, to) {
98233
+ let bestOffset = 0;
98234
+ let bestCost = Infinity;
98235
+ for (let offset = 0; offset < to.length; offset++) {
98236
+ let cost = 0;
98237
+ for (let i = 0; i < from.length; i++) {
98238
+ const t = to[(i + offset) % to.length];
98239
+ const dx = from[i].x - t.x;
98240
+ const dy = from[i].y - t.y;
98241
+ cost += dx * dx + dy * dy;
98242
+ if (cost >= bestCost) {
98243
+ break;
98244
+ }
98245
+ }
98246
+ if (cost < bestCost) {
98247
+ bestCost = cost;
98248
+ bestOffset = offset;
98249
+ }
98250
+ }
98251
+ return bestOffset;
98252
+ }
98253
+ function normalizeOutlinePair(fromPoly, toPoly, count = OUTLINE_SAMPLE_COUNT) {
98254
+ const from = resamplePolygon(fromPoly, count);
98255
+ let to = resamplePolygon(toPoly, count);
98256
+ if (Math.sign(signedArea2(from)) !== Math.sign(signedArea2(to))) {
98257
+ to = [...to].reverse();
98258
+ }
98259
+ const offset = bestRotation(from, to);
98260
+ to = rotateRing(to, offset);
98261
+ return [from, to];
98262
+ }
98263
+ function interpolateOutline(from, to, t) {
98264
+ const clamped = Math.max(0, Math.min(1, t));
98265
+ const len = Math.min(from.length, to.length);
98266
+ if (len === 0) {
98267
+ return "";
98268
+ }
98269
+ const parts = [];
98270
+ for (let i = 0; i < len; i++) {
98271
+ const x = from[i].x + (to[i].x - from[i].x) * clamped;
98272
+ const y = from[i].y + (to[i].y - from[i].y) * clamped;
98273
+ parts.push(`${i === 0 ? "M" : "L"}${Number(x.toFixed(2))} ${Number(y.toFixed(2))}`);
98274
+ }
98275
+ parts.push("Z");
98276
+ return parts.join(" ");
98277
+ }
98278
+ var MORPH_EASING = "cubic-bezier(0.4, 0, 0.2, 1)";
98279
+ var PROXIMITY_THRESHOLD = 300;
98280
+ var GEOMETRY_MORPH_STEPS = 8;
98281
+ function shouldGeometryMorph(pair) {
98282
+ const fromType = pair.fromElement.shapeType;
98283
+ const toType = pair.toElement.shapeType;
98284
+ if (!fromType || !toType) {
98285
+ return false;
98286
+ }
98287
+ if (fromType.toLowerCase() !== toType.toLowerCase()) {
98288
+ return true;
98289
+ }
98290
+ const fromAdj = JSON.stringify(
98291
+ pair.fromElement.shapeAdjustments ?? {}
98292
+ );
98293
+ const toAdj = JSON.stringify(
98294
+ pair.toElement.shapeAdjustments ?? {}
98295
+ );
98296
+ return fromAdj !== toAdj;
98297
+ }
98298
+ function buildClipKeyframeBody(from, to, steps) {
98299
+ const [fromRing, toRing] = normalizeOutlinePair(
98300
+ resolveElementOutline(from),
98301
+ resolveElementOutline(to)
98302
+ );
98303
+ if (fromRing.length === 0 || toRing.length === 0) {
98304
+ return null;
98305
+ }
98306
+ const lines = [];
98307
+ for (let s = 0; s <= steps; s++) {
98308
+ const t = s / steps;
98309
+ const d = interpolateOutline(fromRing, toRing, t);
98310
+ if (!d) {
98311
+ return null;
98312
+ }
98313
+ const pct = Number((s / steps * 100).toFixed(2));
98314
+ lines.push(` ${pct}% {
98315
+ clip-path: path('${d}');
98316
+ }`);
98317
+ }
98318
+ return lines.join("\n");
98319
+ }
98320
+ function generateGeometryMorphAnimation(pair, durationMs, pairIndex, steps = GEOMETRY_MORPH_STEPS) {
98321
+ if (!shouldGeometryMorph(pair)) {
98322
+ return null;
98323
+ }
98324
+ const body = buildClipKeyframeBody(pair.fromElement, pair.toElement, steps);
98325
+ if (!body) {
98326
+ return null;
98327
+ }
98328
+ const safeName = `pptx-morph-geo-${pairIndex}-${pair.toElement.id.replace(/[^a-zA-Z0-9]/gu, "")}`;
98329
+ const keyframes = `
98330
+ @keyframes ${safeName} {
98331
+ ${body}
98332
+ }`;
98333
+ return {
98334
+ elementId: pair.toElement.id,
98335
+ animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
98336
+ keyframes
98337
+ };
98338
+ }
98339
+ function getElementMorphName(element) {
98340
+ if (element.name) {
98341
+ const name = element.name.trim();
98342
+ if (name.startsWith("!!")) {
98343
+ return name;
98344
+ }
98345
+ }
98346
+ if (hasTextProperties(element) && element.text) {
98347
+ const text2 = element.text.trim();
98348
+ if (text2.startsWith("!!")) {
98349
+ return text2;
98350
+ }
98351
+ }
98352
+ return void 0;
98353
+ }
98354
+ function matchMorphElementsFull(fromSlide, toSlide) {
98355
+ const pairs2 = [];
98356
+ const usedFrom = /* @__PURE__ */ new Set();
98357
+ const usedTo = /* @__PURE__ */ new Set();
98358
+ for (const fromEl of fromSlide.elements) {
98359
+ const fromName = getElementMorphName(fromEl);
98360
+ if (!fromName) {
98361
+ continue;
98362
+ }
98363
+ for (const toEl of toSlide.elements) {
98364
+ if (usedTo.has(toEl.id)) {
98365
+ continue;
98366
+ }
98367
+ const toName = getElementMorphName(toEl);
98368
+ if (toName === fromName) {
98369
+ pairs2.push({ fromElement: fromEl, toElement: toEl });
98370
+ usedFrom.add(fromEl.id);
98371
+ usedTo.add(toEl.id);
98372
+ break;
98373
+ }
98374
+ }
98375
+ }
98376
+ for (const fromEl of fromSlide.elements) {
98377
+ if (usedFrom.has(fromEl.id)) {
98378
+ continue;
98379
+ }
98380
+ for (const toEl of toSlide.elements) {
98381
+ if (usedTo.has(toEl.id)) {
98382
+ continue;
98383
+ }
98384
+ if (fromEl.id === toEl.id) {
98385
+ pairs2.push({ fromElement: fromEl, toElement: toEl });
98386
+ usedFrom.add(fromEl.id);
98387
+ usedTo.add(toEl.id);
98388
+ break;
98389
+ }
98390
+ }
98391
+ }
98392
+ for (const fromEl of fromSlide.elements) {
98393
+ if (usedFrom.has(fromEl.id)) {
98394
+ continue;
98395
+ }
98396
+ let bestMatch = null;
98397
+ let bestDist = Infinity;
98398
+ for (const toEl of toSlide.elements) {
98399
+ if (usedTo.has(toEl.id)) {
98400
+ continue;
98401
+ }
98402
+ if (fromEl.type !== toEl.type) {
98403
+ continue;
98404
+ }
98405
+ const dx = fromEl.x - toEl.x;
98406
+ const dy = fromEl.y - toEl.y;
98407
+ const dist2 = Math.sqrt(dx * dx + dy * dy);
98408
+ if (dist2 < bestDist && dist2 < PROXIMITY_THRESHOLD) {
98409
+ bestDist = dist2;
98410
+ bestMatch = toEl;
98411
+ }
98412
+ }
98413
+ if (bestMatch) {
98414
+ pairs2.push({ fromElement: fromEl, toElement: bestMatch });
98415
+ usedFrom.add(fromEl.id);
98416
+ usedTo.add(bestMatch.id);
98417
+ }
98418
+ }
98419
+ const unmatchedFrom = fromSlide.elements.filter((el) => !usedFrom.has(el.id));
98420
+ const unmatchedTo = toSlide.elements.filter((el) => !usedTo.has(el.id));
98421
+ return { pairs: pairs2, unmatchedFrom, unmatchedTo };
98422
+ }
98423
+ function tokenizeText(element, mode) {
98424
+ if (!hasTextProperties(element) || !element.text) {
98425
+ return [];
98426
+ }
98427
+ const text2 = element.text;
98428
+ const style = element.textStyle;
98429
+ const fontSize = style?.fontSize ?? 14;
98430
+ const fontWeight = style?.bold ? "bold" : "normal";
98431
+ const color2 = style?.color ?? "#000000";
98432
+ const tokens = [];
98433
+ if (mode === "character") {
98434
+ const chars = Array.from(text2);
98435
+ const totalChars = chars.length;
98436
+ if (totalChars === 0) {
98437
+ return [];
98438
+ }
98439
+ for (let i = 0; i < chars.length; i++) {
98440
+ if (chars[i] === "\n") {
98441
+ continue;
98442
+ }
98443
+ tokens.push({
98444
+ text: chars[i],
98445
+ x: totalChars > 1 ? i / (totalChars - 1) : 0.5,
98446
+ y: 0.5,
98447
+ fontSize,
98448
+ fontWeight,
98449
+ color: color2
98450
+ });
98451
+ }
98452
+ } else {
98453
+ const words = text2.split(/\s+/u);
98454
+ const nonEmptyWords = words.filter((w) => w.trim().length > 0);
98455
+ const totalWords = nonEmptyWords.length;
98456
+ if (totalWords === 0) {
98457
+ return [];
98458
+ }
98459
+ let wordIndex = 0;
98460
+ for (const word of words) {
98461
+ if (word.trim().length === 0) {
98462
+ continue;
98463
+ }
98464
+ tokens.push({
98465
+ text: word,
98466
+ x: totalWords > 1 ? wordIndex / (totalWords - 1) : 0.5,
98467
+ y: 0.5,
98468
+ fontSize,
98469
+ fontWeight,
98470
+ color: color2
98471
+ });
98472
+ wordIndex++;
98473
+ }
98474
+ }
98475
+ return tokens;
98476
+ }
98477
+ function diffTokens(fromTokens, toTokens) {
98478
+ const n = fromTokens.length;
98479
+ const m = toTokens.length;
98480
+ const lcs = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
98481
+ for (let i2 = n - 1; i2 >= 0; i2--) {
98482
+ for (let j2 = m - 1; j2 >= 0; j2--) {
98483
+ lcs[i2][j2] = fromTokens[i2].text === toTokens[j2].text ? lcs[i2 + 1][j2 + 1] + 1 : Math.max(lcs[i2 + 1][j2], lcs[i2][j2 + 1]);
98484
+ }
98485
+ }
98486
+ const ops = [];
98487
+ let i = 0;
98488
+ let j = 0;
98489
+ while (i < n && j < m) {
98490
+ if (fromTokens[i].text === toTokens[j].text) {
98491
+ ops.push({
98492
+ change: "shared",
98493
+ from: fromTokens[i],
98494
+ to: toTokens[j],
98495
+ fromIndex: i,
98496
+ toIndex: j
98497
+ });
98498
+ i++;
98499
+ j++;
98500
+ } else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
98501
+ ops.push({ change: "removed", from: fromTokens[i], to: null, fromIndex: i, toIndex: -1 });
98502
+ i++;
98503
+ } else {
98504
+ ops.push({ change: "added", from: null, to: toTokens[j], fromIndex: -1, toIndex: j });
98505
+ j++;
98506
+ }
98507
+ }
98508
+ while (i < n) {
98509
+ ops.push({ change: "removed", from: fromTokens[i], to: null, fromIndex: i, toIndex: -1 });
98510
+ i++;
98511
+ }
98512
+ while (j < m) {
98513
+ ops.push({ change: "added", from: null, to: toTokens[j], fromIndex: -1, toIndex: j });
98514
+ j++;
98515
+ }
98516
+ return ops;
98517
+ }
98518
+ function tokenColor(token2) {
98519
+ const parsed = parseHexColor(token2.color);
98520
+ return parsed ? lerpColor2(parsed, parsed, 0) : token2.color;
98521
+ }
98522
+ function sharedKeyframes(name, op) {
98523
+ const from = op.from;
98524
+ const to = op.to;
98525
+ return `
98526
+ @keyframes ${name} {
98527
+ from {
98528
+ left: ${Number((from.x * 100).toFixed(2))}%;
98529
+ top: ${Number((from.y * 100).toFixed(2))}%;
98530
+ font-size: ${from.fontSize}pt;
98531
+ font-weight: ${from.fontWeight};
98532
+ color: ${tokenColor(from)};
98533
+ opacity: 1;
98534
+ }
98535
+ to {
98536
+ left: ${Number((to.x * 100).toFixed(2))}%;
98537
+ top: ${Number((to.y * 100).toFixed(2))}%;
98538
+ font-size: ${to.fontSize}pt;
98539
+ font-weight: ${to.fontWeight};
98540
+ color: ${tokenColor(to)};
98541
+ opacity: 1;
98542
+ }
98543
+ }`;
98544
+ }
98545
+ function fadeKeyframes(name, fadeIn) {
98546
+ const a = fadeIn ? 0 : 1;
98547
+ const b = fadeIn ? 1 : 0;
98548
+ return `
98549
+ @keyframes ${name} {
98550
+ from { opacity: ${a}; }
98551
+ to { opacity: ${b}; }
98552
+ }`;
98553
+ }
98554
+ function buildTokenMorphAnimations(ops, fromId, toId, durationMs, pairIndex) {
98555
+ const animations = [];
98556
+ for (let k = 0; k < ops.length; k++) {
98557
+ const op = ops[k];
98558
+ const name = `pptx-morph-tok-${pairIndex}-${k}`;
98559
+ const anim = `${name} ${durationMs}ms ${MORPH_EASING} forwards`;
98560
+ if (op.change === "shared") {
98561
+ animations.push({
98562
+ elementId: `${toId}__token_${op.toIndex}`,
98563
+ animation: anim,
98564
+ keyframes: sharedKeyframes(name, op)
98565
+ });
98566
+ } else if (op.change === "added") {
98567
+ animations.push({
98568
+ elementId: `${toId}__token_${op.toIndex}`,
98569
+ animation: anim,
98570
+ keyframes: fadeKeyframes(name, true)
98571
+ });
98572
+ } else {
98573
+ animations.push({
98574
+ elementId: `${fromId}__token_${op.fromIndex}`,
98575
+ animation: anim,
98576
+ keyframes: fadeKeyframes(name, false)
98577
+ });
98578
+ }
98579
+ }
98580
+ return animations;
98581
+ }
98582
+ function buildColorInterpolationProps(fromElement, toElement) {
98583
+ const fromFill = hasShapeProperties(fromElement) ? fromElement.shapeStyle?.fillColor : void 0;
98584
+ const toFill = hasShapeProperties(toElement) ? toElement.shapeStyle?.fillColor : void 0;
98585
+ if (!fromFill && !toFill) {
98586
+ return null;
98587
+ }
98588
+ if (fromFill === toFill) {
98589
+ return null;
98590
+ }
98591
+ const fromColor = parseHexColor(fromFill);
98592
+ const toColor = parseHexColor(toFill);
98593
+ if (!fromColor && !toColor) {
98594
+ return null;
98595
+ }
98596
+ const from = fromColor ?? { r: 255, g: 255, b: 255, a: 0 };
98597
+ const to = toColor ?? { r: 255, g: 255, b: 255, a: 0 };
98598
+ return {
98599
+ fromBg: lerpColor2(from, from, 0),
98600
+ toBg: lerpColor2(to, to, 0)
98601
+ };
98602
+ }
98603
+ function buildStrokeInterpolationProps(fromElement, toElement) {
98604
+ const fromStyle = hasShapeProperties(fromElement) ? fromElement.shapeStyle : void 0;
98605
+ const toStyle = hasShapeProperties(toElement) ? toElement.shapeStyle : void 0;
98606
+ const fromColor = fromStyle?.strokeColor;
98607
+ const toColor = toStyle?.strokeColor;
98608
+ const fromWidth = fromStyle?.strokeWidth ?? 0;
98609
+ const toWidth = toStyle?.strokeWidth ?? 0;
98610
+ if (!fromColor && !toColor && fromWidth === 0 && toWidth === 0) {
98611
+ return null;
98612
+ }
98613
+ if (fromColor === toColor && fromWidth === toWidth) {
98614
+ return null;
98615
+ }
98616
+ const fc = parseHexColor(fromColor) ?? { r: 0, g: 0, b: 0, a: 1 };
98617
+ const tc = parseHexColor(toColor) ?? { r: 0, g: 0, b: 0, a: 1 };
98618
+ return {
98619
+ fromStroke: lerpColor2(fc, fc, 0),
98620
+ toStroke: lerpColor2(tc, tc, 0),
98621
+ fromWidth,
98622
+ toWidth
98623
+ };
98624
+ }
98625
+ function generateMorphAnimations(pairs2, durationMs, _mode = "object") {
98626
+ const animations = [];
98627
+ for (let index = 0; index < pairs2.length; index++) {
98628
+ const { fromElement, toElement } = pairs2[index];
98629
+ const safeName = `pptx-morph-${index}-${toElement.id.replace(/[^a-zA-Z0-9]/gu, "")}`;
98630
+ const dx = fromElement.x - toElement.x;
98631
+ const dy = fromElement.y - toElement.y;
98632
+ const sx = Math.max(fromElement.width, 1) / Math.max(toElement.width, 1);
98633
+ const sy = Math.max(fromElement.height, 1) / Math.max(toElement.height, 1);
98634
+ const dr = (fromElement.rotation ?? 0) - (toElement.rotation ?? 0);
98635
+ const fromOpacity = fromElement.opacity ?? 1;
98636
+ const toOpacity = toElement.opacity ?? 1;
98637
+ const fromProps = [
98638
+ ` transform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${dr}deg);`,
98639
+ ` opacity: ${fromOpacity};`
98640
+ ];
98641
+ const toProps = [
98642
+ " transform: translate(0, 0) scale(1, 1) rotate(0deg);",
98643
+ ` opacity: ${toOpacity};`
98644
+ ];
98645
+ const colorInterp = buildColorInterpolationProps(fromElement, toElement);
98646
+ if (colorInterp) {
98647
+ fromProps.push(` background-color: ${colorInterp.fromBg};`);
98648
+ toProps.push(` background-color: ${colorInterp.toBg};`);
98649
+ }
98650
+ const strokeInterp = buildStrokeInterpolationProps(fromElement, toElement);
98651
+ if (strokeInterp) {
98652
+ fromProps.push(` outline: ${strokeInterp.fromWidth}px solid ${strokeInterp.fromStroke};`);
98653
+ toProps.push(` outline: ${strokeInterp.toWidth}px solid ${strokeInterp.toStroke};`);
98654
+ }
98655
+ const keyframes = `
98656
+ @keyframes ${safeName} {
98657
+ from {
98658
+ ${fromProps.join("\n")}
98659
+ }
98660
+ to {
98661
+ ${toProps.join("\n")}
98662
+ }
98663
+ }`;
98664
+ animations.push({
98665
+ elementId: toElement.id,
98666
+ animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
98667
+ keyframes
98668
+ });
98669
+ }
98670
+ return animations;
98671
+ }
98672
+ function generateUnmatchedFadeOutAnimations(elements, durationMs, startIndex) {
98673
+ return elements.map((el, i) => {
98674
+ const safeName = `pptx-morph-fadeout-${startIndex + i}-${el.id.replace(/[^a-zA-Z0-9]/gu, "")}`;
98675
+ const keyframes = `
98676
+ @keyframes ${safeName} {
98677
+ from {
98678
+ opacity: ${el.opacity ?? 1};
98679
+ transform: scale(1);
98680
+ }
98681
+ to {
98682
+ opacity: 0;
98683
+ transform: scale(0.95);
98684
+ }
98685
+ }`;
98686
+ return {
98687
+ elementId: el.id,
98688
+ animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
98689
+ keyframes
98690
+ };
98691
+ });
98692
+ }
98693
+ function generateUnmatchedFadeInAnimations(elements, durationMs, startIndex) {
98694
+ return elements.map((el, i) => {
98695
+ const safeName = `pptx-morph-fadein-${startIndex + i}-${el.id.replace(/[^a-zA-Z0-9]/gu, "")}`;
98696
+ const keyframes = `
98697
+ @keyframes ${safeName} {
98698
+ from {
98699
+ opacity: 0;
98700
+ transform: scale(0.95);
98701
+ }
98702
+ to {
98703
+ opacity: ${el.opacity ?? 1};
98704
+ transform: scale(1);
98705
+ }
98706
+ }`;
98707
+ return {
98708
+ elementId: el.id,
98709
+ animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
98710
+ keyframes
98711
+ };
98712
+ });
98713
+ }
98714
+ function generateTextMorphAnimations(pair, durationMs, mode, pairIndex) {
98715
+ const fromTokens = tokenizeText(pair.fromElement, mode);
98716
+ const toTokens = tokenizeText(pair.toElement, mode);
98717
+ if (fromTokens.length === 0 && toTokens.length === 0) {
98718
+ return [];
98719
+ }
98720
+ const ops = diffTokens(fromTokens, toTokens);
98721
+ return buildTokenMorphAnimations(
98722
+ ops,
98723
+ pair.fromElement.id,
98724
+ pair.toElement.id,
98725
+ durationMs,
98726
+ pairIndex
98727
+ );
98728
+ }
98729
+ function generateFullMorphTransition(fromSlide, toSlide, durationMs, mode = "object") {
98730
+ const matchResult = matchMorphElementsFull(fromSlide, toSlide);
98731
+ const allAnimations = [];
98732
+ const pairAnims = generateMorphAnimations(matchResult.pairs, durationMs, mode);
98733
+ allAnimations.push(...pairAnims);
98734
+ for (let i = 0; i < matchResult.pairs.length; i++) {
98735
+ const geo = generateGeometryMorphAnimation(matchResult.pairs[i], durationMs, i);
98736
+ if (geo) {
98737
+ allAnimations.push(geo);
98738
+ }
98739
+ }
98740
+ if (mode === "word" || mode === "character") {
98741
+ for (let i = 0; i < matchResult.pairs.length; i++) {
98742
+ const pair = matchResult.pairs[i];
98743
+ if (hasTextProperties(pair.fromElement) && hasTextProperties(pair.toElement)) {
98744
+ const textAnims = generateTextMorphAnimations(pair, durationMs, mode, i);
98745
+ allAnimations.push(...textAnims);
98746
+ }
98747
+ }
98748
+ }
98749
+ const fadeOuts = generateUnmatchedFadeOutAnimations(
98750
+ matchResult.unmatchedFrom,
98751
+ durationMs,
98752
+ pairAnims.length
98753
+ );
98754
+ allAnimations.push(...fadeOuts);
98755
+ const fadeIns = generateUnmatchedFadeInAnimations(
98756
+ matchResult.unmatchedTo,
98757
+ durationMs,
98758
+ pairAnims.length + fadeOuts.length
98759
+ );
98760
+ allAnimations.push(...fadeIns);
98761
+ return allAnimations;
98762
+ }
98763
+ function morphOptionToMode(option) {
98764
+ if (option === "byWord") {
98765
+ return "word";
98766
+ }
98767
+ if (option === "byChar") {
98768
+ return "character";
98769
+ }
98770
+ return "object";
98771
+ }
98772
+ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = "object") {
98773
+ if (!fromSlide || !toSlide) {
98774
+ return void 0;
98775
+ }
98776
+ const match = matchMorphElementsFull(fromSlide, toSlide);
98777
+ if (match.pairs.length === 0 && match.unmatchedFrom.length === 0 && match.unmatchedTo.length === 0) {
98778
+ return void 0;
98779
+ }
98780
+ const animations = generateFullMorphTransition(fromSlide, toSlide, durationMs, mode);
98781
+ const outgoingIds = new Set(match.unmatchedFrom.map((element) => element.id));
98782
+ const incomingAnimations = /* @__PURE__ */ new Map();
98783
+ const outgoingAnimations = /* @__PURE__ */ new Map();
98784
+ const keyframes = [];
98785
+ for (const animation of animations) {
98786
+ keyframes.push(animation.keyframes);
98787
+ if (outgoingIds.has(animation.elementId)) {
98788
+ outgoingAnimations.set(animation.elementId, animation.animation);
98789
+ } else {
98790
+ incomingAnimations.set(animation.elementId, animation.animation);
98791
+ }
98792
+ }
98793
+ return {
98794
+ keyframesCss: keyframes.join("\n"),
98795
+ incomingAnimations,
98796
+ outgoingAnimations,
98797
+ outgoingElements: match.unmatchedFrom,
98798
+ durationMs
98799
+ };
98800
+ }
97947
98801
  function hexToRgb6(hex10) {
97948
98802
  const clean = hex10.replace(/^#/u, "");
97949
98803
  return {
@@ -109831,6 +110685,7 @@ exports.buildHandoutsHtml = buildHandoutsHtml;
109831
110685
  exports.buildInitialGuides = buildInitialGuides;
109832
110686
  exports.buildInnerShadowCssFromShapeStyle = buildInnerShadowCssFromShapeStyle;
109833
110687
  exports.buildJoinCollaborationConfig = buildJoinCollaborationConfig;
110688
+ exports.buildMorphTransitionPlan = buildMorphTransitionPlan;
109834
110689
  exports.buildMultiLayerShadowCss = buildMultiLayerShadowCss;
109835
110690
  exports.buildNotesHtml = buildNotesHtml;
109836
110691
  exports.buildNotesPdfBytes = buildNotesPdfBytes;
@@ -110067,6 +110922,7 @@ exports.mergePresentationSnapshot = mergePresentationSnapshot;
110067
110922
  exports.mergeShapes = mergeShapes;
110068
110923
  exports.mobileElapsedSince = mobileElapsedSince;
110069
110924
  exports.mobileSlideCounter = mobileSlideCounter;
110925
+ exports.morphOptionToMode = morphOptionToMode;
110070
110926
  exports.mountModel3D = mountModel3D;
110071
110927
  exports.mountSurfaceChart3D = mountSurfaceChart3D;
110072
110928
  exports.movePresenterPointer = movePresenterPointer;
@@ -110135,6 +110991,7 @@ exports.resolveLineHeight = resolveLineHeight;
110135
110991
  exports.resolveOleType = resolveOleType;
110136
110992
  exports.resolveParagraphAlign = resolveParagraphAlign;
110137
110993
  exports.resolveParagraphRtl = resolveParagraphRtl;
110994
+ exports.resolveParagraphStrutFontSize = resolveParagraphStrutFontSize;
110138
110995
  exports.resolvePictureBullet = resolvePictureBullet;
110139
110996
  exports.resolveProfileInitial = resolveProfileInitial;
110140
110997
  exports.resolveRegionCode = resolveRegionCode;