{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dialog",
  "type": "registry:ui",
  "title": "Dialog",
  "description": "Modal overlay for focused tasks and forms, with animated enter/exit and focus trapping.",
  "dependencies": [
    "@radix-ui/react-dialog",
    "@saasflare/ui",
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/dialog.tsx",
      "type": "registry:ui",
      "content": "// @toreview\n\"use client\"\n\n/**\n * @fileoverview Saasflare Dialog — modal overlay with spring entry animation.\n * @module packages/ui/components/ui/dialog\n * @layer core\n *\n * Self-contained implementation using Radix Dialog primitive directly.\n * Entry animation (Motion spring) respects reduced-motion preference and the\n * `animated` axis; exit is handled by Radix CSS state classes because Radix\n * unmounts Content on close (no AnimatePresence wrapper keeps the node mounted).\n *\n * @example\n * import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle } from \"@saasflare/ui\";\n * <Dialog>\n *   <DialogTrigger asChild><Button>Open</Button></DialogTrigger>\n *   <DialogContent>\n *     <DialogHeader><DialogTitle>Edit Profile</DialogTitle></DialogHeader>\n *   </DialogContent>\n * </Dialog>\n */\n\nimport * as React from \"react\"\nimport { m } from \"motion/react\"\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\"\nimport { XIcon } from \"@saasflare/ui\"\nimport { cn } from \"@saasflare/ui\"\nimport { useSaasflareProps, type SaasflareComponentProps } from \"@saasflare/ui\"\nimport { useSaasflareMotion, springBouncy } from \"@saasflare/ui\"\n\n/**\n * Dialog root. Controls open/close state for the modal.\n *\n * @component\n * @layer core\n */\nfunction Dialog({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n  return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />\n}\n\n/**\n * Element that toggles the dialog open. Use `asChild` to compose with a Button.\n *\n * @component\n * @layer core\n */\nfunction DialogTrigger({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n  return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />\n}\n\n/**\n * Portals dialog content into the document body, escaping overflow/stacking contexts.\n *\n * @component\n * @layer core\n */\nfunction DialogPortal({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n  return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />\n}\n\n/**\n * Element that closes the dialog when activated. Use `asChild` to compose.\n *\n * @component\n * @layer core\n */\nfunction DialogClose({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n  return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />\n}\n\n/**\n * Backdrop scrim rendered behind the dialog content.\n *\n * @component\n * @layer core\n */\nfunction DialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n  return (\n    <DialogPrimitive.Overlay\n      data-slot=\"dialog-overlay\"\n      className={cn(\n        \"fixed inset-0 z-50 bg-black/50 backdrop-blur-[2px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\n/**\n * Props for {@link DialogContent}.\n *\n * Extends the Radix Dialog Content props with {@link SaasflareComponentProps},\n * so `surface`, `radius`, `animated`, and `iconWeight` can be supplied\n * per-instance or inherited from <SaasflareProvider>.\n */\ninterface DialogContentProps\n  extends Omit<React.ComponentProps<typeof DialogPrimitive.Content>, keyof SaasflareComponentProps>,\n    SaasflareComponentProps {\n  /**\n   * Render the built-in top-right close button (X).\n   * @default true — preserves current behavior; set `false` to supply your own\n   *                 DialogClose (e.g. command palettes, full-bleed media dialogs).\n   *                 Esc-to-close and overlay-click-to-close remain active, so the\n   *                 dialog stays escapable even when the button is hidden.\n   */\n  showCloseButton?: boolean\n}\n\n/**\n * Dialog content panel with spring entry animation.\n *\n * @component\n * @layer core\n */\nfunction DialogContent({\n  className,\n  children,\n  showCloseButton = true,\n  surface,\n  radius,\n  animated,\n  iconWeight,\n  ...props\n}: DialogContentProps) {\n  const sf = useSaasflareProps({ surface, radius, animated, iconWeight })\n  const motion = useSaasflareMotion(sf.animated, springBouncy)\n\n  return (\n    <DialogPortal>\n      <DialogOverlay />\n      <DialogPrimitive.Content\n        {...props}\n        data-slot=\"dialog-content\"\n        asChild\n      >\n        <m.div\n          data-surface={sf.surface}\n          data-radius={sf.radius}\n          data-animated={String(sf.animated)}\n          initial={motion.disabled ? { opacity: 1 } : { opacity: 0, scale: 0.95, y: 10 }}\n          animate={{ opacity: 1, scale: 1, y: 0 }}\n          transition={motion.transition}\n          className={cn(\n            \"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 surface-card p-6 sm:max-w-lg data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95\",\n            className\n          )}\n        >\n          {children}\n          {showCloseButton && (\n            <DialogPrimitive.Close className=\"absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none cursor-pointer [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\">\n              <XIcon weight={sf.iconWeight} />\n              <span className=\"sr-only\">Close</span>\n            </DialogPrimitive.Close>\n          )}\n        </m.div>\n      </DialogPrimitive.Content>\n    </DialogPortal>\n  )\n}\n\n/**\n * Header region for the dialog title and description.\n *\n * @component\n * @layer core\n */\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-header\"\n      className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n      {...props}\n    />\n  )\n}\n\n/**\n * Footer region for dialog actions (e.g. confirm/cancel buttons).\n *\n * @component\n * @layer core\n */\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-footer\"\n      className={cn(\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\", className)}\n      {...props}\n    />\n  )\n}\n\n/**\n * Accessible title for the dialog, announced to screen readers.\n *\n * @component\n * @layer core\n */\nfunction DialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n  return (\n    <DialogPrimitive.Title\n      data-slot=\"dialog-title\"\n      className={cn(\"text-lg leading-none font-semibold\", className)}\n      {...props}\n    />\n  )\n}\n\n/**\n * Accessible supporting description for the dialog.\n *\n * @component\n * @layer core\n */\nfunction DialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n  return (\n    <DialogPrimitive.Description\n      data-slot=\"dialog-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogOverlay,\n  DialogPortal,\n  DialogTitle,\n  DialogTrigger,\n  type DialogContentProps,\n}\n",
      "target": "components/ui/dialog.tsx"
    }
  ],
  "$meta": {
    "source": "https://ui.saasflare.io/r/dialog.json"
  }
}
