{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dialog",
  "type": "registry:ui",
  "title": "Dialog",
  "description": "@interlace/ui — dialog primitive (shadcn-compatible).",
  "dependencies": [
    "@base-ui-components/react",
    "lucide-react"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/interlace-ui/dialog.tsx",
      "target": "components/ui/dialog.tsx",
      "type": "registry:ui",
      "content": "'use client';\n\n/**\n * @interlace/ui — Dialog (gold-standard reference for the interlace-component skill)\n *\n * This file is the canonical example of the portable component-modeling floor.\n * Every rule R1–R26 from `skills/interlace-component/SKILL.md` that is applicable\n * to a Dialog primitive is illustrated here.\n *\n * | Rule | Concept                          | Where in this file                                            |\n * | ---- | -------------------------------- | ------------------------------------------------------------- |\n * | R4   | Extends native el + JSDoc        | `React.ComponentProps<typeof BaseDialog.*>` on every export   |\n * | R5   | data-testid type-required        | Inherited via consumer-supplied `data-testid` on `...props`   |\n * | R6   | data-slot on every named part    | `data-slot=\"dialog\"` / `\"dialog-trigger\"` / `\"dialog-portal\"` / `\"dialog-close\"` / `\"dialog-overlay\"` / `\"dialog-popup\"` |\n * | R7   | className merged + ...rest + ref | `cn(...)` merged className; `{...props}` spread to root       |\n * | R8   | No `isXxx` prefix on booleans    | All boolean props inherited from Base UI use the no-`is` form |\n * | R11  | Composition over prop-drilling   | DialogContent / DialogHeader / DialogFooter / DialogTitle / DialogDescription compound parts |\n * | R12  | Reuse primitives — don't wrap    | XIcon from lucide-react is slotted, not wrapped in a `DialogCloseIcon` |\n * | R13  | Build with the ecosystem         | `@base-ui-components/react/dialog` provides keyboard / focus / portal / ARIA |\n * | R14  | Controlled + uncontrolled        | Inherited from `BaseDialog.Root` — `open` + `onOpenChange` + `defaultOpen` |\n * | R16  | No internal coupling             | DialogClose accepts children; consumer slots their own button if needed |\n * | R17  | API parity with MUI/shadcn       | Shape mirrors shadcn/ui Dialog + Base UI primitives — no deviation |\n * | R18  | Tailwind only — no inline style  | Every visual class is Tailwind; zero `style={{}}` in this file |\n * | R19  | Tokens only — no raw hex/rgba    | Visual classes use theme tokens (`bg-background`, `text-foreground`, `border`) |\n * | R20  | AA contrast                      | Tokens guarantee contrast in light + dark via the theme       |\n * | R23  | CLS=0                            | Overlay is positioned via `fixed inset-0`; no layout shift     |\n * | R24  | Product-neutral vocabulary       | All names structural (`Dialog`, `Title`, `Description`, `Footer`) — no domain terms |\n * | R26  | A11y from headless primitive     | All ARIA / keyboard / focus handled by `@base-ui-components/react/dialog` |\n *\n * Out of scope here (rules that don't apply to this primitive):\n * - R3 / R12 (RFC, wrappers) — this is shipped reference code, not a new RFC.\n * - R9 / R10 — event shape inherited from Base UI; sub-element access is via slots, not `xxxProps`.\n * - R21 / R22 — layout primitives (Section/Container) are sibling components, not Dialog concerns.\n * - R25 — `'use client'` is correct for an interactive dialog; not a server component.\n *\n * Consumer-side, this file is the answer to \"what does a state-of-the-art primitive look like?\"\n */\n\nimport * as React from 'react';\nimport { Dialog as BaseDialog } from '@base-ui-components/react/dialog';\nimport { XIcon } from 'lucide-react';\n\nimport { cn } from '../lib/cn.js';\n\nfunction Dialog(props: React.ComponentProps<typeof BaseDialog.Root>) {\n  return <BaseDialog.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger(\n  props: React.ComponentProps<typeof BaseDialog.Trigger>,\n) {\n  return <BaseDialog.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal(props: React.ComponentProps<typeof BaseDialog.Portal>) {\n  return <BaseDialog.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose(props: React.ComponentProps<typeof BaseDialog.Close>) {\n  return <BaseDialog.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseDialog.Backdrop>) {\n  return (\n    <BaseDialog.Backdrop\n      data-slot=\"dialog-overlay\"\n      className={cn(\n        'data-[open]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[open]:fade-in-0 fixed inset-0 z-50 bg-black/50',\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DialogContent({\n  className,\n  children,\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof BaseDialog.Popup> & {\n  showCloseButton?: boolean;\n}) {\n  return (\n    <DialogPortal>\n      <DialogOverlay />\n      <BaseDialog.Popup\n        data-slot=\"dialog-content\"\n        className={cn(\n          'bg-background data-[open]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[open]:fade-in-0 data-[closed]:zoom-out-95 data-[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',\n          className,\n        )}\n        {...props}\n      >\n        {children}\n        {showCloseButton ? (\n          <BaseDialog.Close\n            data-slot=\"dialog-close\"\n            className=\"ring-offset-background focus:ring-ring data-[open]:bg-accent data-[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\"\n          >\n            <XIcon />\n            <span className=\"sr-only\">Close</span>\n          </BaseDialog.Close>\n        ) : null}\n      </BaseDialog.Popup>\n    </DialogPortal>\n  );\n}\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\nfunction DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {\n  return (\n    <div\n      data-slot=\"dialog-footer\"\n      className={cn(\n        'flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseDialog.Title>) {\n  return (\n    <BaseDialog.Title\n      data-slot=\"dialog-title\"\n      className={cn('text-lg leading-none font-semibold', className)}\n      {...props}\n    />\n  );\n}\n\nfunction DialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseDialog.Description>) {\n  return (\n    <BaseDialog.Description\n      data-slot=\"dialog-description\"\n      className={cn('text-muted-foreground text-sm', 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};\n"
    }
  ]
}
