hyperframes 0.8.98 → 0.8.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-QAX64UD5.js → add-YOGFHV5P.js} +18 -17
- package/dist/{animatedGifPrep-5KUI3AAL.js → animatedGifPrep-RZVYVAXD.js} +8 -7
- package/dist/{asset-6PAUWV7A.js → asset-RVTEKOMS.js} +2 -2
- package/dist/{assetCataloger-FUXNMJYE.js → assetCataloger-BQREHRS2.js} +4 -3
- package/dist/{auth-RURB6JL2.js → auth-3ZGHKXTY.js} +2 -2
- package/dist/{autoUpdate-ZX5GPKIG.js → autoUpdate-DHDVAKLG.js} +2 -2
- package/dist/{backgroundChecks-GZ3LYLFZ.js → backgroundChecks-TJZXWBCQ.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-2BIKSPOP.js → batchRender-AQN5PRXM.js} +5 -4
- package/dist/{beats-FMDUDET7.js → beats-PZEJBKPX.js} +12 -11
- package/dist/{benchmark-5NXPAFTK.js → benchmark-XTNKYDB3.js} +14 -13
- package/dist/{browser-W5IZK2LF.js → browser-33R5MU5T.js} +11 -10
- package/dist/{bundleWithLocalizedFonts-QYS67RJT.js → bundleWithLocalizedFonts-JKJKZR2S.js} +2 -2
- package/dist/{capture-Z47X2EG6.js → capture-5BCJWVC7.js} +2 -2
- package/dist/{capture-HOXFOHCG.js → capture-QYLHIYKJ.js} +9 -8
- package/dist/{catalog-TEUY2DP3.js → catalog-QCJADIDT.js} +19 -18
- package/dist/{check-6KE5ZV6K.js → check-V5AIEMEJ.js} +34 -32
- package/dist/{checkBrowser-F6MKBAL3.js → checkBrowser-LI4OCQCC.js} +33 -31
- package/dist/{chunk-45WXLLUL.js → chunk-32Y3HRS3.js} +2 -2
- package/dist/{chunk-DHLZLPIA.js → chunk-3ME4RRT4.js} +8 -8
- package/dist/{chunk-M7Y4BQAC.js → chunk-4WAMN4IF.js} +1 -1
- package/dist/chunk-4Z5O7BTD.js +114 -0
- package/dist/{chunk-H5ZRB3SN.js → chunk-6CN2QLB5.js} +3 -3
- package/dist/{chunk-6SXRFLBV.js → chunk-6F6EEQNB.js} +5 -12
- package/dist/{chunk-MRQEWIM3.js → chunk-7PJG4Z2H.js} +8 -8
- package/dist/{chunk-OIT6L7OY.js → chunk-AZQLJHAO.js} +1 -1
- package/dist/{chunk-A7GG3RLG.js → chunk-EBY3SP4T.js} +4 -4
- package/dist/chunk-FOKUJKBN.js +3420 -0
- package/dist/{chunk-EA5GAMEY.js → chunk-GMECXFAN.js} +1 -1
- package/dist/{chunk-QVGB3PQ2.js → chunk-GOI4GCUB.js} +1 -1
- package/dist/{chunk-ULER6XBR.js → chunk-HFFR7TN7.js} +1 -1
- package/dist/{chunk-6D7WQM6D.js → chunk-HGJZKJRO.js} +1 -1
- package/dist/{chunk-J7QMXLNY.js → chunk-HUHJYNST.js} +1 -1
- package/dist/{chunk-4CMGNIJD.js → chunk-I6M4GXMC.js} +1 -1
- package/dist/{chunk-QPN3GV5R.js → chunk-I77CAR4W.js} +2 -2
- package/dist/{chunk-UH4PYJXV.js → chunk-IGV5J5ZW.js} +1 -1
- package/dist/{chunk-WPP2NJVF.js → chunk-IH6NEFVL.js} +3 -3
- package/dist/{chunk-UPGW6TTK.js → chunk-IQ4UCWV7.js} +1 -1
- package/dist/{chunk-6RC6OPDF.js → chunk-JUJ2XONM.js} +9 -9
- package/dist/{chunk-VSVNEDUL.js → chunk-JXXE3SWC.js} +10 -10
- package/dist/{chunk-7JABNLBL.js → chunk-L5FZ5SFX.js} +5 -5
- package/dist/{chunk-B7E6IWMM.js → chunk-LBPAJ5EJ.js} +1 -1
- package/dist/{chunk-KF4BPO7K.js → chunk-M4KS6MJN.js} +4 -4
- package/dist/{chunk-IOM5EJZB.js → chunk-MCABWC2G.js} +2 -2
- package/dist/{chunk-E6ABDLBN.js → chunk-O5TBFZ7X.js} +3 -3
- package/dist/chunk-OFQWTKPW.js +117 -0
- package/dist/{chunk-P7CAZ6YA.js → chunk-OKQLXBQQ.js} +3 -3
- package/dist/{chunk-G7REKKB7.js → chunk-P5GP2XJX.js} +1 -1
- package/dist/{chunk-WY7DTUVY.js → chunk-PB2OX2JY.js} +1 -1
- package/dist/{chunk-A67QXF4W.js → chunk-PDRHNLKE.js} +3 -3
- package/dist/{chunk-NY4NHA3Y.js → chunk-PUB5XZYL.js} +1 -1
- package/dist/{chunk-6P7TUF6Z.js → chunk-R5RF3LGS.js} +1 -1
- package/dist/{chunk-XMNWWURD.js → chunk-RDMAU7AJ.js} +14 -0
- package/dist/{chunk-RRJU47XY.js → chunk-T2HQSEIH.js} +1 -1
- package/dist/{chunk-TXY724ZK.js → chunk-TEXPOC5V.js} +2 -2
- package/dist/{chunk-YVGQM466.js → chunk-TH4APNRP.js} +6 -4
- package/dist/{chunk-WFO4PSIZ.js → chunk-TLYU5625.js} +9 -0
- package/dist/{chunk-YM2WZIJ7.js → chunk-TMLEIURT.js} +1 -1
- package/dist/{chunk-EJQTOUPG.js → chunk-TYA65W4U.js} +4 -4
- package/dist/{chunk-XKHIUGY3.js → chunk-USWOTTSP.js} +1 -1
- package/dist/{chunk-KVA65K7M.js → chunk-UVUAU3CH.js} +2 -2
- package/dist/{chunk-NBQ7RWSG.js → chunk-VBTX4DPW.js} +3 -3
- package/dist/{chunk-H7EMX7GA.js → chunk-VW5OMJNG.js} +3 -3
- package/dist/{chunk-UBSAIOMW.js → chunk-XL2CUGEG.js} +105 -92
- package/dist/{chunk-5BJFUD4T.js → chunk-XZSH5GS7.js} +4 -4
- package/dist/{chunk-CLW66MZ7.js → chunk-Y2CZEJPK.js} +2 -2
- package/dist/{chunk-N4H5U5BT.js → chunk-YZMYYF2X.js} +2 -2
- package/dist/{chunk-U3ZB2Z53.js → chunk-ZN2VS7HX.js} +2 -2
- package/dist/{clean-GB5Z4WEM.js → clean-S5HLSHKF.js} +18 -16
- package/dist/cli.js +50 -50
- package/dist/{cloud-TEEFEBH2.js → cloud-YVFKYAPL.js} +4 -4
- package/dist/{cloudrun-6OB4LUGS.js → cloudrun-ISE6GSUO.js} +6 -5
- package/dist/{compare-DVPSR4DL.js → compare-ADNK57U4.js} +28 -26
- package/dist/{compiler-CYMKVOVA.js → compiler-QMEZK6CU.js} +4 -3
- package/dist/{component-U2INC5IT.js → component-PEY7SIFS.js} +3 -3
- package/dist/{compositions-74IQZR7R.js → compositions-45NJDJ4D.js} +13 -12
- package/dist/{delete-HEYUHORS.js → delete-5JV2P3JW.js} +5 -3
- package/dist/{deterministicFonts-RMJFQXDW.js → deterministicFonts-XS3PGWH5.js} +2 -2
- package/dist/{dist-HJFL4ZN5.js → dist-E44WU6LH.js} +1 -1
- package/dist/{dist-XAD3AJS3.js → dist-R24TLUYO.js} +13 -11
- package/dist/{doctor-ULRZSIUT.js → doctor-EPDFEGGY.js} +12 -11
- package/dist/{events-DMSH3WM4.js → events-G6FHOEJQ.js} +10 -9
- package/dist/{events-LESQE4GC.js → events-JIGBMB22.js} +11 -10
- package/dist/{feedback-2XHCU2ZK.js → feedback-Y7DL2O2L.js} +12 -11
- package/dist/{figma-BERLUHLI.js → figma-4RJX4QL5.js} +3 -3
- package/dist/fontLocalizeCli.js +11 -10
- package/dist/{get-4YBNEMTP.js → get-2VZICXM2.js} +5 -3
- package/dist/{gpuPolicy-HKUPBZJK.js → gpuPolicy-BQFPO7UA.js} +8 -7
- package/dist/{grade-compare-EPUP4JHB.js → grade-compare-UIR2Q6GF.js} +28 -26
- package/dist/{gsapParser-IQS5TBGJ.js → gsapParser-EZGJSSV5.js} +46 -11
- package/dist/{gsapParserAcorn-OYHIHFF5.js → gsapParserAcorn-SZANFUAQ.js} +3 -1
- package/dist/{help-7RREVPSW.js → help-LTA4R652.js} +1 -1
- package/dist/{history-DRM6E3K7.js → history-RJIZMB4C.js} +18 -16
- package/dist/hyperframe-runtime.js +1 -1
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +1 -1
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/{info-T46MLAIJ.js → info-Q74CT24F.js} +13 -12
- package/dist/{init-XUENGFUL.js → init-ZPLWAASI.js} +23 -22
- package/dist/{inspect-UJ6VQ4AQ.js → inspect-ALYVRN2U.js} +29 -27
- package/dist/{installer-3EXYDXIP.js → installer-UZSVMUKT.js} +7 -6
- package/dist/{keyframes-W3CGZVFU.js → keyframes-7KIXRNZL.js} +23 -13
- package/dist/{lambda-AORIF7O3.js → lambda-U4WIJQCJ.js} +7 -6
- package/dist/{layout-ZWO2PFYM.js → layout-RGO5RRS3.js} +29 -27
- package/dist/{lint-363LQDQQ.js → lint-HF4ZT3Q2.js} +14 -13
- package/dist/{lintProject-ESEUOGXF.js → lintProject-4P4C6AN2.js} +1 -1
- package/dist/{list-4UY5CXXR.js → list-YFOSCQPU.js} +5 -3
- package/dist/{login-GQEPZV6R.js → login-6DWXT7KZ.js} +4 -4
- package/dist/{media-treatment-ALANZWB6.js → media-treatment-5G6F4AV6.js} +14 -13
- package/dist/{models-QKXFAS6W.js → models-LXUIU5DC.js} +9 -8
- package/dist/{motionShot-BMDELKKS.js → motionShot-XRSPP3G6.js} +12 -11
- package/dist/{normalize-audio-IUMGNRZP.js → normalize-audio-5SDICUXG.js} +12 -11
- package/dist/{pipeline-HB3B54ID.js → pipeline-OFFKTFXS.js} +8 -7
- package/dist/{play-BPMDBZ4B.js → play-64NBPQZX.js} +24 -22
- package/dist/{preflight-A5GAQUXY.js → preflight-TVCVP5P2.js} +9 -8
- package/dist/{present-TVA7OFEX.js → present-P65ZUVJ4.js} +19 -17
- package/dist/{preview-YPBQWOBV.js → preview-VHRLBZ6E.js} +20 -19
- package/dist/{producer-JX3R2SJD.js → producer-LGG3TOUI.js} +1 -1
- package/dist/{projectConfig-D72ZCV4U.js → projectConfig-V53SEFIS.js} +9 -8
- package/dist/{publication-NXK5YHOQ.js → publication-7RKKPKLM.js} +6 -5
- package/dist/{publish-5OD66ODR.js → publish-TRRFCEMQ.js} +11 -10
- package/dist/{remove-background-LBVJV7OI.js → remove-background-HJFT46Z5.js} +9 -8
- package/dist/{render-3P4RQGWW.js → render-3T3GAQRD.js} +16 -14
- package/dist/{render-WV3L66CZ.js → render-H6NZB4R5.js} +24 -23
- package/dist/{render-ZI2B2XFE.js → render-TPZ5FXHS.js} +5 -4
- package/dist/{render-batch-S3H4HVUJ.js → render-batch-4ZF5C2LN.js} +5 -4
- package/dist/{renderCancellation-O6XHCGN6.js → renderCancellation-4PYGAN5D.js} +8 -7
- package/dist/renderSetupWorker.js +1 -1
- package/dist/{resolver-Y3I7ADOB.js → resolver-4JRJPC6S.js} +7 -6
- package/dist/{sherpa-NIP27UXM.js → sherpa-MNCWRFD4.js} +11 -9
- package/dist/{skills-QIN53D3I.js → skills-REGO6WJ3.js} +13 -12
- package/dist/{skillsUpdateCheck-2QDUGU26.js → skillsUpdateCheck-7CKNNDEI.js} +3 -3
- package/dist/{snapshot-U4QNSCIR.js → snapshot-QGXDXDFW.js} +29 -27
- package/dist/{src-BH62F364.js → src-QF6RYX76.js} +10 -9
- package/dist/{src-3CKPQCXW.js → src-QX5PPANW.js} +7 -6
- package/dist/{staticProjectServer-2XMNYJTA.js → staticProjectServer-TEVGFDXU.js} +18 -16
- package/dist/{status-RP5AM4YY.js → status-C3IDZFDG.js} +8 -7
- package/dist/studio/assets/{hyperframes-player-C6muFtfk.js → hyperframes-player-fWt87gyh.js} +1 -1
- package/dist/studio/assets/{index-B6vU39NM.js → index-D34Oy5DN.js} +1 -1
- package/dist/studio/assets/{index-itc1XziP.js → index-D6TjRAvz.js} +171 -171
- package/dist/studio/assets/{index-BxnoLgxG.js → index-DofdzdxJ.js} +1 -1
- package/dist/studio/index.html +1 -1
- package/dist/studio/index.js +718 -438
- package/dist/studio/index.js.map +1 -1
- package/dist/{studio-api-OGPSLKV7.js → studio-api-VNIEVFVL.js} +12 -10
- package/dist/{studioServer-ZJ22K33M.js → studioServer-QRHT7WQE.js} +48 -44
- package/dist/{system-SHCBJHHU.js → system-OAB2LYBV.js} +8 -7
- package/dist/{telemetry-GK7XOOXI.js → telemetry-O6OTMDXT.js} +11 -10
- package/dist/{timeline-46FRT64J.js → timeline-GKK57X67.js} +18 -16
- package/dist/{tokens-HJ2LB2GR.js → tokens-2YYS3Y5M.js} +2 -2
- package/dist/{transcribe-S75EUMVN.js → transcribe-5V3UCT5O.js} +14 -13
- package/dist/{transcribe-IK5WYH4B.js → transcribe-AL3E5MBZ.js} +9 -8
- package/dist/{updateCheck-PLFHDWQS.js → updateCheck-Y6FACNPT.js} +2 -2
- package/dist/{upgrade-2VUYCOJA.js → upgrade-E2P6HGXJ.js} +2 -2
- package/dist/{urlDownloader-EMO4Y44J.js → urlDownloader-U3TNOPD5.js} +7 -6
- package/dist/{validate-G5S2R6QT.js → validate-PGI3PX6W.js} +17 -16
- package/dist/{video-5WCMLASZ.js → video-KAHL76HG.js} +8 -7
- package/package.json +1 -1
- package/dist/chunk-M5YNZQXZ.js +0 -3528
package/dist/studio/index.js
CHANGED
|
@@ -2173,6 +2173,9 @@ function getTimelinePlayheadTransform(time, pixelsPerSecond, contentOrigin, atRe
|
|
|
2173
2173
|
function roundTo3(val) {
|
|
2174
2174
|
return Math.round(val * 1e3) / 1e3;
|
|
2175
2175
|
}
|
|
2176
|
+
function roundToLayoutPx(val) {
|
|
2177
|
+
return Math.round(val);
|
|
2178
|
+
}
|
|
2176
2179
|
function roundToCenti(val) {
|
|
2177
2180
|
return Math.round(val * 100) / 100;
|
|
2178
2181
|
}
|
|
@@ -19808,6 +19811,8 @@ async function postGsapMutation(projectId, filePath, mutation, fallback) {
|
|
|
19808
19811
|
}
|
|
19809
19812
|
|
|
19810
19813
|
// src/hooks/timelineTimingSync.ts
|
|
19814
|
+
import { findTimelineScript } from "@hyperframes/core/gsap-parser-acorn";
|
|
19815
|
+
import { walkCompositionDescendants } from "@hyperframes/parsers/hf-ids";
|
|
19811
19816
|
async function readFileContent(projectId, targetPath) {
|
|
19812
19817
|
if (targetPath.includes("\0") || targetPath.includes("..")) {
|
|
19813
19818
|
throw new Error(`Unsafe path: ${targetPath}`);
|
|
@@ -20007,8 +20012,19 @@ async function scaleGsapPositions(projectId, filePath, elementId2, oldStart, old
|
|
|
20007
20012
|
"scale-positions failed"
|
|
20008
20013
|
);
|
|
20009
20014
|
}
|
|
20015
|
+
function sdkTimingGsapSync(result) {
|
|
20016
|
+
const timelineText = (html2) => {
|
|
20017
|
+
const scripts = [];
|
|
20018
|
+
walkCompositionDescendants(new DOMParser().parseFromString(html2, "text/html"), (el) => {
|
|
20019
|
+
if (el.tagName.toLowerCase() === "script") scripts.push(el);
|
|
20020
|
+
});
|
|
20021
|
+
return findTimelineScript(scripts)?.textContent ?? null;
|
|
20022
|
+
};
|
|
20023
|
+
if (timelineText(result.before) === timelineText(result.after)) return null;
|
|
20024
|
+
return { mutated: true, scriptText: extractGsapScriptText(result.after) };
|
|
20025
|
+
}
|
|
20010
20026
|
function finishClipTimingFallback(input) {
|
|
20011
|
-
const { projectId, targetPath, domId, edit } = input;
|
|
20027
|
+
const { projectId, targetPath, domId, edit, sdkGsap } = input;
|
|
20012
20028
|
const timingChanged = edit.kind === "shift" ? edit.delta !== 0 : edit.from.start !== edit.to.start || edit.from.duration !== edit.to.duration;
|
|
20013
20029
|
const runMutation = (pid, id) => edit.kind === "shift" ? shiftGsapPositions(pid, targetPath, id, edit.delta) : scaleGsapPositions(
|
|
20014
20030
|
pid,
|
|
@@ -20023,7 +20039,7 @@ function finishClipTimingFallback(input) {
|
|
|
20023
20039
|
return finishTimelineTimingFallback({
|
|
20024
20040
|
iframe: input.iframe,
|
|
20025
20041
|
reloadPreview: input.reloadPreview,
|
|
20026
|
-
gsapMutation: timingChanged && domId && projectId ? () => foldGsapMutationIntoHistory({
|
|
20042
|
+
gsapMutation: sdkGsap ? () => Promise.resolve(sdkGsap) : timingChanged && domId && projectId ? () => foldGsapMutationIntoHistory({
|
|
20027
20043
|
writeFile: input.writeProjectFile,
|
|
20028
20044
|
paths: [targetPath],
|
|
20029
20045
|
projectId,
|
|
@@ -20043,6 +20059,17 @@ async function finishGroupTimingGsapFallback(input) {
|
|
|
20043
20059
|
(change) => input.resolveChangePath(change.element) !== activePath
|
|
20044
20060
|
);
|
|
20045
20061
|
const onGsapError = (err) => console.error(`[Timeline] ${input.errorLabel}`, err);
|
|
20062
|
+
const { sdkGsap } = input;
|
|
20063
|
+
if (sdkGsap) {
|
|
20064
|
+
await finishTimelineTimingFallback({
|
|
20065
|
+
iframe: input.iframe,
|
|
20066
|
+
reloadPreview: input.reloadPreview,
|
|
20067
|
+
gsapMutation: () => Promise.resolve(sdkGsap),
|
|
20068
|
+
onGsapError,
|
|
20069
|
+
rebindWhenUnmutated: !otherFileChanged
|
|
20070
|
+
});
|
|
20071
|
+
return;
|
|
20072
|
+
}
|
|
20046
20073
|
await finishTimelineTimingFallback({
|
|
20047
20074
|
iframe: input.iframe,
|
|
20048
20075
|
reloadPreview: input.reloadPreview,
|
|
@@ -30159,12 +30186,52 @@ function cropRectFromInsets(rect, insets, scaleX, scaleY) {
|
|
|
30159
30186
|
height: Math.max(0, rect.height - (insets.top + insets.bottom) * sy)
|
|
30160
30187
|
};
|
|
30161
30188
|
}
|
|
30162
|
-
|
|
30189
|
+
var cropLifts = /* @__PURE__ */ new WeakMap();
|
|
30190
|
+
function liftSelector(element) {
|
|
30191
|
+
const quote = (value) => `"${value.replace(/["\\]/g, "\\$&")}"`;
|
|
30192
|
+
const hfId = element.getAttribute("data-hf-id");
|
|
30193
|
+
if (hfId) return `[data-hf-id=${quote(hfId)}]`;
|
|
30194
|
+
return element.id ? `[id=${quote(element.id)}]` : null;
|
|
30195
|
+
}
|
|
30196
|
+
function liftElementCrop(element) {
|
|
30197
|
+
const selector = liftSelector(element);
|
|
30198
|
+
if (!selector || cropLifts.has(element)) return;
|
|
30199
|
+
const doc = element.ownerDocument;
|
|
30200
|
+
const rule = doc.createElement("style");
|
|
30201
|
+
rule.textContent = `${selector}{clip-path:none!important}`;
|
|
30202
|
+
(doc.head ?? doc.documentElement).append(rule);
|
|
30203
|
+
cropLifts.set(element, { rule });
|
|
30204
|
+
}
|
|
30205
|
+
function dropElementCropLift(element) {
|
|
30206
|
+
cropLifts.get(element)?.rule.remove();
|
|
30207
|
+
cropLifts.delete(element);
|
|
30208
|
+
}
|
|
30209
|
+
function isElementCropLifted(element) {
|
|
30210
|
+
return cropLifts.has(element);
|
|
30211
|
+
}
|
|
30212
|
+
var computedClipPath = (element) => element.ownerDocument.defaultView?.getComputedStyle(element).clipPath.trim() || "";
|
|
30213
|
+
function readElementClipPath(element) {
|
|
30163
30214
|
const inline = element.style.getPropertyValue("clip-path").trim();
|
|
30164
|
-
const
|
|
30215
|
+
const lift = cropLifts.get(element);
|
|
30216
|
+
if (inline || !lift) return inline || computedClipPath(element);
|
|
30217
|
+
if (lift.sheetClip === void 0) {
|
|
30218
|
+
const { parentNode, nextSibling } = lift.rule;
|
|
30219
|
+
lift.rule.remove();
|
|
30220
|
+
lift.sheetClip = computedClipPath(element);
|
|
30221
|
+
parentNode?.insertBefore(lift.rule, nextSibling);
|
|
30222
|
+
}
|
|
30223
|
+
return lift.sheetClip;
|
|
30224
|
+
}
|
|
30225
|
+
function parseCropClipPath(value) {
|
|
30165
30226
|
if (!value || value === "none") return { top: 0, right: 0, bottom: 0, left: 0, radius: 0 };
|
|
30166
30227
|
return parseInsetClipPathSides(value);
|
|
30167
30228
|
}
|
|
30229
|
+
function readElementCropInsets(element) {
|
|
30230
|
+
return parseCropClipPath(readElementClipPath(element));
|
|
30231
|
+
}
|
|
30232
|
+
function hasCropInsets(insets) {
|
|
30233
|
+
return insets.top > 0 || insets.right > 0 || insets.bottom > 0 || insets.left > 0;
|
|
30234
|
+
}
|
|
30168
30235
|
function clampInset(value, max) {
|
|
30169
30236
|
if (!Number.isFinite(value)) return 0;
|
|
30170
30237
|
return Math.min(Math.max(0, value), Math.max(0, max));
|
|
@@ -30206,7 +30273,7 @@ function resolveCropInsetFromMoveDrag(input) {
|
|
|
30206
30273
|
return { left, right: totalX - left, top, bottom: totalY - top };
|
|
30207
30274
|
}
|
|
30208
30275
|
function hugRectForElement(rect, element) {
|
|
30209
|
-
const insets = readElementCropInsets(element);
|
|
30276
|
+
const insets = isElementCropLifted(element) ? null : readElementCropInsets(element);
|
|
30210
30277
|
if (!insets || insets.top <= 0 && insets.right <= 0 && insets.bottom <= 0 && insets.left <= 0)
|
|
30211
30278
|
return rect;
|
|
30212
30279
|
return cropRectFromInsets(rect, insets, rect.editScaleX, rect.editScaleY);
|
|
@@ -30944,9 +31011,6 @@ function pointerAngleDegrees(centerX, centerY, x, y) {
|
|
|
30944
31011
|
function normalizeAngleDelta(delta) {
|
|
30945
31012
|
return ((delta + 180) % 360 + 360) % 360 - 180;
|
|
30946
31013
|
}
|
|
30947
|
-
function roundAngle(angle) {
|
|
30948
|
-
return Math.round(angle * 10) / 10;
|
|
30949
|
-
}
|
|
30950
31014
|
function resolveDomEditRotationGesture(input) {
|
|
30951
31015
|
const startAngle = pointerAngleDegrees(input.centerX, input.centerY, input.startX, input.startY);
|
|
30952
31016
|
const currentAngle = pointerAngleDegrees(
|
|
@@ -30958,7 +31022,7 @@ function resolveDomEditRotationGesture(input) {
|
|
|
30958
31022
|
const delta = normalizeAngleDelta(currentAngle - startAngle);
|
|
30959
31023
|
const angle = input.actualAngle + delta;
|
|
30960
31024
|
return {
|
|
30961
|
-
angle: input.snap ? Math.round(angle / ROTATION_SNAP_DEGREES) * ROTATION_SNAP_DEGREES :
|
|
31025
|
+
angle: input.snap ? Math.round(angle / ROTATION_SNAP_DEGREES) * ROTATION_SNAP_DEGREES : roundTo3(angle)
|
|
30962
31026
|
};
|
|
30963
31027
|
}
|
|
30964
31028
|
function hasDomEditRotationChanged(initialAngle, nextAngle) {
|
|
@@ -31317,9 +31381,6 @@ var STUDIO_ROTATION_TRANSFORM_ORIGIN = "center center";
|
|
|
31317
31381
|
function finiteNumber2(value) {
|
|
31318
31382
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
31319
31383
|
}
|
|
31320
|
-
function roundRotationAngle(angle) {
|
|
31321
|
-
return Math.round(angle * 10) / 10;
|
|
31322
|
-
}
|
|
31323
31384
|
function normalizeStudioFileChangePath(path) {
|
|
31324
31385
|
return path.trim().replace(/\\/g, "/").replace(/^\.?\//, "");
|
|
31325
31386
|
}
|
|
@@ -31523,8 +31584,8 @@ function prepareStudioPathOffsetBase(element, updateBase) {
|
|
|
31523
31584
|
function writeStudioPathOffsetVars(element, offset, options = {}) {
|
|
31524
31585
|
prepareStudioPathOffsetBase(element, options.updateBase ?? true);
|
|
31525
31586
|
element.setAttribute(STUDIO_PATH_OFFSET_ATTR, "true");
|
|
31526
|
-
element.style.setProperty(STUDIO_OFFSET_X_PROP, `${
|
|
31527
|
-
element.style.setProperty(STUDIO_OFFSET_Y_PROP, `${
|
|
31587
|
+
element.style.setProperty(STUDIO_OFFSET_X_PROP, `${roundTo3(offset.x)}px`);
|
|
31588
|
+
element.style.setProperty(STUDIO_OFFSET_Y_PROP, `${roundTo3(offset.y)}px`);
|
|
31528
31589
|
}
|
|
31529
31590
|
function isIdentityAfterTranslateStrip(m) {
|
|
31530
31591
|
return m.is2D && m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1;
|
|
@@ -31594,7 +31655,7 @@ function applyStudioPathOffsetDraft(element, offset) {
|
|
|
31594
31655
|
if (applyStudioPathOffsetViaGsap(element, offset)) return;
|
|
31595
31656
|
element.style.setProperty(
|
|
31596
31657
|
"translate",
|
|
31597
|
-
composeTranslateValue(element, `${
|
|
31658
|
+
composeTranslateValue(element, `${roundTo3(offset.x)}px`, `${roundTo3(offset.y)}px`)
|
|
31598
31659
|
);
|
|
31599
31660
|
stripGsapTranslateFromTransform(element);
|
|
31600
31661
|
}
|
|
@@ -31604,7 +31665,7 @@ function readParentFlexBasisPixels(element, size) {
|
|
|
31604
31665
|
const display2 = readStyleOrComputed(parent, "display").trim();
|
|
31605
31666
|
if (display2 !== "flex" && display2 !== "inline-flex") return null;
|
|
31606
31667
|
const direction = readStyleOrComputed(parent, "flex-direction").trim();
|
|
31607
|
-
return
|
|
31668
|
+
return roundToLayoutPx(Math.max(1, direction.startsWith("column") ? size.height : size.width));
|
|
31608
31669
|
}
|
|
31609
31670
|
function restoreStaleStudioScaleResize(element) {
|
|
31610
31671
|
if (!element.hasAttribute(STUDIO_ORIGINAL_SCALE_ATTR)) return;
|
|
@@ -31667,14 +31728,14 @@ function writeStudioBoxSizeVars(element, size) {
|
|
|
31667
31728
|
element.setAttribute(STUDIO_ORIGINAL_DISPLAY_ATTR, element.style.getPropertyValue("display"));
|
|
31668
31729
|
}
|
|
31669
31730
|
element.setAttribute(STUDIO_BOX_SIZE_ATTR, "true");
|
|
31670
|
-
element.style.setProperty(STUDIO_WIDTH_PROP, `${
|
|
31671
|
-
element.style.setProperty(STUDIO_HEIGHT_PROP, `${
|
|
31731
|
+
element.style.setProperty(STUDIO_WIDTH_PROP, `${roundToLayoutPx(Math.max(1, size.width))}px`);
|
|
31732
|
+
element.style.setProperty(STUDIO_HEIGHT_PROP, `${roundToLayoutPx(Math.max(1, size.height))}px`);
|
|
31672
31733
|
}
|
|
31673
31734
|
function applyStudioBoxSizeDimensions(element, size) {
|
|
31674
31735
|
writeStudioBoxSizeVars(element, size);
|
|
31675
31736
|
restoreStaleStudioScaleResize(element);
|
|
31676
|
-
const width =
|
|
31677
|
-
const height =
|
|
31737
|
+
const width = roundToLayoutPx(Math.max(1, size.width));
|
|
31738
|
+
const height = roundToLayoutPx(Math.max(1, size.height));
|
|
31678
31739
|
element.style.setProperty("box-sizing", "border-box");
|
|
31679
31740
|
element.style.setProperty("width", `${width}px`);
|
|
31680
31741
|
element.style.setProperty("height", `${height}px`);
|
|
@@ -31697,7 +31758,17 @@ function applyStudioBoxSize(element, size) {
|
|
|
31697
31758
|
promoteInlineForTransform(element);
|
|
31698
31759
|
applyStudioBoxSizeDimensions(element, size);
|
|
31699
31760
|
}
|
|
31761
|
+
var boxSizeDraftBases = /* @__PURE__ */ new WeakMap();
|
|
31762
|
+
function readStudioBoxSizeDraftBase(element) {
|
|
31763
|
+
return boxSizeDraftBases.get(element) ?? null;
|
|
31764
|
+
}
|
|
31765
|
+
function forgetStudioBoxSizeDraftBase(element) {
|
|
31766
|
+
boxSizeDraftBases.delete(element);
|
|
31767
|
+
}
|
|
31700
31768
|
function applyStudioBoxSizeDraft(element, size) {
|
|
31769
|
+
if (!boxSizeDraftBases.has(element)) {
|
|
31770
|
+
boxSizeDraftBases.set(element, { width: element.offsetWidth, height: element.offsetHeight });
|
|
31771
|
+
}
|
|
31701
31772
|
promoteInlineForTransform(element);
|
|
31702
31773
|
applyStudioBoxSizeDimensions(element, size);
|
|
31703
31774
|
}
|
|
@@ -31735,7 +31806,7 @@ function prepareStudioRotationBase(element, updateBase) {
|
|
|
31735
31806
|
function writeStudioRotationVars(element, rotation, options = {}) {
|
|
31736
31807
|
prepareStudioRotationBase(element, options.updateBase ?? true);
|
|
31737
31808
|
element.setAttribute(STUDIO_ROTATION_ATTR, "true");
|
|
31738
|
-
element.style.setProperty(STUDIO_ROTATION_PROP, `${
|
|
31809
|
+
element.style.setProperty(STUDIO_ROTATION_PROP, `${roundTo3(rotation.angle)}deg`);
|
|
31739
31810
|
element.style.setProperty("transform-origin", STUDIO_ROTATION_TRANSFORM_ORIGIN);
|
|
31740
31811
|
}
|
|
31741
31812
|
function applyStudioRotation(element, rotation) {
|
|
@@ -31753,7 +31824,7 @@ function applyStudioRotationDraft(element, rotation) {
|
|
|
31753
31824
|
element.setAttribute(STUDIO_ROTATION_DRAFT_ATTR, "true");
|
|
31754
31825
|
element.style.setProperty(
|
|
31755
31826
|
"rotate",
|
|
31756
|
-
composeStudioRotationValue(element, `${
|
|
31827
|
+
composeStudioRotationValue(element, `${roundTo3(rotation.angle)}deg`)
|
|
31757
31828
|
);
|
|
31758
31829
|
}
|
|
31759
31830
|
|
|
@@ -31921,6 +31992,7 @@ function restoreStyleProperty(element, property, value) {
|
|
|
31921
31992
|
else element.style.removeProperty(property);
|
|
31922
31993
|
}
|
|
31923
31994
|
function restoreStudioBoxSize(element, previous) {
|
|
31995
|
+
forgetStudioBoxSizeDraftBase(element);
|
|
31924
31996
|
restoreStyleProperty(element, "width", previous.width);
|
|
31925
31997
|
restoreStyleProperty(element, "height", previous.height);
|
|
31926
31998
|
restoreStyleProperty(element, "min-width", previous.minWidth);
|
|
@@ -32050,6 +32122,7 @@ function clearStudioRotation(element) {
|
|
|
32050
32122
|
element.removeAttribute(STUDIO_ORIGINAL_ROTATION_TRANSFORM_ORIGIN_ATTR);
|
|
32051
32123
|
}
|
|
32052
32124
|
function clearStudioBoxSize(element) {
|
|
32125
|
+
forgetStudioBoxSizeDraftBase(element);
|
|
32053
32126
|
if (element.hasAttribute(STUDIO_BOX_SIZE_ATTR) || styleUsesStudioSize(element.style.getPropertyValue("width")) || styleUsesStudioSize(element.style.getPropertyValue("height")) || element.hasAttribute(STUDIO_ORIGINAL_SCALE_ATTR)) {
|
|
32054
32127
|
restoreOriginalBoxSizeProperty(element, "width", STUDIO_ORIGINAL_WIDTH_ATTR);
|
|
32055
32128
|
restoreOriginalBoxSizeProperty(element, "height", STUDIO_ORIGINAL_HEIGHT_ATTR);
|
|
@@ -32303,13 +32376,341 @@ function computeDraggedGsapPosition(element, studioOffset, fallbackBase) {
|
|
|
32303
32376
|
const baseGsapX = Number.isFinite(parsedBaseX) ? parsedBaseX : fallbackBase.x;
|
|
32304
32377
|
const baseGsapY = Number.isFinite(parsedBaseY) ? parsedBaseY : fallbackBase.y;
|
|
32305
32378
|
return {
|
|
32306
|
-
newX:
|
|
32307
|
-
newY:
|
|
32379
|
+
newX: roundTo3(baseGsapX + adjX),
|
|
32380
|
+
newY: roundTo3(baseGsapY + adjY),
|
|
32308
32381
|
baseGsapX,
|
|
32309
32382
|
baseGsapY
|
|
32310
32383
|
};
|
|
32311
32384
|
}
|
|
32312
32385
|
|
|
32386
|
+
// src/hooks/gsapRuntimeKeyframes.ts
|
|
32387
|
+
import { buildArcPath } from "@hyperframes/core/gsap-parser-acorn";
|
|
32388
|
+
var FLAT_SKIP_KEYS = /* @__PURE__ */ new Set([
|
|
32389
|
+
"ease",
|
|
32390
|
+
"duration",
|
|
32391
|
+
"delay",
|
|
32392
|
+
"stagger",
|
|
32393
|
+
"motionPath",
|
|
32394
|
+
"overwrite",
|
|
32395
|
+
"immediateRender",
|
|
32396
|
+
"onComplete",
|
|
32397
|
+
"onUpdate",
|
|
32398
|
+
"onStart",
|
|
32399
|
+
"keyframes"
|
|
32400
|
+
]);
|
|
32401
|
+
function timelinesOf(iframe) {
|
|
32402
|
+
if (!iframe?.contentWindow) return null;
|
|
32403
|
+
try {
|
|
32404
|
+
return iframe.contentWindow.__timelines ?? null;
|
|
32405
|
+
} catch {
|
|
32406
|
+
return null;
|
|
32407
|
+
}
|
|
32408
|
+
}
|
|
32409
|
+
function isXY(p) {
|
|
32410
|
+
return !!p && typeof p.x === "number" && typeof p.y === "number";
|
|
32411
|
+
}
|
|
32412
|
+
function isZeroDurationSet(duration) {
|
|
32413
|
+
return !(duration > 0);
|
|
32414
|
+
}
|
|
32415
|
+
function coordsFromMotionPath(mp) {
|
|
32416
|
+
if (!mp || typeof mp !== "object") return null;
|
|
32417
|
+
const obj = mp;
|
|
32418
|
+
const pathVal = Array.isArray(mp) ? mp : obj.path;
|
|
32419
|
+
if (!Array.isArray(pathVal)) return null;
|
|
32420
|
+
const coords = pathVal.filter(isXY).map((p) => ({ x: p.x, y: p.y }));
|
|
32421
|
+
if (coords.length < 2) return null;
|
|
32422
|
+
const curviness = typeof obj.curviness === "number" ? obj.curviness : 1;
|
|
32423
|
+
const autoRotate = typeof obj.autoRotate === "number" ? obj.autoRotate : obj.autoRotate === true;
|
|
32424
|
+
return { coords, curviness, autoRotate, isCubic: obj.type === "cubic" };
|
|
32425
|
+
}
|
|
32426
|
+
function flatTweenKeyframes(vars) {
|
|
32427
|
+
const properties = {};
|
|
32428
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
32429
|
+
if (FLAT_SKIP_KEYS.has(k)) continue;
|
|
32430
|
+
if (typeof v === "number") properties[k] = roundTo3(v);
|
|
32431
|
+
else if (typeof v === "string") properties[k] = v;
|
|
32432
|
+
}
|
|
32433
|
+
if (Object.keys(properties).length === 0) return null;
|
|
32434
|
+
return [
|
|
32435
|
+
{ percentage: 0, properties },
|
|
32436
|
+
{ percentage: 100, properties }
|
|
32437
|
+
];
|
|
32438
|
+
}
|
|
32439
|
+
function readTween(vars) {
|
|
32440
|
+
if (vars.keyframes && typeof vars.keyframes === "object") {
|
|
32441
|
+
const parsed = parsePercentageKeyframes(vars.keyframes);
|
|
32442
|
+
if (parsed) return parsed;
|
|
32443
|
+
}
|
|
32444
|
+
const mp = coordsFromMotionPath(vars.motionPath);
|
|
32445
|
+
if (mp) {
|
|
32446
|
+
const shape = buildArcPath(mp.coords, mp.curviness, mp.autoRotate, mp.isCubic);
|
|
32447
|
+
if (shape) {
|
|
32448
|
+
const n = shape.waypoints.length;
|
|
32449
|
+
const keyframes = shape.waypoints.map((wp, i) => ({
|
|
32450
|
+
percentage: n > 1 ? Math.round(i / (n - 1) * 100) : 0,
|
|
32451
|
+
properties: { x: wp.x, y: wp.y }
|
|
32452
|
+
}));
|
|
32453
|
+
return { keyframes, arcPath: shape.arcPath };
|
|
32454
|
+
}
|
|
32455
|
+
}
|
|
32456
|
+
const flat = flatTweenKeyframes(vars);
|
|
32457
|
+
return flat ? { keyframes: flat } : null;
|
|
32458
|
+
}
|
|
32459
|
+
function matchesElement(tween, el) {
|
|
32460
|
+
if (!tween.targets) return false;
|
|
32461
|
+
for (const t of tween.targets()) {
|
|
32462
|
+
if (t === el || el.id && t.id === el.id) return true;
|
|
32463
|
+
}
|
|
32464
|
+
return false;
|
|
32465
|
+
}
|
|
32466
|
+
function tweenTiming(tween) {
|
|
32467
|
+
const rawStart = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
32468
|
+
const rawDur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
32469
|
+
return {
|
|
32470
|
+
start: Number.isFinite(rawStart) ? rawStart : 0,
|
|
32471
|
+
duration: Number.isFinite(rawDur) ? rawDur : 0
|
|
32472
|
+
};
|
|
32473
|
+
}
|
|
32474
|
+
function varsCarryChannel(vars, channels) {
|
|
32475
|
+
if (!vars) return false;
|
|
32476
|
+
for (const ch of channels) {
|
|
32477
|
+
if (Object.prototype.hasOwnProperty.call(vars, ch)) return true;
|
|
32478
|
+
}
|
|
32479
|
+
return false;
|
|
32480
|
+
}
|
|
32481
|
+
function keyframeVarsCarryChannel(vars, channels) {
|
|
32482
|
+
const kf = vars?.keyframes;
|
|
32483
|
+
if (!kf || typeof kf !== "object") return false;
|
|
32484
|
+
if (!Array.isArray(kf) && channels.some((ch) => Object.prototype.hasOwnProperty.call(kf, ch)))
|
|
32485
|
+
return true;
|
|
32486
|
+
const steps = Array.isArray(kf) ? kf : Object.values(kf);
|
|
32487
|
+
return steps.some(
|
|
32488
|
+
(step) => step != null && typeof step === "object" && channels.some((ch) => Object.prototype.hasOwnProperty.call(step, ch))
|
|
32489
|
+
);
|
|
32490
|
+
}
|
|
32491
|
+
function resolveRuntimeTween(iframe, selector, kind, compositionId, channels) {
|
|
32492
|
+
const timelines = timelinesOf(iframe);
|
|
32493
|
+
if (!timelines) return null;
|
|
32494
|
+
let targetEl = null;
|
|
32495
|
+
try {
|
|
32496
|
+
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
32497
|
+
} catch {
|
|
32498
|
+
return null;
|
|
32499
|
+
}
|
|
32500
|
+
if (!targetEl) return null;
|
|
32501
|
+
const tlIds = compositionId ? [compositionId] : Object.keys(timelines).filter((k) => typeof timelines[k]?.getChildren === "function");
|
|
32502
|
+
const wantChannels = channels && channels.length > 0 ? channels : null;
|
|
32503
|
+
let first = null;
|
|
32504
|
+
let channelMatch = null;
|
|
32505
|
+
for (const tlId of tlIds) {
|
|
32506
|
+
const timeline = timelines[tlId];
|
|
32507
|
+
if (!timeline?.getChildren) continue;
|
|
32508
|
+
const now2 = typeof timeline.time === "function" ? timeline.time() : null;
|
|
32509
|
+
for (const tween of timeline.getChildren(true)) {
|
|
32510
|
+
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
32511
|
+
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
32512
|
+
const isSet = !(dur > 0);
|
|
32513
|
+
if (kind === "set" ? !isSet : isSet) continue;
|
|
32514
|
+
if (wantChannels) {
|
|
32515
|
+
const carries = kind === "set" ? varsCarryChannel(tween.vars, wantChannels) : keyframeVarsCarryChannel(tween.vars, wantChannels);
|
|
32516
|
+
if (carries) {
|
|
32517
|
+
if (channelMatch === null) channelMatch = { tween, timeline };
|
|
32518
|
+
} else if (first === null) {
|
|
32519
|
+
first = { tween, timeline };
|
|
32520
|
+
}
|
|
32521
|
+
continue;
|
|
32522
|
+
}
|
|
32523
|
+
if (first === null) first = { tween, timeline };
|
|
32524
|
+
if (kind === "keyframe" && now2 != null) {
|
|
32525
|
+
const start = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
32526
|
+
if (now2 >= start - 1e-3 && now2 <= start + dur + 1e-3) return { tween, timeline };
|
|
32527
|
+
}
|
|
32528
|
+
}
|
|
32529
|
+
}
|
|
32530
|
+
return channelMatch ?? first;
|
|
32531
|
+
}
|
|
32532
|
+
function readCarriesChannel(read, channels) {
|
|
32533
|
+
return read.keyframes.some((kf) => channels.some((c) => kf.properties[c] != null));
|
|
32534
|
+
}
|
|
32535
|
+
function readRuntimeKeyframes(iframe, selector, compositionId, requireChannels) {
|
|
32536
|
+
const timelines = timelinesOf(iframe);
|
|
32537
|
+
if (!timelines) return null;
|
|
32538
|
+
let targetEl = null;
|
|
32539
|
+
try {
|
|
32540
|
+
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
32541
|
+
} catch {
|
|
32542
|
+
return null;
|
|
32543
|
+
}
|
|
32544
|
+
if (!targetEl) return null;
|
|
32545
|
+
const tlIds = compositionId ? [compositionId] : Object.keys(timelines).filter((k) => typeof timelines[k]?.getChildren === "function");
|
|
32546
|
+
if (tlIds.length === 0) return null;
|
|
32547
|
+
let firstRead = null;
|
|
32548
|
+
for (const tlId of tlIds) {
|
|
32549
|
+
const timeline = timelines[tlId];
|
|
32550
|
+
if (!timeline?.getChildren) continue;
|
|
32551
|
+
const now2 = typeof timeline.time === "function" ? timeline.time() : null;
|
|
32552
|
+
for (const tween of timeline.getChildren(true)) {
|
|
32553
|
+
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
32554
|
+
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
32555
|
+
if (isZeroDurationSet(dur)) continue;
|
|
32556
|
+
const read = readTween(tween.vars);
|
|
32557
|
+
if (!read) continue;
|
|
32558
|
+
if (requireChannels && !readCarriesChannel(read, requireChannels)) continue;
|
|
32559
|
+
if (firstRead === null) firstRead = read;
|
|
32560
|
+
if (now2 != null) {
|
|
32561
|
+
const start = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
32562
|
+
if (now2 >= start - 1e-3 && now2 <= start + dur + 1e-3) return read;
|
|
32563
|
+
}
|
|
32564
|
+
}
|
|
32565
|
+
}
|
|
32566
|
+
return firstRead;
|
|
32567
|
+
}
|
|
32568
|
+
function hasNonHoldTweenForElement(iframe, selector, compositionId, channels) {
|
|
32569
|
+
let targetEl = null;
|
|
32570
|
+
try {
|
|
32571
|
+
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
32572
|
+
} catch {
|
|
32573
|
+
return false;
|
|
32574
|
+
}
|
|
32575
|
+
return !!targetEl && hasNonHoldTween(timelinesOf(iframe), targetEl, channels, compositionId);
|
|
32576
|
+
}
|
|
32577
|
+
var POSITION_CHANNELS = [
|
|
32578
|
+
"x",
|
|
32579
|
+
"y",
|
|
32580
|
+
"xPercent",
|
|
32581
|
+
"yPercent",
|
|
32582
|
+
"left",
|
|
32583
|
+
"top",
|
|
32584
|
+
// readTween reads the authored translateX/Y; GSAP normalizes them to x/y only at play time.
|
|
32585
|
+
"translateX",
|
|
32586
|
+
"translateY"
|
|
32587
|
+
];
|
|
32588
|
+
var MOVE_CHANNELS = [...POSITION_CHANNELS, "motionPath"];
|
|
32589
|
+
function gsapWritesChannels(el, channels) {
|
|
32590
|
+
const win = el.ownerDocument.defaultView;
|
|
32591
|
+
return Object.values(win?.__timelines ?? {}).some(
|
|
32592
|
+
(tl) => (tl?.getChildren?.(true) ?? []).some(
|
|
32593
|
+
(tween) => !!tween.vars && matchesElement(tween, el) && (channels.some((ch) => ch in tween.vars) || keyframeVarsCarryChannel(tween.vars, channels))
|
|
32594
|
+
)
|
|
32595
|
+
);
|
|
32596
|
+
}
|
|
32597
|
+
function gsapWritesPosition(el) {
|
|
32598
|
+
const cache2 = el._gsap;
|
|
32599
|
+
return !!cache2?.renderTransform || gsapWritesChannels(el, MOVE_CHANNELS);
|
|
32600
|
+
}
|
|
32601
|
+
function elementHasNonHoldTween(el, channels) {
|
|
32602
|
+
const win = el.ownerDocument.defaultView;
|
|
32603
|
+
return hasNonHoldTween(win?.__timelines ?? null, el, channels);
|
|
32604
|
+
}
|
|
32605
|
+
function hasNonHoldTween(timelines, targetEl, channels, compositionId) {
|
|
32606
|
+
if (!timelines) return false;
|
|
32607
|
+
for (const tlId of compositionId ? [compositionId] : Object.keys(timelines)) {
|
|
32608
|
+
for (const tween of timelines[tlId]?.getChildren?.(true) ?? []) {
|
|
32609
|
+
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
32610
|
+
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
32611
|
+
if (isZeroDurationSet(dur)) continue;
|
|
32612
|
+
if (channels && keyframeVarsCarryChannel(tween.vars, channels)) return true;
|
|
32613
|
+
const read = readTween(tween.vars);
|
|
32614
|
+
if (read && (!channels || readCarriesChannel(read, channels))) return true;
|
|
32615
|
+
}
|
|
32616
|
+
}
|
|
32617
|
+
return false;
|
|
32618
|
+
}
|
|
32619
|
+
function toClipRelative(keyframes, tweenStart, tweenDuration, clip) {
|
|
32620
|
+
if (!clip || clip.duration <= 0) return keyframes;
|
|
32621
|
+
return keyframes.map((kf) => {
|
|
32622
|
+
const abs = toAbsoluteTime(tweenStart, tweenDuration, kf.percentage);
|
|
32623
|
+
return { ...kf, percentage: Math.round((abs - clip.start) / clip.duration * 1e5) / 1e3 };
|
|
32624
|
+
});
|
|
32625
|
+
}
|
|
32626
|
+
function buildEntry(read, start, duration, clip) {
|
|
32627
|
+
return {
|
|
32628
|
+
keyframes: toClipRelative(read.keyframes, start, duration, clip),
|
|
32629
|
+
tweenStart: start,
|
|
32630
|
+
tweenDuration: duration,
|
|
32631
|
+
...read.easeEach ? { easeEach: read.easeEach } : {},
|
|
32632
|
+
...read.arcPath ? { arcPath: read.arcPath } : {}
|
|
32633
|
+
};
|
|
32634
|
+
}
|
|
32635
|
+
function addScanEntry(result, tween, clipById) {
|
|
32636
|
+
if (!tween.targets || !tween.vars) return;
|
|
32637
|
+
const { start, duration } = tweenTiming(tween);
|
|
32638
|
+
if (isZeroDurationSet(duration)) return;
|
|
32639
|
+
const read = readTween(tween.vars);
|
|
32640
|
+
if (!read) return;
|
|
32641
|
+
for (const target of tween.targets()) {
|
|
32642
|
+
const id = target.id;
|
|
32643
|
+
if (id && !result.has(id)) result.set(id, buildEntry(read, start, duration, clipById?.get(id)));
|
|
32644
|
+
}
|
|
32645
|
+
}
|
|
32646
|
+
function scanAllRuntimeKeyframes(iframe, clipById) {
|
|
32647
|
+
const result = /* @__PURE__ */ new Map();
|
|
32648
|
+
const timelines = timelinesOf(iframe);
|
|
32649
|
+
if (!timelines) return result;
|
|
32650
|
+
for (const timeline of Object.values(timelines)) {
|
|
32651
|
+
if (!timeline?.getChildren) continue;
|
|
32652
|
+
for (const tween of timeline.getChildren(true)) addScanEntry(result, tween, clipById);
|
|
32653
|
+
}
|
|
32654
|
+
return result;
|
|
32655
|
+
}
|
|
32656
|
+
|
|
32657
|
+
// src/components/editor/plainTranslate.ts
|
|
32658
|
+
var TERM = /^(-?\d*\.?\d+(?:e[-+]?\d+)?)(px|%)$/i;
|
|
32659
|
+
var SIGN = { "+": 1, "-": -1 };
|
|
32660
|
+
function termPx(term, side) {
|
|
32661
|
+
const match = TERM.exec(term ?? "");
|
|
32662
|
+
return match ? Number(match[1]) * (match[2] === "%" ? side / 100 : 1) : null;
|
|
32663
|
+
}
|
|
32664
|
+
function resolveLength(value, side) {
|
|
32665
|
+
const parts = (/^calc\((.*)\)$/.exec(value)?.[1] ?? value).split(" ");
|
|
32666
|
+
if (parts.length % 2 === 0) return null;
|
|
32667
|
+
let total = termPx(parts[0], side);
|
|
32668
|
+
for (let i = 1; i < parts.length && total !== null; i += 2) {
|
|
32669
|
+
const term = termPx(parts[i + 1], side);
|
|
32670
|
+
const sign = SIGN[parts[i] ?? ""];
|
|
32671
|
+
total = term === null || !sign ? null : total + sign * term;
|
|
32672
|
+
}
|
|
32673
|
+
return total;
|
|
32674
|
+
}
|
|
32675
|
+
function borderBox(cs, size, a, b) {
|
|
32676
|
+
const n = (prop) => Number.parseFloat(cs.getPropertyValue(prop)) || 0;
|
|
32677
|
+
const pad = n(`padding-${a}`) + n(`padding-${b}`) + n(`border-${a}-width`) + n(`border-${b}-width`);
|
|
32678
|
+
return n(size) + (cs.boxSizing === "border-box" ? 0 : pad);
|
|
32679
|
+
}
|
|
32680
|
+
function resolveInTransform(el, x, y) {
|
|
32681
|
+
const style = el.style;
|
|
32682
|
+
const saved2 = [style.getPropertyValue("transform"), style.getPropertyPriority("transform")];
|
|
32683
|
+
style.setProperty("transform", `translate(${x}, ${y})`, "important");
|
|
32684
|
+
try {
|
|
32685
|
+
const resolved2 = el.ownerDocument.defaultView?.getComputedStyle(el).transform ?? "";
|
|
32686
|
+
const matrix = new DOMMatrixReadOnly(resolved2.startsWith("matrix") ? resolved2 : void 0);
|
|
32687
|
+
return { x: matrix.m41, y: matrix.m42 };
|
|
32688
|
+
} finally {
|
|
32689
|
+
style.setProperty("transform", saved2[0] ?? "", saved2[1] ?? "");
|
|
32690
|
+
}
|
|
32691
|
+
}
|
|
32692
|
+
function readTranslatePx(el) {
|
|
32693
|
+
const cs = el.ownerDocument.defaultView?.getComputedStyle(el);
|
|
32694
|
+
const value = el.style.getPropertyValue("translate") || cs?.translate || "none";
|
|
32695
|
+
if (value === "none") return { x: 0, y: 0 };
|
|
32696
|
+
const [x = "0px", y = "0px"] = splitTopLevelWhitespace(value);
|
|
32697
|
+
const px = cs && resolveLength(x, borderBox(cs, "width", "left", "right"));
|
|
32698
|
+
const py = cs && resolveLength(y, borderBox(cs, "height", "top", "bottom"));
|
|
32699
|
+
return px != null && py != null ? { x: px, y: py } : resolveInTransform(el, x, y);
|
|
32700
|
+
}
|
|
32701
|
+
function formatTranslatePx(p) {
|
|
32702
|
+
return `${roundTo3(p.x)}px ${roundTo3(p.y)}px`;
|
|
32703
|
+
}
|
|
32704
|
+
function translatePatch(p) {
|
|
32705
|
+
return { type: "inline-style", property: "translate", value: formatTranslatePx(p) };
|
|
32706
|
+
}
|
|
32707
|
+
function writeTranslatePx(el, p) {
|
|
32708
|
+
el.style.setProperty("translate", formatTranslatePx(p));
|
|
32709
|
+
}
|
|
32710
|
+
function readMoveOffset(el) {
|
|
32711
|
+
return gsapWritesPosition(el) ? readStudioPathOffset(el) : readTranslatePx(el);
|
|
32712
|
+
}
|
|
32713
|
+
|
|
32313
32714
|
// src/components/editor/manualOffsetDrag.ts
|
|
32314
32715
|
function getOffsetDragGsap(element) {
|
|
32315
32716
|
const win = element.ownerDocument.defaultView;
|
|
@@ -32421,14 +32822,15 @@ function measureManualOffsetDragScreenToOffsetMatrix(element, initialOffset, opt
|
|
|
32421
32822
|
if (!Number.isFinite(probeSize) || probeSize <= 0) {
|
|
32422
32823
|
return { ok: false, reason: "Invalid movement probe size." };
|
|
32423
32824
|
}
|
|
32825
|
+
const draw = options.plainTranslate ? writeTranslatePx : applyStudioPathOffsetDraft;
|
|
32424
32826
|
const snapshot3 = captureStudioPathOffset(element);
|
|
32425
32827
|
try {
|
|
32426
|
-
|
|
32828
|
+
draw(element, initialOffset);
|
|
32427
32829
|
const origin = getRectCenter(element);
|
|
32428
32830
|
if (!origin) {
|
|
32429
32831
|
return { ok: false, reason: "Element has no measurable box." };
|
|
32430
32832
|
}
|
|
32431
|
-
|
|
32833
|
+
draw(element, {
|
|
32432
32834
|
x: initialOffset.x + probeSize,
|
|
32433
32835
|
y: initialOffset.y
|
|
32434
32836
|
});
|
|
@@ -32436,7 +32838,7 @@ function measureManualOffsetDragScreenToOffsetMatrix(element, initialOffset, opt
|
|
|
32436
32838
|
if (!probeX) {
|
|
32437
32839
|
return { ok: false, reason: "Element X movement could not be measured." };
|
|
32438
32840
|
}
|
|
32439
|
-
|
|
32841
|
+
draw(element, {
|
|
32440
32842
|
x: initialOffset.x,
|
|
32441
32843
|
y: initialOffset.y + probeSize
|
|
32442
32844
|
});
|
|
@@ -32481,14 +32883,13 @@ function resolveManualOffsetForPointerDelta(input) {
|
|
|
32481
32883
|
};
|
|
32482
32884
|
}
|
|
32483
32885
|
function createManualOffsetDragMember(input) {
|
|
32484
|
-
const
|
|
32485
|
-
input.element
|
|
32486
|
-
input.element.setAttribute("data-hf-drag-initial-offset-y", String(initialOffset.y));
|
|
32886
|
+
const plainTranslate = !!input.gesture && !gsapWritesPosition(input.element);
|
|
32887
|
+
const initialOffset = plainTranslate ? readTranslatePx(input.element) : readAppliedStudioPathOffset(input.element);
|
|
32487
32888
|
const win = input.element.ownerDocument.defaultView;
|
|
32488
|
-
const gsapX = win?.gsap?.getProperty?.(input.element, "x") || 0;
|
|
32489
|
-
const gsapY = win?.gsap?.getProperty?.(input.element, "y") || 0;
|
|
32490
|
-
|
|
32491
|
-
input.element
|
|
32889
|
+
const gsapX = !plainTranslate && win?.gsap?.getProperty?.(input.element, "x") || 0;
|
|
32890
|
+
const gsapY = !plainTranslate && win?.gsap?.getProperty?.(input.element, "y") || 0;
|
|
32891
|
+
const baseGsap = { x: gsapX, y: gsapY };
|
|
32892
|
+
if (!plainTranslate) stampGestureBase(input.element, initialOffset, baseGsap);
|
|
32492
32893
|
if (win?.__timelines) {
|
|
32493
32894
|
const paused = [];
|
|
32494
32895
|
for (const [id, tl] of Object.entries(win.__timelines)) {
|
|
@@ -32508,9 +32909,9 @@ function createManualOffsetDragMember(input) {
|
|
|
32508
32909
|
const gestureToken = beginStudioManualEditGesture(input.element);
|
|
32509
32910
|
const measured = measureManualOffsetDragScreenToOffsetMatrix(input.element, initialOffset, {
|
|
32510
32911
|
scaleX: input.rect.editScaleX,
|
|
32511
|
-
scaleY: input.rect.editScaleY
|
|
32912
|
+
scaleY: input.rect.editScaleY,
|
|
32913
|
+
plainTranslate
|
|
32512
32914
|
});
|
|
32513
|
-
const baseGsap = { x: gsapX, y: gsapY };
|
|
32514
32915
|
if (!measured.ok) {
|
|
32515
32916
|
const scaleX = input.rect.editScaleX || 1;
|
|
32516
32917
|
const scaleY = input.rect.editScaleY || 1;
|
|
@@ -32522,6 +32923,7 @@ function createManualOffsetDragMember(input) {
|
|
|
32522
32923
|
selection: input.selection,
|
|
32523
32924
|
element: input.element,
|
|
32524
32925
|
initialOffset,
|
|
32926
|
+
plainTranslate,
|
|
32525
32927
|
baseGsap,
|
|
32526
32928
|
initialPathOffset,
|
|
32527
32929
|
gestureToken,
|
|
@@ -32537,6 +32939,7 @@ function createManualOffsetDragMember(input) {
|
|
|
32537
32939
|
selection: input.selection,
|
|
32538
32940
|
element: input.element,
|
|
32539
32941
|
initialOffset,
|
|
32942
|
+
plainTranslate,
|
|
32540
32943
|
baseGsap,
|
|
32541
32944
|
initialPathOffset,
|
|
32542
32945
|
gestureToken,
|
|
@@ -32553,24 +32956,27 @@ function resolveManualOffsetDragMemberOffset(member, dx, dy) {
|
|
|
32553
32956
|
dy
|
|
32554
32957
|
});
|
|
32555
32958
|
}
|
|
32959
|
+
function drawMemberOffset(member, offset, commit) {
|
|
32960
|
+
if (member.plainTranslate) writeTranslatePx(member.element, offset);
|
|
32961
|
+
else if (applyOffsetDragDraftViaGsap(member.element, offset, member.baseGsap)) return;
|
|
32962
|
+
else if (commit) applyStudioPathOffset(member.element, offset);
|
|
32963
|
+
else applyStudioPathOffsetDraft(member.element, offset);
|
|
32964
|
+
}
|
|
32556
32965
|
function applyManualOffsetDragDraft(member, dx, dy) {
|
|
32557
32966
|
const offset = resolveManualOffsetDragMemberOffset(member, dx, dy);
|
|
32558
|
-
|
|
32559
|
-
applyStudioPathOffsetDraft(member.element, offset);
|
|
32560
|
-
}
|
|
32967
|
+
drawMemberOffset(member, offset, false);
|
|
32561
32968
|
return offset;
|
|
32562
32969
|
}
|
|
32563
|
-
function
|
|
32564
|
-
|
|
32565
|
-
|
|
32566
|
-
|
|
32567
|
-
|
|
32970
|
+
function stampGestureBase(el, initialOffset, baseGsap) {
|
|
32971
|
+
el.setAttribute("data-hf-drag-gsap-base-x", String(baseGsap.x));
|
|
32972
|
+
el.setAttribute("data-hf-drag-gsap-base-y", String(baseGsap.y));
|
|
32973
|
+
el.setAttribute("data-hf-drag-initial-offset-x", String(initialOffset.x));
|
|
32974
|
+
el.setAttribute("data-hf-drag-initial-offset-y", String(initialOffset.y));
|
|
32568
32975
|
}
|
|
32569
32976
|
function applyManualOffsetCommitValue(member, offset) {
|
|
32570
|
-
|
|
32571
|
-
|
|
32572
|
-
|
|
32573
|
-
}
|
|
32977
|
+
if (!member.plainTranslate)
|
|
32978
|
+
stampGestureBase(member.element, member.initialOffset, member.baseGsap);
|
|
32979
|
+
drawMemberOffset(member, offset, true);
|
|
32574
32980
|
return offset;
|
|
32575
32981
|
}
|
|
32576
32982
|
function applyManualOffsetDragCommit(member, dx, dy) {
|
|
@@ -32581,9 +32987,7 @@ function applyManualOffsetNudgeDraft(member, delta) {
|
|
|
32581
32987
|
x: member.initialOffset.x + delta.x,
|
|
32582
32988
|
y: member.initialOffset.y + delta.y
|
|
32583
32989
|
};
|
|
32584
|
-
|
|
32585
|
-
applyStudioPathOffsetDraft(member.element, offset);
|
|
32586
|
-
}
|
|
32990
|
+
drawMemberOffset(member, offset, false);
|
|
32587
32991
|
return offset;
|
|
32588
32992
|
}
|
|
32589
32993
|
function applyManualOffsetNudgeCommit(member, delta) {
|
|
@@ -32594,7 +32998,9 @@ function applyManualOffsetNudgeCommit(member, delta) {
|
|
|
32594
32998
|
}
|
|
32595
32999
|
function restoreManualOffsetDragMember(member) {
|
|
32596
33000
|
restoreStudioPathOffset(member.element, member.initialPathOffset);
|
|
32597
|
-
|
|
33001
|
+
if (!member.plainTranslate) {
|
|
33002
|
+
getOffsetDragGsap(member.element)?.set(member.element, { ...member.baseGsap });
|
|
33003
|
+
}
|
|
32598
33004
|
endStudioManualEditGesture(member.element, member.gestureToken);
|
|
32599
33005
|
}
|
|
32600
33006
|
function restoreManualOffsetDragMembers(members) {
|
|
@@ -32619,7 +33025,7 @@ function endManualOffsetDragMembers(members) {
|
|
|
32619
33025
|
member.element.removeAttribute("data-hf-drag-initial-offset-y");
|
|
32620
33026
|
member.element.removeAttribute("data-hf-drag-gsap-base-x");
|
|
32621
33027
|
member.element.removeAttribute("data-hf-drag-gsap-base-y");
|
|
32622
|
-
const gsapOwnsPosition = Boolean(getOffsetDragGsap(member.element));
|
|
33028
|
+
const gsapOwnsPosition = !member.plainTranslate && Boolean(getOffsetDragGsap(member.element));
|
|
32623
33029
|
if (gsapOwnsPosition) clearStudioPathOffset(member.element);
|
|
32624
33030
|
settleDraftTranslate(member.element, gsapOwnsPosition);
|
|
32625
33031
|
resumeGsapTimelines(member.element);
|
|
@@ -33272,7 +33678,8 @@ function startGroupDrag(e, opts) {
|
|
|
33272
33678
|
key: item.key,
|
|
33273
33679
|
selection: item.selection,
|
|
33274
33680
|
element: item.element,
|
|
33275
|
-
rect: item.rect
|
|
33681
|
+
rect: item.rect,
|
|
33682
|
+
gesture: "drag"
|
|
33276
33683
|
});
|
|
33277
33684
|
if (!result.ok) {
|
|
33278
33685
|
restoreManualOffsetDragMembers(members);
|
|
@@ -33336,7 +33743,6 @@ function startGesture(kind, e, opts, options) {
|
|
|
33336
33743
|
if (kind === "resize" && (!Number.isFinite(rect.width) || !Number.isFinite(rect.height)))
|
|
33337
33744
|
return false;
|
|
33338
33745
|
const size = readStudioBoxSize(sel.element);
|
|
33339
|
-
const rotation = { angle: readGsapRotation(sel.element) + readStudioRotation(sel.element).angle };
|
|
33340
33746
|
const layoutWidth = sel.element.offsetWidth;
|
|
33341
33747
|
const layoutHeight = sel.element.offsetHeight;
|
|
33342
33748
|
const actualWidth = size.width > 0 ? size.width : layoutWidth > 0 ? layoutWidth : rect.width / rect.editScaleX;
|
|
@@ -33367,7 +33773,8 @@ function startGesture(kind, e, opts, options) {
|
|
|
33367
33773
|
key: selectionCacheKey(sel),
|
|
33368
33774
|
selection: sel,
|
|
33369
33775
|
element: sel.element,
|
|
33370
|
-
rect
|
|
33776
|
+
rect,
|
|
33777
|
+
gesture: "drag"
|
|
33371
33778
|
});
|
|
33372
33779
|
if (!result.ok) {
|
|
33373
33780
|
opts.onBlockedMoveRef.current(result.selection);
|
|
@@ -33396,6 +33803,8 @@ function startGesture(kind, e, opts, options) {
|
|
|
33396
33803
|
manualEditDragToken = beginStudioManualEditGesture(sel.element);
|
|
33397
33804
|
}
|
|
33398
33805
|
}
|
|
33806
|
+
const gsapRotation = pathOffsetMember?.plainTranslate ? 0 : readGsapRotation(sel.element);
|
|
33807
|
+
const rotation = { angle: gsapRotation + readStudioRotation(sel.element).angle };
|
|
33399
33808
|
const overlayBounds = overlayEl?.getBoundingClientRect();
|
|
33400
33809
|
const centerX = (overlayBounds?.left ?? 0) + rect.left + rect.width / 2;
|
|
33401
33810
|
const centerY = (overlayBounds?.top ?? 0) + rect.top + rect.height / 2;
|
|
@@ -34112,7 +34521,7 @@ function useDomEditNudge(params) {
|
|
|
34112
34521
|
if (!targets) return null;
|
|
34113
34522
|
const members = [];
|
|
34114
34523
|
for (const target of targets) {
|
|
34115
|
-
const result = createManualOffsetDragMember(target);
|
|
34524
|
+
const result = createManualOffsetDragMember({ ...target, gesture: "nudge" });
|
|
34116
34525
|
if (!result.ok) {
|
|
34117
34526
|
restoreManualOffsetDragMembers(members);
|
|
34118
34527
|
return null;
|
|
@@ -34301,6 +34710,93 @@ var SnapGuideOverlay = memo23(function SnapGuideOverlay2({
|
|
|
34301
34710
|
|
|
34302
34711
|
// src/components/editor/DomEditCropHandles.tsx
|
|
34303
34712
|
import { useEffect as useEffect44, useRef as useRef65, useState as useState40 } from "react";
|
|
34713
|
+
|
|
34714
|
+
// src/components/editor/cropResize.ts
|
|
34715
|
+
var boxOf = (element) => ({
|
|
34716
|
+
width: element.offsetWidth,
|
|
34717
|
+
height: element.offsetHeight
|
|
34718
|
+
});
|
|
34719
|
+
function cropFollows(element) {
|
|
34720
|
+
const clip = gsapAnimatesProperty(element, "clipPath");
|
|
34721
|
+
return {
|
|
34722
|
+
width: !clip && !elementHasNonHoldTween(element, ["width"]),
|
|
34723
|
+
height: !clip && !elementHasNonHoldTween(element, ["height"])
|
|
34724
|
+
};
|
|
34725
|
+
}
|
|
34726
|
+
function scaleCrop(crop, from, to, follows) {
|
|
34727
|
+
const sx = follows.width && from.width > 0 ? to.width / from.width : 1;
|
|
34728
|
+
const sy = follows.height && from.height > 0 ? to.height / from.height : 1;
|
|
34729
|
+
return {
|
|
34730
|
+
top: crop.top * sy,
|
|
34731
|
+
right: crop.right * sx,
|
|
34732
|
+
bottom: crop.bottom * sy,
|
|
34733
|
+
left: crop.left * sx,
|
|
34734
|
+
radius: crop.radius
|
|
34735
|
+
};
|
|
34736
|
+
}
|
|
34737
|
+
function readCropFollowingResize(element) {
|
|
34738
|
+
const crop = readElementCropInsets(element);
|
|
34739
|
+
const base2 = readStudioBoxSizeDraftBase(element);
|
|
34740
|
+
return crop && base2 ? scaleCrop(crop, base2, boxOf(element), cropFollows(element)) : crop;
|
|
34741
|
+
}
|
|
34742
|
+
function prepareCropResize(element) {
|
|
34743
|
+
const from = readStudioBoxSizeDraftBase(element) ?? boxOf(element);
|
|
34744
|
+
const before = element.style.getPropertyValue("clip-path");
|
|
34745
|
+
const priority = element.style.getPropertyPriority("clip-path");
|
|
34746
|
+
const follows = cropFollows(element);
|
|
34747
|
+
const crop = readElementCropInsets(element);
|
|
34748
|
+
return () => {
|
|
34749
|
+
forgetStudioBoxSizeDraftBase(element);
|
|
34750
|
+
const to = boxOf(element);
|
|
34751
|
+
const untouched = element.style.getPropertyValue("clip-path") === before;
|
|
34752
|
+
if (!crop || !hasCropInsets(crop) || !untouched || !(to.width > 0 && to.height > 0))
|
|
34753
|
+
return null;
|
|
34754
|
+
const clip = buildInsetClipPathSides(scaleCrop(crop, from, to, follows), crop.radius);
|
|
34755
|
+
if (clip === buildInsetClipPathSides(crop, crop.radius)) return null;
|
|
34756
|
+
element.style.setProperty("clip-path", clip, priority);
|
|
34757
|
+
return {
|
|
34758
|
+
patch: {
|
|
34759
|
+
type: "inline-style",
|
|
34760
|
+
property: "clip-path",
|
|
34761
|
+
value: priority ? `${clip} !important` : clip
|
|
34762
|
+
},
|
|
34763
|
+
revert: () => {
|
|
34764
|
+
if (before) element.style.setProperty("clip-path", before, priority);
|
|
34765
|
+
else element.style.removeProperty("clip-path");
|
|
34766
|
+
}
|
|
34767
|
+
};
|
|
34768
|
+
};
|
|
34769
|
+
}
|
|
34770
|
+
async function saveCropResize(stage, selection, commit, coalesceKey) {
|
|
34771
|
+
const crop = stage();
|
|
34772
|
+
if (!crop) return;
|
|
34773
|
+
try {
|
|
34774
|
+
await commit(selection, [crop.patch], {
|
|
34775
|
+
label: "Resize layer",
|
|
34776
|
+
coalesceKey,
|
|
34777
|
+
coalesceMs: Number.POSITIVE_INFINITY
|
|
34778
|
+
});
|
|
34779
|
+
} catch (error) {
|
|
34780
|
+
crop.revert();
|
|
34781
|
+
throw error;
|
|
34782
|
+
}
|
|
34783
|
+
}
|
|
34784
|
+
var sizeWriteCounter = 0;
|
|
34785
|
+
async function writeSizeWithCrop(selection, properties, mutation, commit, write) {
|
|
34786
|
+
if (!mutation || !("width" in properties || "height" in properties)) return write();
|
|
34787
|
+
const stage = prepareCropResize(selection.element);
|
|
34788
|
+
const coalesceKey = `size-write:${++sizeWriteCounter}`;
|
|
34789
|
+
const undoStep = { coalesceKey, coalesceMs: Number.POSITIVE_INFINITY };
|
|
34790
|
+
const keyed = (s, m, options) => mutation(s, m, { ...options, ...undoStep });
|
|
34791
|
+
if (mutation.batch) {
|
|
34792
|
+
const batch = mutation.batch;
|
|
34793
|
+
keyed.batch = (calls, options) => batch(calls, { ...options, ...undoStep });
|
|
34794
|
+
}
|
|
34795
|
+
await write(keyed);
|
|
34796
|
+
await saveCropResize(stage, selection, commit, coalesceKey);
|
|
34797
|
+
}
|
|
34798
|
+
|
|
34799
|
+
// src/components/editor/DomEditCropHandles.tsx
|
|
34304
34800
|
import { Fragment as Fragment26, jsx as jsx84, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
34305
34801
|
var EDGE_HIT_THICKNESS = 12;
|
|
34306
34802
|
var EDGE_HIT_LENGTH = 32;
|
|
@@ -34341,6 +34837,7 @@ function repositionHandleSize(rect) {
|
|
|
34341
34837
|
return Math.min(REPOSITION_HANDLE_PX, Math.max(rect.width, rect.height) - RESIZE_HANDLE_HIT_PX);
|
|
34342
34838
|
}
|
|
34343
34839
|
var EDGES = ["top", "right", "bottom", "left"];
|
|
34840
|
+
var NO_CROP = { top: 0, right: 0, bottom: 0, left: 0, radius: 0 };
|
|
34344
34841
|
function DomEditCropHandles({
|
|
34345
34842
|
selection,
|
|
34346
34843
|
overlayRect,
|
|
@@ -34351,38 +34848,28 @@ function DomEditCropHandles({
|
|
|
34351
34848
|
const [hotEdge, setHotEdge] = useState40(null);
|
|
34352
34849
|
const cropStateFor = (element) => {
|
|
34353
34850
|
const parsed = readElementCropInsets(element);
|
|
34354
|
-
const {
|
|
34355
|
-
return { element, croppable: parsed !== null, insets,
|
|
34851
|
+
const { top, right, bottom, left } = parsed ?? NO_CROP;
|
|
34852
|
+
return { element, croppable: parsed !== null, insets: { top, right, bottom, left } };
|
|
34356
34853
|
};
|
|
34357
34854
|
const [state, setState] = useState40(() => cropStateFor(selection.element));
|
|
34358
34855
|
if (state.element !== selection.element) {
|
|
34359
34856
|
setState(cropStateFor(selection.element));
|
|
34360
34857
|
}
|
|
34361
|
-
const
|
|
34362
|
-
const
|
|
34363
|
-
const
|
|
34364
|
-
const committedClipRef = useRef65(null);
|
|
34858
|
+
const committed = readCropFollowingResize(selection.element) ?? NO_CROP;
|
|
34859
|
+
const insets = dragging ? state.insets : committed;
|
|
34860
|
+
const hasCrop = hasCropInsets(insets);
|
|
34365
34861
|
useEffect44(() => {
|
|
34366
34862
|
const el = selection.element;
|
|
34367
34863
|
if (readElementCropInsets(el) === null) return;
|
|
34368
|
-
|
|
34369
|
-
|
|
34370
|
-
el.style.setProperty("clip-path", "none");
|
|
34371
|
-
liftedRef.current = true;
|
|
34372
|
-
return () => {
|
|
34373
|
-
liftedRef.current = false;
|
|
34374
|
-
const committed = committedClipRef.current;
|
|
34375
|
-
const restore = committed !== null ? committed || null : preLiftInlineClipRef.current || null;
|
|
34376
|
-
if (restore) el.style.setProperty("clip-path", restore);
|
|
34377
|
-
else el.style.removeProperty("clip-path");
|
|
34378
|
-
};
|
|
34864
|
+
liftElementCrop(el);
|
|
34865
|
+
return () => dropElementCropLift(el);
|
|
34379
34866
|
}, [selection.element]);
|
|
34380
34867
|
const frame = readElementCropFrame(selection.element, overlayRect);
|
|
34381
34868
|
const width = frame.width / frame.scaleX;
|
|
34382
34869
|
const height = frame.height / frame.scaleY;
|
|
34383
34870
|
const cropRect = cropRectFromInsets(
|
|
34384
34871
|
{ left: 0, top: 0, width: frame.width, height: frame.height },
|
|
34385
|
-
|
|
34872
|
+
insets,
|
|
34386
34873
|
frame.scaleX,
|
|
34387
34874
|
frame.scaleY
|
|
34388
34875
|
);
|
|
@@ -34392,17 +34879,20 @@ function DomEditCropHandles({
|
|
|
34392
34879
|
event.preventDefault();
|
|
34393
34880
|
event.stopPropagation();
|
|
34394
34881
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
34882
|
+
const pressed = readCropFollowingResize(selection.element) ?? NO_CROP;
|
|
34395
34883
|
gestureRef.current = {
|
|
34396
34884
|
edge,
|
|
34397
34885
|
pointerId: event.pointerId,
|
|
34398
34886
|
startX: event.clientX,
|
|
34399
34887
|
startY: event.clientY,
|
|
34400
|
-
startInsets:
|
|
34401
|
-
insets:
|
|
34888
|
+
startInsets: pressed,
|
|
34889
|
+
insets: pressed,
|
|
34890
|
+
radius: pressed.radius,
|
|
34402
34891
|
angleDeg: frame.angleDeg,
|
|
34403
34892
|
scaleX: frame.scaleX,
|
|
34404
34893
|
scaleY: frame.scaleY
|
|
34405
34894
|
};
|
|
34895
|
+
setState((prev) => ({ ...prev, insets: pressed }));
|
|
34406
34896
|
setDragging(true);
|
|
34407
34897
|
};
|
|
34408
34898
|
const updateCropGesture = (event) => {
|
|
@@ -34438,19 +34928,10 @@ function DomEditCropHandles({
|
|
|
34438
34928
|
const finishCropGesture = (event) => {
|
|
34439
34929
|
const gesture = endCropGesture(event);
|
|
34440
34930
|
if (!gesture) return;
|
|
34441
|
-
const
|
|
34442
|
-
|
|
34443
|
-
|
|
34444
|
-
|
|
34445
|
-
const { insets } = gesture;
|
|
34446
|
-
const committedValue = buildInsetClipPathSides(insets, state.radius);
|
|
34447
|
-
if (committedValue === buildInsetClipPathSides(gesture.startInsets, state.radius)) return;
|
|
34448
|
-
const cropped = insets.top > 0 || insets.right > 0 || insets.bottom > 0 || insets.left > 0;
|
|
34449
|
-
const commit = onStyleCommit?.("clip-path", committedValue);
|
|
34450
|
-
reLift();
|
|
34451
|
-
void Promise.resolve(commit).then(() => {
|
|
34452
|
-
committedClipRef.current = cropped ? committedValue : "";
|
|
34453
|
-
}, reLift);
|
|
34931
|
+
const value = buildInsetClipPathSides(gesture.insets, gesture.radius);
|
|
34932
|
+
if (value === buildInsetClipPathSides(gesture.startInsets, gesture.radius)) return;
|
|
34933
|
+
const commit = onStyleCommit?.("clip-path", value);
|
|
34934
|
+
void Promise.resolve(commit).catch(() => void 0);
|
|
34454
34935
|
};
|
|
34455
34936
|
const cancelCropGesture = (event) => {
|
|
34456
34937
|
const gesture = endCropGesture(event);
|
|
@@ -34803,19 +35284,19 @@ function DomEditSelectionChrome({
|
|
|
34803
35284
|
// src/hooks/useCropOverlay.ts
|
|
34804
35285
|
function useCropOverlay(params) {
|
|
34805
35286
|
const { selection, overlayRect } = params;
|
|
34806
|
-
const cropInsets = selection ? readElementCropInsets(selection.element) : null;
|
|
34807
|
-
const
|
|
35287
|
+
const cropInsets = selection && !isElementCropLifted(selection.element) ? readElementCropInsets(selection.element) : null;
|
|
35288
|
+
const hasCropInsets2 = Boolean(
|
|
34808
35289
|
cropInsets && (cropInsets.top > 0 || cropInsets.right > 0 || cropInsets.bottom > 0 || cropInsets.left > 0)
|
|
34809
35290
|
);
|
|
34810
35291
|
const sx = overlayRect && overlayRect.editScaleX > 0 ? overlayRect.editScaleX : 1;
|
|
34811
35292
|
const sy = overlayRect && overlayRect.editScaleY > 0 ? overlayRect.editScaleY : 1;
|
|
34812
|
-
const cropOutlineInsetPx = cropInsets &&
|
|
35293
|
+
const cropOutlineInsetPx = cropInsets && hasCropInsets2 ? {
|
|
34813
35294
|
top: cropInsets.top * sy,
|
|
34814
35295
|
right: cropInsets.right * sx,
|
|
34815
35296
|
bottom: cropInsets.bottom * sy,
|
|
34816
35297
|
left: cropInsets.left * sx
|
|
34817
35298
|
} : void 0;
|
|
34818
|
-
return { hasCropInsets, cropOutlineInsetPx };
|
|
35299
|
+
return { hasCropInsets: hasCropInsets2, cropOutlineInsetPx };
|
|
34819
35300
|
}
|
|
34820
35301
|
|
|
34821
35302
|
// src/components/editor/domEditOverlayShape.ts
|
|
@@ -36270,11 +36751,11 @@ var DomEditOverlay = memo25(function DomEditOverlay2({
|
|
|
36270
36751
|
const compRect = useDomEditCompositionRect({ iframeRef, overlayRef });
|
|
36271
36752
|
const compRectRef = useRef69(compRect);
|
|
36272
36753
|
compRectRef.current = compRect;
|
|
36273
|
-
const { hasCropInsets, cropOutlineInsetPx } = useCropOverlay({
|
|
36754
|
+
const { hasCropInsets: hasCropInsets2, cropOutlineInsetPx } = useCropOverlay({
|
|
36274
36755
|
selection,
|
|
36275
36756
|
overlayRect
|
|
36276
36757
|
});
|
|
36277
|
-
const boxClipPath =
|
|
36758
|
+
const boxClipPath = hasCropInsets2 ? void 0 : selectionShapeStyles.clipPath;
|
|
36278
36759
|
const boxChromeClass = resolveBoxChromeClass(Boolean(cropOutlineInsetPx), boxClipPath);
|
|
36279
36760
|
const { offCanvasRects, offCanvasElementsRef } = useOffCanvasIndicators({
|
|
36280
36761
|
iframeRef,
|
|
@@ -37576,7 +38057,12 @@ async function commitCandidateEdit(edit, targetPath, originalContent, deps, opti
|
|
|
37576
38057
|
});
|
|
37577
38058
|
}
|
|
37578
38059
|
if (refreshTarget) refreshCommittedEdit(edit.after, deps, options);
|
|
37579
|
-
return {
|
|
38060
|
+
return {
|
|
38061
|
+
status: "committed",
|
|
38062
|
+
version: hashContent(edit.after),
|
|
38063
|
+
before: originalContent,
|
|
38064
|
+
after: edit.after
|
|
38065
|
+
};
|
|
37580
38066
|
}
|
|
37581
38067
|
async function persistSdkCandidateMutation(live, targetPath, originalContent, deps, mutate, options, sourceSnapshot) {
|
|
37582
38068
|
return serializeStudioFileMutation(
|
|
@@ -39854,6 +40340,10 @@ var GsapEditBlockedError = class extends Error {
|
|
|
39854
40340
|
function assertGsapEditPersisted(outcome) {
|
|
39855
40341
|
if (outcome.status === "blocked") throw new GsapEditBlockedError(outcome.reason, outcome.detail);
|
|
39856
40342
|
}
|
|
40343
|
+
async function saveMove(outcome, saveOnElement) {
|
|
40344
|
+
if (outcome.status === "element-offset") return saveOnElement();
|
|
40345
|
+
assertGsapEditPersisted(outcome);
|
|
40346
|
+
}
|
|
39857
40347
|
function assertGsapAnimationDirectlyEditable(animation) {
|
|
39858
40348
|
const editability = editabilityForProvenance(animation.provenance);
|
|
39859
40349
|
if (editability === "unroll") throw new GsapEditBlockedError("unroll-required");
|
|
@@ -40034,8 +40524,8 @@ async function commitStaticGsapRotation(selection, newRotation, selector, existi
|
|
|
40034
40524
|
);
|
|
40035
40525
|
}
|
|
40036
40526
|
async function commitStaticGsapSize(selection, size, selector, existingSet, callbacks) {
|
|
40037
|
-
const width =
|
|
40038
|
-
const height =
|
|
40527
|
+
const width = roundToLayoutPx(size.width);
|
|
40528
|
+
const height = roundToLayoutPx(size.height);
|
|
40039
40529
|
if (existingSet) {
|
|
40040
40530
|
await callbacks.commitMutation(
|
|
40041
40531
|
selection,
|
|
@@ -40063,7 +40553,7 @@ async function commitStaticGsapSize(selection, size, selector, existingSet, call
|
|
|
40063
40553
|
);
|
|
40064
40554
|
}
|
|
40065
40555
|
function positiveOr(n, fallback) {
|
|
40066
|
-
return Number.isFinite(n) && n > 0 ?
|
|
40556
|
+
return Number.isFinite(n) && n > 0 ? roundToLayoutPx(n) : fallback;
|
|
40067
40557
|
}
|
|
40068
40558
|
function resolvePriorSize(sizeSet, el, fallbackW, fallbackH) {
|
|
40069
40559
|
if (sizeSet) {
|
|
@@ -40080,8 +40570,8 @@ async function commitKeyframedSizeFromResize(selection, size, selector, sizeSet,
|
|
|
40080
40570
|
const ts = resolveTweenStart(animatedTween) ?? 0;
|
|
40081
40571
|
const td = resolveTweenDuration(animatedTween);
|
|
40082
40572
|
if (!(td > 0)) return false;
|
|
40083
|
-
const newW =
|
|
40084
|
-
const newH =
|
|
40573
|
+
const newW = roundToLayoutPx(size.width);
|
|
40574
|
+
const newH = roundToLayoutPx(size.height);
|
|
40085
40575
|
const prior = resolvePriorSize(sizeSet, selection.element, newW, newH);
|
|
40086
40576
|
const ct = usePlayerStore.getState().currentTime;
|
|
40087
40577
|
const pct = Math.max(0, Math.min(100, Math.round((ct - ts) / td * 1e3) / 10));
|
|
@@ -40411,249 +40901,6 @@ function commitCreatePath(targetSelector, position, x, y, commit) {
|
|
|
40411
40901
|
|
|
40412
40902
|
// src/components/editor/useMotionPathData.ts
|
|
40413
40903
|
import { useEffect as useEffect52, useRef as useRef73, useState as useState45 } from "react";
|
|
40414
|
-
|
|
40415
|
-
// src/hooks/gsapRuntimeKeyframes.ts
|
|
40416
|
-
import { buildArcPath } from "@hyperframes/core/gsap-parser-acorn";
|
|
40417
|
-
var FLAT_SKIP_KEYS = /* @__PURE__ */ new Set([
|
|
40418
|
-
"ease",
|
|
40419
|
-
"duration",
|
|
40420
|
-
"delay",
|
|
40421
|
-
"stagger",
|
|
40422
|
-
"motionPath",
|
|
40423
|
-
"overwrite",
|
|
40424
|
-
"immediateRender",
|
|
40425
|
-
"onComplete",
|
|
40426
|
-
"onUpdate",
|
|
40427
|
-
"onStart",
|
|
40428
|
-
"keyframes"
|
|
40429
|
-
]);
|
|
40430
|
-
function timelinesOf(iframe) {
|
|
40431
|
-
if (!iframe?.contentWindow) return null;
|
|
40432
|
-
try {
|
|
40433
|
-
return iframe.contentWindow.__timelines ?? null;
|
|
40434
|
-
} catch {
|
|
40435
|
-
return null;
|
|
40436
|
-
}
|
|
40437
|
-
}
|
|
40438
|
-
function isXY(p) {
|
|
40439
|
-
return !!p && typeof p.x === "number" && typeof p.y === "number";
|
|
40440
|
-
}
|
|
40441
|
-
function isZeroDurationSet(duration) {
|
|
40442
|
-
return !(duration > 0);
|
|
40443
|
-
}
|
|
40444
|
-
function coordsFromMotionPath(mp) {
|
|
40445
|
-
if (!mp || typeof mp !== "object") return null;
|
|
40446
|
-
const obj = mp;
|
|
40447
|
-
const pathVal = Array.isArray(mp) ? mp : obj.path;
|
|
40448
|
-
if (!Array.isArray(pathVal)) return null;
|
|
40449
|
-
const coords = pathVal.filter(isXY).map((p) => ({ x: p.x, y: p.y }));
|
|
40450
|
-
if (coords.length < 2) return null;
|
|
40451
|
-
const curviness = typeof obj.curviness === "number" ? obj.curviness : 1;
|
|
40452
|
-
const autoRotate = typeof obj.autoRotate === "number" ? obj.autoRotate : obj.autoRotate === true;
|
|
40453
|
-
return { coords, curviness, autoRotate, isCubic: obj.type === "cubic" };
|
|
40454
|
-
}
|
|
40455
|
-
function flatTweenKeyframes(vars) {
|
|
40456
|
-
const properties = {};
|
|
40457
|
-
for (const [k, v] of Object.entries(vars)) {
|
|
40458
|
-
if (FLAT_SKIP_KEYS.has(k)) continue;
|
|
40459
|
-
if (typeof v === "number") properties[k] = roundTo3(v);
|
|
40460
|
-
else if (typeof v === "string") properties[k] = v;
|
|
40461
|
-
}
|
|
40462
|
-
if (Object.keys(properties).length === 0) return null;
|
|
40463
|
-
return [
|
|
40464
|
-
{ percentage: 0, properties },
|
|
40465
|
-
{ percentage: 100, properties }
|
|
40466
|
-
];
|
|
40467
|
-
}
|
|
40468
|
-
function readTween(vars) {
|
|
40469
|
-
if (vars.keyframes && typeof vars.keyframes === "object") {
|
|
40470
|
-
const parsed = parsePercentageKeyframes(vars.keyframes);
|
|
40471
|
-
if (parsed) return parsed;
|
|
40472
|
-
}
|
|
40473
|
-
const mp = coordsFromMotionPath(vars.motionPath);
|
|
40474
|
-
if (mp) {
|
|
40475
|
-
const shape = buildArcPath(mp.coords, mp.curviness, mp.autoRotate, mp.isCubic);
|
|
40476
|
-
if (shape) {
|
|
40477
|
-
const n = shape.waypoints.length;
|
|
40478
|
-
const keyframes = shape.waypoints.map((wp, i) => ({
|
|
40479
|
-
percentage: n > 1 ? Math.round(i / (n - 1) * 100) : 0,
|
|
40480
|
-
properties: { x: wp.x, y: wp.y }
|
|
40481
|
-
}));
|
|
40482
|
-
return { keyframes, arcPath: shape.arcPath };
|
|
40483
|
-
}
|
|
40484
|
-
}
|
|
40485
|
-
const flat = flatTweenKeyframes(vars);
|
|
40486
|
-
return flat ? { keyframes: flat } : null;
|
|
40487
|
-
}
|
|
40488
|
-
function matchesElement(tween, el) {
|
|
40489
|
-
if (!tween.targets) return false;
|
|
40490
|
-
for (const t of tween.targets()) {
|
|
40491
|
-
if (t === el || el.id && t.id === el.id) return true;
|
|
40492
|
-
}
|
|
40493
|
-
return false;
|
|
40494
|
-
}
|
|
40495
|
-
function tweenTiming(tween) {
|
|
40496
|
-
const rawStart = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
40497
|
-
const rawDur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
40498
|
-
return {
|
|
40499
|
-
start: Number.isFinite(rawStart) ? rawStart : 0,
|
|
40500
|
-
duration: Number.isFinite(rawDur) ? rawDur : 0
|
|
40501
|
-
};
|
|
40502
|
-
}
|
|
40503
|
-
function varsCarryChannel(vars, channels) {
|
|
40504
|
-
if (!vars) return false;
|
|
40505
|
-
for (const ch of channels) {
|
|
40506
|
-
if (Object.prototype.hasOwnProperty.call(vars, ch)) return true;
|
|
40507
|
-
}
|
|
40508
|
-
return false;
|
|
40509
|
-
}
|
|
40510
|
-
function keyframeVarsCarryChannel(vars, channels) {
|
|
40511
|
-
const kf = vars?.keyframes;
|
|
40512
|
-
if (!kf || typeof kf !== "object") return false;
|
|
40513
|
-
const steps = Array.isArray(kf) ? kf : Object.values(kf);
|
|
40514
|
-
return steps.some(
|
|
40515
|
-
(step) => step != null && typeof step === "object" && channels.some((ch) => Object.prototype.hasOwnProperty.call(step, ch))
|
|
40516
|
-
);
|
|
40517
|
-
}
|
|
40518
|
-
function resolveRuntimeTween(iframe, selector, kind, compositionId, channels) {
|
|
40519
|
-
const timelines = timelinesOf(iframe);
|
|
40520
|
-
if (!timelines) return null;
|
|
40521
|
-
let targetEl = null;
|
|
40522
|
-
try {
|
|
40523
|
-
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
40524
|
-
} catch {
|
|
40525
|
-
return null;
|
|
40526
|
-
}
|
|
40527
|
-
if (!targetEl) return null;
|
|
40528
|
-
const tlIds = compositionId ? [compositionId] : Object.keys(timelines).filter((k) => typeof timelines[k]?.getChildren === "function");
|
|
40529
|
-
const wantChannels = channels && channels.length > 0 ? channels : null;
|
|
40530
|
-
let first = null;
|
|
40531
|
-
let channelMatch = null;
|
|
40532
|
-
for (const tlId of tlIds) {
|
|
40533
|
-
const timeline = timelines[tlId];
|
|
40534
|
-
if (!timeline?.getChildren) continue;
|
|
40535
|
-
const now2 = typeof timeline.time === "function" ? timeline.time() : null;
|
|
40536
|
-
for (const tween of timeline.getChildren(true)) {
|
|
40537
|
-
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
40538
|
-
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
40539
|
-
const isSet = !(dur > 0);
|
|
40540
|
-
if (kind === "set" ? !isSet : isSet) continue;
|
|
40541
|
-
if (wantChannels) {
|
|
40542
|
-
const carries = kind === "set" ? varsCarryChannel(tween.vars, wantChannels) : keyframeVarsCarryChannel(tween.vars, wantChannels);
|
|
40543
|
-
if (carries) {
|
|
40544
|
-
if (channelMatch === null) channelMatch = { tween, timeline };
|
|
40545
|
-
} else if (first === null) {
|
|
40546
|
-
first = { tween, timeline };
|
|
40547
|
-
}
|
|
40548
|
-
continue;
|
|
40549
|
-
}
|
|
40550
|
-
if (first === null) first = { tween, timeline };
|
|
40551
|
-
if (kind === "keyframe" && now2 != null) {
|
|
40552
|
-
const start = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
40553
|
-
if (now2 >= start - 1e-3 && now2 <= start + dur + 1e-3) return { tween, timeline };
|
|
40554
|
-
}
|
|
40555
|
-
}
|
|
40556
|
-
}
|
|
40557
|
-
return channelMatch ?? first;
|
|
40558
|
-
}
|
|
40559
|
-
function readCarriesChannel(read, channels) {
|
|
40560
|
-
return read.keyframes.some((kf) => channels.some((c) => kf.properties[c] != null));
|
|
40561
|
-
}
|
|
40562
|
-
function readRuntimeKeyframes(iframe, selector, compositionId, requireChannels) {
|
|
40563
|
-
const timelines = timelinesOf(iframe);
|
|
40564
|
-
if (!timelines) return null;
|
|
40565
|
-
let targetEl = null;
|
|
40566
|
-
try {
|
|
40567
|
-
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
40568
|
-
} catch {
|
|
40569
|
-
return null;
|
|
40570
|
-
}
|
|
40571
|
-
if (!targetEl) return null;
|
|
40572
|
-
const tlIds = compositionId ? [compositionId] : Object.keys(timelines).filter((k) => typeof timelines[k]?.getChildren === "function");
|
|
40573
|
-
if (tlIds.length === 0) return null;
|
|
40574
|
-
let firstRead = null;
|
|
40575
|
-
for (const tlId of tlIds) {
|
|
40576
|
-
const timeline = timelines[tlId];
|
|
40577
|
-
if (!timeline?.getChildren) continue;
|
|
40578
|
-
const now2 = typeof timeline.time === "function" ? timeline.time() : null;
|
|
40579
|
-
for (const tween of timeline.getChildren(true)) {
|
|
40580
|
-
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
40581
|
-
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
40582
|
-
if (isZeroDurationSet(dur)) continue;
|
|
40583
|
-
const read = readTween(tween.vars);
|
|
40584
|
-
if (!read) continue;
|
|
40585
|
-
if (requireChannels && !readCarriesChannel(read, requireChannels)) continue;
|
|
40586
|
-
if (firstRead === null) firstRead = read;
|
|
40587
|
-
if (now2 != null) {
|
|
40588
|
-
const start = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
40589
|
-
if (now2 >= start - 1e-3 && now2 <= start + dur + 1e-3) return read;
|
|
40590
|
-
}
|
|
40591
|
-
}
|
|
40592
|
-
}
|
|
40593
|
-
return firstRead;
|
|
40594
|
-
}
|
|
40595
|
-
function hasNonHoldTweenForElement(iframe, selector, compositionId, channels) {
|
|
40596
|
-
const timelines = timelinesOf(iframe);
|
|
40597
|
-
if (!timelines) return false;
|
|
40598
|
-
const tlId = compositionId || Object.keys(timelines).find((k) => typeof timelines[k]?.getChildren === "function");
|
|
40599
|
-
if (!tlId) return false;
|
|
40600
|
-
const timeline = timelines[tlId];
|
|
40601
|
-
if (!timeline?.getChildren) return false;
|
|
40602
|
-
let targetEl = null;
|
|
40603
|
-
try {
|
|
40604
|
-
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
40605
|
-
} catch {
|
|
40606
|
-
return false;
|
|
40607
|
-
}
|
|
40608
|
-
if (!targetEl) return false;
|
|
40609
|
-
for (const tween of timeline.getChildren(true)) {
|
|
40610
|
-
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
40611
|
-
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
40612
|
-
if (isZeroDurationSet(dur)) continue;
|
|
40613
|
-
const read = readTween(tween.vars);
|
|
40614
|
-
if (read && (!channels || readCarriesChannel(read, channels))) return true;
|
|
40615
|
-
}
|
|
40616
|
-
return false;
|
|
40617
|
-
}
|
|
40618
|
-
function toClipRelative(keyframes, tweenStart, tweenDuration, clip) {
|
|
40619
|
-
if (!clip || clip.duration <= 0) return keyframes;
|
|
40620
|
-
return keyframes.map((kf) => {
|
|
40621
|
-
const abs = toAbsoluteTime(tweenStart, tweenDuration, kf.percentage);
|
|
40622
|
-
return { ...kf, percentage: Math.round((abs - clip.start) / clip.duration * 1e5) / 1e3 };
|
|
40623
|
-
});
|
|
40624
|
-
}
|
|
40625
|
-
function buildEntry(read, start, duration, clip) {
|
|
40626
|
-
return {
|
|
40627
|
-
keyframes: toClipRelative(read.keyframes, start, duration, clip),
|
|
40628
|
-
tweenStart: start,
|
|
40629
|
-
tweenDuration: duration,
|
|
40630
|
-
...read.easeEach ? { easeEach: read.easeEach } : {},
|
|
40631
|
-
...read.arcPath ? { arcPath: read.arcPath } : {}
|
|
40632
|
-
};
|
|
40633
|
-
}
|
|
40634
|
-
function addScanEntry(result, tween, clipById) {
|
|
40635
|
-
if (!tween.targets || !tween.vars) return;
|
|
40636
|
-
const { start, duration } = tweenTiming(tween);
|
|
40637
|
-
if (isZeroDurationSet(duration)) return;
|
|
40638
|
-
const read = readTween(tween.vars);
|
|
40639
|
-
if (!read) return;
|
|
40640
|
-
for (const target of tween.targets()) {
|
|
40641
|
-
const id = target.id;
|
|
40642
|
-
if (id && !result.has(id)) result.set(id, buildEntry(read, start, duration, clipById?.get(id)));
|
|
40643
|
-
}
|
|
40644
|
-
}
|
|
40645
|
-
function scanAllRuntimeKeyframes(iframe, clipById) {
|
|
40646
|
-
const result = /* @__PURE__ */ new Map();
|
|
40647
|
-
const timelines = timelinesOf(iframe);
|
|
40648
|
-
if (!timelines) return result;
|
|
40649
|
-
for (const timeline of Object.values(timelines)) {
|
|
40650
|
-
if (!timeline?.getChildren) continue;
|
|
40651
|
-
for (const tween of timeline.getChildren(true)) addScanEntry(result, tween, clipById);
|
|
40652
|
-
}
|
|
40653
|
-
return result;
|
|
40654
|
-
}
|
|
40655
|
-
|
|
40656
|
-
// src/components/editor/useMotionPathData.ts
|
|
40657
40904
|
function transformTranslate(el) {
|
|
40658
40905
|
const t = el.ownerDocument?.defaultView?.getComputedStyle(el).transform;
|
|
40659
40906
|
if (!t || t === "none") return { x: 0, y: 0 };
|
|
@@ -42226,19 +42473,6 @@ function getAnimationsForElement(animations, target, element) {
|
|
|
42226
42473
|
}
|
|
42227
42474
|
|
|
42228
42475
|
// src/hooks/gsapRuntimeBridge.ts
|
|
42229
|
-
var POSITION_CHANNELS = [
|
|
42230
|
-
"x",
|
|
42231
|
-
"y",
|
|
42232
|
-
"xPercent",
|
|
42233
|
-
"yPercent",
|
|
42234
|
-
"left",
|
|
42235
|
-
"top",
|
|
42236
|
-
// GSAP normalizes translateX/Y to x/y at play time, but readTween reads the
|
|
42237
|
-
// AUTHORED shape — include them so a hand-authored translateX/Y position tween
|
|
42238
|
-
// still counts as a live position tween.
|
|
42239
|
-
"translateX",
|
|
42240
|
-
"translateY"
|
|
42241
|
-
];
|
|
42242
42476
|
var POSITION_CHANNEL_SET = new Set(POSITION_CHANNELS);
|
|
42243
42477
|
var ROTATION_CHANNELS = ["rotation", "rotationX", "rotationY", "rotationZ"];
|
|
42244
42478
|
var ROTATION_CHANNEL_SET = new Set(ROTATION_CHANNELS);
|
|
@@ -42451,7 +42685,7 @@ async function tryGsapRotationIntercept(selection, angle, animations, iframe, co
|
|
|
42451
42685
|
if (!anim) {
|
|
42452
42686
|
anim = workingAnimations.find((a) => animationWritesAnyProperty(a, ROTATION_CHANNEL_SET)) ?? null;
|
|
42453
42687
|
}
|
|
42454
|
-
const newRotation =
|
|
42688
|
+
const newRotation = roundTo3(angle);
|
|
42455
42689
|
if (!anim || isInstantHold(anim)) {
|
|
42456
42690
|
const existingSet = anim ?? findRotationSetAnimation(resolvedAnimations, selector, selection.element);
|
|
42457
42691
|
await commitStaticGsapRotation(selection, newRotation, selector, existingSet, {
|
|
@@ -47680,7 +47914,7 @@ function createTransformCommitHandlers({
|
|
|
47680
47914
|
"This element's position can't be edited here yet \u2014 it is driven by its animation"
|
|
47681
47915
|
))
|
|
47682
47916
|
return;
|
|
47683
|
-
const current =
|
|
47917
|
+
const current = readMoveOffset(element.element);
|
|
47684
47918
|
await Promise.resolve(
|
|
47685
47919
|
onSetManualOffset(element, {
|
|
47686
47920
|
x: axis === "x" ? parsed : current.x,
|
|
@@ -64763,7 +64997,7 @@ var PropertyPanel = memo36(function PropertyPanel2(props) {
|
|
|
64763
64997
|
const sourceLabel = element.id ? `#${element.id}` : element.selector ?? "";
|
|
64764
64998
|
const sections = resolveEditingSections(domEditSelectionToFacts(element, gsapAnimations.length));
|
|
64765
64999
|
const showEditableSections = element.capabilities.canEditStyles && sections.style;
|
|
64766
|
-
const manualOffset =
|
|
65000
|
+
const manualOffset = readMoveOffset(element.element);
|
|
64767
65001
|
const manualSize = readStudioBoxSize(element.element);
|
|
64768
65002
|
const resolvedWidth = manualSize.width > 0 ? manualSize.width : parsePxMetricValue(styles.width ?? "") ?? element.boundingBox.width;
|
|
64769
65003
|
const resolvedHeight = manualSize.height > 0 ? manualSize.height : parsePxMetricValue(styles.height ?? "") ?? element.boundingBox.height;
|
|
@@ -70976,7 +71210,7 @@ function useTimelineGroupEditing({
|
|
|
70976
71210
|
async (input) => {
|
|
70977
71211
|
const sharedPath = allChangesSharePath(input.changes, activeCompPath);
|
|
70978
71212
|
const canUseSdk = !input.needsExtension && sharedPath !== null && input.eligible && input.sdkChanges.every((change) => change !== null);
|
|
70979
|
-
if (!canUseSdk) return
|
|
71213
|
+
if (!canUseSdk) return null;
|
|
70980
71214
|
const result = await sdkTimingBatchPersist(
|
|
70981
71215
|
input.sdkChanges.filter((change) => change !== null),
|
|
70982
71216
|
sharedPath,
|
|
@@ -70996,7 +71230,7 @@ function useTimelineGroupEditing({
|
|
|
70996
71230
|
skipRefresh: true
|
|
70997
71231
|
}
|
|
70998
71232
|
);
|
|
70999
|
-
return cutoverCommittedOrThrow(result);
|
|
71233
|
+
return cutoverCommittedOrThrow(result) ? { sdkGsap: sdkTimingGsapSync(result) } : null;
|
|
71000
71234
|
},
|
|
71001
71235
|
[
|
|
71002
71236
|
activeCompPath,
|
|
@@ -71033,7 +71267,7 @@ function useTimelineGroupEditing({
|
|
|
71033
71267
|
const label = options?.label ?? "Move timeline clips";
|
|
71034
71268
|
return enqueueGroupOperation(label, async (projectId) => {
|
|
71035
71269
|
await options?.beforeTiming;
|
|
71036
|
-
const
|
|
71270
|
+
const sdk = await trySdkBatchPersist({
|
|
71037
71271
|
changes,
|
|
71038
71272
|
sdkChanges: toSdkTimingChanges(changes, (change) => ({
|
|
71039
71273
|
start: toAuthoredStart(change.element, change.start)
|
|
@@ -71044,7 +71278,7 @@ function useTimelineGroupEditing({
|
|
|
71044
71278
|
coalesceKey,
|
|
71045
71279
|
coalesceMs
|
|
71046
71280
|
});
|
|
71047
|
-
if (!
|
|
71281
|
+
if (!sdk) {
|
|
71048
71282
|
await persistServerBatch(
|
|
71049
71283
|
projectId,
|
|
71050
71284
|
label,
|
|
@@ -71075,6 +71309,7 @@ function useTimelineGroupEditing({
|
|
|
71075
71309
|
writeProjectFile,
|
|
71076
71310
|
activeCompPath,
|
|
71077
71311
|
changes,
|
|
71312
|
+
sdkGsap: sdk?.sdkGsap,
|
|
71078
71313
|
resolveChangePath: (element) => targetPathFor(element, activeCompPath),
|
|
71079
71314
|
mutateChange: (change, changePath) => {
|
|
71080
71315
|
const delta = change.start - change.element.start;
|
|
@@ -71134,7 +71369,7 @@ function useTimelineGroupEditing({
|
|
|
71134
71369
|
const coalesceMs = options?.coalesceMs;
|
|
71135
71370
|
return enqueueGroupOperation("Resize timeline clips", async (projectId) => {
|
|
71136
71371
|
await options?.beforeTiming;
|
|
71137
|
-
const
|
|
71372
|
+
const sdk = await trySdkBatchPersist({
|
|
71138
71373
|
changes,
|
|
71139
71374
|
sdkChanges: toSdkTimingChanges(changes, (change) => ({
|
|
71140
71375
|
start: toAuthoredStart(change.element, change.start),
|
|
@@ -71146,7 +71381,7 @@ function useTimelineGroupEditing({
|
|
|
71146
71381
|
coalesceKey,
|
|
71147
71382
|
coalesceMs
|
|
71148
71383
|
});
|
|
71149
|
-
if (!
|
|
71384
|
+
if (!sdk) {
|
|
71150
71385
|
await persistServerBatch(
|
|
71151
71386
|
projectId,
|
|
71152
71387
|
"Resize timeline clips",
|
|
@@ -71174,6 +71409,7 @@ function useTimelineGroupEditing({
|
|
|
71174
71409
|
writeProjectFile,
|
|
71175
71410
|
activeCompPath,
|
|
71176
71411
|
changes,
|
|
71412
|
+
sdkGsap: sdk?.sdkGsap,
|
|
71177
71413
|
resolveChangePath: (element) => targetPathFor(element, activeCompPath),
|
|
71178
71414
|
mutateChange: (change, changePath) => {
|
|
71179
71415
|
const domId = change.element.domId;
|
|
@@ -71378,10 +71614,8 @@ function useTimelineEditing({
|
|
|
71378
71614
|
);
|
|
71379
71615
|
};
|
|
71380
71616
|
const coalesceKey = `timeline-move:${element.hfId ?? element.id}`;
|
|
71381
|
-
const finishMoveGsapSync = () => (
|
|
71382
|
-
//
|
|
71383
|
-
// durable clip-start commit. The SDK owns the attribute write; this
|
|
71384
|
-
// sync owns only the dependent animation rewrite and preview refresh.
|
|
71617
|
+
const finishMoveGsapSync = (sdkGsap) => (
|
|
71618
|
+
// One GSAP sync per edit: the SDK commit's own (sdkGsap), else the server rewrite here.
|
|
71385
71619
|
finishClipTimingFallback({
|
|
71386
71620
|
iframe: previewIframeRef.current,
|
|
71387
71621
|
reloadPreview,
|
|
@@ -71392,11 +71626,12 @@ function useTimelineEditing({
|
|
|
71392
71626
|
coalesceKey,
|
|
71393
71627
|
recordEdit,
|
|
71394
71628
|
writeProjectFile,
|
|
71395
|
-
edit: { kind: "shift", delta: updates.start - element.start }
|
|
71629
|
+
edit: { kind: "shift", delta: updates.start - element.start },
|
|
71630
|
+
sdkGsap
|
|
71396
71631
|
}).finally(() => invalidateGsapCache?.())
|
|
71397
71632
|
);
|
|
71398
71633
|
const moveFallback = () => enqueueEdit(element, "Move timeline clip", buildMovePatches, coalesceKey).then(
|
|
71399
|
-
finishMoveGsapSync
|
|
71634
|
+
() => finishMoveGsapSync()
|
|
71400
71635
|
);
|
|
71401
71636
|
return reorderDone.then(() => {
|
|
71402
71637
|
if (sdkSession && element.hfId && !needsExtension && !trackChanged) {
|
|
@@ -71418,7 +71653,7 @@ function useTimelineEditing({
|
|
|
71418
71653
|
{ label: "Move timeline clip", coalesceKey, skipRefresh: true }
|
|
71419
71654
|
).then((result) => {
|
|
71420
71655
|
if (!cutoverCommittedOrThrow(result)) return moveFallback();
|
|
71421
|
-
return finishMoveGsapSync();
|
|
71656
|
+
return finishMoveGsapSync(sdkTimingGsapSync(result));
|
|
71422
71657
|
});
|
|
71423
71658
|
}
|
|
71424
71659
|
return moveFallback();
|
|
@@ -71467,7 +71702,7 @@ function useTimelineEditing({
|
|
|
71467
71702
|
};
|
|
71468
71703
|
const hasPbsAdjustment = updates.playbackStart != null || updates.start !== element.start && element.playbackStart != null;
|
|
71469
71704
|
const coalesceKey = `timeline-resize:${element.hfId ?? element.id}`;
|
|
71470
|
-
const finishResizeGsapSync = () => finishClipTimingFallback({
|
|
71705
|
+
const finishResizeGsapSync = (sdkGsap) => finishClipTimingFallback({
|
|
71471
71706
|
iframe: previewIframeRef.current,
|
|
71472
71707
|
reloadPreview,
|
|
71473
71708
|
projectId: projectIdRef.current,
|
|
@@ -71481,10 +71716,11 @@ function useTimelineEditing({
|
|
|
71481
71716
|
kind: "scale",
|
|
71482
71717
|
from: { start: toCompositionTime(element, element.start), duration: element.duration },
|
|
71483
71718
|
to: { start: toCompositionTime(element, updates.start), duration: updates.duration }
|
|
71484
|
-
}
|
|
71719
|
+
},
|
|
71720
|
+
sdkGsap
|
|
71485
71721
|
}).finally(() => invalidateGsapCache?.());
|
|
71486
71722
|
const resizeFallback = () => enqueueEdit(element, "Resize timeline clip", buildResizePatches, coalesceKey).then(
|
|
71487
|
-
finishResizeGsapSync
|
|
71723
|
+
() => finishResizeGsapSync()
|
|
71488
71724
|
);
|
|
71489
71725
|
const persistDone = sdkSession && element.hfId && !hasPbsAdjustment && !needsExtension ? sdkTimingPersist(
|
|
71490
71726
|
element.hfId,
|
|
@@ -71504,7 +71740,7 @@ function useTimelineEditing({
|
|
|
71504
71740
|
{ label: "Resize timeline clip", coalesceKey, skipRefresh: true }
|
|
71505
71741
|
).then((result) => {
|
|
71506
71742
|
if (!cutoverCommittedOrThrow(result)) return resizeFallback();
|
|
71507
|
-
return finishResizeGsapSync();
|
|
71743
|
+
return finishResizeGsapSync(sdkTimingGsapSync(result));
|
|
71508
71744
|
}) : resizeFallback();
|
|
71509
71745
|
return persistDone.catch((error) => {
|
|
71510
71746
|
rollbackDuration();
|
|
@@ -73556,10 +73792,6 @@ function canCommitInlineTextSelection(selection, element) {
|
|
|
73556
73792
|
if (selection.isCompositionHost || selection.isInsideLockedComposition) return false;
|
|
73557
73793
|
return canEditElementTextInline(element);
|
|
73558
73794
|
}
|
|
73559
|
-
function ownsCurrentPreviewElement(selection, element, document2) {
|
|
73560
|
-
if (!document2 || !element.isConnected) return false;
|
|
73561
|
-
return element === selection.element && element.ownerDocument === document2;
|
|
73562
|
-
}
|
|
73563
73795
|
async function resyncDomTextSelectionFromPreview(doc, selection, activeCompPath, buildDomSelectionFromTarget, applyDomSelection) {
|
|
73564
73796
|
if (!doc) return;
|
|
73565
73797
|
const refreshed = findElementForSelection(doc, selection, activeCompPath);
|
|
@@ -73582,6 +73814,8 @@ function useDomEditTextCommits({
|
|
|
73582
73814
|
}) {
|
|
73583
73815
|
const latestReadOnlyPreviewRef = useRef142(readOnlyPreview);
|
|
73584
73816
|
latestReadOnlyPreviewRef.current = readOnlyPreview;
|
|
73817
|
+
const latestSelectionRef = useRef142(domEditSelection);
|
|
73818
|
+
latestSelectionRef.current = domEditSelection;
|
|
73585
73819
|
const domTextCommitVersionRef = useRef142(/* @__PURE__ */ new Map());
|
|
73586
73820
|
const domStyleCommitVersionRef = useRef142(/* @__PURE__ */ new Map());
|
|
73587
73821
|
const {
|
|
@@ -73693,18 +73927,32 @@ function useDomEditTextCommits({
|
|
|
73693
73927
|
);
|
|
73694
73928
|
const handleDomRichTextCommit = useCallback123(
|
|
73695
73929
|
async ({ element, html: html2, previousHtml }) => {
|
|
73696
|
-
|
|
73697
|
-
if (latestReadOnlyPreviewRef.current) {
|
|
73930
|
+
const putBack = () => {
|
|
73698
73931
|
if (element.isConnected && element.innerHTML === html2) element.innerHTML = previousHtml;
|
|
73699
|
-
|
|
73932
|
+
};
|
|
73933
|
+
if (latestReadOnlyPreviewRef.current) return putBack();
|
|
73934
|
+
const refuse = (reason) => {
|
|
73935
|
+
console.error("[Studio] text edit not saved:", reason, element);
|
|
73936
|
+
showToast(`Couldn't save the text edit: ${reason}`, "error");
|
|
73937
|
+
putBack();
|
|
73938
|
+
};
|
|
73939
|
+
const doc = previewIframeRef.current?.contentDocument;
|
|
73940
|
+
if (!doc || !element.isConnected || element.ownerDocument !== doc) {
|
|
73941
|
+
return refuse("the text's element is gone from the preview");
|
|
73942
|
+
}
|
|
73943
|
+
const selection = await buildDomSelectionFromTarget(element, {
|
|
73944
|
+
exactTarget: true,
|
|
73945
|
+
skipSourceProbe: true
|
|
73946
|
+
});
|
|
73947
|
+
if (selection?.element !== element) {
|
|
73948
|
+
return refuse("this text was not found in the composition's source");
|
|
73949
|
+
}
|
|
73950
|
+
if (!canCommitInlineTextSelection(selection, element)) {
|
|
73951
|
+
return refuse("this text can't be edited in place");
|
|
73700
73952
|
}
|
|
73701
|
-
if (!canCommitInlineTextSelection(domEditSelection, element)) return;
|
|
73702
|
-
const iframe = previewIframeRef.current;
|
|
73703
|
-
const doc = iframe?.contentDocument;
|
|
73704
|
-
if (!ownsCurrentPreviewElement(domEditSelection, element, doc)) return;
|
|
73705
73953
|
const isLatestTextCommit = bumpDomEditCommitMapVersion(
|
|
73706
73954
|
domTextCommitVersionRef.current,
|
|
73707
|
-
getDomEditTargetKey(
|
|
73955
|
+
getDomEditTargetKey(selection)
|
|
73708
73956
|
);
|
|
73709
73957
|
const operations = [buildDomEditRichTextPatchOperation(html2)];
|
|
73710
73958
|
let appliedHtml = "";
|
|
@@ -73716,7 +73964,7 @@ function useDomEditTextCommits({
|
|
|
73716
73964
|
appliedHtml = element.innerHTML;
|
|
73717
73965
|
},
|
|
73718
73966
|
persist: async () => {
|
|
73719
|
-
await persistDomEditOperations(
|
|
73967
|
+
await persistDomEditOperations(selection, operations, {
|
|
73720
73968
|
label: "Edit text",
|
|
73721
73969
|
skipRefresh: true,
|
|
73722
73970
|
shouldSave: isLatestTextCommit
|
|
@@ -73728,11 +73976,12 @@ function useDomEditTextCommits({
|
|
|
73728
73976
|
element.innerHTML = previousHtml;
|
|
73729
73977
|
}
|
|
73730
73978
|
},
|
|
73731
|
-
onError: (error) => reportDomEditPersistFailure(
|
|
73732
|
-
|
|
73979
|
+
onError: (error) => reportDomEditPersistFailure(selection, operations, error, showToast),
|
|
73980
|
+
// Re-select only what is still selected: the selection may have moved on, or a host cleared it.
|
|
73981
|
+
shouldResync: () => isLatestTextCommit() && latestSelectionRef.current?.element === element,
|
|
73733
73982
|
resync: () => resyncDomTextSelectionFromPreview(
|
|
73734
73983
|
doc,
|
|
73735
|
-
|
|
73984
|
+
selection,
|
|
73736
73985
|
activeCompPath,
|
|
73737
73986
|
buildDomSelectionFromTarget,
|
|
73738
73987
|
applyDomSelection
|
|
@@ -73744,7 +73993,6 @@ function useDomEditTextCommits({
|
|
|
73744
73993
|
activeCompPath,
|
|
73745
73994
|
applyDomSelection,
|
|
73746
73995
|
buildDomSelectionFromTarget,
|
|
73747
|
-
domEditSelection,
|
|
73748
73996
|
persistDomEditOperations,
|
|
73749
73997
|
previewIframeRef,
|
|
73750
73998
|
showToast
|
|
@@ -73925,8 +74173,8 @@ function readDragStart(el, axis) {
|
|
|
73925
74173
|
function applyElementPositionOffset(el, gestureOffset) {
|
|
73926
74174
|
const cs = el.ownerDocument.defaultView?.getComputedStyle(el);
|
|
73927
74175
|
if (!cs) return "anchored";
|
|
73928
|
-
const dx =
|
|
73929
|
-
const dy =
|
|
74176
|
+
const dx = roundTo3(gestureOffset.x - readDragStart(el, "x"));
|
|
74177
|
+
const dy = roundTo3(gestureOffset.y - readDragStart(el, "y"));
|
|
73930
74178
|
const lifted = el.getAttribute(LAYER_REVEAL_PRIOR_POSITION_ATTR) === "static";
|
|
73931
74179
|
const isStatic = lifted || !/^(relative|absolute|fixed|sticky)$/.test(cs.position);
|
|
73932
74180
|
if (!isStatic && (cs.left.endsWith("%") || cs.top.endsWith("%"))) return "percent";
|
|
@@ -73935,8 +74183,8 @@ function applyElementPositionOffset(el, gestureOffset) {
|
|
|
73935
74183
|
const previous = { position: el.style.position, left: el.style.left, top: el.style.top };
|
|
73936
74184
|
const before = layoutBox(el);
|
|
73937
74185
|
if (isStatic) el.style.position = "relative";
|
|
73938
|
-
el.style.left = `${
|
|
73939
|
-
el.style.top = `${
|
|
74186
|
+
el.style.left = `${roundTo3(baseLeft + dx)}px`;
|
|
74187
|
+
el.style.top = `${roundTo3(baseTop + dy)}px`;
|
|
73940
74188
|
const after = layoutBox(el);
|
|
73941
74189
|
const shiftedExactly = Math.abs(after.left - before.left - dx) <= 1 && Math.abs(after.top - before.top - dy) <= 1 && Math.abs(after.width - before.width) <= 1 && Math.abs(after.height - before.height) <= 1;
|
|
73942
74190
|
if (!shiftedExactly) {
|
|
@@ -73962,9 +74210,29 @@ function settleGsapDraftAtGestureStart(el) {
|
|
|
73962
74210
|
const y = Number.parseFloat(el.getAttribute("data-hf-drag-gsap-base-y") ?? "");
|
|
73963
74211
|
if (gsap3 && Number.isFinite(x) && Number.isFinite(y)) gsap3.set(el, { x, y });
|
|
73964
74212
|
}
|
|
74213
|
+
var plainMoveCounter = 0;
|
|
74214
|
+
function stagePlainTranslate(commitPositionPatchToHtml, selection, next, coalesceKey) {
|
|
74215
|
+
const style = selection.element.style;
|
|
74216
|
+
const before = style.getPropertyValue("translate");
|
|
74217
|
+
const patch = translatePatch(next);
|
|
74218
|
+
style.setProperty("translate", patch.value);
|
|
74219
|
+
const rollback = () => {
|
|
74220
|
+
if (style.getPropertyValue("translate") === patch.value) style.setProperty("translate", before);
|
|
74221
|
+
};
|
|
74222
|
+
const key2 = coalesceKey ?? `move:${++plainMoveCounter}`;
|
|
74223
|
+
const options = { label: "Move layer", coalesceKey: key2, coalesceMs: Number.POSITIVE_INFINITY };
|
|
74224
|
+
const save = () => commitPositionPatchToHtml(selection, [patch], options).catch((error) => {
|
|
74225
|
+
rollback();
|
|
74226
|
+
throw error;
|
|
74227
|
+
});
|
|
74228
|
+
return { save, rollback };
|
|
74229
|
+
}
|
|
73965
74230
|
function stageElementOffset({ commitPositionPatchToHtml, showToast, readOnlyPreview }, selection, next, coalesceKey) {
|
|
73966
74231
|
const el = selection.element;
|
|
73967
74232
|
if (readOnlyPreview) return { save: () => Promise.resolve(), rollback: () => void 0 };
|
|
74233
|
+
if (!gsapWritesPosition(el)) {
|
|
74234
|
+
return stagePlainTranslate(commitPositionPatchToHtml, selection, next, coalesceKey);
|
|
74235
|
+
}
|
|
73968
74236
|
const previous = { position: el.style.position, left: el.style.left, top: el.style.top };
|
|
73969
74237
|
const liftMarker = el.getAttribute(LAYER_REVEAL_PRIOR_POSITION_ATTR);
|
|
73970
74238
|
const result = applyElementPositionOffset(el, next);
|
|
@@ -74238,8 +74506,11 @@ function useDomGeometryCommits({
|
|
|
74238
74506
|
if (gsapFallback) return gsapFallback;
|
|
74239
74507
|
const beforeSize = captureStudioBoxSize(selection.element);
|
|
74240
74508
|
const beforeOffset = offset ? captureStudioPathOffset(selection.element) : null;
|
|
74509
|
+
const stageCrop = prepareCropResize(selection.element);
|
|
74241
74510
|
applyStudioBoxSize(selection.element, next);
|
|
74511
|
+
const crop = stageCrop();
|
|
74242
74512
|
const patches = buildBoxSizePatches(selection.element);
|
|
74513
|
+
if (crop) patches.push(crop.patch);
|
|
74243
74514
|
if (offset) {
|
|
74244
74515
|
applyStudioPathOffset(selection.element, offset);
|
|
74245
74516
|
patches.push(...buildPathOffsetPatches(selection.element));
|
|
@@ -74250,6 +74521,7 @@ function useDomGeometryCommits({
|
|
|
74250
74521
|
}).catch((error) => {
|
|
74251
74522
|
restoreStudioBoxSize(selection.element, beforeSize);
|
|
74252
74523
|
if (beforeOffset) restoreStudioPathOffset(selection.element, beforeOffset);
|
|
74524
|
+
crop?.revert();
|
|
74253
74525
|
throw error;
|
|
74254
74526
|
});
|
|
74255
74527
|
},
|
|
@@ -74520,6 +74792,7 @@ function useDomEditCommits({
|
|
|
74520
74792
|
handleDomAddTextField,
|
|
74521
74793
|
handleDomRemoveTextField,
|
|
74522
74794
|
stageElementPositionOffset,
|
|
74795
|
+
commitPositionPatchToHtml,
|
|
74523
74796
|
handleDomPathOffsetCommit,
|
|
74524
74797
|
handleDomBoxSizeCommit,
|
|
74525
74798
|
handleDomRotationCommit,
|
|
@@ -76874,8 +77147,8 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
76874
77147
|
}
|
|
76875
77148
|
} else {
|
|
76876
77149
|
resizeProps = {
|
|
76877
|
-
width:
|
|
76878
|
-
height:
|
|
77150
|
+
width: roundToLayoutPx(size.width),
|
|
77151
|
+
height: roundToLayoutPx(size.height)
|
|
76879
77152
|
};
|
|
76880
77153
|
}
|
|
76881
77154
|
const finalizeScaleResizeCommit = async () => {
|
|
@@ -76901,8 +77174,8 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
76901
77174
|
return true;
|
|
76902
77175
|
}
|
|
76903
77176
|
const corrected = {
|
|
76904
|
-
x:
|
|
76905
|
-
y:
|
|
77177
|
+
x: roundTo3(base2.x + residual.x),
|
|
77178
|
+
y: roundTo3(base2.y + residual.y)
|
|
76906
77179
|
};
|
|
76907
77180
|
logResize("scale-finalize", {
|
|
76908
77181
|
dropPoint: scaleDraftDropPoint,
|
|
@@ -77291,8 +77564,8 @@ function useAnimatedPropertyCommit(deps) {
|
|
|
77291
77564
|
const commitAnimatedProperties = useCallback137(
|
|
77292
77565
|
// This is the single routing boundary for set, keyframe, whole-tween, and first-group writes.
|
|
77293
77566
|
// fallow-ignore-next-line complexity
|
|
77294
|
-
async (selection, props) => {
|
|
77295
|
-
if (!
|
|
77567
|
+
async (selection, props, commit = gsapCommitMutation) => {
|
|
77568
|
+
if (!commit) return;
|
|
77296
77569
|
const propEntries = Object.entries(props);
|
|
77297
77570
|
if (propEntries.length === 0) return;
|
|
77298
77571
|
const primaryProp = propEntries[0][0];
|
|
@@ -77329,7 +77602,7 @@ function useAnimatedPropertyCommit(deps) {
|
|
|
77329
77602
|
),
|
|
77330
77603
|
pct,
|
|
77331
77604
|
iframe,
|
|
77332
|
-
{ commitMutation:
|
|
77605
|
+
{ commitMutation: commit },
|
|
77333
77606
|
`Edit ${primaryProp} (whole animation)`
|
|
77334
77607
|
);
|
|
77335
77608
|
return;
|
|
@@ -77342,18 +77615,12 @@ function useAnimatedPropertyCommit(deps) {
|
|
|
77342
77615
|
primaryProp,
|
|
77343
77616
|
selector,
|
|
77344
77617
|
iframe,
|
|
77345
|
-
|
|
77618
|
+
commit
|
|
77346
77619
|
);
|
|
77347
77620
|
return;
|
|
77348
77621
|
}
|
|
77349
77622
|
if (!elementHasKeyframes) {
|
|
77350
|
-
await commitStaticSet(
|
|
77351
|
-
selection,
|
|
77352
|
-
propEntries,
|
|
77353
|
-
selector,
|
|
77354
|
-
selectedGsapAnimations,
|
|
77355
|
-
gsapCommitMutation
|
|
77356
|
-
);
|
|
77623
|
+
await commitStaticSet(selection, propEntries, selector, selectedGsapAnimations, commit);
|
|
77357
77624
|
return;
|
|
77358
77625
|
}
|
|
77359
77626
|
if (anim && isInstantHold(anim)) {
|
|
@@ -77363,7 +77630,7 @@ function useAnimatedPropertyCommit(deps) {
|
|
|
77363
77630
|
propEntries,
|
|
77364
77631
|
selector,
|
|
77365
77632
|
selectedGsapAnimations,
|
|
77366
|
-
|
|
77633
|
+
commit
|
|
77367
77634
|
);
|
|
77368
77635
|
return;
|
|
77369
77636
|
}
|
|
@@ -77379,7 +77646,7 @@ function useAnimatedPropertyCommit(deps) {
|
|
|
77379
77646
|
{ percentage: 0, properties: { ...newProps, _auto: 1 } },
|
|
77380
77647
|
{ percentage: pct, properties: newProps }
|
|
77381
77648
|
];
|
|
77382
|
-
await
|
|
77649
|
+
await commit(
|
|
77383
77650
|
selection,
|
|
77384
77651
|
{
|
|
77385
77652
|
type: "add-with-keyframes",
|
|
@@ -77408,10 +77675,6 @@ function useAnimatedPropertyCommit(deps) {
|
|
|
77408
77675
|
}
|
|
77409
77676
|
|
|
77410
77677
|
// src/hooks/useGsapAwareEditing.ts
|
|
77411
|
-
async function saveMove(outcome, saveOnElement) {
|
|
77412
|
-
if (outcome.status === "element-offset") return saveOnElement();
|
|
77413
|
-
assertGsapEditPersisted(outcome);
|
|
77414
|
-
}
|
|
77415
77678
|
var groupDragCommitCounter = 0;
|
|
77416
77679
|
function firstPreflightFailure(results, updates) {
|
|
77417
77680
|
for (const [index, result] of results.entries()) {
|
|
@@ -77432,6 +77695,7 @@ function useGsapAwareEditing({
|
|
|
77432
77695
|
trackGsapInteractionFailure,
|
|
77433
77696
|
stageElementPositionOffset,
|
|
77434
77697
|
handleDomBoxSizeCommit,
|
|
77698
|
+
commitPositionPatchToHtml,
|
|
77435
77699
|
addGsapAnimation,
|
|
77436
77700
|
convertToKeyframes,
|
|
77437
77701
|
setArcPath,
|
|
@@ -77446,6 +77710,8 @@ function useGsapAwareEditing({
|
|
|
77446
77710
|
);
|
|
77447
77711
|
const handleGsapAwarePathOffsetCommit = useCallback138(
|
|
77448
77712
|
async (selection, next, modifiers) => {
|
|
77713
|
+
if (!gsapWritesPosition(selection.element))
|
|
77714
|
+
return stageElementPositionOffset(selection, next).save();
|
|
77449
77715
|
if (gsapCommitMutation) {
|
|
77450
77716
|
try {
|
|
77451
77717
|
const ownedAnimations = getGsapAnimationsForSelection(selection);
|
|
@@ -77511,6 +77777,7 @@ function useGsapAwareEditing({
|
|
|
77511
77777
|
const offsetMembers = /* @__PURE__ */ new Set();
|
|
77512
77778
|
const preflightResults = await Promise.allSettled(
|
|
77513
77779
|
updates.map(async ({ selection }) => {
|
|
77780
|
+
if (!gsapWritesPosition(selection.element)) return void offsetMembers.add(selection);
|
|
77514
77781
|
const animations = await makeFetchFallback(selection, { failOnFetchError: true })();
|
|
77515
77782
|
preflightAnimations.set(selection, animations);
|
|
77516
77783
|
const outcome = await tryGsapDragIntercept(
|
|
@@ -77609,6 +77876,8 @@ function useGsapAwareEditing({
|
|
|
77609
77876
|
animGroups: targetAnimations.map((a) => `${a.propertyGroup}:${a.method}`)
|
|
77610
77877
|
});
|
|
77611
77878
|
let anchorMove = null;
|
|
77879
|
+
const stageCrop = prepareCropResize(selection.element);
|
|
77880
|
+
let cropUndoKey = null;
|
|
77612
77881
|
return runGestureTransaction({
|
|
77613
77882
|
element: selection.element,
|
|
77614
77883
|
label: "Resize layer",
|
|
@@ -77635,6 +77904,7 @@ function useGsapAwareEditing({
|
|
|
77635
77904
|
makeFetchFallback(selection)
|
|
77636
77905
|
);
|
|
77637
77906
|
assertGsapEditPersisted(outcome);
|
|
77907
|
+
cropUndoKey = coalesceKey;
|
|
77638
77908
|
const ownsDragOffset = outcome.status === "persisted" && outcome.ownsDragOffset === true;
|
|
77639
77909
|
logResize("intercept-handled", {
|
|
77640
77910
|
scaleRoute,
|
|
@@ -77669,7 +77939,12 @@ function useGsapAwareEditing({
|
|
|
77669
77939
|
logResizeSettle(selection.element, "dom-route");
|
|
77670
77940
|
await handleDomBoxSizeCommit(selection, next, offset);
|
|
77671
77941
|
},
|
|
77672
|
-
afterBufferedCommitsSaved: () =>
|
|
77942
|
+
afterBufferedCommitsSaved: async () => {
|
|
77943
|
+
await anchorMove?.save();
|
|
77944
|
+
if (cropUndoKey) {
|
|
77945
|
+
await saveCropResize(stageCrop, selection, commitPositionPatchToHtml, cropUndoKey);
|
|
77946
|
+
}
|
|
77947
|
+
},
|
|
77673
77948
|
restore: () => {
|
|
77674
77949
|
anchorMove?.rollback();
|
|
77675
77950
|
restore();
|
|
@@ -77679,6 +77954,7 @@ function useGsapAwareEditing({
|
|
|
77679
77954
|
},
|
|
77680
77955
|
[
|
|
77681
77956
|
handleDomBoxSizeCommit,
|
|
77957
|
+
commitPositionPatchToHtml,
|
|
77682
77958
|
stageElementPositionOffset,
|
|
77683
77959
|
gsapCommitMutation,
|
|
77684
77960
|
previewIframeRef,
|
|
@@ -77716,10 +77992,7 @@ function useGsapAwareEditing({
|
|
|
77716
77992
|
getGsapAnimationsForSelection
|
|
77717
77993
|
]
|
|
77718
77994
|
);
|
|
77719
|
-
const {
|
|
77720
|
-
commitAnimatedProperty: commitAnimatedPropertyRaw,
|
|
77721
|
-
commitAnimatedProperties: commitAnimatedPropertiesRaw
|
|
77722
|
-
} = useAnimatedPropertyCommit({
|
|
77995
|
+
const { commitAnimatedProperties: commitAnimatedPropertiesRaw } = useAnimatedPropertyCommit({
|
|
77723
77996
|
selectedGsapAnimations,
|
|
77724
77997
|
gsapCommitMutation,
|
|
77725
77998
|
addGsapAnimation: (sel, method, time) => addGsapAnimation(sel, method, time),
|
|
@@ -77730,24 +78003,28 @@ function useGsapAwareEditing({
|
|
|
77730
78003
|
const commitAnimatedProperties = useCallback138(
|
|
77731
78004
|
async (selection, properties) => {
|
|
77732
78005
|
try {
|
|
77733
|
-
await
|
|
78006
|
+
await writeSizeWithCrop(
|
|
78007
|
+
selection,
|
|
78008
|
+
properties,
|
|
78009
|
+
gsapCommitMutation,
|
|
78010
|
+
commitPositionPatchToHtml,
|
|
78011
|
+
(keyed) => commitAnimatedPropertiesRaw(selection, properties, keyed)
|
|
78012
|
+
);
|
|
77734
78013
|
} catch (error) {
|
|
77735
78014
|
trackGsapInteractionFailure(error, selection, "property", "Edit animated property");
|
|
77736
78015
|
throw error;
|
|
77737
78016
|
}
|
|
77738
78017
|
},
|
|
77739
|
-
[
|
|
78018
|
+
[
|
|
78019
|
+
commitAnimatedPropertiesRaw,
|
|
78020
|
+
commitPositionPatchToHtml,
|
|
78021
|
+
gsapCommitMutation,
|
|
78022
|
+
trackGsapInteractionFailure
|
|
78023
|
+
]
|
|
77740
78024
|
);
|
|
77741
78025
|
const commitAnimatedProperty = useCallback138(
|
|
77742
|
-
|
|
77743
|
-
|
|
77744
|
-
await commitAnimatedPropertyRaw(selection, property, value);
|
|
77745
|
-
} catch (error) {
|
|
77746
|
-
trackGsapInteractionFailure(error, selection, "property", "Edit animated property");
|
|
77747
|
-
throw error;
|
|
77748
|
-
}
|
|
77749
|
-
},
|
|
77750
|
-
[commitAnimatedPropertyRaw, trackGsapInteractionFailure]
|
|
78026
|
+
(selection, property, value) => commitAnimatedProperties(selection, { [property]: value }),
|
|
78027
|
+
[commitAnimatedProperties]
|
|
77751
78028
|
);
|
|
77752
78029
|
const handleSetArcPath = useCallback138(
|
|
77753
78030
|
(animId, config) => {
|
|
@@ -78252,6 +78529,7 @@ function useDomEditSession({
|
|
|
78252
78529
|
handleDomAddTextField,
|
|
78253
78530
|
handleDomRemoveTextField,
|
|
78254
78531
|
stageElementPositionOffset,
|
|
78532
|
+
commitPositionPatchToHtml,
|
|
78255
78533
|
handleDomBoxSizeCommit,
|
|
78256
78534
|
handleDomManualEditsReset,
|
|
78257
78535
|
handleDomEditElementsDelete,
|
|
@@ -78482,6 +78760,7 @@ function useDomEditSession({
|
|
|
78482
78760
|
trackGsapInteractionFailure,
|
|
78483
78761
|
stageElementPositionOffset,
|
|
78484
78762
|
handleDomBoxSizeCommit,
|
|
78763
|
+
commitPositionPatchToHtml,
|
|
78485
78764
|
addGsapAnimation,
|
|
78486
78765
|
convertToKeyframes,
|
|
78487
78766
|
setArcPath,
|
|
@@ -80155,7 +80434,7 @@ function useAppHotkeys({
|
|
|
80155
80434
|
|
|
80156
80435
|
// src/hooks/useClipboard.ts
|
|
80157
80436
|
import { useCallback as useCallback147, useRef as useRef154 } from "react";
|
|
80158
|
-
import { EXCLUDED_TAGS, mintHfId, walkCompositionDescendants } from "@hyperframes/parsers/hf-ids";
|
|
80437
|
+
import { EXCLUDED_TAGS, mintHfId, walkCompositionDescendants as walkCompositionDescendants2 } from "@hyperframes/parsers/hf-ids";
|
|
80159
80438
|
|
|
80160
80439
|
// src/utils/clipboardPayload.ts
|
|
80161
80440
|
function insertAsSibling(source, newHtml, selector, selectorIndex) {
|
|
@@ -80354,7 +80633,7 @@ function remintHfIds(html2, parser, taken) {
|
|
|
80354
80633
|
return html2.replace(/\sdata-hf-id=("[^"]*"|'[^']*')/g, "");
|
|
80355
80634
|
}
|
|
80356
80635
|
const elements = [root];
|
|
80357
|
-
|
|
80636
|
+
walkCompositionDescendants2(root, (el) => elements.push(el));
|
|
80358
80637
|
for (const el of elements) {
|
|
80359
80638
|
if (EXCLUDED_TAGS.has(el.tagName.toLowerCase())) el.removeAttribute("data-hf-id");
|
|
80360
80639
|
else el.setAttribute("data-hf-id", mintHfId(el, taken));
|
|
@@ -92455,6 +92734,7 @@ function useDomGeometryCommit({
|
|
|
92455
92734
|
trackGsapInteractionFailure,
|
|
92456
92735
|
stageElementPositionOffset,
|
|
92457
92736
|
handleDomBoxSizeCommit: noDomBoxSizeRoute,
|
|
92737
|
+
commitPositionPatchToHtml: commitWithFreshQueue,
|
|
92458
92738
|
addGsapAnimation: gsap3.addGsapAnimation,
|
|
92459
92739
|
convertToKeyframes: gsap3.convertToKeyframes,
|
|
92460
92740
|
setArcPath: gsap3.setArcPath,
|