"use client"; import * as React from "react"; import { cn } from "../../lib/utils"; import { X } from "lucide-react"; import { cva } from "class-variance-authority"; import { Progress } from "./progress"; /* Toast Components */ const ToastProvider = ({ children }: { children: React.ReactNode }) => { return
{children}
; }; const ToastViewport = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
)); ToastViewport.displayName = "ToastViewport"; const toastVariants = cva( `group relative flex w-96 items-center justify-between overflow-hidden rounded-md border p-4 pr-8 shadow-lg transition-all bg-background text-foreground`, { variants: { variant: { default: "border bg-background text-foreground", destructive: "border-red-500 bg-red-100 text-red-800", success: "border-green-500 bg-green-100 text-green-800", warning: "border-yellow-500 bg-yellow-100 text-yellow-800", info: "border-blue-500 bg-blue-100 text-blue-800", }, }, defaultVariants: { variant: "default", }, } ); export interface ToastProps extends React.HTMLAttributes { variant?: "default" | "destructive" | "success" | "warning" | "info"; duration?: number; onClose?: () => void; } const Toast = React.forwardRef( ({ className, variant = "default", duration = 5000, onClose, ...props }, ref) => { const [progress, setProgress] = React.useState(0); const [isOpen, setIsOpen] = React.useState(true); const intervalRef = React.useRef | null>(null); React.useEffect(() => { if (!isOpen) return; const startTime = Date.now(); const endTime = startTime + duration; if (intervalRef.current) clearInterval(intervalRef.current); setProgress(0); intervalRef.current = setInterval(() => { const now = Date.now(); const timeLeft = Math.max(0, endTime - now); const newProgress = 100 - (timeLeft / duration) * 100; setProgress(newProgress); if (newProgress >= 100) { clearInterval(intervalRef.current!); setTimeout(() => { setIsOpen(false); onClose?.(); }, 100); } }, 10); return () => { if (intervalRef.current) clearInterval(intervalRef.current); }; }, [isOpen, duration, onClose]); if (!isOpen) return null; return (
{props.children} {/* Bottom Progress Bar */}
{/* Close Button */} { setIsOpen(false); onClose?.(); }} />
); } ); Toast.displayName = "Toast"; const ToastClose = React.forwardRef< HTMLButtonElement, React.ButtonHTMLAttributes >(({ className, ...props }, ref) => ( )); ToastClose.displayName = "ToastClose"; const ToastTitle = React.forwardRef< HTMLHeadingElement, React.HTMLAttributes >(({ className, ...props }, ref) => (

)); ToastTitle.displayName = "ToastTitle"; const ToastDescription = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes >(({ className, ...props }, ref) => (

)); ToastDescription.displayName = "ToastDescription"; export { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, };