import { useEffect, useReducer, useRef } from "react"; import { useEditor } from "@/editor/use-editor"; import { useShiftKey } from "@/hooks/use-shift-key"; import { useElementSelection } from "@/timeline/hooks/element/use-element-selection"; import { useTimelineStore } from "@/timeline/timeline-store"; import { registerCanceller } from "@/editor/cancel-interaction"; import { ResizeController, type ResizeConfig, } from "@/timeline/controllers/resize-controller"; import type { ResizeSide } from "@/timeline/group-resize"; import type { SnapPoint } from "@/timeline/snapping"; import type { TimelineElement } from "@/timeline"; export type { ResizeSide }; interface UseTimelineResizeProps { zoomLevel: number; onSnapPointChange?: (snapPoint: SnapPoint | null) => void; } export function useTimelineResize({ zoomLevel, onSnapPointChange, }: UseTimelineResizeProps) { const editor = useEditor(); const isShiftHeldRef = useShiftKey(); const snappingEnabled = useTimelineStore((state) => state.snappingEnabled); const { selectedElements } = useElementSelection(); const config: ResizeConfig = { zoomLevel, snappingEnabled, isShiftHeld: () => isShiftHeldRef.current, getSceneTracks: () => editor.scenes.getActiveScene().tracks, getCurrentPlayheadTime: () => editor.playback.getCurrentTime(), getActiveProjectFps: () => editor.project.getActive()?.settings.fps ?? null, selectedElements, discardPreview: () => editor.timeline.discardPreview(), previewElements: (updates) => editor.timeline.previewElements({ updates: updates.map(({ trackId, elementId, patch }) => ({ trackId, elementId, updates: patch as Partial, })), }), commitElements: (updates) => editor.timeline.updateElements({ updates: updates.map(({ trackId, elementId, patch }) => ({ trackId, elementId, patch: patch as Partial, })), }), onSnapPointChange, }; const configRef = useRef(config); configRef.current = config; const controllerRef = useRef(null); if (!controllerRef.current) { controllerRef.current = new ResizeController({ configRef }); } const controller = controllerRef.current; const [, rerender] = useReducer((n: number) => n + 1, 0); useEffect(() => controller.subscribe(rerender), [controller]); useEffect(() => { if (!controller.isResizing) return; return registerCanceller({ fn: () => controller.cancel() }); }, [controller.isResizing, controller]); useEffect(() => () => controller.destroy(), [controller]); return { isResizing: controller.isResizing, handleResizeStart: controller.onResizeStart, }; }