import { useEffect, useReducer, useRef } from "react"; import { useEditor } from "@/editor/use-editor"; import { useKeyframeSelection } from "./use-keyframe-selection"; import { registerCanceller } from "@/editor/cancel-interaction"; import { KeyframeDragController, type KeyframeDragConfig, type KeyframeDragState, } from "@/timeline/controllers/keyframe-drag-controller"; import type { TimelineElement } from "@/timeline"; export type { KeyframeDragState }; export function useKeyframeDrag({ zoomLevel, element, displayedStartTime, }: { zoomLevel: number; element: TimelineElement; displayedStartTime: number; }) { const editor = useEditor(); const { selectedKeyframes, isKeyframeSelected, setKeyframeSelection, toggleKeyframeSelection, selectKeyframeRange, } = useKeyframeSelection(); const config: KeyframeDragConfig = { zoomLevel, element, displayedStartTime, getFps: () => editor.project.getActive()?.settings.fps ?? null, selectedKeyframes, isKeyframeSelected, setKeyframeSelection, toggleKeyframeSelection, selectKeyframeRange, executeCommand: (command) => editor.command.execute({ command }), seek: (args) => editor.playback.seek(args), getTotalDuration: () => editor.timeline.getTotalDuration(), }; const configRef = useRef(config); configRef.current = config; const controllerRef = useRef(null); if (!controllerRef.current) { controllerRef.current = new KeyframeDragController({ configRef }); } const controller = controllerRef.current; const [, rerender] = useReducer((n: number) => n + 1, 0); useEffect(() => controller.subscribe(rerender), [controller]); useEffect(() => { if (!controller.isActive) return; return registerCanceller({ fn: () => controller.cancel() }); }, [controller.isActive, controller]); useEffect(() => () => controller.destroy(), [controller]); return { keyframeDragState: controller.keyframeDragState, handleKeyframeMouseDown: controller.onKeyframeMouseDown, handleKeyframeClick: controller.onKeyframeClick, getVisualOffsetPx: controller.getVisualOffsetPx, }; }