hyperframes 0.8.115 → 0.8.116
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-ZSLFODRZ.js → add-5AOKGJRR.js} +16 -16
- package/dist/{animatedGifPrep-72A45YER.js → animatedGifPrep-XKCVQ4ZL.js} +7 -7
- package/dist/{asset-SGDOHBBN.js → asset-QE74HE7H.js} +2 -2
- package/dist/{assetCataloger-Q7BCDARF.js → assetCataloger-3VJRWB3N.js} +3 -3
- package/dist/{auth-5JGFN7SV.js → auth-HQE2GKY2.js} +2 -2
- package/dist/{autoUpdate-ZVTMYO7Z.js → autoUpdate-MH57H575.js} +2 -2
- package/dist/{backgroundChecks-IY3G5G2D.js → backgroundChecks-JP2GHEP4.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-QVLLL5DN.js → batchRender-KIFBKKVN.js} +4 -4
- package/dist/{beats-66KZIB5V.js → beats-V334Q2GV.js} +13 -13
- package/dist/{benchmark-AWFKSWQH.js → benchmark-62QZH5YE.js} +13 -13
- package/dist/{browser-J54EXMCE.js → browser-EK7OBU6W.js} +10 -10
- package/dist/{bundleWithLocalizedFonts-BLLHP2TO.js → bundleWithLocalizedFonts-263BUY7C.js} +2 -2
- package/dist/{capture-SLI2I5BS.js → capture-56HMZGJW.js} +10 -10
- package/dist/{capture-D4HRSVSK.js → capture-6F3XPKXI.js} +2 -2
- package/dist/{catalog-BUMLQU7L.js → catalog-JO7WHBYC.js} +16 -16
- package/dist/{check-HEZUK62C.js → check-S4RZIS26.js} +33 -33
- package/dist/{checkBrowser-RVJM6IUO.js → checkBrowser-NVWULRE7.js} +32 -32
- package/dist/{chunk-MPB7BQT7.js → chunk-23KZNTIV.js} +1 -1
- package/dist/{chunk-IOJAVV6J.js → chunk-2E4A277E.js} +1 -1
- package/dist/{chunk-CVBWF2MD.js → chunk-2HE5ZOXK.js} +1 -1
- package/dist/{chunk-TWJT2RGZ.js → chunk-34AE4KPB.js} +4 -4
- package/dist/{chunk-5MXN7WM4.js → chunk-63O3AR5U.js} +3 -3
- package/dist/{chunk-WZYHTXZY.js → chunk-6FRHKGRY.js} +1 -1
- package/dist/{chunk-AXXK3LWL.js → chunk-6TSA2KDM.js} +1 -1
- package/dist/{chunk-YNHP6OFJ.js → chunk-7Z2XNQ7F.js} +2 -2
- package/dist/{chunk-XMAL2A7Y.js → chunk-AIYKVE4Y.js} +1 -1
- package/dist/{chunk-IEE7GIVX.js → chunk-AKZD7VWZ.js} +2 -2
- package/dist/{chunk-ORAISNGN.js → chunk-C47XJXSK.js} +10 -10
- package/dist/{chunk-2H37RGJ2.js → chunk-CCWSLTWA.js} +10 -10
- package/dist/{chunk-SSZYJCAL.js → chunk-CHWO3UN6.js} +2 -2
- package/dist/{chunk-Y2Y4LBJD.js → chunk-CVE7OUZE.js} +3 -3
- package/dist/{chunk-3R6P5BIG.js → chunk-DRLB5STV.js} +2 -2
- package/dist/{chunk-KLZ7OCHR.js → chunk-ENQL7NCM.js} +3 -3
- package/dist/{chunk-T5HXGUM3.js → chunk-EWR3SLQV.js} +1 -1
- package/dist/{chunk-SAO3NQPF.js → chunk-EWUI4PU6.js} +1 -1
- package/dist/{chunk-2GWVY66H.js → chunk-FERBBWDU.js} +1 -1
- package/dist/{chunk-QXNRRMBQ.js → chunk-FFF36PQA.js} +2 -2
- package/dist/{chunk-UUDQD62L.js → chunk-FSLYPQ5Z.js} +1 -1
- package/dist/{chunk-4P2TOD7N.js → chunk-GNQF4NZW.js} +1 -1
- package/dist/{chunk-HOBR4IHC.js → chunk-IGWZCCLO.js} +7 -7
- package/dist/{chunk-2DX6JYL2.js → chunk-IX75NQSA.js} +2 -2
- package/dist/{chunk-SK53U3PF.js → chunk-JBZYEZPZ.js} +1 -1
- package/dist/{chunk-6SEUZGID.js → chunk-JYB7NKO6.js} +3 -3
- package/dist/{chunk-HPWPLV5J.js → chunk-KNCLHJB5.js} +3 -3
- package/dist/{chunk-M7XTMZF5.js → chunk-MZPMAU25.js} +2 -2
- package/dist/{chunk-SC7ICSIU.js → chunk-NCQV2NMY.js} +1 -1
- package/dist/{chunk-YJEGT5L6.js → chunk-NITBGIHR.js} +2 -2
- package/dist/{chunk-PZTEY73C.js → chunk-NRTZ2JPC.js} +1 -1
- package/dist/{chunk-BDNCUMZM.js → chunk-PAZUQZYV.js} +1 -1
- package/dist/{chunk-3J4EBX5M.js → chunk-PHBPRHKK.js} +1 -1
- package/dist/{chunk-3YTWSGBV.js → chunk-QITH7ALB.js} +4 -4
- package/dist/{chunk-XJQ7TRLG.js → chunk-RTLYNXAC.js} +1 -1
- package/dist/{chunk-4HIF3LI3.js → chunk-S5Q46UEI.js} +5 -5
- package/dist/{chunk-PLP4K6WZ.js → chunk-SXV67HVP.js} +92 -34
- package/dist/{chunk-ZBQP54CD.js → chunk-TEYBS6T3.js} +5 -5
- package/dist/{chunk-RDMAU7AJ.js → chunk-TRLP3CSL.js} +1 -1
- package/dist/{chunk-QMFCL2ZN.js → chunk-TY76XMMP.js} +2 -2
- package/dist/{chunk-SOEQWMNS.js → chunk-VJ2RAP65.js} +2 -2
- package/dist/{chunk-TMCJPHPP.js → chunk-VLB4NGRR.js} +1 -1
- package/dist/{chunk-VDASTWUM.js → chunk-VU5IDWKX.js} +2 -2
- package/dist/{chunk-P73WQPSB.js → chunk-WN62HDA7.js} +1 -1
- package/dist/{chunk-BQG33YTI.js → chunk-WUUEWXA2.js} +1 -1
- package/dist/chunk-WWL6YGYK.js +3541 -0
- package/dist/{chunk-74RAXWDF.js → chunk-XTCMIITZ.js} +1 -1
- package/dist/{chunk-5YSA3YXO.js → chunk-YX55Y7UO.js} +9 -9
- package/dist/{clean-X6Y252ZC.js → clean-DPW2FTMM.js} +17 -17
- package/dist/cli.js +50 -50
- package/dist/{cloud-EE4GALWR.js → cloud-OAYSRXAJ.js} +4 -4
- package/dist/{cloudrun-Y6A42KHE.js → cloudrun-NM2ZMAJV.js} +5 -5
- package/dist/{compare-K6XJZ3OC.js → compare-CZC6ROYF.js} +27 -27
- package/dist/{compiler-DYACPLUW.js → compiler-3MFRD377.js} +3 -3
- package/dist/{component-T6IYSCFP.js → component-6D5RBOWZ.js} +3 -3
- package/dist/{compositions-4KUTNS5L.js → compositions-5KCUVODZ.js} +12 -12
- package/dist/{delete-C64TWAPE.js → delete-ZGLELTUJ.js} +2 -2
- package/dist/{deterministicFonts-A4CNCSAL.js → deterministicFonts-O7BTFDJU.js} +2 -2
- package/dist/{dist-HRBNHR4M.js → dist-JAOG6MYW.js} +1 -1
- package/dist/{dist-KNGSQALD.js → dist-XSSXGBRH.js} +3 -3
- package/dist/{doctor-WJXZK5QN.js → doctor-CICSVC7I.js} +11 -11
- package/dist/{events-QRWJBSV4.js → events-V3O6Q5ZH.js} +9 -9
- package/dist/{events-FVG3Y6Q4.js → events-Y4NBIJBP.js} +10 -10
- package/dist/{feedback-NQHRUOZP.js → feedback-EA3K6QXT.js} +11 -11
- package/dist/{figma-MEX4CSIM.js → figma-WOOHCXDA.js} +3 -3
- package/dist/fontLocalizeCli.js +10 -10
- package/dist/{get-CMJIHGSA.js → get-64SDPINM.js} +2 -2
- package/dist/{gpuPolicy-5S4OZDME.js → gpuPolicy-TFCLAD64.js} +7 -7
- package/dist/{grade-compare-NIDMIUGZ.js → grade-compare-NXAFWDBR.js} +27 -27
- package/dist/{gsapParserAcorn-SZANFUAQ.js → gsapParserAcorn-FLWABPQM.js} +1 -1
- package/dist/{help-G6AWAWJW.js → help-6H4ICA27.js} +1 -1
- package/dist/{history-ZBOK2JQF.js → history-TPRRROOR.js} +17 -17
- package/dist/hyperframe-runtime.js +50 -50
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +50 -50
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/{info-2ORQZ6I2.js → info-DDXWWAM3.js} +12 -12
- package/dist/{init-3PSKH6UR.js → init-KULZFAS7.js} +23 -23
- package/dist/{inspect-NR54RMEE.js → inspect-VEJH72DJ.js} +28 -28
- package/dist/{installer-YQUWHYBZ.js → installer-TBL3PE2J.js} +5 -5
- package/dist/{keyframes-KT7T4AEV.js → keyframes-W6KIRZ4O.js} +13 -13
- package/dist/{lambda-3FF4V3X3.js → lambda-JJXODPS5.js} +6 -6
- package/dist/{layout-RB3M37ER.js → layout-KVG7PJ3F.js} +28 -28
- package/dist/{lint-HR57M5YP.js → lint-GQ5IVVCN.js} +13 -13
- package/dist/{lintProject-TOLC6HDS.js → lintProject-FDJYTOVM.js} +1 -1
- package/dist/{list-YDXYHXHF.js → list-QZ7LV6HF.js} +2 -2
- package/dist/{login-N6UNRVYW.js → login-526R3KCB.js} +4 -4
- package/dist/{media-treatment-UXJOTNRO.js → media-treatment-H7LGSO3I.js} +13 -13
- package/dist/{models-Z3XFMGXB.js → models-WOEP555T.js} +8 -8
- package/dist/{motionShot-KQMCXJ77.js → motionShot-235LNUY7.js} +12 -12
- package/dist/{normalize-audio-XJQMDWRV.js → normalize-audio-GTAESDG6.js} +12 -12
- package/dist/{pipeline-U3OISHWV.js → pipeline-NBHOEZPA.js} +7 -7
- package/dist/{play-XP77PML5.js → play-SBTJLOWX.js} +22 -22
- package/dist/{preflight-CANFVC4Y.js → preflight-KQCXRC6W.js} +8 -8
- package/dist/{present-MWGA3O4S.js → present-TXULFA2J.js} +18 -18
- package/dist/{preview-X5GWZ3Q6.js → preview-E2U4ER7H.js} +18 -18
- package/dist/{producer-B2IHU7MA.js → producer-DR3TOPSC.js} +1 -1
- package/dist/{projectConfig-2A64YU5H.js → projectConfig-QBYFCJYE.js} +7 -7
- package/dist/{publication-CFYBPLRS.js → publication-TWGRIP5F.js} +3 -3
- package/dist/{publish-WE6AS77D.js → publish-JOUHOKGX.js} +9 -9
- package/dist/{remove-background-XSDOCVN5.js → remove-background-GQZIZBHM.js} +8 -8
- package/dist/{render-5TMRIC73.js → render-2LC2DUR3.js} +13 -13
- package/dist/{render-QX6AKB6Y.js → render-JR3YIYZ4.js} +4 -4
- package/dist/{render-HVZUCLYW.js → render-UVGS7PLJ.js} +22 -22
- package/dist/{render-batch-QJXFVTDE.js → render-batch-MYH6ZGO3.js} +4 -4
- package/dist/{renderCancellation-WSSSHRFR.js → renderCancellation-EIBZHTFW.js} +7 -7
- package/dist/renderSetupWorker.js +1 -1
- package/dist/{resolver-WTXO6WXA.js → resolver-4Z5YISAU.js} +5 -5
- package/dist/{sherpa-S6ZBBEFO.js → sherpa-UX3MQXO5.js} +8 -8
- package/dist/{skills-CDRSTETB.js → skills-GXETMIED.js} +12 -12
- package/dist/{skillsUpdateCheck-FKREJXSF.js → skillsUpdateCheck-XS7OE6FX.js} +3 -3
- package/dist/{snapshot-T4PFSXTH.js → snapshot-OAHQ3EVJ.js} +28 -28
- package/dist/{src-5BZDQAVN.js → src-AZ5YCYQP.js} +9 -9
- package/dist/{src-IZMCUYK7.js → src-X6ACPJHG.js} +6 -6
- package/dist/{staticProjectServer-VN4ARAH4.js → staticProjectServer-P4QSLLF6.js} +16 -16
- package/dist/{status-OJZWJB53.js → status-KDRWJBPW.js} +7 -7
- package/dist/studio/assets/{hyperframes-player-C-9N8nk0.js → hyperframes-player-mGYvPVpw.js} +1 -1
- package/dist/studio/assets/{index-BoUM6Xqb.js → index-BWHt0-ir.js} +1 -1
- package/dist/studio/assets/{index-CAvZ0AA-.js → index-DYNaXPVf.js} +201 -201
- package/dist/studio/assets/{index-CVuorIMv.js → index-Dr3hNpvS.js} +1 -1
- package/dist/studio/{chunk-TXZMMOMA.js → chunk-3F47EFCT.js} +100 -2
- package/dist/studio/chunk-3F47EFCT.js.map +1 -0
- package/dist/studio/{domEditingLayers-D7VYFJJD.js → domEditingLayers-OL7GLSS4.js} +2 -2
- package/dist/studio/index.d.ts +104 -22
- package/dist/studio/index.html +1 -1
- package/dist/studio/index.js +1131 -1044
- package/dist/studio/index.js.map +1 -1
- package/dist/{studio-api-CIO2NKK5.js → studio-api-SYQOPCMB.js} +10 -10
- package/dist/{studioServer-G5GNYWDI.js → studioServer-ANSX6DY2.js} +42 -42
- package/dist/{system-PPNNGVIM.js → system-B6UYANYL.js} +7 -7
- package/dist/{telemetry-GMDMISOX.js → telemetry-AZEW2DZP.js} +10 -10
- package/dist/{timeline-5LSQX4OS.js → timeline-VIKY65W6.js} +17 -17
- package/dist/{tokens-VBXAT7CK.js → tokens-SSGCAC7E.js} +2 -2
- package/dist/{transcribe-GYCAIIEQ.js → transcribe-O33POKJY.js} +13 -13
- package/dist/{transcribe-VGYAWRXS.js → transcribe-PF6BUHHQ.js} +8 -8
- package/dist/{updateCheck-AZEREUQV.js → updateCheck-Y4SUY6VE.js} +2 -2
- package/dist/{upgrade-S63QN2LA.js → upgrade-EGIS5OCB.js} +2 -2
- package/dist/{urlDownloader-SM6ODN5O.js → urlDownloader-UBY27GFW.js} +6 -6
- package/dist/{validate-7MNUK5MH.js → validate-FE74RMPD.js} +17 -17
- package/dist/{video-JEOHARTC.js → video-DODRESEY.js} +7 -7
- package/package.json +1 -1
- package/dist/chunk-RRPJEHHW.js +0 -3541
- package/dist/studio/chunk-TXZMMOMA.js.map +0 -1
- /package/dist/studio/{domEditingLayers-D7VYFJJD.js.map → domEditingLayers-OL7GLSS4.js.map} +0 -0
package/dist/studio/index.js
CHANGED
|
@@ -71,6 +71,10 @@ import {
|
|
|
71
71
|
} from "./chunk-5VSXRGIX.js";
|
|
72
72
|
import {
|
|
73
73
|
DOM_EDIT_LAYER_OBSERVER_INIT,
|
|
74
|
+
STUDIO_FLAT_INSPECTOR_ENABLED,
|
|
75
|
+
STUDIO_SDK_CUTOVER_ENABLED,
|
|
76
|
+
STUDIO_SDK_CUTOVER_FAMILIES,
|
|
77
|
+
STUDIO_SDK_RESOLVER_SHADOW_ENABLED,
|
|
74
78
|
buildDefaultDomEditTextField,
|
|
75
79
|
buildDomEditPatchTarget,
|
|
76
80
|
buildDomEditRichTextPatchOperation,
|
|
@@ -88,13 +92,16 @@ import {
|
|
|
88
92
|
getDomEditTargetKey,
|
|
89
93
|
getDomLayerPatchTarget,
|
|
90
94
|
isElementComputedVisible,
|
|
95
|
+
isSdkFamilyEnabled,
|
|
91
96
|
isTextEditableSelection,
|
|
92
97
|
liveLayerElement,
|
|
98
|
+
manualEditingAvailability_exports,
|
|
93
99
|
readHfId,
|
|
94
100
|
resolveAllVisualDomEditTargets,
|
|
95
101
|
resolveDomEditSelection,
|
|
96
|
-
serializeDomEditTextFields
|
|
97
|
-
|
|
102
|
+
serializeDomEditTextFields,
|
|
103
|
+
studioApiFetch
|
|
104
|
+
} from "./chunk-3F47EFCT.js";
|
|
98
105
|
import {
|
|
99
106
|
LAYER_REVEAL_PRIOR_POSITION_ATTR,
|
|
100
107
|
LAYER_REVEAL_PRIOR_Z_ATTR,
|
|
@@ -155,9 +162,7 @@ import {
|
|
|
155
162
|
toHexColor,
|
|
156
163
|
wrapTimeline
|
|
157
164
|
} from "./chunk-5EKWJZLM.js";
|
|
158
|
-
import
|
|
159
|
-
__export
|
|
160
|
-
} from "./chunk-PZ5AY32C.js";
|
|
165
|
+
import "./chunk-PZ5AY32C.js";
|
|
161
166
|
|
|
162
167
|
// src/components/EditorShell.tsx
|
|
163
168
|
import { memo as memo33, useCallback as useCallback74 } from "react";
|
|
@@ -545,7 +550,7 @@ async function flushEvents() {
|
|
|
545
550
|
const controller = new AbortController();
|
|
546
551
|
const timeout = setTimeout(() => controller.abort(), FLUSH_TIMEOUT_MS);
|
|
547
552
|
try {
|
|
548
|
-
await
|
|
553
|
+
await studioApiFetch(`${POSTHOG_HOST}/batch/`, {
|
|
549
554
|
method: "POST",
|
|
550
555
|
headers: { "Content-Type": "application/json" },
|
|
551
556
|
body: JSON.stringify({ api_key: POSTHOG_API_KEY2, batch }),
|
|
@@ -4218,8 +4223,8 @@ function useAbandonEditsOnReadOnly(readOnly, abandon) {
|
|
|
4218
4223
|
if (readOnly) abandonNow();
|
|
4219
4224
|
}, [readOnly]);
|
|
4220
4225
|
}
|
|
4221
|
-
function reportPressOnTravel(start,
|
|
4222
|
-
if (!
|
|
4226
|
+
function reportPressOnTravel(start, refuse2, threshold = 4) {
|
|
4227
|
+
if (!refuse2) return;
|
|
4223
4228
|
const stop2 = () => {
|
|
4224
4229
|
window.removeEventListener("pointermove", onMove, true);
|
|
4225
4230
|
window.removeEventListener("pointerup", stop2, true);
|
|
@@ -4229,7 +4234,7 @@ function reportPressOnTravel(start, refuse, threshold = 4) {
|
|
|
4229
4234
|
if (Math.hypot(event.clientX - start.clientX, event.clientY - start.clientY) < threshold)
|
|
4230
4235
|
return;
|
|
4231
4236
|
stop2();
|
|
4232
|
-
|
|
4237
|
+
refuse2();
|
|
4233
4238
|
};
|
|
4234
4239
|
window.addEventListener("pointermove", onMove, true);
|
|
4235
4240
|
window.addEventListener("pointerup", stop2, true);
|
|
@@ -4359,6 +4364,10 @@ var PROPERTY_DEFAULTS = {
|
|
|
4359
4364
|
width: 100,
|
|
4360
4365
|
height: 100
|
|
4361
4366
|
};
|
|
4367
|
+
function keyframeEases(anim) {
|
|
4368
|
+
if (!anim.keyframes) return { easeEach: anim.ease };
|
|
4369
|
+
return { ease: anim.ease, easeEach: anim.keyframes.easeEach };
|
|
4370
|
+
}
|
|
4362
4371
|
function isInstantHold(animation) {
|
|
4363
4372
|
return animation.method === "set" || (animation.method === "to" || animation.method === "fromTo") && resolveTweenDuration(animation) === 0;
|
|
4364
4373
|
}
|
|
@@ -6736,7 +6745,7 @@ function flush() {
|
|
|
6736
6745
|
}
|
|
6737
6746
|
function send(url, payload) {
|
|
6738
6747
|
try {
|
|
6739
|
-
void
|
|
6748
|
+
void studioApiFetch(url, {
|
|
6740
6749
|
method: "POST",
|
|
6741
6750
|
headers: { "Content-Type": "application/json" },
|
|
6742
6751
|
body: payload,
|
|
@@ -11634,6 +11643,7 @@ function asElement(target) {
|
|
|
11634
11643
|
// src/utils/studioPendingEdits.ts
|
|
11635
11644
|
var STUDIO_FLUSH_PENDING_EDITS_EVENT = "hf-studio-flush-pending-edits";
|
|
11636
11645
|
var pendingEdits = /* @__PURE__ */ new Map();
|
|
11646
|
+
var NOT_SAVED = () => Promise.resolve(false);
|
|
11637
11647
|
var adopting = false;
|
|
11638
11648
|
function waitForPostBlurEffects() {
|
|
11639
11649
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
@@ -11677,7 +11687,7 @@ function trackStudioPendingEdit(result) {
|
|
|
11677
11687
|
if (!result) return void 0;
|
|
11678
11688
|
const promise = Promise.resolve(result);
|
|
11679
11689
|
if (adopting) return promise;
|
|
11680
|
-
pendingEdits.set(promise, { revert: null });
|
|
11690
|
+
pendingEdits.set(promise, { revert: null, landed: NOT_SAVED });
|
|
11681
11691
|
promise.then(
|
|
11682
11692
|
() => pendingEdits.delete(promise),
|
|
11683
11693
|
() => pendingEdits.delete(promise)
|
|
@@ -11696,6 +11706,8 @@ function beginStudioPendingEdit(revert) {
|
|
|
11696
11706
|
const promise = trackStudioPendingEdit(new Promise((resolve) => settle = resolve));
|
|
11697
11707
|
const entry2 = pendingEdits.get(promise);
|
|
11698
11708
|
entry2.revert = revert;
|
|
11709
|
+
let landed = Promise.resolve(false);
|
|
11710
|
+
entry2.landed = () => landed;
|
|
11699
11711
|
return {
|
|
11700
11712
|
settle,
|
|
11701
11713
|
reverted: () => entry2.revert === null && revert !== null,
|
|
@@ -11703,7 +11715,12 @@ function beginStudioPendingEdit(revert) {
|
|
|
11703
11715
|
adopt(start) {
|
|
11704
11716
|
adopting = true;
|
|
11705
11717
|
try {
|
|
11706
|
-
|
|
11718
|
+
const committed = start();
|
|
11719
|
+
landed = Promise.resolve(committed).then(
|
|
11720
|
+
() => true,
|
|
11721
|
+
() => false
|
|
11722
|
+
);
|
|
11723
|
+
return committed;
|
|
11707
11724
|
} catch (error) {
|
|
11708
11725
|
settle();
|
|
11709
11726
|
throw error;
|
|
@@ -11713,14 +11730,19 @@ function beginStudioPendingEdit(revert) {
|
|
|
11713
11730
|
}
|
|
11714
11731
|
};
|
|
11715
11732
|
}
|
|
11716
|
-
function
|
|
11733
|
+
function paintBackNewestStudioPendingEdit() {
|
|
11717
11734
|
const newest = [...pendingEdits.values()].at(-1);
|
|
11718
11735
|
const revert = newest?.revert;
|
|
11719
11736
|
if (!newest || !revert) return null;
|
|
11720
11737
|
newest.revert = null;
|
|
11721
|
-
return revert();
|
|
11738
|
+
return { showAgain: revert(), landed: newest.landed };
|
|
11722
11739
|
}
|
|
11723
|
-
|
|
11740
|
+
function revertNewestStudioPendingEdit() {
|
|
11741
|
+
return paintBackNewestStudioPendingEdit()?.showAgain ?? null;
|
|
11742
|
+
}
|
|
11743
|
+
async function flushStudioPendingEdits({
|
|
11744
|
+
onlyCurrent = false
|
|
11745
|
+
} = {}) {
|
|
11724
11746
|
const active = focusedField();
|
|
11725
11747
|
if (active) {
|
|
11726
11748
|
active.blur();
|
|
@@ -11731,10 +11753,12 @@ async function flushStudioPendingEdits() {
|
|
|
11731
11753
|
window.dispatchEvent(
|
|
11732
11754
|
new CustomEvent(STUDIO_FLUSH_PENDING_EDITS_EVENT, { detail })
|
|
11733
11755
|
);
|
|
11756
|
+
const current = onlyCurrent ? new Set(pendingEdits.keys()) : null;
|
|
11757
|
+
const waiting = () => [...pendingEdits.keys()].filter((edit) => !current || current.has(edit));
|
|
11734
11758
|
let conflict;
|
|
11735
11759
|
let firstFailure;
|
|
11736
|
-
while (detail.promises.length > 0 ||
|
|
11737
|
-
const promises = [...detail.promises, ...
|
|
11760
|
+
while (detail.promises.length > 0 || waiting().length > 0) {
|
|
11761
|
+
const promises = [...detail.promises, ...waiting()];
|
|
11738
11762
|
detail.promises = [];
|
|
11739
11763
|
const batchFailures = inspectDrainFailures(await Promise.allSettled(promises));
|
|
11740
11764
|
conflict ??= batchFailures.conflict;
|
|
@@ -11774,6 +11798,7 @@ var SAVES_AN_EDIT = {
|
|
|
11774
11798
|
handleDomAttributeBatchCommit: true,
|
|
11775
11799
|
handleDomPathOffsetCommit: true,
|
|
11776
11800
|
handleDomGroupPathOffsetCommit: true,
|
|
11801
|
+
handleDomGroupMoveBy: true,
|
|
11777
11802
|
handleDomZIndexReorderCommit: true,
|
|
11778
11803
|
handleDomBoxSizeCommit: true,
|
|
11779
11804
|
handleDomRotationCommit: true,
|
|
@@ -11894,6 +11919,7 @@ function DomEditProvider({
|
|
|
11894
11919
|
handleDomAttributeBatchCommit,
|
|
11895
11920
|
handleDomPathOffsetCommit,
|
|
11896
11921
|
handleDomGroupPathOffsetCommit,
|
|
11922
|
+
handleDomGroupMoveBy,
|
|
11897
11923
|
handleDomZIndexReorderCommit,
|
|
11898
11924
|
handleDomBoxSizeCommit,
|
|
11899
11925
|
handleDomRotationCommit,
|
|
@@ -11983,6 +12009,7 @@ function DomEditProvider({
|
|
|
11983
12009
|
handleDomAttributeBatchCommit,
|
|
11984
12010
|
handleDomPathOffsetCommit,
|
|
11985
12011
|
handleDomGroupPathOffsetCommit,
|
|
12012
|
+
handleDomGroupMoveBy,
|
|
11986
12013
|
handleDomZIndexReorderCommit,
|
|
11987
12014
|
handleDomBoxSizeCommit,
|
|
11988
12015
|
handleDomRotationCommit,
|
|
@@ -12059,6 +12086,7 @@ function DomEditProvider({
|
|
|
12059
12086
|
handleDomAttributeBatchCommit,
|
|
12060
12087
|
handleDomPathOffsetCommit,
|
|
12061
12088
|
handleDomGroupPathOffsetCommit,
|
|
12089
|
+
handleDomGroupMoveBy,
|
|
12062
12090
|
handleDomZIndexReorderCommit,
|
|
12063
12091
|
handleDomBoxSizeCommit,
|
|
12064
12092
|
handleDomRotationCommit,
|
|
@@ -14543,8 +14571,8 @@ function TimelineProvider({
|
|
|
14543
14571
|
useLayoutEffect6(() => {
|
|
14544
14572
|
onReadOnlyPressRef.current = onReadOnlyPress;
|
|
14545
14573
|
});
|
|
14546
|
-
const
|
|
14547
|
-
const readOnlyPress = readOnly ?
|
|
14574
|
+
const refuse2 = useCallback24(() => onReadOnlyPressRef.current?.(), []);
|
|
14575
|
+
const readOnlyPress = readOnly ? refuse2 : null;
|
|
14548
14576
|
return /* @__PURE__ */ jsx24(TimelineReadOnlyContext.Provider, { value: readOnlyPress, children: /* @__PURE__ */ jsx24(TimelineEditProvider, { value: readOnly ? NO_EDITS : editContext ?? props, children: /* @__PURE__ */ jsx24(TimelineProviderState, { ...props, children }) }) });
|
|
14549
14577
|
}
|
|
14550
14578
|
function TimelineProviderState({ children, ...props }) {
|
|
@@ -15591,6 +15619,15 @@ var ThumbnailScheduler = class {
|
|
|
15591
15619
|
entry2.controller = controller;
|
|
15592
15620
|
this.activeByBucket[bucket]++;
|
|
15593
15621
|
this.activeByKind[entry2.request.kind]++;
|
|
15622
|
+
let slotFree = false;
|
|
15623
|
+
const freeSlot = () => {
|
|
15624
|
+
if (slotFree) return;
|
|
15625
|
+
slotFree = true;
|
|
15626
|
+
this.activeByBucket[bucket]--;
|
|
15627
|
+
this.activeByKind[entry2.request.kind]--;
|
|
15628
|
+
this.pump();
|
|
15629
|
+
};
|
|
15630
|
+
controller.signal.addEventListener("abort", freeSlot, { once: true });
|
|
15594
15631
|
this.notify(entry2);
|
|
15595
15632
|
const pending2 = this.loadWithTimeout(entry2, controller);
|
|
15596
15633
|
void pending2.then((result) => this.acceptResult(entry2, controller, result)).catch((reason) => {
|
|
@@ -15608,8 +15645,7 @@ var ThumbnailScheduler = class {
|
|
|
15608
15645
|
this.evictFailures();
|
|
15609
15646
|
}).finally(() => {
|
|
15610
15647
|
if (entry2.controller === controller) entry2.controller = null;
|
|
15611
|
-
|
|
15612
|
-
this.activeByKind[entry2.request.kind]--;
|
|
15648
|
+
freeSlot();
|
|
15613
15649
|
this.pump();
|
|
15614
15650
|
});
|
|
15615
15651
|
}
|
|
@@ -15906,7 +15942,7 @@ async function loadWaveform(audioUrl, waveformUrl, signal) {
|
|
|
15906
15942
|
return waveformUrl ? await fetchWaveformPeaks(waveformUrl, signal) : await decodeWaveformPeaks(audioUrl, signal);
|
|
15907
15943
|
}
|
|
15908
15944
|
async function fetchWaveformPeaks(url, signal) {
|
|
15909
|
-
const response = await
|
|
15945
|
+
const response = await studioApiFetch(url, { signal });
|
|
15910
15946
|
if (!response.ok) throw new Error(`Waveform request failed (${response.status})`);
|
|
15911
15947
|
const data = await response.json();
|
|
15912
15948
|
if (typeof data !== "object" || data === null || !("peaks" in data) || !Array.isArray(data.peaks) || !data.peaks.every((peak) => typeof peak === "number")) {
|
|
@@ -15915,7 +15951,7 @@ async function fetchWaveformPeaks(url, signal) {
|
|
|
15915
15951
|
return data.peaks;
|
|
15916
15952
|
}
|
|
15917
15953
|
async function decodeWaveformPeaks(url, signal) {
|
|
15918
|
-
const response = await
|
|
15954
|
+
const response = await studioApiFetch(url, { signal });
|
|
15919
15955
|
if (!response.ok) throw new Error(`Audio request failed (${response.status})`);
|
|
15920
15956
|
const buffer = await response.arrayBuffer();
|
|
15921
15957
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
@@ -16722,7 +16758,9 @@ function serializeStudioFileMutations(writer, targetPaths, task) {
|
|
|
16722
16758
|
|
|
16723
16759
|
// src/utils/studioFileHistory.ts
|
|
16724
16760
|
async function readProjectFileContent(pid, path) {
|
|
16725
|
-
const response = await
|
|
16761
|
+
const response = await studioApiFetch(
|
|
16762
|
+
buildProjectApiPath(pid, `/files/${encodeURIComponent(path)}`)
|
|
16763
|
+
);
|
|
16726
16764
|
if (!response.ok) {
|
|
16727
16765
|
throw await createStudioSaveHttpError(response, `Failed to read ${path}`);
|
|
16728
16766
|
}
|
|
@@ -16929,8 +16967,8 @@ function addTweenTargets(tween, targets) {
|
|
|
16929
16967
|
targets.set(el, seen);
|
|
16930
16968
|
}
|
|
16931
16969
|
}
|
|
16932
|
-
function collectResetTargets(win, doc, targetKeys
|
|
16933
|
-
const targets =
|
|
16970
|
+
function collectResetTargets(win, doc, targetKeys) {
|
|
16971
|
+
const targets = /* @__PURE__ */ new Map();
|
|
16934
16972
|
const timelines = win.__timelines ?? {};
|
|
16935
16973
|
const others = new Set(
|
|
16936
16974
|
Object.entries(timelines).flatMap(([key2, tl]) => targetKeys.includes(key2) ? [] : [tl])
|
|
@@ -17090,7 +17128,7 @@ function timelineKeys(scriptText) {
|
|
|
17090
17128
|
return [...scriptText.matchAll(/__timelines\s*\[\s*["'`]([^"'`]+)["'`]\s*\]/g)].map((m) => m[1]).filter((key2) => key2 !== "__proxied");
|
|
17091
17129
|
}
|
|
17092
17130
|
function applySoftReload(iframe, scriptText, options = {}) {
|
|
17093
|
-
const { onAsyncFailure, currentTimeOverride, authoredHtml
|
|
17131
|
+
const { onAsyncFailure, currentTimeOverride, authoredHtml } = options;
|
|
17094
17132
|
if (!iframe || !scriptText) return "cannot-soft-reload";
|
|
17095
17133
|
const win = iframe.contentWindow;
|
|
17096
17134
|
const doc = iframe.contentDocument;
|
|
@@ -17120,7 +17158,7 @@ function applySoftReload(iframe, scriptText, options = {}) {
|
|
|
17120
17158
|
const readAuthoredOpacity = (el) => findAuthoredStyle(el)?.opacity ?? readStampedAuthoredOpacity(el);
|
|
17121
17159
|
const doReload = () => {
|
|
17122
17160
|
const timelines = win.__timelines;
|
|
17123
|
-
const targets = collectResetTargets(win, doc, targetKeys
|
|
17161
|
+
const targets = collectResetTargets(win, doc, targetKeys);
|
|
17124
17162
|
if (timelines) {
|
|
17125
17163
|
for (const key2 of targetKeys) {
|
|
17126
17164
|
const tl = timelines[key2];
|
|
@@ -17289,7 +17327,7 @@ var GsapPreviewConvergenceError = class extends Error {
|
|
|
17289
17327
|
var GsapOwnershipProtocolError = class extends GsapPreviewConvergenceError {
|
|
17290
17328
|
};
|
|
17291
17329
|
async function requireGsapOwnershipProtocol(projectId) {
|
|
17292
|
-
const response = await
|
|
17330
|
+
const response = await studioApiFetch(
|
|
17293
17331
|
`/api/projects/${encodeURIComponent(projectId)}/gsap-mutation-capabilities`
|
|
17294
17332
|
);
|
|
17295
17333
|
if (!response.ok) {
|
|
@@ -17300,18 +17338,18 @@ async function requireGsapOwnershipProtocol(projectId) {
|
|
|
17300
17338
|
throw new GsapOwnershipProtocolError("Invalid GSAP mutation capability response");
|
|
17301
17339
|
}
|
|
17302
17340
|
}
|
|
17303
|
-
async function rollbackOwnedMutation(projectId, targetPath, expected,
|
|
17341
|
+
async function rollbackOwnedMutation(projectId, targetPath, expected, restore2) {
|
|
17304
17342
|
if (targetPath.includes("\0") || targetPath.includes("..")) {
|
|
17305
17343
|
throw new Error(`Unsafe path: ${targetPath}`);
|
|
17306
17344
|
}
|
|
17307
|
-
const response = await
|
|
17345
|
+
const response = await studioApiFetch(
|
|
17308
17346
|
`/api/projects/${encodeURIComponent(projectId)}/gsap-mutation-rollback/${encodeURIComponent(targetPath)}`,
|
|
17309
17347
|
{
|
|
17310
17348
|
method: "POST",
|
|
17311
17349
|
// Deliberately unclaimed: a rollback runs because a mutation did not
|
|
17312
17350
|
// converge, so let the restored file reload the preview.
|
|
17313
17351
|
headers: { "Content-Type": "application/json" },
|
|
17314
|
-
body: JSON.stringify({ expected, restore })
|
|
17352
|
+
body: JSON.stringify({ expected, restore: restore2 })
|
|
17315
17353
|
}
|
|
17316
17354
|
);
|
|
17317
17355
|
if (!response.ok) {
|
|
@@ -17343,7 +17381,7 @@ function readMutationError(value, fallback) {
|
|
|
17343
17381
|
async function postGsapMutation(projectId, filePath, mutation, fallback) {
|
|
17344
17382
|
let response;
|
|
17345
17383
|
try {
|
|
17346
|
-
response = await
|
|
17384
|
+
response = await studioApiFetch(
|
|
17347
17385
|
`/api/projects/${encodeURIComponent(projectId)}/gsap-mutations/${encodeURIComponent(filePath)}`,
|
|
17348
17386
|
{
|
|
17349
17387
|
method: "POST",
|
|
@@ -17370,7 +17408,7 @@ async function readFileContent(projectId, targetPath) {
|
|
|
17370
17408
|
if (targetPath.includes("\0") || targetPath.includes("..")) {
|
|
17371
17409
|
throw new Error(`Unsafe path: ${targetPath}`);
|
|
17372
17410
|
}
|
|
17373
|
-
const response = await
|
|
17411
|
+
const response = await studioApiFetch(
|
|
17374
17412
|
`/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(targetPath)}`
|
|
17375
17413
|
);
|
|
17376
17414
|
if (!response.ok) {
|
|
@@ -20480,6 +20518,10 @@ function normalizeDomEditStyleValue(property, value) {
|
|
|
20480
20518
|
function isImageBackgroundValue(value) {
|
|
20481
20519
|
return /^url\(/i.test(value.trim());
|
|
20482
20520
|
}
|
|
20521
|
+
function cssPropertyName(property) {
|
|
20522
|
+
if (property.startsWith("--")) return property;
|
|
20523
|
+
return property.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`).replace(/^ms-/, "-ms-");
|
|
20524
|
+
}
|
|
20483
20525
|
function isManualGeometryStyleProperty(property) {
|
|
20484
20526
|
return property === "left" || property === "top" || property === "width" || property === "height";
|
|
20485
20527
|
}
|
|
@@ -20626,7 +20668,7 @@ function isPlainRecord(value) {
|
|
|
20626
20668
|
}
|
|
20627
20669
|
async function resolveAssetHasAudio(projectId, assetPath) {
|
|
20628
20670
|
try {
|
|
20629
|
-
const response = await
|
|
20671
|
+
const response = await studioApiFetch(mediaMetadataUrl(projectId, assetPath));
|
|
20630
20672
|
if (!response.ok) return null;
|
|
20631
20673
|
const data = await response.json();
|
|
20632
20674
|
const metadata = isPlainRecord(data) ? data.metadata : void 0;
|
|
@@ -22356,7 +22398,7 @@ function TimelineTrackRow({
|
|
|
22356
22398
|
),
|
|
22357
22399
|
propertyRows.map((row) => {
|
|
22358
22400
|
const group = row.propertyGroup;
|
|
22359
|
-
const
|
|
22401
|
+
const keyframeCount2 = row.items.filter((item) => item.kind === "keyframe").length;
|
|
22360
22402
|
const easeCount = row.items.filter((item) => item.kind === "ease").length;
|
|
22361
22403
|
return (
|
|
22362
22404
|
// ponytail: aria-owns maps this hidden logical row onto the two visible
|
|
@@ -22387,7 +22429,7 @@ function TimelineTrackRow({
|
|
|
22387
22429
|
"aria-colindex": 2,
|
|
22388
22430
|
"aria-owns": timelineLogicalRowCellId(lanesId, row.id, "content"),
|
|
22389
22431
|
children: [
|
|
22390
|
-
|
|
22432
|
+
keyframeCount2,
|
|
22391
22433
|
" keyframes, ",
|
|
22392
22434
|
easeCount,
|
|
22393
22435
|
" ease controls"
|
|
@@ -24125,7 +24167,7 @@ var peakMapRequests = /* @__PURE__ */ new Map();
|
|
|
24125
24167
|
function loadPeakMap(url) {
|
|
24126
24168
|
const pending2 = peakMapRequests.get(url);
|
|
24127
24169
|
if (pending2) return pending2;
|
|
24128
|
-
const request =
|
|
24170
|
+
const request = studioApiFetch(url).then((res) => res.ok ? res.json() : null).then((body) => isPeakMap(body) ? body : null).catch(() => null);
|
|
24129
24171
|
peakMapRequests.set(url, request);
|
|
24130
24172
|
return request;
|
|
24131
24173
|
}
|
|
@@ -24200,7 +24242,7 @@ function isNormalizePlan(value) {
|
|
|
24200
24242
|
(key2) => typeof Reflect.get(value, key2) === "number"
|
|
24201
24243
|
);
|
|
24202
24244
|
}
|
|
24203
|
-
async function requestNormalizePlan(projectId, el, fetchImpl =
|
|
24245
|
+
async function requestNormalizePlan(projectId, el, fetchImpl = studioApiFetch) {
|
|
24204
24246
|
const origin2 = window.location.origin;
|
|
24205
24247
|
const relative = resolvePreviewRelative(
|
|
24206
24248
|
resolveMediaPreviewUrl(el.src ?? "", projectId, origin2),
|
|
@@ -25257,7 +25299,7 @@ async function measureCarve(doc, voices, strength, bed) {
|
|
|
25257
25299
|
const Ctor = window.OfflineAudioContext ?? window.webkitOfflineAudioContext;
|
|
25258
25300
|
if (!Ctor) return null;
|
|
25259
25301
|
const decode = async (relative, clock) => {
|
|
25260
|
-
const res = await
|
|
25302
|
+
const res = await studioApiFetch(new URL(relative, doc.baseURI).href);
|
|
25261
25303
|
const buffer = await new Ctor(1, 1, DECODE_SAMPLE_RATE).decodeAudioData(
|
|
25262
25304
|
await res.arrayBuffer()
|
|
25263
25305
|
);
|
|
@@ -27147,7 +27189,7 @@ function compositionThumbnailRequest(url, projectId, { sessionEpoch = 0, priorit
|
|
|
27147
27189
|
};
|
|
27148
27190
|
}
|
|
27149
27191
|
async function loadCompositionImage(url, signal) {
|
|
27150
|
-
const response = await
|
|
27192
|
+
const response = await studioApiFetch(url, { signal });
|
|
27151
27193
|
if (!response.ok) throw new Error(`Composition thumbnail failed (${response.status})`);
|
|
27152
27194
|
const blob = await response.blob();
|
|
27153
27195
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
@@ -29921,7 +29963,7 @@ function sceneSwapFor(iframe) {
|
|
|
29921
29963
|
);
|
|
29922
29964
|
cancel?.addEventListener("abort", () => deadline.abort(cancel.reason), { once: true });
|
|
29923
29965
|
const swapping = (async () => {
|
|
29924
|
-
const response = await
|
|
29966
|
+
const response = await studioApiFetch(url, { signal: deadline.signal });
|
|
29925
29967
|
if (!response.ok) throw new Error(`preview request failed with ${response.status}`);
|
|
29926
29968
|
const html2 = await response.text();
|
|
29927
29969
|
if (!isCurrent()) throw new Error("superseded by a newer reload");
|
|
@@ -31048,7 +31090,9 @@ function useTimelinePlayer({
|
|
|
31048
31090
|
const slot = previewGeneration();
|
|
31049
31091
|
const isCurrent = () => gen === refreshGenRef.current && slot === previewGeneration();
|
|
31050
31092
|
const swap = sceneSwapFor(iframe);
|
|
31051
|
-
|
|
31093
|
+
const swapWouldReplaceGestureNode = !!iframe.contentDocument && isStudioManualEditGestureLiveIn(iframe.contentDocument);
|
|
31094
|
+
if (!swap || isRefreshingRef.current || swapWouldReplaceGestureNode)
|
|
31095
|
+
return reloadWholeFilm(url.toString());
|
|
31052
31096
|
swap(url.toString(), isCurrent, cancel.signal).catch((error) => {
|
|
31053
31097
|
if (!isCurrent()) return;
|
|
31054
31098
|
logReload("scene-swap-refused", { reason: String(error) });
|
|
@@ -31363,7 +31407,7 @@ function NLEProvider({
|
|
|
31363
31407
|
setCompIdToSrc(emptyMap);
|
|
31364
31408
|
setCompositionSourceMap(emptyMap);
|
|
31365
31409
|
onCompIdToSrcChangeRef.current?.(emptyMap);
|
|
31366
|
-
|
|
31410
|
+
studioApiFetch(buildProjectApiPath(projectId, `/files/index.html`), {
|
|
31367
31411
|
signal: controller.signal
|
|
31368
31412
|
}).then((r) => {
|
|
31369
31413
|
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
@@ -31899,7 +31943,7 @@ function renderPosterForNextOpen(projectId) {
|
|
|
31899
31943
|
priority: "overscan",
|
|
31900
31944
|
discardWhenReleased: true,
|
|
31901
31945
|
load: async (signal) => {
|
|
31902
|
-
await (await
|
|
31946
|
+
await (await studioApiFetch(url, { signal })).arrayBuffer();
|
|
31903
31947
|
return { value: { kind: "image", url, aspect: 16 / 9 }, weight: 0 };
|
|
31904
31948
|
}
|
|
31905
31949
|
};
|
|
@@ -35897,7 +35941,7 @@ function OffCanvasIndicators({
|
|
|
35897
35941
|
const selectOffCanvas = async () => {
|
|
35898
35942
|
const el = elements.current.get(r.key);
|
|
35899
35943
|
if (!el) return;
|
|
35900
|
-
const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-
|
|
35944
|
+
const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-OL7GLSS4.js");
|
|
35901
35945
|
const acp = activeCompositionPathRef.current ?? "index.html";
|
|
35902
35946
|
const sel = await resolveDomEditSelection2(el, {
|
|
35903
35947
|
activeCompositionPath: acp,
|
|
@@ -36563,6 +36607,13 @@ function computeDraggedGsapPosition(element, studioOffset, fallbackBase) {
|
|
|
36563
36607
|
baseGsapY
|
|
36564
36608
|
};
|
|
36565
36609
|
}
|
|
36610
|
+
function restoreDragOffset(element) {
|
|
36611
|
+
const origin2 = (axis) => Number.parseFloat(element.getAttribute(`data-hf-drag-initial-offset-${axis}`) ?? "") || 0;
|
|
36612
|
+
element.style.setProperty("--hf-studio-offset-x", `${origin2("x")}px`);
|
|
36613
|
+
element.style.setProperty("--hf-studio-offset-y", `${origin2("y")}px`);
|
|
36614
|
+
element.removeAttribute("data-hf-drag-initial-offset-x");
|
|
36615
|
+
element.removeAttribute("data-hf-drag-initial-offset-y");
|
|
36616
|
+
}
|
|
36566
36617
|
|
|
36567
36618
|
// src/components/editor/plainTranslate.ts
|
|
36568
36619
|
var TOKEN = /\s*(?:(\d*\.?\d+(?:e[-+]?\d+)?)(px|%)?|([a-z]+)\(|([-+*/(),]))/giy;
|
|
@@ -36723,11 +36774,11 @@ function getRectCenter(element) {
|
|
|
36723
36774
|
if (!finiteRect(rect) || rect.width <= 0 && rect.height <= 0) {
|
|
36724
36775
|
return null;
|
|
36725
36776
|
}
|
|
36726
|
-
|
|
36727
|
-
|
|
36728
|
-
|
|
36729
|
-
|
|
36730
|
-
let win =
|
|
36777
|
+
const point = { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
|
|
36778
|
+
return toTopScreenPoint(element.ownerDocument, point);
|
|
36779
|
+
}
|
|
36780
|
+
function toTopScreenPoint(doc, point) {
|
|
36781
|
+
let win = doc.defaultView;
|
|
36731
36782
|
while (win) {
|
|
36732
36783
|
const frameElement = getFrameElement(win);
|
|
36733
36784
|
if (!frameElement) break;
|
|
@@ -38427,14 +38478,14 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
38427
38478
|
hasMember: !!member,
|
|
38428
38479
|
inlineStyle: sel.element.getAttribute("style")
|
|
38429
38480
|
});
|
|
38430
|
-
const
|
|
38481
|
+
const restore2 = () => {
|
|
38431
38482
|
if (!g.manualEditDragToken || !isStudioManualEditGestureCurrent(sel.element, g.manualEditDragToken))
|
|
38432
38483
|
return;
|
|
38433
38484
|
restoreStudioBoxSize(sel.element, g.initialBoxSize);
|
|
38434
38485
|
if (finalOffset) restoreStudioPathOffset(sel.element, g.initialPathOffset);
|
|
38435
38486
|
};
|
|
38436
38487
|
void Promise.resolve(
|
|
38437
|
-
opts.onBoxSizeCommitRef.current(sel, finalSize, finalOffset ?? void 0,
|
|
38488
|
+
opts.onBoxSizeCommitRef.current(sel, finalSize, finalOffset ?? void 0, restore2)
|
|
38438
38489
|
).then((result) => trackPreviewEditResult("resize", "drag", result)).catch((error) => {
|
|
38439
38490
|
logGestureCommitFailure("resize commit failed", error);
|
|
38440
38491
|
}).finally(() => {
|
|
@@ -41580,77 +41631,6 @@ function isDomEditPersistOutcome(value) {
|
|
|
41580
41631
|
return typeof Reflect.get(value, "sourceFile") === "string" && typeof Reflect.get(value, "version") === "string" && typeof Reflect.get(value, "changed") === "boolean";
|
|
41581
41632
|
}
|
|
41582
41633
|
|
|
41583
|
-
// src/components/editor/manualEditingAvailability.ts
|
|
41584
|
-
var manualEditingAvailability_exports = {};
|
|
41585
|
-
__export(manualEditingAvailability_exports, {
|
|
41586
|
-
STUDIO_FLAT_INSPECTOR_ENABLED: () => STUDIO_FLAT_INSPECTOR_ENABLED,
|
|
41587
|
-
STUDIO_SDK_CUTOVER_ENABLED: () => STUDIO_SDK_CUTOVER_ENABLED,
|
|
41588
|
-
STUDIO_SDK_CUTOVER_FAMILIES: () => STUDIO_SDK_CUTOVER_FAMILIES,
|
|
41589
|
-
STUDIO_SDK_RESOLVER_SHADOW_ENABLED: () => STUDIO_SDK_RESOLVER_SHADOW_ENABLED,
|
|
41590
|
-
resolveStudioBooleanEnvFlag: () => resolveStudioBooleanEnvFlag
|
|
41591
|
-
});
|
|
41592
|
-
|
|
41593
|
-
// src/utils/sdkCutoverPolicy.ts
|
|
41594
|
-
var STUDIO_SDK_OPERATION_FAMILIES = [
|
|
41595
|
-
"dom",
|
|
41596
|
-
"timing",
|
|
41597
|
-
"gsap-animation",
|
|
41598
|
-
"gsap-keyframe",
|
|
41599
|
-
"lifecycle"
|
|
41600
|
-
];
|
|
41601
|
-
function resolveEnabledSdkFamilies(env2, masterEnabled) {
|
|
41602
|
-
if (!masterEnabled) return /* @__PURE__ */ new Set();
|
|
41603
|
-
const raw = env2["VITE_STUDIO_SDK_CUTOVER_FAMILIES"];
|
|
41604
|
-
if (typeof raw !== "string" || raw.trim() === "") return new Set(STUDIO_SDK_OPERATION_FAMILIES);
|
|
41605
|
-
const requested = raw.split(",").map((family) => family.trim()).filter(Boolean);
|
|
41606
|
-
const known = new Set(STUDIO_SDK_OPERATION_FAMILIES);
|
|
41607
|
-
const unknown = requested.filter((family) => !known.has(family));
|
|
41608
|
-
if (unknown.length > 0) {
|
|
41609
|
-
throw new Error(`Unknown Studio SDK cutover families: ${unknown.join(", ")}`);
|
|
41610
|
-
}
|
|
41611
|
-
return new Set(requested);
|
|
41612
|
-
}
|
|
41613
|
-
function isSdkFamilyEnabled(masterEnabled, configured, family) {
|
|
41614
|
-
return masterEnabled && (configured?.has(family) ?? true);
|
|
41615
|
-
}
|
|
41616
|
-
|
|
41617
|
-
// src/components/editor/manualEditingAvailability.ts
|
|
41618
|
-
var TRUTHY_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on", "enabled"]);
|
|
41619
|
-
var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off", "disabled"]);
|
|
41620
|
-
function resolveStudioBooleanEnvFlag(env2, names, fallback) {
|
|
41621
|
-
for (const name of names) {
|
|
41622
|
-
const value = env2[name];
|
|
41623
|
-
if (typeof value === "boolean") return value;
|
|
41624
|
-
if (typeof value !== "string") continue;
|
|
41625
|
-
const normalized = value.trim().toLowerCase();
|
|
41626
|
-
if (!normalized) continue;
|
|
41627
|
-
if (TRUTHY_ENV_VALUES.has(normalized)) return true;
|
|
41628
|
-
if (FALSY_ENV_VALUES.has(normalized)) return false;
|
|
41629
|
-
}
|
|
41630
|
-
return fallback;
|
|
41631
|
-
}
|
|
41632
|
-
var runtimeEnv = typeof window !== "undefined" ? window.__HF_STUDIO_ENV__ ?? {} : {};
|
|
41633
|
-
var env = { ...import.meta.env ?? {}, ...runtimeEnv };
|
|
41634
|
-
var STUDIO_SDK_CUTOVER_ENABLED = resolveStudioBooleanEnvFlag(
|
|
41635
|
-
env,
|
|
41636
|
-
["VITE_STUDIO_SDK_CUTOVER_ENABLED"],
|
|
41637
|
-
true
|
|
41638
|
-
);
|
|
41639
|
-
var STUDIO_SDK_CUTOVER_FAMILIES = resolveEnabledSdkFamilies(
|
|
41640
|
-
env,
|
|
41641
|
-
STUDIO_SDK_CUTOVER_ENABLED
|
|
41642
|
-
);
|
|
41643
|
-
var STUDIO_SDK_RESOLVER_SHADOW_ENABLED = resolveStudioBooleanEnvFlag(
|
|
41644
|
-
env,
|
|
41645
|
-
["VITE_STUDIO_SDK_RESOLVER_SHADOW_ENABLED"],
|
|
41646
|
-
true
|
|
41647
|
-
);
|
|
41648
|
-
var STUDIO_FLAT_INSPECTOR_ENABLED = resolveStudioBooleanEnvFlag(
|
|
41649
|
-
env,
|
|
41650
|
-
["VITE_STUDIO_ENABLE_FLAT_INSPECTOR", "VITE_STUDIO_FLAT_INSPECTOR_ENABLED"],
|
|
41651
|
-
true
|
|
41652
|
-
);
|
|
41653
|
-
|
|
41654
41634
|
// src/utils/sdkOpMapping.ts
|
|
41655
41635
|
function patchOpsToSdkEditOps(hfId, ops) {
|
|
41656
41636
|
const result = [];
|
|
@@ -42772,7 +42752,7 @@ function useElementLifecycleOps({
|
|
|
42772
42752
|
writeFile: writeProjectFile,
|
|
42773
42753
|
recordEdit: editHistory.recordEdit,
|
|
42774
42754
|
rewrite: async (originalContent) => {
|
|
42775
|
-
const removeResponse = await
|
|
42755
|
+
const removeResponse = await studioApiFetch(
|
|
42776
42756
|
buildProjectApiPath(
|
|
42777
42757
|
pid,
|
|
42778
42758
|
`/file-mutations/remove-elements/${encodeURIComponent(targetPath)}`
|
|
@@ -44716,7 +44696,9 @@ import { editabilityForProvenance } from "@hyperframes/core/gsap-parser";
|
|
|
44716
44696
|
var GSAP_EDIT_BLOCK_COPY = {
|
|
44717
44697
|
"no-selector": "This layer needs a stable selector before Studio can save the edit.",
|
|
44718
44698
|
"unroll-required": "This motion comes from a helper or loop. Choose Unroll to edit it explicitly.",
|
|
44719
|
-
"source-uneditable": "This animation is computed at runtime. Edit the animation in the Code tab."
|
|
44699
|
+
"source-uneditable": "This animation is computed at runtime. Edit the animation in the Code tab.",
|
|
44700
|
+
"keyframes-uneditable": "Studio can't add this edit to the animation's keyframes. Edit this animation in the Code tab.",
|
|
44701
|
+
"mixed-files": "These layers are animated in different files. Move each file's layers separately."
|
|
44720
44702
|
};
|
|
44721
44703
|
var GsapEditBlockedError = class extends Error {
|
|
44722
44704
|
constructor(reason, detail) {
|
|
@@ -44943,62 +44925,6 @@ async function commitStaticGsapSize(selection, size, selector, existingSet, call
|
|
|
44943
44925
|
{ label: "Resize layer", softReload: true }
|
|
44944
44926
|
);
|
|
44945
44927
|
}
|
|
44946
|
-
function positiveOr(n, fallback) {
|
|
44947
|
-
return Number.isFinite(n) && n > 0 ? roundToLayoutPx(n) : fallback;
|
|
44948
|
-
}
|
|
44949
|
-
function resolvePriorSize(sizeSet, el, fallbackW, fallbackH) {
|
|
44950
|
-
if (sizeSet) {
|
|
44951
|
-
return {
|
|
44952
|
-
width: positiveOr(Number(sizeSet.properties.width), fallbackW),
|
|
44953
|
-
height: positiveOr(Number(sizeSet.properties.height), fallbackH)
|
|
44954
|
-
};
|
|
44955
|
-
}
|
|
44956
|
-
const ow = Number.parseFloat(el?.getAttribute(STUDIO_ORIGINAL_WIDTH_ATTR) ?? "");
|
|
44957
|
-
const oh = Number.parseFloat(el?.getAttribute(STUDIO_ORIGINAL_HEIGHT_ATTR) ?? "");
|
|
44958
|
-
return { width: positiveOr(ow, fallbackW), height: positiveOr(oh, fallbackH) };
|
|
44959
|
-
}
|
|
44960
|
-
async function commitKeyframedSizeFromResize(selection, size, selector, sizeSet, animatedTween, callbacks) {
|
|
44961
|
-
const ts = resolveTweenStart(animatedTween) ?? 0;
|
|
44962
|
-
const td = resolveTweenDuration(animatedTween);
|
|
44963
|
-
if (!(td > 0)) return false;
|
|
44964
|
-
const newW = roundToLayoutPx(size.width);
|
|
44965
|
-
const newH = roundToLayoutPx(size.height);
|
|
44966
|
-
const prior = resolvePriorSize(sizeSet, selection.element, newW, newH);
|
|
44967
|
-
const ct = usePlayerStore.getState().currentTime;
|
|
44968
|
-
const pct = Math.max(0, Math.min(100, Math.round((ct - ts) / td * 1e3) / 10));
|
|
44969
|
-
const pcts = new Set(
|
|
44970
|
-
animatedTween.keyframes?.keyframes.map((k) => k.percentage) ?? [0, 100]
|
|
44971
|
-
);
|
|
44972
|
-
pcts.add(0);
|
|
44973
|
-
pcts.add(100);
|
|
44974
|
-
pcts.add(pct);
|
|
44975
|
-
const keyframes = Array.from(pcts).sort((a, b) => a - b).map((p) => ({
|
|
44976
|
-
percentage: p,
|
|
44977
|
-
properties: Math.abs(p - pct) < 0.05 ? { width: newW, height: newH } : { ...prior }
|
|
44978
|
-
}));
|
|
44979
|
-
const addLabel = `Resize (size keyframe ${pct.toFixed(0)}%)`;
|
|
44980
|
-
const target = newTweenTarget(selection);
|
|
44981
|
-
if (!target) return false;
|
|
44982
|
-
await callbacks.commitMutation(
|
|
44983
|
-
selection,
|
|
44984
|
-
{
|
|
44985
|
-
type: "add-with-keyframes",
|
|
44986
|
-
targetSelector: target,
|
|
44987
|
-
position: roundTo3(ts),
|
|
44988
|
-
duration: roundTo3(td),
|
|
44989
|
-
keyframes
|
|
44990
|
-
},
|
|
44991
|
-
sizeSet ? { label: addLabel, skipReload: true } : { label: addLabel, softReload: true }
|
|
44992
|
-
);
|
|
44993
|
-
if (sizeSet) {
|
|
44994
|
-
await callbacks.commitMutation(
|
|
44995
|
-
selection,
|
|
44996
|
-
{ type: "delete", animationId: sizeSet.id },
|
|
44997
|
-
{ label: "Resize layer", softReload: true }
|
|
44998
|
-
);
|
|
44999
|
-
}
|
|
45000
|
-
return true;
|
|
45001
|
-
}
|
|
45002
44928
|
async function commitWholePathOffset(selection, anim, studioOffset, gsapPos, iframe, selector, callbacks) {
|
|
45003
44929
|
const el = selection.element;
|
|
45004
44930
|
const { newX, newY, baseGsapX, baseGsapY } = computeDraggedGsapPosition(
|
|
@@ -45023,7 +44949,6 @@ async function commitWholePathOffset(selection, anim, studioOffset, gsapPos, ifr
|
|
|
45023
44949
|
}
|
|
45024
44950
|
const ts = resolveTweenStart(effectiveAnim);
|
|
45025
44951
|
const td = resolveTweenDuration(effectiveAnim);
|
|
45026
|
-
const ease = effectiveAnim.keyframes?.easeEach ?? effectiveAnim.ease;
|
|
45027
44952
|
let kfs = effectiveAnim.keyframes?.keyframes ?? [];
|
|
45028
44953
|
if (kfs.length === 0) {
|
|
45029
44954
|
const fromProps = effectiveAnim.fromProperties ?? {};
|
|
@@ -45055,7 +44980,7 @@ async function commitWholePathOffset(selection, anim, studioOffset, gsapPos, ifr
|
|
|
45055
44980
|
position: roundTo3(ts ?? 0),
|
|
45056
44981
|
duration: roundTo3(td || 1),
|
|
45057
44982
|
keyframes: shifted,
|
|
45058
|
-
|
|
44983
|
+
...keyframeEases(effectiveAnim)
|
|
45059
44984
|
},
|
|
45060
44985
|
{ label: "Move animation path", softReload: true, beforeReload: restoreOffset }
|
|
45061
44986
|
);
|
|
@@ -45070,7 +44995,6 @@ async function commitWholePropertyOffset(selection, anim, newValues, currentPct,
|
|
|
45070
44995
|
}
|
|
45071
44996
|
const ts = resolveTweenStart(effectiveAnim);
|
|
45072
44997
|
const td = resolveTweenDuration(effectiveAnim);
|
|
45073
|
-
const ease = effectiveAnim.keyframes?.easeEach ?? effectiveAnim.ease;
|
|
45074
44998
|
const keys = Object.keys(newValues);
|
|
45075
44999
|
const at = (props, key2) => typeof props[key2] === "number" ? props[key2] : PROPERTY_DEFAULTS[key2] ?? 0;
|
|
45076
45000
|
const kfs = effectiveAnim.keyframes?.keyframes ?? synthesizeFlatTweenKeyframes(effectiveAnim)?.keyframes;
|
|
@@ -45103,7 +45027,7 @@ async function commitWholePropertyOffset(selection, anim, newValues, currentPct,
|
|
|
45103
45027
|
position: roundTo3(ts ?? 0),
|
|
45104
45028
|
duration: roundTo3(td || 1),
|
|
45105
45029
|
keyframes: shifted,
|
|
45106
|
-
|
|
45030
|
+
...keyframeEases(effectiveAnim)
|
|
45107
45031
|
},
|
|
45108
45032
|
{ label, softReload: true }
|
|
45109
45033
|
);
|
|
@@ -46261,7 +46185,7 @@ import { useCallback as useCallback68, useMemo as useMemo45 } from "react";
|
|
|
46261
46185
|
import { useEffect as useEffect62, useMemo as useMemo44, useRef as useRef78, useState as useState55, useCallback as useCallback67 } from "react";
|
|
46262
46186
|
|
|
46263
46187
|
// src/hooks/gsapRuntimeBridge.ts
|
|
46264
|
-
import { isXYPositionWrite } from "@hyperframes/parsers/gsap-constants";
|
|
46188
|
+
import { isXYPositionWrite, PROPERTY_GROUPS } from "@hyperframes/parsers/gsap-constants";
|
|
46265
46189
|
|
|
46266
46190
|
// src/hooks/gsapRuntimeReaders.ts
|
|
46267
46191
|
import { classifyPropertyGroup as classifyPropertyGroup3 } from "@hyperframes/core/gsap-parser";
|
|
@@ -46367,183 +46291,404 @@ function readAllAnimatedProperties(iframe, selector, anim, group) {
|
|
|
46367
46291
|
return result;
|
|
46368
46292
|
}
|
|
46369
46293
|
|
|
46370
|
-
// src/
|
|
46371
|
-
|
|
46372
|
-
|
|
46373
|
-
return [
|
|
46374
|
-
...(anim.keyframes?.keyframes ?? []).filter((keyframe) => Math.abs(keyframe.percentage - percentage) > KEYFRAME_PCT_MATCH).map((keyframe) => ({
|
|
46375
|
-
percentage: keyframe.percentage,
|
|
46376
|
-
properties: { ...keyframe.properties },
|
|
46377
|
-
...keyframe.ease ? { ease: keyframe.ease } : {}
|
|
46378
|
-
})),
|
|
46379
|
-
{ percentage, properties }
|
|
46380
|
-
].sort((a, b) => a.percentage - b.percentage);
|
|
46294
|
+
// src/utils/elementGsap.ts
|
|
46295
|
+
function gsapOf(element) {
|
|
46296
|
+
return element.ownerDocument.defaultView?.gsap;
|
|
46381
46297
|
}
|
|
46382
|
-
|
|
46383
|
-
const
|
|
46384
|
-
|
|
46385
|
-
|
|
46386
|
-
|
|
46387
|
-
const existingKfs = anim.keyframes?.keyframes ?? [];
|
|
46388
|
-
const remappedKfs = [];
|
|
46389
|
-
for (const kf of existingKfs) {
|
|
46390
|
-
const absTime = tweenStart + kf.percentage / 100 * tweenDuration;
|
|
46391
|
-
const newPct = Math.round((absTime - newStart) / newDuration * 1e3) / 10;
|
|
46392
|
-
const props = { ...kf.properties };
|
|
46393
|
-
for (const k of Object.keys(properties)) {
|
|
46394
|
-
if (!(k in props) && backfillDefaults?.[k] != null) props[k] = backfillDefaults[k];
|
|
46395
|
-
}
|
|
46396
|
-
remappedKfs.push({ percentage: newPct, properties: props });
|
|
46397
|
-
}
|
|
46398
|
-
const targetPct = Math.round((targetTime - newStart) / newDuration * 1e3) / 10;
|
|
46399
|
-
remappedKfs.push({ percentage: targetPct, properties });
|
|
46400
|
-
remappedKfs.sort((a, b) => a.percentage - b.percentage);
|
|
46401
|
-
await callbacks.commitMutation(
|
|
46402
|
-
selection,
|
|
46403
|
-
{
|
|
46404
|
-
type: "replace-with-keyframes",
|
|
46405
|
-
animationId: anim.id,
|
|
46406
|
-
targetSelector: anim.targetSelector,
|
|
46407
|
-
position: roundTo3(newStart),
|
|
46408
|
-
duration: roundTo3(newDuration),
|
|
46409
|
-
keyframes: remappedKfs
|
|
46410
|
-
},
|
|
46411
|
-
{
|
|
46412
|
-
label: `Move layer (extended keyframe)`,
|
|
46413
|
-
keyframeAction: "add",
|
|
46414
|
-
softReload: true,
|
|
46415
|
-
beforeReload
|
|
46416
|
-
}
|
|
46417
|
-
);
|
|
46298
|
+
function setElementGsapPosition(element, x, y) {
|
|
46299
|
+
const gsap3 = gsapOf(element);
|
|
46300
|
+
if (!gsap3?.set) return false;
|
|
46301
|
+
gsap3.set(element, { x, y });
|
|
46302
|
+
return true;
|
|
46418
46303
|
}
|
|
46419
|
-
|
|
46420
|
-
const
|
|
46421
|
-
|
|
46422
|
-
|
|
46423
|
-
|
|
46424
|
-
|
|
46425
|
-
|
|
46426
|
-
|
|
46427
|
-
|
|
46428
|
-
percentage: pct,
|
|
46429
|
-
properties,
|
|
46430
|
-
...backfillDefaults ? { backfillDefaults } : {}
|
|
46431
|
-
},
|
|
46432
|
-
{ label: `Move layer (keyframe ${pct}%)`, softReload: true, beforeReload }
|
|
46304
|
+
function setElementGsapScale(element, x, y) {
|
|
46305
|
+
const gsap3 = gsapOf(element);
|
|
46306
|
+
if (!gsap3?.set) return false;
|
|
46307
|
+
gsap3.set(element, { scaleX: x, scaleY: y });
|
|
46308
|
+
return true;
|
|
46309
|
+
}
|
|
46310
|
+
function elementTargets(tween) {
|
|
46311
|
+
return (tween.targets?.() ?? []).filter(
|
|
46312
|
+
(t2) => Boolean(t2?.style && t2.nodeType)
|
|
46433
46313
|
);
|
|
46434
|
-
|
|
46435
|
-
|
|
46436
|
-
|
|
46314
|
+
}
|
|
46315
|
+
|
|
46316
|
+
// src/hooks/gsapParsedTween.ts
|
|
46317
|
+
var PARSED_NAME = { scale: "scaleX", rotate: "rotation" };
|
|
46318
|
+
function findPropTween(pt, prop) {
|
|
46319
|
+
for (let node = pt; node; node = node._next) {
|
|
46320
|
+
if (node.p === prop && typeof node.s === "number" && typeof node.c === "number") return node;
|
|
46321
|
+
const nested = findPropTween(node.d?._pt, prop);
|
|
46322
|
+
if (nested) return nested;
|
|
46437
46323
|
}
|
|
46324
|
+
return null;
|
|
46438
46325
|
}
|
|
46439
|
-
function
|
|
46440
|
-
|
|
46441
|
-
|
|
46442
|
-
const
|
|
46443
|
-
|
|
46444
|
-
|
|
46326
|
+
function endsIn(tween, prop) {
|
|
46327
|
+
const pt = findPropTween(tween._pt, PARSED_NAME[prop] ?? prop);
|
|
46328
|
+
if (!pt) return null;
|
|
46329
|
+
const pair = [pt.s, pt.s + pt.c];
|
|
46330
|
+
return tween._from ? [pair[1], pair[0]] : pair;
|
|
46331
|
+
}
|
|
46332
|
+
function findParsedTween(iframe, element, anim) {
|
|
46333
|
+
const win = iframe?.contentWindow;
|
|
46334
|
+
const start = resolveTweenStart(anim);
|
|
46335
|
+
if (!win?.__timelines || start == null) return null;
|
|
46336
|
+
const steps = anim.keyframes?.keyframes.map((kf) => kf.properties) ?? [anim.properties];
|
|
46337
|
+
const props = [...new Set(steps.flatMap((step) => Object.keys(step)))];
|
|
46338
|
+
const keyframed = Boolean(anim.keyframes);
|
|
46339
|
+
for (const timeline of Object.values(win.__timelines)) {
|
|
46340
|
+
for (const tween of timeline?.getChildren?.(true) ?? []) {
|
|
46341
|
+
const targets = tween.targets?.() ?? [];
|
|
46342
|
+
if (!targets.includes(element) && !targets.some((t2) => element.id && t2.id === element.id))
|
|
46343
|
+
continue;
|
|
46344
|
+
if (!startsAt(tween, start)) continue;
|
|
46345
|
+
const vars = tween.vars ?? {};
|
|
46346
|
+
const carries = keyframed ? "keyframes" in vars : props.some((p) => p in vars);
|
|
46347
|
+
if (!carries || !((tween.duration?.() ?? 0) > 0)) continue;
|
|
46348
|
+
parseUnplayed(win, element, tween, props);
|
|
46349
|
+
return tween;
|
|
46350
|
+
}
|
|
46351
|
+
}
|
|
46352
|
+
return null;
|
|
46353
|
+
}
|
|
46354
|
+
function startsAt(tween, start) {
|
|
46355
|
+
const delay2 = Number(tween.vars?.delay) || 0;
|
|
46356
|
+
return Math.abs((tween.startTime?.() ?? Number.NaN) - delay2 - start) <= 1e-3;
|
|
46357
|
+
}
|
|
46358
|
+
function withLiveTiming(anim, tween) {
|
|
46359
|
+
const start = tween?.startTime?.();
|
|
46360
|
+
return {
|
|
46361
|
+
...anim,
|
|
46362
|
+
...Number.isFinite(start) && { resolvedStart: start },
|
|
46363
|
+
...anim.duration == null && tween && { duration: tween.duration?.() }
|
|
46364
|
+
};
|
|
46365
|
+
}
|
|
46366
|
+
function parseUnplayed(win, element, tween, props) {
|
|
46367
|
+
const seek = !isParsed(tween) && seekable(win, tween);
|
|
46368
|
+
if (!seek) return;
|
|
46369
|
+
const { parent, gsap: gsap3 } = seek;
|
|
46370
|
+
const before = layerStates(tween, element);
|
|
46371
|
+
const now2 = parent.time();
|
|
46372
|
+
const start = tween.startTime?.() ?? 0;
|
|
46373
|
+
gsap3.set(element, { clearProps: props.join(",") });
|
|
46374
|
+
for (const p of props) gsap3.getProperty(element, p);
|
|
46445
46375
|
try {
|
|
46446
|
-
|
|
46447
|
-
|
|
46448
|
-
|
|
46376
|
+
parent.seek(start, true);
|
|
46377
|
+
parent.seek(start + (tween.duration?.() ?? 0), true);
|
|
46378
|
+
} finally {
|
|
46379
|
+
parent.seek(now2, true);
|
|
46380
|
+
restore(before);
|
|
46449
46381
|
}
|
|
46450
|
-
|
|
46451
|
-
|
|
46452
|
-
const
|
|
46453
|
-
|
|
46382
|
+
}
|
|
46383
|
+
function isParsed(tween) {
|
|
46384
|
+
const parts = tween.timeline?.getChildren?.() ?? [];
|
|
46385
|
+
return Boolean(tween._initted) && parts.every((part) => part._initted);
|
|
46386
|
+
}
|
|
46387
|
+
function seekable(win, tween) {
|
|
46388
|
+
const { parent } = tween;
|
|
46389
|
+
const gsap3 = win.gsap;
|
|
46390
|
+
if (!parent?.seek || !parent.time || !gsap3?.getProperty || !gsap3.set) return null;
|
|
46454
46391
|
return {
|
|
46455
|
-
|
|
46456
|
-
|
|
46457
|
-
|
|
46458
|
-
|
|
46392
|
+
parent: { seek: parent.seek.bind(parent), time: parent.time.bind(parent) },
|
|
46393
|
+
gsap: { getProperty: gsap3.getProperty.bind(gsap3), set: gsap3.set.bind(gsap3) }
|
|
46394
|
+
};
|
|
46395
|
+
}
|
|
46396
|
+
function layerStates(tween, element) {
|
|
46397
|
+
const layers = /* @__PURE__ */ new Set([element]);
|
|
46398
|
+
for (const child of tween.parent?.getChildren?.(true, true, false) ?? [])
|
|
46399
|
+
for (const target of elementTargets(child)) layers.add(target);
|
|
46400
|
+
return [...layers].map((layer) => ({
|
|
46401
|
+
layer,
|
|
46402
|
+
attributes: new Map([...layer.attributes].map((a) => [a.name, a.value])),
|
|
46403
|
+
cache: layer._gsap && { ...layer._gsap }
|
|
46404
|
+
}));
|
|
46459
46405
|
}
|
|
46460
|
-
|
|
46461
|
-
const
|
|
46462
|
-
|
|
46463
|
-
|
|
46464
|
-
|
|
46465
|
-
|
|
46466
|
-
|
|
46467
|
-
const
|
|
46468
|
-
|
|
46469
|
-
|
|
46470
|
-
|
|
46471
|
-
|
|
46472
|
-
|
|
46473
|
-
|
|
46474
|
-
|
|
46475
|
-
|
|
46476
|
-
|
|
46477
|
-
|
|
46406
|
+
function restore(states) {
|
|
46407
|
+
for (const { layer, attributes, cache: cache2 } of states) {
|
|
46408
|
+
restoreAttributes(layer, attributes);
|
|
46409
|
+
if (cache2 && layer._gsap) restoreCache(layer._gsap, cache2);
|
|
46410
|
+
}
|
|
46411
|
+
}
|
|
46412
|
+
function restoreAttributes(layer, attributes) {
|
|
46413
|
+
for (const { name } of [...layer.attributes])
|
|
46414
|
+
if (!attributes.has(name)) layer.removeAttribute(name);
|
|
46415
|
+
for (const [name, value] of attributes)
|
|
46416
|
+
if (layer.getAttribute(name) !== value) layer.setAttribute(name, value);
|
|
46417
|
+
}
|
|
46418
|
+
function restoreCache(live, cache2) {
|
|
46419
|
+
for (const key2 of Object.keys(live)) if (!(key2 in cache2)) delete live[key2];
|
|
46420
|
+
Object.assign(live, cache2);
|
|
46421
|
+
}
|
|
46422
|
+
function parsedImplicitEndValue(tween) {
|
|
46423
|
+
return (prop, end) => {
|
|
46424
|
+
if (!tween) return null;
|
|
46425
|
+
for (const part of partsFrom(tween, end)) {
|
|
46426
|
+
const pair = endsIn(part, prop);
|
|
46427
|
+
if (pair) return end === "start" ? pair[0] : pair[1];
|
|
46428
|
+
if (prop in (part.vars ?? {})) return null;
|
|
46478
46429
|
}
|
|
46479
|
-
|
|
46480
|
-
|
|
46481
|
-
|
|
46482
|
-
|
|
46483
|
-
|
|
46484
|
-
|
|
46485
|
-
|
|
46486
|
-
|
|
46487
|
-
|
|
46488
|
-
|
|
46489
|
-
|
|
46490
|
-
|
|
46430
|
+
return null;
|
|
46431
|
+
};
|
|
46432
|
+
}
|
|
46433
|
+
function partsFrom(tween, end) {
|
|
46434
|
+
const parts = tween.timeline?.getChildren?.() ?? [];
|
|
46435
|
+
if (parts.length === 0) return [tween];
|
|
46436
|
+
return end === "start" ? parts : [...parts].reverse();
|
|
46437
|
+
}
|
|
46438
|
+
function parsedTweenEase(iframe, tween) {
|
|
46439
|
+
if (!tween) return null;
|
|
46440
|
+
const win = iframe?.contentWindow;
|
|
46441
|
+
const ease = tween.vars?.ease ?? tween.parent?.vars?.defaults?.ease ?? win?.gsap?.defaults?.().ease;
|
|
46442
|
+
if (typeof ease === "string") return ease;
|
|
46443
|
+
const named = (name) => win?.gsap?.parseEase?.(name) === ease;
|
|
46444
|
+
return typeof ease === "function" ? BUILT_IN_EASES.find(named) ?? null : null;
|
|
46445
|
+
}
|
|
46446
|
+
var BUILT_IN_EASES = [
|
|
46447
|
+
"none",
|
|
46448
|
+
...[
|
|
46449
|
+
"power1",
|
|
46450
|
+
"power2",
|
|
46451
|
+
"power3",
|
|
46452
|
+
"power4",
|
|
46453
|
+
"sine",
|
|
46454
|
+
"expo",
|
|
46455
|
+
"circ",
|
|
46456
|
+
"back",
|
|
46457
|
+
"elastic",
|
|
46458
|
+
"bounce"
|
|
46459
|
+
].flatMap((e) => [`${e}.in`, `${e}.out`, `${e}.inOut`])
|
|
46460
|
+
];
|
|
46461
|
+
function withExactStepTimes(anim, tween) {
|
|
46462
|
+
const data = anim.keyframes;
|
|
46463
|
+
const parts = tween?.timeline?.getChildren?.() ?? [];
|
|
46464
|
+
const total = tween?.duration?.() ?? 0;
|
|
46465
|
+
if (data?.format !== "object-array" || parts.length !== data.keyframes.length || !(total > 0))
|
|
46466
|
+
return anim;
|
|
46467
|
+
const ends = parts.map((part) => ((part.startTime?.() ?? 0) + (part.duration?.() ?? 0)) / total);
|
|
46468
|
+
if (ends.some((end) => !Number.isFinite(end))) return anim;
|
|
46469
|
+
const keyframes = data.keyframes.map((kf, i) => ({
|
|
46470
|
+
...kf,
|
|
46471
|
+
percentage: Math.round(ends[i] * 1e5) / 1e3
|
|
46472
|
+
}));
|
|
46473
|
+
return { ...anim, keyframes: { ...data, keyframes } };
|
|
46474
|
+
}
|
|
46475
|
+
|
|
46476
|
+
// src/hooks/gsapTweenReach.ts
|
|
46477
|
+
function tweenReach(animation, el) {
|
|
46478
|
+
const doc = el?.ownerDocument;
|
|
46479
|
+
if (!el?.isConnected || !doc || animation.hasUnresolvedSelector) return "unknown";
|
|
46480
|
+
let hits;
|
|
46481
|
+
try {
|
|
46482
|
+
hits = [...doc.querySelectorAll(animation.targetSelector)];
|
|
46483
|
+
} catch {
|
|
46484
|
+
return "unknown";
|
|
46485
|
+
}
|
|
46486
|
+
if (!hits.includes(el)) return "elsewhere";
|
|
46487
|
+
return hits.length === 1 ? "own" : "shared";
|
|
46488
|
+
}
|
|
46489
|
+
function tweensForThisElement(selection, animations) {
|
|
46490
|
+
return animations.filter((a) => {
|
|
46491
|
+
const reach = tweenReach(a, selection.element);
|
|
46492
|
+
return reach === "own" || reach === "unknown";
|
|
46493
|
+
});
|
|
46494
|
+
}
|
|
46495
|
+
|
|
46496
|
+
// src/hooks/gsapValueAtPlayhead.ts
|
|
46497
|
+
var PERCENTAGE_SEGMENT_EASE = "power1.inOut";
|
|
46498
|
+
var ARRAY_STEP_EASE = "none";
|
|
46499
|
+
var roundPct2 = (pct) => Math.round(pct * 1e3) / 1e3;
|
|
46500
|
+
var isLinear = (ease) => !ease || ease === "none" || ease === "linear";
|
|
46501
|
+
function refuse(reason) {
|
|
46502
|
+
return { ok: false, reason };
|
|
46503
|
+
}
|
|
46504
|
+
function normalize(edit) {
|
|
46505
|
+
const { anim } = edit;
|
|
46506
|
+
const data = anim.keyframes;
|
|
46507
|
+
if (data) {
|
|
46508
|
+
if (!isLinear(anim.ease) || !isLinear(data.ease)) return { reason: "eased-keyframes" };
|
|
46509
|
+
if (data.format === "simple-array") return { reason: "simple-array-keyframes" };
|
|
46510
|
+
const arrayStep = data.format === "object-array";
|
|
46511
|
+
return {
|
|
46512
|
+
keyframes: data.keyframes.map((kf) => ({
|
|
46513
|
+
...kf,
|
|
46514
|
+
properties: { ...kf.properties },
|
|
46515
|
+
...arrayStep ? { ease: kf.ease ?? ARRAY_STEP_EASE } : {}
|
|
46516
|
+
})),
|
|
46517
|
+
...data.easeEach && !arrayStep ? { easeEach: data.easeEach } : {}
|
|
46518
|
+
};
|
|
46519
|
+
}
|
|
46520
|
+
const easeEach = anim.ease ?? edit.parsedEase;
|
|
46521
|
+
if (!easeEach) return { reason: "unknown-ease" };
|
|
46522
|
+
const to = { percentage: 100, properties: { ...anim.properties } };
|
|
46523
|
+
if (anim.method === "to") return { keyframes: [to], easeEach };
|
|
46524
|
+
if (anim.method === "fromTo") {
|
|
46525
|
+
return { keyframes: [{ percentage: 0, properties: { ...anim.fromProperties } }, to], easeEach };
|
|
46526
|
+
}
|
|
46527
|
+
if (anim.method === "from") {
|
|
46528
|
+
const end = {};
|
|
46529
|
+
for (const prop of Object.keys(anim.properties)) {
|
|
46530
|
+
const value = edit.implicitEndValue(prop, "end");
|
|
46531
|
+
if (value == null) return { reason: "implicit-end-unknown" };
|
|
46532
|
+
end[prop] = value;
|
|
46491
46533
|
}
|
|
46534
|
+
return {
|
|
46535
|
+
keyframes: [
|
|
46536
|
+
{ percentage: 0, properties: { ...anim.properties } },
|
|
46537
|
+
{ percentage: 100, properties: end }
|
|
46538
|
+
],
|
|
46539
|
+
easeEach
|
|
46540
|
+
};
|
|
46492
46541
|
}
|
|
46493
|
-
|
|
46494
|
-
|
|
46495
|
-
|
|
46496
|
-
|
|
46497
|
-
|
|
46498
|
-
|
|
46499
|
-
|
|
46500
|
-
|
|
46501
|
-
|
|
46502
|
-
|
|
46503
|
-
);
|
|
46504
|
-
|
|
46505
|
-
const converted = fresh.find((a) => a.id === anim.id && a.keyframes) ?? fresh.find((a) => a.targetSelector === anim.targetSelector && a.keyframes) ?? anim;
|
|
46506
|
-
const convertedStart = resolveTweenStart(converted) ?? ts;
|
|
46507
|
-
const convertedDur = resolveTweenDuration(converted) || td;
|
|
46508
|
-
await extendTweenAndAddKeyframe(
|
|
46509
|
-
selection,
|
|
46510
|
-
converted,
|
|
46511
|
-
properties,
|
|
46512
|
-
ct,
|
|
46513
|
-
convertedStart,
|
|
46514
|
-
convertedDur,
|
|
46515
|
-
callbacks,
|
|
46516
|
-
beforeReload
|
|
46517
|
-
);
|
|
46518
|
-
return;
|
|
46542
|
+
return { reason: "not-a-tween" };
|
|
46543
|
+
}
|
|
46544
|
+
function valueAt(keyframes, prop, side) {
|
|
46545
|
+
const carrying = keyframes.filter((kf2) => kf2.properties[prop] != null);
|
|
46546
|
+
const kf = side === "first" ? carrying[0] : carrying.at(-1);
|
|
46547
|
+
return kf ? { percentage: kf.percentage, value: kf.properties[prop] } : null;
|
|
46548
|
+
}
|
|
46549
|
+
function upsert(keyframes, percentage, properties, ease) {
|
|
46550
|
+
const hit = keyframes.find((kf) => Math.abs(kf.percentage - percentage) <= KEYFRAME_PCT_MATCH);
|
|
46551
|
+
if (hit) {
|
|
46552
|
+
Object.assign(hit.properties, properties);
|
|
46553
|
+
return hit;
|
|
46519
46554
|
}
|
|
46520
|
-
const
|
|
46521
|
-
|
|
46522
|
-
|
|
46523
|
-
|
|
46524
|
-
|
|
46525
|
-
|
|
46526
|
-
|
|
46527
|
-
|
|
46528
|
-
|
|
46529
|
-
|
|
46530
|
-
|
|
46531
|
-
|
|
46532
|
-
|
|
46533
|
-
|
|
46534
|
-
|
|
46535
|
-
|
|
46536
|
-
|
|
46555
|
+
const added = { percentage, properties, ...ease ? { ease } : {} };
|
|
46556
|
+
keyframes.push(added);
|
|
46557
|
+
return added;
|
|
46558
|
+
}
|
|
46559
|
+
function heldEnds(norm, end, implicit, backfilled) {
|
|
46560
|
+
const props = new Set(norm.keyframes.flatMap((kf) => Object.keys(kf.properties)));
|
|
46561
|
+
const held = {};
|
|
46562
|
+
for (const prop of props) {
|
|
46563
|
+
const known = valueAt(norm.keyframes, prop, end === "start" ? "first" : "last");
|
|
46564
|
+
const value = known && (end === "end" || known.percentage <= 0) ? known.value : backfilled[prop] ?? implicit(prop, "start");
|
|
46565
|
+
if (value == null) return null;
|
|
46566
|
+
held[prop] = value;
|
|
46567
|
+
}
|
|
46568
|
+
return held;
|
|
46569
|
+
}
|
|
46570
|
+
function planValueAtPlayhead(edit) {
|
|
46571
|
+
const { anim, values } = edit;
|
|
46572
|
+
const start = resolveTweenStart(anim);
|
|
46573
|
+
const duration = resolveTweenDuration(anim);
|
|
46574
|
+
if (start == null || !(duration > 0)) return refuse("no-timing");
|
|
46575
|
+
const norm = normalize(edit);
|
|
46576
|
+
if ("reason" in norm) return refuse(norm.reason);
|
|
46577
|
+
const keyframes = norm.keyframes;
|
|
46578
|
+
const authored = keyframes.length;
|
|
46579
|
+
if ("scaleX" in values || "scaleY" in values) {
|
|
46580
|
+
for (const kf of keyframes) {
|
|
46581
|
+
const { scale, ...rest } = kf.properties;
|
|
46582
|
+
if (scale != null) kf.properties = { scaleX: scale, scaleY: scale, ...rest };
|
|
46583
|
+
}
|
|
46584
|
+
}
|
|
46585
|
+
const backfilled = {};
|
|
46586
|
+
for (const [prop, value] of Object.entries(edit.backfill ?? {})) {
|
|
46587
|
+
if (!(prop in values) || keyframes.some((kf) => kf.properties[prop] != null)) continue;
|
|
46588
|
+
if (edit.holdFromStart && !keyframes.some((kf) => kf.percentage <= 0))
|
|
46589
|
+
keyframes.unshift({ percentage: 0, properties: {} });
|
|
46590
|
+
for (const kf of keyframes) kf.properties[prop] = value;
|
|
46591
|
+
backfilled[prop] = value;
|
|
46592
|
+
}
|
|
46593
|
+
if (Object.keys(values).some((prop) => !keyframes.some((kf) => kf.properties[prop] != null)))
|
|
46594
|
+
return refuse("implicit-end-unknown");
|
|
46595
|
+
let position = start;
|
|
46596
|
+
let span = duration;
|
|
46597
|
+
const pct = "percentage" in edit.at ? edit.at.percentage : roundPct2((edit.at.time - start) / duration * 100);
|
|
46598
|
+
if (pct >= -KEYFRAME_PCT_MATCH && pct <= 100 + KEYFRAME_PCT_MATCH) {
|
|
46599
|
+
const at = Math.min(100, Math.max(0, pct));
|
|
46600
|
+
const next = [...keyframes].sort((a, b) => a.percentage - b.percentage).find((kf) => kf.percentage > at + KEYFRAME_PCT_MATCH);
|
|
46601
|
+
upsert(keyframes, at, { ...values }, next?.ease);
|
|
46602
|
+
} else {
|
|
46603
|
+
const time = edit.at.time;
|
|
46604
|
+
const before = time < start;
|
|
46605
|
+
const held = heldEnds(norm, before ? "start" : "end", edit.implicitEndValue, backfilled);
|
|
46606
|
+
if (!held) return refuse("implicit-end-unknown");
|
|
46607
|
+
position = before ? time : start;
|
|
46608
|
+
span = before ? start + duration - time : time - start;
|
|
46609
|
+
for (const kf of keyframes) {
|
|
46610
|
+
kf.percentage = roundPct2(
|
|
46611
|
+
(start + kf.percentage / 100 * duration - position) / span * 100
|
|
46612
|
+
);
|
|
46613
|
+
}
|
|
46614
|
+
const oldEdge = roundPct2(((before ? start : start + duration) - position) / span * 100);
|
|
46615
|
+
const linear = isLinear(norm.easeEach ?? PERCENTAGE_SEGMENT_EASE) ? void 0 : "none";
|
|
46616
|
+
const edge = upsert(keyframes, oldEdge, held, linear);
|
|
46617
|
+
if (before && linear) edge.ease ??= linear;
|
|
46618
|
+
upsert(keyframes, before ? 0 : 100, { ...held, ...values }, before ? void 0 : linear);
|
|
46619
|
+
}
|
|
46620
|
+
keyframes.sort((a, b) => a.percentage - b.percentage);
|
|
46621
|
+
return {
|
|
46622
|
+
ok: true,
|
|
46623
|
+
mutation: {
|
|
46624
|
+
type: "replace-with-keyframes",
|
|
46537
46625
|
animationId: anim.id,
|
|
46538
|
-
|
|
46539
|
-
|
|
46540
|
-
|
|
46541
|
-
|
|
46542
|
-
|
|
46626
|
+
targetSelector: anim.targetSelector,
|
|
46627
|
+
position: roundTo3(position),
|
|
46628
|
+
duration: roundTo3(span),
|
|
46629
|
+
keyframes,
|
|
46630
|
+
...norm.easeEach ? { easeEach: norm.easeEach } : {}
|
|
46631
|
+
},
|
|
46632
|
+
added: keyframes.length > authored
|
|
46633
|
+
};
|
|
46634
|
+
}
|
|
46635
|
+
function planValueEdit(selection, anim, values, iframe, { backfill, holdFromStart } = {}) {
|
|
46636
|
+
if (tweenReach(anim, selection.element) === "shared") return refuse("shared-tween");
|
|
46637
|
+
const { activeKeyframePct, currentTime } = usePlayerStore.getState();
|
|
46638
|
+
const tween = findParsedTween(iframe, selection.element, anim);
|
|
46639
|
+
const timed = withExactStepTimes(anim, tween);
|
|
46640
|
+
return planValueAtPlayhead({
|
|
46641
|
+
anim: withLiveTiming(timed, tween),
|
|
46642
|
+
at: activeKeyframePct != null ? { percentage: activeKeyframePct } : { time: currentTime },
|
|
46643
|
+
values,
|
|
46644
|
+
backfill,
|
|
46645
|
+
holdFromStart,
|
|
46646
|
+
implicitEndValue: parsedImplicitEndValue(tween),
|
|
46647
|
+
parsedEase: parsedTweenEase(iframe, tween)
|
|
46648
|
+
});
|
|
46649
|
+
}
|
|
46650
|
+
async function commitValueAtPlayhead(selection, anim, values, iframe, callbacks, options) {
|
|
46651
|
+
await materializeIfDynamic(anim, iframe, callbacks.commitMutation, selection);
|
|
46652
|
+
const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState();
|
|
46653
|
+
const plan = planValueEdit(selection, anim, values, iframe, options);
|
|
46654
|
+
if (!plan.ok) return { status: "blocked", reason: "keyframes-uneditable", detail: plan.reason };
|
|
46655
|
+
await callbacks.commitMutation(selection, plan.mutation, {
|
|
46656
|
+
label: options.label,
|
|
46657
|
+
softReload: true,
|
|
46658
|
+
beforeReload: options.beforeReload,
|
|
46659
|
+
...plan.added && { keyframeAction: "add" }
|
|
46660
|
+
});
|
|
46661
|
+
if (activeKeyframePct != null) {
|
|
46662
|
+
setActiveKeyframePct(null);
|
|
46663
|
+
parkPlayheadOnKeyframe(anim, activeKeyframePct);
|
|
46664
|
+
}
|
|
46665
|
+
return { status: "persisted" };
|
|
46666
|
+
}
|
|
46667
|
+
|
|
46668
|
+
// src/hooks/gsapDragPositionCommit.ts
|
|
46669
|
+
function buildTemporalArcKeyframes(anim, percentage, properties) {
|
|
46670
|
+
return [
|
|
46671
|
+
...(anim.keyframes?.keyframes ?? []).filter((keyframe) => Math.abs(keyframe.percentage - percentage) > KEYFRAME_PCT_MATCH).map((keyframe) => ({
|
|
46672
|
+
percentage: keyframe.percentage,
|
|
46673
|
+
properties: { ...keyframe.properties },
|
|
46674
|
+
...keyframe.ease ? { ease: keyframe.ease } : {}
|
|
46675
|
+
})),
|
|
46676
|
+
{ percentage, properties }
|
|
46677
|
+
].sort((a, b) => a.percentage - b.percentage);
|
|
46678
|
+
}
|
|
46679
|
+
function gsapPositionFromDragOutcome(selection, anim, studioOffset, gsapPos, iframe) {
|
|
46680
|
+
if (anim.arcPath?.enabled) return { status: "persisted" };
|
|
46681
|
+
const { newX, newY, baseGsapX, baseGsapY } = computeDraggedGsapPosition(
|
|
46682
|
+
selection.element,
|
|
46683
|
+
studioOffset,
|
|
46684
|
+
gsapPos
|
|
46543
46685
|
);
|
|
46544
|
-
|
|
46686
|
+
const plan = planValueEdit(selection, anim, { x: newX, y: newY }, iframe, {
|
|
46687
|
+
backfill: { x: baseGsapX, y: baseGsapY }
|
|
46688
|
+
});
|
|
46689
|
+
return plan.ok ? { status: "persisted" } : { status: "blocked", reason: "keyframes-uneditable", detail: plan.reason };
|
|
46545
46690
|
}
|
|
46546
|
-
async function commitGsapPositionFromDrag(selection, anim, studioOffset, gsapPos, iframe,
|
|
46691
|
+
async function commitGsapPositionFromDrag(selection, anim, studioOffset, gsapPos, iframe, callbacks) {
|
|
46547
46692
|
const el = selection.element;
|
|
46548
46693
|
const { newX, newY, baseGsapX, baseGsapY } = computeDraggedGsapPosition(
|
|
46549
46694
|
el,
|
|
@@ -46558,8 +46703,6 @@ async function commitGsapPositionFromDrag(selection, anim, studioOffset, gsapPos
|
|
|
46558
46703
|
el.removeAttribute("data-hf-drag-initial-offset-x");
|
|
46559
46704
|
el.removeAttribute("data-hf-drag-initial-offset-y");
|
|
46560
46705
|
};
|
|
46561
|
-
const backfillDefaults = { x: baseGsapX, y: baseGsapY };
|
|
46562
|
-
const ct = usePlayerStore.getState().currentTime;
|
|
46563
46706
|
if (anim.arcPath?.enabled) {
|
|
46564
46707
|
const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState();
|
|
46565
46708
|
const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim);
|
|
@@ -46581,11 +46724,12 @@ async function commitGsapPositionFromDrag(selection, anim, studioOffset, gsapPos
|
|
|
46581
46724
|
);
|
|
46582
46725
|
setActiveKeyframePct(null);
|
|
46583
46726
|
parkPlayheadOnKeyframe(anim, pct);
|
|
46584
|
-
return;
|
|
46727
|
+
return { status: "persisted" };
|
|
46585
46728
|
}
|
|
46586
46729
|
const tweenStart = resolveTweenStart(anim);
|
|
46587
46730
|
const tweenDuration = resolveEditableTweenDuration(anim, selection);
|
|
46588
|
-
if (tweenStart === null || tweenDuration <= 0 || keyframes.length < 2)
|
|
46731
|
+
if (tweenStart === null || tweenDuration <= 0 || keyframes.length < 2)
|
|
46732
|
+
return { status: "persisted" };
|
|
46589
46733
|
const temporalKeyframes = buildTemporalArcKeyframes(anim, pct, { x: newX, y: newY });
|
|
46590
46734
|
await callbacks.commitMutation(
|
|
46591
46735
|
selection,
|
|
@@ -46605,171 +46749,12 @@ async function commitGsapPositionFromDrag(selection, anim, studioOffset, gsapPos
|
|
|
46605
46749
|
beforeReload: restoreOffset
|
|
46606
46750
|
}
|
|
46607
46751
|
);
|
|
46608
|
-
return;
|
|
46609
|
-
}
|
|
46610
|
-
if (anim.keyframes) {
|
|
46611
|
-
const newId = await materializeIfDynamic(anim, iframe, callbacks.commitMutation, selection);
|
|
46612
|
-
const effectiveAnim = newId ? { ...anim, id: newId } : anim;
|
|
46613
|
-
const dragProps = { x: newX, y: newY };
|
|
46614
|
-
const ts = resolveTweenStart(effectiveAnim);
|
|
46615
|
-
const td = resolveEditableTweenDuration(effectiveAnim, selection);
|
|
46616
|
-
const outsideRange = ts !== null && td > 0 && (ct < ts - 0.01 || ct > ts + td + 0.01);
|
|
46617
|
-
const hasSelectedKeyframe = usePlayerStore.getState().activeKeyframePct != null;
|
|
46618
|
-
if (outsideRange && !hasSelectedKeyframe) {
|
|
46619
|
-
await extendTweenAndAddKeyframe(
|
|
46620
|
-
selection,
|
|
46621
|
-
effectiveAnim,
|
|
46622
|
-
dragProps,
|
|
46623
|
-
ct,
|
|
46624
|
-
ts,
|
|
46625
|
-
td,
|
|
46626
|
-
callbacks,
|
|
46627
|
-
restoreOffset,
|
|
46628
|
-
backfillDefaults
|
|
46629
|
-
);
|
|
46630
|
-
} else {
|
|
46631
|
-
await commitKeyframedPosition(
|
|
46632
|
-
selection,
|
|
46633
|
-
effectiveAnim,
|
|
46634
|
-
dragProps,
|
|
46635
|
-
callbacks,
|
|
46636
|
-
restoreOffset,
|
|
46637
|
-
backfillDefaults
|
|
46638
|
-
);
|
|
46639
|
-
}
|
|
46640
|
-
} else if (anim.method === "from" || anim.method === "fromTo") {
|
|
46641
|
-
const ct2 = usePlayerStore.getState().currentTime;
|
|
46642
|
-
const ts = resolveTweenStart(anim);
|
|
46643
|
-
const td = resolveEditableTweenDuration(anim, selection);
|
|
46644
|
-
const hasSelectedKeyframe = usePlayerStore.getState().activeKeyframePct != null;
|
|
46645
|
-
const outsideRange = !hasSelectedKeyframe && ts !== null && td > 0 && (ct2 < ts - 0.01 || ct2 > ts + td + 0.01);
|
|
46646
|
-
const dragProps = { x: newX, y: newY };
|
|
46647
|
-
if (outsideRange && ts !== null) {
|
|
46648
|
-
await callbacks.commitMutation(
|
|
46649
|
-
selection,
|
|
46650
|
-
{ type: "split-into-property-groups", animationId: anim.id },
|
|
46651
|
-
{ label: "Split from() for drag", skipReload: true }
|
|
46652
|
-
);
|
|
46653
|
-
const allAnims = callbacks.fetchAnimations ? await callbacks.fetchAnimations() : [];
|
|
46654
|
-
const existingPosAnim = allAnims.find(
|
|
46655
|
-
(a) => a.propertyGroup === "position" && a.targetSelector === anim.targetSelector
|
|
46656
|
-
);
|
|
46657
|
-
if (existingPosAnim?.keyframes) {
|
|
46658
|
-
const posTs = resolveTweenStart(existingPosAnim);
|
|
46659
|
-
const posTd = resolveEditableTweenDuration(existingPosAnim, selection);
|
|
46660
|
-
if (posTs !== null) {
|
|
46661
|
-
await extendTweenAndAddKeyframe(
|
|
46662
|
-
selection,
|
|
46663
|
-
existingPosAnim,
|
|
46664
|
-
{ x: newX, y: newY },
|
|
46665
|
-
ct2,
|
|
46666
|
-
posTs,
|
|
46667
|
-
posTd,
|
|
46668
|
-
callbacks,
|
|
46669
|
-
restoreOffset,
|
|
46670
|
-
backfillDefaults
|
|
46671
|
-
);
|
|
46672
|
-
return;
|
|
46673
|
-
}
|
|
46674
|
-
}
|
|
46675
|
-
const newStart = Math.min(ct2, ts);
|
|
46676
|
-
const newEnd = Math.max(ct2, ts + td);
|
|
46677
|
-
const newDuration = Math.max(0.01, newEnd - newStart);
|
|
46678
|
-
const dragBefore = ct2 < ts;
|
|
46679
|
-
const origStartPct = Math.round((ts - newStart) / newDuration * 1e3) / 10;
|
|
46680
|
-
const origEndPct = Math.round((ts + td - newStart) / newDuration * 1e3) / 10;
|
|
46681
|
-
const keyframes = [];
|
|
46682
|
-
if (dragBefore) {
|
|
46683
|
-
keyframes.push({ percentage: 0, properties: { x: newX, y: newY } });
|
|
46684
|
-
if (origStartPct > 0.5 && origStartPct < 99.5) {
|
|
46685
|
-
keyframes.push({ percentage: origStartPct, properties: { x: 0, y: 0 } });
|
|
46686
|
-
}
|
|
46687
|
-
keyframes.push({ percentage: 100, properties: { x: 0, y: 0 } });
|
|
46688
|
-
} else {
|
|
46689
|
-
keyframes.push({ percentage: 0, properties: { x: 0, y: 0 } });
|
|
46690
|
-
if (origEndPct > 0.5 && origEndPct < 99.5) {
|
|
46691
|
-
keyframes.push({ percentage: origEndPct, properties: { x: 0, y: 0 } });
|
|
46692
|
-
}
|
|
46693
|
-
keyframes.push({ percentage: 100, properties: { x: newX, y: newY } });
|
|
46694
|
-
}
|
|
46695
|
-
keyframes.sort((a, b) => a.percentage - b.percentage);
|
|
46696
|
-
const baseKf = {
|
|
46697
|
-
targetSelector: anim.targetSelector,
|
|
46698
|
-
position: roundTo3(newStart),
|
|
46699
|
-
duration: roundTo3(newDuration),
|
|
46700
|
-
keyframes
|
|
46701
|
-
};
|
|
46702
|
-
await callbacks.commitMutation(
|
|
46703
|
-
selection,
|
|
46704
|
-
existingPosAnim ? { type: "replace-with-keyframes", animationId: existingPosAnim.id, ...baseKf } : { type: "add-with-keyframes", ...baseKf },
|
|
46705
|
-
{
|
|
46706
|
-
label: "Move layer (from extended)",
|
|
46707
|
-
keyframeAction: "add",
|
|
46708
|
-
softReload: true,
|
|
46709
|
-
beforeReload: restoreOffset
|
|
46710
|
-
}
|
|
46711
|
-
);
|
|
46712
|
-
} else {
|
|
46713
|
-
const coalesceKey = `gsap:convert-drag:${anim.id}`;
|
|
46714
|
-
await callbacks.commitMutation(
|
|
46715
|
-
selection,
|
|
46716
|
-
{
|
|
46717
|
-
type: "convert-to-keyframes",
|
|
46718
|
-
animationId: anim.id
|
|
46719
|
-
},
|
|
46720
|
-
{ label: "Convert from() for drag", skipReload: true, coalesceKey }
|
|
46721
|
-
);
|
|
46722
|
-
const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState();
|
|
46723
|
-
const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim);
|
|
46724
|
-
if (activeKeyframePct != null) setActiveKeyframePct(null);
|
|
46725
|
-
await callbacks.commitMutation(
|
|
46726
|
-
selection,
|
|
46727
|
-
{
|
|
46728
|
-
type: "add-keyframe",
|
|
46729
|
-
animationId: anim.id,
|
|
46730
|
-
percentage: pct,
|
|
46731
|
-
properties: dragProps,
|
|
46732
|
-
...backfillDefaults ? { backfillDefaults } : {}
|
|
46733
|
-
},
|
|
46734
|
-
{
|
|
46735
|
-
label: `Move layer (keyframe ${pct}%)`,
|
|
46736
|
-
softReload: true,
|
|
46737
|
-
beforeReload: restoreOffset,
|
|
46738
|
-
coalesceKey
|
|
46739
|
-
}
|
|
46740
|
-
);
|
|
46741
|
-
}
|
|
46742
|
-
} else {
|
|
46743
|
-
await commitFlatViaKeyframes(
|
|
46744
|
-
selection,
|
|
46745
|
-
anim,
|
|
46746
|
-
{ x: newX, y: newY },
|
|
46747
|
-
callbacks,
|
|
46748
|
-
restoreOffset,
|
|
46749
|
-
iframe,
|
|
46750
|
-
selector,
|
|
46751
|
-
backfillDefaults
|
|
46752
|
-
);
|
|
46753
|
-
}
|
|
46754
|
-
}
|
|
46755
|
-
|
|
46756
|
-
// src/hooks/gsapTweenReach.ts
|
|
46757
|
-
function tweenReach(animation, el) {
|
|
46758
|
-
const doc = el?.ownerDocument;
|
|
46759
|
-
if (!el?.isConnected || !doc || animation.hasUnresolvedSelector) return "unknown";
|
|
46760
|
-
let hits;
|
|
46761
|
-
try {
|
|
46762
|
-
hits = [...doc.querySelectorAll(animation.targetSelector)];
|
|
46763
|
-
} catch {
|
|
46764
|
-
return "unknown";
|
|
46752
|
+
return { status: "persisted" };
|
|
46765
46753
|
}
|
|
46766
|
-
|
|
46767
|
-
|
|
46768
|
-
}
|
|
46769
|
-
|
|
46770
|
-
return animations.filter((a) => {
|
|
46771
|
-
const reach = tweenReach(a, selection.element);
|
|
46772
|
-
return reach === "own" || reach === "unknown";
|
|
46754
|
+
return commitValueAtPlayhead(selection, anim, { x: newX, y: newY }, iframe, callbacks, {
|
|
46755
|
+
label: "Move layer",
|
|
46756
|
+
backfill: { x: baseGsapX, y: baseGsapY },
|
|
46757
|
+
beforeReload: restoreOffset
|
|
46773
46758
|
});
|
|
46774
46759
|
}
|
|
46775
46760
|
|
|
@@ -46795,40 +46780,59 @@ function animHasPosition(anim) {
|
|
|
46795
46780
|
function findGsapPositionAnimation(animations, selector) {
|
|
46796
46781
|
if (animations.length === 0) return null;
|
|
46797
46782
|
const currentTime = usePlayerStore.getState().currentTime;
|
|
46798
|
-
const scored = animations.filter(
|
|
46783
|
+
const scored = animations.filter(animHasPosition).map((a) => {
|
|
46799
46784
|
let score = 0;
|
|
46800
|
-
if (animHasPosition(a)) score += 10;
|
|
46801
46785
|
if (a.keyframes) score += 5;
|
|
46802
46786
|
if (selector && a.targetSelector === selector) score += 8;
|
|
46803
46787
|
else if (a.targetSelector.includes(",")) score -= 5;
|
|
46804
|
-
|
|
46805
|
-
const dur = a.duration ?? 0;
|
|
46806
|
-
if (currentTime >= pos - 0.05 && currentTime <= pos + dur + 0.05) score += 50;
|
|
46807
|
-
else
|
|
46808
|
-
score -= Math.round(
|
|
46809
|
-
Math.min(Math.abs(currentTime - pos), Math.abs(currentTime - pos - dur)) * 5
|
|
46810
|
-
);
|
|
46811
|
-
return { anim: a, score };
|
|
46788
|
+
return { anim: a, score: score + playheadProximity(a, currentTime) };
|
|
46812
46789
|
});
|
|
46813
46790
|
scored.sort((a, b) => b.score - a.score);
|
|
46814
|
-
return scored[0]?.anim ??
|
|
46791
|
+
return scored[0]?.anim ?? null;
|
|
46792
|
+
}
|
|
46793
|
+
function playheadProximity(a, currentTime) {
|
|
46794
|
+
const pos = a.resolvedStart ?? (typeof a.position === "number" ? a.position : 0);
|
|
46795
|
+
const dur = a.duration ?? 0;
|
|
46796
|
+
if (currentTime >= pos - 0.05 && currentTime <= pos + dur + 0.05) return 50;
|
|
46797
|
+
return -Math.round(Math.min(Math.abs(currentTime - pos), Math.abs(currentTime - pos - dur)) * 5);
|
|
46798
|
+
}
|
|
46799
|
+
function statesValueAt(anim, time) {
|
|
46800
|
+
const duration = resolveTweenDuration(anim);
|
|
46801
|
+
if (!(duration > 0)) return false;
|
|
46802
|
+
const pct = (time - (resolveTweenStart(anim) ?? 0)) / duration * 100;
|
|
46803
|
+
const near3 = (keyframe) => Math.abs(keyframe - pct) <= KEYFRAME_PCT_MATCH;
|
|
46804
|
+
if (anim.keyframes) return anim.keyframes.keyframes.some((kf) => near3(kf.percentage));
|
|
46805
|
+
if (anim.method === "from") return near3(0);
|
|
46806
|
+
return near3(100) || anim.method === "fromTo" && near3(0);
|
|
46815
46807
|
}
|
|
46816
46808
|
function pickClosestToPlayhead(anims) {
|
|
46817
46809
|
if (anims.length <= 1) return anims[0] ?? null;
|
|
46818
46810
|
const ct = usePlayerStore.getState().currentTime;
|
|
46819
46811
|
return anims.reduce((best, a) => {
|
|
46820
|
-
const
|
|
46821
|
-
const
|
|
46822
|
-
const dist = ct >= s && ct <= e ? 0 : Math.min(Math.abs(ct - s), Math.abs(ct - e));
|
|
46823
|
-
const bestS = resolveTweenStart(best) ?? 0;
|
|
46824
|
-
const bestE = bestS + resolveTweenDuration(best);
|
|
46825
|
-
const bestDist = ct >= bestS && ct <= bestE ? 0 : Math.min(Math.abs(ct - bestS), Math.abs(ct - bestE));
|
|
46812
|
+
const dist = playheadDistance(a, ct);
|
|
46813
|
+
const bestDist = playheadDistance(best, ct);
|
|
46826
46814
|
if (dist < bestDist) return a;
|
|
46827
|
-
|
|
46828
|
-
|
|
46815
|
+
const stated = dist === 0 && bestDist === 0 ? statedValueWinner(a, best, ct) : null;
|
|
46816
|
+
if (stated) return stated;
|
|
46817
|
+
if (dist === bestDist && keyframeCount(a) > keyframeCount(best)) return a;
|
|
46829
46818
|
return best;
|
|
46830
46819
|
});
|
|
46831
46820
|
}
|
|
46821
|
+
function playheadDistance(anim, time) {
|
|
46822
|
+
const s = resolveTweenStart(anim) ?? 0;
|
|
46823
|
+
const e = s + resolveTweenDuration(anim);
|
|
46824
|
+
return time >= s && time <= e ? 0 : Math.min(Math.abs(time - s), Math.abs(time - e));
|
|
46825
|
+
}
|
|
46826
|
+
function statedValueWinner(a, b, time) {
|
|
46827
|
+
const [mine, theirs] = [statesValueAt(a, time), statesValueAt(b, time)];
|
|
46828
|
+
if (mine !== theirs) return mine ? a : b;
|
|
46829
|
+
const [s, bS] = [resolveTweenStart(a) ?? 0, resolveTweenStart(b) ?? 0];
|
|
46830
|
+
if (mine && s !== bS) return s > bS ? a : b;
|
|
46831
|
+
return null;
|
|
46832
|
+
}
|
|
46833
|
+
function keyframeCount(anim) {
|
|
46834
|
+
return anim.keyframes?.keyframes.length ?? 0;
|
|
46835
|
+
}
|
|
46832
46836
|
|
|
46833
46837
|
// src/hooks/gsapElementMatch.ts
|
|
46834
46838
|
function getAnimationsForElement(animations, target, element) {
|
|
@@ -46858,40 +46862,19 @@ function getAnimationsForElement(animations, target, element) {
|
|
|
46858
46862
|
// src/hooks/gsapRuntimeBridge.ts
|
|
46859
46863
|
var POSITION_CHANNEL_SET = new Set(POSITION_CHANNELS);
|
|
46860
46864
|
var ROTATION_CHANNEL_SET = new Set(ROTATION_CHANNELS);
|
|
46861
|
-
async function resolveGroupTween(group, animations,
|
|
46862
|
-
const
|
|
46863
|
-
|
|
46864
|
-
|
|
46865
|
-
|
|
46866
|
-
|
|
46867
|
-
|
|
46868
|
-
|
|
46869
|
-
|
|
46870
|
-
|
|
46871
|
-
|
|
46872
|
-
|
|
46873
|
-
|
|
46874
|
-
const freshGroupAnim = fresh.find((a) => a.propertyGroup === group);
|
|
46875
|
-
if (freshGroupAnim) return { anim: freshGroupAnim, animations: fresh };
|
|
46876
|
-
}
|
|
46877
|
-
}
|
|
46878
|
-
if (!legacyMixed && fetchFallbackAnimations) {
|
|
46879
|
-
const fresh = await fetchFallbackAnimations();
|
|
46880
|
-
const freshGroupAnim = fresh.find((a) => a.propertyGroup === group);
|
|
46881
|
-
if (freshGroupAnim) return { anim: freshGroupAnim, animations: fresh };
|
|
46882
|
-
const freshLegacy = fresh.find((a) => !a.propertyGroup);
|
|
46883
|
-
if (freshLegacy) {
|
|
46884
|
-
await commitMutation(
|
|
46885
|
-
selection,
|
|
46886
|
-
{ type: "split-into-property-groups", animationId: freshLegacy.id },
|
|
46887
|
-
{ label: "Split mixed tween into property groups", skipReload: true }
|
|
46888
|
-
);
|
|
46889
|
-
const reFetched = await fetchFallbackAnimations();
|
|
46890
|
-
const reFetchedGroup = reFetched.find((a) => a.propertyGroup === group);
|
|
46891
|
-
if (reFetchedGroup) return { anim: reFetchedGroup, animations: reFetched };
|
|
46892
|
-
}
|
|
46893
|
-
}
|
|
46894
|
-
return null;
|
|
46865
|
+
async function resolveGroupTween(group, animations, _selection, _commitMutation, fetchFallbackAnimations) {
|
|
46866
|
+
const inGroup = (list) => {
|
|
46867
|
+
const tagged = list.filter((a) => a.propertyGroup === group);
|
|
46868
|
+
const props = new Set(PROPERTY_GROUPS[group]);
|
|
46869
|
+
const mixed = list.filter((a) => !a.propertyGroup && animationWritesAnyProperty(a, props));
|
|
46870
|
+
return pickClosestToPlayhead(tagged.length > 0 ? tagged : mixed);
|
|
46871
|
+
};
|
|
46872
|
+
const anim = inGroup(animations);
|
|
46873
|
+
if (anim) return { anim, animations };
|
|
46874
|
+
if (!fetchFallbackAnimations) return null;
|
|
46875
|
+
const fresh = await fetchFallbackAnimations();
|
|
46876
|
+
const freshAnim = inGroup(fresh);
|
|
46877
|
+
return freshAnim ? { anim: freshAnim, animations: fresh } : null;
|
|
46895
46878
|
}
|
|
46896
46879
|
var writesPosition = (a) => animationWritesAnyProperty(a, POSITION_CHANNEL_SET);
|
|
46897
46880
|
function positionedOnlyBySharedTween(selection, animations) {
|
|
@@ -46939,6 +46922,36 @@ function oneUndoStep(commit) {
|
|
|
46939
46922
|
const coalesceKey = `gsap:drag:${++dragGestureCounter}`;
|
|
46940
46923
|
return (selection, mutation, options) => commit(selection, mutation, { ...options, coalesceKey, coalesceMs: Number.POSITIVE_INFINITY });
|
|
46941
46924
|
}
|
|
46925
|
+
var isPositionWriteOf = (selector) => (a) => a.targetSelector === selector && isXYPositionWrite(a);
|
|
46926
|
+
function positionWriteKeeper(animations, selector) {
|
|
46927
|
+
const dupes = animations.filter(isPositionWriteOf(selector));
|
|
46928
|
+
if (dupes.length < 2 || dupes.filter((a) => !isInstantHold(a)).length > 1) return null;
|
|
46929
|
+
return dupes.find((a) => a.keyframes) ?? dupes.find((a) => (a.duration ?? 0) > 0) ?? dupes[0];
|
|
46930
|
+
}
|
|
46931
|
+
function dragRoute(posAnim, iframe, selector, altKey) {
|
|
46932
|
+
const hasNonHold = hasNonHoldTweenForElement(iframe, selector, void 0, POSITION_CHANNELS);
|
|
46933
|
+
const hasKeyframedPosTween = !!posAnim?.keyframes && resolveTweenDuration(posAnim) > 0;
|
|
46934
|
+
if (!hasNonHold && !hasKeyframedPosTween) return "static";
|
|
46935
|
+
return altKey || !usePlayerStore.getState().autoKeyframeEnabled ? "whole-path" : "at-playhead";
|
|
46936
|
+
}
|
|
46937
|
+
async function planDrag(selection, offset, allAnimations, iframe, options) {
|
|
46938
|
+
const selector = selectorFromSelection(selection);
|
|
46939
|
+
if (!selector) return { status: "blocked", reason: "no-selector" };
|
|
46940
|
+
const own = tweensForThisElement(selection, allAnimations);
|
|
46941
|
+
const keeper = positionWriteKeeper(own, selector);
|
|
46942
|
+
const animations = keeper ? own.filter((a) => a === keeper || !isPositionWriteOf(selector)(a)) : own;
|
|
46943
|
+
const resolved2 = await resolveGroupTween("position", animations, selection, async () => {
|
|
46944
|
+
});
|
|
46945
|
+
const posAnim = resolved2?.anim ?? findGsapPositionAnimation(animations, selector);
|
|
46946
|
+
const route = dragRoute(posAnim, iframe, selector, options.altKey);
|
|
46947
|
+
if (route === "static") return { status: "persisted" };
|
|
46948
|
+
if (!posAnim) {
|
|
46949
|
+
return { status: "blocked", reason: "source-uneditable", detail: "no-position-tween" };
|
|
46950
|
+
}
|
|
46951
|
+
if (route === "whole-path") return { status: "persisted" };
|
|
46952
|
+
const gsapPos = readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 };
|
|
46953
|
+
return gsapPositionFromDragOutcome(selection, posAnim, offset, gsapPos, iframe);
|
|
46954
|
+
}
|
|
46942
46955
|
async function tryGsapDragIntercept(selection, offset, allAnimations, iframe, gestureCommit, fetchAllAnimations, options) {
|
|
46943
46956
|
if (!options?.preflightPassed) {
|
|
46944
46957
|
const preflight = await preflightGsapDragIntercept(
|
|
@@ -46948,7 +46961,10 @@ async function tryGsapDragIntercept(selection, offset, allAnimations, iframe, ge
|
|
|
46948
46961
|
fetchAllAnimations,
|
|
46949
46962
|
options?.group
|
|
46950
46963
|
);
|
|
46951
|
-
if (preflight.status !== "persisted"
|
|
46964
|
+
if (preflight.status !== "persisted") return preflight;
|
|
46965
|
+
if (options?.preflightOnly) {
|
|
46966
|
+
return options.group ? planDrag(selection, offset, allAnimations, iframe, options) : preflight;
|
|
46967
|
+
}
|
|
46952
46968
|
}
|
|
46953
46969
|
const animations = tweensForThisElement(selection, allAnimations);
|
|
46954
46970
|
const fetchFallbackAnimations = fetchAllAnimations && (async () => tweensForThisElement(selection, await fetchAllAnimations()));
|
|
@@ -46956,12 +46972,10 @@ async function tryGsapDragIntercept(selection, offset, allAnimations, iframe, ge
|
|
|
46956
46972
|
if (!selector) return { status: "blocked", reason: "no-selector" };
|
|
46957
46973
|
const commitMutation = oneUndoStep(gestureCommit);
|
|
46958
46974
|
let workingAnimations = animations;
|
|
46959
|
-
|
|
46960
|
-
if (animations.filter(isPosWrite).length > 1 && fetchFallbackAnimations) {
|
|
46975
|
+
if (animations.filter(isPositionWriteOf(selector)).length > 1 && fetchFallbackAnimations) {
|
|
46961
46976
|
const fresh = await fetchFallbackAnimations();
|
|
46962
|
-
const
|
|
46963
|
-
if (
|
|
46964
|
-
const keeper = dupes.find((a) => a.keyframes) ?? dupes.find((a) => (a.duration ?? 0) > 0) ?? dupes[0];
|
|
46977
|
+
const keeper = positionWriteKeeper(fresh, selector);
|
|
46978
|
+
if (keeper) {
|
|
46965
46979
|
await commitMutation(
|
|
46966
46980
|
selection,
|
|
46967
46981
|
{
|
|
@@ -46994,9 +47008,8 @@ async function tryGsapDragIntercept(selection, offset, allAnimations, iframe, ge
|
|
|
46994
47008
|
}
|
|
46995
47009
|
}
|
|
46996
47010
|
const gsapPos = readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 };
|
|
46997
|
-
const
|
|
46998
|
-
|
|
46999
|
-
if (!hasNonHold && !hasKeyframedPosTween) {
|
|
47011
|
+
const route = dragRoute(posAnim, iframe, selector, options?.altKey);
|
|
47012
|
+
if (route === "static") {
|
|
47000
47013
|
const existingSet = posAnim && isInstantHold(posAnim) && posAnim.targetSelector === selector ? posAnim : findExistingPositionWrite(resolvedAnimations, selector, selection.element);
|
|
47001
47014
|
await commitStaticGsapPosition(selection, offset, gsapPos, selector, existingSet, {
|
|
47002
47015
|
commitMutation,
|
|
@@ -47009,19 +47022,20 @@ async function tryGsapDragIntercept(selection, offset, allAnimations, iframe, ge
|
|
|
47009
47022
|
}
|
|
47010
47023
|
if (fetchFallbackAnimations) {
|
|
47011
47024
|
const fresh = await fetchFallbackAnimations();
|
|
47012
|
-
const freshMatch = fresh.find(
|
|
47013
|
-
|
|
47025
|
+
const freshMatch = fresh.find((a) => a.id === posAnim.id) ?? pickClosestToPlayhead(
|
|
47026
|
+
fresh.filter(
|
|
47027
|
+
(a) => a.targetSelector === posAnim.targetSelector && a.propertyGroup === posAnim.propertyGroup && isXYPositionWrite(a) === isXYPositionWrite(posAnim)
|
|
47028
|
+
)
|
|
47014
47029
|
);
|
|
47015
47030
|
if (freshMatch && freshMatch.id !== posAnim.id) {
|
|
47016
47031
|
posAnim = freshMatch;
|
|
47017
47032
|
}
|
|
47018
47033
|
}
|
|
47019
47034
|
const cbs = { commitMutation, fetchAnimations: fetchFallbackAnimations };
|
|
47020
|
-
|
|
47021
|
-
if (options?.altKey || !autoKeyframeEnabled) {
|
|
47035
|
+
if (route === "whole-path") {
|
|
47022
47036
|
await commitWholePathOffset(selection, posAnim, offset, gsapPos, iframe, selector, cbs);
|
|
47023
47037
|
} else {
|
|
47024
|
-
|
|
47038
|
+
return commitGsapPositionFromDrag(selection, posAnim, offset, gsapPos, iframe, cbs);
|
|
47025
47039
|
}
|
|
47026
47040
|
return { status: "persisted" };
|
|
47027
47041
|
}
|
|
@@ -47065,7 +47079,9 @@ async function tryGsapRotationIntercept(selection, angle, animations, iframe, co
|
|
|
47065
47079
|
const resolvedAnimations = resolved2?.animations ?? workingAnimations;
|
|
47066
47080
|
let anim = resolved2?.anim && animationWritesAnyProperty(resolved2.anim, ROTATION_CHANNEL_SET) ? resolved2.anim : null;
|
|
47067
47081
|
if (!anim) {
|
|
47068
|
-
anim =
|
|
47082
|
+
anim = pickClosestToPlayhead(
|
|
47083
|
+
workingAnimations.filter((a) => animationWritesAnyProperty(a, ROTATION_CHANNEL_SET))
|
|
47084
|
+
);
|
|
47069
47085
|
}
|
|
47070
47086
|
const newRotation = roundTo3(angle);
|
|
47071
47087
|
if (!anim || isInstantHold(anim)) {
|
|
@@ -47089,35 +47105,14 @@ async function tryGsapRotationIntercept(selection, angle, animations, iframe, co
|
|
|
47089
47105
|
);
|
|
47090
47106
|
return { status: "persisted" };
|
|
47091
47107
|
}
|
|
47092
|
-
|
|
47093
|
-
const newId = await materializeIfDynamic(anim, iframe, commitMutation, selection);
|
|
47094
|
-
if (newId) anim = { ...anim, id: newId };
|
|
47095
|
-
} else if (!anim.keyframes) {
|
|
47096
|
-
const resolvedFromValues = selector ? readAllAnimatedProperties(iframe, selector, anim, "rotation") : void 0;
|
|
47097
|
-
await commitMutation(
|
|
47098
|
-
selection,
|
|
47099
|
-
{ type: "convert-to-keyframes", animationId: anim.id, resolvedFromValues },
|
|
47100
|
-
{ label: "Convert to keyframes for rotation", skipReload: true }
|
|
47101
|
-
);
|
|
47102
|
-
}
|
|
47103
|
-
const runtimeProps = readAllAnimatedProperties(iframe, selector, anim, "rotation");
|
|
47104
|
-
const backfillDefaults = { ...runtimeProps };
|
|
47105
|
-
if (!("rotation" in runtimeProps)) {
|
|
47106
|
-
backfillDefaults.rotation = readGsapProperty(iframe, selector, "rotation") ?? 0;
|
|
47107
|
-
}
|
|
47108
|
-
const properties = { ...runtimeProps, rotation: newRotation };
|
|
47109
|
-
await commitMutation(
|
|
47108
|
+
return commitValueAtPlayhead(
|
|
47110
47109
|
selection,
|
|
47111
|
-
|
|
47112
|
-
|
|
47113
|
-
|
|
47114
|
-
|
|
47115
|
-
|
|
47116
|
-
backfillDefaults
|
|
47117
|
-
},
|
|
47118
|
-
{ label: `Rotate (keyframe ${pct}%)`, softReload: true }
|
|
47110
|
+
anim,
|
|
47111
|
+
{ rotation: newRotation },
|
|
47112
|
+
iframe,
|
|
47113
|
+
{ commitMutation, fetchAnimations: fetchFallbackAnimations },
|
|
47114
|
+
{ label: "Rotate", backfill: { rotation: newRotation }, holdFromStart: true }
|
|
47119
47115
|
);
|
|
47120
|
-
return { status: "persisted" };
|
|
47121
47116
|
}
|
|
47122
47117
|
|
|
47123
47118
|
// src/hooks/keyframeCacheAstLoad.ts
|
|
@@ -47141,7 +47136,7 @@ function fetchParsedAnimations(projectId, sourceFile, options = {}) {
|
|
|
47141
47136
|
async function requestParsedAnimations(projectId, sourceFile) {
|
|
47142
47137
|
if (!isPreviewBooted(projectId) && !await whenPreviewBooted(projectId)) return null;
|
|
47143
47138
|
try {
|
|
47144
|
-
const res = await
|
|
47139
|
+
const res = await studioApiFetch(
|
|
47145
47140
|
`/api/projects/${encodeURIComponent(projectId)}/gsap-animations/${encodeURIComponent(sourceFile)}`,
|
|
47146
47141
|
// Always revalidate; an unchanged file answers 304. No per-call timestamp
|
|
47147
47142
|
// (a deterministic-render no-no).
|
|
@@ -47433,8 +47428,8 @@ var MIN_TWEEN_DURATION = 0.01;
|
|
|
47433
47428
|
var round33 = (n) => Math.round(n * 1e3) / 1e3;
|
|
47434
47429
|
var clamp5 = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
|
|
47435
47430
|
function resolveFlatTweenBoundaryRetime(opts) {
|
|
47436
|
-
const { keyframeCount, draggedTweenPct, tweenStart, tweenEnd, dropAbsTime } = opts;
|
|
47437
|
-
if (
|
|
47431
|
+
const { keyframeCount: keyframeCount2, draggedTweenPct, tweenStart, tweenEnd, dropAbsTime } = opts;
|
|
47432
|
+
if (keyframeCount2 > 0) return null;
|
|
47438
47433
|
if (draggedTweenPct !== 0 && draggedTweenPct !== 100) return { kind: "noop" };
|
|
47439
47434
|
const draggedTime = draggedTweenPct === 0 ? tweenStart : tweenEnd;
|
|
47440
47435
|
if (Math.abs(dropAbsTime - draggedTime) <= EPSILON_TIME) return { kind: "noop" };
|
|
@@ -49368,7 +49363,7 @@ function StudioAgentTools() {
|
|
|
49368
49363
|
// fetches the URL itself.
|
|
49369
49364
|
probeFrame: async (url) => {
|
|
49370
49365
|
try {
|
|
49371
|
-
const response = await
|
|
49366
|
+
const response = await studioApiFetch(url, { method: "HEAD" });
|
|
49372
49367
|
return { ok: response.ok, status: response.status };
|
|
49373
49368
|
} catch {
|
|
49374
49369
|
return { ok: false, status: 0 };
|
|
@@ -50779,6 +50774,23 @@ function useRenderClipContent({
|
|
|
50779
50774
|
);
|
|
50780
50775
|
}
|
|
50781
50776
|
|
|
50777
|
+
// src/hooks/useThumbnailStill.ts
|
|
50778
|
+
import { useMemo as useMemo49 } from "react";
|
|
50779
|
+
var LOADING = Object.freeze({ status: "loading" });
|
|
50780
|
+
var FAILED = Object.freeze({ status: "failed" });
|
|
50781
|
+
function useThumbnailStill(url, projectId, { sessionEpoch = 0, priority = "visible" } = {}) {
|
|
50782
|
+
const request = useMemo49(
|
|
50783
|
+
() => url ? compositionThumbnailRequest(url, projectId, { sessionEpoch, priority }) : null,
|
|
50784
|
+
[priority, projectId, sessionEpoch, url]
|
|
50785
|
+
);
|
|
50786
|
+
const snapshot3 = useThumbnailLease(request);
|
|
50787
|
+
const ready = snapshot3.status === "ready" && snapshot3.value.kind === "image" ? snapshot3.value.url : null;
|
|
50788
|
+
return useMemo49(
|
|
50789
|
+
() => ready ? { status: "ready", url: ready } : snapshot3.status === "error" ? FAILED : LOADING,
|
|
50790
|
+
[ready, snapshot3.status]
|
|
50791
|
+
);
|
|
50792
|
+
}
|
|
50793
|
+
|
|
50782
50794
|
// src/components/editor/SourceEditor.tsx
|
|
50783
50795
|
import { useRef as useRef82, useCallback as useCallback76, useEffect as useEffect68, memo as memo35 } from "react";
|
|
50784
50796
|
import {
|
|
@@ -51002,13 +51014,13 @@ var SourceEditor = memo35(function SourceEditor2({
|
|
|
51002
51014
|
});
|
|
51003
51015
|
|
|
51004
51016
|
// src/components/editor/PropertyPanel.tsx
|
|
51005
|
-
import { memo as memo39, useMemo as
|
|
51017
|
+
import { memo as memo39, useMemo as useMemo65, useRef as useRef113, useState as useState101 } from "react";
|
|
51006
51018
|
|
|
51007
51019
|
// src/components/editor/InspectorHeaderActions.tsx
|
|
51008
51020
|
import { Eye as Eye3, EyeSlash as EyeSlash2 } from "@phosphor-icons/react";
|
|
51009
51021
|
|
|
51010
51022
|
// src/contexts/DesignPanelInputContext.tsx
|
|
51011
|
-
import { useCallback as useCallback77, useContext as useContext12, useMemo as
|
|
51023
|
+
import { useCallback as useCallback77, useContext as useContext12, useMemo as useMemo50 } from "react";
|
|
51012
51024
|
|
|
51013
51025
|
// src/utils/designInputTracking.ts
|
|
51014
51026
|
var COALESCE_WINDOW_MS = 600;
|
|
@@ -51051,7 +51063,7 @@ function DesignPanelInputProvider({
|
|
|
51051
51063
|
children
|
|
51052
51064
|
}) {
|
|
51053
51065
|
const parent = useContext12(DesignPanelInputContext);
|
|
51054
|
-
const value =
|
|
51066
|
+
const value = useMemo50(
|
|
51055
51067
|
() => ({ ui: ui ?? parent.ui, section: section ?? parent.section }),
|
|
51056
51068
|
[ui, section, parent.ui, parent.section]
|
|
51057
51069
|
);
|
|
@@ -52716,7 +52728,7 @@ function MediaSection({
|
|
|
52716
52728
|
import { isHfColorGradingActive as isHfColorGradingActive2 } from "@hyperframes/core/color-grading";
|
|
52717
52729
|
|
|
52718
52730
|
// src/components/editor/propertyPanelColorGradingControls.tsx
|
|
52719
|
-
import { useMemo as
|
|
52731
|
+
import { useMemo as useMemo51, useRef as useRef87, useState as useState63 } from "react";
|
|
52720
52732
|
import {
|
|
52721
52733
|
HF_COLOR_GRADING_PRESETS,
|
|
52722
52734
|
normalizeHfColorGrading as normalizeHfColorGrading2
|
|
@@ -53160,7 +53172,7 @@ function ColorGradingControls({
|
|
|
53160
53172
|
const [detailSettings, setDetailSettings] = useState63(null);
|
|
53161
53173
|
const [lutImporting, setLutImporting] = useState63(false);
|
|
53162
53174
|
const [lutImportError, setLutImportError] = useState63(null);
|
|
53163
|
-
const lutAssets =
|
|
53175
|
+
const lutAssets = useMemo51(
|
|
53164
53176
|
() => assets.filter((asset) => LUT_EXT.test(asset)).sort((a, b) => a.localeCompare(b)),
|
|
53165
53177
|
[assets]
|
|
53166
53178
|
);
|
|
@@ -53440,7 +53452,7 @@ function ColorGradingControls({
|
|
|
53440
53452
|
}
|
|
53441
53453
|
|
|
53442
53454
|
// src/components/editor/useColorGradingController.ts
|
|
53443
|
-
import { useCallback as useCallback82, useEffect as useEffect75, useMemo as
|
|
53455
|
+
import { useCallback as useCallback82, useEffect as useEffect75, useMemo as useMemo52, useRef as useRef89, useState as useState65 } from "react";
|
|
53444
53456
|
import {
|
|
53445
53457
|
HF_COLOR_GRADING_ATTR as HF_COLOR_GRADING_ATTR3,
|
|
53446
53458
|
hasHfColorGradingAuthoredValues,
|
|
@@ -53803,7 +53815,7 @@ function useColorGradingController({
|
|
|
53803
53815
|
state: "pending",
|
|
53804
53816
|
message: "Waiting for runtime"
|
|
53805
53817
|
}));
|
|
53806
|
-
const selectedAssetPath =
|
|
53818
|
+
const selectedAssetPath = useMemo52(
|
|
53807
53819
|
() => selectedMediaAssetPath(element, projectId),
|
|
53808
53820
|
[element, projectId]
|
|
53809
53821
|
);
|
|
@@ -53850,7 +53862,7 @@ function useColorGradingController({
|
|
|
53850
53862
|
trackStudioPendingEdit(onSetAttributeLive(COLOR_GRADING_DATA_KEY, value));
|
|
53851
53863
|
};
|
|
53852
53864
|
}, [identityKey]);
|
|
53853
|
-
const target =
|
|
53865
|
+
const target = useMemo52(
|
|
53854
53866
|
() => ({
|
|
53855
53867
|
id: element.id ?? null,
|
|
53856
53868
|
hfId: element.hfId ?? null,
|
|
@@ -53871,7 +53883,7 @@ function useColorGradingController({
|
|
|
53871
53883
|
return;
|
|
53872
53884
|
}
|
|
53873
53885
|
const controller = new AbortController();
|
|
53874
|
-
|
|
53886
|
+
studioApiFetch(cacheKey, { signal: controller.signal }).then(async (response) => {
|
|
53875
53887
|
if (!response.ok) return { ok: false };
|
|
53876
53888
|
const data = await response.json();
|
|
53877
53889
|
return { ok: true, metadata: data?.metadata ?? null };
|
|
@@ -54830,7 +54842,7 @@ function ColorField({
|
|
|
54830
54842
|
}
|
|
54831
54843
|
|
|
54832
54844
|
// src/components/editor/propertyPanelFont.tsx
|
|
54833
|
-
import { useEffect as useEffect77, useMemo as
|
|
54845
|
+
import { useEffect as useEffect77, useMemo as useMemo53, useRef as useRef91, useState as useState67, useSyncExternalStore as useSyncExternalStore8 } from "react";
|
|
54834
54846
|
|
|
54835
54847
|
// src/components/editor/fontAssets.ts
|
|
54836
54848
|
var FONT_EXT_RE = /\.(eot|otf|ttc|ttf|woff2?)$/i;
|
|
@@ -54945,7 +54957,7 @@ var fontLists = {
|
|
|
54945
54957
|
var fontListsRequest = null;
|
|
54946
54958
|
var fontListListeners = /* @__PURE__ */ new Set();
|
|
54947
54959
|
async function fetchFontList(url) {
|
|
54948
|
-
const data = await (await
|
|
54960
|
+
const data = await (await studioApiFetch(url)).json();
|
|
54949
54961
|
if (!Array.isArray(data.fonts)) throw new Error(`${url} returned no font list`);
|
|
54950
54962
|
return data.fonts;
|
|
54951
54963
|
}
|
|
@@ -55076,13 +55088,13 @@ function FontFamilyField({
|
|
|
55076
55088
|
setImportingFonts(false);
|
|
55077
55089
|
}
|
|
55078
55090
|
};
|
|
55079
|
-
const projectFontAssets =
|
|
55091
|
+
const projectFontAssets = useMemo53(
|
|
55080
55092
|
() => uniqueFontOptions(
|
|
55081
55093
|
importedFonts.map((f) => ({ family: f.family, source: "Imported" }))
|
|
55082
55094
|
),
|
|
55083
55095
|
[importedFonts]
|
|
55084
55096
|
);
|
|
55085
|
-
const options =
|
|
55097
|
+
const options = useMemo53(() => {
|
|
55086
55098
|
if (!open) return [];
|
|
55087
55099
|
const documentFonts = collectDocumentFontFamilies();
|
|
55088
55100
|
return sortFontOptions(
|
|
@@ -55098,7 +55110,7 @@ function FontFamilyField({
|
|
|
55098
55110
|
])
|
|
55099
55111
|
);
|
|
55100
55112
|
}, [open, currentFamily, lists, localFonts, projectFontAssets]);
|
|
55101
|
-
const filteredOptions =
|
|
55113
|
+
const filteredOptions = useMemo53(() => {
|
|
55102
55114
|
const matches = options.filter((o) => fontMatchesQuery(o.family, query));
|
|
55103
55115
|
if (query.trim()) return matches.slice(0, 200);
|
|
55104
55116
|
const bySource = /* @__PURE__ */ new Map();
|
|
@@ -55128,7 +55140,7 @@ function FontFamilyField({
|
|
|
55128
55140
|
};
|
|
55129
55141
|
const importSystemFont = async (family) => {
|
|
55130
55142
|
if (!onImportFonts) return null;
|
|
55131
|
-
const response = await
|
|
55143
|
+
const response = await studioApiFetch(`/api/fonts/file?family=${encodeURIComponent(family)}`);
|
|
55132
55144
|
if (!response.ok) return null;
|
|
55133
55145
|
const blob = await response.blob();
|
|
55134
55146
|
const ext2 = response.headers.get("Content-Disposition")?.match(/\.(\w+)"?$/)?.[1] ?? "ttf";
|
|
@@ -55334,7 +55346,7 @@ function FontFamilyField({
|
|
|
55334
55346
|
import { useEffect as useEffect79 } from "react";
|
|
55335
55347
|
|
|
55336
55348
|
// src/components/panels/VariablesBindElement.tsx
|
|
55337
|
-
import { useMemo as
|
|
55349
|
+
import { useMemo as useMemo54, useState as useState69 } from "react";
|
|
55338
55350
|
|
|
55339
55351
|
// src/components/panels/VariablesValueControls.tsx
|
|
55340
55352
|
import { useState as useState68 } from "react";
|
|
@@ -55616,7 +55628,7 @@ function VariablesBindElement({
|
|
|
55616
55628
|
}) {
|
|
55617
55629
|
const [activeKey, setActiveKey] = useState69(null);
|
|
55618
55630
|
const [idDraft, setIdDraft] = useState69("");
|
|
55619
|
-
const actions =
|
|
55631
|
+
const actions = useMemo54(() => buildBindActions(selection, sdkSession), [selection, sdkSession]);
|
|
55620
55632
|
if (actions.length === 0) return null;
|
|
55621
55633
|
const active = actions.find((a) => a.key === activeKey) ?? null;
|
|
55622
55634
|
const trimmedId = sanitizeId(idDraft);
|
|
@@ -55727,7 +55739,7 @@ function uniqueId(base2, existing) {
|
|
|
55727
55739
|
}
|
|
55728
55740
|
|
|
55729
55741
|
// src/contexts/VariablePromoteContext.tsx
|
|
55730
|
-
import { useContext as useContext13, useEffect as useEffect78, useMemo as
|
|
55742
|
+
import { useContext as useContext13, useEffect as useEffect78, useMemo as useMemo55, useState as useState70 } from "react";
|
|
55731
55743
|
import { jsx as jsx129 } from "react/jsx-runtime";
|
|
55732
55744
|
var VariablePromoteContext = createStableContext(
|
|
55733
55745
|
"VariablePromoteContext",
|
|
@@ -55750,15 +55762,15 @@ function VariablePromoteProvider({
|
|
|
55750
55762
|
if (!session) return;
|
|
55751
55763
|
return session.on("change", () => setRevision((r) => r + 1));
|
|
55752
55764
|
}, [session]);
|
|
55753
|
-
const actions =
|
|
55765
|
+
const actions = useMemo55(() => {
|
|
55754
55766
|
if (!session || !selection) return [];
|
|
55755
55767
|
return buildBindActions(selection, session);
|
|
55756
55768
|
}, [session, selection, revision]);
|
|
55757
|
-
const declarations =
|
|
55769
|
+
const declarations = useMemo55(() => {
|
|
55758
55770
|
if (!session) return [];
|
|
55759
55771
|
return session.getVariableDeclarations();
|
|
55760
55772
|
}, [session, revision]);
|
|
55761
|
-
const value =
|
|
55773
|
+
const value = useMemo55(
|
|
55762
55774
|
() => ({ session, selection, actions, declarations, persist: persist2, onPersistError }),
|
|
55763
55775
|
[session, selection, actions, declarations, persist2, onPersistError]
|
|
55764
55776
|
);
|
|
@@ -55767,7 +55779,7 @@ function VariablePromoteProvider({
|
|
|
55767
55779
|
function useVariablePromoteChannel(channel) {
|
|
55768
55780
|
const ctx3 = useContext13(VariablePromoteContext);
|
|
55769
55781
|
const key2 = channel.kind === "style" ? `style:${channel.prop}` : channel.kind;
|
|
55770
|
-
return
|
|
55782
|
+
return useMemo55(() => {
|
|
55771
55783
|
if (!ctx3 || !ctx3.session || !ctx3.selection?.hfId) return null;
|
|
55772
55784
|
const { session, selection, actions, declarations, persist: persist2, onPersistError } = ctx3;
|
|
55773
55785
|
const hfId = selection.hfId;
|
|
@@ -56191,7 +56203,7 @@ function insertGradientStop(model, position) {
|
|
|
56191
56203
|
}
|
|
56192
56204
|
|
|
56193
56205
|
// src/components/editor/propertyPanelFill.tsx
|
|
56194
|
-
import { useMemo as
|
|
56206
|
+
import { useMemo as useMemo56, useRef as useRef92, useState as useState71 } from "react";
|
|
56195
56207
|
|
|
56196
56208
|
// src/components/icons/ReverseGradientIcon.tsx
|
|
56197
56209
|
import { jsx as jsx131, jsxs as jsxs97 } from "react/jsx-runtime";
|
|
@@ -56266,8 +56278,8 @@ function ImageFillField({
|
|
|
56266
56278
|
const fileInputRef = useRef92(null);
|
|
56267
56279
|
const [uploading, setUploading] = useState71(false);
|
|
56268
56280
|
const [uploadError, setUploadError] = useState71(null);
|
|
56269
|
-
const imageAssets =
|
|
56270
|
-
const selectedAsset =
|
|
56281
|
+
const imageAssets = useMemo56(() => assets.filter((a) => IMAGE_EXT.test(a)), [assets]);
|
|
56282
|
+
const selectedAsset = useMemo56(
|
|
56271
56283
|
() => resolveSelectedAsset(value, sourceFile, imageAssets),
|
|
56272
56284
|
[imageAssets, sourceFile, value]
|
|
56273
56285
|
);
|
|
@@ -57734,7 +57746,7 @@ import { useCallback as useCallback87, useState as useState76 } from "react";
|
|
|
57734
57746
|
import { useShallow } from "zustand/react/shallow";
|
|
57735
57747
|
|
|
57736
57748
|
// src/components/editor/AnimationCard.tsx
|
|
57737
|
-
import { memo as memo37, useCallback as useCallback86, useEffect as useEffect82, useMemo as
|
|
57749
|
+
import { memo as memo37, useCallback as useCallback86, useEffect as useEffect82, useMemo as useMemo57, useRef as useRef95, useState as useState75 } from "react";
|
|
57738
57750
|
import { SUPPORTED_EASES, SUPPORTED_PROPS } from "@hyperframes/core/gsap-constants";
|
|
57739
57751
|
|
|
57740
57752
|
// src/components/editor/gsapAnimationHelpers.ts
|
|
@@ -58275,21 +58287,21 @@ var AnimationCard = memo37(function AnimationCard2({
|
|
|
58275
58287
|
segment?.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
58276
58288
|
pendingAutoScrollRef.current = false;
|
|
58277
58289
|
}, [expandedKfPct]);
|
|
58278
|
-
const usedProps =
|
|
58290
|
+
const usedProps = useMemo57(
|
|
58279
58291
|
() => new Set(Object.keys(animation.properties)),
|
|
58280
58292
|
[animation.properties]
|
|
58281
58293
|
);
|
|
58282
|
-
const availableProps =
|
|
58294
|
+
const availableProps = useMemo57(
|
|
58283
58295
|
() => SUPPORTED_PROPS.filter(
|
|
58284
58296
|
(p) => !usedProps.has(p) && (animation.method === "set" || !BOOLEAN_PROPS.has(p))
|
|
58285
58297
|
),
|
|
58286
58298
|
[usedProps, animation.method]
|
|
58287
58299
|
);
|
|
58288
|
-
const usedFromProps =
|
|
58300
|
+
const usedFromProps = useMemo57(
|
|
58289
58301
|
() => new Set(Object.keys(animation.fromProperties ?? {})),
|
|
58290
58302
|
[animation.fromProperties]
|
|
58291
58303
|
);
|
|
58292
|
-
const availableFromProps =
|
|
58304
|
+
const availableFromProps = useMemo57(
|
|
58293
58305
|
() => SUPPORTED_PROPS.filter((p) => !usedFromProps.has(p) && !BOOLEAN_PROPS.has(p)),
|
|
58294
58306
|
[usedFromProps]
|
|
58295
58307
|
);
|
|
@@ -58336,7 +58348,7 @@ var AnimationCard = memo37(function AnimationCard2({
|
|
|
58336
58348
|
const easeName = (animation.keyframes ? animation.keyframes.easeEach : void 0) ?? animation.ease ?? "none";
|
|
58337
58349
|
const easeLabel = easeName.startsWith("custom(") ? "Custom curve" : EASE_LABELS[easeName] ?? easeName;
|
|
58338
58350
|
const endTime = typeof animation.position === "number" ? animation.position + (animation.duration ?? 0) : animation.position;
|
|
58339
|
-
const summary =
|
|
58351
|
+
const summary = useMemo57(() => buildTweenSummary(animation), [animation]);
|
|
58340
58352
|
const setKeys = Object.keys(animation.properties);
|
|
58341
58353
|
if (animation.method === "set" && // `every` is vacuously true on an empty bag — require at least one key so a
|
|
58342
58354
|
// property-less set doesn't masquerade as a position row.
|
|
@@ -59484,7 +59496,7 @@ function PropertyPanel3dTransform({
|
|
|
59484
59496
|
}
|
|
59485
59497
|
|
|
59486
59498
|
// src/components/editor/PropertyPanelFlat.tsx
|
|
59487
|
-
import { useEffect as useEffect103, useMemo as
|
|
59499
|
+
import { useEffect as useEffect103, useMemo as useMemo64, useRef as useRef112, useState as useState100 } from "react";
|
|
59488
59500
|
import { useShallow as useShallow2 } from "zustand/react/shallow";
|
|
59489
59501
|
|
|
59490
59502
|
// src/components/editor/audioFxSummary.ts
|
|
@@ -61654,7 +61666,7 @@ function motionSectionLabel(args) {
|
|
|
61654
61666
|
}
|
|
61655
61667
|
|
|
61656
61668
|
// src/components/editor/propertyPanelAudioFxGroup.tsx
|
|
61657
|
-
import { useMemo as
|
|
61669
|
+
import { useMemo as useMemo60, useState as useState88 } from "react";
|
|
61658
61670
|
import {
|
|
61659
61671
|
HF_AUDIO_FX_ATTR as HF_AUDIO_FX_ATTR11,
|
|
61660
61672
|
HF_AUDIO_FX_DATA_KEY as HF_AUDIO_FX_DATA_KEY2,
|
|
@@ -61674,7 +61686,7 @@ import {
|
|
|
61674
61686
|
} from "@hyperframes/core/audio-automation";
|
|
61675
61687
|
|
|
61676
61688
|
// src/components/editor/propertyPanelFxSection.tsx
|
|
61677
|
-
import { useCallback as useCallback90, useEffect as useEffect90, useMemo as
|
|
61689
|
+
import { useCallback as useCallback90, useEffect as useEffect90, useMemo as useMemo59, useRef as useRef100, useState as useState86 } from "react";
|
|
61678
61690
|
|
|
61679
61691
|
// src/components/editor/audioFxRevealTarget.ts
|
|
61680
61692
|
import { parseAutomationTarget as parseAutomationTarget2 } from "@hyperframes/core/audio-automation";
|
|
@@ -62632,7 +62644,7 @@ function FxEqModule({
|
|
|
62632
62644
|
import { getAudioFxPreset as getAudioFxPreset4 } from "@hyperframes/core/audio-fx-presets";
|
|
62633
62645
|
|
|
62634
62646
|
// src/components/editor/propertyPanelFxNodeRow.tsx
|
|
62635
|
-
import { useMemo as
|
|
62647
|
+
import { useMemo as useMemo58, useState as useState85 } from "react";
|
|
62636
62648
|
import {
|
|
62637
62649
|
defaultAudioFxParams as defaultAudioFxParams4,
|
|
62638
62650
|
getAudioFxDef as getAudioFxDef4
|
|
@@ -63069,11 +63081,11 @@ function FxNodeRow({
|
|
|
63069
63081
|
}) {
|
|
63070
63082
|
const trackInput = useTrackDesignInput();
|
|
63071
63083
|
const registryDef = getAudioFxDef4(node.type);
|
|
63072
|
-
const def =
|
|
63084
|
+
const def = useMemo58(() => registryDef ? plainDef(registryDef) : null, [registryDef]);
|
|
63073
63085
|
const primary = registryDef ? primaryParamOf(registryDef) : null;
|
|
63074
63086
|
const profile = getAudioFxProfile2(node.type);
|
|
63075
|
-
const derived =
|
|
63076
|
-
const onlyPrimary =
|
|
63087
|
+
const derived = useMemo58(() => profileParam(node.type), [node.type]);
|
|
63088
|
+
const onlyPrimary = useMemo58(
|
|
63077
63089
|
() => def && primary ? { ...def, params: def.params.filter((p) => p.key === primary) } : def,
|
|
63078
63090
|
[def, primary]
|
|
63079
63091
|
);
|
|
@@ -63745,12 +63757,12 @@ function FxSection({
|
|
|
63745
63757
|
[chain.nodes, mutate, onRemoveNodeAutomation, trackKind]
|
|
63746
63758
|
);
|
|
63747
63759
|
const [carveOpen, setCarveOpen] = useState86(true);
|
|
63748
|
-
const carveNodes =
|
|
63749
|
-
const handBuilt =
|
|
63760
|
+
const carveNodes = useMemo59(() => chain.nodes.filter((n) => n.fromCarve), [chain.nodes]);
|
|
63761
|
+
const handBuilt = useMemo59(
|
|
63750
63762
|
() => chain.nodes.map((node, i) => ({ node, i })).filter(({ node }) => !node.fromCarve && !node.fromEq),
|
|
63751
63763
|
[chain.nodes]
|
|
63752
63764
|
);
|
|
63753
|
-
const runs =
|
|
63765
|
+
const runs = useMemo59(() => {
|
|
63754
63766
|
const out = [];
|
|
63755
63767
|
for (const item of handBuilt) {
|
|
63756
63768
|
const preset = item.node.fromPreset;
|
|
@@ -63761,8 +63773,8 @@ function FxSection({
|
|
|
63761
63773
|
return out;
|
|
63762
63774
|
}, [handBuilt]);
|
|
63763
63775
|
const [collapsedRuns, setCollapsedRuns] = useState86(/* @__PURE__ */ new Set());
|
|
63764
|
-
const eqIds =
|
|
63765
|
-
const positions =
|
|
63776
|
+
const eqIds = useMemo59(() => audioEqIds(chain), [chain]);
|
|
63777
|
+
const positions = useMemo59(() => {
|
|
63766
63778
|
const map = /* @__PURE__ */ new Map();
|
|
63767
63779
|
let at = (showCarve ? 1 : 0) + eqIds.length;
|
|
63768
63780
|
for (const { i } of handBuilt) map.set(i, ++at);
|
|
@@ -64192,7 +64204,7 @@ function useFxLevelling(element, chain, automation, onSetAttributeQuiet, onSetAt
|
|
|
64192
64204
|
if (cached5?.src === src) return cached5;
|
|
64193
64205
|
const Ctor = window.OfflineAudioContext ?? window.webkitOfflineAudioContext;
|
|
64194
64206
|
if (!Ctor) return null;
|
|
64195
|
-
const res = await
|
|
64207
|
+
const res = await studioApiFetch(new URL(src, doc.baseURI).href);
|
|
64196
64208
|
const buffer = await new Ctor(1, 1, DECODE_SAMPLE_RATE2).decodeAudioData(
|
|
64197
64209
|
await res.arrayBuffer()
|
|
64198
64210
|
);
|
|
@@ -64391,7 +64403,7 @@ function AudioFxGroup({
|
|
|
64391
64403
|
const removeNodeAutomation = (nodeId) => removeNodesAutomation([nodeId]);
|
|
64392
64404
|
const [analysing, setAnalysing] = useState88(false);
|
|
64393
64405
|
const storeElements = usePlayerStore((s) => s.elements);
|
|
64394
|
-
const signalPath =
|
|
64406
|
+
const signalPath = useMemo60(() => {
|
|
64395
64407
|
const doc = element.element?.ownerDocument;
|
|
64396
64408
|
return audioFxSignalPath(
|
|
64397
64409
|
element.tagName?.toLowerCase(),
|
|
@@ -65064,7 +65076,7 @@ function createGsapLivePreview(iframeRef) {
|
|
|
65064
65076
|
}
|
|
65065
65077
|
|
|
65066
65078
|
// src/components/editor/propertyPanelFlatColorGradingSection.tsx
|
|
65067
|
-
import { useEffect as useEffect100, useMemo as
|
|
65079
|
+
import { useEffect as useEffect100, useMemo as useMemo62, useRef as useRef111, useState as useState96 } from "react";
|
|
65068
65080
|
import {
|
|
65069
65081
|
HF_COLOR_GRADING_GRADE_PRESETS,
|
|
65070
65082
|
normalizeHfColorGrading as normalizeHfColorGrading6,
|
|
@@ -65099,7 +65111,7 @@ function presetPreviewHandlers({
|
|
|
65099
65111
|
import { useState as useState92 } from "react";
|
|
65100
65112
|
|
|
65101
65113
|
// src/components/editor/propertyPanelColorCurveGraph.tsx
|
|
65102
|
-
import { useMemo as
|
|
65114
|
+
import { useMemo as useMemo61, useRef as useRef104 } from "react";
|
|
65103
65115
|
import {
|
|
65104
65116
|
compileHfColorCurve,
|
|
65105
65117
|
compileHfHueCurve,
|
|
@@ -65287,8 +65299,8 @@ function CurveGraph({
|
|
|
65287
65299
|
onCancel
|
|
65288
65300
|
}) {
|
|
65289
65301
|
const pointerRef = useRef104(null);
|
|
65290
|
-
const samples =
|
|
65291
|
-
const path =
|
|
65302
|
+
const samples = useMemo61(() => samplesFor(points, tab), [points, tab]);
|
|
65303
|
+
const path = useMemo61(() => curvePath(samples, tab), [samples, tab]);
|
|
65292
65304
|
const selectRelativePoint = (offset) => {
|
|
65293
65305
|
if (points.length === 0) return;
|
|
65294
65306
|
const current = selectedIndex ?? (offset > 0 ? -1 : 0);
|
|
@@ -67078,14 +67090,14 @@ function FlatColorGradingSection({
|
|
|
67078
67090
|
const lutInputRef = useRef111(null);
|
|
67079
67091
|
const [lutOpen, setLutOpen] = useState96(false);
|
|
67080
67092
|
const [detailSettingsOpen, setDetailSettingsOpen] = useState96(null);
|
|
67081
|
-
const lutAssets =
|
|
67093
|
+
const lutAssets = useMemo62(
|
|
67082
67094
|
() => assets.filter((asset) => LUT_EXT.test(asset)).sort((a, b) => a.localeCompare(b)),
|
|
67083
67095
|
[assets]
|
|
67084
67096
|
);
|
|
67085
67097
|
const lut = grading.lut;
|
|
67086
67098
|
const selectedLutName = lut?.src ? lut.src.split("/").pop() ?? lut.src : null;
|
|
67087
|
-
const resolvedGrading =
|
|
67088
|
-
const secondaryInputGrading =
|
|
67099
|
+
const resolvedGrading = useMemo62(() => resolveColorGrading(grading), [grading]);
|
|
67100
|
+
const secondaryInputGrading = useMemo62(
|
|
67089
67101
|
() => resolveColorGrading({
|
|
67090
67102
|
intensity: 1,
|
|
67091
67103
|
adjust: resolvedGrading.adjust,
|
|
@@ -67103,7 +67115,7 @@ function FlatColorGradingSection({
|
|
|
67103
67115
|
]
|
|
67104
67116
|
);
|
|
67105
67117
|
const actions = createColorGradingActions(grading, onCommitColorGrading);
|
|
67106
|
-
const scopesRefreshKey =
|
|
67118
|
+
const scopesRefreshKey = useMemo62(() => serializeHfColorGrading2(grading), [grading]);
|
|
67107
67119
|
useEffect100(() => {
|
|
67108
67120
|
if (presetPreviews.status === "idle") onRequestPresetPreviews();
|
|
67109
67121
|
}, [onRequestPresetPreviews, presetPreviews.status]);
|
|
@@ -68233,7 +68245,7 @@ function FlatEffectsSection({
|
|
|
68233
68245
|
import { useState as useState99 } from "react";
|
|
68234
68246
|
|
|
68235
68247
|
// src/hooks/useBlockCatalog.ts
|
|
68236
|
-
import { useState as useState98, useEffect as useEffect102, useMemo as
|
|
68248
|
+
import { useState as useState98, useEffect as useEffect102, useMemo as useMemo63 } from "react";
|
|
68237
68249
|
|
|
68238
68250
|
// src/utils/blockCategories.ts
|
|
68239
68251
|
import {
|
|
@@ -68291,7 +68303,7 @@ function getCategoryColors(category) {
|
|
|
68291
68303
|
var catalogCache = null;
|
|
68292
68304
|
var catalogRequest = null;
|
|
68293
68305
|
function loadCatalog() {
|
|
68294
|
-
catalogRequest ??=
|
|
68306
|
+
catalogRequest ??= studioApiFetch("/api/registry/blocks").then((response) => {
|
|
68295
68307
|
if (!response.ok) throw new Error("Failed to load catalog");
|
|
68296
68308
|
return response.json();
|
|
68297
68309
|
}).then((items) => {
|
|
@@ -68332,7 +68344,7 @@ function useBlockCatalog() {
|
|
|
68332
68344
|
cancelled = true;
|
|
68333
68345
|
};
|
|
68334
68346
|
}, []);
|
|
68335
|
-
const filteredBlocks =
|
|
68347
|
+
const filteredBlocks = useMemo63(() => {
|
|
68336
68348
|
let result = blocks;
|
|
68337
68349
|
if (category) {
|
|
68338
68350
|
result = result.filter((b) => b.category === category);
|
|
@@ -68648,7 +68660,7 @@ function PropertyPanelFlat({
|
|
|
68648
68660
|
onSetAttributeQuiet ?? onSetAttributeLive,
|
|
68649
68661
|
linkedSpeed
|
|
68650
68662
|
);
|
|
68651
|
-
const audioGroupLabel =
|
|
68663
|
+
const audioGroupLabel = useMemo64(() => {
|
|
68652
68664
|
const doc = element.element?.ownerDocument;
|
|
68653
68665
|
const id = element.id;
|
|
68654
68666
|
if (!doc || !id) return void 0;
|
|
@@ -69214,12 +69226,12 @@ var PropertyPanel = memo39(function PropertyPanel2(props) {
|
|
|
69214
69226
|
const cacheEntry = usePlayerStore((s) => s.keyframeCache.get(cacheElementKey));
|
|
69215
69227
|
const iframeRef = previewIframeRef ?? { current: null };
|
|
69216
69228
|
const gsapAnimIdForMemo = element ? gsapAnimations?.find((a) => a.keyframes)?.id ?? gsapAnimations?.[0]?.id ?? null : null;
|
|
69217
|
-
const gsapRuntimeValues =
|
|
69229
|
+
const gsapRuntimeValues = useMemo65(
|
|
69218
69230
|
() => element ? readGsapRuntimeValuesForPanel(gsapAnimIdForMemo, gsapAnimations, element, iframeRef) : null,
|
|
69219
69231
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- iframeRef is stable; currentTime drives re-reads during playback
|
|
69220
69232
|
[gsapAnimIdForMemo, gsapAnimations, element, currentTime]
|
|
69221
69233
|
);
|
|
69222
|
-
const gsapBorderRadius =
|
|
69234
|
+
const gsapBorderRadius = useMemo65(
|
|
69223
69235
|
() => element ? readGsapBorderRadiusForPanel(gsapRuntimeValues, gsapAnimations, element, iframeRef) : null,
|
|
69224
69236
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
69225
69237
|
[gsapRuntimeValues, gsapAnimations, element, currentTime]
|
|
@@ -69596,11 +69608,11 @@ var PropertyPanel = memo39(function PropertyPanel2(props) {
|
|
|
69596
69608
|
});
|
|
69597
69609
|
|
|
69598
69610
|
// src/components/editor/FileTree.tsx
|
|
69599
|
-
import { memo as memo41, useState as useState103, useCallback as useCallback92, useMemo as
|
|
69611
|
+
import { memo as memo41, useState as useState103, useCallback as useCallback92, useMemo as useMemo67, useRef as useRef115 } from "react";
|
|
69600
69612
|
import { Plus as Plus2, FolderSimplePlus as FolderSimplePlus2 } from "@phosphor-icons/react";
|
|
69601
69613
|
|
|
69602
69614
|
// src/components/editor/FileTreeNodes.tsx
|
|
69603
|
-
import { memo as memo40, useState as useState102, useCallback as useCallback91, useMemo as
|
|
69615
|
+
import { memo as memo40, useState as useState102, useCallback as useCallback91, useMemo as useMemo66, useRef as useRef114, useEffect as useEffect104 } from "react";
|
|
69604
69616
|
import {
|
|
69605
69617
|
PencilSimple,
|
|
69606
69618
|
Copy,
|
|
@@ -70103,7 +70115,7 @@ var TreeFolder = memo40(function TreeFolder2({
|
|
|
70103
70115
|
}) {
|
|
70104
70116
|
const [isOpen, setIsOpen] = useState102(defaultOpen);
|
|
70105
70117
|
const toggle = useCallback91(() => setIsOpen((v) => !v), []);
|
|
70106
|
-
const children =
|
|
70118
|
+
const children = useMemo66(() => sortChildren(node.children), [node.children]);
|
|
70107
70119
|
const Chevron = isOpen ? ChevronDown : ChevronRight;
|
|
70108
70120
|
const isDragOver = dragOverFolder === node.fullPath;
|
|
70109
70121
|
const isRenaming = inlineInput?.mode === "rename" && inlineInput.originalPath === node.fullPath;
|
|
@@ -70234,8 +70246,8 @@ var FileTree = memo41(function FileTree2({
|
|
|
70234
70246
|
onImportFiles,
|
|
70235
70247
|
lintFindingsByFile
|
|
70236
70248
|
}) {
|
|
70237
|
-
const tree =
|
|
70238
|
-
const children =
|
|
70249
|
+
const tree = useMemo67(() => buildTree(files), [files]);
|
|
70250
|
+
const children = useMemo67(() => sortChildren(tree.children), [tree]);
|
|
70239
70251
|
const [contextMenu, setContextMenu] = useState103(null);
|
|
70240
70252
|
const [inlineInput, setInlineInput] = useState103(null);
|
|
70241
70253
|
const [deleteTarget, setDeleteTarget] = useState103(null);
|
|
@@ -70502,7 +70514,7 @@ var FileTree = memo41(function FileTree2({
|
|
|
70502
70514
|
});
|
|
70503
70515
|
|
|
70504
70516
|
// src/App.tsx
|
|
70505
|
-
import { useState as useState158, useCallback as useCallback194, useRef as useRef187, useMemo as
|
|
70517
|
+
import { useState as useState158, useCallback as useCallback194, useRef as useRef187, useMemo as useMemo89 } from "react";
|
|
70506
70518
|
|
|
70507
70519
|
// src/hooks/useStableHandlers.ts
|
|
70508
70520
|
import { useRef as useRef116 } from "react";
|
|
@@ -70534,9 +70546,9 @@ function useStableHandlers(value, scope) {
|
|
|
70534
70546
|
}
|
|
70535
70547
|
|
|
70536
70548
|
// src/hooks/useShellSlices.ts
|
|
70537
|
-
import { useMemo as
|
|
70549
|
+
import { useMemo as useMemo68 } from "react";
|
|
70538
70550
|
function useHistoryFlags({ canUndo, canRedo, undoLabel, redoLabel }) {
|
|
70539
|
-
return
|
|
70551
|
+
return useMemo68(
|
|
70540
70552
|
() => ({ canUndo, canRedo, undoLabel, redoLabel }),
|
|
70541
70553
|
[canUndo, canRedo, undoLabel, redoLabel]
|
|
70542
70554
|
);
|
|
@@ -70552,7 +70564,7 @@ function useToolbarSession(session) {
|
|
|
70552
70564
|
handleGsapConvertToKeyframes,
|
|
70553
70565
|
handleGsapRemoveKeyframe
|
|
70554
70566
|
} = session;
|
|
70555
|
-
return
|
|
70567
|
+
return useMemo68(
|
|
70556
70568
|
() => ({
|
|
70557
70569
|
domEditSelection,
|
|
70558
70570
|
selectedGsapAnimations,
|
|
@@ -70625,7 +70637,7 @@ function useRightPanelIntent() {
|
|
|
70625
70637
|
}
|
|
70626
70638
|
|
|
70627
70639
|
// src/components/renders/useRenderQueue.ts
|
|
70628
|
-
import { useState as useState105, useEffect as useEffect107, useCallback as useCallback95, useRef as useRef119, useMemo as
|
|
70640
|
+
import { useState as useState105, useEffect as useEffect107, useCallback as useCallback95, useRef as useRef119, useMemo as useMemo69 } from "react";
|
|
70629
70641
|
|
|
70630
70642
|
// src/components/renders/serverError.ts
|
|
70631
70643
|
async function readServerError(res) {
|
|
@@ -70665,7 +70677,7 @@ function parseStatus(body) {
|
|
|
70665
70677
|
}
|
|
70666
70678
|
async function probe() {
|
|
70667
70679
|
try {
|
|
70668
|
-
const res = await
|
|
70680
|
+
const res = await studioApiFetch("/api/environment/ffmpeg");
|
|
70669
70681
|
return res.ok ? parseStatus(await res.json()) : null;
|
|
70670
70682
|
} catch {
|
|
70671
70683
|
return null;
|
|
@@ -70889,7 +70901,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
|
|
|
70889
70901
|
const loadRenders = useCallback95(async () => {
|
|
70890
70902
|
if (!projectId) return;
|
|
70891
70903
|
try {
|
|
70892
|
-
const res = await
|
|
70904
|
+
const res = await studioApiFetch(buildProjectApiPath(projectId, `/renders`));
|
|
70893
70905
|
if (!res.ok) {
|
|
70894
70906
|
setLoadError(`Couldn't load render history (server error ${res.status}).`);
|
|
70895
70907
|
return;
|
|
@@ -70976,7 +70988,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
|
|
|
70976
70988
|
}
|
|
70977
70989
|
let res;
|
|
70978
70990
|
try {
|
|
70979
|
-
res = await
|
|
70991
|
+
res = await studioApiFetch(buildProjectApiPath(projectId, `/render`), {
|
|
70980
70992
|
method: "POST",
|
|
70981
70993
|
headers: { "Content-Type": "application/json" },
|
|
70982
70994
|
body: JSON.stringify(body)
|
|
@@ -71069,7 +71081,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
|
|
|
71069
71081
|
)
|
|
71070
71082
|
);
|
|
71071
71083
|
try {
|
|
71072
|
-
const res = await
|
|
71084
|
+
const res = await studioApiFetch(`/api/render/${jobId}/cancel`, { method: "POST" });
|
|
71073
71085
|
if (!res.ok && res.status !== 404) {
|
|
71074
71086
|
setActionError("Couldn't cancel on the server \u2014 the render may still be running.");
|
|
71075
71087
|
return;
|
|
@@ -71091,7 +71103,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
|
|
|
71091
71103
|
setActionError(null);
|
|
71092
71104
|
closeActiveEventSource(jobId);
|
|
71093
71105
|
try {
|
|
71094
|
-
const res = await
|
|
71106
|
+
const res = await studioApiFetch(`/api/render/${jobId}`, { method: "DELETE" });
|
|
71095
71107
|
if (!res.ok) {
|
|
71096
71108
|
setActionError("Couldn't delete the render \u2014 it's still on disk.");
|
|
71097
71109
|
return;
|
|
@@ -71148,7 +71160,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
|
|
|
71148
71160
|
};
|
|
71149
71161
|
}, [projectId]);
|
|
71150
71162
|
const isRendering = jobs.some((j) => j.status === "rendering");
|
|
71151
|
-
return
|
|
71163
|
+
return useMemo69(
|
|
71152
71164
|
() => ({
|
|
71153
71165
|
jobs,
|
|
71154
71166
|
isRendering,
|
|
@@ -71574,7 +71586,7 @@ async function captureProjectProvenance(projectId, files, compositions) {
|
|
|
71574
71586
|
};
|
|
71575
71587
|
if (!scaffolded) return;
|
|
71576
71588
|
try {
|
|
71577
|
-
const res = await
|
|
71589
|
+
const res = await studioApiFetch(
|
|
71578
71590
|
buildProjectApiPath(projectId, `/files/${encodeURIComponent(CONFIG_FILE)}`)
|
|
71579
71591
|
);
|
|
71580
71592
|
if (!res.ok) return;
|
|
@@ -72195,7 +72207,7 @@ function ProjectUnreachableBanner({ projectId }) {
|
|
|
72195
72207
|
const [served, setServed] = useState110(null);
|
|
72196
72208
|
useEffect110(() => {
|
|
72197
72209
|
let cancelled = false;
|
|
72198
|
-
|
|
72210
|
+
studioApiFetch("/api/projects").then((res) => res.ok ? res.json() : { projects: [] }).then((data) => {
|
|
72199
72211
|
if (!cancelled) setServed(data.projects ?? []);
|
|
72200
72212
|
}).catch(() => {
|
|
72201
72213
|
if (!cancelled) setServed([]);
|
|
@@ -72305,11 +72317,14 @@ function useCaptionSync(projectId) {
|
|
|
72305
72317
|
}
|
|
72306
72318
|
const seqAtSave = editSeqRef.current;
|
|
72307
72319
|
const overrides = buildOverrides(state.model);
|
|
72308
|
-
|
|
72309
|
-
|
|
72310
|
-
|
|
72311
|
-
|
|
72312
|
-
|
|
72320
|
+
studioApiFetch(
|
|
72321
|
+
buildProjectApiPath(pid, `/files/${encodeURIComponent("caption-overrides.json")}`),
|
|
72322
|
+
{
|
|
72323
|
+
method: "PUT",
|
|
72324
|
+
headers: { "Content-Type": "text/plain", ...studioWriteHeaders() },
|
|
72325
|
+
body: JSON.stringify(overrides, null, 2)
|
|
72326
|
+
}
|
|
72327
|
+
).then((res) => {
|
|
72313
72328
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
72314
72329
|
if (editSeqRef.current === seqAtSave) pendingRef.current = false;
|
|
72315
72330
|
const s = useCaptionStore.getState();
|
|
@@ -72362,7 +72377,7 @@ function useCaptionSync(projectId) {
|
|
|
72362
72377
|
if (!pid) return;
|
|
72363
72378
|
let data;
|
|
72364
72379
|
try {
|
|
72365
|
-
const res = await
|
|
72380
|
+
const res = await studioApiFetch(
|
|
72366
72381
|
buildProjectApiPath(pid, `/files/${encodeURIComponent("caption-overrides.json")}`)
|
|
72367
72382
|
);
|
|
72368
72383
|
if (!res.ok) return;
|
|
@@ -72418,13 +72433,15 @@ function useCaptionSync(projectId) {
|
|
|
72418
72433
|
}
|
|
72419
72434
|
|
|
72420
72435
|
// src/hooks/usePersistentEditHistory.ts
|
|
72421
|
-
import { useCallback as useCallback99, useEffect as useEffect111, useMemo as
|
|
72436
|
+
import { useCallback as useCallback99, useEffect as useEffect111, useMemo as useMemo70, useRef as useRef126, useState as useState111 } from "react";
|
|
72422
72437
|
var EMPTY3 = { entries: [], back: null, forward: null };
|
|
72423
72438
|
var OWN_ENTRIES_KEPT = 100;
|
|
72424
72439
|
function createOwnHistory() {
|
|
72425
72440
|
const own = /* @__PURE__ */ new Map();
|
|
72426
72441
|
let next = null;
|
|
72427
72442
|
let changes = 0;
|
|
72443
|
+
let claimed = { count: 0, id: "" };
|
|
72444
|
+
const undoneIds = /* @__PURE__ */ new Set();
|
|
72428
72445
|
const remember = (id, files) => {
|
|
72429
72446
|
const known = own.get(id) ?? {};
|
|
72430
72447
|
for (const [path, { before, after }] of Object.entries(files)) {
|
|
@@ -72445,7 +72462,15 @@ function createOwnHistory() {
|
|
|
72445
72462
|
if (seen === changes) next = { undo: view.back, redo: view.forward };
|
|
72446
72463
|
},
|
|
72447
72464
|
changes: () => changes,
|
|
72465
|
+
claimCount: () => claimed.count,
|
|
72466
|
+
claimedAfter: (count) => claimed.count > count && claimed.id ? claimed.id : null,
|
|
72467
|
+
targetFor: (id, pressedAt) => !id || !undoneIds.has(id) ? id : claimed.count > pressedAt ? false : null,
|
|
72468
|
+
noteClaim: (id) => {
|
|
72469
|
+
claimed = { count: claimed.count + 1, id };
|
|
72470
|
+
},
|
|
72448
72471
|
stepped: (entry2) => {
|
|
72472
|
+
if (entry2.undoes) undoneIds.add(entry2.undoes);
|
|
72473
|
+
if (undoneIds.size > OWN_ENTRIES_KEPT) undoneIds.delete(undoneIds.values().next().value);
|
|
72449
72474
|
const undone = entry2.undoes ? own.get(entry2.undoes) : void 0;
|
|
72450
72475
|
if (!undone) return;
|
|
72451
72476
|
const swapped = Object.entries(undone).map(([path, f]) => [
|
|
@@ -72461,14 +72486,15 @@ function createOwnHistory() {
|
|
|
72461
72486
|
const paths = files ? Object.keys(files) : [];
|
|
72462
72487
|
if (!files || paths.length !== step.paths.length || !paths.every((p) => step.paths.includes(p)))
|
|
72463
72488
|
return null;
|
|
72464
|
-
const
|
|
72489
|
+
const restore2 = paths.map((path) => [
|
|
72465
72490
|
path,
|
|
72466
72491
|
{ previous: files[path].after, restored: files[path].before }
|
|
72467
72492
|
]);
|
|
72468
|
-
return { id: step.id, files: Object.fromEntries(
|
|
72493
|
+
return { id: step.id, files: Object.fromEntries(restore2) };
|
|
72469
72494
|
},
|
|
72470
72495
|
clear: () => {
|
|
72471
72496
|
own.clear();
|
|
72497
|
+
undoneIds.clear();
|
|
72472
72498
|
next = null;
|
|
72473
72499
|
changes += 1;
|
|
72474
72500
|
}
|
|
@@ -72478,8 +72504,14 @@ var DEFAULT_COALESCE_MS = 300;
|
|
|
72478
72504
|
function historyUrl(projectId, path = "") {
|
|
72479
72505
|
return `/api/projects/${encodeURIComponent(projectId)}/history${path}`;
|
|
72480
72506
|
}
|
|
72507
|
+
async function cantUndo(paths) {
|
|
72508
|
+
return { ok: false, reason: "content-mismatch", paths: paths ?? [] };
|
|
72509
|
+
}
|
|
72510
|
+
function unionPaths(...lists) {
|
|
72511
|
+
return [...new Set(lists.flatMap((list) => list ?? []))];
|
|
72512
|
+
}
|
|
72481
72513
|
async function post(url, body, headers = {}) {
|
|
72482
|
-
const response = await
|
|
72514
|
+
const response = await studioApiFetch(url, {
|
|
72483
72515
|
method: "POST",
|
|
72484
72516
|
headers: { "Content-Type": "application/json", ...headers },
|
|
72485
72517
|
body: JSON.stringify(body)
|
|
@@ -72538,9 +72570,10 @@ function usePersistentEditHistory({ projectId }) {
|
|
|
72538
72570
|
const refresh = useCallback99(async () => {
|
|
72539
72571
|
if (!projectId) return;
|
|
72540
72572
|
const seen = own.changes();
|
|
72541
|
-
const response = await
|
|
72542
|
-
const next = response?.ok ? await response.json() : EMPTY3;
|
|
72573
|
+
const response = await studioApiFetch(historyUrl(projectId)).catch(() => null);
|
|
72574
|
+
const next = response?.ok ? await response.json().catch(() => null) : EMPTY3;
|
|
72543
72575
|
if (projectIdRef.current !== projectId) return;
|
|
72576
|
+
if (!next) return console.error("The history's reply was unreadable.");
|
|
72544
72577
|
setView(next);
|
|
72545
72578
|
own.offered(seen, next);
|
|
72546
72579
|
}, [projectId, own]);
|
|
@@ -72563,7 +72596,10 @@ function usePersistentEditHistory({ projectId }) {
|
|
|
72563
72596
|
...coalesceKey && { coalesceKey, idleMs: coalesceMs ?? DEFAULT_COALESCE_MS }
|
|
72564
72597
|
});
|
|
72565
72598
|
const claimed = claimHeld(reply, label);
|
|
72566
|
-
if (claimed)
|
|
72599
|
+
if (claimed) {
|
|
72600
|
+
own.remember(claimed, files);
|
|
72601
|
+
own.noteClaim(claimed);
|
|
72602
|
+
}
|
|
72567
72603
|
heldClaimRef.current = claimed && coalesceKey ? { paths, at: Date.now() } : null;
|
|
72568
72604
|
await refresh();
|
|
72569
72605
|
},
|
|
@@ -72572,14 +72608,17 @@ function usePersistentEditHistory({ projectId }) {
|
|
|
72572
72608
|
const step = useCallback99(
|
|
72573
72609
|
async (direction, callbacks) => {
|
|
72574
72610
|
if (!projectId) return { ok: false, reason: "empty" };
|
|
72611
|
+
const candidate = direction === "undo" && callbacks.claimedAfter !== void 0 ? own.claimedAfter(callbacks.claimedAfter) : null;
|
|
72575
72612
|
const next = direction === "undo" ? view.back : view.forward;
|
|
72576
|
-
const
|
|
72613
|
+
const stepPaths = candidate ? Object.keys(own.afterOf(candidate)) : next?.paths;
|
|
72614
|
+
const paths = unionPaths(stepPaths, heldClaimRef.current?.paths);
|
|
72615
|
+
const pressedAt = own.claimCount();
|
|
72577
72616
|
own.overtake();
|
|
72578
|
-
const
|
|
72617
|
+
const attempt = async (target) => {
|
|
72579
72618
|
const previous = await readAll(paths, callbacks.readFile);
|
|
72580
72619
|
const posted = await post(
|
|
72581
|
-
historyUrl(projectId, "/step"),
|
|
72582
|
-
{ direction: direction === "undo" ? "back" : "forward" },
|
|
72620
|
+
historyUrl(projectId, target ? "/undo" : "/step"),
|
|
72621
|
+
target ? { entryId: target } : { direction: direction === "undo" ? "back" : "forward" },
|
|
72583
72622
|
studioWriteHeaders()
|
|
72584
72623
|
);
|
|
72585
72624
|
heldClaimRef.current = null;
|
|
@@ -72606,6 +72645,10 @@ function usePersistentEditHistory({ projectId }) {
|
|
|
72606
72645
|
)
|
|
72607
72646
|
};
|
|
72608
72647
|
};
|
|
72648
|
+
const run = () => {
|
|
72649
|
+
const target = own.targetFor(candidate, pressedAt);
|
|
72650
|
+
return target === false ? cantUndo(stepPaths) : attempt(target);
|
|
72651
|
+
};
|
|
72609
72652
|
return callbacks.serialize ? callbacks.serialize(paths, run) : run();
|
|
72610
72653
|
},
|
|
72611
72654
|
[projectId, view, refresh, own]
|
|
@@ -72616,7 +72659,7 @@ function usePersistentEditHistory({ projectId }) {
|
|
|
72616
72659
|
}, [own, refresh]);
|
|
72617
72660
|
const undo = useCallback99((callbacks) => step("undo", callbacks), [step]);
|
|
72618
72661
|
const redo = useCallback99((callbacks) => step("redo", callbacks), [step]);
|
|
72619
|
-
const state =
|
|
72662
|
+
const state = useMemo70(() => {
|
|
72620
72663
|
const backAt = Math.max(view.back?.endedAt ?? 0, heldClaimRef.current?.at ?? 0);
|
|
72621
72664
|
const redoAt = redoneAt(view);
|
|
72622
72665
|
return {
|
|
@@ -72637,6 +72680,7 @@ function usePersistentEditHistory({ projectId }) {
|
|
|
72637
72680
|
undo,
|
|
72638
72681
|
redo,
|
|
72639
72682
|
predict: own.predict,
|
|
72683
|
+
claims: own.claimCount,
|
|
72640
72684
|
noteOutsideChange
|
|
72641
72685
|
};
|
|
72642
72686
|
}
|
|
@@ -72701,7 +72745,7 @@ function usePanelLayout(initialState2) {
|
|
|
72701
72745
|
import { useState as useState113, useCallback as useCallback104, useRef as useRef130 } from "react";
|
|
72702
72746
|
|
|
72703
72747
|
// src/hooks/useFileTree.ts
|
|
72704
|
-
import { useState as useState112, useCallback as useCallback101, useEffect as useEffect113, useMemo as
|
|
72748
|
+
import { useState as useState112, useCallback as useCallback101, useEffect as useEffect113, useMemo as useMemo71, useRef as useRef128 } from "react";
|
|
72705
72749
|
var EMPTY_FILE_LIST = [];
|
|
72706
72750
|
function useFileTree({ projectId, projectIdRef }) {
|
|
72707
72751
|
const [fetched, setFetched] = useState112(null);
|
|
@@ -72714,7 +72758,7 @@ function useFileTree({ projectId, projectIdRef }) {
|
|
|
72714
72758
|
if (!projectId) return;
|
|
72715
72759
|
let cancelled = false;
|
|
72716
72760
|
setFetched({ projectId, loaded: false, fileTree: [], compositionPaths: [], projectDir: null });
|
|
72717
|
-
|
|
72761
|
+
studioApiFetch(buildProjectApiPath(projectId)).then((r) => {
|
|
72718
72762
|
if (!r.ok) throw new Error(`tree fetch failed: ${r.status}`);
|
|
72719
72763
|
return r.json();
|
|
72720
72764
|
}).then((data) => {
|
|
@@ -72747,7 +72791,7 @@ function useFileTree({ projectId, projectIdRef }) {
|
|
|
72747
72791
|
refreshAbortRef.current = controller;
|
|
72748
72792
|
let data;
|
|
72749
72793
|
try {
|
|
72750
|
-
const res = await
|
|
72794
|
+
const res = await studioApiFetch(buildProjectApiPath(pid), { signal: controller.signal });
|
|
72751
72795
|
data = await res.json();
|
|
72752
72796
|
} catch (err) {
|
|
72753
72797
|
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
@@ -72765,11 +72809,11 @@ function useFileTree({ projectId, projectIdRef }) {
|
|
|
72765
72809
|
);
|
|
72766
72810
|
}
|
|
72767
72811
|
}, [projectIdRef]);
|
|
72768
|
-
const assets =
|
|
72812
|
+
const assets = useMemo71(
|
|
72769
72813
|
() => fileTree.filter((f) => !f.endsWith(".html") && !f.endsWith(".md") && !f.endsWith(".json")),
|
|
72770
72814
|
[fileTree]
|
|
72771
72815
|
);
|
|
72772
|
-
const fontAssets =
|
|
72816
|
+
const fontAssets = useMemo71(
|
|
72773
72817
|
() => (projectId ? assets : []).filter((asset) => FONT_EXT.test(asset)).map((asset) => ({
|
|
72774
72818
|
family: fontFamilyFromAssetPath(asset),
|
|
72775
72819
|
path: asset,
|
|
@@ -72913,9 +72957,18 @@ function useEditorSave({
|
|
|
72913
72957
|
}
|
|
72914
72958
|
|
|
72915
72959
|
// src/hooks/useProjectFileWriter.ts
|
|
72916
|
-
import { useCallback as useCallback103, useMemo as
|
|
72960
|
+
import { useCallback as useCallback103, useMemo as useMemo72 } from "react";
|
|
72961
|
+
async function fetchProjectFile(projectId, path, query) {
|
|
72962
|
+
if (!projectId) throw new Error("No active project");
|
|
72963
|
+
const response = await studioApiFetch(
|
|
72964
|
+
`/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(path)}${query}`
|
|
72965
|
+
);
|
|
72966
|
+
if (!response.ok) throw new Error(`Failed to read ${path}`);
|
|
72967
|
+
const data = await response.json();
|
|
72968
|
+
return { content: data.content, version: data.version ?? response.headers.get("etag") };
|
|
72969
|
+
}
|
|
72917
72970
|
function useProjectFileWriter({ projectId }) {
|
|
72918
|
-
const fileVersionScope =
|
|
72971
|
+
const fileVersionScope = useMemo72(
|
|
72919
72972
|
() => ({ projectId, versions: /* @__PURE__ */ new Map() }),
|
|
72920
72973
|
[projectId]
|
|
72921
72974
|
);
|
|
@@ -72928,28 +72981,18 @@ function useProjectFileWriter({ projectId }) {
|
|
|
72928
72981
|
);
|
|
72929
72982
|
const readProjectFile = useCallback103(
|
|
72930
72983
|
async (path) => {
|
|
72931
|
-
|
|
72932
|
-
|
|
72933
|
-
|
|
72934
|
-
|
|
72935
|
-
if (!response.ok) throw new Error(`Failed to read ${path}`);
|
|
72936
|
-
const data = await response.json();
|
|
72937
|
-
if (typeof data.content !== "string") throw new Error(`Missing file contents for ${path}`);
|
|
72938
|
-
fileVersions.set(path, data.version ?? response.headers.get("etag"));
|
|
72939
|
-
return data.content;
|
|
72984
|
+
const { content, version } = await fetchProjectFile(projectId, path, "");
|
|
72985
|
+
if (typeof content !== "string") throw new Error(`Missing file contents for ${path}`);
|
|
72986
|
+
fileVersions.set(path, version);
|
|
72987
|
+
return content;
|
|
72940
72988
|
},
|
|
72941
72989
|
[fileVersions, projectId]
|
|
72942
72990
|
);
|
|
72943
72991
|
const readOptionalProjectFile = useCallback103(
|
|
72944
72992
|
async (path) => {
|
|
72945
|
-
|
|
72946
|
-
|
|
72947
|
-
|
|
72948
|
-
);
|
|
72949
|
-
if (!response.ok) throw new Error(`Failed to read ${path}`);
|
|
72950
|
-
const data = await response.json();
|
|
72951
|
-
fileVersions.set(path, data.version ?? response.headers.get("etag"));
|
|
72952
|
-
return typeof data.content === "string" ? data.content : "";
|
|
72993
|
+
const { content, version } = await fetchProjectFile(projectId, path, "?optional=1");
|
|
72994
|
+
fileVersions.set(path, version);
|
|
72995
|
+
return typeof content === "string" ? content : "";
|
|
72953
72996
|
},
|
|
72954
72997
|
[fileVersions, projectId]
|
|
72955
72998
|
);
|
|
@@ -72959,7 +73002,7 @@ function useProjectFileWriter({ projectId }) {
|
|
|
72959
73002
|
const writeProjectId = projectId;
|
|
72960
73003
|
let expectedVersion = await studioExpectedFileVersion(fileVersions, path, expectedContent);
|
|
72961
73004
|
if (expectedVersion === void 0) {
|
|
72962
|
-
const preflight = await
|
|
73005
|
+
const preflight = await studioApiFetch(
|
|
72963
73006
|
`/api/projects/${encodeURIComponent(writeProjectId)}/files/${encodeURIComponent(path)}`
|
|
72964
73007
|
);
|
|
72965
73008
|
if (preflight.ok) {
|
|
@@ -72979,7 +73022,7 @@ function useProjectFileWriter({ projectId }) {
|
|
|
72979
73022
|
await retryStudioSave(async () => {
|
|
72980
73023
|
let response;
|
|
72981
73024
|
try {
|
|
72982
|
-
response = await
|
|
73025
|
+
response = await studioApiFetch(
|
|
72983
73026
|
`/api/projects/${encodeURIComponent(writeProjectId)}/files/${encodeURIComponent(path)}`,
|
|
72984
73027
|
{
|
|
72985
73028
|
method: "PUT",
|
|
@@ -73020,7 +73063,7 @@ function useProjectFileWriter({ projectId }) {
|
|
|
73020
73063
|
},
|
|
73021
73064
|
[fileVersions, projectId]
|
|
73022
73065
|
);
|
|
73023
|
-
return
|
|
73066
|
+
return useMemo72(
|
|
73024
73067
|
() => ({
|
|
73025
73068
|
fileVersions,
|
|
73026
73069
|
readProjectFile,
|
|
@@ -73124,7 +73167,7 @@ function useFileManager({
|
|
|
73124
73167
|
setEditingFile({ path, content: null });
|
|
73125
73168
|
return;
|
|
73126
73169
|
}
|
|
73127
|
-
|
|
73170
|
+
studioApiFetch(`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path)}`).then((r) => {
|
|
73128
73171
|
if (!r.ok) throw new Error(`Failed to load ${path} (${r.status})`);
|
|
73129
73172
|
return r.json();
|
|
73130
73173
|
}).then((data) => {
|
|
@@ -73152,9 +73195,12 @@ function useFileManager({
|
|
|
73152
73195
|
const requestId = ++revealRequestIdRef.current;
|
|
73153
73196
|
const controller = new AbortController();
|
|
73154
73197
|
revealAbortRef.current = controller;
|
|
73155
|
-
|
|
73156
|
-
|
|
73157
|
-
|
|
73198
|
+
studioApiFetch(
|
|
73199
|
+
`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(sourceFile)}`,
|
|
73200
|
+
{
|
|
73201
|
+
signal: controller.signal
|
|
73202
|
+
}
|
|
73203
|
+
).then((r) => r.json()).then((data) => {
|
|
73158
73204
|
if (requestId !== revealRequestIdRef.current) return;
|
|
73159
73205
|
if (data.content != null) {
|
|
73160
73206
|
fileVersions.set(sourceFile, data.version ?? null);
|
|
@@ -73178,7 +73224,7 @@ function useFileManager({
|
|
|
73178
73224
|
}
|
|
73179
73225
|
const qs = dir ? `?dir=${encodeURIComponent(dir)}` : "";
|
|
73180
73226
|
try {
|
|
73181
|
-
const res = await
|
|
73227
|
+
const res = await studioApiFetch(`/api/projects/${encodeURIComponent(pid)}/upload${qs}`, {
|
|
73182
73228
|
method: "POST",
|
|
73183
73229
|
body: formData
|
|
73184
73230
|
});
|
|
@@ -73218,7 +73264,7 @@ function useFileManager({
|
|
|
73218
73264
|
if (path.endsWith(".html")) {
|
|
73219
73265
|
content = '<!DOCTYPE html>\n<html>\n<head>\n <meta charset="UTF-8">\n</head>\n<body>\n\n</body>\n</html>\n';
|
|
73220
73266
|
}
|
|
73221
|
-
const res = await
|
|
73267
|
+
const res = await studioApiFetch(
|
|
73222
73268
|
`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path)}`,
|
|
73223
73269
|
{
|
|
73224
73270
|
method: "POST",
|
|
@@ -73241,7 +73287,7 @@ function useFileManager({
|
|
|
73241
73287
|
async (path) => {
|
|
73242
73288
|
const pid = projectIdRef.current;
|
|
73243
73289
|
if (!pid) return;
|
|
73244
|
-
const res = await
|
|
73290
|
+
const res = await studioApiFetch(
|
|
73245
73291
|
`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path + "/.gitkeep")}`,
|
|
73246
73292
|
{
|
|
73247
73293
|
method: "POST",
|
|
@@ -73263,7 +73309,7 @@ function useFileManager({
|
|
|
73263
73309
|
async (path) => {
|
|
73264
73310
|
const pid = projectIdRef.current;
|
|
73265
73311
|
if (!pid) return;
|
|
73266
|
-
const res = await
|
|
73312
|
+
const res = await studioApiFetch(
|
|
73267
73313
|
`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path)}`,
|
|
73268
73314
|
{
|
|
73269
73315
|
method: "DELETE"
|
|
@@ -73284,7 +73330,7 @@ function useFileManager({
|
|
|
73284
73330
|
async (oldPath, newPath) => {
|
|
73285
73331
|
const pid = projectIdRef.current;
|
|
73286
73332
|
if (!pid) return;
|
|
73287
|
-
const res = await
|
|
73333
|
+
const res = await studioApiFetch(
|
|
73288
73334
|
`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(oldPath)}`,
|
|
73289
73335
|
{
|
|
73290
73336
|
method: "PATCH",
|
|
@@ -73310,7 +73356,7 @@ function useFileManager({
|
|
|
73310
73356
|
async (path) => {
|
|
73311
73357
|
const pid = projectIdRef.current;
|
|
73312
73358
|
if (!pid) return;
|
|
73313
|
-
const res = await
|
|
73359
|
+
const res = await studioApiFetch(`/api/projects/${encodeURIComponent(pid)}/duplicate-file`, {
|
|
73314
73360
|
method: "POST",
|
|
73315
73361
|
headers: { "Content-Type": "application/json" },
|
|
73316
73362
|
body: JSON.stringify({ path })
|
|
@@ -73619,18 +73665,17 @@ function applyUndoRestoreToPreview(iframe, activeCompPath, files, currentTime, r
|
|
|
73619
73665
|
const active = files[activeDocPath];
|
|
73620
73666
|
const restoredScript = active ? extractGsapScriptText(active.restored) : null;
|
|
73621
73667
|
const previousScript = active ? extractGsapScriptText(active.previous) : null;
|
|
73622
|
-
const reparse = plan.scripted
|
|
73623
|
-
if (reparse
|
|
73668
|
+
const reparse = plan.scripted && plan.targets.some(({ live }) => "_gsap" in live);
|
|
73669
|
+
if (reparse && !restoredScript) {
|
|
73624
73670
|
reloadPreview();
|
|
73625
73671
|
return "full";
|
|
73626
73672
|
}
|
|
73627
|
-
if (restoredScript && (restoredScript !== previousScript || reparse
|
|
73673
|
+
if (restoredScript && (restoredScript !== previousScript || reparse)) {
|
|
73628
73674
|
syncStaleEditMarks(doc, active);
|
|
73629
73675
|
const result = applySoftReload(iframe, restoredScript, {
|
|
73630
73676
|
onAsyncFailure: reloadPreview,
|
|
73631
73677
|
currentTimeOverride: currentTime,
|
|
73632
73678
|
authoredHtml: active.restored,
|
|
73633
|
-
reparse,
|
|
73634
73679
|
nestedFiles
|
|
73635
73680
|
});
|
|
73636
73681
|
if (result === "cannot-soft-reload") {
|
|
@@ -73799,8 +73844,9 @@ function usePreviewPersistence({
|
|
|
73799
73844
|
if (result.status !== "clean") throw result.error;
|
|
73800
73845
|
}, [drainPendingDomEditSaves]);
|
|
73801
73846
|
const settlePendingEdits = useCallback105(async () => {
|
|
73802
|
-
|
|
73803
|
-
await
|
|
73847
|
+
const queued = domEditSaveQueueRef.current?.waitForIdle();
|
|
73848
|
+
await flushStudioPendingEdits({ onlyCurrent: true });
|
|
73849
|
+
await queued;
|
|
73804
73850
|
}, []);
|
|
73805
73851
|
const resetDomEditSaveQueueBreaker = useCallback105(() => {
|
|
73806
73852
|
domEditSaveQueueRef.current?.reset();
|
|
@@ -73825,20 +73871,20 @@ function usePreviewPersistence({
|
|
|
73825
73871
|
);
|
|
73826
73872
|
applyStudioManualEditsToPreviewRef.current = applyStudioManualEditsToPreview;
|
|
73827
73873
|
const syncHistoryPreviewAfterApply = useCallback105(
|
|
73828
|
-
async (
|
|
73874
|
+
async (restore2) => {
|
|
73829
73875
|
const projectId = usePlayerStore.getState().timelineProjectId;
|
|
73830
73876
|
const nestedFiles = await settleNestedReads(
|
|
73831
|
-
|
|
73877
|
+
readUndoNestedFiles(
|
|
73832
73878
|
previewIframeRef.current,
|
|
73833
73879
|
activeCompPathRef.current,
|
|
73834
|
-
|
|
73835
|
-
(path) => readProjectFileContent(projectId, path)
|
|
73836
|
-
)
|
|
73880
|
+
restore2.files,
|
|
73881
|
+
(path) => projectId ? readProjectFileContent(projectId, path) : Promise.reject(new Error("No project is open to read nested files from."))
|
|
73882
|
+
)
|
|
73837
73883
|
);
|
|
73838
73884
|
const strategy = applyUndoRestoreToPreview(
|
|
73839
73885
|
previewIframeRef.current,
|
|
73840
73886
|
activeCompPathRef.current,
|
|
73841
|
-
|
|
73887
|
+
restore2.files,
|
|
73842
73888
|
usePlayerStore.getState().currentTime,
|
|
73843
73889
|
reloadPreview,
|
|
73844
73890
|
nestedFiles
|
|
@@ -73952,7 +73998,7 @@ function buildAtomicCutIntents(elements, splitTime, activeCompPath) {
|
|
|
73952
73998
|
return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
|
|
73953
73999
|
}
|
|
73954
74000
|
async function readFileVersion(projectId, path) {
|
|
73955
|
-
const response = await
|
|
74001
|
+
const response = await studioApiFetch(
|
|
73956
74002
|
buildProjectApiPath(projectId, `/files/${encodeURIComponent(path)}`)
|
|
73957
74003
|
);
|
|
73958
74004
|
if (!response.ok) throw new Error(`Failed to read ${path} before cut (${response.status})`);
|
|
@@ -73971,14 +74017,17 @@ async function requestAtomicCut(projectId, intents) {
|
|
|
73971
74017
|
}
|
|
73972
74018
|
const transactionToken = `cut:${crypto.randomUUID()}`;
|
|
73973
74019
|
markStudioWriteToken(transactionToken);
|
|
73974
|
-
const response = await
|
|
73975
|
-
|
|
73976
|
-
|
|
73977
|
-
|
|
73978
|
-
|
|
73979
|
-
|
|
73980
|
-
|
|
73981
|
-
|
|
74020
|
+
const response = await studioApiFetch(
|
|
74021
|
+
buildProjectApiPath(projectId, "/file-mutations/split-batch"),
|
|
74022
|
+
{
|
|
74023
|
+
method: "POST",
|
|
74024
|
+
headers: {
|
|
74025
|
+
"Content-Type": "application/json",
|
|
74026
|
+
"X-Hyperframes-Write-Token": transactionToken
|
|
74027
|
+
},
|
|
74028
|
+
body: JSON.stringify({ files, transactionToken })
|
|
74029
|
+
}
|
|
74030
|
+
);
|
|
73982
74031
|
const body = await response.json().catch(() => null);
|
|
73983
74032
|
if (!response.ok || body?.ok !== true || !Array.isArray(body.files)) {
|
|
73984
74033
|
const prefix = response.status === 409 ? "Cut conflict" : "Cut failed";
|
|
@@ -74046,7 +74095,7 @@ function errorOf(value) {
|
|
|
74046
74095
|
return typeof value.error === "string" ? value.error : null;
|
|
74047
74096
|
}
|
|
74048
74097
|
async function readVersion(projectId, path) {
|
|
74049
|
-
const response = await
|
|
74098
|
+
const response = await studioApiFetch(
|
|
74050
74099
|
buildProjectApiPath(projectId, `/files/${encodeURIComponent(path)}`)
|
|
74051
74100
|
);
|
|
74052
74101
|
const body = await response.json().catch(() => null);
|
|
@@ -74060,7 +74109,7 @@ async function requestFreezeFrame(input) {
|
|
|
74060
74109
|
const expectedVersion = await readVersion(input.projectId, input.path);
|
|
74061
74110
|
const transactionToken = `freeze:${crypto.randomUUID()}`;
|
|
74062
74111
|
markStudioWriteToken(transactionToken);
|
|
74063
|
-
const response = await
|
|
74112
|
+
const response = await studioApiFetch(
|
|
74064
74113
|
buildProjectApiPath(input.projectId, "/file-mutations/freeze-frame"),
|
|
74065
74114
|
{
|
|
74066
74115
|
method: "POST",
|
|
@@ -74315,7 +74364,7 @@ function resolveDropTrack(input) {
|
|
|
74315
74364
|
|
|
74316
74365
|
// src/utils/timelineCompositionInsert.ts
|
|
74317
74366
|
async function insertTimelineComposition(input) {
|
|
74318
|
-
const current = await
|
|
74367
|
+
const current = await studioApiFetch(
|
|
74319
74368
|
buildProjectApiPath(input.projectId, `/files/${encodeURIComponent(input.targetPath)}`)
|
|
74320
74369
|
);
|
|
74321
74370
|
if (!current.ok) {
|
|
@@ -74323,7 +74372,7 @@ async function insertTimelineComposition(input) {
|
|
|
74323
74372
|
}
|
|
74324
74373
|
const snapshot3 = await current.json();
|
|
74325
74374
|
if (typeof snapshot3.version !== "string") throw new Error("Missing composition file version");
|
|
74326
|
-
const response = await
|
|
74375
|
+
const response = await studioApiFetch(
|
|
74327
74376
|
buildProjectApiPath(
|
|
74328
74377
|
input.projectId,
|
|
74329
74378
|
`/file-mutations/insert-composition/${encodeURIComponent(input.targetPath)}`
|
|
@@ -74656,10 +74705,10 @@ function useTimelineEditRefusal(canEdit, showToast) {
|
|
|
74656
74705
|
);
|
|
74657
74706
|
}
|
|
74658
74707
|
function useTimelineEditGate(canEdit, showToast) {
|
|
74659
|
-
const
|
|
74708
|
+
const refuse2 = useTimelineEditRefusal(canEdit, showToast);
|
|
74660
74709
|
return useCallback110(
|
|
74661
|
-
(targets) =>
|
|
74662
|
-
[
|
|
74710
|
+
(targets) => refuse2(targets) === null,
|
|
74711
|
+
[refuse2]
|
|
74663
74712
|
);
|
|
74664
74713
|
}
|
|
74665
74714
|
|
|
@@ -75261,7 +75310,7 @@ function useTimelineDeleteOps({
|
|
|
75261
75310
|
}
|
|
75262
75311
|
return patchTarget;
|
|
75263
75312
|
});
|
|
75264
|
-
const removeResponse = await
|
|
75313
|
+
const removeResponse = await studioApiFetch(
|
|
75265
75314
|
buildProjectApiPath(
|
|
75266
75315
|
pid,
|
|
75267
75316
|
`/file-mutations/remove-elements/${encodeURIComponent(targetPath)}`
|
|
@@ -75892,11 +75941,11 @@ function assertAudioGroupEditable(checkEditable, elements) {
|
|
|
75892
75941
|
throw new Error("Timeline edit blocked");
|
|
75893
75942
|
}
|
|
75894
75943
|
}
|
|
75895
|
-
function patchLiveAudioGroupState(iframe, elements, groupId, activeCompPath,
|
|
75944
|
+
function patchLiveAudioGroupState(iframe, elements, groupId, activeCompPath, restore2) {
|
|
75896
75945
|
for (const element of elements) {
|
|
75897
75946
|
const target = findTimelineElementInIframe(iframe, element, activeCompPath);
|
|
75898
75947
|
if (!target) continue;
|
|
75899
|
-
const next =
|
|
75948
|
+
const next = restore2 ? restore2.get(element) ?? null : groupId;
|
|
75900
75949
|
if (next) target.setAttribute(HF_AUDIO_GROUP_ATTR5, next);
|
|
75901
75950
|
else target.removeAttribute(HF_AUDIO_GROUP_ATTR5);
|
|
75902
75951
|
}
|
|
@@ -76896,9 +76945,9 @@ function useTimelineEditing({
|
|
|
76896
76945
|
handleTimelineGroupResize: track2(
|
|
76897
76946
|
guard((changes) => changes.map((c) => c.element), groupEditing.handleTimelineGroupResize)
|
|
76898
76947
|
),
|
|
76899
|
-
restoreLiveLanes: (
|
|
76900
|
-
setElementFxAttribute.restoreLive(
|
|
76901
|
-
setAudioGroupAttribute2.restoreLive(
|
|
76948
|
+
restoreLiveLanes: (restore2) => {
|
|
76949
|
+
setElementFxAttribute.restoreLive(restore2);
|
|
76950
|
+
setAudioGroupAttribute2.restoreLive(restore2);
|
|
76902
76951
|
}
|
|
76903
76952
|
};
|
|
76904
76953
|
return useStableHandlers(editing, projectId);
|
|
@@ -76958,7 +77007,7 @@ function useAskAgentModal({
|
|
|
76958
77007
|
if (!pid) return;
|
|
76959
77008
|
const targetPath = selection.sourceFile || activeCompPath || "index.html";
|
|
76960
77009
|
try {
|
|
76961
|
-
const response = await
|
|
77010
|
+
const response = await studioApiFetch(
|
|
76962
77011
|
buildProjectApiPath(pid, `/files/${encodeURIComponent(targetPath)}`)
|
|
76963
77012
|
);
|
|
76964
77013
|
if (!response.ok) return;
|
|
@@ -78014,7 +78063,7 @@ async function assignGsapTargetAutoIdIfNeeded({
|
|
|
78014
78063
|
showToast?.("Couldn't assign element id because the patch contains invalid values", "error");
|
|
78015
78064
|
return false;
|
|
78016
78065
|
}
|
|
78017
|
-
const res = await
|
|
78066
|
+
const res = await studioApiFetch(
|
|
78018
78067
|
`/api/projects/${encodeURIComponent(projectId)}/file-mutations/patch-element/${encodeURIComponent(targetPath)}`,
|
|
78019
78068
|
{
|
|
78020
78069
|
method: "POST",
|
|
@@ -78080,7 +78129,7 @@ function isAtomicElementPatchFile(value) {
|
|
|
78080
78129
|
async function patchElementBatches(projectId, batches) {
|
|
78081
78130
|
const body = JSON.stringify({ batches });
|
|
78082
78131
|
try {
|
|
78083
|
-
const response = await
|
|
78132
|
+
const response = await studioApiFetch(
|
|
78084
78133
|
`/api/projects/${encodeURIComponent(projectId)}/file-mutations/patch-element-batches`,
|
|
78085
78134
|
{
|
|
78086
78135
|
method: "POST",
|
|
@@ -78120,7 +78169,7 @@ function batchesAreInlineStyleOnly(batches) {
|
|
|
78120
78169
|
);
|
|
78121
78170
|
}
|
|
78122
78171
|
async function postPatchElement(projectId, targetPath, body, showToast) {
|
|
78123
|
-
const response = await
|
|
78172
|
+
const response = await studioApiFetch(
|
|
78124
78173
|
buildProjectApiPath(
|
|
78125
78174
|
projectId,
|
|
78126
78175
|
`/file-mutations/patch-element/${encodeURIComponent(targetPath)}`
|
|
@@ -78418,7 +78467,13 @@ var IMAGE_BACKGROUND_FIT = [
|
|
|
78418
78467
|
["background-repeat", "no-repeat"],
|
|
78419
78468
|
["background-size", "contain"]
|
|
78420
78469
|
];
|
|
78421
|
-
async function commitDomStyles(context, selection,
|
|
78470
|
+
async function commitDomStyles(context, selection, stylesInEitherCase) {
|
|
78471
|
+
const styles = Object.fromEntries(
|
|
78472
|
+
Object.entries(stylesInEitherCase).map(([property, value]) => [
|
|
78473
|
+
cssPropertyName(property),
|
|
78474
|
+
value
|
|
78475
|
+
])
|
|
78476
|
+
);
|
|
78422
78477
|
const entries = Object.entries(styles);
|
|
78423
78478
|
if (entries.length === 0) return domEditCommitDeclined("no-selection");
|
|
78424
78479
|
if (entries.some(([property]) => isManualGeometryStyleProperty(property)))
|
|
@@ -78855,7 +78910,7 @@ function useDomEditTextCommits({
|
|
|
78855
78910
|
persistDomEditOperations
|
|
78856
78911
|
});
|
|
78857
78912
|
const handleDomStyleCommitForSelection = useCallback130(
|
|
78858
|
-
(selection,
|
|
78913
|
+
(selection, propertyOrStylesAsOnePatch, value = "") => commitDomStyles(
|
|
78859
78914
|
{
|
|
78860
78915
|
activeCompPath,
|
|
78861
78916
|
previewIframeRef,
|
|
@@ -78866,7 +78921,7 @@ function useDomEditTextCommits({
|
|
|
78866
78921
|
resync: refreshDomEditSelectionFromPreview
|
|
78867
78922
|
},
|
|
78868
78923
|
selection,
|
|
78869
|
-
{ [
|
|
78924
|
+
typeof propertyOrStylesAsOnePatch === "string" ? { [propertyOrStylesAsOnePatch]: value } : propertyOrStylesAsOnePatch
|
|
78870
78925
|
),
|
|
78871
78926
|
[
|
|
78872
78927
|
activeCompPath,
|
|
@@ -78953,24 +79008,24 @@ function useDomEditTextCommits({
|
|
|
78953
79008
|
if (element.isConnected && element.innerHTML === html2) element.innerHTML = previousHtml;
|
|
78954
79009
|
};
|
|
78955
79010
|
if (latestReadOnlyPreviewRef.current) return putBack();
|
|
78956
|
-
const
|
|
79011
|
+
const refuse2 = (reason) => {
|
|
78957
79012
|
console.error("[Studio] text edit not saved:", reason, element);
|
|
78958
79013
|
showToast(`Couldn't save the text edit: ${reason}`, "error");
|
|
78959
79014
|
putBack();
|
|
78960
79015
|
};
|
|
78961
79016
|
const doc = previewIframeRef.current?.contentDocument;
|
|
78962
79017
|
if (!doc || !element.isConnected || element.ownerDocument !== doc) {
|
|
78963
|
-
return
|
|
79018
|
+
return refuse2("the text's element is gone from the preview");
|
|
78964
79019
|
}
|
|
78965
79020
|
const selection = await buildDomSelectionFromTarget(element, {
|
|
78966
79021
|
exactTarget: true,
|
|
78967
79022
|
skipSourceProbe: true
|
|
78968
79023
|
});
|
|
78969
79024
|
if (selection?.element !== element) {
|
|
78970
|
-
return
|
|
79025
|
+
return refuse2("this text was not found in the composition's source");
|
|
78971
79026
|
}
|
|
78972
79027
|
if (!canCommitInlineTextSelection(selection, element)) {
|
|
78973
|
-
return
|
|
79028
|
+
return refuse2("this text can't be edited in place");
|
|
78974
79029
|
}
|
|
78975
79030
|
const isLatestTextCommit = bumpDomEditCommitMapVersion(
|
|
78976
79031
|
domTextCommitVersionRef.current,
|
|
@@ -79229,18 +79284,18 @@ var ELEMENT_OFFSET_REFUSED = {
|
|
|
79229
79284
|
anchored: "This layer is anchored from its right or bottom edge. Move it in the Code tab.",
|
|
79230
79285
|
percent: "This layer's position is set in percent. Move it in the Code tab."
|
|
79231
79286
|
};
|
|
79232
|
-
function
|
|
79287
|
+
function gsapOf2(el) {
|
|
79233
79288
|
return el.ownerDocument.defaultView?.gsap;
|
|
79234
79289
|
}
|
|
79235
79290
|
function settleGsapDraftAtGestureStart(el) {
|
|
79236
|
-
const gsap3 =
|
|
79291
|
+
const gsap3 = gsapOf2(el);
|
|
79237
79292
|
const x = Number.parseFloat(el.getAttribute("data-hf-drag-gsap-base-x") ?? "");
|
|
79238
79293
|
const y = Number.parseFloat(el.getAttribute("data-hf-drag-gsap-base-y") ?? "");
|
|
79239
79294
|
if (gsap3 && Number.isFinite(x) && Number.isFinite(y)) gsap3.set(el, { x, y });
|
|
79240
79295
|
}
|
|
79241
79296
|
function refuseGsapTakeover(el, showToast) {
|
|
79242
79297
|
if (!gsapHoldsTranslate(el)) return;
|
|
79243
|
-
|
|
79298
|
+
gsapOf2(el)?.set(el, { x: 0, y: 0, xPercent: 0, yPercent: 0 });
|
|
79244
79299
|
showToast(GSAP_TOOK_OVER, "error");
|
|
79245
79300
|
throw markStudioSaveErrorAlreadyToasted(new Error(GSAP_TOOK_OVER));
|
|
79246
79301
|
}
|
|
@@ -79331,7 +79386,7 @@ function useDomGeometryCommits({
|
|
|
79331
79386
|
[commitPositionPatchToHtml, readOnlyPreview, showToast]
|
|
79332
79387
|
);
|
|
79333
79388
|
const handleDomBoxSizeCommit = useCallback131(
|
|
79334
|
-
(selection, next, offset,
|
|
79389
|
+
(selection, next, offset, restore2, undoKey) => {
|
|
79335
79390
|
if (readOnlyPreview) return Promise.resolve(void 0);
|
|
79336
79391
|
const element = selection.element;
|
|
79337
79392
|
const beforeSize = captureStudioBoxSize(element);
|
|
@@ -79349,7 +79404,7 @@ function useDomGeometryCommits({
|
|
|
79349
79404
|
restoreStudioBoxSize(element, beforeSize);
|
|
79350
79405
|
if (offset) restoreStudioPathOffset(element, beforeOffset);
|
|
79351
79406
|
crop?.revert();
|
|
79352
|
-
|
|
79407
|
+
restore2?.();
|
|
79353
79408
|
throw error;
|
|
79354
79409
|
});
|
|
79355
79410
|
},
|
|
@@ -79672,7 +79727,7 @@ async function commitStructuralMutation(pid, targetPath, route, body, label, dep
|
|
|
79672
79727
|
writeFile: deps.writeProjectFile,
|
|
79673
79728
|
recordEdit: deps.editHistory.recordEdit,
|
|
79674
79729
|
rewrite: async (originalContent) => {
|
|
79675
|
-
const mutateResponse = await
|
|
79730
|
+
const mutateResponse = await studioApiFetch(
|
|
79676
79731
|
buildProjectApiPath(pid, `/file-mutations/${route}/${encodeURIComponent(targetPath)}`),
|
|
79677
79732
|
{
|
|
79678
79733
|
method: "POST",
|
|
@@ -79749,7 +79804,7 @@ function useGroupCommits(params) {
|
|
|
79749
79804
|
}
|
|
79750
79805
|
|
|
79751
79806
|
// src/hooks/useGsapScriptCommits.ts
|
|
79752
|
-
import { useCallback as useCallback139, useMemo as
|
|
79807
|
+
import { useCallback as useCallback139, useMemo as useMemo73, useRef as useRef148 } from "react";
|
|
79753
79808
|
import { findUnsafeMutationValues } from "@hyperframes/core/studio-api/finite-mutation";
|
|
79754
79809
|
|
|
79755
79810
|
// src/hooks/gsapRuntimePatch.ts
|
|
@@ -79943,6 +79998,11 @@ function createKeyedSerializer() {
|
|
|
79943
79998
|
};
|
|
79944
79999
|
}
|
|
79945
80000
|
|
|
80001
|
+
// src/hooks/gsapScriptCommitTypes.ts
|
|
80002
|
+
function gsapWriteFile(selection, activeCompPath) {
|
|
80003
|
+
return selection.sourceFile || activeCompPath || "index.html";
|
|
80004
|
+
}
|
|
80005
|
+
|
|
79946
80006
|
// src/hooks/useGsapAnimationOps.ts
|
|
79947
80007
|
import { useCallback as useCallback134 } from "react";
|
|
79948
80008
|
function useGsapAnimationOps({
|
|
@@ -80862,7 +80922,7 @@ function useSafeGsapCommitMutation(commitMutation, trackGsapSaveFailure, showToa
|
|
|
80862
80922
|
|
|
80863
80923
|
// src/hooks/useGsapScriptCommits.ts
|
|
80864
80924
|
async function mutateGsapScript(projectId, sourceFile, mutation) {
|
|
80865
|
-
const res = await
|
|
80925
|
+
const res = await studioApiFetch(
|
|
80866
80926
|
`/api/projects/${encodeURIComponent(projectId)}/gsap-mutations/${encodeURIComponent(sourceFile)}`,
|
|
80867
80927
|
{
|
|
80868
80928
|
method: "POST",
|
|
@@ -80876,7 +80936,7 @@ async function mutateGsapScript(projectId, sourceFile, mutation) {
|
|
|
80876
80936
|
return result;
|
|
80877
80937
|
}
|
|
80878
80938
|
async function mutateGsapScriptBatch(projectId, sourceFile, mutations) {
|
|
80879
|
-
const res = await
|
|
80939
|
+
const res = await studioApiFetch(
|
|
80880
80940
|
`/api/projects/${encodeURIComponent(projectId)}/gsap-mutations-batch/${encodeURIComponent(sourceFile)}`,
|
|
80881
80941
|
{
|
|
80882
80942
|
method: "POST",
|
|
@@ -81105,7 +81165,7 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
|
|
|
81105
81165
|
const { instantPatch: _instantPatch, ...batchOptions } = options;
|
|
81106
81166
|
await finalizeSuccessfulMutation(pid, compositionPath, last.selection, last.mutation, targetPath, result, instantPatches.length > 0 ? { ...batchOptions, instantPatches } : batchOptions);
|
|
81107
81167
|
}, [showToast, finalizeSuccessfulMutation]);
|
|
81108
|
-
const commitMutation =
|
|
81168
|
+
const commitMutation = useMemo73(() => {
|
|
81109
81169
|
const serializeFile = (file, task) => {
|
|
81110
81170
|
if (writeProjectFile) {
|
|
81111
81171
|
return serializeStudioFileMutation(writeProjectFile, file, task);
|
|
@@ -81122,7 +81182,7 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
|
|
|
81122
81182
|
};
|
|
81123
81183
|
const commit = trackedStudioEdit((selection, mutation, options) => {
|
|
81124
81184
|
if (!activeProjectId) return Promise.resolve();
|
|
81125
|
-
const file = selection
|
|
81185
|
+
const file = gsapWriteFile(selection, activeCompPath);
|
|
81126
81186
|
return serializeCommit(
|
|
81127
81187
|
file,
|
|
81128
81188
|
options.serializeKey,
|
|
@@ -81131,7 +81191,7 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
|
|
|
81131
81191
|
});
|
|
81132
81192
|
commit.batch = trackedStudioEdit((calls, options) => {
|
|
81133
81193
|
if (!activeProjectId) return Promise.resolve();
|
|
81134
|
-
const file = calls[0]
|
|
81194
|
+
const file = calls[0] ? gsapWriteFile(calls[0].selection, activeCompPath) : "index.html";
|
|
81135
81195
|
return serializeCommit(
|
|
81136
81196
|
file,
|
|
81137
81197
|
options.serializeKey,
|
|
@@ -81170,7 +81230,7 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
|
|
|
81170
81230
|
},
|
|
81171
81231
|
[activeProjectId]
|
|
81172
81232
|
);
|
|
81173
|
-
const sdkDeps =
|
|
81233
|
+
const sdkDeps = useMemo73(
|
|
81174
81234
|
() => writeProjectFile ? {
|
|
81175
81235
|
editHistory: { recordEdit: editHistory.recordEdit },
|
|
81176
81236
|
writeProjectFile,
|
|
@@ -81363,13 +81423,13 @@ function useGsapAnimationFetchFallback(projectId) {
|
|
|
81363
81423
|
|
|
81364
81424
|
// src/hooks/useGsapInteractionFailureTelemetry.ts
|
|
81365
81425
|
import { useCallback as useCallback141 } from "react";
|
|
81366
|
-
function failureToast(error) {
|
|
81367
|
-
if (wasAlreadyToasted(error)) return null;
|
|
81426
|
+
function failureToast(error, toast) {
|
|
81427
|
+
if (!toast || wasAlreadyToasted(error)) return null;
|
|
81368
81428
|
return isGsapEditBlockedError(error) ? error.message : "Failed to save animated edit.";
|
|
81369
81429
|
}
|
|
81370
81430
|
function useGsapInteractionFailureTelemetry(activeCompPath, showToast) {
|
|
81371
81431
|
return useCallback141(
|
|
81372
|
-
(error, selection, mutationType, label) => {
|
|
81432
|
+
(error, selection, mutationType, label, toast) => {
|
|
81373
81433
|
const report = isGsapEditBlockedError(error) ? trackStudioEditBlocked : trackStudioSaveFailure;
|
|
81374
81434
|
report({
|
|
81375
81435
|
source: "gsap_commit",
|
|
@@ -81381,7 +81441,7 @@ function useGsapInteractionFailureTelemetry(activeCompPath, showToast) {
|
|
|
81381
81441
|
targetSelector: selection?.selector,
|
|
81382
81442
|
targetSourceFile: selection?.sourceFile
|
|
81383
81443
|
});
|
|
81384
|
-
const message = failureToast(error);
|
|
81444
|
+
const message = failureToast(error, toast !== false);
|
|
81385
81445
|
if (message) showToast(message, "error");
|
|
81386
81446
|
},
|
|
81387
81447
|
[activeCompPath, showToast]
|
|
@@ -81835,17 +81895,29 @@ function useDomEditWiring(params) {
|
|
|
81835
81895
|
|
|
81836
81896
|
// src/hooks/useGsapAwareGroupMove.ts
|
|
81837
81897
|
import { useCallback as useCallback144 } from "react";
|
|
81838
|
-
|
|
81839
|
-
|
|
81898
|
+
|
|
81899
|
+
// src/hooks/gsapGroupPreflight.ts
|
|
81900
|
+
function firstPreflightFailure(results, updates, savedOnElement, activeCompPath) {
|
|
81840
81901
|
for (const [index, result] of results.entries()) {
|
|
81841
81902
|
if (result.status !== "rejected") continue;
|
|
81842
81903
|
const selection = updates[index]?.selection;
|
|
81843
81904
|
if (selection) return { error: result.reason, selection };
|
|
81844
81905
|
}
|
|
81845
|
-
return
|
|
81906
|
+
return secondFile(updates, savedOnElement, activeCompPath);
|
|
81907
|
+
}
|
|
81908
|
+
function secondFile(updates, savedOnElement, activeCompPath) {
|
|
81909
|
+
const scripted = updates.filter(({ selection }) => !savedOnElement.has(selection));
|
|
81910
|
+
const fileOf = (s) => gsapWriteFile(s, activeCompPath);
|
|
81911
|
+
const file = scripted[0] && fileOf(scripted[0].selection);
|
|
81912
|
+
const other = scripted.find(({ selection }) => fileOf(selection) !== file);
|
|
81913
|
+
return other ? { error: new GsapEditBlockedError("mixed-files"), selection: other.selection } : null;
|
|
81846
81914
|
}
|
|
81915
|
+
|
|
81916
|
+
// src/hooks/useGsapAwareGroupMove.ts
|
|
81917
|
+
var groupDragCommitCounter = 0;
|
|
81847
81918
|
function useGsapAwareGroupMove({
|
|
81848
81919
|
gsapCommitMutation,
|
|
81920
|
+
activeCompPath,
|
|
81849
81921
|
previewIframeRef,
|
|
81850
81922
|
makeFetchFallback,
|
|
81851
81923
|
trackGsapInteractionFailure,
|
|
@@ -81853,15 +81925,16 @@ function useGsapAwareGroupMove({
|
|
|
81853
81925
|
showToast
|
|
81854
81926
|
}) {
|
|
81855
81927
|
const handleGsapAwareGroupPathOffsetCommit = useCallback144(
|
|
81856
|
-
async (updates) => {
|
|
81928
|
+
async (updates, options = {}) => {
|
|
81857
81929
|
const writes = observeGsapGesture(gsapCommitMutation);
|
|
81858
81930
|
const writer = writes.commit;
|
|
81859
81931
|
if (!writer) return { ok: true, changed: false };
|
|
81932
|
+
const toastRefusal = options.refusalToast !== false;
|
|
81860
81933
|
const coalesceKey = `group-drag:${++groupDragCommitCounter}`;
|
|
81861
81934
|
let renderOnCommit = false;
|
|
81862
81935
|
const previewFallbackLatch = { pending: false };
|
|
81863
|
-
const withGroupOptions = (
|
|
81864
|
-
...
|
|
81936
|
+
const withGroupOptions = (options2) => ({
|
|
81937
|
+
...options2,
|
|
81865
81938
|
coalesceKey,
|
|
81866
81939
|
coalesceMs: Number.POSITIVE_INFINITY,
|
|
81867
81940
|
deferPreviewSync: !renderOnCommit,
|
|
@@ -81882,23 +81955,24 @@ function useGsapAwareGroupMove({
|
|
|
81882
81955
|
label: "Move animated layer (group)"
|
|
81883
81956
|
});
|
|
81884
81957
|
};
|
|
81885
|
-
const coalescedCommit = (selection, mutation,
|
|
81886
|
-
queued.push({ selection, mutation, options: withGroupOptions(
|
|
81958
|
+
const coalescedCommit = (selection, mutation, options2) => {
|
|
81959
|
+
queued.push({ selection, mutation, options: withGroupOptions(options2) });
|
|
81887
81960
|
return Promise.resolve();
|
|
81888
81961
|
};
|
|
81889
81962
|
const preflightAnimations = /* @__PURE__ */ new Map();
|
|
81890
81963
|
const offsetMembers = /* @__PURE__ */ new Map();
|
|
81891
81964
|
const preflightResults = await Promise.allSettled(
|
|
81892
|
-
updates.map(async ({ selection, plainTranslate }) => {
|
|
81965
|
+
updates.map(async ({ selection, next, plainTranslate }) => {
|
|
81893
81966
|
if (plainTranslate ?? !gsapWritesPosition(selection.element)) {
|
|
81894
|
-
refuseGsapTakeover(selection.element, showToast)
|
|
81967
|
+
refuseGsapTakeover(selection.element, toastRefusal ? showToast : () => {
|
|
81968
|
+
});
|
|
81895
81969
|
return void offsetMembers.set(selection, true);
|
|
81896
81970
|
}
|
|
81897
81971
|
const animations = await makeFetchFallback(selection, { failOnFetchError: true })();
|
|
81898
81972
|
preflightAnimations.set(selection, animations);
|
|
81899
81973
|
const outcome = await tryGsapDragIntercept(
|
|
81900
81974
|
selection,
|
|
81901
|
-
|
|
81975
|
+
next,
|
|
81902
81976
|
animations,
|
|
81903
81977
|
previewIframeRef.current,
|
|
81904
81978
|
coalescedCommit,
|
|
@@ -81909,13 +81983,19 @@ function useGsapAwareGroupMove({
|
|
|
81909
81983
|
assertGsapEditPersisted(outcome);
|
|
81910
81984
|
})
|
|
81911
81985
|
);
|
|
81912
|
-
const preflightFailure = firstPreflightFailure(
|
|
81986
|
+
const preflightFailure = firstPreflightFailure(
|
|
81987
|
+
preflightResults,
|
|
81988
|
+
updates,
|
|
81989
|
+
offsetMembers,
|
|
81990
|
+
activeCompPath
|
|
81991
|
+
);
|
|
81913
81992
|
if (preflightFailure) {
|
|
81914
81993
|
trackGsapInteractionFailure(
|
|
81915
81994
|
preflightFailure.error,
|
|
81916
81995
|
preflightFailure.selection,
|
|
81917
81996
|
"drag",
|
|
81918
|
-
"Move animated layer (group)"
|
|
81997
|
+
"Move animated layer (group)",
|
|
81998
|
+
toastRefusal
|
|
81919
81999
|
);
|
|
81920
82000
|
throw preflightFailure.error;
|
|
81921
82001
|
}
|
|
@@ -81967,6 +82047,7 @@ function useGsapAwareGroupMove({
|
|
|
81967
82047
|
},
|
|
81968
82048
|
[
|
|
81969
82049
|
gsapCommitMutation,
|
|
82050
|
+
activeCompPath,
|
|
81970
82051
|
previewIframeRef,
|
|
81971
82052
|
makeFetchFallback,
|
|
81972
82053
|
trackGsapInteractionFailure,
|
|
@@ -81980,23 +82061,6 @@ function useGsapAwareGroupMove({
|
|
|
81980
82061
|
// src/hooks/useGsapAwareEditing.ts
|
|
81981
82062
|
import { useCallback as useCallback146 } from "react";
|
|
81982
82063
|
|
|
81983
|
-
// src/utils/elementGsap.ts
|
|
81984
|
-
function gsapOf2(element) {
|
|
81985
|
-
return element.ownerDocument.defaultView?.gsap;
|
|
81986
|
-
}
|
|
81987
|
-
function setElementGsapPosition(element, x, y) {
|
|
81988
|
-
const gsap3 = gsapOf2(element);
|
|
81989
|
-
if (!gsap3?.set) return false;
|
|
81990
|
-
gsap3.set(element, { x, y });
|
|
81991
|
-
return true;
|
|
81992
|
-
}
|
|
81993
|
-
function setElementGsapScale(element, x, y) {
|
|
81994
|
-
const gsap3 = gsapOf2(element);
|
|
81995
|
-
if (!gsap3?.set) return false;
|
|
81996
|
-
gsap3.set(element, { scaleX: x, scaleY: y });
|
|
81997
|
-
return true;
|
|
81998
|
-
}
|
|
81999
|
-
|
|
82000
82064
|
// src/hooks/gsapResizePreflight.ts
|
|
82001
82065
|
function resizeRoute(animations, fetchedAnimations) {
|
|
82002
82066
|
const allKnownAnimations = [...animations, ...fetchedAnimations];
|
|
@@ -82028,16 +82092,8 @@ function preflightGsapResizeIntercept(selection, animations, iframe, fetchedAnim
|
|
|
82028
82092
|
}
|
|
82029
82093
|
|
|
82030
82094
|
// src/hooks/gsapResizeIntercept.ts
|
|
82031
|
-
var IDENTITY_ONE_PROPS = /* @__PURE__ */ new Set(["opacity", "autoAlpha", "scale", "scaleX", "scaleY"]);
|
|
82032
82095
|
var SIZE_PROPS = /* @__PURE__ */ new Set(["width", "height"]);
|
|
82033
|
-
|
|
82034
|
-
const id = {};
|
|
82035
|
-
for (const [k, v] of Object.entries(source)) {
|
|
82036
|
-
if (typeof v === "number") id[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
82037
|
-
else id[k] = v;
|
|
82038
|
-
}
|
|
82039
|
-
return id;
|
|
82040
|
-
}
|
|
82096
|
+
var POSITION_XY = /* @__PURE__ */ new Set(["x", "y"]);
|
|
82041
82097
|
function originalBoxSize(el, measuredAttr, inlineProperty) {
|
|
82042
82098
|
const measured = Number.parseFloat(el?.getAttribute(measuredAttr) ?? "");
|
|
82043
82099
|
if (Number.isFinite(measured) && measured > 0) return measured;
|
|
@@ -82046,6 +82102,36 @@ function originalBoxSize(el, measuredAttr, inlineProperty) {
|
|
|
82046
82102
|
);
|
|
82047
82103
|
return Number.isFinite(inline) && inline > 0 ? inline : null;
|
|
82048
82104
|
}
|
|
82105
|
+
function preGestureBoxSize(el) {
|
|
82106
|
+
const width = originalBoxSize(el, STUDIO_ORIGINAL_BOX_WIDTH_ATTR, "width");
|
|
82107
|
+
const height = originalBoxSize(el, STUDIO_ORIGINAL_BOX_HEIGHT_ATTR, "height");
|
|
82108
|
+
return { ...width != null && { width }, ...height != null && { height } };
|
|
82109
|
+
}
|
|
82110
|
+
async function commitSizeAtPlayhead(selection, anim, size, iframe, dragOffset, callbacks) {
|
|
82111
|
+
const selector = selectorFromSelection(selection);
|
|
82112
|
+
const moves = !!dragOffset && (dragOffset.x !== 0 || dragOffset.y !== 0) && !!selector;
|
|
82113
|
+
const anchor2 = moves && animationWritesAnyProperty(anim, POSITION_XY) ? computeDraggedGsapPosition(
|
|
82114
|
+
selection.element,
|
|
82115
|
+
dragOffset,
|
|
82116
|
+
readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 }
|
|
82117
|
+
) : null;
|
|
82118
|
+
const written = await commitValueAtPlayhead(
|
|
82119
|
+
selection,
|
|
82120
|
+
anim,
|
|
82121
|
+
anchor2 ? { ...size, x: anchor2.newX, y: anchor2.newY } : size,
|
|
82122
|
+
iframe,
|
|
82123
|
+
callbacks,
|
|
82124
|
+
{
|
|
82125
|
+
label: "Resize",
|
|
82126
|
+
backfill: {
|
|
82127
|
+
...preGestureBoxSize(selection.element),
|
|
82128
|
+
...anchor2 && { x: anchor2.baseGsapX, y: anchor2.baseGsapY }
|
|
82129
|
+
},
|
|
82130
|
+
...anchor2 && { beforeReload: () => restoreDragOffset(selection.element) }
|
|
82131
|
+
}
|
|
82132
|
+
);
|
|
82133
|
+
return written.status === "persisted" && anchor2 ? { ...written, ownsDragOffset: true } : written;
|
|
82134
|
+
}
|
|
82049
82135
|
function tweenUsesScaleLonghands(anim) {
|
|
82050
82136
|
const isLonghand = (name) => name === "scaleX" || name === "scaleY";
|
|
82051
82137
|
const inKeyframes = (anim?.keyframes?.keyframes ?? []).some(
|
|
@@ -82053,7 +82139,7 @@ function tweenUsesScaleLonghands(anim) {
|
|
|
82053
82139
|
);
|
|
82054
82140
|
return inKeyframes || Object.keys(anim?.properties ?? {}).some(isLonghand);
|
|
82055
82141
|
}
|
|
82056
|
-
async function tryGsapResizeIntercept(selection, size, animations, iframe, commitMutation, fetchFallbackAnimations) {
|
|
82142
|
+
async function tryGsapResizeIntercept(selection, size, animations, iframe, commitMutation, fetchFallbackAnimations, dragOffset) {
|
|
82057
82143
|
const fetchedAnimations = fetchFallbackAnimations ? await fetchFallbackAnimations() : [];
|
|
82058
82144
|
const outcome = preflightGsapResizeIntercept(selection, animations, iframe, fetchedAnimations);
|
|
82059
82145
|
if (outcome.status === "blocked") return outcome;
|
|
@@ -82069,7 +82155,7 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82069
82155
|
commitMutation,
|
|
82070
82156
|
postSplitFetch
|
|
82071
82157
|
);
|
|
82072
|
-
|
|
82158
|
+
const anim = resolved2?.anim && animationWritesAnyProperty(resolved2.anim, resizeProperties) ? resolved2.anim : null;
|
|
82073
82159
|
logResize("intercept-enter", {
|
|
82074
82160
|
hasScaleGroup: resizeGroup === "scale",
|
|
82075
82161
|
resizeGroup,
|
|
@@ -82093,15 +82179,11 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82093
82179
|
);
|
|
82094
82180
|
if (animatedTween) {
|
|
82095
82181
|
logResize("intercept-route", { route: "keyframed-size", tweenId: animatedTween.id });
|
|
82096
|
-
const
|
|
82097
|
-
|
|
82098
|
-
|
|
82099
|
-
|
|
82100
|
-
|
|
82101
|
-
animatedTween,
|
|
82102
|
-
{ commitMutation, fetchAnimations: fetchFallbackAnimations }
|
|
82103
|
-
);
|
|
82104
|
-
if (handled) return { status: "persisted" };
|
|
82182
|
+
const sized = { width: roundToLayoutPx(size.width), height: roundToLayoutPx(size.height) };
|
|
82183
|
+
return commitSizeAtPlayhead(selection, animatedTween, sized, iframe, dragOffset, {
|
|
82184
|
+
commitMutation,
|
|
82185
|
+
fetchAnimations: fetchFallbackAnimations
|
|
82186
|
+
});
|
|
82105
82187
|
}
|
|
82106
82188
|
}
|
|
82107
82189
|
logResize("intercept-route", { route: "static-size-set", hadSizeSet: !!sizeSet, resizeGroup });
|
|
@@ -82117,10 +82199,9 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82117
82199
|
}
|
|
82118
82200
|
const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState();
|
|
82119
82201
|
const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim);
|
|
82120
|
-
if (activeKeyframePct != null) setActiveKeyframePct(null);
|
|
82121
82202
|
const selector = selectorFromSelection(selection);
|
|
82122
|
-
const runtimeProps = selector ? readAllAnimatedProperties(iframe, selector, anim, resizeGroup) : {};
|
|
82123
82203
|
let resizeProps;
|
|
82204
|
+
let resizeBackfill;
|
|
82124
82205
|
let scaleDraftEl = null;
|
|
82125
82206
|
let scaleDraftDropPoint = null;
|
|
82126
82207
|
let committedScale = null;
|
|
@@ -82140,6 +82221,7 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82140
82221
|
nonUniformScale = uniformDrift > 0.5;
|
|
82141
82222
|
useScaleLonghands = nonUniformScale || tweenUsesScaleLonghands(anim);
|
|
82142
82223
|
resizeProps = useScaleLonghands ? { scaleX: newScaleX, scaleY: newScaleY } : { scale: newScaleX };
|
|
82224
|
+
resizeBackfill = { scaleX: liveScaleX, scaleY: liveScaleY };
|
|
82143
82225
|
logResize("intercept-route", {
|
|
82144
82226
|
route: "scale-tween",
|
|
82145
82227
|
cssW,
|
|
@@ -82161,6 +82243,7 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82161
82243
|
width: roundToLayoutPx(size.width),
|
|
82162
82244
|
height: roundToLayoutPx(size.height)
|
|
82163
82245
|
};
|
|
82246
|
+
resizeBackfill = preGestureBoxSize(selection.element);
|
|
82164
82247
|
}
|
|
82165
82248
|
const finalizeScaleResizeCommit = async () => {
|
|
82166
82249
|
if (!scaleDraftEl) return false;
|
|
@@ -82206,10 +82289,12 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82206
82289
|
);
|
|
82207
82290
|
if (positionTween) {
|
|
82208
82291
|
logResize("scale-finalize", { route: "position-keyframe", tweenId: positionTween.id });
|
|
82209
|
-
|
|
82210
|
-
|
|
82211
|
-
|
|
82212
|
-
|
|
82292
|
+
assertGsapEditPersisted(
|
|
82293
|
+
await commitGsapPositionFromDrag(selection, positionTween, delta, base2, iframe, {
|
|
82294
|
+
commitMutation,
|
|
82295
|
+
fetchAnimations: fetchFallbackAnimations
|
|
82296
|
+
})
|
|
82297
|
+
);
|
|
82213
82298
|
return true;
|
|
82214
82299
|
}
|
|
82215
82300
|
const existingSet = findExistingPositionWrite(currentAnimations, selector, selection.element);
|
|
@@ -82232,102 +82317,14 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82232
82317
|
);
|
|
82233
82318
|
return { status: "persisted", ownsDragOffset: await finalizeScaleResizeCommit() };
|
|
82234
82319
|
}
|
|
82235
|
-
const
|
|
82236
|
-
|
|
82237
|
-
|
|
82238
|
-
const
|
|
82239
|
-
|
|
82240
|
-
|
|
82241
|
-
|
|
82242
|
-
|
|
82243
|
-
} else if (!anim.keyframes) {
|
|
82244
|
-
const resolvedFromValues = selector ? readAllAnimatedProperties(iframe, selector, anim, resizeGroup) : void 0;
|
|
82245
|
-
await commitMutation(
|
|
82246
|
-
selection,
|
|
82247
|
-
{ type: "convert-to-keyframes", animationId: anim.id, resolvedFromValues },
|
|
82248
|
-
{ label: "Convert to keyframes for resize" }
|
|
82249
|
-
);
|
|
82250
|
-
if (fetchFallbackAnimations) {
|
|
82251
|
-
const fresh = await fetchFallbackAnimations();
|
|
82252
|
-
const refreshed = fresh.find(
|
|
82253
|
-
(a) => a.targetSelector === anim.targetSelector && a.keyframes
|
|
82254
|
-
);
|
|
82255
|
-
if (refreshed) anim = refreshed;
|
|
82256
|
-
}
|
|
82257
|
-
}
|
|
82258
|
-
}
|
|
82259
|
-
if ((outsideRange || useScaleLonghands) && ts !== null) {
|
|
82260
|
-
const kfs = anim.keyframes?.keyframes ?? (() => {
|
|
82261
|
-
const fromProps = anim.method === "from" || anim.method === "fromTo" ? { ...anim.properties } : synthesizeIdentityProps(anim.properties);
|
|
82262
|
-
const toProps = anim.method === "from" ? synthesizeIdentityProps(anim.properties) : { ...anim.properties };
|
|
82263
|
-
return [
|
|
82264
|
-
{ percentage: 0, properties: fromProps },
|
|
82265
|
-
{ percentage: 100, properties: toProps }
|
|
82266
|
-
];
|
|
82267
|
-
})();
|
|
82268
|
-
const newStart = Math.min(ct, ts);
|
|
82269
|
-
const newEnd = Math.max(ct, ts + td);
|
|
82270
|
-
const newDuration = Math.max(0.01, newEnd - newStart);
|
|
82271
|
-
const existingKfs = kfs;
|
|
82272
|
-
const remapped = [];
|
|
82273
|
-
for (const kf of existingKfs) {
|
|
82274
|
-
const absTime = ts + kf.percentage / 100 * td;
|
|
82275
|
-
const newPct = Math.round((absTime - newStart) / newDuration * 1e3) / 10;
|
|
82276
|
-
const props = { ...kf.properties };
|
|
82277
|
-
if (nonUniformScale && "scale" in props) {
|
|
82278
|
-
const uniform = props.scale;
|
|
82279
|
-
if (typeof uniform === "number") {
|
|
82280
|
-
props.scaleX = uniform;
|
|
82281
|
-
props.scaleY = uniform;
|
|
82282
|
-
}
|
|
82283
|
-
delete props.scale;
|
|
82284
|
-
}
|
|
82285
|
-
for (const k of Object.keys(resizeProps)) {
|
|
82286
|
-
if (k in props) continue;
|
|
82287
|
-
if (k === "width" || k === "height") continue;
|
|
82288
|
-
props[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
82289
|
-
}
|
|
82290
|
-
remapped.push({ percentage: newPct, properties: props });
|
|
82291
|
-
}
|
|
82292
|
-
const targetPct = Math.round((ct - newStart) / newDuration * 1e3) / 10;
|
|
82293
|
-
const collidingKf = remapped.find((kf) => Math.abs(kf.percentage - targetPct) < 0.05);
|
|
82294
|
-
if (collidingKf) Object.assign(collidingKf.properties, resizeProps);
|
|
82295
|
-
else remapped.push({ percentage: targetPct, properties: resizeProps });
|
|
82296
|
-
remapped.sort((a, b) => a.percentage - b.percentage);
|
|
82297
|
-
await commitMutation(
|
|
82298
|
-
selection,
|
|
82299
|
-
{
|
|
82300
|
-
type: "replace-with-keyframes",
|
|
82301
|
-
animationId: anim.id,
|
|
82302
|
-
targetSelector: anim.targetSelector,
|
|
82303
|
-
position: roundTo3(newStart),
|
|
82304
|
-
duration: roundTo3(newDuration),
|
|
82305
|
-
keyframes: remapped
|
|
82306
|
-
},
|
|
82307
|
-
{
|
|
82308
|
-
label: outsideRange ? `Resize (extended to ${ct.toFixed(2)}s)` : `Resize (keyframe ${Math.round((ct - newStart) / newDuration * 1e3) / 10}%)`,
|
|
82309
|
-
softReload: true,
|
|
82310
|
-
...!collidingKf ? { keyframeAction: "add" } : {}
|
|
82311
|
-
}
|
|
82312
|
-
);
|
|
82313
|
-
return { status: "persisted", ownsDragOffset: await finalizeScaleResizeCommit() };
|
|
82314
|
-
}
|
|
82315
|
-
const backfillDefaults = {};
|
|
82316
|
-
for (const k of Object.keys(runtimeProps)) {
|
|
82317
|
-
if (SIZE_PROPS.has(k)) continue;
|
|
82318
|
-
backfillDefaults[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
82319
|
-
}
|
|
82320
|
-
await commitMutation(
|
|
82321
|
-
selection,
|
|
82322
|
-
{
|
|
82323
|
-
type: "add-keyframe",
|
|
82324
|
-
animationId: anim.id,
|
|
82325
|
-
percentage: pct,
|
|
82326
|
-
properties: resizeProps,
|
|
82327
|
-
backfillDefaults
|
|
82328
|
-
},
|
|
82329
|
-
{ label: `Resize (keyframe ${pct}%)`, softReload: true }
|
|
82330
|
-
);
|
|
82320
|
+
const callbacks = { commitMutation, fetchAnimations: fetchFallbackAnimations };
|
|
82321
|
+
if (resizeGroup === "size")
|
|
82322
|
+
return commitSizeAtPlayhead(selection, anim, resizeProps, iframe, dragOffset, callbacks);
|
|
82323
|
+
const written = await commitValueAtPlayhead(selection, anim, resizeProps, iframe, callbacks, {
|
|
82324
|
+
label: "Resize",
|
|
82325
|
+
backfill: resizeBackfill
|
|
82326
|
+
});
|
|
82327
|
+
if (written.status !== "persisted") return written;
|
|
82331
82328
|
return { status: "persisted", ownsDragOffset: await finalizeScaleResizeCommit() };
|
|
82332
82329
|
}
|
|
82333
82330
|
|
|
@@ -82690,6 +82687,7 @@ function useGsapAwareEditing({
|
|
|
82690
82687
|
domEditSelection,
|
|
82691
82688
|
selectedGsapAnimations,
|
|
82692
82689
|
gsapCommitMutation,
|
|
82690
|
+
activeCompPath,
|
|
82693
82691
|
previewIframeRef,
|
|
82694
82692
|
showToast,
|
|
82695
82693
|
bumpGsapCache,
|
|
@@ -82753,6 +82751,7 @@ function useGsapAwareEditing({
|
|
|
82753
82751
|
);
|
|
82754
82752
|
const handleGsapAwareGroupPathOffsetCommit = useGsapAwareGroupMove({
|
|
82755
82753
|
gsapCommitMutation,
|
|
82754
|
+
activeCompPath,
|
|
82756
82755
|
previewIframeRef,
|
|
82757
82756
|
makeFetchFallback,
|
|
82758
82757
|
trackGsapInteractionFailure,
|
|
@@ -82760,10 +82759,10 @@ function useGsapAwareEditing({
|
|
|
82760
82759
|
showToast
|
|
82761
82760
|
});
|
|
82762
82761
|
const handleGsapAwareBoxSizeCommit = useCallback146(
|
|
82763
|
-
async (selection, next, offset,
|
|
82762
|
+
async (selection, next, offset, restore2 = () => void 0) => {
|
|
82764
82763
|
const writes = observeGsapGesture(gsapCommitMutation);
|
|
82765
82764
|
if (!gsapWritesBox(selection.element)) {
|
|
82766
|
-
const result = await handleDomBoxSizeCommit(selection, next, offset,
|
|
82765
|
+
const result = await handleDomBoxSizeCommit(selection, next, offset, restore2);
|
|
82767
82766
|
return writes.finish(result?.changed === true);
|
|
82768
82767
|
}
|
|
82769
82768
|
let targetAnimations;
|
|
@@ -82771,7 +82770,7 @@ function useGsapAwareEditing({
|
|
|
82771
82770
|
const ownedAnimations = getGsapAnimationsForSelection(selection);
|
|
82772
82771
|
targetAnimations = Array.isArray(ownedAnimations) ? ownedAnimations : await ownedAnimations;
|
|
82773
82772
|
} catch (error) {
|
|
82774
|
-
|
|
82773
|
+
restore2();
|
|
82775
82774
|
trackGsapInteractionFailure(error, selection, "resize", "Resize animated layer");
|
|
82776
82775
|
throw error;
|
|
82777
82776
|
}
|
|
@@ -82832,7 +82831,8 @@ function useGsapAwareEditing({
|
|
|
82832
82831
|
targetAnimations,
|
|
82833
82832
|
previewIframeRef.current,
|
|
82834
82833
|
commitMutation2,
|
|
82835
|
-
makeFetchFallback(selection)
|
|
82834
|
+
makeFetchFallback(selection),
|
|
82835
|
+
offset
|
|
82836
82836
|
);
|
|
82837
82837
|
assertGsapEditPersisted(outcome);
|
|
82838
82838
|
if (outcome.status === "element-size") {
|
|
@@ -82876,7 +82876,7 @@ function useGsapAwareEditing({
|
|
|
82876
82876
|
},
|
|
82877
82877
|
restore: () => {
|
|
82878
82878
|
anchorMove?.rollback();
|
|
82879
|
-
|
|
82879
|
+
restore2();
|
|
82880
82880
|
},
|
|
82881
82881
|
skipPixelAssert: hasLivePositionTween
|
|
82882
82882
|
});
|
|
@@ -83089,7 +83089,7 @@ function reportSelectionPublishError(error) {
|
|
|
83089
83089
|
console.warn("[Studio] Failed to update agent selection context", error);
|
|
83090
83090
|
}
|
|
83091
83091
|
function putSelection(projectId, selection, signal) {
|
|
83092
|
-
return
|
|
83092
|
+
return studioApiFetch(`/api/projects/${encodeURIComponent(projectId)}/selection`, {
|
|
83093
83093
|
method: "PUT",
|
|
83094
83094
|
headers: { "Content-Type": "application/json" },
|
|
83095
83095
|
body: JSON.stringify({ selection }),
|
|
@@ -83205,7 +83205,7 @@ function useKeyframeEaseCommits({
|
|
|
83205
83205
|
}
|
|
83206
83206
|
|
|
83207
83207
|
// src/hooks/useCommitPreflightCapabilities.ts
|
|
83208
|
-
import { useEffect as useEffect122, useMemo as
|
|
83208
|
+
import { useEffect as useEffect122, useMemo as useMemo74, useRef as useRef153, useState as useState119 } from "react";
|
|
83209
83209
|
function runCommitPreflights(selection, fileAnimations, iframe, group) {
|
|
83210
83210
|
const target = { id: selection.id ?? null, selector: selection.selector ?? null };
|
|
83211
83211
|
const animations = getAnimationsForElement(fileAnimations, target, selection.element);
|
|
@@ -83274,7 +83274,7 @@ function useCommitPreflightCapabilities({
|
|
|
83274
83274
|
});
|
|
83275
83275
|
}
|
|
83276
83276
|
}, [enabled, projectId, selection, groupSelections, version]);
|
|
83277
|
-
return
|
|
83277
|
+
return useMemo74(() => {
|
|
83278
83278
|
void parseTick;
|
|
83279
83279
|
if (!enabled || !projectId) return { selection, groupSelections };
|
|
83280
83280
|
const group = groupSelections.length > 1;
|
|
@@ -83322,6 +83322,70 @@ function useLivePreviewIframe2(host) {
|
|
|
83322
83322
|
return live;
|
|
83323
83323
|
}
|
|
83324
83324
|
|
|
83325
|
+
// src/components/editor/domGroupMoveBy.ts
|
|
83326
|
+
function toScreen(doc, delta) {
|
|
83327
|
+
const origin2 = toTopScreenPoint(doc, { x: 0, y: 0 });
|
|
83328
|
+
const moved = toTopScreenPoint(doc, delta);
|
|
83329
|
+
if (!origin2 || !moved) throw new Error("The preview has no measurable size.");
|
|
83330
|
+
return { x: moved.x - origin2.x, y: moved.y - origin2.y };
|
|
83331
|
+
}
|
|
83332
|
+
function memberFor(selection, scale) {
|
|
83333
|
+
const { element } = selection;
|
|
83334
|
+
const box = element.getBoundingClientRect();
|
|
83335
|
+
const result = createManualOffsetDragMember({
|
|
83336
|
+
key: selection.id ?? selection.selector ?? selection.label,
|
|
83337
|
+
selection,
|
|
83338
|
+
element,
|
|
83339
|
+
rect: {
|
|
83340
|
+
left: box.left,
|
|
83341
|
+
top: box.top,
|
|
83342
|
+
width: box.width,
|
|
83343
|
+
height: box.height,
|
|
83344
|
+
editScaleX: scale.x,
|
|
83345
|
+
editScaleY: scale.y
|
|
83346
|
+
},
|
|
83347
|
+
gesture: "drag"
|
|
83348
|
+
});
|
|
83349
|
+
if (!result.ok) throw new Error(result.reason);
|
|
83350
|
+
return result.member;
|
|
83351
|
+
}
|
|
83352
|
+
async function moveDomGroupBy(moves, commitGroup) {
|
|
83353
|
+
const moving = moves.filter(({ delta }) => delta.x !== 0 || delta.y !== 0);
|
|
83354
|
+
if (moving.length === 0) return;
|
|
83355
|
+
const selections = moving.map(({ selection }) => selection);
|
|
83356
|
+
if (!canCanvasNudgeTargets(selections)) {
|
|
83357
|
+
const blocked = selections.find((s) => !s.capabilities.canApplyManualOffset);
|
|
83358
|
+
throw new Error(blocked?.capabilities.reasonIfDisabled ?? `${blocked?.label} can't be moved.`);
|
|
83359
|
+
}
|
|
83360
|
+
const screens = moving.map(
|
|
83361
|
+
({ selection, delta }) => toScreen(selection.element.ownerDocument, delta)
|
|
83362
|
+
);
|
|
83363
|
+
const members = [];
|
|
83364
|
+
try {
|
|
83365
|
+
for (const selection of selections)
|
|
83366
|
+
members.push(memberFor(selection, toScreen(selection.element.ownerDocument, { x: 1, y: 1 })));
|
|
83367
|
+
} catch (error) {
|
|
83368
|
+
restoreManualOffsetDragMembers(members);
|
|
83369
|
+
throw error;
|
|
83370
|
+
}
|
|
83371
|
+
const updates = members.map((member, index) => ({
|
|
83372
|
+
selection: member.selection,
|
|
83373
|
+
next: applyManualOffsetDragCommit(member, screens[index].x, screens[index].y),
|
|
83374
|
+
plainTranslate: member.plainTranslate
|
|
83375
|
+
}));
|
|
83376
|
+
try {
|
|
83377
|
+
await countStudioManualEditSave(members[0].element, () => commitGroup(updates));
|
|
83378
|
+
} catch (error) {
|
|
83379
|
+
for (const member of members) {
|
|
83380
|
+
if (isStudioManualEditGestureCurrent(member.element, member.gestureToken))
|
|
83381
|
+
restoreStudioPathOffset(member.element, member.initialPathOffset);
|
|
83382
|
+
}
|
|
83383
|
+
throw error;
|
|
83384
|
+
} finally {
|
|
83385
|
+
endManualOffsetDragMembers(members);
|
|
83386
|
+
}
|
|
83387
|
+
}
|
|
83388
|
+
|
|
83325
83389
|
// src/hooks/useDomEditSession.ts
|
|
83326
83390
|
function useDomEditSession({
|
|
83327
83391
|
projectId,
|
|
@@ -83674,6 +83738,7 @@ function useDomEditSession({
|
|
|
83674
83738
|
domEditSelection,
|
|
83675
83739
|
selectedGsapAnimations,
|
|
83676
83740
|
gsapCommitMutation,
|
|
83741
|
+
activeCompPath,
|
|
83677
83742
|
previewIframeRef,
|
|
83678
83743
|
showToast,
|
|
83679
83744
|
bumpGsapCache,
|
|
@@ -83688,6 +83753,13 @@ function useDomEditSession({
|
|
|
83688
83753
|
setArcPath,
|
|
83689
83754
|
updateArcSegment
|
|
83690
83755
|
});
|
|
83756
|
+
const handleDomGroupMoveBy = useCallback148(
|
|
83757
|
+
(moves) => moveDomGroupBy(
|
|
83758
|
+
moves,
|
|
83759
|
+
(updates) => handleGsapAwareGroupPathOffsetCommit(updates, { refusalToast: false })
|
|
83760
|
+
),
|
|
83761
|
+
[handleGsapAwareGroupPathOffsetCommit]
|
|
83762
|
+
);
|
|
83691
83763
|
const { handleUpdateSegmentEase, handleUpdateKeyframeEase, handleSetAllKeyframeEases } = useKeyframeEaseCommits({ gsapCommitMutation, domEditSelectionRef });
|
|
83692
83764
|
const committable = useCommitPreflightCapabilities({
|
|
83693
83765
|
projectId,
|
|
@@ -83725,6 +83797,7 @@ function useDomEditSession({
|
|
|
83725
83797
|
handleDomAttributeBatchCommit,
|
|
83726
83798
|
handleDomPathOffsetCommit: handleGsapAwarePathOffsetCommit,
|
|
83727
83799
|
handleDomGroupPathOffsetCommit: handleGsapAwareGroupPathOffsetCommit,
|
|
83800
|
+
handleDomGroupMoveBy,
|
|
83728
83801
|
handleDomZIndexReorderCommit,
|
|
83729
83802
|
handleDomBoxSizeCommit: handleGsapAwareBoxSizeCommit,
|
|
83730
83803
|
handleDomRotationCommit: handleGsapAwareRotationCommit,
|
|
@@ -83873,7 +83946,7 @@ async function readProjectFileOptional(projectId, path) {
|
|
|
83873
83946
|
let res;
|
|
83874
83947
|
const fetchStarted = performance.now();
|
|
83875
83948
|
try {
|
|
83876
|
-
res = await
|
|
83949
|
+
res = await studioApiFetch(
|
|
83877
83950
|
`/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(path)}?optional=1`
|
|
83878
83951
|
);
|
|
83879
83952
|
} catch {
|
|
@@ -84458,8 +84531,10 @@ function useExternalFileChangeCoordinator({
|
|
|
84458
84531
|
},
|
|
84459
84532
|
[projectId, pendingTimelineEditPathRef, startDrainLoop, onAcceptedPersistedFileChange]
|
|
84460
84533
|
);
|
|
84534
|
+
const processChangeRef = useRef156(processChange);
|
|
84535
|
+
processChangeRef.current = processChange;
|
|
84461
84536
|
useEffect127(() => {
|
|
84462
|
-
const handler = (delivery) =>
|
|
84537
|
+
const handler = (delivery) => processChangeRef.current(decodeFileChange(delivery));
|
|
84463
84538
|
const adapter = testHotAdapter();
|
|
84464
84539
|
if (adapter) {
|
|
84465
84540
|
adapter.on("hf:file-change", handler);
|
|
@@ -84470,7 +84545,7 @@ function useExternalFileChangeCoordinator({
|
|
|
84470
84545
|
return () => import.meta.hot?.off?.("hf:file-change", handler);
|
|
84471
84546
|
}
|
|
84472
84547
|
return sseFileChangeChannel(handler);
|
|
84473
|
-
}, [
|
|
84548
|
+
}, []);
|
|
84474
84549
|
const retry = useCallback150(async () => {
|
|
84475
84550
|
const current = blockedRef.current;
|
|
84476
84551
|
if (!current || current.status === "conflict" || current.recovered) return;
|
|
@@ -84617,7 +84692,7 @@ function useStudioExternalFileChanges({
|
|
|
84617
84692
|
}
|
|
84618
84693
|
|
|
84619
84694
|
// src/hooks/useBlockHandlers.ts
|
|
84620
|
-
import { useCallback as useCallback152, useMemo as
|
|
84695
|
+
import { useCallback as useCallback152, useMemo as useMemo75, useRef as useRef157, useState as useState123 } from "react";
|
|
84621
84696
|
|
|
84622
84697
|
// src/utils/blockInstaller.ts
|
|
84623
84698
|
function getMaxZIndexFromIframe(iframe) {
|
|
@@ -84646,7 +84721,7 @@ async function installRegistryItem({
|
|
|
84646
84721
|
blockName,
|
|
84647
84722
|
showToast
|
|
84648
84723
|
}) {
|
|
84649
|
-
const response = await
|
|
84724
|
+
const response = await studioApiFetch(buildProjectApiPath(projectId, `/registry/install`), {
|
|
84650
84725
|
method: "POST",
|
|
84651
84726
|
headers: { "Content-Type": "application/json" },
|
|
84652
84727
|
body: JSON.stringify({ blockName })
|
|
@@ -84811,7 +84886,7 @@ function useBlockHandlers({
|
|
|
84811
84886
|
setRightPanelTab
|
|
84812
84887
|
}) {
|
|
84813
84888
|
const [activeBlockParams, setActiveBlockParams] = useState123(null);
|
|
84814
|
-
const blockCtx =
|
|
84889
|
+
const blockCtx = useMemo75(
|
|
84815
84890
|
() => ({
|
|
84816
84891
|
activeCompPath: blockCtxDeps.activeCompPath,
|
|
84817
84892
|
timelineElements: blockCtxDeps.timelineElements,
|
|
@@ -85178,7 +85253,7 @@ function dispatchPlainKey(event, key2, cb) {
|
|
|
85178
85253
|
}
|
|
85179
85254
|
|
|
85180
85255
|
// src/hooks/useEditHistoryActions.ts
|
|
85181
|
-
import { useCallback as useCallback153, useMemo as
|
|
85256
|
+
import { useCallback as useCallback153, useMemo as useMemo76 } from "react";
|
|
85182
85257
|
function useEditHistoryActions({
|
|
85183
85258
|
editHistory,
|
|
85184
85259
|
readOptionalProjectFile,
|
|
@@ -85205,20 +85280,25 @@ function useEditHistoryActions({
|
|
|
85205
85280
|
const noun = direction === "undo" ? "Undo" : "Redo";
|
|
85206
85281
|
const predicted = editHistory.predict?.(direction) ?? null;
|
|
85207
85282
|
const predictedShown = predicted ? showHistoryRestoreNow?.(predicted.files) ?? null : null;
|
|
85208
|
-
const pendingEditShown = !predictedShown && direction === "undo" ?
|
|
85209
|
-
const putBack = predictedShown ?? pendingEditShown;
|
|
85283
|
+
const pendingEditShown = !predictedShown && direction === "undo" ? paintBackNewestStudioPendingEdit() : null;
|
|
85284
|
+
const putBack = predictedShown ?? pendingEditShown?.showAgain;
|
|
85285
|
+
const claimedAfter = direction === "undo" && hasStudioPendingEdits() ? editHistory.claims?.() : void 0;
|
|
85210
85286
|
let result = { ok: false, reason: "failed" };
|
|
85211
85287
|
let serverSteppedShown = false;
|
|
85288
|
+
let revertIsTheUndo = false;
|
|
85212
85289
|
try {
|
|
85213
85290
|
await waitForPendingDomEditSaves();
|
|
85291
|
+
revertIsTheUndo = Boolean(pendingEditShown && !await pendingEditShown.landed());
|
|
85292
|
+
if (revertIsTheUndo) return;
|
|
85214
85293
|
result = await editHistory[direction]({
|
|
85215
85294
|
readFile: readHistoryFile,
|
|
85216
|
-
serialize: serializeHistoryFiles
|
|
85295
|
+
serialize: serializeHistoryFiles,
|
|
85296
|
+
claimedAfter
|
|
85217
85297
|
});
|
|
85218
85298
|
const stepped = Boolean(result.ok && result.label);
|
|
85219
85299
|
serverSteppedShown = predictedShown ? stepped && result.undoes === predicted?.id : stepped && Boolean(pendingEditShown);
|
|
85220
85300
|
} finally {
|
|
85221
|
-
if (putBack && !serverSteppedShown) putBack();
|
|
85301
|
+
if (putBack && !serverSteppedShown && !revertIsTheUndo) putBack();
|
|
85222
85302
|
}
|
|
85223
85303
|
if (!result.ok && result.reason === "content-mismatch") {
|
|
85224
85304
|
showToast(
|
|
@@ -85233,12 +85313,12 @@ function useEditHistoryActions({
|
|
|
85233
85313
|
}
|
|
85234
85314
|
if (result.ok && result.label) {
|
|
85235
85315
|
const files = serverSteppedShown && predictedShown ? fromShown(result.files, predicted.files) : result.files;
|
|
85236
|
-
const
|
|
85237
|
-
onAfterUndoRedo?.(
|
|
85316
|
+
const restore2 = { paths: result.paths, files };
|
|
85317
|
+
onAfterUndoRedo?.(restore2);
|
|
85238
85318
|
if (activeCompPath && result.paths?.includes(activeCompPath)) {
|
|
85239
85319
|
forceReloadSdkSession?.();
|
|
85240
85320
|
}
|
|
85241
|
-
await syncHistoryPreviewAfterApply(
|
|
85321
|
+
await syncHistoryPreviewAfterApply(restore2);
|
|
85242
85322
|
showToast(result.label, "info");
|
|
85243
85323
|
}
|
|
85244
85324
|
},
|
|
@@ -85257,7 +85337,7 @@ function useEditHistoryActions({
|
|
|
85257
85337
|
);
|
|
85258
85338
|
const undo = useCallback153(() => apply("undo"), [apply]);
|
|
85259
85339
|
const redo = useCallback153(() => apply("redo"), [apply]);
|
|
85260
|
-
return
|
|
85340
|
+
return useMemo76(() => ({ undo, redo }), [undo, redo]);
|
|
85261
85341
|
}
|
|
85262
85342
|
function fromShown(files, shown2) {
|
|
85263
85343
|
if (!files) return files;
|
|
@@ -86252,7 +86332,7 @@ function useCaptionDetection({
|
|
|
86252
86332
|
if (!captionSrcPath) return;
|
|
86253
86333
|
activating = true;
|
|
86254
86334
|
const srcPath = captionSrcPath;
|
|
86255
|
-
|
|
86335
|
+
studioApiFetch(buildProjectApiPath(projectId, `/files/${encodeURIComponent(srcPath)}`)).then((r) => r.json()).then((data) => {
|
|
86256
86336
|
if (!data.content || !doc || !win || useCaptionStore.getState().isEditMode) return;
|
|
86257
86337
|
const root = doc.querySelector("[data-composition-id]");
|
|
86258
86338
|
const w = parseInt(root?.getAttribute("data-width") ?? "1920", 10);
|
|
@@ -86365,7 +86445,7 @@ function useConsoleErrorCapture(previewIframe) {
|
|
|
86365
86445
|
}
|
|
86366
86446
|
|
|
86367
86447
|
// src/hooks/useFrameCapture.ts
|
|
86368
|
-
import { useMemo as
|
|
86448
|
+
import { useMemo as useMemo77, useState as useState125, useCallback as useCallback157, useRef as useRef162 } from "react";
|
|
86369
86449
|
function useFrameCapture({
|
|
86370
86450
|
projectId,
|
|
86371
86451
|
activeCompPath,
|
|
@@ -86417,7 +86497,10 @@ function useFrameCapture({
|
|
|
86417
86497
|
const controller = new AbortController();
|
|
86418
86498
|
const timeout = setTimeout(() => controller.abort(), 3e4);
|
|
86419
86499
|
try {
|
|
86420
|
-
const response = await
|
|
86500
|
+
const response = await studioApiFetch(href, {
|
|
86501
|
+
cache: "no-store",
|
|
86502
|
+
signal: controller.signal
|
|
86503
|
+
});
|
|
86421
86504
|
clearTimeout(timeout);
|
|
86422
86505
|
if (!response.ok) {
|
|
86423
86506
|
let msg = `Capture failed (${response.status})`;
|
|
@@ -86453,7 +86536,7 @@ function useFrameCapture({
|
|
|
86453
86536
|
},
|
|
86454
86537
|
[activeCompPath, playheadTime, projectId, showToast, waitForPendingDomEditSaves]
|
|
86455
86538
|
);
|
|
86456
|
-
const captureFrameHref =
|
|
86539
|
+
const captureFrameHref = useMemo77(
|
|
86457
86540
|
() => projectId ? buildFrameCaptureUrl({
|
|
86458
86541
|
projectId,
|
|
86459
86542
|
compositionPath: activeCompPath,
|
|
@@ -86473,7 +86556,7 @@ function useFrameCapture({
|
|
|
86473
86556
|
}
|
|
86474
86557
|
|
|
86475
86558
|
// src/hooks/useLintModal.ts
|
|
86476
|
-
import { useState as useState126, useCallback as useCallback158, useEffect as useEffect131, useRef as useRef163, useMemo as
|
|
86559
|
+
import { useState as useState126, useCallback as useCallback158, useEffect as useEffect131, useRef as useRef163, useMemo as useMemo78 } from "react";
|
|
86477
86560
|
function parseFinding(f) {
|
|
86478
86561
|
return {
|
|
86479
86562
|
severity: f.severity === "error" ? "error" : "warning",
|
|
@@ -86484,7 +86567,7 @@ function parseFinding(f) {
|
|
|
86484
86567
|
};
|
|
86485
86568
|
}
|
|
86486
86569
|
async function fetchLintFindings(projectId) {
|
|
86487
|
-
const res = await
|
|
86570
|
+
const res = await studioApiFetch(buildProjectApiPath(projectId, `/lint`));
|
|
86488
86571
|
const data = await res.json();
|
|
86489
86572
|
return (data.findings ?? []).map(parseFinding);
|
|
86490
86573
|
}
|
|
@@ -86546,8 +86629,8 @@ function useLintModal(projectId, refreshKey) {
|
|
|
86546
86629
|
},
|
|
86547
86630
|
[backgroundFindings]
|
|
86548
86631
|
);
|
|
86549
|
-
const findingsByElement =
|
|
86550
|
-
const findingsByFile =
|
|
86632
|
+
const findingsByElement = useMemo78(() => groupFindings((f) => f.elementId), [groupFindings]);
|
|
86633
|
+
const findingsByFile = useMemo78(() => groupFindings((f) => f.file), [groupFindings]);
|
|
86551
86634
|
const badgeFindings = lintModal ?? backgroundFindings;
|
|
86552
86635
|
const lintFindingCount = badgeFindings.length;
|
|
86553
86636
|
const hasLintError = badgeFindings.some((f) => f.severity === "error");
|
|
@@ -87012,16 +87095,16 @@ function useStudioUrlState({
|
|
|
87012
87095
|
}
|
|
87013
87096
|
|
|
87014
87097
|
// src/hooks/useEffectiveTimelineDuration.ts
|
|
87015
|
-
import { useMemo as
|
|
87098
|
+
import { useMemo as useMemo79 } from "react";
|
|
87016
87099
|
function useEffectiveTimelineDuration(timelineDuration2, timelineElements) {
|
|
87017
|
-
return
|
|
87100
|
+
return useMemo79(
|
|
87018
87101
|
() => getEffectiveTimelineDuration(timelineDuration2, timelineElements),
|
|
87019
87102
|
[timelineDuration2, timelineElements]
|
|
87020
87103
|
);
|
|
87021
87104
|
}
|
|
87022
87105
|
|
|
87023
87106
|
// src/hooks/useStudioContextValue.ts
|
|
87024
|
-
import { useCallback as useCallback161, useMemo as
|
|
87107
|
+
import { useCallback as useCallback161, useMemo as useMemo80 } from "react";
|
|
87025
87108
|
function buildStudioContextValue(input) {
|
|
87026
87109
|
return {
|
|
87027
87110
|
projectId: input.projectId,
|
|
@@ -87049,7 +87132,7 @@ function buildStudioContextValue(input) {
|
|
|
87049
87132
|
};
|
|
87050
87133
|
}
|
|
87051
87134
|
function useInspectorState(rightPanel, isPlaying, domEditSelection, isGestureRecording) {
|
|
87052
|
-
return
|
|
87135
|
+
return useMemo80(() => {
|
|
87053
87136
|
const inspectorPanelActive = rightPanel === "layers" || rightPanel === "design";
|
|
87054
87137
|
return {
|
|
87055
87138
|
inspectorPanelActive,
|
|
@@ -87095,7 +87178,7 @@ function useGlobalFileDrop(handleTimelineFileDrop) {
|
|
|
87095
87178
|
import { memo as memo44, useContext as useContext15 } from "react";
|
|
87096
87179
|
|
|
87097
87180
|
// src/contexts/PanelLayoutContext.tsx
|
|
87098
|
-
import { useContext as useContext14, useMemo as
|
|
87181
|
+
import { useContext as useContext14, useMemo as useMemo81 } from "react";
|
|
87099
87182
|
import { jsx as jsx199 } from "react/jsx-runtime";
|
|
87100
87183
|
var PanelLayoutContext = createStableContext("PanelLayoutContext", null);
|
|
87101
87184
|
function usePanelLayoutContext() {
|
|
@@ -87107,7 +87190,7 @@ function PanelLayoutProvider({
|
|
|
87107
87190
|
value: { rightCollapsed, setRightCollapsed, rightPanelTab, setRightPanelTab },
|
|
87108
87191
|
children
|
|
87109
87192
|
}) {
|
|
87110
|
-
const stable =
|
|
87193
|
+
const stable = useMemo81(
|
|
87111
87194
|
() => ({ rightCollapsed, setRightCollapsed, rightPanelTab, setRightPanelTab }),
|
|
87112
87195
|
[rightCollapsed, setRightCollapsed, rightPanelTab, setRightPanelTab]
|
|
87113
87196
|
);
|
|
@@ -88179,7 +88262,7 @@ function useGestureCommit({
|
|
|
88179
88262
|
import { useLayoutEffect as useLayoutEffect13, useRef as useRef168 } from "react";
|
|
88180
88263
|
|
|
88181
88264
|
// src/components/editor/GestureTrailOverlay.tsx
|
|
88182
|
-
import { memo as memo45, useMemo as
|
|
88265
|
+
import { memo as memo45, useMemo as useMemo82 } from "react";
|
|
88183
88266
|
import { Fragment as Fragment57, jsx as jsx203, jsxs as jsxs162 } from "react/jsx-runtime";
|
|
88184
88267
|
var GestureTrailOverlay = memo45(function GestureTrailOverlay2({
|
|
88185
88268
|
samples,
|
|
@@ -88191,7 +88274,7 @@ var GestureTrailOverlay = memo45(function GestureTrailOverlay2({
|
|
|
88191
88274
|
mode,
|
|
88192
88275
|
accentColor = "#3CE6AC"
|
|
88193
88276
|
}) {
|
|
88194
|
-
const trailPoints =
|
|
88277
|
+
const trailPoints = useMemo82(() => {
|
|
88195
88278
|
if (!canvasRect) return "";
|
|
88196
88279
|
if (trail2 && trail2.length > 1) {
|
|
88197
88280
|
return trail2.map((p) => `${p.x - canvasRect.left},${p.y - canvasRect.top}`).join(" ");
|
|
@@ -88199,7 +88282,7 @@ var GestureTrailOverlay = memo45(function GestureTrailOverlay2({
|
|
|
88199
88282
|
if (samples.length === 0) return "";
|
|
88200
88283
|
return samples.filter((s) => s.properties.x != null && s.properties.y != null).map((s) => `${s.properties.x},${s.properties.y}`).join(" ");
|
|
88201
88284
|
}, [samples, trail2, sampleCount, canvasRect?.left, canvasRect?.top]);
|
|
88202
|
-
const simplifiedPath =
|
|
88285
|
+
const simplifiedPath = useMemo82(() => {
|
|
88203
88286
|
if (!simplifiedPoints || simplifiedPoints.size === 0) return "";
|
|
88204
88287
|
const pts = [];
|
|
88205
88288
|
for (const [pct, props] of simplifiedPoints) {
|
|
@@ -88211,7 +88294,7 @@ var GestureTrailOverlay = memo45(function GestureTrailOverlay2({
|
|
|
88211
88294
|
if (pts.length === 0) return "";
|
|
88212
88295
|
return pts.map((p) => `${p.x},${p.y}`).join(" ");
|
|
88213
88296
|
}, [simplifiedPoints]);
|
|
88214
|
-
const diamondPositions =
|
|
88297
|
+
const diamondPositions = useMemo82(() => {
|
|
88215
88298
|
if (!simplifiedPoints || simplifiedPoints.size === 0) return [];
|
|
88216
88299
|
const pts = [];
|
|
88217
88300
|
for (const [pct, props] of simplifiedPoints) {
|
|
@@ -88319,7 +88402,7 @@ function useGestureTrailOverlay({
|
|
|
88319
88402
|
}
|
|
88320
88403
|
|
|
88321
88404
|
// src/hooks/useStudioSidePanels.tsx
|
|
88322
|
-
import { useMemo as
|
|
88405
|
+
import { useMemo as useMemo88 } from "react";
|
|
88323
88406
|
|
|
88324
88407
|
// src/components/StudioLeftPanels.tsx
|
|
88325
88408
|
import { memo as memo49, useCallback as useCallback171 } from "react";
|
|
@@ -88441,7 +88524,7 @@ function MediaPreview({ projectId, filePath }) {
|
|
|
88441
88524
|
}
|
|
88442
88525
|
|
|
88443
88526
|
// src/components/sidebar/AssetsTab.tsx
|
|
88444
|
-
import { memo as memo46, useState as useState137, useCallback as useCallback167, useRef as useRef172, useMemo as
|
|
88527
|
+
import { memo as memo46, useState as useState137, useCallback as useCallback167, useRef as useRef172, useMemo as useMemo84, useEffect as useEffect140 } from "react";
|
|
88445
88528
|
|
|
88446
88529
|
// src/components/ui/SearchInput.tsx
|
|
88447
88530
|
import { jsx as jsx206, jsxs as jsxs164 } from "react/jsx-runtime";
|
|
@@ -89053,7 +89136,7 @@ function AudioRow({
|
|
|
89053
89136
|
}
|
|
89054
89137
|
|
|
89055
89138
|
// src/components/sidebar/GlobalAssetsView.tsx
|
|
89056
|
-
import { useEffect as useEffect137, useMemo as
|
|
89139
|
+
import { useEffect as useEffect137, useMemo as useMemo83, useState as useState134 } from "react";
|
|
89057
89140
|
import { jsx as jsx209, jsxs as jsxs167 } from "react/jsx-runtime";
|
|
89058
89141
|
function globalAssetRows(records, query = "") {
|
|
89059
89142
|
const q = query.trim().toLowerCase();
|
|
@@ -89071,7 +89154,7 @@ function GlobalAssetsView({ searchQuery }) {
|
|
|
89071
89154
|
const [records, setRecords] = useState134(null);
|
|
89072
89155
|
useEffect137(() => {
|
|
89073
89156
|
let cancelled = false;
|
|
89074
|
-
|
|
89157
|
+
studioApiFetch("/api/assets/global").then((r) => r.ok ? r.json() : { assets: [] }).then((d) => {
|
|
89075
89158
|
if (!cancelled) setRecords(Array.isArray(d.assets) ? d.assets : []);
|
|
89076
89159
|
}).catch(() => {
|
|
89077
89160
|
if (!cancelled) setRecords([]);
|
|
@@ -89080,7 +89163,7 @@ function GlobalAssetsView({ searchQuery }) {
|
|
|
89080
89163
|
cancelled = true;
|
|
89081
89164
|
};
|
|
89082
89165
|
}, []);
|
|
89083
|
-
const rows =
|
|
89166
|
+
const rows = useMemo83(() => globalAssetRows(records ?? [], searchQuery), [records, searchQuery]);
|
|
89084
89167
|
if (records === null) {
|
|
89085
89168
|
return /* @__PURE__ */ jsx209("p", { className: "px-4 py-3 text-[11px] text-panel-text-5", children: "Loading global assets\u2026" });
|
|
89086
89169
|
}
|
|
@@ -89592,7 +89675,7 @@ var AssetsTab = memo46(function AssetsTab2({
|
|
|
89592
89675
|
useEffect140(() => {
|
|
89593
89676
|
if (manifest404Ref.current.has(projectId)) return;
|
|
89594
89677
|
let cancelled = false;
|
|
89595
|
-
|
|
89678
|
+
studioApiFetch(buildProjectApiPath(projectId, `/preview/.media/manifest.jsonl`)).then((r) => {
|
|
89596
89679
|
if (!r.ok) {
|
|
89597
89680
|
manifest404Ref.current.add(projectId);
|
|
89598
89681
|
return "";
|
|
@@ -89642,12 +89725,12 @@ var AssetsTab = memo46(function AssetsTab2({
|
|
|
89642
89725
|
setTimeout(() => setCopyFeedback(null), copied ? 1500 : 3e3);
|
|
89643
89726
|
}, []);
|
|
89644
89727
|
const elements = usePlayerStore((s) => s.elements);
|
|
89645
|
-
const usedPaths =
|
|
89646
|
-
const allMediaAssets =
|
|
89728
|
+
const usedPaths = useMemo84(() => deriveUsedPaths(elements), [elements]);
|
|
89729
|
+
const allMediaAssets = useMemo84(
|
|
89647
89730
|
() => assets.filter((a) => MEDIA_EXT.test(a) || FONT_EXT.test(a)),
|
|
89648
89731
|
[assets]
|
|
89649
89732
|
);
|
|
89650
|
-
const mediaAssets =
|
|
89733
|
+
const mediaAssets = useMemo84(() => {
|
|
89651
89734
|
const all = filterByUsage(allMediaAssets, usedPaths, usageFilter);
|
|
89652
89735
|
if (!searchQuery) return all;
|
|
89653
89736
|
const q = searchQuery.toLowerCase();
|
|
@@ -89657,7 +89740,7 @@ var AssetsTab = memo46(function AssetsTab2({
|
|
|
89657
89740
|
return rec?.description?.toLowerCase().includes(q);
|
|
89658
89741
|
});
|
|
89659
89742
|
}, [allMediaAssets, searchQuery, manifest, usageFilter, usedPaths]);
|
|
89660
|
-
const categorized =
|
|
89743
|
+
const categorized = useMemo84(() => {
|
|
89661
89744
|
const groups = { audio: [], images: [], video: [], fonts: [] };
|
|
89662
89745
|
for (const a of mediaAssets) {
|
|
89663
89746
|
const cat = getCategory(a);
|
|
@@ -89672,12 +89755,12 @@ var AssetsTab = memo46(function AssetsTab2({
|
|
|
89672
89755
|
}
|
|
89673
89756
|
return groups;
|
|
89674
89757
|
}, [mediaAssets, usedPaths]);
|
|
89675
|
-
const counts =
|
|
89758
|
+
const counts = useMemo84(() => {
|
|
89676
89759
|
const c = { all: mediaAssets.length };
|
|
89677
89760
|
for (const cat of FILTER_ORDER) c[cat] = categorized[cat].length;
|
|
89678
89761
|
return c;
|
|
89679
89762
|
}, [mediaAssets, categorized]);
|
|
89680
|
-
const usageCounts =
|
|
89763
|
+
const usageCounts = useMemo84(
|
|
89681
89764
|
() => countUsage(
|
|
89682
89765
|
assets.filter((a) => MEDIA_EXT.test(a) || FONT_EXT.test(a)),
|
|
89683
89766
|
usedPaths
|
|
@@ -90337,7 +90420,7 @@ function BlockCard({
|
|
|
90337
90420
|
}
|
|
90338
90421
|
|
|
90339
90422
|
// src/components/sidebar/CompositionsTab.tsx
|
|
90340
|
-
import { memo as memo48, useCallback as useCallback170, useEffect as useEffect143, useLayoutEffect as useLayoutEffect15, useMemo as
|
|
90423
|
+
import { memo as memo48, useCallback as useCallback170, useEffect as useEffect143, useLayoutEffect as useLayoutEffect15, useMemo as useMemo85, useRef as useRef175, useState as useState140 } from "react";
|
|
90341
90424
|
import { jsx as jsx215, jsxs as jsxs172 } from "react/jsx-runtime";
|
|
90342
90425
|
var DEFAULT_PREVIEW_STAGE = { width: 1920, height: 1080 };
|
|
90343
90426
|
var CARD_W = 80;
|
|
@@ -90479,7 +90562,7 @@ function CompCard({
|
|
|
90479
90562
|
const thumbnailUrl2 = compositionCardThumbnailUrl(projectId, comp, contentRevision);
|
|
90480
90563
|
const [thumbnailBox, nearViewport] = useNearViewport();
|
|
90481
90564
|
const timelineSessionEpoch = usePlayerStore((state) => state.timelineSessionEpoch);
|
|
90482
|
-
const thumbnailRequest =
|
|
90565
|
+
const thumbnailRequest = useMemo85(
|
|
90483
90566
|
() => previewBooted && nearViewport ? compositionThumbnailRequest(thumbnailUrl2, projectId, {
|
|
90484
90567
|
sessionEpoch: timelineSessionEpoch,
|
|
90485
90568
|
rich: true
|
|
@@ -94102,7 +94185,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
|
|
|
94102
94185
|
}
|
|
94103
94186
|
|
|
94104
94187
|
// src/components/panels/VariablesPanel.tsx
|
|
94105
|
-
import { memo as memo58, useCallback as useCallback183, useEffect as useEffect151, useMemo as
|
|
94188
|
+
import { memo as memo58, useCallback as useCallback183, useEffect as useEffect151, useMemo as useMemo86, useState as useState154 } from "react";
|
|
94106
94189
|
|
|
94107
94190
|
// src/hooks/useVariablesPersist.ts
|
|
94108
94191
|
import { useCallback as useCallback180 } from "react";
|
|
@@ -94798,22 +94881,22 @@ var VariablesPanel = memo58(function VariablesPanel2({
|
|
|
94798
94881
|
reloadPreview,
|
|
94799
94882
|
publishSdkSession
|
|
94800
94883
|
});
|
|
94801
|
-
const declarations =
|
|
94884
|
+
const declarations = useMemo86(
|
|
94802
94885
|
() => sdkSession?.getVariableDeclarations() ?? [],
|
|
94803
94886
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
94804
94887
|
[sdkSession, refreshKey, revision]
|
|
94805
94888
|
);
|
|
94806
|
-
const usage =
|
|
94889
|
+
const usage = useMemo86(
|
|
94807
94890
|
() => sdkSession?.getVariableUsage() ?? null,
|
|
94808
94891
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
94809
94892
|
[sdkSession, refreshKey, revision]
|
|
94810
94893
|
);
|
|
94811
|
-
const issues =
|
|
94894
|
+
const issues = useMemo86(
|
|
94812
94895
|
() => previewValues && sdkSession ? sdkSession.validateVariableValues(previewValues) : [],
|
|
94813
94896
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
94814
94897
|
[sdkSession, previewValues, refreshKey, revision]
|
|
94815
94898
|
);
|
|
94816
|
-
const effectiveValues =
|
|
94899
|
+
const effectiveValues = useMemo86(
|
|
94817
94900
|
() => sdkSession?.getVariableValues(previewValues ?? void 0) ?? {},
|
|
94818
94901
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
94819
94902
|
[sdkSession, previewValues, refreshKey, revision]
|
|
@@ -95128,15 +95211,15 @@ function useSlideshowPersist({
|
|
|
95128
95211
|
}
|
|
95129
95212
|
|
|
95130
95213
|
// src/hooks/useSlideshowTabState.ts
|
|
95131
|
-
import { useMemo as
|
|
95214
|
+
import { useMemo as useMemo87 } from "react";
|
|
95132
95215
|
import { SLIDESHOW_ISLAND_TYPE as SLIDESHOW_ISLAND_TYPE2, slideshowIslandRegex as slideshowIslandRegex2 } from "@hyperframes/core/slideshow";
|
|
95133
95216
|
function useSlideshowTabState(params) {
|
|
95134
95217
|
const { editingFileContent, previewIframeRef, refreshKey, slideshowVisible } = params;
|
|
95135
|
-
const isSlideshowComposition =
|
|
95218
|
+
const isSlideshowComposition = useMemo87(() => {
|
|
95136
95219
|
if (!editingFileContent || !editingFileContent.includes(SLIDESHOW_ISLAND_TYPE2)) return false;
|
|
95137
95220
|
return slideshowIslandRegex2("i").test(editingFileContent);
|
|
95138
95221
|
}, [editingFileContent]);
|
|
95139
|
-
const slideshowScenes =
|
|
95222
|
+
const slideshowScenes = useMemo87(() => {
|
|
95140
95223
|
try {
|
|
95141
95224
|
const win = previewIframeRef.current?.contentWindow;
|
|
95142
95225
|
return (win?.__clipManifest?.scenes ?? []).map((s) => ({
|
|
@@ -95313,7 +95396,7 @@ function useRemoveBackground(projectId, refreshFileTree, showToast) {
|
|
|
95313
95396
|
return useCallback186(
|
|
95314
95397
|
// fallow-ignore-next-line complexity
|
|
95315
95398
|
async (inputPath, options) => {
|
|
95316
|
-
const response = await
|
|
95399
|
+
const response = await studioApiFetch(
|
|
95317
95400
|
`/api/projects/${encodeURIComponent(projectId)}/media/remove-background`,
|
|
95318
95401
|
{
|
|
95319
95402
|
method: "POST",
|
|
@@ -95751,7 +95834,7 @@ import { Fragment as Fragment66, jsx as jsx236, jsxs as jsxs189 } from "react/js
|
|
|
95751
95834
|
function useStudioSidePanels(left, right, projectId) {
|
|
95752
95835
|
const stableLeft = useStableHandlers(left, projectId);
|
|
95753
95836
|
const stableRight = useStableHandlers(right, projectId);
|
|
95754
|
-
return
|
|
95837
|
+
return useMemo88(
|
|
95755
95838
|
() => /* @__PURE__ */ jsxs189(Fragment66, { children: [
|
|
95756
95839
|
/* @__PURE__ */ jsx236(StudioLeftPanels, { ...stableLeft }),
|
|
95757
95840
|
/* @__PURE__ */ jsx236(StudioRightPanels, { ...stableRight })
|
|
@@ -95890,7 +95973,7 @@ async function extendKeyframedTweenToPlayhead(session, sel, anim, currentTime, d
|
|
|
95890
95973
|
position: extended.position,
|
|
95891
95974
|
duration: extended.duration,
|
|
95892
95975
|
keyframes: extended.keyframes,
|
|
95893
|
-
|
|
95976
|
+
...keyframeEases(anim)
|
|
95894
95977
|
},
|
|
95895
95978
|
{
|
|
95896
95979
|
label: "Add keyframe",
|
|
@@ -96770,7 +96853,7 @@ function StudioSplash({ waiting }) {
|
|
|
96770
96853
|
import { useEffect as useEffect155, useState as useState156 } from "react";
|
|
96771
96854
|
async function resolveHashProject(id) {
|
|
96772
96855
|
try {
|
|
96773
|
-
const res = await
|
|
96856
|
+
const res = await studioApiFetch(`/api/projects/${encodeURIComponent(id)}`);
|
|
96774
96857
|
if (res.ok) return { outcome: "ok", status: res.status };
|
|
96775
96858
|
return { outcome: res.status === 404 ? "missing" : "unknown", status: res.status };
|
|
96776
96859
|
} catch {
|
|
@@ -96782,7 +96865,7 @@ function replaceProjectHash(projectId) {
|
|
|
96782
96865
|
}
|
|
96783
96866
|
async function firstProjectId() {
|
|
96784
96867
|
try {
|
|
96785
|
-
const res = await
|
|
96868
|
+
const res = await studioApiFetch("/api/projects");
|
|
96786
96869
|
const data = await res.json();
|
|
96787
96870
|
return data.projects?.[0]?.id ?? null;
|
|
96788
96871
|
} catch {
|
|
@@ -96809,7 +96892,7 @@ function useServerConnection() {
|
|
|
96809
96892
|
retryTimer = window.setTimeout(tryConnect, 2e3);
|
|
96810
96893
|
}
|
|
96811
96894
|
function tryConnect() {
|
|
96812
|
-
|
|
96895
|
+
studioApiFetch("/api/projects").then((r) => r.json()).then(async (data) => {
|
|
96813
96896
|
if (cancelled) return;
|
|
96814
96897
|
if (hashProjectId) {
|
|
96815
96898
|
const verdict = await resolveHashProject(hashProjectId);
|
|
@@ -96953,7 +97036,7 @@ function useCompositionContentLoader({
|
|
|
96953
97036
|
if (!projectId) return;
|
|
96954
97037
|
setActiveCompPath(comp.endsWith(".html") ? comp : null);
|
|
96955
97038
|
setEditingFile({ path: comp, content: null });
|
|
96956
|
-
|
|
97039
|
+
studioApiFetch(buildProjectApiPath(projectId, `/files/${encodeURIComponent(comp)}`)).then(async (r) => {
|
|
96957
97040
|
if (!r.ok) throw new Error(`Failed to load ${comp} (${r.status})`);
|
|
96958
97041
|
return r.json();
|
|
96959
97042
|
}).then((data) => {
|
|
@@ -97074,7 +97157,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
|
|
|
97074
97157
|
setRefreshKey
|
|
97075
97158
|
});
|
|
97076
97159
|
const fileManager = useStableHandlers(fileManagerResult, projectId);
|
|
97077
|
-
const masterCompPath =
|
|
97160
|
+
const masterCompPath = useMemo89(
|
|
97078
97161
|
() => resolveMasterCompositionPath(fileManager.compositions),
|
|
97079
97162
|
[fileManager.compositions]
|
|
97080
97163
|
);
|
|
@@ -97178,7 +97261,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
|
|
|
97178
97261
|
} = useStableHandlers(blockHandlersResult, projectId);
|
|
97179
97262
|
const dismissBlockParams = useCallback194(() => setActiveBlockParams(null), [setActiveBlockParams]);
|
|
97180
97263
|
const setRightPanelTab = useDismissingTabSetter(panelLayout.setRightPanelTab, dismissBlockParams);
|
|
97181
|
-
const layout =
|
|
97264
|
+
const layout = useMemo89(
|
|
97182
97265
|
() => ({ ...panelLayout, setRightPanelTab }),
|
|
97183
97266
|
[panelLayout, setRightPanelTab]
|
|
97184
97267
|
);
|
|
@@ -97227,9 +97310,9 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
|
|
|
97227
97310
|
handleDuplicate,
|
|
97228
97311
|
onResetKeyframes: () => resetKeyframesRef.current(),
|
|
97229
97312
|
onDeleteSelectedKeyframes: () => deleteSelectedKeyframesRef.current(),
|
|
97230
|
-
onAfterUndoRedo: (
|
|
97313
|
+
onAfterUndoRedo: (restore2) => {
|
|
97231
97314
|
invalidateGsapCacheRef.current();
|
|
97232
|
-
timelineEditing.restoreLiveLanes(
|
|
97315
|
+
timelineEditing.restoreLiveLanes(restore2);
|
|
97233
97316
|
},
|
|
97234
97317
|
onGroupSelection: () => domEditSessionRef.current.handleGroupSelection(),
|
|
97235
97318
|
onUngroupSelection: () => domEditSessionRef.current.handleUngroupSelection(),
|
|
@@ -97403,7 +97486,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
|
|
|
97403
97486
|
handlePreviewIframeRef,
|
|
97404
97487
|
refreshPreviewDocumentVersion
|
|
97405
97488
|
});
|
|
97406
|
-
const timelineToolbar =
|
|
97489
|
+
const timelineToolbar = useMemo89(
|
|
97407
97490
|
() => /* @__PURE__ */ jsx244(
|
|
97408
97491
|
TimelineToolbar,
|
|
97409
97492
|
{
|
|
@@ -97912,7 +97995,7 @@ function findElementBlock(html2, elementId2) {
|
|
|
97912
97995
|
}
|
|
97913
97996
|
|
|
97914
97997
|
// src/hooks/useDomStyleCommit.ts
|
|
97915
|
-
import { useCallback as useCallback196, useMemo as
|
|
97998
|
+
import { useCallback as useCallback196, useMemo as useMemo90, useRef as useRef189, useState as useState160 } from "react";
|
|
97916
97999
|
var noop = () => {
|
|
97917
98000
|
};
|
|
97918
98001
|
function useDomStyleCommit({
|
|
@@ -97928,7 +98011,7 @@ function useDomStyleCommit({
|
|
|
97928
98011
|
const [queue2] = useState160(createDomEditSaveQueue);
|
|
97929
98012
|
useMountEffect(() => () => queue2.destroy());
|
|
97930
98013
|
const versions = useRef189(/* @__PURE__ */ new Map()).current;
|
|
97931
|
-
const editHistory =
|
|
98014
|
+
const editHistory = useMemo90(() => ({ recordEdit }), [recordEdit]);
|
|
97932
98015
|
const persistDomEditOperations = useDomEditPersist({
|
|
97933
98016
|
activeCompPath,
|
|
97934
98017
|
previewIframeRef: iframeRef,
|
|
@@ -97960,7 +98043,7 @@ function useDomStyleCommit({
|
|
|
97960
98043
|
}
|
|
97961
98044
|
|
|
97962
98045
|
// src/hooks/useDomGeometryCommit.ts
|
|
97963
|
-
import { useCallback as useCallback197, useMemo as
|
|
98046
|
+
import { useCallback as useCallback197, useMemo as useMemo91, useRef as useRef190, useState as useState161 } from "react";
|
|
97964
98047
|
var noop2 = () => {
|
|
97965
98048
|
};
|
|
97966
98049
|
var NO_SELECTED_ANIMATIONS = [];
|
|
@@ -97976,7 +98059,7 @@ function useDomGeometryCommit({
|
|
|
97976
98059
|
const projectIdRef = useRef190(projectId);
|
|
97977
98060
|
projectIdRef.current = projectId;
|
|
97978
98061
|
const pending2 = useRef190(/* @__PURE__ */ new Set()).current;
|
|
97979
|
-
const editHistory =
|
|
98062
|
+
const editHistory = useMemo91(() => ({ recordEdit }), [recordEdit]);
|
|
97980
98063
|
const reload = useCallback197(
|
|
97981
98064
|
() => reloadPreview ? reloadPreview() : iframeRef.current?.contentWindow?.location.reload(),
|
|
97982
98065
|
[reloadPreview, iframeRef]
|
|
@@ -98033,6 +98116,7 @@ function useDomGeometryCommit({
|
|
|
98033
98116
|
domEditSelection: null,
|
|
98034
98117
|
selectedGsapAnimations: NO_SELECTED_ANIMATIONS,
|
|
98035
98118
|
gsapCommitMutation: gsap3.commitMutation,
|
|
98119
|
+
activeCompPath,
|
|
98036
98120
|
previewIframeRef: iframeRef,
|
|
98037
98121
|
showToast,
|
|
98038
98122
|
bumpGsapCache,
|
|
@@ -98048,10 +98132,10 @@ function useDomGeometryCommit({
|
|
|
98048
98132
|
updateArcSegment: gsap3.updateArcSegment
|
|
98049
98133
|
});
|
|
98050
98134
|
const saved2 = useCallback197(
|
|
98051
|
-
async (commit,
|
|
98135
|
+
async (commit, restore2 = noop2) => {
|
|
98052
98136
|
const refusal2 = !projectIdRef.current ? "No project is open" : !isPreviewBooted(projectIdRef.current) ? "The preview for this project has not loaded yet" : null;
|
|
98053
98137
|
if (refusal2) {
|
|
98054
|
-
|
|
98138
|
+
restore2();
|
|
98055
98139
|
showToast(refusal2, "error");
|
|
98056
98140
|
throw new Error(refusal2);
|
|
98057
98141
|
}
|
|
@@ -98065,11 +98149,11 @@ function useDomGeometryCommit({
|
|
|
98065
98149
|
},
|
|
98066
98150
|
[pending2, showToast]
|
|
98067
98151
|
);
|
|
98068
|
-
return
|
|
98152
|
+
return useMemo91(
|
|
98069
98153
|
() => ({
|
|
98070
98154
|
commitPathOffset: (selection, next, modifiers) => saved2(() => handleGsapAwarePathOffsetCommit(selection, next, modifiers)),
|
|
98071
98155
|
commitGroupPathOffset: (updates) => saved2(() => handleGsapAwareGroupPathOffsetCommit(updates)),
|
|
98072
|
-
commitBoxSize: (selection, next, offset,
|
|
98156
|
+
commitBoxSize: (selection, next, offset, restore2) => saved2(() => handleGsapAwareBoxSizeCommit(selection, next, offset, restore2), restore2),
|
|
98073
98157
|
commitRotation: (selection, next) => saved2(() => handleGsapAwareRotationCommit(selection, next)),
|
|
98074
98158
|
waitForPendingSaves: () => Promise.allSettled([...pending2]).then(noop2)
|
|
98075
98159
|
}),
|
|
@@ -98093,6 +98177,7 @@ export {
|
|
|
98093
98177
|
AudioMeterStrip,
|
|
98094
98178
|
AudioWaveform,
|
|
98095
98179
|
Button,
|
|
98180
|
+
ColorField,
|
|
98096
98181
|
CompositionBreadcrumb,
|
|
98097
98182
|
CompositionThumbnail,
|
|
98098
98183
|
ConnectedDomEditOverlay,
|
|
@@ -98104,6 +98189,7 @@ export {
|
|
|
98104
98189
|
EditorShell,
|
|
98105
98190
|
ExternalFileConflictBanner,
|
|
98106
98191
|
FileTree,
|
|
98192
|
+
GradientField,
|
|
98107
98193
|
GridOverlay,
|
|
98108
98194
|
HyperframesLoader,
|
|
98109
98195
|
HyperframesLogo,
|
|
@@ -98223,6 +98309,7 @@ export {
|
|
|
98223
98309
|
useProjectFileWriter,
|
|
98224
98310
|
useRenderClipContent,
|
|
98225
98311
|
useRenderQueue,
|
|
98312
|
+
useThumbnailStill,
|
|
98226
98313
|
useTimelineContext,
|
|
98227
98314
|
useTimelineEditing,
|
|
98228
98315
|
useTimelinePlayer
|