@hyperframes/studio 0.7.54 → 0.7.56
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/{index-uBY329wb.js → index-BWnOxAiH.js} +1 -1
- package/dist/assets/{index-CMHYjEZ5.js → index-C4csZims.js} +1 -1
- package/dist/assets/index-CmVCjZjp.js +423 -0
- package/dist/assets/index-D-GyYi2d.css +1 -0
- package/dist/{chunk-SOTCF4DF.js → chunk-5QSIMBEJ.js} +2 -1
- package/dist/chunk-5QSIMBEJ.js.map +1 -0
- package/dist/{domEditingLayers-2ECJK24D.js → domEditingLayers-6LQGKPOI.js} +2 -2
- package/dist/index.d.ts +146 -144
- package/dist/index.html +2 -2
- package/dist/index.js +40582 -37803
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/App.tsx +106 -96
- package/src/components/EditorShell.tsx +253 -0
- package/src/components/StudioGlobalDragOverlay.tsx +1 -3
- package/src/components/StudioLeftSidebar.tsx +13 -3
- package/src/components/StudioRightPanel.tsx +8 -3
- package/src/components/TimelineToolbar.test.tsx +2 -2
- package/src/components/TimelineToolbar.tsx +179 -121
- package/src/components/editor/CanvasContextMenu.test.tsx +115 -0
- package/src/components/editor/CanvasContextMenu.tsx +198 -0
- package/src/components/editor/DomEditCropHandles.test.tsx +74 -3
- package/src/components/editor/DomEditCropHandles.tsx +64 -29
- package/src/components/editor/DomEditOverlay.test.ts +245 -279
- package/src/components/editor/DomEditOverlay.tsx +158 -126
- package/src/components/editor/DomEditOverlayHover.test.tsx +90 -0
- package/src/components/editor/DomEditRotateHandle.tsx +38 -18
- package/src/components/editor/DomEditSelectionChrome.test.tsx +80 -0
- package/src/components/editor/DomEditSelectionChrome.tsx +257 -0
- package/src/components/editor/LayersPanel.test.ts +66 -2
- package/src/components/editor/LayersPanel.tsx +43 -1
- package/src/components/editor/OffCanvasIndicators.test.tsx +34 -0
- package/src/components/editor/OffCanvasIndicators.tsx +49 -10
- package/src/components/editor/SnapGuideOverlay.tsx +28 -23
- package/src/components/editor/SnapToolbar.test.tsx +0 -1
- package/src/components/editor/anchoredResizeCommitFeedsOffset.test.ts +214 -0
- package/src/components/editor/anchoredResizeReleaseShift.test.ts +208 -0
- package/src/components/editor/canvasContextMenuZOrder.test.ts +435 -0
- package/src/components/editor/canvasContextMenuZOrder.ts +352 -0
- package/src/components/editor/domEditNudge.test.ts +80 -0
- package/src/components/editor/domEditNudge.ts +44 -0
- package/src/components/editor/domEditOverlayGeometry.test.ts +167 -1
- package/src/components/editor/domEditOverlayGeometry.ts +280 -20
- package/src/components/editor/domEditOverlayGestures.ts +44 -41
- package/src/components/editor/domEditOverlayStartGesture.ts +62 -2
- package/src/components/editor/domEditResizeLocal.test.ts +131 -0
- package/src/components/editor/domEditResizeLocal.ts +125 -0
- package/src/components/editor/domEditingDom.ts +1 -1
- package/src/components/editor/manualEditsDomPatches.test.ts +47 -0
- package/src/components/editor/manualOffsetDrag.ts +55 -12
- package/src/components/editor/offCanvasIndicatorGeometry.ts +31 -10
- package/src/components/editor/offCanvasIndicatorRefresh.test.tsx +25 -1
- package/src/components/editor/resizeDraft.ts +108 -0
- package/src/components/editor/snapEngine.test.ts +12 -78
- package/src/components/editor/snapEngine.ts +13 -53
- package/src/components/editor/useDomEditNudge.test.tsx +228 -0
- package/src/components/editor/useDomEditNudge.ts +254 -0
- package/src/components/editor/useDomEditOverlayGestures.ts +115 -116
- package/src/components/editor/useDomEditOverlayRects.ts +9 -2
- package/src/components/nle/AssetPreviewOverlay.tsx +147 -0
- package/src/components/nle/NLEContext.test.ts +144 -0
- package/src/components/nle/NLEContext.tsx +328 -0
- package/src/components/nle/NLEPreview.tsx +1 -1
- package/src/components/nle/PreviewOverlays.tsx +240 -0
- package/src/components/nle/PreviewPane.tsx +163 -0
- package/src/components/nle/TimelinePane.test.ts +60 -0
- package/src/components/nle/TimelinePane.tsx +293 -0
- package/src/components/nle/TimelineResizeDivider.tsx +8 -2
- package/src/components/nle/useCompositionStack.test.tsx +44 -0
- package/src/components/nle/useCompositionStack.ts +17 -9
- package/src/components/nle/useTimelineEditCallbacks.ts +217 -0
- package/src/components/sidebar/AssetCard.tsx +326 -0
- package/src/components/sidebar/AssetContextMenu.tsx +15 -30
- package/src/components/sidebar/AssetsTab.test.ts +96 -0
- package/src/components/sidebar/AssetsTab.tsx +71 -206
- package/src/components/sidebar/AudioRow.tsx +39 -2
- package/src/components/sidebar/BlocksTab.tsx +8 -1
- package/src/components/sidebar/LeftSidebar.tsx +4 -1
- package/src/components/sidebar/assetHelpers.ts +29 -0
- package/src/contexts/DomEditContext.tsx +9 -0
- package/src/contexts/StudioContext.tsx +9 -8
- package/src/contexts/TimelineEditContext.tsx +3 -7
- package/src/hooks/deleteSelectedKeyframes.ts +35 -0
- package/src/hooks/domEditCommitTypes.ts +12 -1
- package/src/hooks/domSelectionTestHarness.ts +14 -0
- package/src/hooks/gestureTransaction.test.ts +311 -0
- package/src/hooks/gestureTransaction.ts +199 -0
- package/src/hooks/gsapDragCommit.test.ts +141 -41
- package/src/hooks/gsapDragCommit.ts +64 -74
- package/src/hooks/gsapDragStaticSetHelpers.ts +9 -21
- package/src/hooks/gsapResizeIntercept.test.ts +69 -0
- package/src/hooks/gsapResizeIntercept.ts +38 -10
- package/src/hooks/gsapRuntimeBridge.test.ts +49 -13
- package/src/hooks/gsapRuntimeBridge.ts +4 -4
- package/src/hooks/gsapScriptCommitTypes.ts +16 -5
- package/src/hooks/gsapShared.test.ts +19 -1
- package/src/hooks/gsapShared.ts +14 -0
- package/src/hooks/patchDocumentRootDuration.test.ts +71 -0
- package/src/hooks/timelineEditingGsap.ts +14 -0
- package/src/hooks/timelineEditingHelpers.test.ts +34 -1
- package/src/hooks/timelineEditingHelpers.ts +22 -48
- package/src/hooks/timelineMoveAdapter.test.ts +77 -0
- package/src/hooks/timelineMoveAdapter.ts +37 -0
- package/src/hooks/useAnimatedPropertyCommit.test.tsx +36 -8
- package/src/hooks/useAnimatedPropertyCommit.ts +31 -26
- package/src/hooks/useAppHotkeys.ts +16 -25
- package/src/hooks/useBlockHandlers.ts +55 -27
- package/src/hooks/useContextMenuDismiss.ts +31 -7
- package/src/hooks/useDomEditCommits.test.tsx +154 -1
- package/src/hooks/useDomEditCommits.ts +100 -3
- package/src/hooks/useDomEditPositionPatchCommit.ts +2 -0
- package/src/hooks/useDomEditSession.ts +2 -2
- package/src/hooks/useDomEditTextCommits.test.tsx +135 -0
- package/src/hooks/useDomEditTextCommits.ts +8 -3
- package/src/hooks/useDomEditWiring.ts +7 -9
- package/src/hooks/useDomGeometryCommits.ts +17 -2
- package/src/hooks/useDomSelection.test.ts +2 -36
- package/src/hooks/useDomSelection.ts +81 -51
- package/src/hooks/useDomSelectionSelectionGuards.test.ts +276 -0
- package/src/hooks/useElementLifecycleOps.test.tsx +258 -0
- package/src/hooks/useElementLifecycleOps.ts +40 -71
- package/src/hooks/useEnableKeyframes.test.ts +142 -1
- package/src/hooks/useEnableKeyframes.ts +73 -29
- package/src/hooks/useGestureCommit.test.tsx +130 -0
- package/src/hooks/useGestureCommit.ts +32 -8
- package/src/hooks/useGroupCommits.ts +7 -28
- package/src/hooks/useGsapAwareEditing.test.tsx +239 -0
- package/src/hooks/useGsapAwareEditing.ts +115 -20
- package/src/hooks/useGsapKeyframeOps.test.tsx +59 -0
- package/src/hooks/useGsapKeyframeOps.ts +38 -10
- package/src/hooks/useGsapScriptCommits.test.tsx +40 -1
- package/src/hooks/useGsapScriptCommits.ts +134 -50
- package/src/hooks/useGsapSelectionHandlers.ts +49 -16
- package/src/hooks/useMusicBeatAnalysis.ts +72 -36
- package/src/hooks/usePersistentEditHistory.test.ts +33 -0
- package/src/hooks/usePersistentEditHistory.ts +92 -58
- package/src/hooks/usePreviewPersistence.ts +25 -7
- package/src/hooks/useRazorSplit.history.test.tsx +303 -0
- package/src/hooks/useRazorSplit.test.ts +269 -0
- package/src/hooks/useRazorSplit.testHelpers.ts +64 -0
- package/src/hooks/useRazorSplit.ts +107 -36
- package/src/hooks/useRenderClipContent.ts +24 -6
- package/src/hooks/useStudioContextValue.ts +15 -5
- package/src/hooks/useStudioUrlState.ts +2 -4
- package/src/hooks/useTimelineEditing.test.tsx +20 -29
- package/src/hooks/useTimelineEditingTypes.ts +6 -0
- package/src/hooks/useTimelineGroupEditing.ts +18 -4
- package/src/index.ts +1 -1
- package/src/player/components/ImageThumbnail.test.tsx +173 -0
- package/src/player/components/ImageThumbnail.tsx +160 -0
- package/src/player/components/PlayheadIndicator.tsx +50 -5
- package/src/player/components/Timeline.test.ts +102 -19
- package/src/player/components/Timeline.tsx +194 -194
- package/src/player/components/TimelineCanvas.tsx +207 -521
- package/src/player/components/TimelineClip.tsx +4 -1
- package/src/player/components/TimelineClipDiamonds.tsx +9 -40
- package/src/player/components/TimelineEmptyState.tsx +3 -1
- package/src/player/components/TimelineLanes.tsx +487 -0
- package/src/player/components/TimelineOverlays.tsx +122 -0
- package/src/player/components/VideoThumbnail.test.tsx +152 -0
- package/src/player/components/VideoThumbnail.tsx +28 -7
- package/src/player/components/thumbnailUtils.test.ts +127 -0
- package/src/player/components/thumbnailUtils.ts +54 -0
- package/src/player/components/timelineCallbacks.ts +18 -18
- package/src/player/components/timelineClipChildren.tsx +39 -0
- package/src/player/components/timelineClipDragCommit.test.ts +943 -0
- package/src/player/components/timelineClipDragCommit.ts +401 -0
- package/src/player/components/timelineClipDragPreview.test.ts +144 -0
- package/src/player/components/timelineClipDragPreview.ts +323 -38
- package/src/player/components/timelineClipDragTypes.ts +65 -0
- package/src/player/components/timelineCollision.test.ts +477 -0
- package/src/player/components/timelineCollision.ts +263 -0
- package/src/player/components/timelineDragDrop.ts +69 -60
- package/src/player/components/timelineEditCapabilities.ts +52 -0
- package/src/player/components/timelineEditing.test.ts +1 -1
- package/src/player/components/timelineEditing.ts +76 -59
- package/src/player/components/timelineGroupEditing.test.ts +126 -0
- package/src/player/components/timelineGroupEditing.ts +133 -0
- package/src/player/components/timelineGroupResizeCommit.ts +54 -0
- package/src/player/components/timelineLayout.test.ts +95 -23
- package/src/player/components/timelineLayout.ts +120 -61
- package/src/player/components/timelineMarquee.test.ts +197 -0
- package/src/player/components/timelineMarquee.ts +112 -0
- package/src/player/components/timelineMultiDragPreview.test.ts +127 -0
- package/src/player/components/timelineMultiDragPreview.ts +106 -0
- package/src/player/components/timelineOptimisticRevision.ts +42 -0
- package/src/player/components/timelineSnapping.test.ts +134 -0
- package/src/player/components/timelineSnapping.ts +110 -0
- package/src/player/components/timelineStackingSync.test.ts +244 -0
- package/src/player/components/timelineStackingSync.ts +331 -0
- package/src/player/components/timelineTheme.ts +6 -1
- package/src/player/components/timelineZones.test.ts +425 -0
- package/src/player/components/timelineZones.ts +198 -0
- package/src/player/components/timelineZoom.test.ts +67 -0
- package/src/player/components/timelineZoom.ts +51 -0
- package/src/player/components/useResolvedTimelineEditCallbacks.ts +25 -3
- package/src/player/components/useTimelineClipDrag.resize.test.tsx +241 -0
- package/src/player/components/useTimelineClipDrag.ts +380 -386
- package/src/player/components/useTimelineEditPinning.ts +121 -0
- package/src/player/components/useTimelineGeometry.ts +129 -0
- package/src/player/components/useTimelinePlayhead.ts +4 -16
- package/src/player/components/useTimelineRangeSelection.ts +341 -50
- package/src/player/components/useTimelineStackingSync.test.tsx +67 -0
- package/src/player/components/useTimelineStackingSync.ts +83 -0
- package/src/player/hooks/useExpandedTimelineElements.ts +0 -3
- package/src/player/hooks/usePlaybackKeyboard.ts +5 -0
- package/src/player/hooks/useTimelinePlayer.ts +48 -53
- package/src/player/hooks/useTimelinePlayerLoop.ts +85 -0
- package/src/player/hooks/useTimelineSyncCallbacks.test.ts +219 -0
- package/src/player/hooks/useTimelineSyncCallbacks.ts +104 -4
- package/src/player/index.ts +3 -2
- package/src/player/lib/time.test.ts +19 -19
- package/src/player/lib/time.ts +6 -2
- package/src/player/lib/timelineDOM.test.ts +25 -98
- package/src/player/lib/timelineDOM.ts +12 -81
- package/src/player/lib/timelineElementHelpers.ts +54 -5
- package/src/player/lib/timelineIframeHelpers.ts +2 -0
- package/src/player/store/playerStore.ts +62 -3
- package/src/styles/studio.css +27 -0
- package/src/utils/assetClickBehavior.test.ts +104 -0
- package/src/utils/assetClickBehavior.ts +75 -0
- package/src/utils/assetPreviewStore.ts +33 -0
- package/src/utils/blockInstaller.ts +10 -2
- package/src/utils/canvasNudgeGate.test.ts +31 -0
- package/src/utils/canvasNudgeGate.ts +32 -0
- package/src/utils/editHistory.test.ts +35 -0
- package/src/utils/gsapSoftReload.test.ts +119 -1
- package/src/utils/gsapSoftReload.ts +153 -0
- package/src/utils/mediaTypes.ts +3 -2
- package/src/utils/resizeDebug.ts +55 -0
- package/src/utils/rootDuration.test.ts +90 -1
- package/src/utils/rootDuration.ts +76 -13
- package/src/utils/sdkCutover.ts +4 -0
- package/src/utils/studioFileHistory.ts +37 -7
- package/src/utils/studioHelpers.ts +62 -0
- package/src/utils/studioPreviewHelpers.test.ts +65 -8
- package/src/utils/studioPreviewHelpers.ts +10 -0
- package/src/utils/studioTelemetry.ts +4 -1
- package/src/utils/studioUiPreferences.test.ts +38 -0
- package/src/utils/studioUiPreferences.ts +27 -0
- package/src/utils/studioUrlState.test.ts +0 -1
- package/src/utils/timelineAssetDrop.ts +62 -0
- package/src/utils/timelineDiscovery.ts +0 -17
- package/src/utils/timelineInspector.test.ts +121 -0
- package/src/utils/timelineInspector.ts +32 -1
- package/dist/assets/index-Dq7FEg0K.css +0 -1
- package/dist/assets/index-pRhCpGPz.js +0 -423
- package/dist/chunk-SOTCF4DF.js.map +0 -1
- package/src/components/StudioPreviewArea.tsx +0 -500
- package/src/components/nle/NLELayout.test.ts +0 -12
- package/src/components/nle/NLELayout.tsx +0 -591
- package/src/player/components/TimelineLayerGutter.tsx +0 -61
- package/src/player/components/TimelineSelectionOverlays.tsx +0 -55
- package/src/player/components/timelineMarqueeSelection.test.ts +0 -87
- package/src/player/components/timelineSnapTargets.test.ts +0 -144
- package/src/player/components/timelineSnapTargets.ts +0 -164
- package/src/player/components/useTimelineClipDrag.test.tsx +0 -506
- package/src/player/components/useTimelineClipGroupDrag.ts +0 -417
- package/src/player/components/useTimelineMarqueeSelection.test.tsx +0 -231
- package/src/player/components/useTimelineMarqueeSelection.ts +0 -276
- package/src/utils/timelineDiscovery.test.ts +0 -90
- /package/dist/{domEditingLayers-2ECJK24D.js.map → domEditingLayers-6LQGKPOI.js.map} +0 -0
|
@@ -5,39 +5,31 @@ import { remapBeatAnalysisToComposition } from "../../utils/beatEditActions";
|
|
|
5
5
|
import { usePlayerStore, type TimelineElement } from "../store/playerStore";
|
|
6
6
|
import { useExpandedTimelineElements } from "../hooks/useExpandedTimelineElements";
|
|
7
7
|
import { useMountEffect } from "../../hooks/useMountEffect";
|
|
8
|
-
import { EditPopover } from "./EditModal";
|
|
9
8
|
import { defaultTimelineTheme } from "./timelineTheme";
|
|
10
9
|
import { useTimelineRangeSelection } from "./useTimelineRangeSelection";
|
|
11
|
-
import { useTimelineMarqueeSelection } from "./useTimelineMarqueeSelection";
|
|
12
10
|
import { useTimelinePlayhead } from "./useTimelinePlayhead";
|
|
13
11
|
import { useTimelineActiveClips } from "./useTimelineActiveClips";
|
|
14
12
|
import { type TrackVisualStyle, getTrackStyle } from "./timelineIcons";
|
|
15
|
-
import { getTimelinePixelsPerSecond } from "./timelineZoom";
|
|
16
13
|
import { useTimelineZoom } from "./useTimelineZoom";
|
|
17
14
|
import { useTimelineAssetDrop } from "./timelineDragDrop";
|
|
18
15
|
import { TimelineEmptyState } from "./TimelineEmptyState";
|
|
19
16
|
import { TimelineCanvas } from "./TimelineCanvas";
|
|
20
|
-
import {
|
|
21
|
-
KeyframeDiamondContextMenu,
|
|
22
|
-
type KeyframeDiamondContextMenuState,
|
|
23
|
-
} from "./KeyframeDiamondContextMenu";
|
|
17
|
+
import { type KeyframeDiamondContextMenuState } from "./KeyframeDiamondContextMenu";
|
|
24
18
|
import { useTimelineClipDrag } from "./useTimelineClipDrag";
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import { getTimelineLayerGroupHeaderTotalHeight } from "./TimelineLayerGroupHeader";
|
|
19
|
+
import { TimelineOverlays } from "./TimelineOverlays";
|
|
20
|
+
import { useTimelineEditPinning } from "./useTimelineEditPinning";
|
|
21
|
+
import { useTimelineStackingSync } from "./useTimelineStackingSync";
|
|
22
|
+
import { useTimelineGeometry } from "./useTimelineGeometry";
|
|
30
23
|
import {
|
|
31
24
|
GUTTER,
|
|
32
|
-
|
|
25
|
+
generateTicks,
|
|
33
26
|
getTimelineCanvasHeight,
|
|
34
27
|
shouldShowTimelineShortcutHint,
|
|
35
|
-
computeTimelineBasisDuration,
|
|
36
|
-
computeTimelineEffectiveDuration,
|
|
37
28
|
} from "./timelineLayout";
|
|
38
29
|
import { useResolvedTimelineEditCallbacks } from "./useResolvedTimelineEditCallbacks";
|
|
39
30
|
import type { TimelineProps } from "./TimelineTypes";
|
|
40
31
|
|
|
32
|
+
// Re-export pure utilities so existing imports from "./Timeline" still resolve.
|
|
41
33
|
export {
|
|
42
34
|
generateTicks,
|
|
43
35
|
formatTimelineTickLabel,
|
|
@@ -62,7 +54,9 @@ export const Timeline = memo(function Timeline({
|
|
|
62
54
|
onBlockDrop,
|
|
63
55
|
onDeleteElement: _onDeleteElement,
|
|
64
56
|
onMoveElement: onMoveElementOverride,
|
|
57
|
+
onMoveElements: onMoveElementsOverride,
|
|
65
58
|
onResizeElement: onResizeElementOverride,
|
|
59
|
+
onResizeElements: onResizeElementsOverride,
|
|
66
60
|
onBlockedEditAttempt: onBlockedEditAttemptOverride,
|
|
67
61
|
onSplitElement: onSplitElementOverride,
|
|
68
62
|
onSelectElement,
|
|
@@ -70,11 +64,9 @@ export const Timeline = memo(function Timeline({
|
|
|
70
64
|
}: TimelineProps = {}) {
|
|
71
65
|
const {
|
|
72
66
|
onMoveElement,
|
|
73
|
-
onResizeElement,
|
|
74
67
|
onMoveElements,
|
|
68
|
+
onResizeElement,
|
|
75
69
|
onResizeElements,
|
|
76
|
-
onPreviewMoveElements,
|
|
77
|
-
onPreviewResizeElements,
|
|
78
70
|
onBlockedEditAttempt,
|
|
79
71
|
onSplitElement,
|
|
80
72
|
onRazorSplitAll,
|
|
@@ -85,7 +77,9 @@ export const Timeline = memo(function Timeline({
|
|
|
85
77
|
onMoveKeyframe,
|
|
86
78
|
} = useResolvedTimelineEditCallbacks({
|
|
87
79
|
onMoveElement: onMoveElementOverride,
|
|
80
|
+
onMoveElements: onMoveElementsOverride,
|
|
88
81
|
onResizeElement: onResizeElementOverride,
|
|
82
|
+
onResizeElements: onResizeElementsOverride,
|
|
89
83
|
onBlockedEditAttempt: onBlockedEditAttemptOverride,
|
|
90
84
|
onSplitElement: onSplitElementOverride,
|
|
91
85
|
});
|
|
@@ -103,17 +97,20 @@ export const Timeline = memo(function Timeline({
|
|
|
103
97
|
const duration = usePlayerStore((s) => s.duration);
|
|
104
98
|
const timelineReady = usePlayerStore((s) => s.timelineReady);
|
|
105
99
|
const selectedElementId = usePlayerStore((s) => s.selectedElementId);
|
|
100
|
+
const selectedElementIds = usePlayerStore((s) => s.selectedElementIds);
|
|
106
101
|
const setSelectedElementId = usePlayerStore((s) => s.setSelectedElementId);
|
|
107
102
|
const currentTime = usePlayerStore((s) => s.currentTime);
|
|
108
103
|
const { zoomMode, manualZoomPercent, setZoomMode, setManualZoomPercent } = useTimelineZoom();
|
|
109
104
|
|
|
110
105
|
const playheadRef = useRef<HTMLDivElement>(null);
|
|
106
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
111
107
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
112
108
|
const activeTool = usePlayerStore((s) => s.activeTool);
|
|
113
109
|
const [hoveredClip, setHoveredClip] = useState<string | null>(null);
|
|
114
110
|
const isDragging = useRef(false);
|
|
115
111
|
const [shiftHeld, setShiftHeld] = useState(false);
|
|
116
112
|
const [razorGuideX, setRazorGuideX] = useState<number | null>(null);
|
|
113
|
+
|
|
117
114
|
useMountEffect(() => {
|
|
118
115
|
const down = (e: KeyboardEvent) => e.key === "Shift" && setShiftHeld(true);
|
|
119
116
|
const up = (e: KeyboardEvent) => e.key === "Shift" && setShiftHeld(false);
|
|
@@ -139,6 +136,7 @@ export const Timeline = memo(function Timeline({
|
|
|
139
136
|
const [viewportWidth, setViewportWidth] = useState(0);
|
|
140
137
|
const roRef = useRef<ResizeObserver | null>(null);
|
|
141
138
|
const shortcutHintRafRef = useRef(0);
|
|
139
|
+
|
|
142
140
|
const syncShortcutHintVisibility = useCallback(() => {
|
|
143
141
|
const scroll = scrollRef.current;
|
|
144
142
|
setShowShortcutHint(
|
|
@@ -154,6 +152,16 @@ export const Timeline = memo(function Timeline({
|
|
|
154
152
|
});
|
|
155
153
|
}, [syncShortcutHintVisibility]);
|
|
156
154
|
|
|
155
|
+
const setContainerRef = useCallback((el: HTMLDivElement | null) => {
|
|
156
|
+
containerRef.current = el;
|
|
157
|
+
}, []);
|
|
158
|
+
|
|
159
|
+
// Last horizontal scroll offset, tracked so it can be RESTORED across the
|
|
160
|
+
// post-edit iframe reload: an edit re-derives elements (and may shrink the
|
|
161
|
+
// content width), which the browser clamps into a scroll jump. Paired with the
|
|
162
|
+
// pinned zoom (which keeps pps constant so the pixel offset stays meaningful),
|
|
163
|
+
// restoring this keeps the user parked at the same spot after any edit.
|
|
164
|
+
const lastScrollLeftRef = useRef(0);
|
|
157
165
|
const setScrollRef = useCallback(
|
|
158
166
|
(el: HTMLDivElement | null) => {
|
|
159
167
|
if (roRef.current) {
|
|
@@ -180,31 +188,70 @@ export const Timeline = memo(function Timeline({
|
|
|
180
188
|
if (shortcutHintRafRef.current) cancelAnimationFrame(shortcutHintRafRef.current);
|
|
181
189
|
});
|
|
182
190
|
|
|
183
|
-
const
|
|
184
|
-
()
|
|
185
|
-
|
|
186
|
-
|
|
191
|
+
const effectiveDuration = useMemo(() => {
|
|
192
|
+
const safeDur = Number.isFinite(duration) ? duration : 0;
|
|
193
|
+
if (rawElements.length === 0) return safeDur;
|
|
194
|
+
const maxEnd = Math.max(...rawElements.map((el) => el.start + el.duration));
|
|
195
|
+
const result = Math.max(safeDur, maxEnd);
|
|
196
|
+
return Number.isFinite(result) ? result : safeDur;
|
|
197
|
+
}, [rawElements, duration]);
|
|
198
|
+
|
|
199
|
+
const tracks = useMemo(() => {
|
|
200
|
+
const map = new Map<number, typeof expandedElements>();
|
|
201
|
+
for (const el of expandedElements) {
|
|
202
|
+
const list = map.get(el.track) ?? [];
|
|
203
|
+
list.push(el);
|
|
204
|
+
map.set(el.track, list);
|
|
205
|
+
}
|
|
206
|
+
return Array.from(map.entries()).sort(([a], [b]) => a - b);
|
|
207
|
+
}, [expandedElements]);
|
|
187
208
|
|
|
188
209
|
const trackStyles = useMemo(() => {
|
|
189
|
-
const map = new Map<
|
|
190
|
-
for (const
|
|
191
|
-
map.set(
|
|
210
|
+
const map = new Map<number, TrackVisualStyle>();
|
|
211
|
+
for (const [trackNum, els] of tracks) {
|
|
212
|
+
map.set(trackNum, getTrackStyle(els[0]?.tag ?? ""));
|
|
192
213
|
}
|
|
193
214
|
return map;
|
|
194
215
|
}, [tracks]);
|
|
195
216
|
|
|
196
|
-
const trackOrder = useMemo(() => tracks.map((
|
|
217
|
+
const trackOrder = useMemo(() => tracks.map(([trackNum]) => trackNum), [tracks]);
|
|
197
218
|
const trackOrderRef = useRef(trackOrder);
|
|
198
219
|
trackOrderRef.current = trackOrder;
|
|
199
|
-
const timelineLayersRef = useRef(tracks);
|
|
200
|
-
timelineLayersRef.current = tracks;
|
|
201
220
|
const expandedElementsRef = useRef(expandedElements);
|
|
202
221
|
expandedElementsRef.current = expandedElements;
|
|
203
222
|
|
|
204
223
|
const ppsRef = useRef(100);
|
|
205
|
-
const durationRef = useRef(
|
|
224
|
+
const durationRef = useRef(effectiveDuration);
|
|
225
|
+
durationRef.current = effectiveDuration;
|
|
226
|
+
// Declared here (used before the fitPps derivation below) so the edit-pin
|
|
227
|
+
// wrappers can close over it; `fitPpsRef.current` is refreshed each render.
|
|
228
|
+
const fitPpsRef = useRef(100);
|
|
206
229
|
|
|
207
|
-
const
|
|
230
|
+
const {
|
|
231
|
+
pinZoomBeforeEdit,
|
|
232
|
+
setRangeSelectionRef,
|
|
233
|
+
pinnedOnMoveElement,
|
|
234
|
+
pinnedOnMoveElements,
|
|
235
|
+
pinnedOnResizeElement,
|
|
236
|
+
pinnedOnResizeElements,
|
|
237
|
+
pinnedOnFileDrop,
|
|
238
|
+
pinnedOnAssetDrop,
|
|
239
|
+
pinnedOnBlockDrop,
|
|
240
|
+
} = useTimelineEditPinning({
|
|
241
|
+
ppsRef,
|
|
242
|
+
fitPpsRef,
|
|
243
|
+
onMoveElement,
|
|
244
|
+
onMoveElements,
|
|
245
|
+
onResizeElement,
|
|
246
|
+
onResizeElements,
|
|
247
|
+
onFileDrop,
|
|
248
|
+
onAssetDrop,
|
|
249
|
+
onBlockDrop,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const { readClipZIndex, applyStackingPatches, zSyncEnabled } = useTimelineStackingSync({
|
|
253
|
+
expandedElementsRef,
|
|
254
|
+
});
|
|
208
255
|
|
|
209
256
|
const {
|
|
210
257
|
draggedClip,
|
|
@@ -217,67 +264,39 @@ export const Timeline = memo(function Timeline({
|
|
|
217
264
|
} = useTimelineClipDrag({
|
|
218
265
|
scrollRef,
|
|
219
266
|
ppsRef,
|
|
267
|
+
durationRef,
|
|
220
268
|
trackOrderRef,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
onMoveElements,
|
|
226
|
-
onResizeElements,
|
|
227
|
-
onPreviewMoveElements,
|
|
228
|
-
onPreviewResizeElements,
|
|
269
|
+
onMoveElement: pinnedOnMoveElement,
|
|
270
|
+
onMoveElements: pinnedOnMoveElements,
|
|
271
|
+
onResizeElement: pinnedOnResizeElement,
|
|
272
|
+
onResizeElements: pinnedOnResizeElements,
|
|
229
273
|
onBlockedEditAttempt,
|
|
230
274
|
setShowPopover,
|
|
231
275
|
setRangeSelectionRef,
|
|
276
|
+
readZIndex: zSyncEnabled ? readClipZIndex : undefined,
|
|
277
|
+
onStackingPatches: zSyncEnabled ? applyStackingPatches : undefined,
|
|
232
278
|
});
|
|
233
279
|
|
|
234
|
-
const
|
|
235
|
-
(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
computeTimelineEffectiveDuration(basisDuration, [
|
|
245
|
-
draggedClip?.started ? draggedClip.previewStart + draggedClip.element.duration : null,
|
|
246
|
-
resizingClip?.started ? resizingClip.previewStart + resizingClip.previewDuration : null,
|
|
247
|
-
]),
|
|
248
|
-
[basisDuration, draggedClip, resizingClip],
|
|
249
|
-
);
|
|
250
|
-
durationRef.current = effectiveDuration;
|
|
280
|
+
const { isDragOver, handleAssetDragOver, handleAssetDrop, clearDropPreview } =
|
|
281
|
+
useTimelineAssetDrop({
|
|
282
|
+
scrollRef,
|
|
283
|
+
ppsRef,
|
|
284
|
+
durationRef,
|
|
285
|
+
trackOrderRef,
|
|
286
|
+
onFileDrop: pinnedOnFileDrop,
|
|
287
|
+
onAssetDrop: pinnedOnAssetDrop,
|
|
288
|
+
onBlockDrop: pinnedOnBlockDrop,
|
|
289
|
+
});
|
|
251
290
|
|
|
252
291
|
const displayTrackOrder = useMemo(() => {
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
trackOrder.length === 0 ||
|
|
256
|
-
trackOrder.includes(draggedClip.previewLayerId)
|
|
257
|
-
)
|
|
258
|
-
return trackOrder;
|
|
259
|
-
return insertPreviewTrackOrder(
|
|
260
|
-
trackOrder,
|
|
261
|
-
draggedClip.previewLayerId,
|
|
262
|
-
draggedClip.previewLayerIndex,
|
|
263
|
-
);
|
|
292
|
+
if (!draggedClip?.started || trackOrder.includes(draggedClip.previewTrack)) return trackOrder;
|
|
293
|
+
return [...trackOrder, draggedClip.previewTrack].sort((a, b) => a - b);
|
|
264
294
|
}, [draggedClip, trackOrder]);
|
|
265
295
|
|
|
266
|
-
const totalH =
|
|
267
|
-
getTimelineCanvasHeight(displayTrackOrder.length) +
|
|
268
|
-
getTimelineLayerGroupHeaderTotalHeight(displayTrackOrder, tracks);
|
|
296
|
+
const totalH = getTimelineCanvasHeight(displayTrackOrder.length);
|
|
269
297
|
const keyframeCache = usePlayerStore((s) => s.keyframeCache);
|
|
270
298
|
const selectedKeyframes = usePlayerStore((s) => s.selectedKeyframes);
|
|
271
299
|
const toggleSelectedKeyframe = usePlayerStore((s) => s.toggleSelectedKeyframe);
|
|
272
|
-
const keyframeHandlers = useTimelineKeyframeHandlers({
|
|
273
|
-
expandedElements,
|
|
274
|
-
keyframeCache,
|
|
275
|
-
onSelectElement,
|
|
276
|
-
onSeek,
|
|
277
|
-
setSelectedElementId,
|
|
278
|
-
setKfContextMenu,
|
|
279
|
-
toggleSelectedKeyframe,
|
|
280
|
-
});
|
|
281
300
|
|
|
282
301
|
const selectedElement = useMemo(
|
|
283
302
|
() =>
|
|
@@ -287,26 +306,28 @@ export const Timeline = memo(function Timeline({
|
|
|
287
306
|
const selectedElementRef = useRef<TimelineElement | null>(selectedElement);
|
|
288
307
|
selectedElementRef.current = selectedElement;
|
|
289
308
|
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
309
|
+
const {
|
|
310
|
+
pps,
|
|
311
|
+
fitPps,
|
|
312
|
+
displayContentWidth,
|
|
313
|
+
displayDuration,
|
|
314
|
+
clipStateVersion,
|
|
315
|
+
zoomModeRef,
|
|
316
|
+
manualZoomPercentRef,
|
|
317
|
+
} = useTimelineGeometry({
|
|
318
|
+
viewportWidth,
|
|
319
|
+
effectiveDuration,
|
|
320
|
+
zoomMode,
|
|
321
|
+
manualZoomPercent,
|
|
322
|
+
ppsRef,
|
|
323
|
+
fitPpsRef,
|
|
324
|
+
draggedClip,
|
|
325
|
+
resizingClip,
|
|
326
|
+
expandedElements,
|
|
327
|
+
isDragging,
|
|
328
|
+
scrollRef,
|
|
329
|
+
lastScrollLeftRef,
|
|
330
|
+
});
|
|
310
331
|
|
|
311
332
|
const { seekFromX, autoScrollDuringDrag, dragScrollRaf } = useTimelinePlayhead({
|
|
312
333
|
playheadRef,
|
|
@@ -339,6 +360,8 @@ export const Timeline = memo(function Timeline({
|
|
|
339
360
|
rangeSelection,
|
|
340
361
|
setRangeSelection,
|
|
341
362
|
shiftClickClipRef,
|
|
363
|
+
marqueeRect,
|
|
364
|
+
isScrubbing,
|
|
342
365
|
handlePointerDown,
|
|
343
366
|
handlePointerMove,
|
|
344
367
|
handlePointerUp,
|
|
@@ -353,28 +376,12 @@ export const Timeline = memo(function Timeline({
|
|
|
353
376
|
dragScrollRaf,
|
|
354
377
|
isDragging,
|
|
355
378
|
setShowPopover,
|
|
356
|
-
|
|
357
|
-
const {
|
|
358
|
-
marqueeRect,
|
|
359
|
-
handlePointerDown: handleMarqueePointerDown,
|
|
360
|
-
handlePointerMove: handleMarqueePointerMove,
|
|
361
|
-
handlePointerUp: handleMarqueePointerUp,
|
|
362
|
-
} = useTimelineMarqueeSelection({
|
|
363
|
-
scrollRef,
|
|
364
|
-
ppsRef,
|
|
379
|
+
elementsRef: expandedElementsRef,
|
|
365
380
|
trackOrderRef,
|
|
366
|
-
|
|
367
|
-
disabled: activeTool === "razor",
|
|
368
|
-
setShowPopover,
|
|
369
|
-
setRangeSelectionRef,
|
|
370
|
-
seekFromX,
|
|
381
|
+
onSelectElement,
|
|
371
382
|
});
|
|
383
|
+
// Wire setRangeSelection into the stable ref consumed by useTimelineClipDrag
|
|
372
384
|
setRangeSelectionRef.current = setRangeSelection;
|
|
373
|
-
// Pointer-up and lost-capture end a gesture identically (marquee-claims-first).
|
|
374
|
-
const releasePointer = (event: Parameters<typeof handleMarqueePointerUp>[0]) => {
|
|
375
|
-
if (handleMarqueePointerUp(event)) return;
|
|
376
|
-
handlePointerUp();
|
|
377
|
-
};
|
|
378
385
|
|
|
379
386
|
const prevSelectedRef = useRef(selectedElementRef.current);
|
|
380
387
|
// eslint-disable-next-line no-restricted-syntax, react-hooks/exhaustive-deps
|
|
@@ -389,8 +396,8 @@ export const Timeline = memo(function Timeline({
|
|
|
389
396
|
});
|
|
390
397
|
|
|
391
398
|
const { major, minor } = useMemo(
|
|
392
|
-
() =>
|
|
393
|
-
[
|
|
399
|
+
() => generateTicks(displayDuration, pps),
|
|
400
|
+
[displayDuration, pps],
|
|
394
401
|
);
|
|
395
402
|
const majorTickInterval = major.length >= 2 ? major[1] - major[0] : effectiveDuration;
|
|
396
403
|
|
|
@@ -416,24 +423,13 @@ export const Timeline = memo(function Timeline({
|
|
|
416
423
|
[resizingClip],
|
|
417
424
|
);
|
|
418
425
|
|
|
419
|
-
const { isDragOver, setIsDragOver, handleAssetDragOver, handleAssetDrop } = useTimelineAssetDrop({
|
|
420
|
-
scrollRef,
|
|
421
|
-
ppsRef,
|
|
422
|
-
durationRef,
|
|
423
|
-
trackOrderRef,
|
|
424
|
-
timelineLayersRef,
|
|
425
|
-
onFileDrop,
|
|
426
|
-
onAssetDrop,
|
|
427
|
-
onBlockDrop,
|
|
428
|
-
});
|
|
429
|
-
|
|
430
426
|
if (!timelineReady || expandedElements.length === 0) {
|
|
431
427
|
return (
|
|
432
428
|
<TimelineEmptyState
|
|
433
429
|
isDragOver={isDragOver}
|
|
434
430
|
onFileDrop={!!onFileDrop}
|
|
435
431
|
onDragOver={handleAssetDragOver}
|
|
436
|
-
onDragLeave={() =>
|
|
432
|
+
onDragLeave={() => clearDropPreview()}
|
|
437
433
|
onDrop={handleAssetDrop}
|
|
438
434
|
/>
|
|
439
435
|
);
|
|
@@ -441,6 +437,7 @@ export const Timeline = memo(function Timeline({
|
|
|
441
437
|
|
|
442
438
|
return (
|
|
443
439
|
<div
|
|
440
|
+
ref={setContainerRef}
|
|
444
441
|
aria-label="Timeline"
|
|
445
442
|
className={`relative border-t select-none h-full overflow-hidden ${activeTool === "razor" ? "cursor-crosshair" : shiftHeld ? "cursor-crosshair" : "cursor-default"}`}
|
|
446
443
|
onMouseMove={(e) => {
|
|
@@ -460,8 +457,12 @@ export const Timeline = memo(function Timeline({
|
|
|
460
457
|
ref={setScrollRef}
|
|
461
458
|
tabIndex={-1}
|
|
462
459
|
className={`${zoomMode === "fit" ? "overflow-x-hidden" : "overflow-x-auto"} overflow-y-auto h-full outline-none`}
|
|
460
|
+
onScroll={(e) => {
|
|
461
|
+
// Remember the live offset so it can be restored across a post-edit reload.
|
|
462
|
+
lastScrollLeftRef.current = e.currentTarget.scrollLeft;
|
|
463
|
+
}}
|
|
463
464
|
onDragOver={handleAssetDragOver}
|
|
464
|
-
onDragLeave={() =>
|
|
465
|
+
onDragLeave={() => clearDropPreview()}
|
|
465
466
|
onDrop={handleAssetDrop}
|
|
466
467
|
onPointerDown={(e) => {
|
|
467
468
|
if (activeTool === "razor" && e.shiftKey && e.button === 0 && scrollRef.current) {
|
|
@@ -471,21 +472,17 @@ export const Timeline = memo(function Timeline({
|
|
|
471
472
|
onRazorSplitAll?.(splitTime);
|
|
472
473
|
return;
|
|
473
474
|
}
|
|
474
|
-
if (handleMarqueePointerDown(e)) return;
|
|
475
475
|
handlePointerDown(e);
|
|
476
476
|
}}
|
|
477
|
-
onPointerMove={
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}}
|
|
481
|
-
onPointerUp={releasePointer}
|
|
482
|
-
onLostPointerCapture={releasePointer}
|
|
477
|
+
onPointerMove={handlePointerMove}
|
|
478
|
+
onPointerUp={handlePointerUp}
|
|
479
|
+
onLostPointerCapture={handlePointerUp}
|
|
483
480
|
>
|
|
484
481
|
<TimelineCanvas
|
|
485
482
|
major={major}
|
|
486
483
|
minor={minor}
|
|
487
484
|
pps={pps}
|
|
488
|
-
trackContentWidth={
|
|
485
|
+
trackContentWidth={displayContentWidth}
|
|
489
486
|
totalH={totalH}
|
|
490
487
|
effectiveDuration={effectiveDuration}
|
|
491
488
|
majorTickInterval={majorTickInterval}
|
|
@@ -497,9 +494,11 @@ export const Timeline = memo(function Timeline({
|
|
|
497
494
|
tracks={tracks}
|
|
498
495
|
trackStyles={trackStyles}
|
|
499
496
|
selectedElementId={selectedElementId}
|
|
497
|
+
selectedElementIds={selectedElementIds}
|
|
500
498
|
hoveredClip={hoveredClip}
|
|
501
499
|
draggedClip={draggedClip}
|
|
502
500
|
resizingClip={resizingClip}
|
|
501
|
+
isScrubbing={isScrubbing}
|
|
503
502
|
blockedClipRef={blockedClipRef}
|
|
504
503
|
suppressClickRef={suppressClickRef}
|
|
505
504
|
scrollRef={scrollRef}
|
|
@@ -522,10 +521,41 @@ export const Timeline = memo(function Timeline({
|
|
|
522
521
|
selectedKeyframes={selectedKeyframes}
|
|
523
522
|
currentTime={currentTime}
|
|
524
523
|
beatAnalysis={adjustedBeatAnalysis}
|
|
525
|
-
onClickKeyframe={
|
|
526
|
-
|
|
524
|
+
onClickKeyframe={(el, pct) => {
|
|
525
|
+
usePlayerStore.getState().clearSelectedKeyframes();
|
|
526
|
+
const elKey = el.key ?? el.id;
|
|
527
|
+
setSelectedElementId(elKey);
|
|
528
|
+
onSelectElement?.(el);
|
|
529
|
+
// Visually select the clicked diamond (matches shift-click / motion-path
|
|
530
|
+
// selection); cleared above so this single-selects it.
|
|
531
|
+
toggleSelectedKeyframe(`${elKey}:${pct}`);
|
|
532
|
+
const absTime = el.start + (pct / 100) * el.duration;
|
|
533
|
+
onSeek?.(absTime);
|
|
534
|
+
const kfData = keyframeCache?.get(elKey);
|
|
535
|
+
const kf = kfData?.keyframes.find((k) => Math.abs(k.percentage - pct) < 0.5);
|
|
536
|
+
usePlayerStore.getState().setActiveKeyframePct(kf?.tweenPercentage ?? null);
|
|
537
|
+
}}
|
|
538
|
+
onShiftClickKeyframe={(elId, pct) => {
|
|
539
|
+
toggleSelectedKeyframe(`${elId}:${pct}`);
|
|
540
|
+
}}
|
|
527
541
|
onMoveKeyframe={onMoveKeyframe}
|
|
528
|
-
onContextMenuKeyframe={
|
|
542
|
+
onContextMenuKeyframe={(e, elId, pct) => {
|
|
543
|
+
const el = expandedElements.find((x) => (x.key ?? x.id) === elId);
|
|
544
|
+
if (el) {
|
|
545
|
+
setSelectedElementId(elId);
|
|
546
|
+
onSelectElement?.(el);
|
|
547
|
+
}
|
|
548
|
+
const kfData = keyframeCache.get(elId);
|
|
549
|
+
const kf = kfData?.keyframes.find((k) => Math.abs(k.percentage - pct) < 0.2);
|
|
550
|
+
setKfContextMenu({
|
|
551
|
+
x: e.clientX + 4,
|
|
552
|
+
y: e.clientY + 2,
|
|
553
|
+
elementId: elId,
|
|
554
|
+
percentage: pct,
|
|
555
|
+
tweenPercentage: kf?.tweenPercentage,
|
|
556
|
+
currentEase: kf?.ease ?? kfData?.ease,
|
|
557
|
+
});
|
|
558
|
+
}}
|
|
529
559
|
onContextMenuClip={(e, el) => {
|
|
530
560
|
e.preventDefault();
|
|
531
561
|
setSelectedElementId(el.key ?? el.id);
|
|
@@ -544,57 +574,27 @@ export const Timeline = memo(function Timeline({
|
|
|
544
574
|
/>
|
|
545
575
|
)}
|
|
546
576
|
</div>
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
onClose={() => setKfContextMenu(null)}
|
|
569
|
-
onDelete={(elId, pct) => onDeleteKeyframe?.(elId, pct)}
|
|
570
|
-
onDeleteAll={(elId) => onDeleteAllKeyframes?.(elId)}
|
|
571
|
-
onChangeEase={(elId, pct, ease) => onChangeKeyframeEase?.(elId, pct, ease)}
|
|
572
|
-
onMoveToPlayhead={
|
|
573
|
-
onMoveKeyframeToPlayhead
|
|
574
|
-
? (elId, pct) => onMoveKeyframeToPlayhead(elId, pct)
|
|
575
|
-
: undefined
|
|
576
|
-
}
|
|
577
|
-
onCopyProperties={(elId, pct) => {
|
|
578
|
-
const kfData = keyframeCache.get(elId);
|
|
579
|
-
const kf = kfData?.keyframes.find((k) => k.percentage === pct);
|
|
580
|
-
if (kf) {
|
|
581
|
-
void navigator.clipboard.writeText(JSON.stringify(kf.properties, null, 2));
|
|
582
|
-
}
|
|
583
|
-
}}
|
|
584
|
-
/>
|
|
585
|
-
)}
|
|
586
|
-
|
|
587
|
-
{clipContextMenu && (
|
|
588
|
-
<ClipContextMenu
|
|
589
|
-
x={clipContextMenu.x}
|
|
590
|
-
y={clipContextMenu.y}
|
|
591
|
-
element={clipContextMenu.element}
|
|
592
|
-
currentTime={currentTime}
|
|
593
|
-
onClose={() => setClipContextMenu(null)}
|
|
594
|
-
onSplit={(el, time) => onSplitElement?.(el, time)}
|
|
595
|
-
onDelete={(el) => _onDeleteElement?.(el)}
|
|
596
|
-
/>
|
|
597
|
-
)}
|
|
577
|
+
<TimelineOverlays
|
|
578
|
+
theme={theme}
|
|
579
|
+
showShortcutHint={showShortcutHint}
|
|
580
|
+
showPopover={showPopover}
|
|
581
|
+
rangeSelection={rangeSelection}
|
|
582
|
+
setShowPopover={setShowPopover}
|
|
583
|
+
setRangeSelection={setRangeSelection}
|
|
584
|
+
kfContextMenu={kfContextMenu}
|
|
585
|
+
setKfContextMenu={setKfContextMenu}
|
|
586
|
+
onDeleteKeyframe={onDeleteKeyframe}
|
|
587
|
+
onDeleteAllKeyframes={onDeleteAllKeyframes}
|
|
588
|
+
onChangeKeyframeEase={onChangeKeyframeEase}
|
|
589
|
+
onMoveKeyframeToPlayhead={onMoveKeyframeToPlayhead}
|
|
590
|
+
keyframeCache={keyframeCache}
|
|
591
|
+
clipContextMenu={clipContextMenu}
|
|
592
|
+
setClipContextMenu={setClipContextMenu}
|
|
593
|
+
currentTime={currentTime}
|
|
594
|
+
onSplitElement={onSplitElement}
|
|
595
|
+
pinZoomBeforeEdit={pinZoomBeforeEdit}
|
|
596
|
+
onDeleteElement={_onDeleteElement}
|
|
597
|
+
/>
|
|
598
598
|
</div>
|
|
599
599
|
);
|
|
600
600
|
});
|