{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <educlopez93@gmail.com>","css":{},"dependencies":["motion","lucide-react"],"description":"A BasicToast component for SmoothUI.","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { AlertCircle, CheckCircle, Info, X, XCircle } from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport type ToastType = \"success\" | \"error\" | \"info\" | \"warning\";\n\nexport interface ToastProps {\n  className?: string;\n  duration?: number;\n  isVisible?: boolean;\n  message: string;\n  onClose?: () => void;\n  type?: ToastType;\n}\n\nconst toastIcons = {\n  error: <XCircle className=\"h-5 w-5 text-red-500\" />,\n  info: <Info className=\"h-5 w-5 text-blue-500\" />,\n  success: <CheckCircle className=\"h-5 w-5 text-emerald-500\" />,\n  warning: <AlertCircle className=\"h-5 w-5 text-amber-500\" />,\n};\n\nconst toastClasses = {\n  error: \"border-red-100 bg-red-50 dark:border-red-900 dark:bg-red-950\",\n  info: \"border-blue-100 bg-blue-50 dark:border-blue-900 dark:bg-blue-950\",\n  success:\n    \"border-emerald-100 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950\",\n  warning:\n    \"border-amber-100 bg-amber-50 dark:border-amber-900 dark:bg-amber-950\",\n};\n\nexport default function BasicToast({\n  message,\n  type = \"info\",\n  duration = 3000,\n  onClose,\n  isVisible = true,\n  className = \"\",\n}: ToastProps) {\n  const [visible, setVisible] = useState(isVisible);\n  const [mounted, setMounted] = useState(false);\n  const shouldReduceMotion = useReducedMotion();\n\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  useEffect(() => {\n    setVisible(isVisible);\n  }, [isVisible]);\n\n  useEffect(() => {\n    if (visible && duration > 0) {\n      const timer = setTimeout(() => {\n        setVisible(false);\n        onClose?.();\n      }, duration);\n      return () => clearTimeout(timer);\n    }\n  }, [visible, duration, onClose]);\n\n  if (!mounted) {\n    return null;\n  }\n\n  const toastContent = (\n    <AnimatePresence>\n      {visible ? (\n        <motion.div\n          animate={\n            shouldReduceMotion ? { opacity: 1 } : { opacity: 1, scale: 1, x: 0 }\n          }\n          className={`fixed top-4 right-4 z-50 flex w-80 items-center gap-3 rounded-lg border p-4 shadow-lg ${toastClasses[type]} ${className}`}\n          exit={\n            shouldReduceMotion\n              ? { opacity: 0, transition: { duration: 0 } }\n              : {\n                  opacity: 0,\n                  scale: 0.8,\n                  transition: { duration: 0.15 },\n                  x: 50,\n                }\n          }\n          initial={\n            shouldReduceMotion\n              ? { opacity: 1 }\n              : { opacity: 0, scale: 0.8, x: 50 }\n          }\n          transition={\n            shouldReduceMotion\n              ? { duration: 0 }\n              : { bounce: 0.1, duration: 0.25, type: \"spring\" as const }\n          }\n        >\n          <div className=\"flex-shrink-0\">{toastIcons[type]}</div>\n          <p className=\"flex-1 text-sm\">{message}</p>\n          <button\n            className=\"flex-shrink-0 cursor-pointer rounded-full p-1 transition-colors hover:bg-black/5 dark:hover:bg-white/10\"\n            onClick={() => {\n              setVisible(false);\n              onClose?.();\n            }}\n            type=\"button\"\n          >\n            <X className=\"h-4 w-4\" />\n          </button>\n        </motion.div>\n      ) : null}\n    </AnimatePresence>\n  );\n\n  return createPortal(toastContent, document.body);\n}\n\n// Example of how to use this component:\nexport function ToastDemo() {\n  const [showToast, setShowToast] = useState(false);\n  const [toastType, setToastType] = useState<ToastType>(\"success\");\n\n  const handleShowToast = (type: ToastType) => {\n    setToastType(type);\n    setShowToast(true);\n  };\n\n  return (\n    <div className=\"flex flex-col gap-4 p-4\">\n      <div className=\"flex flex-wrap gap-2\">\n        <button\n          className=\"cursor-pointer rounded-md bg-emerald-500 px-3 py-1.5 text-sm text-white hover:bg-emerald-600\"\n          onClick={() => handleShowToast(\"success\")}\n          type=\"button\"\n        >\n          Success Toast\n        </button>\n        <button\n          className=\"cursor-pointer rounded-md bg-red-500 px-3 py-1.5 text-sm text-white hover:bg-red-600\"\n          onClick={() => handleShowToast(\"error\")}\n          type=\"button\"\n        >\n          Error Toast\n        </button>\n        <button\n          className=\"cursor-pointer rounded-md bg-amber-500 px-3 py-1.5 text-sm text-white hover:bg-amber-600\"\n          onClick={() => handleShowToast(\"warning\")}\n          type=\"button\"\n        >\n          Warning Toast\n        </button>\n        <button\n          className=\"cursor-pointer rounded-md bg-blue-500 px-3 py-1.5 text-sm text-white hover:bg-blue-600\"\n          onClick={() => handleShowToast(\"info\")}\n          type=\"button\"\n        >\n          Info Toast\n        </button>\n      </div>\n\n      <AnimatePresence>\n        {showToast ? (\n          <BasicToast\n            duration={3000}\n            message={`This is a ${toastType} message example!`}\n            onClose={() => setShowToast(false)}\n            type={toastType}\n          />\n        ) : null}\n      </AnimatePresence>\n    </div>\n  );\n}\n","path":"index.tsx","target":"components/smoothui/basic-toast/index.tsx","type":"registry:ui"}],"name":"basic-toast","registryDependencies":[],"title":"Basic Toast","type":"registry:ui"}