dialog.tsx
1 import * as React from 'react'; 2 import { XIcon } from 'lucide-react'; 3 import { Dialog as DialogPrimitive } from 'radix-ui'; 4 5 import { cn } from '@/lib/utils'; 6 import { Button } from '@/components/ui/button'; 7 8 function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) { 9 return <DialogPrimitive.Root data-slot="dialog" {...props} />; 10 } 11 12 function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) { 13 return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />; 14 } 15 16 function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) { 17 return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />; 18 } 19 20 function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) { 21 return <DialogPrimitive.Close data-slot="dialog-close" {...props} />; 22 } 23 24 function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>) { 25 return ( 26 <DialogPrimitive.Overlay 27 data-slot="dialog-overlay" 28 className={cn( 29 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50 backdrop-blur-sm', 30 className 31 )} 32 {...props} 33 /> 34 ); 35 } 36 37 function DialogContent({ 38 className, 39 children, 40 showCloseButton = true, 41 ...props 42 }: React.ComponentProps<typeof DialogPrimitive.Content> & { 43 showCloseButton?: boolean; 44 }) { 45 return ( 46 <DialogPortal data-slot="dialog-portal"> 47 <DialogOverlay /> 48 <DialogPrimitive.Content 49 data-slot="dialog-content" 50 className={cn( 51 'bg-background 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 fixed top-[10vh] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg', 52 className 53 )} 54 {...props} 55 > 56 {children} 57 {showCloseButton && ( 58 <DialogPrimitive.Close 59 data-slot="dialog-close" 60 className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4" 61 > 62 <XIcon /> 63 <span className="sr-only">Close</span> 64 </DialogPrimitive.Close> 65 )} 66 </DialogPrimitive.Content> 67 </DialogPortal> 68 ); 69 } 70 71 function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { 72 return ( 73 <div 74 data-slot="dialog-header" 75 className={cn('flex flex-col gap-2 text-center sm:text-left', className)} 76 {...props} 77 /> 78 ); 79 } 80 81 function DialogFooter({ 82 className, 83 showCloseButton = false, 84 children, 85 ...props 86 }: React.ComponentProps<'div'> & { 87 showCloseButton?: boolean; 88 }) { 89 return ( 90 <div 91 data-slot="dialog-footer" 92 className={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)} 93 {...props} 94 > 95 {children} 96 {showCloseButton && ( 97 <DialogPrimitive.Close asChild> 98 <Button variant="outline">Close</Button> 99 </DialogPrimitive.Close> 100 )} 101 </div> 102 ); 103 } 104 105 function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) { 106 return ( 107 <DialogPrimitive.Title 108 data-slot="dialog-title" 109 className={cn('text-lg leading-none font-semibold', className)} 110 {...props} 111 /> 112 ); 113 } 114 115 function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>) { 116 return ( 117 <DialogPrimitive.Description 118 data-slot="dialog-description" 119 className={cn('text-muted-foreground text-sm', className)} 120 {...props} 121 /> 122 ); 123 } 124 125 export { 126 Dialog, 127 DialogClose, 128 DialogContent, 129 DialogDescription, 130 DialogFooter, 131 DialogHeader, 132 DialogOverlay, 133 DialogPortal, 134 DialogTitle, 135 DialogTrigger, 136 };