{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sonner",
  "type": "registry:ui",
  "title": "Toast",
  "description": "Provider-based tactile notifications with status semantics and dismissal.",
  "dependencies": [
    "clsx",
    "tailwind-merge",
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/ui/sonner.tsx",
      "content": "import * as React from 'react'\nimport { CheckCircle2, Info, X, XCircle } from 'lucide-react'\nimport { cn } from '@/lib/utils'\n\nexport type ToastVariant = 'default' | 'success' | 'error' | 'info'\n\nexport interface ToastData {\n  id: string\n  title: React.ReactNode\n  description?: React.ReactNode\n  variant?: ToastVariant\n}\n\nexport interface ToastOptions {\n  title: React.ReactNode\n  description?: React.ReactNode\n  variant?: ToastVariant\n}\n\ninterface ToastContextValue {\n  toast: (options: ToastOptions) => string\n  dismiss: (id: string) => void\n}\n\nconst ToastContext = React.createContext<ToastContextValue | null>(null)\n\nconst variantClasses: Record<ToastVariant, string> = {\n  default: 'bg-rk-surface',\n  success: 'bg-rk-mint',\n  error: 'bg-rk-error',\n  info: 'bg-rk-sky',\n}\n\nexport function ToastProvider({ children, duration = 4000 }: { children: React.ReactNode; duration?: number }) {\n  const [toasts, setToasts] = React.useState<ToastData[]>([])\n\n  const dismiss = React.useCallback((id: string) => setToasts((current) => current.filter((toast) => toast.id !== id)), [])\n  const toast = React.useCallback((options: ToastOptions) => {\n    const id = `${Date.now()}-${Math.random().toString(36).slice(2)}`\n    setToasts((current) => [...current, { ...options, id }])\n    if (duration > 0) window.setTimeout(() => dismiss(id), duration)\n    return id\n  }, [dismiss, duration])\n\n  return (\n    <ToastContext.Provider value={{ toast, dismiss }}>\n      {children}\n      <div aria-live=\"polite\" aria-atomic=\"false\" className=\"fixed inset-x-4 bottom-4 z-[60] flex flex-col items-end gap-3 sm:left-auto sm:w-96\">\n        {toasts.map((item) => (\n          <div key={item.id} role={item.variant === 'error' ? 'alert' : 'status'} className={cn('flex w-full items-start gap-3 rounded-2xl p-4 font-sans rk-border rk-shadow-lg', variantClasses[item.variant ?? 'default'])}>\n            <ToastIcon variant={item.variant} />\n            <div className=\"min-w-0 flex-1\"><div className=\"font-display text-sm font-black\">{item.title}</div>{item.description && <div className=\"mt-0.5 text-xs font-bold text-black/65\">{item.description}</div>}</div>\n            <button type=\"button\" aria-label=\"Dismiss notification\" onClick={() => dismiss(item.id)} className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-rk-surface rk-border-sm hover:bg-rk-primary focus:outline-none focus:ring-2 focus:ring-black\"><X className=\"h-4 w-4 stroke-[3]\" aria-hidden=\"true\" /></button>\n          </div>\n        ))}\n      </div>\n    </ToastContext.Provider>\n  )\n}\n\nfunction ToastIcon({ variant }: { variant?: ToastVariant }) {\n  if (variant === 'success') return <CheckCircle2 className=\"mt-0.5 h-5 w-5 shrink-0 stroke-[2.5]\" aria-hidden=\"true\" />\n  if (variant === 'error') return <XCircle className=\"mt-0.5 h-5 w-5 shrink-0 stroke-[2.5]\" aria-hidden=\"true\" />\n  if (variant === 'info') return <Info className=\"mt-0.5 h-5 w-5 shrink-0 stroke-[2.5]\" aria-hidden=\"true\" />\n  return null\n}\n\nexport function useToast() {\n  const context = React.useContext(ToastContext)\n  if (!context) throw new Error('useToast must be used within a ToastProvider')\n  return context\n}\n",
      "type": "registry:ui",
      "target": "components/ui/sonner.tsx"
    }
  ]
}