{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dialog",
  "title": "Dialog",
  "description": "Rises from below out of a blur, then its title, fields and buttons arrive one after another.",
  "dependencies": [
    "@ui-sdk/core@0.1.0-beta.2",
    "@ui-sdk/react@0.1.0-beta.2"
  ],
  "registryDependencies": [
    "@keyframery/motion"
  ],
  "files": [
    {
      "path": "registry/components/keyframery/primitives/dialog.tsx",
      "content": "\"use client\"\n\n/* Animated drop-in for `@ui-sdk/react/dialog`: same parts, same props. Swap the import and keep\n   your code. This file adds motion only. Colours, radii, shadows and spacing stay yours. */\n\nimport {\n  DialogBackdrop as DialogBackdropPart,\n  DialogClose as DialogClosePart,\n  DialogContent as DialogContentPart,\n  DialogTrigger as DialogTriggerPart,\n} from \"@ui-sdk/react/dialog\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport * from \"@ui-sdk/react/dialog\"\n\n/* Press: the key gives under the finger and springs back on release. */\nconst press =\n  \"transition-[scale] duration-[calc(200ms*var(--kf-speed,1))] ease-pop not-data-disabled:not-data-pending:active:scale-[0.96] motion-reduce:transition-none!\"\n\n/* Cascade: each direct child of the content (a header, a body, a footer) rises in out of a blur a\n   little after the one before it. It is a keyframe animation rather than a transition because the\n   children have no earlier style to transition from when the content first appears. Close buttons\n   and arrows are left out so their own presses stay quick, and nothing on the children transitions,\n   so a hover is never delayed. */\nconst cascadeKeyframes = \"@keyframes kf-cascade{from{opacity:0;translate:0 8px;filter:blur(4px)}}@media (prefers-reduced-motion:reduce){@keyframes kf-cascade{from{opacity:0}}}\"\nconst cascade = cn(\n  \"[&>*:not([data-slot$=-close],[data-slot$=-arrow])]:animate-[kf-cascade_calc(420ms*var(--kf-speed,1))_var(--ease-spring)_backwards]\",\n  \"[&>*:not([data-slot$=-close],[data-slot$=-arrow])]:[animation-delay:calc(calc(40ms*var(--kf-speed,1))+(min(sibling-index(),10)-1)*calc(40ms*var(--kf-speed,1)))]\",\n  \"motion-reduce:[&>*]:animate-none\",\n)\n\nfunction DialogTrigger({ className, ...props }: React.ComponentProps<typeof DialogTriggerPart>) {\n  return <DialogTriggerPart className={cn(press, className)} {...props} />\n}\n\nfunction DialogClose({ className, ...props }: React.ComponentProps<typeof DialogClosePart>) {\n  return <DialogClosePart className={cn(press, className)} {...props} />\n}\n\n/* The page behind softens into a blur as it dims, and clears faster than it came. */\nfunction DialogBackdrop({ className, ...props }: React.ComponentProps<typeof DialogBackdropPart>) {\n  return (\n    <DialogBackdropPart\n      className={cn(\n        \"backdrop-blur-[4px] transition-[opacity,backdrop-filter] duration-[calc(380ms*var(--kf-speed,1))] ease-house\",\n        \"data-starting-style:opacity-0 data-starting-style:backdrop-blur-none\",\n        \"data-ending-style:opacity-0 data-ending-style:backdrop-blur-none data-ending-style:duration-[calc(180ms*var(--kf-speed,1))]\",\n        \"motion-reduce:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Unfold from below: the sheet rises 24px out of a blur, grows from 0.9 and settles on a spring,\n   then its sections cascade in. It leaves quickly, sinking a little. */\nfunction DialogContent<Payload = unknown>({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogContentPart<Payload>>) {\n  return (\n    <>\n      <style href=\"kf-cascade\" precedence=\"default\">\n        {cascadeKeyframes}\n      </style>\n      <DialogContentPart<Payload>\n        className={cn(\n          \"group/dialog transition-[opacity,scale,translate,filter] duration-[calc(420ms*var(--kf-speed,1))] ease-spring\",\n          \"data-starting-style:translate-y-6 data-starting-style:scale-[0.9] data-starting-style:opacity-0 data-starting-style:blur-[8px]\",\n          \"data-ending-style:translate-y-2 data-ending-style:scale-[0.96] data-ending-style:opacity-0 data-ending-style:blur-[4px] data-ending-style:duration-[calc(180ms*var(--kf-speed,1))] data-ending-style:ease-house\",\n          \"data-nested-open:scale-[0.95] data-nested-open:opacity-70\",\n          cascade,\n          \"motion-reduce:transition-none!\",\n          className,\n        )}\n        {...props}\n      />\n    </>\n  )\n}\n\nexport { DialogBackdrop, DialogClose, DialogContent, DialogTrigger }\n",
      "type": "registry:component",
      "target": "components/keyframery/primitives/dialog.tsx"
    },
    {
      "path": "registry/components/keyframery/dialog.tsx",
      "content": "\"use client\"\n\n/* Styled dialog: the animated primitive plus the Keyframery look. */\n\nimport {\n  Dialog as DialogRoot,\n  DialogBackdrop as DialogBackdropPart,\n  DialogClose as DialogClosePart,\n  DialogContent as DialogContentPart,\n  DialogDescription as DialogDescriptionPart,\n  DialogShortcut as DialogShortcutPart,\n  DialogTitle as DialogTitlePart,\n  DialogTrigger as DialogTriggerPart,\n} from \"@/components/keyframery/primitives/dialog\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype DialogCloseVariant = \"default\" | \"primary\" | \"destructive\" | \"icon\"\n\n/* A key: the thing you press. Shared by the trigger and the close buttons. */\nconst keyBase = cn(\n  \"inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 leading-none font-medium whitespace-nowrap outline-none select-none [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n  /* The primitive presses the key; colour and shadow ride the same 200ms pop. */\n  \"transition-[color,background-color,box-shadow,opacity,scale] duration-[calc(200ms*var(--kf-speed,1))] ease-pop\",\n  \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n  \"data-disabled:cursor-not-allowed data-disabled:opacity-50 data-pending:cursor-progress data-pending:opacity-70\",\n  \"motion-reduce:transition-none!\",\n)\n\nconst keySurface = cn(\n  \"bg-background text-foreground dark:bg-accent\",\n  \"shadow-[0_0_0_1px_rgb(0_0_0/0.06),0_1px_1px_rgb(0_0_0/0.05),0_3px_6px_-2px_rgb(0_0_0/0.1)]\",\n  \"dark:shadow-[0_0_0_1px_rgb(255_255_255/0.07),inset_0_1px_0_rgb(255_255_255/0.08),0_2px_6px_-1px_rgb(0_0_0/0.6)]\",\n  \"not-data-disabled:hover:bg-[color-mix(in_oklab,var(--background),var(--foreground)_3%)]\",\n  \"dark:not-data-disabled:hover:bg-[color-mix(in_oklab,var(--accent),var(--foreground)_7%)]\",\n  \"not-data-disabled:hover:shadow-[0_0_0_1px_rgb(0_0_0/0.1),0_1px_1px_rgb(0_0_0/0.05),0_4px_8px_-2px_rgb(0_0_0/0.12)]\",\n  \"dark:not-data-disabled:hover:shadow-[0_0_0_1px_rgb(255_255_255/0.12),inset_0_1px_0_rgb(255_255_255/0.1),0_2px_6px_-1px_rgb(0_0_0/0.6)]\",\n  \"not-data-disabled:active:shadow-[0_0_0_1px_rgb(0_0_0/0.1),0_1px_1px_rgb(0_0_0/0.04),0_1px_2px_-1px_rgb(0_0_0/0.06)]\",\n  \"dark:not-data-disabled:active:shadow-[0_0_0_1px_rgb(255_255_255/0.09),inset_0_1px_0_rgb(255_255_255/0.04),0_1px_2px_-1px_rgb(0_0_0/0.6)]\",\n)\n\nconst closeVariants: Record<DialogCloseVariant, string> = {\n  default: cn(keySurface, \"h-8 rounded-[9px] px-3 text-[13px] [&_svg]:size-4\"),\n  primary: cn(\n    \"h-8 rounded-[9px] px-3 text-[13px] [&_svg]:size-4\",\n    \"bg-primary text-primary-foreground\",\n    \"shadow-[inset_0_1px_0_rgb(255_255_255/0.14),0_1px_2px_rgb(0_0_0/0.25)]\",\n    \"dark:shadow-[inset_0_1px_0_rgb(255_255_255/0.7),0_1px_2px_rgb(0_0_0/0.5)]\",\n    \"not-data-disabled:hover:bg-[color-mix(in_oklab,var(--primary),var(--background)_14%)]\",\n    \"not-data-disabled:active:shadow-[inset_0_1px_0_rgb(255_255_255/0.08),0_0_1px_rgb(0_0_0/0.3)]\",\n  ),\n  destructive: cn(\n    \"h-8 rounded-[9px] px-3 text-[13px] [&_svg]:size-4\",\n    \"bg-destructive text-background dark:bg-[color-mix(in_oklab,var(--destructive),var(--background)_24%)] dark:text-foreground\",\n    \"shadow-[inset_0_1px_0_rgb(255_255_255/0.18),0_1px_2px_rgb(0_0_0/0.2)]\",\n    \"dark:shadow-[inset_0_1px_0_rgb(255_255_255/0.16),0_1px_2px_rgb(0_0_0/0.5)]\",\n    \"not-data-disabled:hover:bg-[color-mix(in_oklab,var(--destructive),var(--foreground)_10%)]\",\n    \"dark:not-data-disabled:hover:bg-[color-mix(in_oklab,var(--destructive),var(--background)_14%)]\",\n    \"not-data-disabled:active:shadow-[inset_0_1px_0_rgb(255_255_255/0.08),0_0_1px_rgb(0_0_0/0.3)]\",\n  ),\n  /* The small corner key that closes the dialog. */\n  icon: cn(\n    keySurface,\n    \"absolute top-3.5 right-3.5 size-7 rounded-[8px] text-muted-foreground not-data-disabled:hover:text-foreground [&_svg]:size-3.5\",\n  ),\n}\n\nfunction XIcon() {\n  return (\n    <svg\n      viewBox=\"0 0 16 16\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"1.5\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      aria-hidden\n    >\n      <path d=\"M4.5 4.5l7 7M11.5 4.5l-7 7\" />\n    </svg>\n  )\n}\n\nfunction Dialog(props: React.ComponentProps<typeof DialogRoot>) {\n  return <DialogRoot {...props} />\n}\n\n/* A key by default. Pass `render` to use a button of your own instead. */\nfunction DialogTrigger({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogTriggerPart>) {\n  return (\n    <DialogTriggerPart\n      className={cn(\n        !props.render && [keyBase, keySurface, \"h-8 rounded-[9px] px-3 text-[13px] [&_svg]:size-4\"],\n        props.render && \"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The page dims behind the dialog. The primitive blurs it in and out. */\nfunction DialogBackdrop({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogBackdropPart>) {\n  return (\n    <DialogBackdropPart\n      className={cn(\"fixed inset-0 bg-black/25 dark:bg-black/55\", className)}\n      {...props}\n    />\n  )\n}\n\n/* The sheet. The primitive unfolds it from below and cascades its sections in. */\nfunction DialogContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogContentPart>) {\n  return (\n    <DialogContentPart\n      className={cn(\n        \"fixed inset-0 m-auto h-fit max-h-[calc(100dvh-32px)] w-[min(440px,calc(100vw-32px))] max-w-none overflow-y-auto overscroll-contain\",\n        \"border-0 p-5 outline-none backdrop:bg-transparent\",\n        \"rounded-[18px] bg-popover text-popover-foreground\",\n        \"shadow-[0_0_0_1px_rgb(0_0_0/0.06),0_2px_6px_-2px_rgb(0_0_0/0.08),0_24px_56px_-12px_rgb(0_0_0/0.28)]\",\n        \"dark:shadow-[0_0_0_1px_rgb(255_255_255/0.08),0_24px_56px_-12px_rgb(0_0_0/0.8)]\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Title and description stacked, with room for the corner close key. */\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-header\"\n      className={cn(\"flex flex-col gap-1 pr-9\", className)}\n      {...props}\n    />\n  )\n}\n\n/* The answers, right-aligned at the foot of the sheet. */\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-footer\"\n      className={cn(\"mt-5 flex items-center justify-end gap-2\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogTitlePart>) {\n  return (\n    <DialogTitlePart\n      className={cn(\"text-[15px] leading-5 font-semibold tracking-tight\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogDescriptionPart>) {\n  return (\n    <DialogDescriptionPart\n      className={cn(\"text-[13px] leading-5 text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\n/* A key. `variant=\"icon\"` is the small corner key with an X, and needs no children. */\nfunction DialogClose({\n  className,\n  variant = \"default\",\n  children,\n  ...props\n}: React.ComponentProps<typeof DialogClosePart> & { variant?: DialogCloseVariant }) {\n  return (\n    <DialogClosePart\n      data-variant={variant}\n      aria-label={variant === \"icon\" && !children ? \"Close\" : undefined}\n      className={cn(!props.render && [keyBase, closeVariants[variant]], className)}\n      {...props}\n    >\n      {variant === \"icon\" && !children ? <XIcon /> : children}\n    </DialogClosePart>\n  )\n}\n\nfunction DialogShortcut({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogShortcutPart>) {\n  return (\n    <DialogShortcutPart\n      className={cn(\n        \"ms-1 text-[12px] leading-none tracking-[0.04em] text-muted-foreground tabular-nums\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Dialog,\n  DialogBackdrop,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogShortcut,\n  DialogTitle,\n  DialogTrigger,\n}\n",
      "type": "registry:component",
      "target": "components/keyframery/dialog.tsx"
    }
  ],
  "type": "registry:component"
}