@hyperframes/studio 0.7.55 → 0.7.57
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--Z69cEkE.js +459 -0
- package/dist/assets/{index-CPetwHFV.js → index-Bf1x1y8H.js} +1 -1
- package/dist/assets/index-DfmYkU44.js +423 -0
- package/dist/assets/{index-BXaqaVKt.js → index-KsfE1bUu.js} +1 -1
- package/dist/assets/index-_pqzyxB1.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 +172 -144
- package/dist/index.html +2 -2
- package/dist/index.js +43613 -40346
- 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 +152 -1
- package/src/components/editor/CanvasContextMenu.tsx +33 -18
- 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 +126 -125
- 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 +53 -2
- 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 +106 -10
- package/src/components/editor/canvasContextMenuZOrder.test.ts +186 -2
- package/src/components/editor/canvasContextMenuZOrder.ts +144 -22
- 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/propertyPanelColorGradingSection.tsx +15 -21
- 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/useCanvasContextMenuState.ts +92 -0
- 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/editor/useZOrderCrossedFlash.tsx +68 -0
- package/src/components/nle/AssetPreviewOverlay.test.tsx +106 -0
- package/src/components/nle/AssetPreviewOverlay.tsx +171 -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 +260 -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.test.tsx +106 -0
- package/src/components/sidebar/AssetCard.tsx +343 -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 +56 -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 +23 -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 +125 -1
- package/src/hooks/timelineEditingHelpers.ts +53 -292
- package/src/hooks/timelineMoveAdapter.test.ts +81 -0
- package/src/hooks/timelineMoveAdapter.ts +39 -0
- package/src/hooks/timelineTimingSync.test.ts +150 -0
- package/src/hooks/timelineTimingSync.ts +412 -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/useCaptionDetection.ts +2 -0
- package/src/hooks/useCompositionDimensions.ts +32 -5
- package/src/hooks/useContextMenuDismiss.ts +31 -7
- package/src/hooks/useDomEditCommits.test.tsx +245 -1
- package/src/hooks/useDomEditCommits.ts +162 -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 +423 -0
- package/src/hooks/useElementLifecycleOps.ts +53 -71
- package/src/hooks/useElementPicker.ts +7 -8
- 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 +148 -18
- 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/useTimelineAssetDropOps.ts +175 -0
- package/src/hooks/useTimelineEditing.test.tsx +398 -241
- package/src/hooks/useTimelineEditing.ts +181 -265
- package/src/hooks/useTimelineEditingTypes.ts +6 -0
- package/src/hooks/useTimelineGroupEditing.ts +167 -132
- 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/PlayerControls.tsx +5 -5
- package/src/player/components/PlayheadIndicator.tsx +55 -5
- package/src/player/components/Timeline.test.ts +183 -23
- package/src/player/components/Timeline.tsx +194 -194
- package/src/player/components/TimelineCanvas.tsx +218 -523
- 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/TimelineRuler.tsx +58 -48
- 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 +1026 -0
- package/src/player/components/timelineClipDragCommit.ts +498 -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 +42 -2
- 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 +207 -75
- package/src/player/components/timelineMarquee.test.ts +197 -0
- package/src/player/components/timelineMarquee.ts +112 -0
- package/src/player/components/timelineOptimisticRevision.ts +42 -0
- package/src/player/components/timelineRevealScroll.test.ts +133 -0
- package/src/player/components/timelineRevealScroll.ts +91 -0
- package/src/player/components/timelineStackingSync.test.ts +60 -0
- package/src/player/components/timelineStackingSync.ts +27 -2
- package/src/player/components/timelineTheme.ts +6 -1
- package/src/player/components/timelineTrackPersistPipeline.test.ts +168 -0
- package/src/player/components/timelineZones.test.ts +122 -310
- package/src/player/components/timelineZones.ts +82 -135
- 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/useTimelineRevealClip.ts +56 -0
- package/src/player/components/useTimelineStackingSync.test.tsx +77 -0
- package/src/player/components/useTimelineStackingSync.ts +94 -0
- package/src/player/hooks/useExpandedTimelineElements.ts +7 -3
- package/src/player/hooks/usePlaybackKeyboard.ts +5 -0
- package/src/player/hooks/useTimelinePlayer.seek.test.ts +55 -0
- package/src/player/hooks/useTimelinePlayer.test.ts +36 -3
- package/src/player/hooks/useTimelinePlayer.ts +52 -53
- package/src/player/hooks/useTimelinePlayerLoop.ts +85 -0
- package/src/player/hooks/useTimelineSyncCallbacks.ts +9 -1
- package/src/player/index.ts +5 -2
- package/src/player/lib/runtimeProtocol.test.ts +48 -0
- package/src/player/lib/runtimeProtocol.ts +65 -0
- 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 +21 -81
- package/src/player/lib/timelineElementHelpers.ts +73 -5
- package/src/player/lib/timelineIframeHelpers.ts +4 -4
- package/src/player/store/playerStore.test.ts +38 -13
- package/src/player/store/playerStore.ts +99 -3
- package/src/styles/studio.css +27 -0
- package/src/utils/assetPreviewDismiss.test.ts +27 -0
- package/src/utils/assetPreviewDismiss.ts +29 -0
- package/src/utils/assetPreviewStore.ts +33 -0
- package/src/utils/blockInstaller.ts +10 -2
- 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/studioUrlState.test.ts +0 -1
- package/src/utils/timelineAssetDrop.test.ts +144 -52
- package/src/utils/timelineAssetDrop.ts +67 -29
- package/src/utils/timelineDiscovery.ts +0 -17
- package/dist/assets/hyperframes-player-BBrKzTGd.js +0 -459
- package/dist/assets/index-BRwkMj0w.js +0 -423
- package/dist/assets/index-Dq7FEg0K.css +0 -1
- 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,32 @@ 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";
|
|
29
|
+
import { STUDIO_PREVIEW_FPS } from "../lib/time";
|
|
38
30
|
import { useResolvedTimelineEditCallbacks } from "./useResolvedTimelineEditCallbacks";
|
|
39
31
|
import type { TimelineProps } from "./TimelineTypes";
|
|
40
32
|
|
|
33
|
+
// Re-export pure utilities so existing imports from "./Timeline" still resolve.
|
|
41
34
|
export {
|
|
42
35
|
generateTicks,
|
|
43
36
|
formatTimelineTickLabel,
|
|
@@ -62,7 +55,9 @@ export const Timeline = memo(function Timeline({
|
|
|
62
55
|
onBlockDrop,
|
|
63
56
|
onDeleteElement: _onDeleteElement,
|
|
64
57
|
onMoveElement: onMoveElementOverride,
|
|
58
|
+
onMoveElements: onMoveElementsOverride,
|
|
65
59
|
onResizeElement: onResizeElementOverride,
|
|
60
|
+
onResizeElements: onResizeElementsOverride,
|
|
66
61
|
onBlockedEditAttempt: onBlockedEditAttemptOverride,
|
|
67
62
|
onSplitElement: onSplitElementOverride,
|
|
68
63
|
onSelectElement,
|
|
@@ -70,11 +65,9 @@ export const Timeline = memo(function Timeline({
|
|
|
70
65
|
}: TimelineProps = {}) {
|
|
71
66
|
const {
|
|
72
67
|
onMoveElement,
|
|
73
|
-
onResizeElement,
|
|
74
68
|
onMoveElements,
|
|
69
|
+
onResizeElement,
|
|
75
70
|
onResizeElements,
|
|
76
|
-
onPreviewMoveElements,
|
|
77
|
-
onPreviewResizeElements,
|
|
78
71
|
onBlockedEditAttempt,
|
|
79
72
|
onSplitElement,
|
|
80
73
|
onRazorSplitAll,
|
|
@@ -85,7 +78,9 @@ export const Timeline = memo(function Timeline({
|
|
|
85
78
|
onMoveKeyframe,
|
|
86
79
|
} = useResolvedTimelineEditCallbacks({
|
|
87
80
|
onMoveElement: onMoveElementOverride,
|
|
81
|
+
onMoveElements: onMoveElementsOverride,
|
|
88
82
|
onResizeElement: onResizeElementOverride,
|
|
83
|
+
onResizeElements: onResizeElementsOverride,
|
|
89
84
|
onBlockedEditAttempt: onBlockedEditAttemptOverride,
|
|
90
85
|
onSplitElement: onSplitElementOverride,
|
|
91
86
|
});
|
|
@@ -101,19 +96,23 @@ export const Timeline = memo(function Timeline({
|
|
|
101
96
|
[beatAnalysis, musicElement, beatEdits],
|
|
102
97
|
);
|
|
103
98
|
const duration = usePlayerStore((s) => s.duration);
|
|
99
|
+
const timeDisplayMode = usePlayerStore((s) => s.timeDisplayMode);
|
|
104
100
|
const timelineReady = usePlayerStore((s) => s.timelineReady);
|
|
105
101
|
const selectedElementId = usePlayerStore((s) => s.selectedElementId);
|
|
102
|
+
const selectedElementIds = usePlayerStore((s) => s.selectedElementIds);
|
|
106
103
|
const setSelectedElementId = usePlayerStore((s) => s.setSelectedElementId);
|
|
107
104
|
const currentTime = usePlayerStore((s) => s.currentTime);
|
|
108
105
|
const { zoomMode, manualZoomPercent, setZoomMode, setManualZoomPercent } = useTimelineZoom();
|
|
109
106
|
|
|
110
107
|
const playheadRef = useRef<HTMLDivElement>(null);
|
|
108
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
111
109
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
112
110
|
const activeTool = usePlayerStore((s) => s.activeTool);
|
|
113
111
|
const [hoveredClip, setHoveredClip] = useState<string | null>(null);
|
|
114
112
|
const isDragging = useRef(false);
|
|
115
113
|
const [shiftHeld, setShiftHeld] = useState(false);
|
|
116
114
|
const [razorGuideX, setRazorGuideX] = useState<number | null>(null);
|
|
115
|
+
|
|
117
116
|
useMountEffect(() => {
|
|
118
117
|
const down = (e: KeyboardEvent) => e.key === "Shift" && setShiftHeld(true);
|
|
119
118
|
const up = (e: KeyboardEvent) => e.key === "Shift" && setShiftHeld(false);
|
|
@@ -139,6 +138,7 @@ export const Timeline = memo(function Timeline({
|
|
|
139
138
|
const [viewportWidth, setViewportWidth] = useState(0);
|
|
140
139
|
const roRef = useRef<ResizeObserver | null>(null);
|
|
141
140
|
const shortcutHintRafRef = useRef(0);
|
|
141
|
+
|
|
142
142
|
const syncShortcutHintVisibility = useCallback(() => {
|
|
143
143
|
const scroll = scrollRef.current;
|
|
144
144
|
setShowShortcutHint(
|
|
@@ -154,6 +154,13 @@ export const Timeline = memo(function Timeline({
|
|
|
154
154
|
});
|
|
155
155
|
}, [syncShortcutHintVisibility]);
|
|
156
156
|
|
|
157
|
+
const setContainerRef = useCallback((el: HTMLDivElement | null) => {
|
|
158
|
+
containerRef.current = el;
|
|
159
|
+
}, []);
|
|
160
|
+
|
|
161
|
+
// Last horizontal scroll offset, RESTORED across the post-edit iframe reload (which clamps into
|
|
162
|
+
// a scroll jump); with the pinned zoom this keeps the user parked at the same spot after edits.
|
|
163
|
+
const lastScrollLeftRef = useRef(0);
|
|
157
164
|
const setScrollRef = useCallback(
|
|
158
165
|
(el: HTMLDivElement | null) => {
|
|
159
166
|
if (roRef.current) {
|
|
@@ -180,31 +187,70 @@ export const Timeline = memo(function Timeline({
|
|
|
180
187
|
if (shortcutHintRafRef.current) cancelAnimationFrame(shortcutHintRafRef.current);
|
|
181
188
|
});
|
|
182
189
|
|
|
183
|
-
const
|
|
184
|
-
()
|
|
185
|
-
|
|
186
|
-
|
|
190
|
+
const effectiveDuration = useMemo(() => {
|
|
191
|
+
const safeDur = Number.isFinite(duration) ? duration : 0;
|
|
192
|
+
if (rawElements.length === 0) return safeDur;
|
|
193
|
+
const maxEnd = Math.max(...rawElements.map((el) => el.start + el.duration));
|
|
194
|
+
const result = Math.max(safeDur, maxEnd);
|
|
195
|
+
return Number.isFinite(result) ? result : safeDur;
|
|
196
|
+
}, [rawElements, duration]);
|
|
197
|
+
|
|
198
|
+
const tracks = useMemo(() => {
|
|
199
|
+
const map = new Map<number, typeof expandedElements>();
|
|
200
|
+
for (const el of expandedElements) {
|
|
201
|
+
const list = map.get(el.track) ?? [];
|
|
202
|
+
list.push(el);
|
|
203
|
+
map.set(el.track, list);
|
|
204
|
+
}
|
|
205
|
+
return Array.from(map.entries()).sort(([a], [b]) => a - b);
|
|
206
|
+
}, [expandedElements]);
|
|
187
207
|
|
|
188
208
|
const trackStyles = useMemo(() => {
|
|
189
|
-
const map = new Map<
|
|
190
|
-
for (const
|
|
191
|
-
map.set(
|
|
209
|
+
const map = new Map<number, TrackVisualStyle>();
|
|
210
|
+
for (const [trackNum, els] of tracks) {
|
|
211
|
+
map.set(trackNum, getTrackStyle(els[0]?.tag ?? ""));
|
|
192
212
|
}
|
|
193
213
|
return map;
|
|
194
214
|
}, [tracks]);
|
|
195
215
|
|
|
196
|
-
const trackOrder = useMemo(() => tracks.map((
|
|
216
|
+
const trackOrder = useMemo(() => tracks.map(([trackNum]) => trackNum), [tracks]);
|
|
197
217
|
const trackOrderRef = useRef(trackOrder);
|
|
198
218
|
trackOrderRef.current = trackOrder;
|
|
199
|
-
const timelineLayersRef = useRef(tracks);
|
|
200
|
-
timelineLayersRef.current = tracks;
|
|
201
219
|
const expandedElementsRef = useRef(expandedElements);
|
|
202
220
|
expandedElementsRef.current = expandedElements;
|
|
203
221
|
|
|
204
222
|
const ppsRef = useRef(100);
|
|
205
|
-
const durationRef = useRef(
|
|
223
|
+
const durationRef = useRef(effectiveDuration);
|
|
224
|
+
durationRef.current = effectiveDuration;
|
|
225
|
+
// Declared here (used before the fitPps derivation below) so the edit-pin
|
|
226
|
+
// wrappers can close over it; `fitPpsRef.current` is refreshed each render.
|
|
227
|
+
const fitPpsRef = useRef(100);
|
|
206
228
|
|
|
207
|
-
const
|
|
229
|
+
const {
|
|
230
|
+
pinZoomBeforeEdit,
|
|
231
|
+
setRangeSelectionRef,
|
|
232
|
+
pinnedOnMoveElement,
|
|
233
|
+
pinnedOnMoveElements,
|
|
234
|
+
pinnedOnResizeElement,
|
|
235
|
+
pinnedOnResizeElements,
|
|
236
|
+
pinnedOnFileDrop,
|
|
237
|
+
pinnedOnAssetDrop,
|
|
238
|
+
pinnedOnBlockDrop,
|
|
239
|
+
} = useTimelineEditPinning({
|
|
240
|
+
ppsRef,
|
|
241
|
+
fitPpsRef,
|
|
242
|
+
onMoveElement,
|
|
243
|
+
onMoveElements,
|
|
244
|
+
onResizeElement,
|
|
245
|
+
onResizeElements,
|
|
246
|
+
onFileDrop,
|
|
247
|
+
onAssetDrop,
|
|
248
|
+
onBlockDrop,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const { readClipZIndex, applyStackingPatches, zSyncEnabled } = useTimelineStackingSync({
|
|
252
|
+
expandedElementsRef,
|
|
253
|
+
});
|
|
208
254
|
|
|
209
255
|
const {
|
|
210
256
|
draggedClip,
|
|
@@ -217,67 +263,39 @@ export const Timeline = memo(function Timeline({
|
|
|
217
263
|
} = useTimelineClipDrag({
|
|
218
264
|
scrollRef,
|
|
219
265
|
ppsRef,
|
|
266
|
+
durationRef,
|
|
220
267
|
trackOrderRef,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
onMoveElements,
|
|
226
|
-
onResizeElements,
|
|
227
|
-
onPreviewMoveElements,
|
|
228
|
-
onPreviewResizeElements,
|
|
268
|
+
onMoveElement: pinnedOnMoveElement,
|
|
269
|
+
onMoveElements: pinnedOnMoveElements,
|
|
270
|
+
onResizeElement: pinnedOnResizeElement,
|
|
271
|
+
onResizeElements: pinnedOnResizeElements,
|
|
229
272
|
onBlockedEditAttempt,
|
|
230
273
|
setShowPopover,
|
|
231
274
|
setRangeSelectionRef,
|
|
275
|
+
readZIndex: zSyncEnabled ? readClipZIndex : undefined,
|
|
276
|
+
onStackingPatches: zSyncEnabled ? applyStackingPatches : undefined,
|
|
232
277
|
});
|
|
233
278
|
|
|
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;
|
|
279
|
+
const { isDragOver, handleAssetDragOver, handleAssetDrop, clearDropPreview } =
|
|
280
|
+
useTimelineAssetDrop({
|
|
281
|
+
scrollRef,
|
|
282
|
+
ppsRef,
|
|
283
|
+
durationRef,
|
|
284
|
+
trackOrderRef,
|
|
285
|
+
onFileDrop: pinnedOnFileDrop,
|
|
286
|
+
onAssetDrop: pinnedOnAssetDrop,
|
|
287
|
+
onBlockDrop: pinnedOnBlockDrop,
|
|
288
|
+
});
|
|
251
289
|
|
|
252
290
|
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
|
-
);
|
|
291
|
+
if (!draggedClip?.started || trackOrder.includes(draggedClip.previewTrack)) return trackOrder;
|
|
292
|
+
return [...trackOrder, draggedClip.previewTrack].sort((a, b) => a - b);
|
|
264
293
|
}, [draggedClip, trackOrder]);
|
|
265
294
|
|
|
266
|
-
const totalH =
|
|
267
|
-
getTimelineCanvasHeight(displayTrackOrder.length) +
|
|
268
|
-
getTimelineLayerGroupHeaderTotalHeight(displayTrackOrder, tracks);
|
|
295
|
+
const totalH = getTimelineCanvasHeight(displayTrackOrder.length);
|
|
269
296
|
const keyframeCache = usePlayerStore((s) => s.keyframeCache);
|
|
270
297
|
const selectedKeyframes = usePlayerStore((s) => s.selectedKeyframes);
|
|
271
298
|
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
299
|
|
|
282
300
|
const selectedElement = useMemo(
|
|
283
301
|
() =>
|
|
@@ -287,26 +305,28 @@ export const Timeline = memo(function Timeline({
|
|
|
287
305
|
const selectedElementRef = useRef<TimelineElement | null>(selectedElement);
|
|
288
306
|
selectedElementRef.current = selectedElement;
|
|
289
307
|
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
308
|
+
const {
|
|
309
|
+
pps,
|
|
310
|
+
fitPps,
|
|
311
|
+
displayContentWidth,
|
|
312
|
+
displayDuration,
|
|
313
|
+
clipStateVersion,
|
|
314
|
+
zoomModeRef,
|
|
315
|
+
manualZoomPercentRef,
|
|
316
|
+
} = useTimelineGeometry({
|
|
317
|
+
viewportWidth,
|
|
318
|
+
effectiveDuration,
|
|
319
|
+
zoomMode,
|
|
320
|
+
manualZoomPercent,
|
|
321
|
+
ppsRef,
|
|
322
|
+
fitPpsRef,
|
|
323
|
+
draggedClip,
|
|
324
|
+
resizingClip,
|
|
325
|
+
expandedElements,
|
|
326
|
+
isDragging,
|
|
327
|
+
scrollRef,
|
|
328
|
+
lastScrollLeftRef,
|
|
329
|
+
});
|
|
310
330
|
|
|
311
331
|
const { seekFromX, autoScrollDuringDrag, dragScrollRaf } = useTimelinePlayhead({
|
|
312
332
|
playheadRef,
|
|
@@ -339,6 +359,8 @@ export const Timeline = memo(function Timeline({
|
|
|
339
359
|
rangeSelection,
|
|
340
360
|
setRangeSelection,
|
|
341
361
|
shiftClickClipRef,
|
|
362
|
+
marqueeRect,
|
|
363
|
+
isScrubbing,
|
|
342
364
|
handlePointerDown,
|
|
343
365
|
handlePointerMove,
|
|
344
366
|
handlePointerUp,
|
|
@@ -353,28 +375,12 @@ export const Timeline = memo(function Timeline({
|
|
|
353
375
|
dragScrollRaf,
|
|
354
376
|
isDragging,
|
|
355
377
|
setShowPopover,
|
|
356
|
-
|
|
357
|
-
const {
|
|
358
|
-
marqueeRect,
|
|
359
|
-
handlePointerDown: handleMarqueePointerDown,
|
|
360
|
-
handlePointerMove: handleMarqueePointerMove,
|
|
361
|
-
handlePointerUp: handleMarqueePointerUp,
|
|
362
|
-
} = useTimelineMarqueeSelection({
|
|
363
|
-
scrollRef,
|
|
364
|
-
ppsRef,
|
|
378
|
+
elementsRef: expandedElementsRef,
|
|
365
379
|
trackOrderRef,
|
|
366
|
-
|
|
367
|
-
disabled: activeTool === "razor",
|
|
368
|
-
setShowPopover,
|
|
369
|
-
setRangeSelectionRef,
|
|
370
|
-
seekFromX,
|
|
380
|
+
onSelectElement,
|
|
371
381
|
});
|
|
382
|
+
// Wire setRangeSelection into the stable ref consumed by useTimelineClipDrag
|
|
372
383
|
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
384
|
|
|
379
385
|
const prevSelectedRef = useRef(selectedElementRef.current);
|
|
380
386
|
// eslint-disable-next-line no-restricted-syntax, react-hooks/exhaustive-deps
|
|
@@ -388,9 +394,11 @@ export const Timeline = memo(function Timeline({
|
|
|
388
394
|
}
|
|
389
395
|
});
|
|
390
396
|
|
|
397
|
+
// Frame display mode labels ruler ticks as frame numbers — pass the fps so ticks snap to frames.
|
|
398
|
+
const tickFps = timeDisplayMode === "frame" ? STUDIO_PREVIEW_FPS : undefined;
|
|
391
399
|
const { major, minor } = useMemo(
|
|
392
|
-
() =>
|
|
393
|
-
[
|
|
400
|
+
() => generateTicks(displayDuration, pps, tickFps),
|
|
401
|
+
[displayDuration, pps, tickFps],
|
|
394
402
|
);
|
|
395
403
|
const majorTickInterval = major.length >= 2 ? major[1] - major[0] : effectiveDuration;
|
|
396
404
|
|
|
@@ -416,24 +424,13 @@ export const Timeline = memo(function Timeline({
|
|
|
416
424
|
[resizingClip],
|
|
417
425
|
);
|
|
418
426
|
|
|
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
427
|
if (!timelineReady || expandedElements.length === 0) {
|
|
431
428
|
return (
|
|
432
429
|
<TimelineEmptyState
|
|
433
430
|
isDragOver={isDragOver}
|
|
434
431
|
onFileDrop={!!onFileDrop}
|
|
435
432
|
onDragOver={handleAssetDragOver}
|
|
436
|
-
onDragLeave={() =>
|
|
433
|
+
onDragLeave={() => clearDropPreview()}
|
|
437
434
|
onDrop={handleAssetDrop}
|
|
438
435
|
/>
|
|
439
436
|
);
|
|
@@ -441,6 +438,7 @@ export const Timeline = memo(function Timeline({
|
|
|
441
438
|
|
|
442
439
|
return (
|
|
443
440
|
<div
|
|
441
|
+
ref={setContainerRef}
|
|
444
442
|
aria-label="Timeline"
|
|
445
443
|
className={`relative border-t select-none h-full overflow-hidden ${activeTool === "razor" ? "cursor-crosshair" : shiftHeld ? "cursor-crosshair" : "cursor-default"}`}
|
|
446
444
|
onMouseMove={(e) => {
|
|
@@ -460,8 +458,12 @@ export const Timeline = memo(function Timeline({
|
|
|
460
458
|
ref={setScrollRef}
|
|
461
459
|
tabIndex={-1}
|
|
462
460
|
className={`${zoomMode === "fit" ? "overflow-x-hidden" : "overflow-x-auto"} overflow-y-auto h-full outline-none`}
|
|
461
|
+
onScroll={(e) => {
|
|
462
|
+
// Remember the live offset so it can be restored across a post-edit reload.
|
|
463
|
+
lastScrollLeftRef.current = e.currentTarget.scrollLeft;
|
|
464
|
+
}}
|
|
463
465
|
onDragOver={handleAssetDragOver}
|
|
464
|
-
onDragLeave={() =>
|
|
466
|
+
onDragLeave={() => clearDropPreview()}
|
|
465
467
|
onDrop={handleAssetDrop}
|
|
466
468
|
onPointerDown={(e) => {
|
|
467
469
|
if (activeTool === "razor" && e.shiftKey && e.button === 0 && scrollRef.current) {
|
|
@@ -471,21 +473,17 @@ export const Timeline = memo(function Timeline({
|
|
|
471
473
|
onRazorSplitAll?.(splitTime);
|
|
472
474
|
return;
|
|
473
475
|
}
|
|
474
|
-
if (handleMarqueePointerDown(e)) return;
|
|
475
476
|
handlePointerDown(e);
|
|
476
477
|
}}
|
|
477
|
-
onPointerMove={
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}}
|
|
481
|
-
onPointerUp={releasePointer}
|
|
482
|
-
onLostPointerCapture={releasePointer}
|
|
478
|
+
onPointerMove={handlePointerMove}
|
|
479
|
+
onPointerUp={handlePointerUp}
|
|
480
|
+
onLostPointerCapture={handlePointerUp}
|
|
483
481
|
>
|
|
484
482
|
<TimelineCanvas
|
|
485
483
|
major={major}
|
|
486
484
|
minor={minor}
|
|
487
485
|
pps={pps}
|
|
488
|
-
trackContentWidth={
|
|
486
|
+
trackContentWidth={displayContentWidth}
|
|
489
487
|
totalH={totalH}
|
|
490
488
|
effectiveDuration={effectiveDuration}
|
|
491
489
|
majorTickInterval={majorTickInterval}
|
|
@@ -497,9 +495,11 @@ export const Timeline = memo(function Timeline({
|
|
|
497
495
|
tracks={tracks}
|
|
498
496
|
trackStyles={trackStyles}
|
|
499
497
|
selectedElementId={selectedElementId}
|
|
498
|
+
selectedElementIds={selectedElementIds}
|
|
500
499
|
hoveredClip={hoveredClip}
|
|
501
500
|
draggedClip={draggedClip}
|
|
502
501
|
resizingClip={resizingClip}
|
|
502
|
+
isScrubbing={isScrubbing}
|
|
503
503
|
blockedClipRef={blockedClipRef}
|
|
504
504
|
suppressClickRef={suppressClickRef}
|
|
505
505
|
scrollRef={scrollRef}
|
|
@@ -522,10 +522,40 @@ export const Timeline = memo(function Timeline({
|
|
|
522
522
|
selectedKeyframes={selectedKeyframes}
|
|
523
523
|
currentTime={currentTime}
|
|
524
524
|
beatAnalysis={adjustedBeatAnalysis}
|
|
525
|
-
onClickKeyframe={
|
|
526
|
-
|
|
525
|
+
onClickKeyframe={(el, pct) => {
|
|
526
|
+
usePlayerStore.getState().clearSelectedKeyframes();
|
|
527
|
+
const elKey = el.key ?? el.id;
|
|
528
|
+
setSelectedElementId(elKey);
|
|
529
|
+
onSelectElement?.(el);
|
|
530
|
+
// Select the clicked diamond (matches shift-click); cleared above so this single-selects.
|
|
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
|
});
|