open-prompt / src /components /ui /dialog.tsx
GitHub Action
Automated sync to Hugging Face
bcce530
"use client"
import * as React from "react"
import { cn } from "@/lib/utils"
import { X } from "lucide-react"
interface DialogProps {
open?: boolean
onOpenChange?: (open: boolean) => void
children: React.ReactNode
}
const DialogContext = React.createContext<{
open: boolean
setOpen: (open: boolean) => void
} | null>(null)
function Dialog({ open: controlledOpen, onOpenChange, children }: DialogProps) {
const [internalOpen, setInternalOpen] = React.useState(false)
const open = controlledOpen !== undefined ? controlledOpen : internalOpen
const setOpen = onOpenChange || setInternalOpen
return (
<DialogContext.Provider value={{ open, setOpen }}>
{children}
</DialogContext.Provider>
)
}
function useDialog() {
const context = React.useContext(DialogContext)
if (!context) {
throw new Error("useDialog must be used within a Dialog")
}
return context
}
interface DialogTriggerProps {
children: React.ReactNode
asChild?: boolean
}
function DialogTrigger({ children, asChild }: DialogTriggerProps) {
const { setOpen } = useDialog()
if (asChild && React.isValidElement(children)) {
return React.cloneElement(children as React.ReactElement<any>, {
onClick: (e: React.MouseEvent) => {
(children as React.ReactElement<any>).props.onClick?.(e)
setOpen(true)
}
})
}
return (
<button onClick={() => setOpen(true)}>
{children}
</button>
)
}
interface DialogContentProps {
children: React.ReactNode
className?: string
}
function DialogContent({ children, className }: DialogContentProps) {
const { open, setOpen } = useDialog()
if (!open) return null
return (
<div className="fixed inset-0 z-50">
{/* Backdrop */}
<div
className="fixed inset-0 bg-black/80"
onClick={() => setOpen(false)}
/>
{/* Content */}
<div className="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 sm:rounded-lg">
<div className={cn("", className)}>
{children}
</div>
{/* Close button */}
<button
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"
onClick={() => setOpen(false)}
>
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</button>
</div>
</div>
)
}
function DialogHeader({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)}
{...props}
/>
)
}
function DialogTitle({
className,
...props
}: React.HTMLAttributes<HTMLHeadingElement>) {
return (
<h2
className={cn("text-lg font-semibold leading-none tracking-tight", className)}
{...props}
/>
)
}
function DialogDescription({
className,
...props
}: React.HTMLAttributes<HTMLParagraphElement>) {
return (
<p
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
)
}
export {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
}