dialog.tsx (4098B)
1 "use client" 2 3 import { Root, Trigger, Portal, Close, Overlay, Content, Title, Description } from "@radix-ui/react-dialog" 4 import { X } from "lucide-react" 5 6 import { cn } from "@/lib/utils" 7 import { forwardRef, ComponentRef, ComponentPropsWithoutRef, HTMLAttributes } from "react" 8 9 const Dialog = Root 10 11 const DialogTrigger = Trigger 12 13 const DialogPortal = Portal 14 15 const DialogClose = Close 16 17 const DialogOverlay = forwardRef< 18 ComponentRef<typeof Overlay>, 19 ComponentPropsWithoutRef<typeof Overlay> 20 >(({ className, ...props }, ref) => ( 21 <Overlay 22 ref={ref} 23 className={cn( 24 "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", 25 className 26 )} 27 {...props} 28 /> 29 )) 30 DialogOverlay.displayName = Overlay.displayName 31 32 const DialogContent = forwardRef< 33 ComponentRef<typeof Content>, 34 ComponentPropsWithoutRef<typeof Content> 35 >(({ className, children, ...props }, ref) => ( 36 <DialogPortal> 37 <DialogOverlay /> 38 <Content 39 ref={ref} 40 className={cn( 41 "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", 42 className 43 )} 44 {...props} 45 > 46 {children} 47 <Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> 48 <X className="h-4 w-4" /> 49 <span className="sr-only">Close</span> 50 </Close> 51 </Content> 52 </DialogPortal> 53 )) 54 DialogContent.displayName = Content.displayName 55 56 const DialogHeader = ({ 57 className, 58 ...props 59 }: HTMLAttributes<HTMLDivElement>) => ( 60 <div 61 className={cn( 62 "flex flex-col space-y-1.5 text-center sm:text-left", 63 className 64 )} 65 {...props} 66 /> 67 ) 68 DialogHeader.displayName = "DialogHeader" 69 70 const DialogFooter = ({ 71 className, 72 ...props 73 }: HTMLAttributes<HTMLDivElement>) => ( 74 <div 75 className={cn( 76 "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", 77 className 78 )} 79 {...props} 80 /> 81 ) 82 DialogFooter.displayName = "DialogFooter" 83 84 const DialogTitle = forwardRef< 85 ComponentRef<typeof Title>, 86 ComponentPropsWithoutRef<typeof Title> 87 >(({ className, ...props }, ref) => ( 88 <Title 89 ref={ref} 90 className={cn( 91 "text-lg font-semibold leading-none tracking-tight", 92 className 93 )} 94 {...props} 95 /> 96 )) 97 DialogTitle.displayName = Title.displayName 98 99 const DialogDescription = forwardRef< 100 ComponentRef<typeof Description>, 101 ComponentPropsWithoutRef<typeof Description> 102 >(({ className, ...props }, ref) => ( 103 <Description 104 ref={ref} 105 className={cn("text-sm text-muted-foreground", className)} 106 {...props} 107 /> 108 )) 109 DialogDescription.displayName = Description.displayName 110 111 // Close Button 112 const DialogCloseButton = forwardRef< 113 ComponentRef<typeof Close>, 114 ComponentPropsWithoutRef<typeof Close> 115 >(({ className, ...props }, ref) => ( 116 <Close 117 ref={ref} 118 className={cn( 119 "p-2 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", 120 className 121 )} 122 {...props} 123 /> 124 )) 125 DialogCloseButton.displayName = Close.displayName 126 127 export { 128 Dialog, 129 DialogPortal, 130 DialogOverlay, 131 DialogClose, 132 DialogTrigger, 133 DialogContent, 134 DialogHeader, 135 DialogFooter, 136 DialogTitle, 137 DialogDescription, 138 DialogCloseButton, 139 }