| 1 | 'use client' |
| 2 | |
| 3 | import * as DialogPrimitive from '@radix-ui/react-dialog' |
| 4 | import { X } from 'lucide-react' |
| 5 | import * as React from 'react' |
| 6 | import { cn } from '@/utils/className' |
| 7 | |
| 8 | const Sheet = DialogPrimitive.Root |
| 9 | const SheetTrigger = DialogPrimitive.Trigger |
| 10 | const SheetClose = DialogPrimitive.Close |
| 11 | const SheetPortal = DialogPrimitive.Portal |
| 12 | |
| 13 | const SheetOverlay = React.forwardRef< |
| 14 | React.ElementRef<typeof DialogPrimitive.Overlay>, |
| 15 | React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> |
| 16 | >(({ className, ...props }, ref) => ( |
| 17 | <DialogPrimitive.Overlay |
| 18 | ref={ref} |
| 19 | className={cn( |
| 20 | 'fixed inset-0 z-50 bg-foreground/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', |
| 21 | className, |
| 22 | )} |
| 23 | {...props} |
| 24 | /> |
| 25 | )) |
| 26 | SheetOverlay.displayName = DialogPrimitive.Overlay.displayName |
| 27 | |
| 28 | type SheetSide = 'top' | 'right' | 'bottom' | 'left' |
| 29 | |
| 30 | const sheetSideClassMap: Record<SheetSide, string> = { |
| 31 | top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top', |
| 32 | right: 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm', |
| 33 | bottom: 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom', |
| 34 | left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm', |
| 35 | } |
| 36 | |
| 37 | interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> { |
| 38 | side?: SheetSide |
| 39 | overlayClassName?: string |
| 40 | hideCloseButton?: boolean |
| 41 | closeLabel?: string |
| 42 | } |
| 43 | |
| 44 | const SheetContent = React.forwardRef< |
| 45 | React.ElementRef<typeof DialogPrimitive.Content>, |
| 46 | SheetContentProps |
| 47 | >(({ side = 'right', className, children, overlayClassName, hideCloseButton, closeLabel = 'Close', ...props }, ref) => ( |
| 48 | <SheetPortal> |
| 49 | <SheetOverlay className={overlayClassName} /> |
| 50 | <DialogPrimitive.Content |
| 51 | ref={ref} |
| 52 | className={cn( |
| 53 | 'fixed z-50 gap-4 bg-background p-6 shadow-2xl transition ease-in-out data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:duration-300 data-[state=open]:duration-500', |
| 54 | sheetSideClassMap[side], |
| 55 | className, |
| 56 | )} |
| 57 | {...props} |
| 58 | > |
| 59 | {children} |
| 60 | {!hideCloseButton && ( |
| 61 | <DialogPrimitive.Close className="absolute right-4 top-4 rounded-md p-1 opacity-70 ring-offset-background transition-opacity hover:bg-accent hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none"> |
| 62 | <X className="h-4 w-4" /> |
| 63 | <span className="sr-only">{closeLabel}</span> |
| 64 | </DialogPrimitive.Close> |
| 65 | )} |
| 66 | </DialogPrimitive.Content> |
| 67 | </SheetPortal> |
| 68 | )) |
| 69 | SheetContent.displayName = DialogPrimitive.Content.displayName |
| 70 | |
| 71 | function SheetHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) { |
| 72 | return <div className={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...props} /> |
| 73 | } |
| 74 | SheetHeader.displayName = 'SheetHeader' |
| 75 | |
| 76 | function SheetFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) { |
| 77 | return <div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)} {...props} /> |
| 78 | } |
| 79 | SheetFooter.displayName = 'SheetFooter' |
| 80 | |
| 81 | const SheetTitle = React.forwardRef< |
| 82 | React.ElementRef<typeof DialogPrimitive.Title>, |
| 83 | React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> |
| 84 | >(({ className, ...props }, ref) => ( |
| 85 | <DialogPrimitive.Title ref={ref} className={cn('text-lg font-semibold text-foreground', className)} {...props} /> |
| 86 | )) |
| 87 | SheetTitle.displayName = DialogPrimitive.Title.displayName |
| 88 | |
| 89 | const SheetDescription = React.forwardRef< |
| 90 | React.ElementRef<typeof DialogPrimitive.Description>, |
| 91 | React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> |
| 92 | >(({ className, ...props }, ref) => ( |
| 93 | <DialogPrimitive.Description ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} /> |
| 94 | )) |
| 95 | SheetDescription.displayName = DialogPrimitive.Description.displayName |
| 96 | |
| 97 | export { |
| 98 | Sheet, |
| 99 | SheetClose, |
| 100 | SheetContent, |
| 101 | SheetDescription, |
| 102 | SheetFooter, |
| 103 | SheetHeader, |
| 104 | SheetOverlay, |
| 105 | SheetPortal, |
| 106 | SheetTitle, |
| 107 | SheetTrigger, |
| 108 | } |
| 109 |