import { useEffect, useRef, useState, type ReactNode, type TouchEvent } from 'react'; import { cn } from '@/lib/utils'; interface Props { open: boolean; onClose: () => void; children: ReactNode; title?: string; } // Past this drag distance, release dismisses the sheet. const SWIPE_DISMISS_THRESHOLD_PX = 80; export function BottomSheet({ open, onClose, children, title }: Props) { const [dragY, setDragY] = useState(0); const startYRef = useRef(null); useEffect(() => { if (!open) return; const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [open, onClose]); useEffect(() => { if (!open) { setDragY(0); startYRef.current = null; } }, [open]); function onTouchStart(e: TouchEvent) { const t = e.touches[0]; if (!t) return; startYRef.current = t.clientY; } function onTouchMove(e: TouchEvent) { const t = e.touches[0]; if (!t || startYRef.current === null) return; const dy = t.clientY - startYRef.current; // Clamp to downward drags so the sheet doesn't "rubber-band" up. if (dy > 0) setDragY(dy); } function onTouchEnd() { if (dragY > SWIPE_DISMISS_THRESHOLD_PX) { onClose(); } else { setDragY(0); } startYRef.current = null; } if (!open) return null; return ( <>