@hyperframes/studio 0.8.123 → 0.8.125
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/assets/{hyperframes-player-yABdb6yk.js → hyperframes-player-CmIh-wq9.js} +1 -1
- package/dist/assets/{index-D77MIjSJ.js → index-4LRR6o2F.js} +1 -1
- package/dist/assets/{index-Dt7lWtY7.js → index-CrYoEZ5p.js} +139 -139
- package/dist/assets/{index-LrNlT5Tg.css → index-D11atkBt.css} +1 -1
- package/dist/assets/{index-DWjF2Kxw.js → index-yCK8osBg.js} +1 -1
- package/dist/index.d.ts +43 -35
- package/dist/index.html +2 -2
- package/dist/index.js +283 -143
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +8 -8
- package/src/components/OpenInDesktopButton.dom.test.tsx +27 -10
- package/src/components/OpenInDesktopButton.tsx +22 -15
- package/src/components/editor/domEditOverlayGestures.ts +2 -0
- package/src/components/editor/domEditOverlayStartGesture.ts +6 -0
- package/src/components/editor/dragUndoPaint.test.ts +170 -2
- package/src/components/editor/gestureUndoRevert.ts +104 -0
- package/src/components/editor/manualOffsetDrag.ts +1 -12
- package/src/components/editor/useDomEditNudge.ts +1 -1
- package/src/components/editor/useDomEditOverlayGestures.ts +9 -5
- package/src/hooks/gestureTransaction.test.ts +60 -0
- package/src/hooks/gestureTransaction.ts +5 -2
- package/src/hooks/gsapGestureOutcome.ts +9 -2
- package/src/hooks/gsapResizeDropPoint.test.ts +39 -1
- package/src/hooks/gsapResizeElementSize.test.tsx +27 -0
- package/src/hooks/gsapResizeIntercept.ts +55 -68
- package/src/hooks/gsapScriptCommitTypes.ts +2 -0
- package/src/hooks/useGsapAwareEditing.groupPlan.test.tsx +29 -1
- package/src/hooks/useGsapAwareEditing.test.tsx +1 -0
- package/src/hooks/useGsapAwareEditing.ts +21 -25
- package/src/hooks/useGsapAwareGroupMove.ts +4 -6
- package/src/hooks/useGsapScriptCommits.test.tsx +42 -1
- package/src/hooks/useGsapScriptCommits.ts +12 -3
- package/src/player/components/AudibleVideoClipContent.test.tsx +67 -0
- package/src/player/components/AudibleVideoClipContent.tsx +5 -4
- package/src/player/components/AudioWaveform.tsx +2 -1
- package/src/player/components/ClipPeakMarks.tsx +5 -2
- package/src/player/components/OutOfSyncBadge.tsx +1 -1
- package/src/player/components/Timeline.trackPadding.test.tsx +1 -3
- package/src/player/components/TimelineCanvas.tsx +1 -0
- package/src/player/components/TimelineClip.filmstrip.test.tsx +27 -0
- package/src/player/components/TimelineClipFades.test.tsx +2 -1
- package/src/player/components/timelineClipDragPreview.test.ts +31 -0
- package/src/player/components/timelineClipDragPreview.ts +42 -37
- package/src/player/hooks/useTimelinePlayer.seek.test.ts +11 -0
- package/src/styles/components.css +33 -3
- package/src/utils/studioPendingEdits.test.ts +52 -0
- package/src/utils/studioPendingEdits.ts +55 -10
package/dist/index.js
CHANGED
|
@@ -4187,7 +4187,7 @@ function computeDragPreview(drag, clientX, clientY, ctx3) {
|
|
|
4187
4187
|
drag.element.key ?? drag.element.id,
|
|
4188
4188
|
!isMusicTrack(drag.element)
|
|
4189
4189
|
);
|
|
4190
|
-
const
|
|
4190
|
+
const snapped = snapMoveToTargets(
|
|
4191
4191
|
nextMove.start,
|
|
4192
4192
|
drag.element.duration,
|
|
4193
4193
|
targets,
|
|
@@ -4197,6 +4197,9 @@ function computeDragPreview(drag, clientX, clientY, ctx3) {
|
|
|
4197
4197
|
dragMaxStart + drag.element.duration,
|
|
4198
4198
|
ctx3.gridStep
|
|
4199
4199
|
);
|
|
4200
|
+
const target = snapTarget(snapped);
|
|
4201
|
+
const missed = target !== null && !guideIfSaved(drag.element, { start: snapped.start }, target, pps);
|
|
4202
|
+
const snap = missed ? { start: nextMove.start, snapTime: null, snapType: null } : snapped;
|
|
4200
4203
|
const group = resolveGroupDrag(drag, ctx3);
|
|
4201
4204
|
const dragKey = drag.element.key ?? drag.element.id;
|
|
4202
4205
|
const passengers = ctx3.elements.filter(
|
|
@@ -4213,8 +4216,7 @@ function computeDragPreview(drag, clientX, clientY, ctx3) {
|
|
|
4213
4216
|
return { ...drag, started: true };
|
|
4214
4217
|
}
|
|
4215
4218
|
const { track: previewTrack, insertRow } = placement;
|
|
4216
|
-
const
|
|
4217
|
-
const guide = guideIfSaved(drag.element, { start: snap.start }, target, pps);
|
|
4219
|
+
const guide = placement.start === snap.start ? snapTarget(snap) : null;
|
|
4218
4220
|
return {
|
|
4219
4221
|
...drag,
|
|
4220
4222
|
started: true,
|
|
@@ -4230,6 +4232,7 @@ function computeDragPreview(drag, clientX, clientY, ctx3) {
|
|
|
4230
4232
|
snapType: guide?.type ?? null
|
|
4231
4233
|
};
|
|
4232
4234
|
}
|
|
4235
|
+
var snapTarget = (s) => s.snapTime !== null && s.snapType !== null ? { time: s.snapTime, type: s.snapType } : null;
|
|
4233
4236
|
function guideIfSaved(element, clip, target, pps) {
|
|
4234
4237
|
if (!target) return null;
|
|
4235
4238
|
const saved2 = savedClipEdges(element, clip.start, clip.duration);
|
|
@@ -4273,30 +4276,30 @@ function computeResizePreview(resize2, clientX, ctx3) {
|
|
|
4273
4276
|
);
|
|
4274
4277
|
const gridStep = ctx3.gridStep ?? 0;
|
|
4275
4278
|
let snap = null;
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4279
|
+
const snapSecs = TIMELINE_SNAP_PX / Math.max(pps, 1);
|
|
4280
|
+
if (resize2.edge === "end") {
|
|
4281
|
+
const edgeTime2 = nextResize.start + nextResize.duration;
|
|
4282
|
+
const { time: snapped, target } = snapTimelineTime(edgeTime2, trimTargets, snapSecs, gridStep);
|
|
4283
|
+
const snappedDuration = Math.round((snapped - nextResize.start) * 1e3) / 1e3;
|
|
4284
|
+
if (target && snapped <= maxEnd + 1e-6 && snappedDuration >= resolveTimelineMinDuration() - 1e-6) {
|
|
4285
|
+
const onTarget = snapped === edgeTime2 ? nextResize : { ...nextResize, duration: snappedDuration };
|
|
4286
|
+
snap = guideIfSaved(resize2.element, onTarget, target, pps);
|
|
4287
|
+
if (snap) nextResize = onTarget;
|
|
4288
|
+
}
|
|
4289
|
+
} else {
|
|
4290
|
+
const { time: snapped, target } = snapTimelineTime(
|
|
4291
|
+
nextResize.start,
|
|
4292
|
+
trimTargets,
|
|
4293
|
+
snapSecs,
|
|
4294
|
+
gridStep
|
|
4295
|
+
);
|
|
4296
|
+
const clip = { ...nextResize, playbackRate: resize2.element.playbackRate };
|
|
4297
|
+
const delta = snapped - nextResize.start;
|
|
4298
|
+
const bounds = clipStartTrimDeltaBounds(clip, minStart, resolveTimelineMinDuration());
|
|
4299
|
+
if (target && delta >= bounds.minDelta - 1e-6 && delta <= bounds.maxDelta + 1e-6) {
|
|
4300
|
+
const onTarget = snapped === nextResize.start ? nextResize : applyClipStartTrimDelta(clip, delta);
|
|
4301
|
+
snap = guideIfSaved(resize2.element, onTarget, target, pps);
|
|
4302
|
+
if (snap) nextResize = onTarget;
|
|
4300
4303
|
}
|
|
4301
4304
|
}
|
|
4302
4305
|
return {
|
|
@@ -11831,7 +11834,10 @@ function asElement(target) {
|
|
|
11831
11834
|
var STUDIO_FLUSH_PENDING_EDITS_EVENT = "hf-studio-flush-pending-edits";
|
|
11832
11835
|
var pendingEdits = /* @__PURE__ */ new Map();
|
|
11833
11836
|
var NOT_SAVED = () => Promise.resolve(false);
|
|
11834
|
-
var adopting =
|
|
11837
|
+
var adopting = null;
|
|
11838
|
+
function adoptingStudioPendingEdit() {
|
|
11839
|
+
return adopting;
|
|
11840
|
+
}
|
|
11835
11841
|
function waitForPostBlurEffects() {
|
|
11836
11842
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
11837
11843
|
}
|
|
@@ -11874,7 +11880,7 @@ function trackStudioPendingEdit(result) {
|
|
|
11874
11880
|
if (!result) return void 0;
|
|
11875
11881
|
const promise = Promise.resolve(result);
|
|
11876
11882
|
if (adopting) return promise;
|
|
11877
|
-
pendingEdits.set(promise, { revert: null, landed: NOT_SAVED });
|
|
11883
|
+
pendingEdits.set(promise, { revert: null, landed: NOT_SAVED, redraws: [], showAgain: null });
|
|
11878
11884
|
promise.then(
|
|
11879
11885
|
() => pendingEdits.delete(promise),
|
|
11880
11886
|
() => pendingEdits.delete(promise)
|
|
@@ -11894,25 +11900,49 @@ function beginStudioPendingEdit(revert) {
|
|
|
11894
11900
|
const entry2 = pendingEdits.get(promise);
|
|
11895
11901
|
entry2.revert = revert;
|
|
11896
11902
|
let landed = Promise.resolve(false);
|
|
11903
|
+
let saved2 = false;
|
|
11897
11904
|
entry2.landed = () => landed;
|
|
11905
|
+
const inFlight = {
|
|
11906
|
+
reverted: () => entry2.revert === null && revert !== null,
|
|
11907
|
+
within(run) {
|
|
11908
|
+
const outer = adopting;
|
|
11909
|
+
adopting = inFlight;
|
|
11910
|
+
try {
|
|
11911
|
+
return run();
|
|
11912
|
+
} finally {
|
|
11913
|
+
adopting = outer;
|
|
11914
|
+
}
|
|
11915
|
+
},
|
|
11916
|
+
drawUnlessUndone(draw) {
|
|
11917
|
+
if (inFlight.reverted()) entry2.redraws.push(draw);
|
|
11918
|
+
else draw();
|
|
11919
|
+
},
|
|
11920
|
+
drawKeepingUndone(draw) {
|
|
11921
|
+
if (!inFlight.reverted()) return draw();
|
|
11922
|
+
entry2.showAgain?.();
|
|
11923
|
+
try {
|
|
11924
|
+
return draw();
|
|
11925
|
+
} finally {
|
|
11926
|
+
entry2.showAgain = revert();
|
|
11927
|
+
}
|
|
11928
|
+
},
|
|
11929
|
+
markSaved: () => void (saved2 = true)
|
|
11930
|
+
};
|
|
11898
11931
|
return {
|
|
11899
11932
|
settle,
|
|
11900
|
-
reverted:
|
|
11901
|
-
// Only what `start` registers synchronously is adopted; a
|
|
11933
|
+
reverted: inFlight.reverted,
|
|
11934
|
+
// Only what `start` registers synchronously is adopted; a later write joins only through `within`.
|
|
11902
11935
|
adopt(start) {
|
|
11903
|
-
adopting = true;
|
|
11904
11936
|
try {
|
|
11905
|
-
const committed = start
|
|
11937
|
+
const committed = inFlight.within(start);
|
|
11906
11938
|
landed = Promise.resolve(committed).then(
|
|
11907
11939
|
() => true,
|
|
11908
|
-
() =>
|
|
11940
|
+
() => saved2
|
|
11909
11941
|
);
|
|
11910
11942
|
return committed;
|
|
11911
11943
|
} catch (error) {
|
|
11912
11944
|
settle();
|
|
11913
11945
|
throw error;
|
|
11914
|
-
} finally {
|
|
11915
|
-
adopting = false;
|
|
11916
11946
|
}
|
|
11917
11947
|
}
|
|
11918
11948
|
};
|
|
@@ -11922,7 +11952,14 @@ function paintBackNewestStudioPendingEdit() {
|
|
|
11922
11952
|
const revert = newest?.revert;
|
|
11923
11953
|
if (!newest || !revert) return null;
|
|
11924
11954
|
newest.revert = null;
|
|
11925
|
-
|
|
11955
|
+
newest.showAgain = revert();
|
|
11956
|
+
return {
|
|
11957
|
+
showAgain: () => {
|
|
11958
|
+
newest.showAgain?.();
|
|
11959
|
+
for (const redraw of newest.redraws.splice(0)) redraw();
|
|
11960
|
+
},
|
|
11961
|
+
landed: newest.landed
|
|
11962
|
+
};
|
|
11926
11963
|
}
|
|
11927
11964
|
function revertNewestStudioPendingEdit() {
|
|
11928
11965
|
return paintBackNewestStudioPendingEdit()?.showAgain ?? null;
|
|
@@ -15955,6 +15992,7 @@ import { jsx as jsx30, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
|
15955
15992
|
var BAR_STEP = 3;
|
|
15956
15993
|
var rendersWaveform = (el) => el.tag === "audio";
|
|
15957
15994
|
var FADE_GHOST_OPACITY = 0.27;
|
|
15995
|
+
var WAVEFORM_LAYER_Z = 10;
|
|
15958
15996
|
function paintWaveformBars(context, bars, height, waveformBarRgb, waveformBaselineRgb, amplitudes) {
|
|
15959
15997
|
bars.forEach((bar, index) => {
|
|
15960
15998
|
const opacity = loudnessToOpacity(amplitudes[index] ?? 0);
|
|
@@ -16113,7 +16151,7 @@ var AudioWaveform = memo10(function AudioWaveform2({
|
|
|
16113
16151
|
else clip.removeAttribute("data-audio-muted");
|
|
16114
16152
|
return () => clip.removeAttribute("data-audio-muted");
|
|
16115
16153
|
}, [muted]);
|
|
16116
|
-
return /* @__PURE__ */ jsx30("div", { ref: rootRef, className: "absolute inset-0", children: /* @__PURE__ */ jsxs17("div", { className: "absolute inset-0 overflow-hidden", style: { zIndex:
|
|
16154
|
+
return /* @__PURE__ */ jsx30("div", { ref: rootRef, className: "absolute inset-0", children: /* @__PURE__ */ jsxs17("div", { className: "absolute inset-0 overflow-hidden", style: { zIndex: WAVEFORM_LAYER_Z }, children: [
|
|
16117
16155
|
/* @__PURE__ */ jsx30(
|
|
16118
16156
|
"canvas",
|
|
16119
16157
|
{
|
|
@@ -18468,7 +18506,7 @@ var OutOfSyncBadge = memo12(function OutOfSyncBadge2({ el }) {
|
|
|
18468
18506
|
"aria-label": `Out of sync with ${partnerName} by ${label} frames`,
|
|
18469
18507
|
title: `Out of sync with ${partnerName} by ${label} \u2014 click for Move or Slip into Sync`,
|
|
18470
18508
|
"data-testid": "out-of-sync-badge",
|
|
18471
|
-
className: "absolute bottom-0.5 left-1 z-[
|
|
18509
|
+
className: "absolute bottom-0.5 left-1 z-[12] cursor-pointer rounded-[3px] bg-red-600 px-1 font-mono text-[9px] leading-[14px] text-white tabular-nums",
|
|
18472
18510
|
onPointerDown: stop,
|
|
18473
18511
|
onDoubleClick: stop,
|
|
18474
18512
|
onClick: open,
|
|
@@ -24016,6 +24054,7 @@ var TimelineCanvas = memo16(function TimelineCanvas2() {
|
|
|
24016
24054
|
draggedClip?.started && draggedClip.insertRow == null && draggedRowIndex >= 0 && /* @__PURE__ */ jsx59(
|
|
24017
24055
|
"div",
|
|
24018
24056
|
{
|
|
24057
|
+
"data-testid": "timeline-drag-landing",
|
|
24019
24058
|
className: "absolute pointer-events-none",
|
|
24020
24059
|
style: {
|
|
24021
24060
|
top: props.rowGeometry.getRowTop(draggedRowIndex) + CLIP_Y,
|
|
@@ -37145,14 +37184,6 @@ function restoreManualOffsetDragMember(member) {
|
|
|
37145
37184
|
}
|
|
37146
37185
|
endStudioManualEditGesture(member.element, member.gestureToken);
|
|
37147
37186
|
}
|
|
37148
|
-
function manualOffsetMoveRevert(members) {
|
|
37149
|
-
if (!members.every((member) => member.plainTranslate)) return null;
|
|
37150
|
-
return () => {
|
|
37151
|
-
const shown2 = members.map((member) => captureStudioPathOffset(member.element));
|
|
37152
|
-
for (const member of members) restoreStudioPathOffset(member.element, member.initialPathOffset);
|
|
37153
|
-
return () => members.forEach((member, i) => restoreStudioPathOffset(member.element, shown2[i]));
|
|
37154
|
-
};
|
|
37155
|
-
}
|
|
37156
37187
|
function restoreManualOffsetDragMembers(members) {
|
|
37157
37188
|
for (const member of members) {
|
|
37158
37189
|
restoreManualOffsetDragMember(member);
|
|
@@ -37197,6 +37228,70 @@ function resumeGsapTimelines(element) {
|
|
|
37197
37228
|
win.__player?.seek?.(t2);
|
|
37198
37229
|
}
|
|
37199
37230
|
|
|
37231
|
+
// src/components/editor/gestureUndoRevert.ts
|
|
37232
|
+
var PLACEMENT = ["position", "left", "top"];
|
|
37233
|
+
var placementOf = (element) => PLACEMENT.map((prop) => element.style.getPropertyValue(prop));
|
|
37234
|
+
function showPlacement(element, placement) {
|
|
37235
|
+
PLACEMENT.forEach((prop, i) => {
|
|
37236
|
+
if (placement[i]) element.style.setProperty(prop, placement[i]);
|
|
37237
|
+
else element.style.removeProperty(prop);
|
|
37238
|
+
});
|
|
37239
|
+
}
|
|
37240
|
+
function readMemberPosition(member) {
|
|
37241
|
+
const gsap3 = member.plainTranslate ? null : getOffsetDragGsap(member.element);
|
|
37242
|
+
return {
|
|
37243
|
+
offset: captureStudioPathOffset(member.element),
|
|
37244
|
+
gsap: gsap3 && {
|
|
37245
|
+
x: Number(gsap3.getProperty(member.element, "x")),
|
|
37246
|
+
y: Number(gsap3.getProperty(member.element, "y"))
|
|
37247
|
+
},
|
|
37248
|
+
placement: placementOf(member.element)
|
|
37249
|
+
};
|
|
37250
|
+
}
|
|
37251
|
+
function showMemberPosition(member, position) {
|
|
37252
|
+
restoreStudioPathOffset(member.element, position.offset);
|
|
37253
|
+
showPlacement(member.element, position.placement);
|
|
37254
|
+
if (position.gsap) getOffsetDragGsap(member.element)?.set(member.element, { ...position.gsap });
|
|
37255
|
+
if (!member.plainTranslate)
|
|
37256
|
+
stampGestureBase(member.element, member.initialOffset, member.baseGsap);
|
|
37257
|
+
}
|
|
37258
|
+
function manualOffsetMoveRevert(members) {
|
|
37259
|
+
const startPlacement = members.map((member) => placementOf(member.element));
|
|
37260
|
+
return () => {
|
|
37261
|
+
const shown2 = members.map(readMemberPosition);
|
|
37262
|
+
members.forEach(
|
|
37263
|
+
(member, i) => showMemberPosition(member, {
|
|
37264
|
+
offset: member.initialPathOffset,
|
|
37265
|
+
gsap: member.plainTranslate ? null : member.baseGsap,
|
|
37266
|
+
placement: startPlacement[i]
|
|
37267
|
+
})
|
|
37268
|
+
);
|
|
37269
|
+
return () => members.forEach((member, i) => showMemberPosition(member, shown2[i]));
|
|
37270
|
+
};
|
|
37271
|
+
}
|
|
37272
|
+
var GSAP_LOOK_PROPS = ["x", "y", "rotation", "scaleX", "scaleY"];
|
|
37273
|
+
function readElementLook(element, gsapOwned) {
|
|
37274
|
+
const gsap3 = gsapOwned ? getOffsetDragGsap(element) : null;
|
|
37275
|
+
return {
|
|
37276
|
+
style: element.getAttribute("style"),
|
|
37277
|
+
gsap: gsap3 && Object.fromEntries(
|
|
37278
|
+
GSAP_LOOK_PROPS.map((prop) => [prop, Number(gsap3.getProperty(element, prop))])
|
|
37279
|
+
)
|
|
37280
|
+
};
|
|
37281
|
+
}
|
|
37282
|
+
function showElementLook(element, look) {
|
|
37283
|
+
if (look.style === null) element.removeAttribute("style");
|
|
37284
|
+
else element.setAttribute("style", look.style);
|
|
37285
|
+
if (look.gsap) getOffsetDragGsap(element)?.set(element, { ...look.gsap });
|
|
37286
|
+
}
|
|
37287
|
+
function elementLookRevert(element, start) {
|
|
37288
|
+
return () => {
|
|
37289
|
+
const shown2 = readElementLook(element, start.gsap !== null);
|
|
37290
|
+
showElementLook(element, start);
|
|
37291
|
+
return () => showElementLook(element, shown2);
|
|
37292
|
+
};
|
|
37293
|
+
}
|
|
37294
|
+
|
|
37200
37295
|
// src/components/editor/rotationDraft.ts
|
|
37201
37296
|
function lastRuleTransform(element) {
|
|
37202
37297
|
let value = "";
|
|
@@ -37975,6 +38070,10 @@ function startGesture(kind, e, opts, options) {
|
|
|
37975
38070
|
const rawContentScaleY = rect.height / (rect.editScaleY * actualHeight);
|
|
37976
38071
|
const contentScaleX = Number.isFinite(rawContentScaleX) && rawContentScaleX > 0 ? rawContentScaleX : 1;
|
|
37977
38072
|
const contentScaleY = Number.isFinite(rawContentScaleY) && rawContentScaleY > 0 ? rawContentScaleY : 1;
|
|
38073
|
+
const initialLook = readElementLook(
|
|
38074
|
+
sel.element,
|
|
38075
|
+
kind !== "drag" && !editsPlainCss(sel.element, kind === "rotate" ? "rotate" : "resize")
|
|
38076
|
+
);
|
|
37978
38077
|
let initialPathOffset = captureStudioPathOffset(sel.element);
|
|
37979
38078
|
let manualEditDragToken;
|
|
37980
38079
|
let pathOffsetMember;
|
|
@@ -38054,6 +38153,7 @@ function startGesture(kind, e, opts, options) {
|
|
|
38054
38153
|
initialPathOffset,
|
|
38055
38154
|
initialRotation: captureStudioRotation(sel.element),
|
|
38056
38155
|
initialBoxSize: captureStudioBoxSize(sel.element),
|
|
38156
|
+
initialLook,
|
|
38057
38157
|
pathOffsetMember,
|
|
38058
38158
|
originLeft: rect.left,
|
|
38059
38159
|
originTop: rect.top,
|
|
@@ -38555,11 +38655,13 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
38555
38655
|
}
|
|
38556
38656
|
applyRotationDraft(sel.element, finalRotation.angle, g.plainRotation);
|
|
38557
38657
|
const commit = { ...finalRotation, plain: g.plainRotation };
|
|
38558
|
-
|
|
38658
|
+
const edit = beginStudioPendingEdit(elementLookRevert(sel.element, g.initialLook));
|
|
38659
|
+
const saved2 = Promise.resolve(edit.adopt(() => opts.onRotationCommitRef.current(sel, commit))).then((result) => trackPreviewEditResult("rotate", "drag", result)).catch((error) => {
|
|
38559
38660
|
logGestureCommitFailure("rotate commit failed", error);
|
|
38560
38661
|
if (g.manualEditDragToken && isStudioManualEditGestureCurrent(sel.element, g.manualEditDragToken))
|
|
38561
38662
|
restoreRotation();
|
|
38562
38663
|
}).finally(() => endStudioManualEditGesture(sel.element, g.manualEditDragToken));
|
|
38664
|
+
edit.settle(saved2);
|
|
38563
38665
|
} else if (g.kind === "drag") {
|
|
38564
38666
|
opts.suppressNextBoxClickRef.current = true;
|
|
38565
38667
|
const dx = g.lastSnappedDx ?? e.clientX - g.startX;
|
|
@@ -38619,14 +38721,15 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
38619
38721
|
restoreStudioBoxSize(sel.element, g.initialBoxSize);
|
|
38620
38722
|
if (finalOffset) restoreStudioPathOffset(sel.element, g.initialPathOffset);
|
|
38621
38723
|
};
|
|
38622
|
-
|
|
38623
|
-
|
|
38624
|
-
).then((result) => trackPreviewEditResult("resize", "drag", result)).catch((error) => {
|
|
38724
|
+
const commitSize = () => opts.onBoxSizeCommitRef.current(sel, finalSize, finalOffset ?? void 0, restore2, member);
|
|
38725
|
+
const edit = beginStudioPendingEdit(elementLookRevert(sel.element, g.initialLook));
|
|
38726
|
+
const saved2 = Promise.resolve(edit.adopt(commitSize)).then((result) => trackPreviewEditResult("resize", "drag", result)).catch((error) => {
|
|
38625
38727
|
logGestureCommitFailure("resize commit failed", error);
|
|
38626
38728
|
}).finally(() => {
|
|
38627
38729
|
if (member) endManualOffsetDragMembers([member]);
|
|
38628
38730
|
else endStudioManualEditGesture(sel.element, g.manualEditDragToken);
|
|
38629
38731
|
});
|
|
38732
|
+
edit.settle(saved2);
|
|
38630
38733
|
logResizeSettle(sel.element, "post-release");
|
|
38631
38734
|
}
|
|
38632
38735
|
};
|
|
@@ -44460,6 +44563,8 @@ function trackKeyframeCommit(mutations, result, options, memberOptions) {
|
|
|
44460
44563
|
|
|
44461
44564
|
// src/hooks/gsapGestureOutcome.ts
|
|
44462
44565
|
function observeGsapGesture(writer) {
|
|
44566
|
+
const edit = adoptingStudioPendingEdit();
|
|
44567
|
+
const join = (run) => edit ? edit.within(run) : run();
|
|
44463
44568
|
let changed = false;
|
|
44464
44569
|
let pendingResults = 0;
|
|
44465
44570
|
const actions = /* @__PURE__ */ new Set();
|
|
@@ -44467,12 +44572,14 @@ function observeGsapGesture(writer) {
|
|
|
44467
44572
|
pendingResults += 1;
|
|
44468
44573
|
return {
|
|
44469
44574
|
...options,
|
|
44575
|
+
...edit && { pendingEdit: edit },
|
|
44470
44576
|
keyframeTelemetry: false,
|
|
44471
44577
|
onResult: (result) => {
|
|
44472
44578
|
pendingResults -= 1;
|
|
44473
44579
|
options.onResult?.(result);
|
|
44474
44580
|
if (!result.ok || result.changed !== true) return;
|
|
44475
44581
|
changed = true;
|
|
44582
|
+
edit?.markSaved();
|
|
44476
44583
|
const members = changedMutationIndices(
|
|
44477
44584
|
result,
|
|
44478
44585
|
calls.length,
|
|
@@ -44488,16 +44595,18 @@ function observeGsapGesture(writer) {
|
|
|
44488
44595
|
};
|
|
44489
44596
|
let commit = null;
|
|
44490
44597
|
if (writer) {
|
|
44491
|
-
commit = (selection, mutation, options) => writer(selection, mutation, observe([{ selection, mutation, options }], options));
|
|
44598
|
+
commit = (selection, mutation, options) => join(() => writer(selection, mutation, observe([{ selection, mutation, options }], options)));
|
|
44492
44599
|
if (writer.batch) {
|
|
44493
44600
|
const batch = writer.batch;
|
|
44494
|
-
commit.batch = (calls, options) => batch(calls, observe(calls, options));
|
|
44601
|
+
commit.batch = (calls, options) => join(() => batch(calls, observe(calls, options)));
|
|
44495
44602
|
}
|
|
44496
44603
|
}
|
|
44497
44604
|
return {
|
|
44498
44605
|
commit,
|
|
44606
|
+
drawKeepingUndone: (draw) => edit ? edit.drawKeepingUndone(draw) : draw(),
|
|
44499
44607
|
recordDomResult: (result) => {
|
|
44500
44608
|
changed ||= result?.changed === true;
|
|
44609
|
+
if (result?.changed) edit?.markSaved();
|
|
44501
44610
|
},
|
|
44502
44611
|
finish: (domChanged = false) => {
|
|
44503
44612
|
if (pendingResults !== 0) return { ok: true, changed: false };
|
|
@@ -44741,7 +44850,8 @@ function runGestureTransaction(tx) {
|
|
|
44741
44850
|
logCommit("start", { label: tx.label, coalesceKey });
|
|
44742
44851
|
tx.settle();
|
|
44743
44852
|
logCommit("settled", { label: tx.label, coalesceKey });
|
|
44744
|
-
const
|
|
44853
|
+
const measure = () => tx.draw ? tx.draw(() => readPixelRect(tx.element)) : readPixelRect(tx.element);
|
|
44854
|
+
const before = !tx.skipPixelAssert ? measure() : null;
|
|
44745
44855
|
const commit = (commitMutation) => {
|
|
44746
44856
|
const wrapped = (selection, mutation, options) => {
|
|
44747
44857
|
mutationCount += 1;
|
|
@@ -44762,7 +44872,7 @@ function runGestureTransaction(tx) {
|
|
|
44762
44872
|
const durationMs = Math.round(performance.now() - startedAt2);
|
|
44763
44873
|
logCommit("persisted", { label: tx.label, coalesceKey });
|
|
44764
44874
|
if (before) {
|
|
44765
|
-
const after =
|
|
44875
|
+
const after = measure();
|
|
44766
44876
|
const delta = pixelDelta(before, after);
|
|
44767
44877
|
if (exceedsPixelTolerance(delta)) {
|
|
44768
44878
|
logCommit("persist-changed-pixels", { label: tx.label, before, after, delta });
|
|
@@ -50698,7 +50808,8 @@ function TextClipContent({ text }) {
|
|
|
50698
50808
|
|
|
50699
50809
|
// src/player/components/AudibleVideoClipContent.tsx
|
|
50700
50810
|
import { jsx as jsx115, jsxs as jsxs84 } from "react/jsx-runtime";
|
|
50701
|
-
var AUDIBLE_VIDEO_WAVE_SHARE = 0.
|
|
50811
|
+
var AUDIBLE_VIDEO_WAVE_SHARE = 0.5;
|
|
50812
|
+
var AUDIO_CLIP_SURFACE = "var(--timeline-clip-audio-bg)";
|
|
50702
50813
|
function AudibleVideoClipContent({
|
|
50703
50814
|
thumbnail,
|
|
50704
50815
|
waveform
|
|
@@ -50709,9 +50820,9 @@ function AudibleVideoClipContent({
|
|
|
50709
50820
|
/* @__PURE__ */ jsx115(
|
|
50710
50821
|
"div",
|
|
50711
50822
|
{
|
|
50712
|
-
className: "absolute inset-x-0 bottom-0
|
|
50823
|
+
className: "audible-video-wave absolute inset-x-0 bottom-0",
|
|
50713
50824
|
"data-testid": "audible-video-wave",
|
|
50714
|
-
style: { height: waveHeight },
|
|
50825
|
+
style: { height: waveHeight, backgroundColor: AUDIO_CLIP_SURFACE },
|
|
50715
50826
|
children: waveform
|
|
50716
50827
|
}
|
|
50717
50828
|
)
|
|
@@ -50760,10 +50871,20 @@ function ClipPeakMarks({
|
|
|
50760
50871
|
},
|
|
50761
50872
|
run.from
|
|
50762
50873
|
)),
|
|
50763
|
-
/* @__PURE__ */ jsxs85(
|
|
50764
|
-
"
|
|
50765
|
-
|
|
50766
|
-
|
|
50874
|
+
/* @__PURE__ */ jsxs85(
|
|
50875
|
+
"span",
|
|
50876
|
+
{
|
|
50877
|
+
className: "absolute top-0 right-1 font-mono text-[9px] leading-none text-red-400",
|
|
50878
|
+
"data-peak-badge": true,
|
|
50879
|
+
children: [
|
|
50880
|
+
"\u25B2",
|
|
50881
|
+
/* @__PURE__ */ jsxs85("span", { "data-peak-text": true, children: [
|
|
50882
|
+
" peaks ",
|
|
50883
|
+
dbText2(peakDbfs)
|
|
50884
|
+
] })
|
|
50885
|
+
]
|
|
50886
|
+
}
|
|
50887
|
+
)
|
|
50767
50888
|
]
|
|
50768
50889
|
}
|
|
50769
50890
|
)
|
|
@@ -81164,13 +81285,22 @@ async function runMutationRequest(mutations, options, showToast, request) {
|
|
|
81164
81285
|
function finishUnchangedMutation(iframe, result, options, reloadPreview) {
|
|
81165
81286
|
if (result.changed !== false) return false;
|
|
81166
81287
|
if (!options.skipReload && (instantPatchesFor(options).length > 0 || options.previewFallbackLatch?.pending)) {
|
|
81167
|
-
|
|
81288
|
+
redrawUnlessPaintedBack(
|
|
81289
|
+
options,
|
|
81290
|
+
() => applyPreviewSync(iframe, result, options, reloadPreview)
|
|
81291
|
+
);
|
|
81168
81292
|
}
|
|
81169
81293
|
return true;
|
|
81170
81294
|
}
|
|
81295
|
+
function redrawUnlessPaintedBack(options, redraw) {
|
|
81296
|
+
if (options.pendingEdit) options.pendingEdit.drawUnlessUndone(redraw);
|
|
81297
|
+
else redraw();
|
|
81298
|
+
}
|
|
81171
81299
|
function refreshMutationPreview(iframe, result, options, reloadPreview, onCacheInvalidate, nestedFiles) {
|
|
81172
|
-
options
|
|
81173
|
-
|
|
81300
|
+
redrawUnlessPaintedBack(options, () => {
|
|
81301
|
+
options.beforeReload?.();
|
|
81302
|
+
applyPreviewSync(iframe, result, options, reloadPreview, nestedFiles);
|
|
81303
|
+
});
|
|
81174
81304
|
onCacheInvalidate();
|
|
81175
81305
|
}
|
|
81176
81306
|
function isActiveCommitTarget(projectIdRef, activeCompPathRef, projectId, compositionPath) {
|
|
@@ -82192,12 +82322,10 @@ function useGsapAwareGroupMove({
|
|
|
82192
82322
|
renderOnCommit = index === lastScriptWrite;
|
|
82193
82323
|
const plain = offsetMembers.get(selection);
|
|
82194
82324
|
if (plain !== void 0) {
|
|
82195
|
-
const
|
|
82196
|
-
selection,
|
|
82197
|
-
|
|
82198
|
-
|
|
82199
|
-
coalesceKey
|
|
82200
|
-
).save();
|
|
82325
|
+
const staged = writes.drawKeepingUndone(
|
|
82326
|
+
() => stageElementPositionOffset(selection, next, plain, coalesceKey)
|
|
82327
|
+
);
|
|
82328
|
+
const result = await staged.save();
|
|
82201
82329
|
writes.recordDomResult(result);
|
|
82202
82330
|
continue;
|
|
82203
82331
|
}
|
|
@@ -82325,7 +82453,7 @@ function tweenUsesScaleLonghands(anim) {
|
|
|
82325
82453
|
);
|
|
82326
82454
|
return inKeyframes || Object.keys(anim?.properties ?? {}).some(isLonghand);
|
|
82327
82455
|
}
|
|
82328
|
-
async function tryGsapResizeIntercept(selection, size, animations, iframe, commitMutation, fetchFallbackAnimations, dragOffset) {
|
|
82456
|
+
async function tryGsapResizeIntercept(selection, size, animations, iframe, commitMutation, fetchFallbackAnimations, dragOffset, draw = (run) => run()) {
|
|
82329
82457
|
const fetchedAnimations = fetchFallbackAnimations ? await fetchFallbackAnimations() : [];
|
|
82330
82458
|
const outcome = preflightGsapResizeIntercept(selection, animations, iframe, fetchedAnimations);
|
|
82331
82459
|
if (outcome.status === "blocked") return outcome;
|
|
@@ -82421,7 +82549,7 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82421
82549
|
scaleDraftEl = el;
|
|
82422
82550
|
committedScale = useScaleLonghands ? { x: newScaleX, y: newScaleY } : { x: newScaleX, y: newScaleX };
|
|
82423
82551
|
if (el) {
|
|
82424
|
-
const dropRect = el.getBoundingClientRect();
|
|
82552
|
+
const dropRect = draw(() => el.getBoundingClientRect());
|
|
82425
82553
|
scaleDraftDropPoint = { x: dropRect.x, y: dropRect.y };
|
|
82426
82554
|
}
|
|
82427
82555
|
} else {
|
|
@@ -82433,39 +82561,50 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
82433
82561
|
}
|
|
82434
82562
|
const finalizeScaleResizeCommit = async () => {
|
|
82435
82563
|
if (!scaleDraftEl) return false;
|
|
82436
|
-
|
|
82437
|
-
if (!scaleDraftDropPoint || !selector)
|
|
82438
|
-
|
|
82439
|
-
|
|
82440
|
-
}
|
|
82441
|
-
const gsapPos = readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 };
|
|
82442
|
-
const { baseGsapX, baseGsapY } = computeDraggedGsapPosition(
|
|
82443
|
-
selection.element,
|
|
82444
|
-
{ x: 0, y: 0 },
|
|
82445
|
-
gsapPos
|
|
82446
|
-
);
|
|
82447
|
-
const base2 = { x: baseGsapX, y: baseGsapY };
|
|
82448
|
-
setElementGsapPosition(scaleDraftEl, base2.x, base2.y);
|
|
82449
|
-
const post2 = scaleDraftEl.getBoundingClientRect();
|
|
82450
|
-
const residual = { x: scaleDraftDropPoint.x - post2.x, y: scaleDraftDropPoint.y - post2.y };
|
|
82451
|
-
if (!Number.isFinite(residual.x) || !Number.isFinite(residual.y)) return false;
|
|
82452
|
-
if (Math.abs(residual.x) < 0.5 && Math.abs(residual.y) < 0.5) {
|
|
82453
|
-
logResize("scale-finalize", { skipped: "already-on-drop-point", residual, base: base2 });
|
|
82454
|
-
return true;
|
|
82564
|
+
const draftEl = scaleDraftEl;
|
|
82565
|
+
if (!scaleDraftDropPoint || !selector) {
|
|
82566
|
+
draw(() => clearStudioBoxSize(draftEl));
|
|
82567
|
+
return false;
|
|
82455
82568
|
}
|
|
82456
|
-
const
|
|
82457
|
-
|
|
82458
|
-
|
|
82459
|
-
|
|
82460
|
-
|
|
82461
|
-
|
|
82462
|
-
|
|
82463
|
-
|
|
82464
|
-
|
|
82465
|
-
|
|
82466
|
-
|
|
82569
|
+
const dropPoint = scaleDraftDropPoint;
|
|
82570
|
+
const measured = draw(() => {
|
|
82571
|
+
clearStudioBoxSize(draftEl);
|
|
82572
|
+
if (committedScale) {
|
|
82573
|
+
setElementGsapScale(draftEl, committedScale.x, committedScale.y);
|
|
82574
|
+
}
|
|
82575
|
+
const gsapPos = readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 };
|
|
82576
|
+
const { baseGsapX, baseGsapY } = computeDraggedGsapPosition(
|
|
82577
|
+
selection.element,
|
|
82578
|
+
{ x: 0, y: 0 },
|
|
82579
|
+
gsapPos
|
|
82580
|
+
);
|
|
82581
|
+
const base3 = { x: baseGsapX, y: baseGsapY };
|
|
82582
|
+
setElementGsapPosition(draftEl, base3.x, base3.y);
|
|
82583
|
+
const post2 = draftEl.getBoundingClientRect();
|
|
82584
|
+
const residual = { x: dropPoint.x - post2.x, y: dropPoint.y - post2.y };
|
|
82585
|
+
if (!Number.isFinite(residual.x) || !Number.isFinite(residual.y)) return null;
|
|
82586
|
+
if (Math.abs(residual.x) < 0.5 && Math.abs(residual.y) < 0.5) {
|
|
82587
|
+
logResize("scale-finalize", { skipped: "already-on-drop-point", residual, base: base3 });
|
|
82588
|
+
return "settled";
|
|
82589
|
+
}
|
|
82590
|
+
const corrected2 = {
|
|
82591
|
+
x: roundTo3(base3.x + residual.x),
|
|
82592
|
+
y: roundTo3(base3.y + residual.y)
|
|
82593
|
+
};
|
|
82594
|
+
logResize("scale-finalize", {
|
|
82595
|
+
dropPoint,
|
|
82596
|
+
post: { x: post2.x, y: post2.y },
|
|
82597
|
+
residual,
|
|
82598
|
+
gsapPos,
|
|
82599
|
+
base: base3,
|
|
82600
|
+
corrected: corrected2
|
|
82601
|
+
});
|
|
82602
|
+
setElementGsapPosition(draftEl, corrected2.x, corrected2.y);
|
|
82603
|
+
return { base: base3, corrected: corrected2 };
|
|
82467
82604
|
});
|
|
82468
|
-
|
|
82605
|
+
if (measured === null) return false;
|
|
82606
|
+
if (measured === "settled") return true;
|
|
82607
|
+
const { base: base2, corrected } = measured;
|
|
82469
82608
|
const currentAnimations = fetchFallbackAnimations ? await fetchFallbackAnimations() : resolved2?.animations ?? animations;
|
|
82470
82609
|
const delta = { x: corrected.x - base2.x, y: corrected.y - base2.y };
|
|
82471
82610
|
const positionTween = pickClosestToPlayhead(
|
|
@@ -82916,8 +83055,10 @@ function useGsapAwareEditing({
|
|
|
82916
83055
|
modifiers
|
|
82917
83056
|
);
|
|
82918
83057
|
await saveMove(outcome, async () => {
|
|
82919
|
-
const
|
|
82920
|
-
|
|
83058
|
+
const staged = writes.drawKeepingUndone(
|
|
83059
|
+
() => stageElementPositionOffset(selection, next, false)
|
|
83060
|
+
);
|
|
83061
|
+
writes.recordDomResult(await staged.save());
|
|
82921
83062
|
});
|
|
82922
83063
|
return writes.finish();
|
|
82923
83064
|
} catch (error) {
|
|
@@ -82990,11 +83131,8 @@ function useGsapAwareEditing({
|
|
|
82990
83131
|
);
|
|
82991
83132
|
await saveMove(dragOutcome, async () => {
|
|
82992
83133
|
const plainAfterSettle = editsPlainCss(selection.element, "move");
|
|
82993
|
-
anchorMove =
|
|
82994
|
-
selection,
|
|
82995
|
-
offset,
|
|
82996
|
-
plainAfterSettle,
|
|
82997
|
-
coalesceKey
|
|
83134
|
+
anchorMove = writes.drawKeepingUndone(
|
|
83135
|
+
() => stageElementPositionOffset(selection, offset, plainAfterSettle, coalesceKey)
|
|
82998
83136
|
);
|
|
82999
83137
|
});
|
|
83000
83138
|
}
|
|
@@ -83002,15 +83140,18 @@ function useGsapAwareEditing({
|
|
|
83002
83140
|
await runGestureTransaction({
|
|
83003
83141
|
element: selection.element,
|
|
83004
83142
|
label: "Resize layer",
|
|
83143
|
+
draw: writes.drawKeepingUndone,
|
|
83005
83144
|
settle: () => {
|
|
83006
83145
|
if (!offset || scaleRoute || !selector) return;
|
|
83007
|
-
|
|
83008
|
-
|
|
83009
|
-
|
|
83010
|
-
|
|
83011
|
-
|
|
83012
|
-
|
|
83013
|
-
|
|
83146
|
+
writes.drawKeepingUndone(() => {
|
|
83147
|
+
const gsapPos = readGsapPositionFromIframe(previewIframeRef.current, selector) ?? {
|
|
83148
|
+
x: 0,
|
|
83149
|
+
y: 0
|
|
83150
|
+
};
|
|
83151
|
+
const { newX, newY } = computeDraggedGsapPosition(selection.element, offset, gsapPos);
|
|
83152
|
+
logResize("sync-settle", { gsapPos, offset, newX, newY });
|
|
83153
|
+
setElementGsapPosition(selection.element, newX, newY);
|
|
83154
|
+
});
|
|
83014
83155
|
},
|
|
83015
83156
|
persist: async (commit, coalesceKey) => {
|
|
83016
83157
|
if (writes.commit) {
|
|
@@ -83023,16 +83164,13 @@ function useGsapAwareEditing({
|
|
|
83023
83164
|
previewIframeRef.current,
|
|
83024
83165
|
commitMutation2,
|
|
83025
83166
|
makeFetchFallback(selection),
|
|
83026
|
-
offset
|
|
83167
|
+
offset,
|
|
83168
|
+
writes.drawKeepingUndone
|
|
83027
83169
|
);
|
|
83028
83170
|
assertGsapEditPersisted(outcome);
|
|
83029
83171
|
if (outcome.status === "element-size") {
|
|
83030
|
-
const result = await
|
|
83031
|
-
selection,
|
|
83032
|
-
next,
|
|
83033
|
-
void 0,
|
|
83034
|
-
void 0,
|
|
83035
|
-
coalesceKey
|
|
83172
|
+
const result = await writes.drawKeepingUndone(
|
|
83173
|
+
() => handleDomBoxSizeCommit(selection, next, void 0, void 0, coalesceKey)
|
|
83036
83174
|
);
|
|
83037
83175
|
writes.recordDomResult(result);
|
|
83038
83176
|
} else cropUndoKey = coalesceKey;
|
|
@@ -83056,11 +83194,8 @@ function useGsapAwareEditing({
|
|
|
83056
83194
|
const anchorResult = await anchorMove?.save();
|
|
83057
83195
|
writes.recordDomResult(anchorResult);
|
|
83058
83196
|
if (cropUndoKey) {
|
|
83059
|
-
const cropResult = await
|
|
83060
|
-
stageCrop,
|
|
83061
|
-
selection,
|
|
83062
|
-
commitPositionPatchToHtml,
|
|
83063
|
-
cropUndoKey
|
|
83197
|
+
const cropResult = await writes.drawKeepingUndone(
|
|
83198
|
+
() => saveCropResize(stageCrop, selection, commitPositionPatchToHtml, cropUndoKey)
|
|
83064
83199
|
);
|
|
83065
83200
|
writes.recordDomResult(cropResult);
|
|
83066
83201
|
}
|
|
@@ -87441,7 +87576,6 @@ function FrameyGlyph({
|
|
|
87441
87576
|
// src/components/OpenInDesktopButton.tsx
|
|
87442
87577
|
import { jsx as jsx203, jsxs as jsxs161 } from "react/jsx-runtime";
|
|
87443
87578
|
var ROUTE = "/api/open-in-desktop";
|
|
87444
|
-
var DOWNLOAD_URL = "https://hyperframes.dev/studio/download";
|
|
87445
87579
|
var GAZE = 2.2;
|
|
87446
87580
|
var OPENING_MS = 1600;
|
|
87447
87581
|
function useDesktopRoute() {
|
|
@@ -87449,7 +87583,10 @@ function useDesktopRoute() {
|
|
|
87449
87583
|
useEffect133(() => {
|
|
87450
87584
|
let live = true;
|
|
87451
87585
|
studioApiFetch(ROUTE).then((res) => res.ok ? res.json() : null).then((body) => {
|
|
87452
|
-
if (live
|
|
87586
|
+
if (!live || body?.available !== true) return;
|
|
87587
|
+
const handoff = body.handoff === true;
|
|
87588
|
+
const downloadUrl = typeof body.downloadUrl === "string" ? body.downloadUrl : null;
|
|
87589
|
+
if (handoff || downloadUrl) setRoute({ handoff, downloadUrl });
|
|
87453
87590
|
}).catch(() => {
|
|
87454
87591
|
});
|
|
87455
87592
|
return () => {
|
|
@@ -87491,7 +87628,7 @@ function OpenInDesktopButton() {
|
|
|
87491
87628
|
const open = async () => {
|
|
87492
87629
|
if (!route.handoff) {
|
|
87493
87630
|
trackStudioEvent("toolbar_action", { action: "open_in_desktop" });
|
|
87494
|
-
setDownloadUrl(
|
|
87631
|
+
setDownloadUrl(route.downloadUrl);
|
|
87495
87632
|
return;
|
|
87496
87633
|
}
|
|
87497
87634
|
if (opening) return;
|
|
@@ -87501,7 +87638,7 @@ function OpenInDesktopButton() {
|
|
|
87501
87638
|
const res = await studioApiFetch(ROUTE, { method: "POST" });
|
|
87502
87639
|
const result = await res.json();
|
|
87503
87640
|
if (result.opened) {
|
|
87504
|
-
showToast("Framey is opening this project in HyperFrames
|
|
87641
|
+
showToast("Framey is opening this project in the HyperFrames desktop app", "info");
|
|
87505
87642
|
await new Promise((done) => setTimeout(done, OPENING_MS));
|
|
87506
87643
|
} else setDownloadUrl(result.downloadUrl);
|
|
87507
87644
|
} catch {
|
|
@@ -87523,17 +87660,20 @@ function OpenInDesktopButton() {
|
|
|
87523
87660
|
arrow: true,
|
|
87524
87661
|
"aria-label": "Meet Framey",
|
|
87525
87662
|
className: "w-72",
|
|
87526
|
-
trigger: /* @__PURE__ */
|
|
87663
|
+
trigger: /* @__PURE__ */ jsxs161(
|
|
87527
87664
|
Button,
|
|
87528
87665
|
{
|
|
87529
87666
|
ref: trigger,
|
|
87530
87667
|
variant: "ghost",
|
|
87531
87668
|
"data-testid": "header-open-in-desktop",
|
|
87532
87669
|
"data-opening": opening || void 0,
|
|
87533
|
-
title: "Open this project in HyperFrames
|
|
87534
|
-
className: "hf-framey-trigger gap-1.5 pl-1
|
|
87535
|
-
icon: /* @__PURE__ */ jsx203(FrameyGlyph, { size:
|
|
87536
|
-
children:
|
|
87670
|
+
title: "Open this project in the HyperFrames desktop app and edit it with Framey",
|
|
87671
|
+
className: "hf-framey-trigger gap-1.5 border border-accent/40 bg-accent/10 pl-1 font-semibold text-text-0 enabled:hover:bg-accent/20",
|
|
87672
|
+
icon: /* @__PURE__ */ jsx203(FrameyGlyph, { size: 24, className: "hf-framey", eyeRef: eye }),
|
|
87673
|
+
children: [
|
|
87674
|
+
opening ? "Opening in the app\u2026" : "Edit with Framey",
|
|
87675
|
+
!opening && /* @__PURE__ */ jsx203("span", { className: "rounded-full bg-accent px-1.5 text-[10px] leading-4 font-bold text-on-accent", children: "New" })
|
|
87676
|
+
]
|
|
87537
87677
|
}
|
|
87538
87678
|
),
|
|
87539
87679
|
children: [
|
|
@@ -87541,7 +87681,7 @@ function OpenInDesktopButton() {
|
|
|
87541
87681
|
/* @__PURE__ */ jsx203(FrameyGlyph, { size: 36 }),
|
|
87542
87682
|
/* @__PURE__ */ jsx203("p", { className: "text-step-12 font-medium text-text-0", children: "Meet Framey" })
|
|
87543
87683
|
] }),
|
|
87544
|
-
/* @__PURE__ */ jsx203("p", { className: "mt-2 text-text-3", children: "I live in
|
|
87684
|
+
/* @__PURE__ */ jsx203("p", { className: "mt-2 text-balance text-text-3", children: "I live in the free HyperFrames desktop app:" }),
|
|
87545
87685
|
/* @__PURE__ */ jsxs161("ul", { className: "mt-1.5 grid gap-1 text-text-1", children: [
|
|
87546
87686
|
/* @__PURE__ */ jsx203("li", { children: "Chat to change anything in the video" }),
|
|
87547
87687
|
/* @__PURE__ */ jsx203("li", { children: "Draw on a frame to point at it" }),
|
|
@@ -87557,7 +87697,7 @@ function OpenInDesktopButton() {
|
|
|
87557
87697
|
rel: "noopener noreferrer",
|
|
87558
87698
|
className: cn(buttonBase, buttonVariants.primary, buttonSizes.md),
|
|
87559
87699
|
onClick: () => trackStudioEvent("toolbar_action", { action: "get_desktop_app" }),
|
|
87560
|
-
children: "Get
|
|
87700
|
+
children: "Get the desktop app"
|
|
87561
87701
|
}
|
|
87562
87702
|
)
|
|
87563
87703
|
] })
|
|
@@ -92969,7 +93109,7 @@ var RenderQueueItem = memo54(function RenderQueueItem2({
|
|
|
92969
93109
|
// src/components/renders/FfmpegRequiredNotice.tsx
|
|
92970
93110
|
import { memo as memo55, useEffect as useEffect148, useRef as useRef181, useState as useState148 } from "react";
|
|
92971
93111
|
import { jsx as jsx228, jsxs as jsxs183 } from "react/jsx-runtime";
|
|
92972
|
-
var
|
|
93112
|
+
var DOWNLOAD_URL = "https://ffmpeg.org/download.html";
|
|
92973
93113
|
var CUE_MS = 1600;
|
|
92974
93114
|
var FOCUS_RING = "outline-hidden focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-studio-accent";
|
|
92975
93115
|
var FfmpegRequiredNotice = memo55(function FfmpegRequiredNotice2({
|
|
@@ -93033,7 +93173,7 @@ var FfmpegRequiredNotice = memo55(function FfmpegRequiredNotice2({
|
|
|
93033
93173
|
/* @__PURE__ */ jsx228(
|
|
93034
93174
|
"a",
|
|
93035
93175
|
{
|
|
93036
|
-
href:
|
|
93176
|
+
href: DOWNLOAD_URL,
|
|
93037
93177
|
target: "_blank",
|
|
93038
93178
|
rel: "noreferrer",
|
|
93039
93179
|
className: `rounded-xs py-0.5 text-[10px] text-panel-text-2 underline-offset-2 transition-colors hover:text-panel-text-0 hover:underline ${FOCUS_RING}`,
|