mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
refactor: centralize editor interaction state
Move timeline and preview gestures into dedicated controllers so hooks stay thin around editor state and DOM events. This also routes drag and playback synchronization through manager APIs and reuses persistent wasm surfaces so scrubbing, seeking, and preview rendering stay in sync. Made-with: Cursor
This commit is contained in:
@@ -29,7 +29,7 @@ import {
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import type { ElementDragState, DropTarget } from "@/timeline";
|
||||
import type { ElementDragView, DropTarget } from "@/timeline";
|
||||
import { TimelineTrackContent } from "./timeline-track";
|
||||
import { TimelinePlayhead } from "./timeline-playhead";
|
||||
import { SelectionBox } from "@/selection/selection-box";
|
||||
@@ -287,20 +287,15 @@ export function Timeline() {
|
||||
isReady: tracks.length > 0,
|
||||
});
|
||||
|
||||
const {
|
||||
dragState,
|
||||
dragDropTarget,
|
||||
handleElementMouseDown,
|
||||
handleElementClick,
|
||||
lastMouseXRef,
|
||||
} = useElementInteraction({
|
||||
zoomLevel,
|
||||
timelineRef,
|
||||
tracksContainerRef,
|
||||
tracksScrollRef,
|
||||
snappingEnabled,
|
||||
onSnapPointChange: handleSnapPointChange,
|
||||
});
|
||||
const { dragView, handleElementMouseDown, handleElementClick } =
|
||||
useElementInteraction({
|
||||
zoomLevel,
|
||||
tracksContainerRef,
|
||||
tracksScrollRef,
|
||||
snappingEnabled,
|
||||
onSnapPointChange: handleSnapPointChange,
|
||||
});
|
||||
const isElementDragging = dragView.kind === "dragging";
|
||||
|
||||
const {
|
||||
dragState: bookmarkDragState,
|
||||
@@ -391,10 +386,19 @@ export function Timeline() {
|
||||
contentWidth: dynamicTimelineWidth,
|
||||
});
|
||||
|
||||
useEdgeAutoScroll({
|
||||
isActive: isElementDragging,
|
||||
getMouseClientX: () =>
|
||||
dragView.kind === "dragging" ? dragView.currentMouseX : 0,
|
||||
rulerScrollRef,
|
||||
tracksScrollRef,
|
||||
contentWidth: dynamicTimelineWidth,
|
||||
});
|
||||
|
||||
const showSnapIndicator =
|
||||
snappingEnabled &&
|
||||
currentSnapPoint !== null &&
|
||||
(dragState.isDragging || bookmarkDragState.isDragging || isResizing);
|
||||
(isElementDragging || bookmarkDragState.isDragging || isResizing);
|
||||
|
||||
const {
|
||||
handleTracksMouseDown,
|
||||
@@ -457,9 +461,9 @@ export function Timeline() {
|
||||
headerHeight={timelineHeaderHeight}
|
||||
/>
|
||||
<DragLine
|
||||
dropTarget={dragDropTarget}
|
||||
dropTarget={isElementDragging ? dragView.dropTarget : null}
|
||||
tracks={tracks}
|
||||
isVisible={dragState.isDragging}
|
||||
isVisible={isElementDragging}
|
||||
headerHeight={timelineHeaderHeight}
|
||||
/>
|
||||
|
||||
@@ -540,9 +544,7 @@ export function Timeline() {
|
||||
<TimelineTrackRows
|
||||
mainTrackId={mainTrackId}
|
||||
zoomLevel={zoomLevel}
|
||||
dragState={dragState}
|
||||
tracksScrollRef={tracksScrollRef}
|
||||
lastMouseXRef={lastMouseXRef}
|
||||
dragView={dragView}
|
||||
onResizeStart={handleResizeStart}
|
||||
onElementMouseDown={handleElementMouseDown}
|
||||
onElementClick={handleElementClick}
|
||||
@@ -718,9 +720,7 @@ function TrackLabelsPanel({
|
||||
function TimelineTrackRows({
|
||||
mainTrackId,
|
||||
zoomLevel,
|
||||
dragState,
|
||||
tracksScrollRef,
|
||||
lastMouseXRef,
|
||||
dragView,
|
||||
onResizeStart,
|
||||
onElementMouseDown,
|
||||
onElementClick,
|
||||
@@ -732,9 +732,7 @@ function TimelineTrackRows({
|
||||
}: {
|
||||
mainTrackId: string | null;
|
||||
zoomLevel: number;
|
||||
dragState: ElementDragState;
|
||||
tracksScrollRef: React.RefObject<HTMLDivElement | null>;
|
||||
lastMouseXRef: React.RefObject<number>;
|
||||
dragView: ElementDragView;
|
||||
onResizeStart: React.ComponentProps<
|
||||
typeof TimelineTrackContent
|
||||
>["onResizeStart"];
|
||||
@@ -776,8 +774,16 @@ function TimelineTrackRows({
|
||||
[tracks, expandedElementIds],
|
||||
);
|
||||
|
||||
const draggingElementIds = useMemo(
|
||||
() =>
|
||||
dragView.kind === "dragging"
|
||||
? dragView.memberTimeOffsets
|
||||
: (null as ReadonlyMap<string, number> | null),
|
||||
[dragView],
|
||||
);
|
||||
const sortedTracks = useMemo(() => {
|
||||
const draggingElementIds = new Set(dragState.dragElementIds);
|
||||
if (!draggingElementIds)
|
||||
return tracks.map((track, index) => ({ track, index }));
|
||||
return [...tracks]
|
||||
.map((track, index) => ({ track, index }))
|
||||
.sort((a, b) => {
|
||||
@@ -791,7 +797,7 @@ function TimelineTrackRows({
|
||||
if (bHasDragged) return -1;
|
||||
return 0;
|
||||
});
|
||||
}, [tracks, dragState.dragElementIds]);
|
||||
}, [tracks, draggingElementIds]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -811,10 +817,7 @@ function TimelineTrackRows({
|
||||
<TimelineTrackContent
|
||||
track={track}
|
||||
zoomLevel={zoomLevel}
|
||||
dragState={dragState}
|
||||
rulerScrollRef={tracksScrollRef}
|
||||
tracksScrollRef={tracksScrollRef}
|
||||
lastMouseXRef={lastMouseXRef}
|
||||
dragView={dragView}
|
||||
onResizeStart={onResizeStart}
|
||||
onElementMouseDown={onElementMouseDown}
|
||||
onElementClick={onElementClick}
|
||||
|
||||
Reference in New Issue
Block a user