import { useCallback, useRef } from "react"; import { MIN_PREVIEW_H, MIN_TIMELINE_H, fitTimelineHeight } from "../../utils/fitPanels"; /** * Horizontal drag/keyboard-resizable divider between the preview and the * timeline. Implements the separator pattern: ArrowUp grows the timeline, * ArrowDown shrinks it (mirrors the drag direction). */ export function TimelineResizeDivider({ timelineH, setTimelineH, persistTimelineH, containerRef, disabled, }: { timelineH: number; setTimelineH: React.Dispatch>; persistTimelineH: (h: number) => void; containerRef: React.RefObject; disabled: boolean; }) { const isDragging = useRef(false); const timelineHRef = useRef(timelineH); timelineHRef.current = timelineH; const handlePointerDown = useCallback( (e: React.PointerEvent) => { if (disabled) return; e.preventDefault(); isDragging.current = true; (e.target as HTMLElement).setPointerCapture(e.pointerId); }, [disabled], ); const handlePointerMove = useCallback( (e: React.PointerEvent) => { if (disabled) return; if (!isDragging.current || !containerRef.current) return; const rect = containerRef.current.getBoundingClientRect(); const mouseY = e.clientY - rect.top; setTimelineH(fitTimelineHeight(rect.height, rect.height - mouseY)); }, [disabled, containerRef, setTimelineH], ); const handlePointerUp = useCallback(() => { if (isDragging.current) persistTimelineH(timelineHRef.current); isDragging.current = false; }, [persistTimelineH]); const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (disabled) return; if (e.key !== "ArrowUp" && e.key !== "ArrowDown") return; e.preventDefault(); const containerH = containerRef.current?.getBoundingClientRect().height ?? 0; const delta = e.key === "ArrowUp" ? 16 : -16; setTimelineH((prev) => { const next = fitTimelineHeight(containerH, prev + delta); persistTimelineH(next); return next; }); }, [disabled, containerRef, setTimelineH, persistTimelineH], ); return ( // Horizontal resize divider: 3px visible seam (h-[3px]), 10px pointer-capture // zone via the absolutely-positioned inner hit area so the layout gap stays // at 3px while draggability is preserved over the full band.
{/* Expanded hit zone, deliberately asymmetric: 4px up into the transport row's vertical centring slack, the 3px seam, then 3px down into the timeline card's border + toolbar padding. It stops at 10px rather than the 24px WCAG 2.2 (2.5.8) target because that is all the dead space there is: 28px transport buttons sit above and 28px toolbar buttons below, and silently stealing their clicks is the worse bug. */}
{/* Visible hairline — invisible at rest, subtle wash on hover/drag/focus */}
); }