"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}
>
)}
);
}