"use client"; import { AnimatePresence, motion } from "motion/react"; import { useCallback, useEffect } from "react"; import { useMediaQuery } from "@/hooks/use-media-query"; import { SLIDEOUT_PANEL_OPENED_EVENT } from "@/lib/layout-events"; interface SidebarSlideOutPanelProps { open: boolean; onOpenChange: (open: boolean) => void; ariaLabel: string; width?: number; children: React.ReactNode; } /** * Reusable slide-out panel that extends from the sidebar. * * Desktop: absolutely positioned at the sidebar's right edge, overlaying the main * content with a blur backdrop. Does not push/shrink the main content. * * Mobile: full-width absolute overlay (unchanged). */ export function SidebarSlideOutPanel({ open, onOpenChange, ariaLabel, width = 360, children, }: SidebarSlideOutPanelProps) { const isMobile = !useMediaQuery("(min-width: 640px)"); useEffect(() => { if (open) { window.dispatchEvent(new Event(SLIDEOUT_PANEL_OPENED_EVENT)); } }, [open]); const handleEscape = useCallback( (e: KeyboardEvent) => { if (e.key === "Escape") onOpenChange(false); }, [onOpenChange] ); useEffect(() => { if (!open) return; document.addEventListener("keydown", handleEscape); return () => document.removeEventListener("keydown", handleEscape); }, [open, handleEscape]); if (isMobile) { return ( {open && (
{children}
)}
); } return ( {open && ( <> {/* Blur backdrop covering the main content area (right of sidebar) */} onOpenChange(false)} aria-hidden="true" /> {/* Panel extending from sidebar's right edge, flush with the wrapper border */}
{children}
)}
); }