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.
- package/CHANGELOG.md +13 -0
- package/dist/{AiChatPanel-OHSLJNYG.js → AiChatPanel-53W2JG6G.js} +22 -22
- package/dist/AiChatPanel-53W2JG6G.js.br +0 -0
- package/dist/AiChatPanel-53W2JG6G.js.gz +0 -0
- package/dist/{AiChatPanel-EMF3UYCE.mjs → AiChatPanel-L5IOO72H.mjs} +3 -3
- package/dist/AiChatPanel-L5IOO72H.mjs.br +0 -0
- package/dist/AiChatPanel-L5IOO72H.mjs.gz +0 -0
- package/dist/{Model3DScene-ULHIJPMU.js → Model3DScene-E7JGXNJN.js} +2 -2
- package/dist/Model3DScene-E7JGXNJN.js.br +0 -0
- package/dist/Model3DScene-E7JGXNJN.js.gz +0 -0
- package/dist/{Model3DScene-X6QJTWHV.mjs → Model3DScene-EW7OWRJK.mjs} +1 -1
- package/dist/Model3DScene-EW7OWRJK.mjs.br +0 -0
- package/dist/Model3DScene-EW7OWRJK.mjs.gz +0 -0
- package/dist/{SurfaceChart3DScene-K7Q5NYZ4.js → SurfaceChart3DScene-3QB6NVKD.js} +2 -2
- package/dist/SurfaceChart3DScene-3QB6NVKD.js.br +0 -0
- package/dist/SurfaceChart3DScene-3QB6NVKD.js.gz +0 -0
- package/dist/{SurfaceChart3DScene-PRCKQJQQ.mjs → SurfaceChart3DScene-64HI3U7Y.mjs} +1 -1
- package/dist/{SurfaceChart3DScene-PRCKQJQQ.mjs.br → SurfaceChart3DScene-64HI3U7Y.mjs.br} +0 -0
- package/dist/SurfaceChart3DScene-64HI3U7Y.mjs.gz +0 -0
- package/dist/{chunk-VOV2N3NY.mjs → chunk-34ZW32XK.mjs} +919 -65
- package/dist/chunk-34ZW32XK.mjs.br +0 -0
- package/dist/chunk-34ZW32XK.mjs.gz +0 -0
- package/dist/{chunk-TGVID6BB.mjs → chunk-DWQJW3UM.mjs} +19 -4
- package/dist/chunk-DWQJW3UM.mjs.br +0 -0
- package/dist/chunk-DWQJW3UM.mjs.gz +0 -0
- package/dist/{chunk-7Q7AEPO7.js → chunk-EJ24IFPL.js} +346 -315
- package/dist/chunk-EJ24IFPL.js.br +0 -0
- package/dist/chunk-EJ24IFPL.js.gz +0 -0
- package/dist/{chunk-NVH3RIN7.js → chunk-NXSAYLYI.js} +251 -236
- package/dist/chunk-NXSAYLYI.js.br +0 -0
- package/dist/chunk-NXSAYLYI.js.gz +0 -0
- package/dist/{chunk-WJKMTDXS.mjs → chunk-PENV7S7Z.mjs} +1 -1
- package/dist/chunk-PENV7S7Z.mjs.br +0 -0
- package/dist/{chunk-WJKMTDXS.mjs.gz → chunk-PENV7S7Z.mjs.gz} +0 -0
- package/dist/{chunk-HDKHZKSW.mjs → chunk-UO55N46T.mjs} +91 -13
- package/dist/chunk-UO55N46T.mjs.br +0 -0
- package/dist/chunk-UO55N46T.mjs.gz +0 -0
- package/dist/{chunk-LTEDT475.js → chunk-UVA55CRK.js} +921 -64
- package/dist/chunk-UVA55CRK.js.br +0 -0
- package/dist/chunk-UVA55CRK.js.gz +0 -0
- package/dist/{chunk-OSSVKJGF.js → chunk-V5XVTKFS.js} +925 -847
- package/dist/chunk-V5XVTKFS.js.br +0 -0
- package/dist/chunk-V5XVTKFS.js.gz +0 -0
- package/dist/{chunk-MJAEB43A.js → chunk-VBWWICDF.js} +3 -3
- package/dist/chunk-VBWWICDF.js.br +0 -0
- package/dist/chunk-VBWWICDF.js.gz +0 -0
- package/dist/{chunk-LIQGO45T.mjs → chunk-WCO3NEH5.mjs} +35 -4
- package/dist/chunk-WCO3NEH5.mjs.br +0 -0
- package/dist/chunk-WCO3NEH5.mjs.gz +0 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +34 -34
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.br +0 -0
- package/dist/index.mjs.gz +0 -0
- package/dist/internals.d.ts +42 -0
- package/dist/internals.d.ts.map +1 -1
- package/dist/internals.js +78 -78
- package/dist/internals.js.br +0 -0
- package/dist/internals.js.gz +0 -0
- package/dist/internals.mjs +3 -3
- package/dist/internals.mjs.br +0 -0
- package/dist/internals.mjs.gz +0 -0
- package/dist/pptx-viewer.css +1 -1
- package/dist/pptx-viewer.css.br +0 -0
- package/dist/pptx-viewer.css.gz +0 -0
- package/dist/viewer/index.d.ts +15 -0
- package/dist/viewer/index.js +21 -21
- package/dist/viewer/index.js.br +0 -0
- package/dist/viewer/index.js.gz +0 -0
- package/dist/viewer/index.mjs +5 -5
- package/dist/viewer/index.mjs.br +0 -0
- package/dist/viewer/index.mjs.gz +0 -0
- package/package.json +3 -3
- package/dist/AiChatPanel-EMF3UYCE.mjs.br +0 -0
- package/dist/AiChatPanel-EMF3UYCE.mjs.gz +0 -0
- package/dist/AiChatPanel-OHSLJNYG.js.br +0 -0
- package/dist/AiChatPanel-OHSLJNYG.js.gz +0 -0
- package/dist/Model3DScene-ULHIJPMU.js.br +0 -0
- package/dist/Model3DScene-ULHIJPMU.js.gz +0 -0
- package/dist/Model3DScene-X6QJTWHV.mjs.br +0 -0
- package/dist/Model3DScene-X6QJTWHV.mjs.gz +0 -0
- package/dist/SurfaceChart3DScene-K7Q5NYZ4.js.br +0 -0
- package/dist/SurfaceChart3DScene-K7Q5NYZ4.js.gz +0 -0
- package/dist/SurfaceChart3DScene-PRCKQJQQ.mjs.gz +0 -0
- package/dist/chunk-7Q7AEPO7.js.br +0 -0
- package/dist/chunk-7Q7AEPO7.js.gz +0 -0
- package/dist/chunk-HDKHZKSW.mjs.br +0 -0
- package/dist/chunk-HDKHZKSW.mjs.gz +0 -0
- package/dist/chunk-LIQGO45T.mjs.br +0 -0
- package/dist/chunk-LIQGO45T.mjs.gz +0 -0
- package/dist/chunk-LTEDT475.js.br +0 -0
- package/dist/chunk-LTEDT475.js.gz +0 -0
- package/dist/chunk-MJAEB43A.js.br +0 -0
- package/dist/chunk-MJAEB43A.js.gz +0 -0
- package/dist/chunk-NVH3RIN7.js.br +0 -0
- package/dist/chunk-NVH3RIN7.js.gz +0 -0
- package/dist/chunk-OSSVKJGF.js.br +0 -0
- package/dist/chunk-OSSVKJGF.js.gz +0 -0
- package/dist/chunk-TGVID6BB.mjs.br +0 -0
- package/dist/chunk-TGVID6BB.mjs.gz +0 -0
- package/dist/chunk-VOV2N3NY.mjs.br +0 -0
- package/dist/chunk-VOV2N3NY.mjs.gz +0 -0
- 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.
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
12661
|
-
if (Number.isFinite(
|
|
12662
|
-
style.reflectionDistance =
|
|
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
|
-
|
|
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
|
|
20624
|
-
|
|
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
|
|
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
|
-
|
|
20690
|
-
|
|
20691
|
-
}
|
|
20692
|
-
return true;
|
|
20704
|
+
return {
|
|
20705
|
+
morphOption: normalizeMorphOption(value?.["@_option"])
|
|
20706
|
+
};
|
|
20693
20707
|
}
|
|
20694
20708
|
}
|
|
20695
20709
|
}
|
|
20696
|
-
return
|
|
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
|
-
|
|
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
|
|
40992
|
+
const fontSizePx2 = fontSizePt * (4 / 3);
|
|
40961
40993
|
const lineHeightMultiplier = style?.lineSpacing ?? DEFAULT_LINE_HEIGHT_MULTIPLIER;
|
|
40962
|
-
const lineHeightPx =
|
|
40994
|
+
const lineHeightPx = fontSizePx2 * lineHeightMultiplier;
|
|
40963
40995
|
const charsPerLine = Math.max(
|
|
40964
40996
|
1,
|
|
40965
|
-
Math.floor(availableWidth / (
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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) *
|
|
51314
|
-
style.textShadowOffsetY = Math.round(Math.sin(dirRad) *
|
|
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:
|
|
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
|
-
|
|
63411
|
-
|
|
63412
|
-
|
|
63413
|
-
|
|
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 =
|
|
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
|
|
66430
|
+
const dist2 = parseInt(String(outerShdw["@_dist"] || "0"));
|
|
66360
66431
|
const dir = parseInt(String(outerShdw["@_dir"] || "0"));
|
|
66361
|
-
if (Number.isFinite(
|
|
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) *
|
|
66364
|
-
result.shadowOffsetY = Math.sin(angleRad) *
|
|
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
|
|
66446
|
+
const dist2 = parseInt(String(innerShdw["@_dist"] || "0"));
|
|
66376
66447
|
const dir = parseInt(String(innerShdw["@_dir"] || "0"));
|
|
66377
|
-
if (Number.isFinite(
|
|
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) *
|
|
66380
|
-
result.innerShadowOffsetY = Math.sin(angleRad) *
|
|
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
|
|
66426
|
-
if (Number.isFinite(
|
|
66427
|
-
result.reflectionDistance =
|
|
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;
|