hyperframes 0.7.44 → 0.7.46
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/cli.js +2347 -1027
- package/dist/hyperframe-runtime.js +21 -21
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +21 -21
- package/dist/skills/hyperframes/SKILL.md +10 -10
- package/dist/skills/hyperframes-cli/SKILL.md +2 -2
- package/dist/studio/assets/{index-8c83yScV.js → index-BGVoOXdg.js} +1 -1
- package/dist/studio/assets/{index-BtAysyap.js → index-BsLQ2qGn.js} +237 -213
- package/dist/studio/assets/{index-BiZvHXPu.js → index-DO2MAFSG.js} +1 -1
- package/dist/studio/assets/index-DoVLXke0.css +1 -0
- package/dist/studio/index.d.ts +0 -10
- package/dist/studio/index.html +2 -2
- package/dist/studio/index.js +354 -363
- package/dist/studio/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/studio/assets/index-BpM6cnfP.css +0 -1
package/dist/studio/index.js
CHANGED
|
@@ -1372,10 +1372,6 @@ var usePlayerStore = create((set, get) => ({
|
|
|
1372
1372
|
setMotionPathCreateAvailable: (available) => set({ motionPathCreateAvailable: available }),
|
|
1373
1373
|
autoKeyframeEnabled: true,
|
|
1374
1374
|
setAutoKeyframeEnabled: (enabled) => set({ autoKeyframeEnabled: enabled }),
|
|
1375
|
-
cropMode: false,
|
|
1376
|
-
setCropMode: (active) => set({ cropMode: active }),
|
|
1377
|
-
cropAvailable: false,
|
|
1378
|
-
setCropAvailable: (available) => set(available ? { cropAvailable: true } : { cropAvailable: false, cropMode: false }),
|
|
1379
1375
|
selectedElementIds: /* @__PURE__ */ new Set(),
|
|
1380
1376
|
toggleSelectedElementId: (id) => set((s) => {
|
|
1381
1377
|
const next = new Set(s.selectedElementIds);
|
|
@@ -1758,10 +1754,8 @@ var SHORTCUT_SECTIONS = [
|
|
|
1758
1754
|
{
|
|
1759
1755
|
title: "Crop",
|
|
1760
1756
|
hints: [
|
|
1761
|
-
{ key: "
|
|
1762
|
-
{ key: "Drag
|
|
1763
|
-
{ key: "Drag frame", label: "Move crop window" },
|
|
1764
|
-
{ key: "Esc", label: "Exit crop (or click outside)" }
|
|
1757
|
+
{ key: "Drag edge", label: "Crop a side" },
|
|
1758
|
+
{ key: "Drag center", label: "Reposition the crop" }
|
|
1765
1759
|
]
|
|
1766
1760
|
},
|
|
1767
1761
|
{
|
|
@@ -16660,9 +16654,7 @@ function StyleSections({
|
|
|
16660
16654
|
assets,
|
|
16661
16655
|
onSetStyle,
|
|
16662
16656
|
onImportAssets,
|
|
16663
|
-
gsapBorderRadius
|
|
16664
|
-
cropMode = false,
|
|
16665
|
-
onCropModeChange
|
|
16657
|
+
gsapBorderRadius
|
|
16666
16658
|
}) {
|
|
16667
16659
|
const styleEditingDisabled = !element.capabilities.canEditStyles;
|
|
16668
16660
|
const isFlex = styles.display === "flex" || styles.display === "inline-flex";
|
|
@@ -17006,21 +16998,7 @@ function StyleSections({
|
|
|
17006
16998
|
onCommit: (next) => commitClipInsetSide("left", next)
|
|
17007
16999
|
}
|
|
17008
17000
|
)
|
|
17009
|
-
] }) })
|
|
17010
|
-
/* @__PURE__ */ jsxs34(
|
|
17011
|
-
"button",
|
|
17012
|
-
{
|
|
17013
|
-
type: "button",
|
|
17014
|
-
disabled: styleEditingDisabled || !onCropModeChange,
|
|
17015
|
-
"aria-pressed": cropMode,
|
|
17016
|
-
onClick: () => onCropModeChange?.(!cropMode),
|
|
17017
|
-
className: `inline-flex h-8 w-fit items-center gap-1.5 rounded-md border px-2 text-[11px] font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${cropMode ? "border-studio-accent/60 bg-studio-accent/15 text-studio-accent" : "border-panel-border bg-panel-input text-panel-text-2 hover:text-white"}`,
|
|
17018
|
-
children: [
|
|
17019
|
-
/* @__PURE__ */ jsx41(Scissors, { size: 13 }),
|
|
17020
|
-
"Crop"
|
|
17021
|
-
]
|
|
17022
|
-
}
|
|
17023
|
-
)
|
|
17001
|
+
] }) })
|
|
17024
17002
|
] }) }),
|
|
17025
17003
|
/* @__PURE__ */ jsx41(Section, { title: "Transparency", icon: /* @__PURE__ */ jsx41(Eye2, { size: 15 }), defaultCollapsed: true, children: /* @__PURE__ */ jsxs34("div", { className: "space-y-4", children: [
|
|
17026
17004
|
/* @__PURE__ */ jsx41(
|
|
@@ -19833,9 +19811,7 @@ var PropertyPanel = memo22(function PropertyPanel2({
|
|
|
19833
19811
|
onSeekToTime,
|
|
19834
19812
|
recordingState,
|
|
19835
19813
|
recordingDuration,
|
|
19836
|
-
onToggleRecording
|
|
19837
|
-
cropMode,
|
|
19838
|
-
onCropModeChange
|
|
19814
|
+
onToggleRecording
|
|
19839
19815
|
}) {
|
|
19840
19816
|
const styles = element?.computedStyles ?? EMPTY_STYLES;
|
|
19841
19817
|
const { showToast } = useStudioShellContext();
|
|
@@ -20267,9 +20243,7 @@ var PropertyPanel = memo22(function PropertyPanel2({
|
|
|
20267
20243
|
assets,
|
|
20268
20244
|
onSetStyle,
|
|
20269
20245
|
onImportAssets,
|
|
20270
|
-
gsapBorderRadius
|
|
20271
|
-
cropMode,
|
|
20272
|
-
onCropModeChange
|
|
20246
|
+
gsapBorderRadius
|
|
20273
20247
|
}
|
|
20274
20248
|
)
|
|
20275
20249
|
] })
|
|
@@ -21082,7 +21056,7 @@ var FileTree = memo24(function FileTree2({
|
|
|
21082
21056
|
});
|
|
21083
21057
|
|
|
21084
21058
|
// src/App.tsx
|
|
21085
|
-
import { useState as
|
|
21059
|
+
import { useState as useState98, useCallback as useCallback114, useRef as useRef100, useMemo as useMemo38, useEffect as useEffect73, useLayoutEffect as useLayoutEffect4 } from "react";
|
|
21086
21060
|
|
|
21087
21061
|
// src/components/renders/useRenderQueue.ts
|
|
21088
21062
|
import { useState as useState38, useEffect as useEffect28, useCallback as useCallback34, useRef as useRef39, useMemo as useMemo18 } from "react";
|
|
@@ -36227,123 +36201,8 @@ function useGestureCommit({
|
|
|
36227
36201
|
return { gestureState, gestureRecording, handleToggleRecording };
|
|
36228
36202
|
}
|
|
36229
36203
|
|
|
36230
|
-
// src/hooks/useCropMode.ts
|
|
36231
|
-
import { useEffect as useEffect50, useMemo as useMemo28, useReducer } from "react";
|
|
36232
|
-
|
|
36233
|
-
// src/components/editor/domEditOverlayCrop.ts
|
|
36234
|
-
function cropRectFromInsets(rect, insets, scaleX, scaleY) {
|
|
36235
|
-
const sx = scaleX > 0 ? scaleX : 1;
|
|
36236
|
-
const sy = scaleY > 0 ? scaleY : 1;
|
|
36237
|
-
const left = rect.left + insets.left * sx;
|
|
36238
|
-
const top = rect.top + insets.top * sy;
|
|
36239
|
-
return {
|
|
36240
|
-
left,
|
|
36241
|
-
top,
|
|
36242
|
-
width: Math.max(0, rect.width - (insets.left + insets.right) * sx),
|
|
36243
|
-
height: Math.max(0, rect.height - (insets.top + insets.bottom) * sy)
|
|
36244
|
-
};
|
|
36245
|
-
}
|
|
36246
|
-
function readElementCropInsets(element) {
|
|
36247
|
-
const inline = element.style.getPropertyValue("clip-path").trim();
|
|
36248
|
-
const value = inline || element.ownerDocument.defaultView?.getComputedStyle(element).clipPath.trim() || "";
|
|
36249
|
-
const parsed = parseInsetClipPathSides(value === "none" ? "" : value);
|
|
36250
|
-
return parsed ?? { top: 0, right: 0, bottom: 0, left: 0, radius: 0 };
|
|
36251
|
-
}
|
|
36252
|
-
function clampInset(value, max) {
|
|
36253
|
-
if (!Number.isFinite(value)) return 0;
|
|
36254
|
-
return Math.min(Math.max(0, value), Math.max(0, max));
|
|
36255
|
-
}
|
|
36256
|
-
function resolveCropInsetFromEdgeDrag(input) {
|
|
36257
|
-
const scaleX = input.scaleX > 0 ? input.scaleX : 1;
|
|
36258
|
-
const scaleY = input.scaleY > 0 ? input.scaleY : 1;
|
|
36259
|
-
const next = { ...input.startInsets };
|
|
36260
|
-
if (input.edge === "left") {
|
|
36261
|
-
next.left = clampInset(
|
|
36262
|
-
input.startInsets.left + input.deltaX / scaleX,
|
|
36263
|
-
input.width - next.right
|
|
36264
|
-
);
|
|
36265
|
-
} else if (input.edge === "right") {
|
|
36266
|
-
next.right = clampInset(
|
|
36267
|
-
input.startInsets.right - input.deltaX / scaleX,
|
|
36268
|
-
input.width - next.left
|
|
36269
|
-
);
|
|
36270
|
-
} else if (input.edge === "top") {
|
|
36271
|
-
next.top = clampInset(
|
|
36272
|
-
input.startInsets.top + input.deltaY / scaleY,
|
|
36273
|
-
input.height - next.bottom
|
|
36274
|
-
);
|
|
36275
|
-
} else {
|
|
36276
|
-
next.bottom = clampInset(
|
|
36277
|
-
input.startInsets.bottom - input.deltaY / scaleY,
|
|
36278
|
-
input.height - next.top
|
|
36279
|
-
);
|
|
36280
|
-
}
|
|
36281
|
-
return next;
|
|
36282
|
-
}
|
|
36283
|
-
function resolveCropInsetFromMoveDrag(input) {
|
|
36284
|
-
const sx = input.scaleX > 0 ? input.scaleX : 1;
|
|
36285
|
-
const sy = input.scaleY > 0 ? input.scaleY : 1;
|
|
36286
|
-
const totalX = input.startInsets.left + input.startInsets.right;
|
|
36287
|
-
const totalY = input.startInsets.top + input.startInsets.bottom;
|
|
36288
|
-
const left = Math.min(Math.max(0, input.startInsets.left + input.deltaX / sx), totalX);
|
|
36289
|
-
const top = Math.min(Math.max(0, input.startInsets.top + input.deltaY / sy), totalY);
|
|
36290
|
-
return { left, right: totalX - left, top, bottom: totalY - top };
|
|
36291
|
-
}
|
|
36292
|
-
function hugRectForElement(rect, element) {
|
|
36293
|
-
const insets = readElementCropInsets(element);
|
|
36294
|
-
if (insets.top <= 0 && insets.right <= 0 && insets.bottom <= 0 && insets.left <= 0) return rect;
|
|
36295
|
-
return cropRectFromInsets(rect, insets, rect.editScaleX, rect.editScaleY);
|
|
36296
|
-
}
|
|
36297
|
-
|
|
36298
|
-
// src/hooks/useCropMode.ts
|
|
36299
|
-
function useCropModeProps() {
|
|
36300
|
-
const cropMode = usePlayerStore((s) => s.cropMode);
|
|
36301
|
-
const setCropMode = usePlayerStore((s) => s.setCropMode);
|
|
36302
|
-
return useMemo28(
|
|
36303
|
-
() => ({
|
|
36304
|
-
cropMode,
|
|
36305
|
-
onCropModeChange: setCropMode
|
|
36306
|
-
}),
|
|
36307
|
-
[cropMode, setCropMode]
|
|
36308
|
-
);
|
|
36309
|
-
}
|
|
36310
|
-
function useCropOverlay(params) {
|
|
36311
|
-
const { selection, groupCount, cropMode, onCropModeChange, overlayRect } = params;
|
|
36312
|
-
useEffect50(() => {
|
|
36313
|
-
if (!cropMode || !onCropModeChange) return;
|
|
36314
|
-
const handleKeyDown = (event) => {
|
|
36315
|
-
if (event.key === "Escape") onCropModeChange(false);
|
|
36316
|
-
};
|
|
36317
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
36318
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
36319
|
-
}, [cropMode, onCropModeChange]);
|
|
36320
|
-
const setCropAvailable = usePlayerStore((s) => s.setCropAvailable);
|
|
36321
|
-
const cropAvailable = Boolean(selection && groupCount <= 1 && selection.capabilities.canCrop);
|
|
36322
|
-
useEffect50(() => {
|
|
36323
|
-
setCropAvailable(cropAvailable);
|
|
36324
|
-
return () => setCropAvailable(false);
|
|
36325
|
-
}, [cropAvailable, setCropAvailable]);
|
|
36326
|
-
const [, bumpAfterExit] = useReducer((x) => x + 1, 0);
|
|
36327
|
-
useEffect50(() => {
|
|
36328
|
-
if (!cropMode) bumpAfterExit();
|
|
36329
|
-
}, [cropMode]);
|
|
36330
|
-
const cropInsets = selection ? readElementCropInsets(selection.element) : null;
|
|
36331
|
-
const hasCropInsets = Boolean(
|
|
36332
|
-
cropInsets && (cropInsets.top > 0 || cropInsets.right > 0 || cropInsets.bottom > 0 || cropInsets.left > 0)
|
|
36333
|
-
);
|
|
36334
|
-
const sx = overlayRect && overlayRect.editScaleX > 0 ? overlayRect.editScaleX : 1;
|
|
36335
|
-
const sy = overlayRect && overlayRect.editScaleY > 0 ? overlayRect.editScaleY : 1;
|
|
36336
|
-
const cropOutlineInsetPx = cropInsets && hasCropInsets && !cropMode ? {
|
|
36337
|
-
top: cropInsets.top * sy,
|
|
36338
|
-
right: cropInsets.right * sx,
|
|
36339
|
-
bottom: cropInsets.bottom * sy,
|
|
36340
|
-
left: cropInsets.left * sx
|
|
36341
|
-
} : void 0;
|
|
36342
|
-
return { hasCropInsets, cropOutlineInsetPx };
|
|
36343
|
-
}
|
|
36344
|
-
|
|
36345
36204
|
// src/components/editor/GestureTrailOverlay.tsx
|
|
36346
|
-
import { memo as memo26, useMemo as
|
|
36205
|
+
import { memo as memo26, useMemo as useMemo28 } from "react";
|
|
36347
36206
|
import { Fragment as Fragment19, jsx as jsx71, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
36348
36207
|
var GestureTrailOverlay = memo26(function GestureTrailOverlay2({
|
|
36349
36208
|
samples,
|
|
@@ -36355,7 +36214,7 @@ var GestureTrailOverlay = memo26(function GestureTrailOverlay2({
|
|
|
36355
36214
|
mode,
|
|
36356
36215
|
accentColor = "#3CE6AC"
|
|
36357
36216
|
}) {
|
|
36358
|
-
const trailPoints =
|
|
36217
|
+
const trailPoints = useMemo28(() => {
|
|
36359
36218
|
if (!canvasRect) return "";
|
|
36360
36219
|
if (trail && trail.length > 1) {
|
|
36361
36220
|
return trail.map((p) => `${p.x - canvasRect.left},${p.y - canvasRect.top}`).join(" ");
|
|
@@ -36363,7 +36222,7 @@ var GestureTrailOverlay = memo26(function GestureTrailOverlay2({
|
|
|
36363
36222
|
if (samples.length === 0) return "";
|
|
36364
36223
|
return samples.filter((s) => s.properties.x != null && s.properties.y != null).map((s) => `${s.properties.x},${s.properties.y}`).join(" ");
|
|
36365
36224
|
}, [samples, trail, sampleCount, canvasRect?.left, canvasRect?.top]);
|
|
36366
|
-
const simplifiedPath =
|
|
36225
|
+
const simplifiedPath = useMemo28(() => {
|
|
36367
36226
|
if (!simplifiedPoints || simplifiedPoints.size === 0) return "";
|
|
36368
36227
|
const pts = [];
|
|
36369
36228
|
for (const [pct, props] of simplifiedPoints) {
|
|
@@ -36375,7 +36234,7 @@ var GestureTrailOverlay = memo26(function GestureTrailOverlay2({
|
|
|
36375
36234
|
if (pts.length === 0) return "";
|
|
36376
36235
|
return pts.map((p) => `${p.x},${p.y}`).join(" ");
|
|
36377
36236
|
}, [simplifiedPoints]);
|
|
36378
|
-
const diamondPositions =
|
|
36237
|
+
const diamondPositions = useMemo28(() => {
|
|
36379
36238
|
if (!simplifiedPoints || simplifiedPoints.size === 0) return [];
|
|
36380
36239
|
const pts = [];
|
|
36381
36240
|
for (const [pct, props] of simplifiedPoints) {
|
|
@@ -36468,7 +36327,7 @@ import {
|
|
|
36468
36327
|
} from "react";
|
|
36469
36328
|
|
|
36470
36329
|
// src/components/sidebar/CompositionsTab.tsx
|
|
36471
|
-
import { memo as memo27, useCallback as useCallback86, useEffect as
|
|
36330
|
+
import { memo as memo27, useCallback as useCallback86, useEffect as useEffect50, useRef as useRef76, useState as useState62 } from "react";
|
|
36472
36331
|
import { jsx as jsx72, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
36473
36332
|
var DEFAULT_PREVIEW_STAGE = { width: 1920, height: 1080 };
|
|
36474
36333
|
var CARD_W = 80;
|
|
@@ -36570,10 +36429,10 @@ function CompCard({
|
|
|
36570
36429
|
});
|
|
36571
36430
|
const thumbnailOffsetX = (CARD_W - stageSize.width * previewScale) / 2;
|
|
36572
36431
|
const thumbnailOffsetY = (CARD_H - stageSize.height * previewScale) / 2;
|
|
36573
|
-
|
|
36432
|
+
useEffect50(() => {
|
|
36574
36433
|
requestIframePlaybackSync(hovered);
|
|
36575
36434
|
}, [hovered, requestIframePlaybackSync]);
|
|
36576
|
-
|
|
36435
|
+
useEffect50(() => {
|
|
36577
36436
|
return () => {
|
|
36578
36437
|
if (hoverTimer.current) clearTimeout(hoverTimer.current);
|
|
36579
36438
|
if (syncTimer.current) clearTimeout(syncTimer.current);
|
|
@@ -36697,10 +36556,10 @@ var CompositionsTab = memo27(function CompositionsTab2({
|
|
|
36697
36556
|
});
|
|
36698
36557
|
|
|
36699
36558
|
// src/components/sidebar/AssetsTab.tsx
|
|
36700
|
-
import { memo as memo28, useState as useState66, useCallback as useCallback88, useRef as useRef78, useMemo as
|
|
36559
|
+
import { memo as memo28, useState as useState66, useCallback as useCallback88, useRef as useRef78, useMemo as useMemo30, useEffect as useEffect54 } from "react";
|
|
36701
36560
|
|
|
36702
36561
|
// src/components/ui/VideoFrameThumbnail.tsx
|
|
36703
|
-
import { useState as useState63, useEffect as
|
|
36562
|
+
import { useState as useState63, useEffect as useEffect51 } from "react";
|
|
36704
36563
|
import { jsx as jsx73 } from "react/jsx-runtime";
|
|
36705
36564
|
function VideoFrameThumbnail({
|
|
36706
36565
|
src,
|
|
@@ -36708,7 +36567,7 @@ function VideoFrameThumbnail({
|
|
|
36708
36567
|
}) {
|
|
36709
36568
|
const [frame, setFrame] = useState63(null);
|
|
36710
36569
|
const [failed2, setFailed] = useState63(false);
|
|
36711
|
-
|
|
36570
|
+
useEffect51(() => {
|
|
36712
36571
|
setFailed(false);
|
|
36713
36572
|
const video = document.createElement("video");
|
|
36714
36573
|
video.crossOrigin = "anonymous";
|
|
@@ -36850,7 +36709,7 @@ var CATEGORY_LABELS = {
|
|
|
36850
36709
|
var FILTER_ORDER = ["audio", "images", "video", "fonts"];
|
|
36851
36710
|
|
|
36852
36711
|
// src/components/sidebar/AudioRow.tsx
|
|
36853
|
-
import { useState as useState64, useRef as useRef77, useEffect as
|
|
36712
|
+
import { useState as useState64, useRef as useRef77, useEffect as useEffect52, useCallback as useCallback87 } from "react";
|
|
36854
36713
|
import { Fragment as Fragment20, jsx as jsx75, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
36855
36714
|
function AudioRow({
|
|
36856
36715
|
projectId,
|
|
@@ -36873,14 +36732,14 @@ function AudioRow({
|
|
|
36873
36732
|
const name = basename(asset);
|
|
36874
36733
|
const subtype = getAudioSubtype(asset);
|
|
36875
36734
|
const serveUrl = `/api/projects/${projectId}/preview/${asset}`;
|
|
36876
|
-
|
|
36735
|
+
useEffect52(() => {
|
|
36877
36736
|
return () => {
|
|
36878
36737
|
cancelAnimationFrame(animRef.current);
|
|
36879
36738
|
audioRef.current?.pause();
|
|
36880
36739
|
actxRef.current?.close();
|
|
36881
36740
|
};
|
|
36882
36741
|
}, []);
|
|
36883
|
-
|
|
36742
|
+
useEffect52(() => {
|
|
36884
36743
|
if (playing) {
|
|
36885
36744
|
const barCount = 24;
|
|
36886
36745
|
const loop = () => {
|
|
@@ -37016,7 +36875,7 @@ function AudioRow({
|
|
|
37016
36875
|
}
|
|
37017
36876
|
|
|
37018
36877
|
// src/components/sidebar/GlobalAssetsView.tsx
|
|
37019
|
-
import { useEffect as
|
|
36878
|
+
import { useEffect as useEffect53, useMemo as useMemo29, useState as useState65 } from "react";
|
|
37020
36879
|
import { jsx as jsx76, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
37021
36880
|
function globalAssetRows(records, query = "") {
|
|
37022
36881
|
const q = query.trim().toLowerCase();
|
|
@@ -37032,7 +36891,7 @@ function globalAssetRows(records, query = "") {
|
|
|
37032
36891
|
}
|
|
37033
36892
|
function GlobalAssetsView({ searchQuery }) {
|
|
37034
36893
|
const [records, setRecords] = useState65(null);
|
|
37035
|
-
|
|
36894
|
+
useEffect53(() => {
|
|
37036
36895
|
let cancelled = false;
|
|
37037
36896
|
fetch("/api/assets/global").then((r) => r.ok ? r.json() : { assets: [] }).then((d) => {
|
|
37038
36897
|
if (!cancelled) setRecords(Array.isArray(d.assets) ? d.assets : []);
|
|
@@ -37043,7 +36902,7 @@ function GlobalAssetsView({ searchQuery }) {
|
|
|
37043
36902
|
cancelled = true;
|
|
37044
36903
|
};
|
|
37045
36904
|
}, []);
|
|
37046
|
-
const rows =
|
|
36905
|
+
const rows = useMemo29(() => globalAssetRows(records ?? [], searchQuery), [records, searchQuery]);
|
|
37047
36906
|
if (records === null) {
|
|
37048
36907
|
return /* @__PURE__ */ jsx76("p", { className: "px-4 py-3 text-[11px] text-panel-text-5", children: "Loading global assets\u2026" });
|
|
37049
36908
|
}
|
|
@@ -37233,7 +37092,7 @@ var AssetsTab = memo28(function AssetsTab2({
|
|
|
37233
37092
|
const [manifest, setManifest] = useState66(/* @__PURE__ */ new Map());
|
|
37234
37093
|
const manifest404Ref = useRef78(/* @__PURE__ */ new Set());
|
|
37235
37094
|
const assetsKey = assets.join("|");
|
|
37236
|
-
|
|
37095
|
+
useEffect54(() => {
|
|
37237
37096
|
if (manifest404Ref.current.has(projectId)) return;
|
|
37238
37097
|
let cancelled = false;
|
|
37239
37098
|
fetch(`/api/projects/${projectId}/preview/.media/manifest.jsonl`).then((r) => {
|
|
@@ -37276,8 +37135,8 @@ var AssetsTab = memo28(function AssetsTab2({
|
|
|
37276
37135
|
}
|
|
37277
37136
|
}, []);
|
|
37278
37137
|
const elements = usePlayerStore((s) => s.elements);
|
|
37279
|
-
const usedPaths =
|
|
37280
|
-
const mediaAssets =
|
|
37138
|
+
const usedPaths = useMemo30(() => deriveUsedPaths(elements), [elements]);
|
|
37139
|
+
const mediaAssets = useMemo30(() => {
|
|
37281
37140
|
const media = assets.filter((a) => MEDIA_EXT.test(a) || FONT_EXT.test(a));
|
|
37282
37141
|
const all = filterByUsage(media, usedPaths, usageFilter);
|
|
37283
37142
|
if (!searchQuery) return all;
|
|
@@ -37288,7 +37147,7 @@ var AssetsTab = memo28(function AssetsTab2({
|
|
|
37288
37147
|
return rec?.description?.toLowerCase().includes(q);
|
|
37289
37148
|
});
|
|
37290
37149
|
}, [assets, searchQuery, manifest, usageFilter, usedPaths]);
|
|
37291
|
-
const categorized =
|
|
37150
|
+
const categorized = useMemo30(() => {
|
|
37292
37151
|
const groups = { audio: [], images: [], video: [], fonts: [] };
|
|
37293
37152
|
for (const a of mediaAssets) {
|
|
37294
37153
|
const cat = getCategory(a);
|
|
@@ -37303,12 +37162,12 @@ var AssetsTab = memo28(function AssetsTab2({
|
|
|
37303
37162
|
}
|
|
37304
37163
|
return groups;
|
|
37305
37164
|
}, [mediaAssets, usedPaths]);
|
|
37306
|
-
const counts =
|
|
37165
|
+
const counts = useMemo30(() => {
|
|
37307
37166
|
const c = { all: mediaAssets.length };
|
|
37308
37167
|
for (const cat of FILTER_ORDER) c[cat] = categorized[cat].length;
|
|
37309
37168
|
return c;
|
|
37310
37169
|
}, [mediaAssets, categorized]);
|
|
37311
|
-
const usageCounts =
|
|
37170
|
+
const usageCounts = useMemo30(
|
|
37312
37171
|
() => countUsage(
|
|
37313
37172
|
assets.filter((a) => MEDIA_EXT.test(a) || FONT_EXT.test(a)),
|
|
37314
37173
|
usedPaths
|
|
@@ -37550,11 +37409,11 @@ var AssetsTab = memo28(function AssetsTab2({
|
|
|
37550
37409
|
});
|
|
37551
37410
|
|
|
37552
37411
|
// src/components/sidebar/BlocksTab.tsx
|
|
37553
|
-
import { memo as memo29, useState as useState68, useCallback as useCallback89, useRef as useRef79, useEffect as
|
|
37412
|
+
import { memo as memo29, useState as useState68, useCallback as useCallback89, useRef as useRef79, useEffect as useEffect56 } from "react";
|
|
37554
37413
|
import { createPortal as createPortal5 } from "react-dom";
|
|
37555
37414
|
|
|
37556
37415
|
// src/hooks/useBlockCatalog.ts
|
|
37557
|
-
import { useState as useState67, useEffect as
|
|
37416
|
+
import { useState as useState67, useEffect as useEffect55, useMemo as useMemo31 } from "react";
|
|
37558
37417
|
|
|
37559
37418
|
// src/utils/blockCategories.ts
|
|
37560
37419
|
import {
|
|
@@ -37583,7 +37442,7 @@ function useBlockCatalog() {
|
|
|
37583
37442
|
const [error, setError] = useState67(null);
|
|
37584
37443
|
const [search, setSearch] = useState67("");
|
|
37585
37444
|
const [category, setCategory] = useState67(null);
|
|
37586
|
-
|
|
37445
|
+
useEffect55(() => {
|
|
37587
37446
|
let cancelled = false;
|
|
37588
37447
|
(async () => {
|
|
37589
37448
|
try {
|
|
@@ -37608,7 +37467,7 @@ function useBlockCatalog() {
|
|
|
37608
37467
|
cancelled = true;
|
|
37609
37468
|
};
|
|
37610
37469
|
}, []);
|
|
37611
|
-
const filteredBlocks =
|
|
37470
|
+
const filteredBlocks = useMemo31(() => {
|
|
37612
37471
|
let result = blocks;
|
|
37613
37472
|
if (category) {
|
|
37614
37473
|
result = result.filter((b) => b.category === category);
|
|
@@ -37861,7 +37720,7 @@ function BlockCard({
|
|
|
37861
37720
|
setHovered(false);
|
|
37862
37721
|
onPreview?.(null);
|
|
37863
37722
|
}, [onPreview]);
|
|
37864
|
-
|
|
37723
|
+
useEffect56(() => {
|
|
37865
37724
|
return () => {
|
|
37866
37725
|
if (hoverTimer.current) clearTimeout(hoverTimer.current);
|
|
37867
37726
|
};
|
|
@@ -38016,7 +37875,7 @@ function PromptPreviewModal({
|
|
|
38016
37875
|
const [value, setValue] = useState68(prompt);
|
|
38017
37876
|
const [copied, setCopied] = useState68(false);
|
|
38018
37877
|
const textareaRef = useRef79(null);
|
|
38019
|
-
|
|
37878
|
+
useEffect56(() => {
|
|
38020
37879
|
requestAnimationFrame(() => textareaRef.current?.focus());
|
|
38021
37880
|
}, []);
|
|
38022
37881
|
const handleCopy = useCallback89(() => {
|
|
@@ -38604,7 +38463,7 @@ function StudioLeftSidebar({
|
|
|
38604
38463
|
}
|
|
38605
38464
|
|
|
38606
38465
|
// src/components/StudioPreviewArea.tsx
|
|
38607
|
-
import { useState as useState81, useMemo as
|
|
38466
|
+
import { useState as useState81, useMemo as useMemo34, useCallback as useCallback98 } from "react";
|
|
38608
38467
|
|
|
38609
38468
|
// src/captions/components/CaptionOverlay.tsx
|
|
38610
38469
|
import { memo as memo31, useState as useState71, useCallback as useCallback92, useRef as useRef81 } from "react";
|
|
@@ -39231,7 +39090,7 @@ var CaptionTimeline = memo32(function CaptionTimeline2({
|
|
|
39231
39090
|
});
|
|
39232
39091
|
|
|
39233
39092
|
// src/components/editor/DomEditOverlay.tsx
|
|
39234
|
-
import { memo as memo35, useEffect as
|
|
39093
|
+
import { memo as memo35, useEffect as useEffect58, useMemo as useMemo32, useRef as useRef87, useState as useState76 } from "react";
|
|
39235
39094
|
|
|
39236
39095
|
// src/components/editor/marqueeCommit.ts
|
|
39237
39096
|
import { useCallback as useCallback94, useRef as useRef83, useState as useState72 } from "react";
|
|
@@ -39241,6 +39100,71 @@ function rectsOverlap(a, b) {
|
|
|
39241
39100
|
return a.left < b.left + b.width && a.left + a.width > b.left && a.top < b.top + b.height && a.top + a.height > b.top;
|
|
39242
39101
|
}
|
|
39243
39102
|
|
|
39103
|
+
// src/components/editor/domEditOverlayCrop.ts
|
|
39104
|
+
function cropRectFromInsets(rect, insets, scaleX, scaleY) {
|
|
39105
|
+
const sx = scaleX > 0 ? scaleX : 1;
|
|
39106
|
+
const sy = scaleY > 0 ? scaleY : 1;
|
|
39107
|
+
const left = rect.left + insets.left * sx;
|
|
39108
|
+
const top = rect.top + insets.top * sy;
|
|
39109
|
+
return {
|
|
39110
|
+
left,
|
|
39111
|
+
top,
|
|
39112
|
+
width: Math.max(0, rect.width - (insets.left + insets.right) * sx),
|
|
39113
|
+
height: Math.max(0, rect.height - (insets.top + insets.bottom) * sy)
|
|
39114
|
+
};
|
|
39115
|
+
}
|
|
39116
|
+
function readElementCropInsets(element) {
|
|
39117
|
+
const inline = element.style.getPropertyValue("clip-path").trim();
|
|
39118
|
+
const value = inline || element.ownerDocument.defaultView?.getComputedStyle(element).clipPath.trim() || "";
|
|
39119
|
+
const parsed = parseInsetClipPathSides(value === "none" ? "" : value);
|
|
39120
|
+
return parsed ?? { top: 0, right: 0, bottom: 0, left: 0, radius: 0 };
|
|
39121
|
+
}
|
|
39122
|
+
function clampInset(value, max) {
|
|
39123
|
+
if (!Number.isFinite(value)) return 0;
|
|
39124
|
+
return Math.min(Math.max(0, value), Math.max(0, max));
|
|
39125
|
+
}
|
|
39126
|
+
function resolveCropInsetFromEdgeDrag(input) {
|
|
39127
|
+
const scaleX = input.scaleX > 0 ? input.scaleX : 1;
|
|
39128
|
+
const scaleY = input.scaleY > 0 ? input.scaleY : 1;
|
|
39129
|
+
const next = { ...input.startInsets };
|
|
39130
|
+
if (input.edge === "left") {
|
|
39131
|
+
next.left = clampInset(
|
|
39132
|
+
input.startInsets.left + input.deltaX / scaleX,
|
|
39133
|
+
input.width - next.right
|
|
39134
|
+
);
|
|
39135
|
+
} else if (input.edge === "right") {
|
|
39136
|
+
next.right = clampInset(
|
|
39137
|
+
input.startInsets.right - input.deltaX / scaleX,
|
|
39138
|
+
input.width - next.left
|
|
39139
|
+
);
|
|
39140
|
+
} else if (input.edge === "top") {
|
|
39141
|
+
next.top = clampInset(
|
|
39142
|
+
input.startInsets.top + input.deltaY / scaleY,
|
|
39143
|
+
input.height - next.bottom
|
|
39144
|
+
);
|
|
39145
|
+
} else {
|
|
39146
|
+
next.bottom = clampInset(
|
|
39147
|
+
input.startInsets.bottom - input.deltaY / scaleY,
|
|
39148
|
+
input.height - next.top
|
|
39149
|
+
);
|
|
39150
|
+
}
|
|
39151
|
+
return next;
|
|
39152
|
+
}
|
|
39153
|
+
function resolveCropInsetFromMoveDrag(input) {
|
|
39154
|
+
const sx = input.scaleX > 0 ? input.scaleX : 1;
|
|
39155
|
+
const sy = input.scaleY > 0 ? input.scaleY : 1;
|
|
39156
|
+
const totalX = input.startInsets.left + input.startInsets.right;
|
|
39157
|
+
const totalY = input.startInsets.top + input.startInsets.bottom;
|
|
39158
|
+
const left = Math.min(Math.max(0, input.startInsets.left + input.deltaX / sx), totalX);
|
|
39159
|
+
const top = Math.min(Math.max(0, input.startInsets.top + input.deltaY / sy), totalY);
|
|
39160
|
+
return { left, right: totalX - left, top, bottom: totalY - top };
|
|
39161
|
+
}
|
|
39162
|
+
function hugRectForElement(rect, element) {
|
|
39163
|
+
const insets = readElementCropInsets(element);
|
|
39164
|
+
if (insets.top <= 0 && insets.right <= 0 && insets.bottom <= 0 && insets.left <= 0) return rect;
|
|
39165
|
+
return cropRectFromInsets(rect, insets, rect.editScaleX, rect.editScaleY);
|
|
39166
|
+
}
|
|
39167
|
+
|
|
39244
39168
|
// src/components/editor/domEditOverlayGeometry.ts
|
|
39245
39169
|
function isElementVisibleForOverlay(el) {
|
|
39246
39170
|
return isElementVisibleThroughAncestors(el);
|
|
@@ -41272,13 +41196,30 @@ var GridOverlay = memo34(function GridOverlay2({
|
|
|
41272
41196
|
});
|
|
41273
41197
|
|
|
41274
41198
|
// src/components/editor/DomEditCropHandles.tsx
|
|
41275
|
-
import { useEffect as
|
|
41199
|
+
import { useEffect as useEffect57, useRef as useRef86, useState as useState74 } from "react";
|
|
41276
41200
|
import { Fragment as Fragment27, jsx as jsx88, jsxs as jsxs74 } from "react/jsx-runtime";
|
|
41277
|
-
|
|
41278
|
-
|
|
41279
|
-
|
|
41280
|
-
|
|
41281
|
-
|
|
41201
|
+
var EDGE_HANDLE_GAP = 8;
|
|
41202
|
+
function edgeHandlePlacement(edge, rect) {
|
|
41203
|
+
const cx = rect.left + rect.width / 2;
|
|
41204
|
+
const cy = rect.top + rect.height / 2;
|
|
41205
|
+
if (edge === "top") {
|
|
41206
|
+
return { left: cx, top: rect.top - EDGE_HANDLE_GAP, transform: "translate(-50%, -100%)" };
|
|
41207
|
+
}
|
|
41208
|
+
if (edge === "bottom") {
|
|
41209
|
+
return {
|
|
41210
|
+
left: cx,
|
|
41211
|
+
top: rect.top + rect.height + EDGE_HANDLE_GAP,
|
|
41212
|
+
transform: "translate(-50%, 0)"
|
|
41213
|
+
};
|
|
41214
|
+
}
|
|
41215
|
+
if (edge === "left") {
|
|
41216
|
+
return { left: rect.left - EDGE_HANDLE_GAP, top: cy, transform: "translate(-100%, -50%)" };
|
|
41217
|
+
}
|
|
41218
|
+
return {
|
|
41219
|
+
left: rect.left + rect.width + EDGE_HANDLE_GAP,
|
|
41220
|
+
top: cy,
|
|
41221
|
+
transform: "translate(0, -50%)"
|
|
41222
|
+
};
|
|
41282
41223
|
}
|
|
41283
41224
|
var EDGES = ["top", "right", "bottom", "left"];
|
|
41284
41225
|
function DomEditCropHandles({
|
|
@@ -41287,6 +41228,7 @@ function DomEditCropHandles({
|
|
|
41287
41228
|
onStyleCommit
|
|
41288
41229
|
}) {
|
|
41289
41230
|
const gestureRef = useRef86(null);
|
|
41231
|
+
const [dragging, setDragging] = useState74(false);
|
|
41290
41232
|
const [state, setState] = useState74(() => {
|
|
41291
41233
|
const parsed = readElementCropInsets(selection.element);
|
|
41292
41234
|
return {
|
|
@@ -41301,20 +41243,23 @@ function DomEditCropHandles({
|
|
|
41301
41243
|
};
|
|
41302
41244
|
});
|
|
41303
41245
|
if (state.element !== selection.element) {
|
|
41304
|
-
const
|
|
41246
|
+
const liveInsets = readElementCropInsets(selection.element);
|
|
41305
41247
|
setState({
|
|
41306
41248
|
element: selection.element,
|
|
41307
|
-
insets: {
|
|
41308
|
-
|
|
41249
|
+
insets: {
|
|
41250
|
+
top: liveInsets.top,
|
|
41251
|
+
right: liveInsets.right,
|
|
41252
|
+
bottom: liveInsets.bottom,
|
|
41253
|
+
left: liveInsets.left
|
|
41254
|
+
},
|
|
41255
|
+
radius: liveInsets.radius
|
|
41309
41256
|
});
|
|
41310
41257
|
}
|
|
41258
|
+
const hasCrop = state.insets.top > 0 || state.insets.right > 0 || state.insets.bottom > 0 || state.insets.left > 0;
|
|
41311
41259
|
const committedRef = useRef86(null);
|
|
41312
|
-
|
|
41313
|
-
const hasCrop = state.insets.top > 0 || state.insets.right > 0 || state.insets.bottom > 0 || state.insets.left > 0;
|
|
41314
|
-
committedRef.current = hasCrop ? buildInsetClipPathSides(state.insets, state.radius) : null;
|
|
41315
|
-
}
|
|
41260
|
+
committedRef.current = hasCrop ? buildInsetClipPathSides(state.insets, state.radius) : null;
|
|
41316
41261
|
const liftedRef = useRef86(false);
|
|
41317
|
-
|
|
41262
|
+
useEffect57(() => {
|
|
41318
41263
|
const el = selection.element;
|
|
41319
41264
|
el.style.setProperty("clip-path", "none");
|
|
41320
41265
|
liftedRef.current = true;
|
|
@@ -41342,6 +41287,7 @@ function DomEditCropHandles({
|
|
|
41342
41287
|
startInsets: state.insets,
|
|
41343
41288
|
didMove: false
|
|
41344
41289
|
};
|
|
41290
|
+
setDragging(true);
|
|
41345
41291
|
};
|
|
41346
41292
|
const updateCropGesture = (event) => {
|
|
41347
41293
|
const gesture = gestureRef.current;
|
|
@@ -41365,24 +41311,27 @@ function DomEditCropHandles({
|
|
|
41365
41311
|
event.preventDefault();
|
|
41366
41312
|
event.stopPropagation();
|
|
41367
41313
|
gestureRef.current = null;
|
|
41314
|
+
setDragging(false);
|
|
41368
41315
|
if (!gesture.didMove) return;
|
|
41369
41316
|
const el = selection.element;
|
|
41317
|
+
const reLift = () => {
|
|
41318
|
+
if (liftedRef.current) el.style.setProperty("clip-path", "none");
|
|
41319
|
+
};
|
|
41370
41320
|
void Promise.resolve(
|
|
41371
41321
|
onStyleCommit?.("clip-path", buildInsetClipPathSides(state.insets, state.radius))
|
|
41372
|
-
).then(
|
|
41373
|
-
if (liftedRef.current) el.style.setProperty("clip-path", "none");
|
|
41374
|
-
});
|
|
41322
|
+
).then(reLift, reLift);
|
|
41375
41323
|
};
|
|
41376
41324
|
const cancelCropGesture = (event) => {
|
|
41377
41325
|
const gesture = gestureRef.current;
|
|
41378
41326
|
if (!gesture || gesture.pointerId !== event.pointerId) return;
|
|
41379
41327
|
event.preventDefault();
|
|
41380
41328
|
event.stopPropagation();
|
|
41381
|
-
setState((prev) => ({ ...prev, insets: gesture.startInsets }));
|
|
41382
41329
|
gestureRef.current = null;
|
|
41330
|
+
setDragging(false);
|
|
41331
|
+
setState((prev) => ({ ...prev, insets: gesture.startInsets }));
|
|
41383
41332
|
};
|
|
41384
41333
|
return /* @__PURE__ */ jsxs74(Fragment27, { children: [
|
|
41385
|
-
/* @__PURE__ */ jsx88(
|
|
41334
|
+
hasCrop && /* @__PURE__ */ jsx88(
|
|
41386
41335
|
"div",
|
|
41387
41336
|
{
|
|
41388
41337
|
className: "pointer-events-none absolute overflow-hidden",
|
|
@@ -41410,13 +41359,35 @@ function DomEditCropHandles({
|
|
|
41410
41359
|
/* @__PURE__ */ jsx88(
|
|
41411
41360
|
"div",
|
|
41412
41361
|
{
|
|
41413
|
-
"
|
|
41414
|
-
className: "pointer-events-
|
|
41362
|
+
"aria-hidden": "true",
|
|
41363
|
+
className: "pointer-events-none absolute border border-dashed border-studio-accent",
|
|
41415
41364
|
style: {
|
|
41416
41365
|
left: cropRect.left,
|
|
41417
41366
|
top: cropRect.top,
|
|
41418
41367
|
width: cropRect.width,
|
|
41419
|
-
height: cropRect.height
|
|
41368
|
+
height: cropRect.height
|
|
41369
|
+
},
|
|
41370
|
+
children: dragging && /* @__PURE__ */ jsxs74(Fragment27, { children: [
|
|
41371
|
+
/* @__PURE__ */ jsx88("div", { className: "absolute inset-y-0 left-1/3 w-px bg-studio-accent/40" }),
|
|
41372
|
+
/* @__PURE__ */ jsx88("div", { className: "absolute inset-y-0 left-2/3 w-px bg-studio-accent/40" }),
|
|
41373
|
+
/* @__PURE__ */ jsx88("div", { className: "absolute inset-x-0 top-1/3 h-px bg-studio-accent/40" }),
|
|
41374
|
+
/* @__PURE__ */ jsx88("div", { className: "absolute inset-x-0 top-2/3 h-px bg-studio-accent/40" })
|
|
41375
|
+
] })
|
|
41376
|
+
}
|
|
41377
|
+
),
|
|
41378
|
+
hasCrop && /* @__PURE__ */ jsx88(
|
|
41379
|
+
"button",
|
|
41380
|
+
{
|
|
41381
|
+
type: "button",
|
|
41382
|
+
"aria-label": "Reposition crop",
|
|
41383
|
+
"data-dom-edit-crop-handle": "true",
|
|
41384
|
+
className: "pointer-events-auto absolute rounded-full border-2 border-studio-accent bg-studio-accent/30 shadow-[0_0_0_1px_rgba(0,0,0,0.4)]",
|
|
41385
|
+
style: {
|
|
41386
|
+
left: cropRect.left + cropRect.width / 2,
|
|
41387
|
+
top: cropRect.top + cropRect.height / 2,
|
|
41388
|
+
width: 22,
|
|
41389
|
+
height: 22,
|
|
41390
|
+
transform: "translate(-50%, -50%)",
|
|
41420
41391
|
cursor: "move",
|
|
41421
41392
|
touchAction: "none"
|
|
41422
41393
|
},
|
|
@@ -41427,21 +41398,21 @@ function DomEditCropHandles({
|
|
|
41427
41398
|
}
|
|
41428
41399
|
),
|
|
41429
41400
|
EDGES.map((edge) => {
|
|
41430
|
-
const center = handleCenter(edge, cropRect);
|
|
41431
41401
|
const vertical = edge === "left" || edge === "right";
|
|
41402
|
+
const place = edgeHandlePlacement(edge, cropRect);
|
|
41432
41403
|
return /* @__PURE__ */ jsx88(
|
|
41433
41404
|
"button",
|
|
41434
41405
|
{
|
|
41435
41406
|
type: "button",
|
|
41436
41407
|
"aria-label": `Crop ${edge}`,
|
|
41437
41408
|
"data-dom-edit-crop-handle": "true",
|
|
41438
|
-
className: "pointer-events-auto absolute rounded-
|
|
41409
|
+
className: "pointer-events-auto absolute rounded-full bg-studio-accent shadow-[0_0_0_1px_rgba(0,0,0,0.4)]",
|
|
41439
41410
|
style: {
|
|
41440
|
-
left:
|
|
41441
|
-
top:
|
|
41442
|
-
width: vertical ?
|
|
41443
|
-
height: vertical ?
|
|
41444
|
-
transform:
|
|
41411
|
+
left: place.left,
|
|
41412
|
+
top: place.top,
|
|
41413
|
+
width: vertical ? 5 : 26,
|
|
41414
|
+
height: vertical ? 26 : 5,
|
|
41415
|
+
transform: place.transform,
|
|
41445
41416
|
cursor: vertical ? "ew-resize" : "ns-resize",
|
|
41446
41417
|
touchAction: "none"
|
|
41447
41418
|
},
|
|
@@ -41496,6 +41467,24 @@ function DomEditRotateHandle({
|
|
|
41496
41467
|
);
|
|
41497
41468
|
}
|
|
41498
41469
|
|
|
41470
|
+
// src/hooks/useCropOverlay.ts
|
|
41471
|
+
function useCropOverlay(params) {
|
|
41472
|
+
const { selection, overlayRect } = params;
|
|
41473
|
+
const cropInsets = selection ? readElementCropInsets(selection.element) : null;
|
|
41474
|
+
const hasCropInsets = Boolean(
|
|
41475
|
+
cropInsets && (cropInsets.top > 0 || cropInsets.right > 0 || cropInsets.bottom > 0 || cropInsets.left > 0)
|
|
41476
|
+
);
|
|
41477
|
+
const sx = overlayRect && overlayRect.editScaleX > 0 ? overlayRect.editScaleX : 1;
|
|
41478
|
+
const sy = overlayRect && overlayRect.editScaleY > 0 ? overlayRect.editScaleY : 1;
|
|
41479
|
+
const cropOutlineInsetPx = cropInsets && hasCropInsets ? {
|
|
41480
|
+
top: cropInsets.top * sy,
|
|
41481
|
+
right: cropInsets.right * sx,
|
|
41482
|
+
bottom: cropInsets.bottom * sy,
|
|
41483
|
+
left: cropInsets.left * sx
|
|
41484
|
+
} : void 0;
|
|
41485
|
+
return { hasCropInsets, cropOutlineInsetPx };
|
|
41486
|
+
}
|
|
41487
|
+
|
|
41499
41488
|
// src/components/editor/domEditOverlayShape.ts
|
|
41500
41489
|
function readDomEditSelectionShapeStyles(selection) {
|
|
41501
41490
|
const fallback = {
|
|
@@ -41713,8 +41702,6 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
41713
41702
|
onBoxSizeCommit,
|
|
41714
41703
|
onRotationCommit,
|
|
41715
41704
|
onStyleCommit,
|
|
41716
|
-
cropMode = false,
|
|
41717
|
-
onCropModeChange,
|
|
41718
41705
|
onMarqueeSelect
|
|
41719
41706
|
}) {
|
|
41720
41707
|
const overlayRef = useRef87(null);
|
|
@@ -41781,9 +41768,6 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
41781
41768
|
compRectRef.current = compRect;
|
|
41782
41769
|
const { hasCropInsets, cropOutlineInsetPx } = useCropOverlay({
|
|
41783
41770
|
selection,
|
|
41784
|
-
groupCount: groupSelections.length,
|
|
41785
|
-
cropMode,
|
|
41786
|
-
onCropModeChange,
|
|
41787
41771
|
overlayRect
|
|
41788
41772
|
});
|
|
41789
41773
|
const boxClipPath = hasCropInsets ? void 0 : selectionShapeStyles.clipPath;
|
|
@@ -41808,7 +41792,7 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
41808
41792
|
setRects: setOffCanvasRects
|
|
41809
41793
|
})
|
|
41810
41794
|
);
|
|
41811
|
-
|
|
41795
|
+
useEffect58(() => {
|
|
41812
41796
|
offCanvasDirtyRef.current = true;
|
|
41813
41797
|
}, [activeCompositionPath]);
|
|
41814
41798
|
const gestures = createDomEditOverlayGestureHandlers({
|
|
@@ -41844,11 +41828,11 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
41844
41828
|
selectionRef,
|
|
41845
41829
|
gestures
|
|
41846
41830
|
});
|
|
41847
|
-
const selectionKey =
|
|
41831
|
+
const selectionKey = useMemo32(() => {
|
|
41848
41832
|
if (!selection) return "none";
|
|
41849
41833
|
return `${selection.sourceFile}:${selection.id ?? selection.selector ?? selection.label}:${selection.selectorIndex ?? 0}`;
|
|
41850
41834
|
}, [selection]);
|
|
41851
|
-
const groupBounds =
|
|
41835
|
+
const groupBounds = useMemo32(
|
|
41852
41836
|
() => resolveDomEditGroupOverlayRect(groupOverlayItems.map((item) => item.rect)),
|
|
41853
41837
|
[groupOverlayItems]
|
|
41854
41838
|
);
|
|
@@ -41856,11 +41840,6 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
41856
41840
|
const groupCanMove = hasGroupSelection && groupOverlayItems.length > 1 && groupOverlayItems.every((item) => item.selection.capabilities.canApplyManualOffset);
|
|
41857
41841
|
const handleOverlayMouseDown = (event) => {
|
|
41858
41842
|
if (!allowCanvasMovement) return;
|
|
41859
|
-
if (cropMode) {
|
|
41860
|
-
event.preventDefault();
|
|
41861
|
-
event.stopPropagation();
|
|
41862
|
-
return;
|
|
41863
|
-
}
|
|
41864
41843
|
if (suppressNextOverlayMouseDownRef.current) {
|
|
41865
41844
|
suppressNextOverlayMouseDownRef.current = false;
|
|
41866
41845
|
suppressNextBoxMouseDownRef.current = false;
|
|
@@ -41879,12 +41858,6 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
41879
41858
|
};
|
|
41880
41859
|
const handleOverlayPointerDown = (event) => {
|
|
41881
41860
|
if (!allowCanvasMovement || event.button !== 0) return;
|
|
41882
|
-
if (cropMode) {
|
|
41883
|
-
event.preventDefault();
|
|
41884
|
-
event.stopPropagation();
|
|
41885
|
-
onCropModeChange?.(false);
|
|
41886
|
-
return;
|
|
41887
|
-
}
|
|
41888
41861
|
if (event.shiftKey) {
|
|
41889
41862
|
const candidate = hoverSelectionRef.current;
|
|
41890
41863
|
if (!candidate) return;
|
|
@@ -41923,14 +41896,8 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
41923
41896
|
}
|
|
41924
41897
|
}
|
|
41925
41898
|
};
|
|
41926
|
-
const lastBoxPointerDownAtRef = useRef87(0);
|
|
41927
41899
|
const handleBoxClick = (event) => {
|
|
41928
41900
|
if (!allowCanvasMovement) return;
|
|
41929
|
-
if (cropMode) {
|
|
41930
|
-
event.preventDefault();
|
|
41931
|
-
event.stopPropagation();
|
|
41932
|
-
return;
|
|
41933
|
-
}
|
|
41934
41901
|
if (gestureRef.current || groupGestureRef.current) return;
|
|
41935
41902
|
if (suppressNextBoxClickRef.current) {
|
|
41936
41903
|
suppressNextBoxClickRef.current = false;
|
|
@@ -41956,10 +41923,10 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
41956
41923
|
onPointerDownCapture: (event) => focusDomEditOverlayElement(event.currentTarget),
|
|
41957
41924
|
onPointerDown: handleOverlayPointerDown,
|
|
41958
41925
|
onMouseDown: handleOverlayMouseDown,
|
|
41959
|
-
onPointerMove:
|
|
41926
|
+
onPointerMove: marquee.onPointerMove,
|
|
41960
41927
|
onPointerLeave: () => onCanvasPointerLeaveRef.current(),
|
|
41961
|
-
onPointerUp:
|
|
41962
|
-
onPointerCancel:
|
|
41928
|
+
onPointerUp: marquee.onPointerUp,
|
|
41929
|
+
onPointerCancel: marquee.onPointerCancel,
|
|
41963
41930
|
children: [
|
|
41964
41931
|
hoverSelection && hoverRect && compRect.width > 0 && /* @__PURE__ */ jsx90(
|
|
41965
41932
|
"div",
|
|
@@ -42007,7 +41974,7 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
42007
41974
|
)
|
|
42008
41975
|
] }),
|
|
42009
41976
|
!hasGroupSelection && selection && overlayRect && compRect.width > 0 && /* @__PURE__ */ jsxs76(Fragment28, { children: [
|
|
42010
|
-
allowCanvasMovement &&
|
|
41977
|
+
allowCanvasMovement && selection.capabilities.canApplyManualRotation && /* @__PURE__ */ jsx90(
|
|
42011
41978
|
DomEditRotateHandle,
|
|
42012
41979
|
{
|
|
42013
41980
|
overlayRect,
|
|
@@ -42030,25 +41997,10 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
42030
41997
|
width: overlayRect.width,
|
|
42031
41998
|
height: overlayRect.height,
|
|
42032
41999
|
clipPath: boxClipPath,
|
|
42033
|
-
cursor: allowCanvasMovement &&
|
|
42000
|
+
cursor: allowCanvasMovement && selection.capabilities.canApplyManualOffset ? "move" : "default"
|
|
42034
42001
|
},
|
|
42035
42002
|
onPointerDown: (e) => {
|
|
42036
|
-
if (cropMode) {
|
|
42037
|
-
e.preventDefault();
|
|
42038
|
-
e.stopPropagation();
|
|
42039
|
-
return;
|
|
42040
|
-
}
|
|
42041
42003
|
if (!allowCanvasMovement || e.shiftKey) return;
|
|
42042
|
-
const now = Date.now();
|
|
42043
|
-
const isDoubleClick = now - lastBoxPointerDownAtRef.current < 400;
|
|
42044
|
-
lastBoxPointerDownAtRef.current = now;
|
|
42045
|
-
if (isDoubleClick && onCropModeChange && selection.capabilities.canCrop) {
|
|
42046
|
-
lastBoxPointerDownAtRef.current = 0;
|
|
42047
|
-
e.preventDefault();
|
|
42048
|
-
e.stopPropagation();
|
|
42049
|
-
onCropModeChange(true);
|
|
42050
|
-
return;
|
|
42051
|
-
}
|
|
42052
42004
|
if (selection.capabilities.canApplyManualOffset) {
|
|
42053
42005
|
gestures.startGesture("drag", e);
|
|
42054
42006
|
return;
|
|
@@ -42078,7 +42030,7 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
42078
42030
|
}
|
|
42079
42031
|
}
|
|
42080
42032
|
),
|
|
42081
|
-
allowCanvasMovement &&
|
|
42033
|
+
allowCanvasMovement && selection.capabilities.canApplyManualSize && /* @__PURE__ */ jsx90(
|
|
42082
42034
|
"div",
|
|
42083
42035
|
{
|
|
42084
42036
|
className: "absolute -right-1.5 -bottom-1.5 w-3 h-3 rounded-sm bg-studio-accent border border-studio-accent/60",
|
|
@@ -42100,7 +42052,7 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
42100
42052
|
},
|
|
42101
42053
|
selectionKey
|
|
42102
42054
|
),
|
|
42103
|
-
|
|
42055
|
+
selection.capabilities.canCrop && groupSelections.length <= 1 && /* @__PURE__ */ jsx90(
|
|
42104
42056
|
DomEditCropHandles,
|
|
42105
42057
|
{
|
|
42106
42058
|
selection,
|
|
@@ -42162,10 +42114,10 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
42162
42114
|
});
|
|
42163
42115
|
|
|
42164
42116
|
// src/components/editor/MotionPathOverlay.tsx
|
|
42165
|
-
import { memo as memo36, useEffect as
|
|
42117
|
+
import { memo as memo36, useEffect as useEffect60, useRef as useRef90, useState as useState78 } from "react";
|
|
42166
42118
|
|
|
42167
42119
|
// src/contexts/DomEditContext.tsx
|
|
42168
|
-
import { createContext as createContext6, useCallback as useCallback95, useContext as useContext6, useMemo as
|
|
42120
|
+
import { createContext as createContext6, useCallback as useCallback95, useContext as useContext6, useMemo as useMemo33, useRef as useRef88 } from "react";
|
|
42169
42121
|
import { jsx as jsx91 } from "react/jsx-runtime";
|
|
42170
42122
|
var DomEditActionsContext = createContext6(null);
|
|
42171
42123
|
var DomEditSelectionContext = createContext6(null);
|
|
@@ -42270,7 +42222,7 @@ function DomEditProvider({
|
|
|
42270
42222
|
(mutation, options) => commitMutationRef.current(mutation, options),
|
|
42271
42223
|
[]
|
|
42272
42224
|
);
|
|
42273
|
-
const actions =
|
|
42225
|
+
const actions = useMemo33(
|
|
42274
42226
|
() => ({
|
|
42275
42227
|
handleTimelineElementSelect,
|
|
42276
42228
|
handlePreviewCanvasMouseDown,
|
|
@@ -42406,7 +42358,7 @@ function DomEditProvider({
|
|
|
42406
42358
|
handleSetAllKeyframeEases
|
|
42407
42359
|
]
|
|
42408
42360
|
);
|
|
42409
|
-
const selection =
|
|
42361
|
+
const selection = useMemo33(
|
|
42410
42362
|
() => ({
|
|
42411
42363
|
domEditSelection,
|
|
42412
42364
|
domEditGroupSelections,
|
|
@@ -42621,7 +42573,7 @@ function commitCreatePath(targetSelector, position, x, y, commit) {
|
|
|
42621
42573
|
}
|
|
42622
42574
|
|
|
42623
42575
|
// src/components/editor/useMotionPathData.ts
|
|
42624
|
-
import { useEffect as
|
|
42576
|
+
import { useEffect as useEffect59, useRef as useRef89, useState as useState77 } from "react";
|
|
42625
42577
|
function transformTranslate(el) {
|
|
42626
42578
|
const t = el.ownerDocument?.defaultView?.getComputedStyle(el).transform;
|
|
42627
42579
|
if (!t || t === "none") return { x: 0, y: 0 };
|
|
@@ -42692,7 +42644,7 @@ function useMotionPathData(iframeRef, selector) {
|
|
|
42692
42644
|
const [visibleInPreview, setVisibleInPreview] = useState77(true);
|
|
42693
42645
|
const [home, setHome] = useState77(null);
|
|
42694
42646
|
const [pScale, setPScale] = useState77(1);
|
|
42695
|
-
|
|
42647
|
+
useEffect59(() => {
|
|
42696
42648
|
if (!selector) {
|
|
42697
42649
|
setRect(null);
|
|
42698
42650
|
setHome(null);
|
|
@@ -42735,7 +42687,7 @@ function useMotionPathData(iframeRef, selector) {
|
|
|
42735
42687
|
raf = requestAnimationFrame(tick);
|
|
42736
42688
|
return () => cancelAnimationFrame(raf);
|
|
42737
42689
|
}, [selector, iframeRef]);
|
|
42738
|
-
|
|
42690
|
+
useEffect59(() => {
|
|
42739
42691
|
if (!selector) {
|
|
42740
42692
|
setGeometry(null);
|
|
42741
42693
|
return;
|
|
@@ -42787,19 +42739,19 @@ var MotionPathOverlay = memo36(function MotionPathOverlay2({
|
|
|
42787
42739
|
const dragRef = useRef90(null);
|
|
42788
42740
|
const parkTimerRef = useRef90(void 0);
|
|
42789
42741
|
const animId = editableAnimationId(selectedGsapAnimations ?? [], geometry?.kind ?? "linear");
|
|
42790
|
-
|
|
42742
|
+
useEffect60(() => () => clearTimeout(parkTimerRef.current), [animId]);
|
|
42791
42743
|
const createMode = geometryResolved && !geometry && Boolean(selection?.element) && !isPlaying;
|
|
42792
42744
|
const createSelector = createMode ? selectorFor(selection) : null;
|
|
42793
42745
|
const compW = compositionSize?.width ?? null;
|
|
42794
42746
|
const canCreate = createMode && hasMotionPathPlugin(iframeRef.current);
|
|
42795
|
-
|
|
42747
|
+
useEffect60(() => {
|
|
42796
42748
|
setMotionPathCreateAvailable(Boolean(canCreate));
|
|
42797
42749
|
return () => setMotionPathCreateAvailable(false);
|
|
42798
42750
|
}, [canCreate, setMotionPathCreateAvailable]);
|
|
42799
|
-
|
|
42751
|
+
useEffect60(() => {
|
|
42800
42752
|
if (armed && !canCreate) setMotionPathArmed(false);
|
|
42801
42753
|
}, [armed, canCreate, setMotionPathArmed]);
|
|
42802
|
-
|
|
42754
|
+
useEffect60(() => {
|
|
42803
42755
|
if (!armed || !createSelector || !compW) return;
|
|
42804
42756
|
const surface = iframeRef.current?.ownerDocument?.querySelector(
|
|
42805
42757
|
"[data-preview-pan-surface]"
|
|
@@ -43113,8 +43065,8 @@ var MotionPathOverlay = memo36(function MotionPathOverlay2({
|
|
|
43113
43065
|
});
|
|
43114
43066
|
|
|
43115
43067
|
// src/components/editor/SnapToolbar.tsx
|
|
43116
|
-
import { memo as memo37, useCallback as useCallback96, useEffect as
|
|
43117
|
-
import {
|
|
43068
|
+
import { memo as memo37, useCallback as useCallback96, useEffect as useEffect61, useRef as useRef91, useState as useState79 } from "react";
|
|
43069
|
+
import { MagnetStraight, GridFour, Path } from "@phosphor-icons/react";
|
|
43118
43070
|
import { jsx as jsx94, jsxs as jsxs79 } from "react/jsx-runtime";
|
|
43119
43071
|
var SNAP_DEFAULTS = {
|
|
43120
43072
|
snapEnabled: true,
|
|
@@ -43137,9 +43089,6 @@ var SnapToolbar = memo37(function SnapToolbar2({ onSnapChange }) {
|
|
|
43137
43089
|
const motionPathCreateAvailable = usePlayerStore((s) => s.motionPathCreateAvailable);
|
|
43138
43090
|
const motionPathArmed = usePlayerStore((s) => s.motionPathArmed);
|
|
43139
43091
|
const setMotionPathArmed = usePlayerStore((s) => s.setMotionPathArmed);
|
|
43140
|
-
const cropAvailable = usePlayerStore((s) => s.cropAvailable);
|
|
43141
|
-
const cropMode = usePlayerStore((s) => s.cropMode);
|
|
43142
|
-
const setCropMode = usePlayerStore((s) => s.setCropMode);
|
|
43143
43092
|
const popoverRef = useRef91(null);
|
|
43144
43093
|
const gridButtonRef = useRef91(null);
|
|
43145
43094
|
const updatePrefs = useCallback96(
|
|
@@ -43159,7 +43108,7 @@ var SnapToolbar = memo37(function SnapToolbar2({ onSnapChange }) {
|
|
|
43159
43108
|
const toggleGrid = useCallback96(() => {
|
|
43160
43109
|
updatePrefs({ gridVisible: !prefs.gridVisible });
|
|
43161
43110
|
}, [prefs.gridVisible, updatePrefs]);
|
|
43162
|
-
|
|
43111
|
+
useEffect61(() => {
|
|
43163
43112
|
const handleKeyDown = (e) => {
|
|
43164
43113
|
if (e.defaultPrevented) return;
|
|
43165
43114
|
const t = e.target;
|
|
@@ -43178,7 +43127,7 @@ var SnapToolbar = memo37(function SnapToolbar2({ onSnapChange }) {
|
|
|
43178
43127
|
document.addEventListener("keydown", handleKeyDown);
|
|
43179
43128
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
43180
43129
|
}, [updatePrefs]);
|
|
43181
|
-
|
|
43130
|
+
useEffect61(() => {
|
|
43182
43131
|
if (!gridPopoverOpen) return;
|
|
43183
43132
|
const handleClickOutside = (e) => {
|
|
43184
43133
|
const target = e.target;
|
|
@@ -43194,18 +43143,6 @@ var SnapToolbar = memo37(function SnapToolbar2({ onSnapChange }) {
|
|
|
43194
43143
|
className: "absolute top-2 right-2 z-50 flex items-center gap-1",
|
|
43195
43144
|
onPointerDown: (e) => e.stopPropagation(),
|
|
43196
43145
|
children: [
|
|
43197
|
-
cropAvailable && /* @__PURE__ */ jsx94(
|
|
43198
|
-
"button",
|
|
43199
|
-
{
|
|
43200
|
-
type: "button",
|
|
43201
|
-
className: `rounded-md p-1.5 transition-colors ${cropMode ? "bg-studio-accent/20 text-studio-accent" : "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"}`,
|
|
43202
|
-
onClick: () => setCropMode(!cropMode),
|
|
43203
|
-
title: cropMode ? "Exit crop (Esc)" : "Crop selection",
|
|
43204
|
-
"aria-label": "Crop selection",
|
|
43205
|
-
"aria-pressed": cropMode,
|
|
43206
|
-
children: /* @__PURE__ */ jsx94(Crop, { size: 16, weight: cropMode ? "fill" : "regular" })
|
|
43207
|
-
}
|
|
43208
|
-
),
|
|
43209
43146
|
motionPathCreateAvailable && /* @__PURE__ */ jsx94(
|
|
43210
43147
|
"button",
|
|
43211
43148
|
{
|
|
@@ -43293,7 +43230,7 @@ var SnapToolbar = memo37(function SnapToolbar2({ onSnapChange }) {
|
|
|
43293
43230
|
});
|
|
43294
43231
|
|
|
43295
43232
|
// src/components/StudioFeedbackBar.tsx
|
|
43296
|
-
import { memo as memo38, useState as useState80, useCallback as useCallback97, useRef as useRef92, useEffect as
|
|
43233
|
+
import { memo as memo38, useState as useState80, useCallback as useCallback97, useRef as useRef92, useEffect as useEffect62 } from "react";
|
|
43297
43234
|
import { Fragment as Fragment30, jsx as jsx95, jsxs as jsxs80 } from "react/jsx-runtime";
|
|
43298
43235
|
var DEFAULT_FEEDBACK_INTERVAL = 10;
|
|
43299
43236
|
var AUTO_DISMISS_MS2 = 2e4;
|
|
@@ -43355,7 +43292,7 @@ var StudioFeedbackBar = memo38(function StudioFeedbackBar2() {
|
|
|
43355
43292
|
const [exiting, setExiting] = useState80(false);
|
|
43356
43293
|
const inputRef = useRef92(null);
|
|
43357
43294
|
const dismissTimerRef = useRef92(null);
|
|
43358
|
-
|
|
43295
|
+
useEffect62(() => {
|
|
43359
43296
|
incrementSessionCount();
|
|
43360
43297
|
const showTimer = setTimeout(() => {
|
|
43361
43298
|
if (shouldShowFeedback()) {
|
|
@@ -43364,12 +43301,12 @@ var StudioFeedbackBar = memo38(function StudioFeedbackBar2() {
|
|
|
43364
43301
|
}, 3e3);
|
|
43365
43302
|
return () => clearTimeout(showTimer);
|
|
43366
43303
|
}, []);
|
|
43367
|
-
|
|
43304
|
+
useEffect62(() => {
|
|
43368
43305
|
if (!visible) return;
|
|
43369
43306
|
const raf = requestAnimationFrame(() => setEntered(true));
|
|
43370
43307
|
return () => cancelAnimationFrame(raf);
|
|
43371
43308
|
}, [visible]);
|
|
43372
|
-
|
|
43309
|
+
useEffect62(() => {
|
|
43373
43310
|
if (!visible || rating !== null || submitted) return;
|
|
43374
43311
|
dismissTimerRef.current = setTimeout(() => {
|
|
43375
43312
|
handleDismiss();
|
|
@@ -43378,7 +43315,7 @@ var StudioFeedbackBar = memo38(function StudioFeedbackBar2() {
|
|
|
43378
43315
|
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
|
|
43379
43316
|
};
|
|
43380
43317
|
}, [visible, rating, submitted]);
|
|
43381
|
-
|
|
43318
|
+
useEffect62(() => {
|
|
43382
43319
|
if (rating !== null && inputRef.current) {
|
|
43383
43320
|
inputRef.current.focus();
|
|
43384
43321
|
}
|
|
@@ -43542,8 +43479,6 @@ function StudioPreviewArea({
|
|
|
43542
43479
|
isGestureRecording,
|
|
43543
43480
|
recordingState,
|
|
43544
43481
|
onToggleRecording,
|
|
43545
|
-
cropMode,
|
|
43546
|
-
onCropModeChange,
|
|
43547
43482
|
blockPreview,
|
|
43548
43483
|
gestureOverlay
|
|
43549
43484
|
}) {
|
|
@@ -43614,7 +43549,7 @@ function StudioPreviewArea({
|
|
|
43614
43549
|
},
|
|
43615
43550
|
[domEditSelection?.id, selectedGsapAnimations]
|
|
43616
43551
|
);
|
|
43617
|
-
const timelineEditCallbacks =
|
|
43552
|
+
const timelineEditCallbacks = useMemo34(
|
|
43618
43553
|
() => ({
|
|
43619
43554
|
onMoveElement: handleTimelineElementMove,
|
|
43620
43555
|
onResizeElement: handleTimelineElementResize,
|
|
@@ -43790,8 +43725,6 @@ function StudioPreviewArea({
|
|
|
43790
43725
|
onBoxSizeCommit: handleDomBoxSizeCommit,
|
|
43791
43726
|
onRotationCommit: handleDomRotationCommit,
|
|
43792
43727
|
onStyleCommit: handleDomStyleCommit,
|
|
43793
|
-
cropMode,
|
|
43794
|
-
onCropModeChange,
|
|
43795
43728
|
gridVisible: snapPrefs.gridVisible,
|
|
43796
43729
|
gridSpacing: snapPrefs.gridSpacing,
|
|
43797
43730
|
recordingState,
|
|
@@ -43833,14 +43766,14 @@ function StudioPreviewArea({
|
|
|
43833
43766
|
// src/components/StudioRightPanel.tsx
|
|
43834
43767
|
import {
|
|
43835
43768
|
useCallback as useCallback108,
|
|
43836
|
-
useEffect as
|
|
43837
|
-
useMemo as
|
|
43769
|
+
useEffect as useEffect66,
|
|
43770
|
+
useMemo as useMemo35,
|
|
43838
43771
|
useRef as useRef97,
|
|
43839
43772
|
useState as useState90
|
|
43840
43773
|
} from "react";
|
|
43841
43774
|
|
|
43842
43775
|
// src/components/editor/LayersPanel.tsx
|
|
43843
|
-
import { memo as memo39, useState as useState83, useCallback as useCallback100, useEffect as
|
|
43776
|
+
import { memo as memo39, useState as useState83, useCallback as useCallback100, useEffect as useEffect63, useRef as useRef94 } from "react";
|
|
43844
43777
|
|
|
43845
43778
|
// src/components/editor/useLayerDrag.ts
|
|
43846
43779
|
import { useRef as useRef93, useState as useState82, useCallback as useCallback99 } from "react";
|
|
@@ -44063,10 +43996,10 @@ var LayersPanel = memo39(function LayersPanel2() {
|
|
|
44063
43996
|
});
|
|
44064
43997
|
setLayers(sortLayersByZIndex(items));
|
|
44065
43998
|
}, [previewIframeRef, activeCompPath, isMasterView, activeGroupElement, setActiveGroupElement]);
|
|
44066
|
-
|
|
43999
|
+
useEffect63(() => {
|
|
44067
44000
|
collectLayers();
|
|
44068
44001
|
}, [collectLayers, refreshKey]);
|
|
44069
|
-
|
|
44002
|
+
useEffect63(() => {
|
|
44070
44003
|
const iframe = previewIframeRef.current;
|
|
44071
44004
|
if (!iframe) return;
|
|
44072
44005
|
const handleLoad = () => {
|
|
@@ -44076,7 +44009,7 @@ var LayersPanel = memo39(function LayersPanel2() {
|
|
|
44076
44009
|
iframe.addEventListener("load", handleLoad);
|
|
44077
44010
|
return () => iframe.removeEventListener("load", handleLoad);
|
|
44078
44011
|
}, [previewIframeRef, collectLayers]);
|
|
44079
|
-
|
|
44012
|
+
useEffect63(() => {
|
|
44080
44013
|
if (!compositionLoading) {
|
|
44081
44014
|
const timer = setTimeout(collectLayers, 100);
|
|
44082
44015
|
return () => clearTimeout(timer);
|
|
@@ -44951,7 +44884,7 @@ function ParamControl({
|
|
|
44951
44884
|
}
|
|
44952
44885
|
|
|
44953
44886
|
// src/components/renders/RenderQueue.tsx
|
|
44954
|
-
import { memo as memo44, useState as useState87, useRef as useRef95, useEffect as
|
|
44887
|
+
import { memo as memo44, useState as useState87, useRef as useRef95, useEffect as useEffect64, useId as useId2 } from "react";
|
|
44955
44888
|
|
|
44956
44889
|
// src/components/renders/RenderQueueItem.tsx
|
|
44957
44890
|
import { memo as memo43, useCallback as useCallback104, useState as useState86 } from "react";
|
|
@@ -45250,8 +45183,8 @@ function FormatInfoTooltip({ format }) {
|
|
|
45250
45183
|
const hide = () => {
|
|
45251
45184
|
timeoutRef.current = setTimeout(() => setOpen(false), 120);
|
|
45252
45185
|
};
|
|
45253
|
-
|
|
45254
|
-
|
|
45186
|
+
useEffect64(() => () => clearTimeout(timeoutRef.current), []);
|
|
45187
|
+
useEffect64(() => {
|
|
45255
45188
|
if (!open) return;
|
|
45256
45189
|
const onKeyDown = (e) => {
|
|
45257
45190
|
if (e.key === "Escape") setOpen(false);
|
|
@@ -45456,7 +45389,7 @@ var RenderQueue = memo44(function RenderQueue2({
|
|
|
45456
45389
|
compositionDimensions
|
|
45457
45390
|
}) {
|
|
45458
45391
|
const listRef = useRef95(null);
|
|
45459
|
-
|
|
45392
|
+
useEffect64(() => {
|
|
45460
45393
|
if (listRef.current) {
|
|
45461
45394
|
listRef.current.scrollTo({ top: listRef.current.scrollHeight, behavior: "smooth" });
|
|
45462
45395
|
}
|
|
@@ -45564,7 +45497,7 @@ var RenderQueue = memo44(function RenderQueue2({
|
|
|
45564
45497
|
});
|
|
45565
45498
|
|
|
45566
45499
|
// src/components/panels/SlideshowPanel.tsx
|
|
45567
|
-
import { useState as useState89, useEffect as
|
|
45500
|
+
import { useState as useState89, useEffect as useEffect65, useCallback as useCallback106, useRef as useRef96 } from "react";
|
|
45568
45501
|
import { parseSlideshowManifest } from "@hyperframes/core/slideshow";
|
|
45569
45502
|
|
|
45570
45503
|
// src/components/panels/SlideshowSubPanels.tsx
|
|
@@ -46203,7 +46136,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
|
|
|
46203
46136
|
const { domEditSelection } = useDomEditSelectionContext();
|
|
46204
46137
|
const manifestRef = useRef96(manifest);
|
|
46205
46138
|
const notesCtrlRef = useRef96(makeSlideshowNotesController());
|
|
46206
|
-
|
|
46139
|
+
useEffect65(() => {
|
|
46207
46140
|
if (!compHtml) {
|
|
46208
46141
|
notesCtrlRef.current.flush();
|
|
46209
46142
|
setManifest({ slides: [] });
|
|
@@ -46237,7 +46170,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
|
|
|
46237
46170
|
},
|
|
46238
46171
|
[onPersistNotes]
|
|
46239
46172
|
);
|
|
46240
|
-
|
|
46173
|
+
useEffect65(() => {
|
|
46241
46174
|
const ctrl = notesCtrlRef.current;
|
|
46242
46175
|
return () => {
|
|
46243
46176
|
ctrl.flush();
|
|
@@ -46775,8 +46708,6 @@ function StudioRightPanel({
|
|
|
46775
46708
|
recordingState,
|
|
46776
46709
|
recordingDuration,
|
|
46777
46710
|
onToggleRecording,
|
|
46778
|
-
cropMode,
|
|
46779
|
-
onCropModeChange,
|
|
46780
46711
|
sdkSession,
|
|
46781
46712
|
reloadPreview,
|
|
46782
46713
|
domEditSaveTimestampRef,
|
|
@@ -46879,7 +46810,7 @@ function StudioRightPanel({
|
|
|
46879
46810
|
const splitContainerRef = useRef97(null);
|
|
46880
46811
|
const splitDragRef = useRef97(null);
|
|
46881
46812
|
const backgroundRemovalAbortRef = useRef97(null);
|
|
46882
|
-
|
|
46813
|
+
useEffect66(
|
|
46883
46814
|
() => () => {
|
|
46884
46815
|
backgroundRemovalAbortRef.current?.abort();
|
|
46885
46816
|
},
|
|
@@ -46887,7 +46818,7 @@ function StudioRightPanel({
|
|
|
46887
46818
|
);
|
|
46888
46819
|
const renderJobs = renderQueue.jobs;
|
|
46889
46820
|
const inspectorTabActive = rightPanelTab === "design" || rightPanelTab === "layers";
|
|
46890
|
-
const slideshowScenes =
|
|
46821
|
+
const slideshowScenes = useMemo35(() => {
|
|
46891
46822
|
try {
|
|
46892
46823
|
const win = previewIframeRef.current?.contentWindow;
|
|
46893
46824
|
return (win?.__clipManifest?.scenes ?? []).map((s) => ({
|
|
@@ -47061,9 +46992,7 @@ function StudioRightPanel({
|
|
|
47061
46992
|
onSetAllKeyframeEases: handleSetAllKeyframeEases,
|
|
47062
46993
|
recordingState,
|
|
47063
46994
|
recordingDuration,
|
|
47064
|
-
onToggleRecording
|
|
47065
|
-
cropMode,
|
|
47066
|
-
onCropModeChange
|
|
46995
|
+
onToggleRecording
|
|
47067
46996
|
}
|
|
47068
46997
|
);
|
|
47069
46998
|
const renderQueuePanel = /* @__PURE__ */ jsx106(
|
|
@@ -47505,7 +47434,7 @@ function useEnableKeyframes(sessionRef) {
|
|
|
47505
47434
|
}
|
|
47506
47435
|
|
|
47507
47436
|
// src/hooks/useKeyframeKeyboard.ts
|
|
47508
|
-
import { useEffect as
|
|
47437
|
+
import { useEffect as useEffect67, useCallback as useCallback110 } from "react";
|
|
47509
47438
|
function isTextInput(el) {
|
|
47510
47439
|
if (!el) return false;
|
|
47511
47440
|
const tag = el.tagName;
|
|
@@ -47573,7 +47502,7 @@ function useKeyframeKeyboard({
|
|
|
47573
47502
|
onNudgeKeyframe
|
|
47574
47503
|
]
|
|
47575
47504
|
);
|
|
47576
|
-
|
|
47505
|
+
useEffect67(() => {
|
|
47577
47506
|
if (!enabled) return;
|
|
47578
47507
|
window.addEventListener("keydown", handler, { capture: true });
|
|
47579
47508
|
return () => window.removeEventListener("keydown", handler, { capture: true });
|
|
@@ -47834,15 +47763,19 @@ function TimelineToolbar({
|
|
|
47834
47763
|
] }) });
|
|
47835
47764
|
}
|
|
47836
47765
|
|
|
47766
|
+
// src/components/storyboard/StoryboardView.tsx
|
|
47767
|
+
import { useState as useState96 } from "react";
|
|
47768
|
+
import { Copy as Copy2, Check as Check2 } from "@phosphor-icons/react";
|
|
47769
|
+
|
|
47837
47770
|
// src/hooks/useStoryboard.ts
|
|
47838
|
-
import { useCallback as useCallback111, useEffect as
|
|
47771
|
+
import { useCallback as useCallback111, useEffect as useEffect68, useState as useState91 } from "react";
|
|
47839
47772
|
function useStoryboard(projectId) {
|
|
47840
47773
|
const [data, setData] = useState91(null);
|
|
47841
47774
|
const [loading, setLoading] = useState91(true);
|
|
47842
47775
|
const [error, setError] = useState91(null);
|
|
47843
47776
|
const [reloadKey, setReloadKey] = useState91(0);
|
|
47844
47777
|
const reload = useCallback111(() => setReloadKey((k) => k + 1), []);
|
|
47845
|
-
|
|
47778
|
+
useEffect68(() => {
|
|
47846
47779
|
if (!projectId) return;
|
|
47847
47780
|
let cancelled = false;
|
|
47848
47781
|
setLoading(true);
|
|
@@ -47865,7 +47798,7 @@ function useStoryboard(projectId) {
|
|
|
47865
47798
|
}
|
|
47866
47799
|
|
|
47867
47800
|
// src/components/storyboard/StoryboardLoaded.tsx
|
|
47868
|
-
import { useMemo as
|
|
47801
|
+
import { useMemo as useMemo37, useState as useState95 } from "react";
|
|
47869
47802
|
|
|
47870
47803
|
// src/components/storyboard/StoryboardDirection.tsx
|
|
47871
47804
|
import { jsx as jsx108, jsxs as jsxs93 } from "react/jsx-runtime";
|
|
@@ -47888,11 +47821,11 @@ function StoryboardDirection({ globals, frameCount }) {
|
|
|
47888
47821
|
}
|
|
47889
47822
|
|
|
47890
47823
|
// src/components/storyboard/FramePoster.tsx
|
|
47891
|
-
import { useEffect as
|
|
47824
|
+
import { useEffect as useEffect69, useState as useState92 } from "react";
|
|
47892
47825
|
import { jsx as jsx109 } from "react/jsx-runtime";
|
|
47893
47826
|
function FramePoster({ projectId, src, seconds, title, fit = "cover" }) {
|
|
47894
47827
|
const [failed2, setFailed] = useState92(false);
|
|
47895
|
-
|
|
47828
|
+
useEffect69(() => setFailed(false), [src, seconds]);
|
|
47896
47829
|
if (failed2) {
|
|
47897
47830
|
return /* @__PURE__ */ jsx109("div", { className: "flex h-full w-full items-center justify-center text-[11px] text-neutral-600", children: "Preview unavailable" });
|
|
47898
47831
|
}
|
|
@@ -48065,7 +47998,7 @@ function StoryboardScriptPanel({ script }) {
|
|
|
48065
47998
|
}
|
|
48066
47999
|
|
|
48067
48000
|
// src/components/storyboard/StoryboardSourceEditor.tsx
|
|
48068
|
-
import { useCallback as useCallback112, useEffect as
|
|
48001
|
+
import { useCallback as useCallback112, useEffect as useEffect70, useMemo as useMemo36, useRef as useRef99, useState as useState93 } from "react";
|
|
48069
48002
|
import { marked } from "marked";
|
|
48070
48003
|
import DOMPurify from "dompurify";
|
|
48071
48004
|
import { jsx as jsx114, jsxs as jsxs97 } from "react/jsx-runtime";
|
|
@@ -48077,7 +48010,7 @@ function useEditableFile(path, onSaved) {
|
|
|
48077
48010
|
const [loading, setLoading] = useState93(true);
|
|
48078
48011
|
const [saving, setSaving] = useState93(false);
|
|
48079
48012
|
const [error, setError] = useState93(null);
|
|
48080
|
-
|
|
48013
|
+
useEffect70(() => {
|
|
48081
48014
|
if (!path) return;
|
|
48082
48015
|
let cancelled = false;
|
|
48083
48016
|
setLoading(true);
|
|
@@ -48115,7 +48048,7 @@ function hardenLinks(node) {
|
|
|
48115
48048
|
function useMarkdownPreview(source) {
|
|
48116
48049
|
const [debounced, setDebounced] = useState93(source);
|
|
48117
48050
|
const primed = useRef99(false);
|
|
48118
|
-
|
|
48051
|
+
useEffect70(() => {
|
|
48119
48052
|
if (!primed.current && source !== "") {
|
|
48120
48053
|
primed.current = true;
|
|
48121
48054
|
setDebounced(source);
|
|
@@ -48124,7 +48057,7 @@ function useMarkdownPreview(source) {
|
|
|
48124
48057
|
const id = window.setTimeout(() => setDebounced(source), 200);
|
|
48125
48058
|
return () => window.clearTimeout(id);
|
|
48126
48059
|
}, [source]);
|
|
48127
|
-
return
|
|
48060
|
+
return useMemo36(() => {
|
|
48128
48061
|
const html2 = marked.parse(debounced, { async: false });
|
|
48129
48062
|
DOMPurify.addHook("afterSanitizeAttributes", hardenLinks);
|
|
48130
48063
|
try {
|
|
@@ -48147,8 +48080,8 @@ function StoryboardSourceEditor({
|
|
|
48147
48080
|
const activePath = files.some((f) => f.path === selected) ? selected : files[0]?.path ?? "";
|
|
48148
48081
|
const file = useEditableFile(activePath, onSaved);
|
|
48149
48082
|
const previewHtml = useMarkdownPreview(file.content);
|
|
48150
|
-
|
|
48151
|
-
|
|
48083
|
+
useEffect70(() => onDirtyChange?.(file.dirty), [onDirtyChange, file.dirty]);
|
|
48084
|
+
useEffect70(() => {
|
|
48152
48085
|
if (!file.dirty) return;
|
|
48153
48086
|
const onBeforeUnload = (event) => {
|
|
48154
48087
|
event.preventDefault();
|
|
@@ -48220,7 +48153,7 @@ function StoryboardSourceEditor({
|
|
|
48220
48153
|
}
|
|
48221
48154
|
|
|
48222
48155
|
// src/components/storyboard/StoryboardFrameFocus.tsx
|
|
48223
|
-
import { useCallback as useCallback113, useEffect as
|
|
48156
|
+
import { useCallback as useCallback113, useEffect as useEffect71, useState as useState94 } from "react";
|
|
48224
48157
|
import { setFrameStatus, setFrameVoiceover } from "@hyperframes/core/storyboard";
|
|
48225
48158
|
import { jsx as jsx115, jsxs as jsxs98 } from "react/jsx-runtime";
|
|
48226
48159
|
function StoryboardFrameFocus({
|
|
@@ -48261,7 +48194,7 @@ function StoryboardFrameFocus({
|
|
|
48261
48194
|
const saveVoiceover = useCallback113(() => {
|
|
48262
48195
|
return applyEdit((src) => setFrameVoiceover(src, frame.index, draft));
|
|
48263
48196
|
}, [applyEdit, frame.index, draft]);
|
|
48264
|
-
|
|
48197
|
+
useEffect71(() => {
|
|
48265
48198
|
if (!dirty) return;
|
|
48266
48199
|
const onBeforeUnload = (e) => {
|
|
48267
48200
|
e.preventDefault();
|
|
@@ -48276,7 +48209,7 @@ function StoryboardFrameFocus({
|
|
|
48276
48209
|
const handleNavigate = (delta) => {
|
|
48277
48210
|
if (confirmLeave()) onNavigate(delta);
|
|
48278
48211
|
};
|
|
48279
|
-
|
|
48212
|
+
useEffect71(() => {
|
|
48280
48213
|
const onKey = (e) => {
|
|
48281
48214
|
const el = document.activeElement;
|
|
48282
48215
|
if (el instanceof HTMLTextAreaElement || el instanceof HTMLInputElement) return;
|
|
@@ -48454,7 +48387,7 @@ function StoryboardLoaded({
|
|
|
48454
48387
|
const [subView, setSubView] = useState95("board");
|
|
48455
48388
|
const [sourceDirty, setSourceDirty] = useState95(false);
|
|
48456
48389
|
const [focusedIndex, setFocusedIndex] = useState95(null);
|
|
48457
|
-
const sourceFiles =
|
|
48390
|
+
const sourceFiles = useMemo37(() => {
|
|
48458
48391
|
const files = [{ path: data.path, label: data.path }];
|
|
48459
48392
|
if (data.script?.exists) files.push({ path: data.script.path, label: data.script.path });
|
|
48460
48393
|
return files;
|
|
@@ -48584,14 +48517,75 @@ function Message({ children, tone = "muted" }) {
|
|
|
48584
48517
|
}
|
|
48585
48518
|
);
|
|
48586
48519
|
}
|
|
48520
|
+
function handoffPrompt(path) {
|
|
48521
|
+
return `Create a \`${path}\` at the project root to plan this video frame by frame.
|
|
48522
|
+
|
|
48523
|
+
Use this format:
|
|
48524
|
+
|
|
48525
|
+
---
|
|
48526
|
+
format: 1920x1080
|
|
48527
|
+
message: <the one-line takeaway of the video>
|
|
48528
|
+
arc: <the narrative shape, e.g. Problem \u2192 Solution>
|
|
48529
|
+
audience: <who it's for>
|
|
48530
|
+
---
|
|
48531
|
+
|
|
48532
|
+
## Frame 1 \u2014 <title>
|
|
48533
|
+
- duration: 5s
|
|
48534
|
+
- transition_in: crossfade
|
|
48535
|
+
- status: planned
|
|
48536
|
+
- src: compositions/frames/01-<slug>.html
|
|
48537
|
+
|
|
48538
|
+
<A sentence or two: what's on screen and what the narration says.>
|
|
48539
|
+
|
|
48540
|
+
Add one \`## Frame N\` section per beat. Keep the arc tight.`;
|
|
48541
|
+
}
|
|
48587
48542
|
function EmptyState({ path }) {
|
|
48588
|
-
|
|
48589
|
-
|
|
48590
|
-
|
|
48591
|
-
|
|
48592
|
-
|
|
48593
|
-
|
|
48594
|
-
|
|
48543
|
+
const [copied, setCopied] = useState96(false);
|
|
48544
|
+
const prompt = handoffPrompt(path);
|
|
48545
|
+
const onCopy = async () => {
|
|
48546
|
+
if (await copyTextToClipboard(prompt)) {
|
|
48547
|
+
setCopied(true);
|
|
48548
|
+
window.setTimeout(() => setCopied(false), 2e3);
|
|
48549
|
+
}
|
|
48550
|
+
};
|
|
48551
|
+
return /* @__PURE__ */ jsxs100("div", { children: [
|
|
48552
|
+
/* @__PURE__ */ jsxs100("div", { className: "rounded-lg border border-dashed border-neutral-800 px-6 py-10 text-center", children: [
|
|
48553
|
+
/* @__PURE__ */ jsx117("h2", { className: "text-base font-semibold text-neutral-300", children: "No storyboard yet" }),
|
|
48554
|
+
/* @__PURE__ */ jsxs100("p", { className: "mx-auto mt-2 max-w-md text-sm text-neutral-500", children: [
|
|
48555
|
+
"Add a ",
|
|
48556
|
+
/* @__PURE__ */ jsx117("code", { className: "rounded bg-neutral-900 px-1 py-0.5 text-neutral-400", children: path }),
|
|
48557
|
+
" ",
|
|
48558
|
+
"at the project root to plan this video frame by frame. Hand this prompt to your coding agent to scaffold it."
|
|
48559
|
+
] }),
|
|
48560
|
+
/* @__PURE__ */ jsxs100("div", { className: "mx-auto mt-6 max-w-2xl overflow-hidden rounded-lg border border-neutral-800 bg-neutral-900 text-left", children: [
|
|
48561
|
+
/* @__PURE__ */ jsxs100("div", { className: "flex items-center justify-between border-b border-neutral-800 px-3 py-2", children: [
|
|
48562
|
+
/* @__PURE__ */ jsx117("span", { className: "font-mono text-xs text-neutral-500", children: "Prompt for your agent" }),
|
|
48563
|
+
/* @__PURE__ */ jsx117(
|
|
48564
|
+
Button,
|
|
48565
|
+
{
|
|
48566
|
+
size: "sm",
|
|
48567
|
+
variant: "secondary",
|
|
48568
|
+
onClick: onCopy,
|
|
48569
|
+
icon: copied ? /* @__PURE__ */ jsx117(Check2, { size: 14 }) : /* @__PURE__ */ jsx117(Copy2, { size: 14 }),
|
|
48570
|
+
children: copied ? "Copied" : "Copy prompt"
|
|
48571
|
+
}
|
|
48572
|
+
)
|
|
48573
|
+
] }),
|
|
48574
|
+
/* @__PURE__ */ jsx117("pre", { className: "max-h-64 overflow-auto px-4 py-3 font-mono text-xs leading-relaxed text-neutral-400 whitespace-pre-wrap", children: prompt })
|
|
48575
|
+
] })
|
|
48576
|
+
] }),
|
|
48577
|
+
/* @__PURE__ */ jsx117(SkeletonPreview, {})
|
|
48578
|
+
] });
|
|
48579
|
+
}
|
|
48580
|
+
function SkeletonPreview() {
|
|
48581
|
+
return /* @__PURE__ */ jsxs100("div", { "aria-hidden": "true", className: "mt-10 select-none opacity-40", children: [
|
|
48582
|
+
/* @__PURE__ */ jsx117("div", { className: "mb-4 text-center text-xs uppercase tracking-wide text-neutral-600", children: "Preview" }),
|
|
48583
|
+
/* @__PURE__ */ jsx117("div", { className: "grid gap-x-6 gap-y-8 [grid-template-columns:repeat(auto-fill,minmax(300px,1fr))]", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsxs100("div", { className: "rounded-lg border border-neutral-800 bg-neutral-900/40 p-3", children: [
|
|
48584
|
+
/* @__PURE__ */ jsx117("div", { className: "aspect-video w-full rounded bg-neutral-800/60" }),
|
|
48585
|
+
/* @__PURE__ */ jsx117("div", { className: "mt-3 h-3 w-2/3 rounded bg-neutral-800/60" }),
|
|
48586
|
+
/* @__PURE__ */ jsx117("div", { className: "mt-2 h-2.5 w-full rounded bg-neutral-800/40" }),
|
|
48587
|
+
/* @__PURE__ */ jsx117("div", { className: "mt-1.5 h-2.5 w-4/5 rounded bg-neutral-800/40" })
|
|
48588
|
+
] }, i)) })
|
|
48595
48589
|
] });
|
|
48596
48590
|
}
|
|
48597
48591
|
|
|
@@ -48612,11 +48606,11 @@ function StudioSplash({ waiting }) {
|
|
|
48612
48606
|
}
|
|
48613
48607
|
|
|
48614
48608
|
// src/hooks/useServerConnection.ts
|
|
48615
|
-
import { useEffect as
|
|
48609
|
+
import { useEffect as useEffect72, useState as useState97 } from "react";
|
|
48616
48610
|
function useServerConnection() {
|
|
48617
|
-
const [projectId, setProjectId] =
|
|
48618
|
-
const [resolving, setResolving] =
|
|
48619
|
-
const [waitingForServer, setWaitingForServer] =
|
|
48611
|
+
const [projectId, setProjectId] = useState97(null);
|
|
48612
|
+
const [resolving, setResolving] = useState97(true);
|
|
48613
|
+
const [waitingForServer, setWaitingForServer] = useState97(false);
|
|
48620
48614
|
useMountEffect(() => {
|
|
48621
48615
|
const hashProjectId = parseProjectIdFromHash(window.location.hash);
|
|
48622
48616
|
let cancelled = false;
|
|
@@ -48653,7 +48647,7 @@ function useServerConnection() {
|
|
|
48653
48647
|
if (retryTimer !== null) clearTimeout(retryTimer);
|
|
48654
48648
|
};
|
|
48655
48649
|
});
|
|
48656
|
-
|
|
48650
|
+
useEffect72(() => {
|
|
48657
48651
|
const onHashChange = () => {
|
|
48658
48652
|
const next = parseProjectIdFromHash(window.location.hash);
|
|
48659
48653
|
if (next && next !== projectId) setProjectId(next);
|
|
@@ -48670,23 +48664,22 @@ function StudioApp() {
|
|
|
48670
48664
|
const { projectId, resolving, waitingForServer } = useServerConnection();
|
|
48671
48665
|
const initialUrlStateRef = useRef100(readStudioUrlStateFromWindow());
|
|
48672
48666
|
const viewModeValue = useViewModeState();
|
|
48673
|
-
|
|
48667
|
+
useEffect73(() => {
|
|
48674
48668
|
if (resolving || waitingForServer) return;
|
|
48675
48669
|
if (hasFiredSessionStart()) return;
|
|
48676
48670
|
markSessionStartFired();
|
|
48677
48671
|
trackStudioSessionStart({ has_project: projectId != null });
|
|
48678
48672
|
}, [projectId, resolving, waitingForServer]);
|
|
48679
|
-
const [activeCompPath, setActiveCompPath] =
|
|
48680
|
-
const [activeCompPathHydrated, setActiveCompPathHydrated] =
|
|
48673
|
+
const [activeCompPath, setActiveCompPath] = useState98(null);
|
|
48674
|
+
const [activeCompPathHydrated, setActiveCompPathHydrated] = useState98(
|
|
48681
48675
|
() => initialUrlStateRef.current.activeCompPath == null
|
|
48682
48676
|
);
|
|
48683
|
-
const [compIdToSrc, setCompIdToSrc] =
|
|
48684
|
-
const [previewIframe, setPreviewIframe] =
|
|
48685
|
-
const [compositionLoading, setCompositionLoading] =
|
|
48686
|
-
const [refreshKey, setRefreshKey] =
|
|
48687
|
-
const [previewDocumentVersion, setPreviewDocumentVersion] =
|
|
48688
|
-
const [blockPreview, setBlockPreview] =
|
|
48689
|
-
const cropModeProps = useCropModeProps();
|
|
48677
|
+
const [compIdToSrc, setCompIdToSrc] = useState98(/* @__PURE__ */ new Map());
|
|
48678
|
+
const [previewIframe, setPreviewIframe] = useState98(null);
|
|
48679
|
+
const [compositionLoading, setCompositionLoading] = useState98(true);
|
|
48680
|
+
const [refreshKey, setRefreshKey] = useState98(0);
|
|
48681
|
+
const [previewDocumentVersion, setPreviewDocumentVersion] = useState98(0);
|
|
48682
|
+
const [blockPreview, setBlockPreview] = useState98(null);
|
|
48690
48683
|
const previewIframeRef = useRef100(null);
|
|
48691
48684
|
const activeCompPathRef = useRef100(activeCompPath);
|
|
48692
48685
|
activeCompPathRef.current = activeCompPath;
|
|
@@ -48701,7 +48694,7 @@ function StudioApp() {
|
|
|
48701
48694
|
const isPlaying = usePlayerStore((s) => s.isPlaying);
|
|
48702
48695
|
const isMasterView = !activeCompPath || activeCompPath === "index.html";
|
|
48703
48696
|
const activePreviewUrl = activeCompPath ? `/api/projects/${projectId}/preview/comp/${activeCompPath}` : null;
|
|
48704
|
-
const effectiveTimelineDuration =
|
|
48697
|
+
const effectiveTimelineDuration = useMemo38(() => {
|
|
48705
48698
|
const maxEnd = timelineElements.length > 0 ? Math.max(...timelineElements.map((el) => el.start + el.duration)) : 0;
|
|
48706
48699
|
return Math.max(timelineDuration, maxEnd);
|
|
48707
48700
|
}, [timelineDuration, timelineElements]);
|
|
@@ -48715,13 +48708,13 @@ function StudioApp() {
|
|
|
48715
48708
|
window.setTimeout(() => setPreviewDocumentVersion((v) => v + 1), 300)
|
|
48716
48709
|
);
|
|
48717
48710
|
}, []);
|
|
48718
|
-
|
|
48711
|
+
useEffect73(
|
|
48719
48712
|
() => () => {
|
|
48720
48713
|
for (const id of refreshTimersRef.current) clearTimeout(id);
|
|
48721
48714
|
},
|
|
48722
48715
|
[]
|
|
48723
48716
|
);
|
|
48724
|
-
const [timelineVisible, setTimelineVisible] =
|
|
48717
|
+
const [timelineVisible, setTimelineVisible] = useState98(
|
|
48725
48718
|
() => initialUrlStateRef.current.timelineVisible ?? readStudioUiPreferences().timelineVisible ?? true
|
|
48726
48719
|
);
|
|
48727
48720
|
const toggleTimelineVisibility = useCallback114(() => {
|
|
@@ -48748,7 +48741,7 @@ function StudioApp() {
|
|
|
48748
48741
|
setRefreshKey
|
|
48749
48742
|
});
|
|
48750
48743
|
const sdkHandle = useSdkSession(projectId, activeCompPath, domEditSaveTimestampRef);
|
|
48751
|
-
|
|
48744
|
+
useEffect73(() => {
|
|
48752
48745
|
if (activeCompPathHydrated) return;
|
|
48753
48746
|
if (!fileManager.fileTreeLoaded) return;
|
|
48754
48747
|
const nextCompPath = normalizeStudioCompositionPath(
|
|
@@ -49047,7 +49040,7 @@ function StudioApp() {
|
|
|
49047
49040
|
timelineVisible,
|
|
49048
49041
|
toggleTimelineVisibility
|
|
49049
49042
|
});
|
|
49050
|
-
const timelineToolbar =
|
|
49043
|
+
const timelineToolbar = useMemo38(
|
|
49051
49044
|
() => /* @__PURE__ */ jsx119(
|
|
49052
49045
|
TimelineToolbar,
|
|
49053
49046
|
{
|
|
@@ -49143,7 +49136,6 @@ function StudioApp() {
|
|
|
49143
49136
|
recordingState: gestureState,
|
|
49144
49137
|
onToggleRecording: recordingToggle,
|
|
49145
49138
|
blockPreview,
|
|
49146
|
-
...cropModeProps,
|
|
49147
49139
|
gestureOverlay: gestureState === "recording" && previewIframe ? /* @__PURE__ */ jsx119(
|
|
49148
49140
|
GestureTrailOverlay,
|
|
49149
49141
|
{
|
|
@@ -49173,7 +49165,6 @@ function StudioApp() {
|
|
|
49173
49165
|
reloadPreview,
|
|
49174
49166
|
domEditSaveTimestampRef,
|
|
49175
49167
|
recordEdit: editHistory.recordEdit,
|
|
49176
|
-
...cropModeProps,
|
|
49177
49168
|
onToggleElementHidden: timelineEditing.handleToggleElementHidden
|
|
49178
49169
|
}
|
|
49179
49170
|
)
|
|
@@ -49202,10 +49193,10 @@ function StudioApp() {
|
|
|
49202
49193
|
}
|
|
49203
49194
|
|
|
49204
49195
|
// src/hooks/useElementPicker.ts
|
|
49205
|
-
import { useState as
|
|
49196
|
+
import { useState as useState99, useCallback as useCallback115, useRef as useRef101 } from "react";
|
|
49206
49197
|
function useElementPicker(iframeRef, options) {
|
|
49207
|
-
const [isPickMode, setIsPickMode] =
|
|
49208
|
-
const [pickedElement, setPickedElement] =
|
|
49198
|
+
const [isPickMode, setIsPickMode] = useState99(false);
|
|
49199
|
+
const [pickedElement, setPickedElement] = useState99(null);
|
|
49209
49200
|
const activeOverrideRef = useRef101(null);
|
|
49210
49201
|
const getActiveIframe = useCallback115(() => {
|
|
49211
49202
|
return activeOverrideRef.current ?? iframeRef.current;
|