{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "alert-dialog",
  "type": "registry:ui",
  "title": "AlertDialog",
  "description": "Destructive action confirmation dialog with danger styling and optional string confirmation phrase.",
  "registryDependencies": [
    "https://ui.arpitbhayani.me/r/aui.json"
  ],
  "files": [
    {
      "path": "ui/alert-dialog.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AlertDialogProps {\n  isOpen: boolean;\n  onClose: () => void;\n  onConfirm: () => void | Promise<void>;\n  title: string;\n  description: string;\n  confirmText?: string;\n  cancelText?: string;\n  variant?: \"danger\" | \"warning\";\n  confirmationPhrase?: string;\n  loading?: boolean;\n  className?: string;\n}\n\nexport function AlertDialog({\n  isOpen,\n  onClose,\n  onConfirm,\n  title,\n  description,\n  confirmText = \"Confirm\",\n  cancelText = \"Cancel\",\n  variant = \"danger\",\n  confirmationPhrase,\n  loading = false,\n  className,\n}: AlertDialogProps) {\n  const [mounted, setMounted] = React.useState(false);\n  const [typedPhrase, setTypedPhrase] = React.useState(\"\");\n  const [submitting, setSubmitting] = React.useState(false);\n  const cancelBtnRef = React.useRef<HTMLButtonElement>(null);\n\n  React.useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  React.useEffect(() => {\n    if (isOpen) {\n      setTypedPhrase(\"\");\n      setSubmitting(false);\n      const timer = setTimeout(() => {\n        cancelBtnRef.current?.focus();\n      }, 30);\n      return () => clearTimeout(timer);\n    }\n  }, [isOpen]);\n\n  React.useEffect(() => {\n    if (!isOpen) return;\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") {\n        e.stopPropagation();\n        onClose();\n      }\n    };\n    document.addEventListener(\"keydown\", handleKeyDown);\n    const originalOverflow = document.body.style.overflow;\n    document.body.style.overflow = \"hidden\";\n    return () => {\n      document.removeEventListener(\"keydown\", handleKeyDown);\n      document.body.style.overflow = originalOverflow;\n    };\n  }, [isOpen, onClose]);\n\n  if (!isOpen || !mounted) return null;\n\n  const phraseMatches = confirmationPhrase\n    ? typedPhrase.trim() === confirmationPhrase.trim()\n    : true;\n\n  const isActionDisabled = !phraseMatches || loading || submitting;\n\n  const handleConfirmClick = async () => {\n    if (isActionDisabled) return;\n    try {\n      setSubmitting(true);\n      await onConfirm();\n    } finally {\n      setSubmitting(false);\n    }\n  };\n\n  const node = (\n    <div\n      className=\"fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] flex items-center justify-center p-4 animate-in fade-in-0\"\n      role=\"alertdialog\"\n      aria-modal=\"true\"\n      onClick={(e) => {\n        if (e.target === e.currentTarget) onClose();\n      }}\n    >\n      <div\n        className={cn(\n          \"w-full max-w-md rounded-xl border bg-card p-6 shadow-2xl overflow-hidden animate-in zoom-in-95\",\n          variant === \"danger\" ? \"border-rose-500/30\" : \"border-amber-500/30\",\n          className\n        )}\n      >\n        <div className=\"flex items-start gap-4\">\n          <div\n            className={cn(\n              \"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg font-bold text-lg\",\n              variant === \"danger\"\n                ? \"bg-rose-500/10 text-rose-600 dark:text-rose-400\"\n                : \"bg-amber-500/10 text-amber-600 dark:text-amber-400\"\n            )}\n          >\n            ⚠\n          </div>\n          <div className=\"flex-1 space-y-1\">\n            <h3 className=\"font-heading font-semibold text-lg text-foreground\">\n              {title}\n            </h3>\n            <p className=\"text-sm text-muted-foreground\">{description}</p>\n          </div>\n        </div>\n\n        {confirmationPhrase && (\n          <div className=\"mt-4 p-3 rounded-lg border border-border bg-muted/40 space-y-2\">\n            <p className=\"text-xs text-muted-foreground\">\n              Please type <code className=\"font-mono font-medium text-primary px-1 py-0.5 rounded bg-muted\">{confirmationPhrase}</code> to confirm:\n            </p>\n            <input\n              type=\"text\"\n              className=\"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 font-mono text-sm shadow-xs outline-hidden focus:ring-1 focus:ring-ring\"\n              value={typedPhrase}\n              onChange={(e) => setTypedPhrase(e.target.value)}\n              placeholder={confirmationPhrase}\n            />\n          </div>\n        )}\n\n        <div className=\"mt-6 flex items-center justify-end gap-3\">\n          <button\n            ref={cancelBtnRef}\n            type=\"button\"\n            className=\"inline-flex h-9 items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium hover:bg-muted transition-colors\"\n            onClick={onClose}\n            disabled={loading || submitting}\n          >\n            {cancelText}\n          </button>\n          <button\n            type=\"button\"\n            className={cn(\n              \"inline-flex h-9 items-center justify-center rounded-md px-4 py-2 text-sm font-medium text-white shadow-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed\",\n              variant === \"danger\" ? \"bg-destructive hover:bg-destructive/90\" : \"bg-primary hover:bg-primary/90\"\n            )}\n            onClick={handleConfirmClick}\n            disabled={isActionDisabled}\n          >\n            {loading || submitting ? \"Processing...\" : confirmText}\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n\n  return typeof document !== \"undefined\"\n    ? createPortal(node, document.body)\n    : null;\n}\n",
      "type": "registry:ui"
    }
  ]
}