shadcn, restyled · @jengacore/dialog
Dialog
Modal on a navy-950 45% scrim, radius-lg, shadow-pop, muted footer. Same API as upstream.
Separate Radix and Base UI builds
Install
terminal
npx shadcn@latest add @jengacore/dialogWithout the namespace configured: npx shadcn@latest add https://ui.jengacore.com/r/<new-york-v4|base-nova>/dialog.json
Registry dependencies
npm packages
lucide-reactradix-ui@base-ui/react
Source
components/ui/dialog.tsx
"use client"
import * as React from "react"
import { XIcon } from "lucide-react"
import { Dialog as DialogPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
/**
* Modal dialog. Use for confirmations that repeat the object ("Suspend Equity Bank?") and short forms.
* Record detail goes in a Sheet, not a dialog.
*/
function Dialog(props: React.ComponentProps<typeof DialogPrimitive.Root>) {
return <DialogPrimitive.Root data-slot="dialog" {...props} />
}
function DialogTrigger(props: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
}
function DialogPortal(props: React.ComponentProps<typeof DialogPrimitive.Portal>) {
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
}
function DialogClose(props: React.ComponentProps<typeof DialogPrimitive.Close>) {
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
}
function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
return (
<DialogPrimitive.Overlay
data-slot="dialog-overlay"
className={cn(
"fixed inset-0 z-50 bg-navy-950/45 duration-base data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
className
)}
{...props}
/>
)
}
function DialogContent({
className,
children,
showCloseButton = true,
...props
}: React.ComponentProps<typeof DialogPrimitive.Content> & { showCloseButton?: boolean }) {
return (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
data-slot="dialog-content"
className={cn(
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border border-border bg-popover p-5 text-sm text-popover-foreground shadow-pop outline-none sm:max-w-md",
"duration-enter ease-jc data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:slide-in-from-bottom-1.5 data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
"contrast:border-input",
className
)}
{...props}
>
{children}
{showCloseButton ? (
<DialogPrimitive.Close
data-slot="dialog-close"
className="absolute top-3 right-3 grid size-8 place-items-center rounded-md text-muted-foreground transition-colors duration-fast hover:bg-accent hover:text-foreground focus-ring"
>
<XIcon className="size-4 stroke-[1.75]" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
) : null}
</DialogPrimitive.Content>
</DialogPortal>
)
}
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return <div data-slot="dialog-header" className={cn("flex flex-col gap-1 pr-8", className)} {...props} />
}
function DialogFooter({
className,
showCloseButton = false,
children,
...props
}: React.ComponentProps<"div"> & { showCloseButton?: boolean }) {
return (
<div
data-slot="dialog-footer"
className={cn(
"-mx-5 -mb-5 flex flex-col-reverse gap-2 rounded-b-lg border-t border-border bg-muted/60 px-5 py-3 sm:flex-row sm:justify-end",
className
)}
{...props}
>
{children}
{showCloseButton ? (
<DialogPrimitive.Close className="inline-flex h-[34px] items-center rounded-md border border-border bg-card px-3.5 text-[13.5px] font-medium hover:bg-accent">
Close
</DialogPrimitive.Close>
) : null}
</div>
)
}
function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {
return <DialogPrimitive.Title data-slot="dialog-title" className={cn("text-[15px] leading-[22px] font-semibold", className)} {...props} />
}
function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>) {
return <DialogPrimitive.Description data-slot="dialog-description" className={cn("text-[13.5px] text-muted-foreground", className)} {...props} />
}
export {
Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger,
}