import { useEffect, useRef, useState, type ReactNode } from "react"; interface AnimatedPanelProps { open: boolean; children: ReactNode; className?: string; /** Duration in ms for the exit animation before unmounting. */ exitDuration?: number; } export function AnimatedPanel({ open, children, className, exitDuration = 140 }: AnimatedPanelProps) { const [mounted, setMounted] = useState(open); const [visible, setVisible] = useState(open); const timerRef = useRef(null); useEffect(() => { if (open) { if (timerRef.current) { window.clearTimeout(timerRef.current); timerRef.current = null; } setMounted(true); requestAnimationFrame(() => { requestAnimationFrame(() => { setVisible(true); }); }); } else { setVisible(false); timerRef.current = window.setTimeout(() => { setMounted(false); timerRef.current = null; }, exitDuration); } }, [open, exitDuration]); useEffect(() => { return () => { if (timerRef.current) { window.clearTimeout(timerRef.current); } }; }, []); if (!mounted) return null; return (
{children}
); }