← full-stack-fastapi-template  /  frontend/src/components/ui/dialog.tsx

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