@hyperframes/studio 0.6.96 → 0.6.98
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-DgsMQSvV.js +418 -0
- package/dist/assets/index-B62bDCQv.css +1 -0
- package/dist/assets/index-Ce3pBm_I.js +252 -0
- package/dist/assets/{index-BWFaypdT.js → index-D-ET9M0b.js} +1 -1
- package/dist/assets/index-D-bS9Dxx.js +1 -0
- package/dist/index.html +2 -2
- package/package.json +7 -5
- package/src/App.tsx +182 -177
- package/src/captions/store.ts +11 -11
- package/src/components/StudioHeader.tsx +4 -4
- package/src/components/StudioLeftSidebar.tsx +2 -2
- package/src/components/StudioPreviewArea.tsx +225 -183
- package/src/components/StudioRightPanel.tsx +3 -3
- package/src/components/TimelineToolbar.tsx +25 -0
- package/src/components/editor/DomEditOverlay.tsx +2 -5
- package/src/components/editor/EaseCurveSection.tsx +2 -3
- package/src/components/editor/GestureTrailOverlay.tsx +4 -3
- package/src/components/editor/LayersPanel.tsx +3 -9
- package/src/components/editor/PropertyPanel.tsx +20 -61
- package/src/components/editor/colorValue.ts +3 -1
- package/src/components/editor/domEditOverlayGestures.ts +54 -1
- package/src/components/editor/domEditOverlayStartGesture.ts +5 -2
- package/src/components/editor/gradientValue.ts +3 -3
- package/src/components/editor/keyframeMove.test.ts +101 -0
- package/src/components/editor/keyframeMove.ts +151 -0
- package/src/components/editor/manualEditsDom.ts +0 -12
- package/src/components/editor/propertyPanelHelpers.ts +10 -38
- package/src/components/editor/propertyPanelMediaSection.tsx +1 -5
- package/src/components/editor/propertyPanelTimingSection.tsx +1 -6
- package/src/components/editor/propertyPanelTransformCommit.ts +129 -0
- package/src/components/editor/studioMotionOps.test.ts +1 -1
- package/src/components/editor/studioMotionOps.ts +2 -1
- package/src/components/editor/useDomEditOverlayGestures.ts +1 -46
- package/src/components/nle/NLELayout.tsx +1 -24
- package/src/components/sidebar/BlocksTab.tsx +2 -2
- package/src/contexts/DomEditContext.tsx +134 -31
- package/src/contexts/StudioContext.tsx +90 -40
- package/src/contexts/TimelineEditContext.tsx +47 -0
- package/src/hooks/domEditCommitTypes.ts +14 -0
- package/src/hooks/gsapDragCommit.ts +9 -24
- package/src/hooks/gsapKeyframeCacheHelpers.ts +2 -1
- package/src/hooks/gsapKeyframeCommit.ts +5 -15
- package/src/hooks/gsapRuntimeBridge.ts +18 -52
- package/src/hooks/gsapRuntimeKeyframes.ts +8 -57
- package/src/hooks/gsapRuntimeReaders.ts +19 -26
- package/src/hooks/gsapScriptCommitHelpers.ts +1 -11
- package/src/hooks/gsapScriptCommitTypes.ts +58 -0
- package/src/hooks/gsapShared.ts +157 -0
- package/src/hooks/timelineEditingHelpers.ts +63 -2
- package/src/hooks/useAnimatedPropertyCommit.ts +3 -25
- package/src/hooks/useAppHotkeys.ts +299 -377
- package/src/hooks/useConsoleErrorCapture.ts +33 -5
- package/src/hooks/useDomEditCommits.ts +35 -293
- package/src/hooks/useDomEditPositionPatchCommit.ts +1 -1
- package/src/hooks/useDomEditSession.ts +78 -249
- package/src/hooks/useDomEditTextCommits.ts +1 -1
- package/src/hooks/useDomEditWiring.ts +255 -0
- package/src/hooks/useDomGeometryCommits.ts +181 -0
- package/src/hooks/useDomSelection.ts +10 -27
- package/src/hooks/useEditorSave.ts +82 -0
- package/src/hooks/useElementLifecycleOps.ts +177 -0
- package/src/hooks/useEnableKeyframes.ts +10 -15
- package/src/hooks/useFileManager.ts +32 -114
- package/src/hooks/useFileTree.ts +80 -0
- package/src/hooks/useGestureCommit.ts +7 -5
- package/src/hooks/useGestureRecording.ts +1 -1
- package/src/hooks/useGsapAnimationOps.ts +122 -0
- package/src/hooks/useGsapArcPathOps.ts +61 -0
- package/src/hooks/useGsapAwareEditing.ts +242 -0
- package/src/hooks/useGsapKeyframeOps.ts +167 -0
- package/src/hooks/useGsapPropertyDebounce.ts +135 -0
- package/src/hooks/useGsapScriptCommits.ts +58 -570
- package/src/hooks/useGsapSelectionHandlers.ts +22 -9
- package/src/hooks/useGsapTweenCache.ts +35 -29
- package/src/hooks/useLintModal.ts +7 -0
- package/src/hooks/useMusicBeatAnalysis.ts +152 -0
- package/src/hooks/useRazorSplit.ts +1 -1
- package/src/hooks/useRenderClipContent.ts +46 -21
- package/src/hooks/useTimelineEditing.ts +48 -4
- package/src/player/components/AudioWaveform.tsx +29 -4
- package/src/player/components/BeatStrip.tsx +166 -0
- package/src/player/components/Timeline.tsx +39 -18
- package/src/player/components/TimelineCanvas.tsx +52 -12
- package/src/player/components/TimelineClipDiamonds.tsx +130 -20
- package/src/player/components/TimelinePropertyRows.tsx +8 -2
- package/src/player/components/TimelineRuler.tsx +36 -2
- package/src/player/components/timelineEditing.ts +30 -5
- package/src/player/components/useTimelineClipDrag.ts +155 -4
- package/src/player/components/useTimelinePlayhead.ts +30 -1
- package/src/player/hooks/useTimelinePlayer.ts +47 -45
- package/src/player/lib/mediaProbe.ts +46 -3
- package/src/player/lib/playbackScrub.ts +16 -0
- package/src/player/lib/timelineDOM.ts +10 -2
- package/src/player/lib/timelineIframeHelpers.ts +89 -0
- package/src/player/store/playerStore.ts +92 -33
- package/src/utils/beatEditActions.ts +109 -0
- package/src/utils/beatEditing.ts +136 -0
- package/src/utils/clipboardPayload.ts +3 -2
- package/src/utils/compositionPatterns.ts +2 -0
- package/src/utils/keyframeSelection.test.ts +45 -0
- package/src/utils/keyframeSelection.ts +29 -0
- package/src/utils/rounding.ts +9 -0
- package/src/utils/studioHelpers.ts +5 -2
- package/src/utils/studioUrlState.ts +2 -1
- package/src/utils/timelineAssetDrop.ts +6 -5
- package/src/utils/timelineInspector.ts +15 -100
- package/dist/assets/hyperframes-player-0esDKGRk.js +0 -418
- package/dist/assets/index-B0twsRu0.css +0 -1
- package/dist/assets/index-BA979yF1.js +0 -251
- package/src/components/editor/DopesheetStrip.tsx +0 -141
- package/src/components/editor/StaggerControls.tsx +0 -61
- package/src/components/editor/TimelineLayerPanel.test.ts +0 -42
- package/src/components/editor/TimelineLayerPanel.tsx +0 -15
- package/src/components/nle/TimelineEditorNotice.tsx +0 -133
- package/src/hooks/gsapRuntimePreview.ts +0 -19
- package/src/player/components/timelineUtils.ts +0 -211
- package/src/utils/audioBeatDetection.ts +0 -58
- package/src/utils/keyframeSnapping.test.ts +0 -74
- package/src/utils/keyframeSnapping.ts +0 -63
- package/src/utils/timelineInspector.test.ts +0 -79
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { DomEditSelection } from "./domEditingTypes";
|
|
2
|
+
import { readStudioBoxSize, readStudioPathOffset } from "./manualEdits";
|
|
3
|
+
import { parsePxMetricValue, type PropertyPanelProps } from "./propertyPanelHelpers";
|
|
4
|
+
|
|
5
|
+
interface TransformCommitDeps {
|
|
6
|
+
element: DomEditSelection;
|
|
7
|
+
styles: Record<string, string>;
|
|
8
|
+
hasGsapAnimation: boolean;
|
|
9
|
+
gsapAnimId: string | null;
|
|
10
|
+
gsapKeyframes: unknown;
|
|
11
|
+
currentPct: number;
|
|
12
|
+
onCommitAnimatedProperty: PropertyPanelProps["onCommitAnimatedProperty"];
|
|
13
|
+
onAddKeyframe: PropertyPanelProps["onAddKeyframe"];
|
|
14
|
+
onSetManualOffset: PropertyPanelProps["onSetManualOffset"];
|
|
15
|
+
onSetManualSize: PropertyPanelProps["onSetManualSize"];
|
|
16
|
+
onSetManualRotation: PropertyPanelProps["onSetManualRotation"];
|
|
17
|
+
showToast?: (message: string, tone?: "error" | "info") => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Build the X/Y, W/H and rotation field commit handlers for the property panel.
|
|
22
|
+
* Each handler routes the value into the GSAP animation when the element is
|
|
23
|
+
* animated (matching the drag gesture and keyframe buttons), and otherwise
|
|
24
|
+
* falls through to the manual transform setter.
|
|
25
|
+
*/
|
|
26
|
+
// fallow-ignore-next-line unit-size
|
|
27
|
+
export function createTransformCommitHandlers({
|
|
28
|
+
element,
|
|
29
|
+
styles,
|
|
30
|
+
hasGsapAnimation,
|
|
31
|
+
gsapAnimId,
|
|
32
|
+
gsapKeyframes,
|
|
33
|
+
currentPct,
|
|
34
|
+
onCommitAnimatedProperty,
|
|
35
|
+
onAddKeyframe,
|
|
36
|
+
onSetManualOffset,
|
|
37
|
+
onSetManualSize,
|
|
38
|
+
onSetManualRotation,
|
|
39
|
+
showToast,
|
|
40
|
+
}: TransformCommitDeps) {
|
|
41
|
+
// Route a transform value into the GSAP animation (or a new keyframe) when the
|
|
42
|
+
// element is animated. Returns true when handled, so callers fall through to
|
|
43
|
+
// the manual-transform path only for non-animated elements.
|
|
44
|
+
const commitAnimatedTransformValue = (
|
|
45
|
+
property: string,
|
|
46
|
+
value: number,
|
|
47
|
+
noCallbacksMessage: string,
|
|
48
|
+
): boolean => {
|
|
49
|
+
if (onCommitAnimatedProperty && hasGsapAnimation) {
|
|
50
|
+
void onCommitAnimatedProperty(element, property, value);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (gsapKeyframes && gsapAnimId && onAddKeyframe) {
|
|
54
|
+
const pct = Math.max(0, Math.min(100, Math.round(currentPct * 10) / 10));
|
|
55
|
+
onAddKeyframe(gsapAnimId, pct, property, value);
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (hasGsapAnimation) {
|
|
59
|
+
showToast?.(noCallbacksMessage);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const commitManualOffset = (axis: "x" | "y", nextValue: string) => {
|
|
66
|
+
const parsed = parsePxMetricValue(nextValue);
|
|
67
|
+
if (parsed == null) return;
|
|
68
|
+
if (
|
|
69
|
+
commitAnimatedTransformValue(
|
|
70
|
+
axis,
|
|
71
|
+
parsed,
|
|
72
|
+
"Cannot edit position — animation callbacks not available",
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
return;
|
|
76
|
+
const current = readStudioPathOffset(element.element);
|
|
77
|
+
void Promise.resolve(
|
|
78
|
+
onSetManualOffset(element, {
|
|
79
|
+
x: axis === "x" ? parsed : current.x,
|
|
80
|
+
y: axis === "y" ? parsed : current.y,
|
|
81
|
+
}),
|
|
82
|
+
).catch(() => undefined);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// fallow-ignore-next-line complexity
|
|
86
|
+
const commitManualSize = (axis: "width" | "height", nextValue: string) => {
|
|
87
|
+
const parsed = parsePxMetricValue(nextValue);
|
|
88
|
+
if (parsed == null || parsed <= 0) return;
|
|
89
|
+
if (onCommitAnimatedProperty && hasGsapAnimation) {
|
|
90
|
+
void onCommitAnimatedProperty(element, axis, parsed);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (hasGsapAnimation) {
|
|
94
|
+
showToast?.("Cannot edit size — animation callbacks not available");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const current = readStudioBoxSize(element.element);
|
|
98
|
+
const width =
|
|
99
|
+
current.width > 0
|
|
100
|
+
? current.width
|
|
101
|
+
: (parsePxMetricValue(styles.width ?? "") ?? element.boundingBox.width);
|
|
102
|
+
const height =
|
|
103
|
+
current.height > 0
|
|
104
|
+
? current.height
|
|
105
|
+
: (parsePxMetricValue(styles.height ?? "") ?? element.boundingBox.height);
|
|
106
|
+
void Promise.resolve(
|
|
107
|
+
onSetManualSize(element, {
|
|
108
|
+
width: axis === "width" ? parsed : width,
|
|
109
|
+
height: axis === "height" ? parsed : height,
|
|
110
|
+
}),
|
|
111
|
+
).catch(() => undefined);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const commitManualRotation = (nextValue: string) => {
|
|
115
|
+
const parsed = Number.parseFloat(nextValue);
|
|
116
|
+
if (!Number.isFinite(parsed)) return;
|
|
117
|
+
if (
|
|
118
|
+
commitAnimatedTransformValue(
|
|
119
|
+
"rotation",
|
|
120
|
+
parsed,
|
|
121
|
+
"Cannot edit rotation — animation callbacks not available",
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
return;
|
|
125
|
+
void Promise.resolve(onSetManualRotation(element, { angle: parsed })).catch(() => undefined);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
return { commitManualOffset, commitManualSize, commitManualRotation };
|
|
129
|
+
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
STUDIO_MOTION_ORIGINAL_OPACITY_ATTR,
|
|
12
12
|
STUDIO_MOTION_ORIGINAL_VISIBILITY_ATTR,
|
|
13
13
|
} from "./studioMotionTypes";
|
|
14
|
-
import { buildMotionPatches, buildClearMotionPatches } from "./
|
|
14
|
+
import { buildMotionPatches, buildClearMotionPatches } from "./manualEditsDomPatches";
|
|
15
15
|
import { applyPatchByTarget, readAttributeByTarget } from "../../utils/sourcePatcher";
|
|
16
16
|
|
|
17
17
|
function createElement(markup: string): HTMLElement {
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type StudioMotionManifest,
|
|
19
19
|
type StudioMotionTarget,
|
|
20
20
|
} from "./studioMotionTypes";
|
|
21
|
+
import { roundTo3 } from "../../utils/rounding";
|
|
21
22
|
|
|
22
23
|
// ── Private helpers ──
|
|
23
24
|
|
|
@@ -34,7 +35,7 @@ function sanitizeEase(value: string): string {
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
function roundEaseNumber(value: number): number {
|
|
37
|
-
return
|
|
38
|
+
return roundTo3(value);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
function clampRange(value: number, min: number, max: number, fallback: number): number {
|
|
@@ -33,15 +33,14 @@ import {
|
|
|
33
33
|
} from "./domEditOverlayGeometry";
|
|
34
34
|
import {
|
|
35
35
|
BLOCKED_MOVE_THRESHOLD_PX,
|
|
36
|
-
type BlockedMoveState,
|
|
37
36
|
type GestureKind,
|
|
38
37
|
type GestureState,
|
|
39
38
|
type GroupGestureState,
|
|
39
|
+
type UseDomEditOverlayGesturesOptions,
|
|
40
40
|
hasDomEditRotationChanged,
|
|
41
41
|
resolveDomEditResizeGesture,
|
|
42
42
|
resolveDomEditRotationGesture,
|
|
43
43
|
} from "./domEditOverlayGestures";
|
|
44
|
-
import type { DomEditGroupPathOffsetCommit } from "./DomEditOverlay";
|
|
45
44
|
import {
|
|
46
45
|
startGesture as _startGesture,
|
|
47
46
|
startGroupDrag as _startGroupDrag,
|
|
@@ -52,50 +51,6 @@ import {
|
|
|
52
51
|
resolveEquidistanceGuides,
|
|
53
52
|
SNAP_THRESHOLD_PX,
|
|
54
53
|
} from "./snapEngine";
|
|
55
|
-
import type { SnapGuidesState } from "./SnapGuideOverlay";
|
|
56
|
-
|
|
57
|
-
// Refs are stable across renders; values are read via .current.
|
|
58
|
-
export type UseDomEditOverlayGesturesOptions = {
|
|
59
|
-
overlayRef: RefObject<HTMLDivElement | null>;
|
|
60
|
-
iframeRef: RefObject<HTMLIFrameElement | null>;
|
|
61
|
-
boxRef: RefObject<HTMLDivElement | null>;
|
|
62
|
-
selectionRef: RefObject<DomEditSelection | null>;
|
|
63
|
-
overlayRectRef: RefObject<OverlayRect | null>;
|
|
64
|
-
groupOverlayItemsRef: RefObject<GroupOverlayItem[]>;
|
|
65
|
-
gestureRef: RefObject<GestureState | null>;
|
|
66
|
-
groupGestureRef: RefObject<GroupGestureState | null>;
|
|
67
|
-
blockedMoveRef: RefObject<BlockedMoveState | null>;
|
|
68
|
-
rafPausedRef: RefObject<boolean>;
|
|
69
|
-
suppressNextBoxClickRef: RefObject<boolean>;
|
|
70
|
-
setOverlayRect: (next: OverlayRect | null) => void;
|
|
71
|
-
setGroupOverlayItems: (next: GroupOverlayItem[]) => void;
|
|
72
|
-
onBlockedMoveRef: RefObject<(selection: DomEditSelection) => void>;
|
|
73
|
-
onManualDragStartRef: RefObject<(() => void) | undefined>;
|
|
74
|
-
onPathOffsetCommitRef: RefObject<
|
|
75
|
-
(s: DomEditSelection, n: { x: number; y: number }) => Promise<void> | void
|
|
76
|
-
>;
|
|
77
|
-
onGroupPathOffsetCommitRef: RefObject<
|
|
78
|
-
(updates: DomEditGroupPathOffsetCommit[]) => Promise<void> | void
|
|
79
|
-
>;
|
|
80
|
-
onBoxSizeCommitRef: RefObject<
|
|
81
|
-
(s: DomEditSelection, n: { width: number; height: number }) => Promise<void> | void
|
|
82
|
-
>;
|
|
83
|
-
onRotationCommitRef: RefObject<
|
|
84
|
-
(s: DomEditSelection, n: { angle: number }) => Promise<void> | void
|
|
85
|
-
>;
|
|
86
|
-
onCanvasPointerMoveRef: RefObject<
|
|
87
|
-
(
|
|
88
|
-
e: React.PointerEvent<HTMLDivElement>,
|
|
89
|
-
o?: { preferClipAncestor?: boolean },
|
|
90
|
-
) => Promise<DomEditSelection | null>
|
|
91
|
-
>;
|
|
92
|
-
onCanvasMouseDown: (
|
|
93
|
-
e: React.MouseEvent<HTMLDivElement>,
|
|
94
|
-
o?: { preferClipAncestor?: boolean },
|
|
95
|
-
) => void;
|
|
96
|
-
snapGuidesRef: RefObject<SnapGuidesState | null>;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
54
|
export function createDomEditOverlayGestureHandlers(opts: UseDomEditOverlayGesturesOptions) {
|
|
100
55
|
const setDraftOverlayRect = (next: OverlayRect) => {
|
|
101
56
|
opts.setOverlayRect(next);
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
import { useMountEffect } from "../../hooks/useMountEffect";
|
|
11
11
|
import { useTimelinePlayer, PlayerControls, Timeline, usePlayerStore } from "../../player";
|
|
12
12
|
import type { TimelineElement } from "../../player";
|
|
13
|
-
import type { TimelineEditCallbacks } from "../../player/components/timelineCallbacks";
|
|
14
13
|
import { NLEPreview } from "./NLEPreview";
|
|
15
14
|
import { CompositionBreadcrumb } from "./CompositionBreadcrumb";
|
|
16
15
|
import { usePreviewBlockDrop } from "./usePreviewBlockDrop";
|
|
@@ -20,7 +19,7 @@ import {
|
|
|
20
19
|
getTimelineToggleTitle,
|
|
21
20
|
} from "../../utils/timelineDiscovery";
|
|
22
21
|
|
|
23
|
-
interface NLELayoutProps
|
|
22
|
+
interface NLELayoutProps {
|
|
24
23
|
projectId: string;
|
|
25
24
|
portrait?: boolean;
|
|
26
25
|
/** Slot for overlays rendered on top of the preview (cursors, highlights, etc.) */
|
|
@@ -104,18 +103,7 @@ export const NLELayout = memo(function NLELayout({
|
|
|
104
103
|
onAssetDrop,
|
|
105
104
|
onBlockDrop,
|
|
106
105
|
onPreviewBlockDrop,
|
|
107
|
-
onMoveElement,
|
|
108
|
-
onResizeElement,
|
|
109
|
-
onBlockedEditAttempt,
|
|
110
|
-
onSplitElement,
|
|
111
|
-
onRazorSplit,
|
|
112
|
-
onRazorSplitAll,
|
|
113
106
|
onSelectTimelineElement,
|
|
114
|
-
onDeleteKeyframe,
|
|
115
|
-
onDeleteAllKeyframes,
|
|
116
|
-
onChangeKeyframeEase,
|
|
117
|
-
onMoveKeyframe,
|
|
118
|
-
onToggleKeyframeAtPlayhead,
|
|
119
107
|
onCompIdToSrcChange,
|
|
120
108
|
timelineVisible,
|
|
121
109
|
onToggleTimeline,
|
|
@@ -444,18 +432,7 @@ export const NLELayout = memo(function NLELayout({
|
|
|
444
432
|
onDeleteElement={onDeleteElement}
|
|
445
433
|
onAssetDrop={onAssetDrop}
|
|
446
434
|
onBlockDrop={onBlockDrop}
|
|
447
|
-
onMoveElement={onMoveElement}
|
|
448
|
-
onResizeElement={onResizeElement}
|
|
449
|
-
onBlockedEditAttempt={onBlockedEditAttempt}
|
|
450
|
-
onSplitElement={onSplitElement}
|
|
451
|
-
onRazorSplit={onRazorSplit}
|
|
452
|
-
onRazorSplitAll={onRazorSplitAll}
|
|
453
435
|
onSelectElement={onSelectTimelineElement}
|
|
454
|
-
onDeleteKeyframe={onDeleteKeyframe}
|
|
455
|
-
onDeleteAllKeyframes={onDeleteAllKeyframes}
|
|
456
|
-
onChangeKeyframeEase={onChangeKeyframeEase}
|
|
457
|
-
onMoveKeyframe={onMoveKeyframe}
|
|
458
|
-
onToggleKeyframeAtPlayhead={onToggleKeyframeAtPlayhead}
|
|
459
436
|
/>
|
|
460
437
|
</div>
|
|
461
438
|
{timelineFooter && <div className="flex-shrink-0">{timelineFooter}</div>}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "../../utils/blockCategories";
|
|
9
9
|
import { usePlayerStore } from "../../player";
|
|
10
10
|
import { formatTime } from "../../player/lib/time";
|
|
11
|
-
import {
|
|
11
|
+
import { useStudioShellContext } from "../../contexts/StudioContext";
|
|
12
12
|
export interface BlockPreviewInfo {
|
|
13
13
|
videoUrl?: string;
|
|
14
14
|
posterUrl?: string;
|
|
@@ -345,7 +345,7 @@ function BlockCard({
|
|
|
345
345
|
[onAdd, adding],
|
|
346
346
|
);
|
|
347
347
|
|
|
348
|
-
const { activeCompPath, compositionDimensions } =
|
|
348
|
+
const { activeCompPath, compositionDimensions } = useStudioShellContext();
|
|
349
349
|
|
|
350
350
|
const handleShowPrompt = useCallback(
|
|
351
351
|
(e: React.MouseEvent) => {
|
|
@@ -1,17 +1,101 @@
|
|
|
1
1
|
// fallow-ignore-file code-duplication
|
|
2
|
-
import { createContext, useContext, useMemo, type ReactNode } from "react";
|
|
2
|
+
import { createContext, useCallback, useContext, useMemo, useRef, type ReactNode } from "react";
|
|
3
3
|
import type { useDomEditSession } from "../hooks/useDomEditSession";
|
|
4
4
|
|
|
5
5
|
type DomEditValue = ReturnType<typeof useDomEditSession>;
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
export interface DomEditActionsValue extends Pick<
|
|
8
|
+
DomEditValue,
|
|
9
|
+
| "handleTimelineElementSelect"
|
|
10
|
+
| "handlePreviewCanvasMouseDown"
|
|
11
|
+
| "handlePreviewCanvasPointerMove"
|
|
12
|
+
| "handlePreviewCanvasPointerLeave"
|
|
13
|
+
| "applyDomSelection"
|
|
14
|
+
| "clearDomSelection"
|
|
15
|
+
| "handleDomStyleCommit"
|
|
16
|
+
| "handleDomAttributeCommit"
|
|
17
|
+
| "handleDomHtmlAttributeCommit"
|
|
18
|
+
| "handleDomPathOffsetCommit"
|
|
19
|
+
| "handleDomGroupPathOffsetCommit"
|
|
20
|
+
| "handleDomZIndexReorderCommit"
|
|
21
|
+
| "handleDomBoxSizeCommit"
|
|
22
|
+
| "handleDomRotationCommit"
|
|
23
|
+
| "handleDomManualEditsReset"
|
|
24
|
+
| "handleDomTextCommit"
|
|
25
|
+
| "handleDomTextFieldStyleCommit"
|
|
26
|
+
| "handleDomAddTextField"
|
|
27
|
+
| "handleDomRemoveTextField"
|
|
28
|
+
| "handleAskAgent"
|
|
29
|
+
| "handleAgentModalSubmit"
|
|
30
|
+
| "handleBlockedDomMove"
|
|
31
|
+
| "handleDomManualDragStart"
|
|
32
|
+
| "handleDomEditElementDelete"
|
|
33
|
+
| "buildDomSelectionFromTarget"
|
|
34
|
+
| "buildDomSelectionForTimelineElement"
|
|
35
|
+
| "updateDomEditHoverSelection"
|
|
36
|
+
| "resolveImportedFontAsset"
|
|
37
|
+
| "setAgentModalOpen"
|
|
38
|
+
| "setAgentPromptSelectionContext"
|
|
39
|
+
| "setAgentModalAnchorPoint"
|
|
40
|
+
| "handleGsapUpdateProperty"
|
|
41
|
+
| "handleGsapUpdateMeta"
|
|
42
|
+
| "handleGsapDeleteAnimation"
|
|
43
|
+
| "handleGsapDeleteAllForElement"
|
|
44
|
+
| "handleGsapAddAnimation"
|
|
45
|
+
| "handleGsapAddProperty"
|
|
46
|
+
| "handleGsapRemoveProperty"
|
|
47
|
+
| "handleGsapUpdateFromProperty"
|
|
48
|
+
| "handleGsapAddFromProperty"
|
|
49
|
+
| "handleGsapRemoveFromProperty"
|
|
50
|
+
| "handleGsapAddKeyframe"
|
|
51
|
+
| "handleGsapAddKeyframeBatch"
|
|
52
|
+
| "handleGsapRemoveKeyframe"
|
|
53
|
+
| "handleGsapConvertToKeyframes"
|
|
54
|
+
| "handleGsapRemoveAllKeyframes"
|
|
55
|
+
| "handleResetSelectedElementKeyframes"
|
|
56
|
+
| "commitAnimatedProperty"
|
|
57
|
+
| "handleSetArcPath"
|
|
58
|
+
| "handleUpdateArcSegment"
|
|
59
|
+
| "invalidateGsapCache"
|
|
60
|
+
| "previewIframeRef"
|
|
61
|
+
| "commitMutation"
|
|
62
|
+
> {}
|
|
8
63
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
64
|
+
export interface DomEditSelectionValue extends Pick<
|
|
65
|
+
DomEditValue,
|
|
66
|
+
| "domEditSelection"
|
|
67
|
+
| "domEditGroupSelections"
|
|
68
|
+
| "domEditHoverSelection"
|
|
69
|
+
| "domEditSelectionRef"
|
|
70
|
+
| "selectedGsapAnimations"
|
|
71
|
+
| "gsapMultipleTimelines"
|
|
72
|
+
| "gsapUnsupportedTimelinePattern"
|
|
73
|
+
| "agentModalOpen"
|
|
74
|
+
| "agentModalAnchorPoint"
|
|
75
|
+
| "copiedAgentPrompt"
|
|
76
|
+
| "agentPromptSelectionContext"
|
|
77
|
+
> {}
|
|
78
|
+
|
|
79
|
+
const DomEditActionsContext = createContext<DomEditActionsValue | null>(null);
|
|
80
|
+
const DomEditSelectionContext = createContext<DomEditSelectionValue | null>(null);
|
|
81
|
+
|
|
82
|
+
export function useDomEditActionsContext(): DomEditActionsValue {
|
|
83
|
+
const ctx = useContext(DomEditActionsContext);
|
|
84
|
+
if (!ctx) throw new Error("useDomEditActionsContext must be used within DomEditProvider");
|
|
85
|
+
return ctx;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function useDomEditSelectionContext(): DomEditSelectionValue {
|
|
89
|
+
const ctx = useContext(DomEditSelectionContext);
|
|
90
|
+
if (!ctx) throw new Error("useDomEditSelectionContext must be used within DomEditProvider");
|
|
12
91
|
return ctx;
|
|
13
92
|
}
|
|
14
93
|
|
|
94
|
+
/** @deprecated Prefer useDomEditActionsContext or useDomEditSelectionContext. */
|
|
95
|
+
export function useDomEditContext(): DomEditValue {
|
|
96
|
+
return { ...useDomEditActionsContext(), ...useDomEditSelectionContext() };
|
|
97
|
+
}
|
|
98
|
+
|
|
15
99
|
export function DomEditProvider({
|
|
16
100
|
value: {
|
|
17
101
|
domEditSelection,
|
|
@@ -85,16 +169,16 @@ export function DomEditProvider({
|
|
|
85
169
|
value: DomEditValue;
|
|
86
170
|
children: ReactNode;
|
|
87
171
|
}) {
|
|
88
|
-
const
|
|
172
|
+
const commitMutationRef = useRef(commitMutation);
|
|
173
|
+
commitMutationRef.current = commitMutation;
|
|
174
|
+
|
|
175
|
+
const stableCommitMutation = useCallback<DomEditActionsValue["commitMutation"]>(
|
|
176
|
+
(mutation, options) => commitMutationRef.current(mutation, options),
|
|
177
|
+
[],
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const actions = useMemo<DomEditActionsValue>(
|
|
89
181
|
() => ({
|
|
90
|
-
domEditSelection,
|
|
91
|
-
domEditGroupSelections,
|
|
92
|
-
domEditHoverSelection,
|
|
93
|
-
agentModalOpen,
|
|
94
|
-
agentModalAnchorPoint,
|
|
95
|
-
copiedAgentPrompt,
|
|
96
|
-
agentPromptSelectionContext,
|
|
97
|
-
domEditSelectionRef,
|
|
98
182
|
handleTimelineElementSelect,
|
|
99
183
|
handlePreviewCanvasMouseDown,
|
|
100
184
|
handlePreviewCanvasPointerMove,
|
|
@@ -126,9 +210,6 @@ export function DomEditProvider({
|
|
|
126
210
|
setAgentModalOpen,
|
|
127
211
|
setAgentPromptSelectionContext,
|
|
128
212
|
setAgentModalAnchorPoint,
|
|
129
|
-
selectedGsapAnimations,
|
|
130
|
-
gsapMultipleTimelines,
|
|
131
|
-
gsapUnsupportedTimelinePattern,
|
|
132
213
|
handleGsapUpdateProperty,
|
|
133
214
|
handleGsapUpdateMeta,
|
|
134
215
|
handleGsapDeleteAnimation,
|
|
@@ -150,17 +231,9 @@ export function DomEditProvider({
|
|
|
150
231
|
handleUpdateArcSegment,
|
|
151
232
|
invalidateGsapCache,
|
|
152
233
|
previewIframeRef,
|
|
153
|
-
commitMutation,
|
|
234
|
+
commitMutation: stableCommitMutation,
|
|
154
235
|
}),
|
|
155
236
|
[
|
|
156
|
-
domEditSelection,
|
|
157
|
-
domEditGroupSelections,
|
|
158
|
-
domEditHoverSelection,
|
|
159
|
-
agentModalOpen,
|
|
160
|
-
agentModalAnchorPoint,
|
|
161
|
-
copiedAgentPrompt,
|
|
162
|
-
agentPromptSelectionContext,
|
|
163
|
-
domEditSelectionRef,
|
|
164
237
|
handleTimelineElementSelect,
|
|
165
238
|
handlePreviewCanvasMouseDown,
|
|
166
239
|
handlePreviewCanvasPointerMove,
|
|
@@ -192,9 +265,6 @@ export function DomEditProvider({
|
|
|
192
265
|
setAgentModalOpen,
|
|
193
266
|
setAgentPromptSelectionContext,
|
|
194
267
|
setAgentModalAnchorPoint,
|
|
195
|
-
selectedGsapAnimations,
|
|
196
|
-
gsapMultipleTimelines,
|
|
197
|
-
gsapUnsupportedTimelinePattern,
|
|
198
268
|
handleGsapUpdateProperty,
|
|
199
269
|
handleGsapUpdateMeta,
|
|
200
270
|
handleGsapDeleteAnimation,
|
|
@@ -216,8 +286,41 @@ export function DomEditProvider({
|
|
|
216
286
|
handleUpdateArcSegment,
|
|
217
287
|
invalidateGsapCache,
|
|
218
288
|
previewIframeRef,
|
|
219
|
-
|
|
289
|
+
stableCommitMutation,
|
|
220
290
|
],
|
|
221
291
|
);
|
|
222
|
-
|
|
292
|
+
|
|
293
|
+
const selection = useMemo<DomEditSelectionValue>(
|
|
294
|
+
() => ({
|
|
295
|
+
domEditSelection,
|
|
296
|
+
domEditGroupSelections,
|
|
297
|
+
domEditHoverSelection,
|
|
298
|
+
domEditSelectionRef,
|
|
299
|
+
selectedGsapAnimations,
|
|
300
|
+
gsapMultipleTimelines,
|
|
301
|
+
gsapUnsupportedTimelinePattern,
|
|
302
|
+
agentModalOpen,
|
|
303
|
+
agentModalAnchorPoint,
|
|
304
|
+
copiedAgentPrompt,
|
|
305
|
+
agentPromptSelectionContext,
|
|
306
|
+
}),
|
|
307
|
+
[
|
|
308
|
+
domEditSelection,
|
|
309
|
+
domEditGroupSelections,
|
|
310
|
+
domEditHoverSelection,
|
|
311
|
+
domEditSelectionRef,
|
|
312
|
+
selectedGsapAnimations,
|
|
313
|
+
gsapMultipleTimelines,
|
|
314
|
+
gsapUnsupportedTimelinePattern,
|
|
315
|
+
agentModalOpen,
|
|
316
|
+
agentModalAnchorPoint,
|
|
317
|
+
copiedAgentPrompt,
|
|
318
|
+
agentPromptSelectionContext,
|
|
319
|
+
],
|
|
320
|
+
);
|
|
321
|
+
return (
|
|
322
|
+
<DomEditActionsContext value={actions}>
|
|
323
|
+
<DomEditSelectionContext value={selection}>{children}</DomEditSelectionContext>
|
|
324
|
+
</DomEditActionsContext>
|
|
325
|
+
);
|
|
223
326
|
}
|