import React, { useEffect, useRef } from 'react'; import { clsx } from 'clsx'; import { X } from 'lucide-react'; import Button from './Button'; export interface SheetProps { open: boolean; onOpenChange: (open: boolean) => void; children: React.ReactNode; side?: 'left' | 'right' | 'top' | 'bottom'; size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'; className?: string; } const sideClasses = { left: 'left-0 top-0 bottom-0', right: 'right-0 top-0 bottom-0', top: 'top-0 left-0 right-0', bottom: 'bottom-0 left-0 right-0', }; const sizeClasses = { sm: 'w-80', md: 'w-96', lg: 'w-[32rem]', xl: 'w-[42rem]', full: 'w-full', }; const slideAnimations = { left: 'animate-in slide-in-from-left duration-300', right: 'animate-in slide-in-from-right duration-300', top: 'animate-in slide-in-from-top duration-300', bottom: 'animate-in slide-in-from-bottom duration-300', }; /** * Sheet/Drawer component - side panel */ export const Sheet = ({ open, onOpenChange, children, side = 'right', size = 'md', className, }: SheetProps) => { const sheetRef = useRef(null); useEffect(() => { if (open) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } return () => { document.body.style.overflow = ''; }; }, [open]); useEffect(() => { const handleEscape = (e: KeyboardEvent) => { if (e.key === 'Escape' && open) { onOpenChange(false); } }; if (open) { document.addEventListener('keydown', handleEscape); // Focus trap const focusableElements = sheetRef.current?.querySelectorAll( 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' ); const firstElement = focusableElements?.[0] as HTMLElement; firstElement?.focus(); } return () => { document.removeEventListener('keydown', handleEscape); }; }, [open, onOpenChange]); if (!open) return null; return ( <> {/* Backdrop */}
onOpenChange(false)} aria-hidden="true" /> {/* Sheet */}
{children}
); }; export interface SheetHeaderProps extends React.HTMLAttributes { children: React.ReactNode; } export const SheetHeader = ({ children, className, ...props }: SheetHeaderProps) => { return (
{children}
); }; export interface SheetTitleProps extends React.HTMLAttributes { children: React.ReactNode; } export const SheetTitle = ({ children, className, ...props }: SheetTitleProps) => { return (

{children}

); }; export interface SheetDescriptionProps extends React.HTMLAttributes { children: React.ReactNode; } export const SheetDescription = ({ children, className, ...props }: SheetDescriptionProps) => { return (

{children}

); }; export interface SheetContentProps extends React.HTMLAttributes { children: React.ReactNode; } export const SheetContent = ({ children, className, ...props }: SheetContentProps) => { return (
{children}
); }; export interface SheetFooterProps extends React.HTMLAttributes { children: React.ReactNode; } export const SheetFooter = ({ children, className, ...props }: SheetFooterProps) => { return (
{children}
); }; export interface SheetCloseProps { onClose: () => void; className?: string; } export const SheetClose = ({ onClose, className }: SheetCloseProps) => { return ( ); };