UNPKG

lightswind

Version:

A professionally designed component library & templates market that brings together functionality, accessibility, and beautiful aesthetics for modern applications.

82 lines (81 loc) 4.47 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; 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 }) => { return _jsx("div", { className: "toast-provider", children: children }); }; const ToastViewport = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn(`fixed z-[40] flex flex-col-reverse gap-2 right-4 top-4 w-auto max-w-sm `, className), ...props }))); 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", }, }); 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); 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 (_jsxs("div", { ref: ref, className: cn(toastVariants({ variant }), "relative z-50 pb-2", // Removed fixed positioning for better stacking className), style: { marginBottom: '8px', // Add spacing between toasts zIndex: 51 // Ensure proper stacking }, ...props, children: [_jsxs("div", { className: "w-full min-h-8", children: [props.children, _jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1", children: _jsx(Progress, { value: progress, className: "h-1 rounded-none", indicatorClassName: cn(variant === "destructive" ? "bg-red-600" : variant === "success" ? "bg-green-600" : variant === "warning" ? "bg-yellow-600" : variant === "info" ? "bg-blue-600" : "bg-gray-600") }) })] }), _jsx(ToastClose, { onClick: () => { setIsOpen(false); onClose?.(); } })] })); }); Toast.displayName = "Toast"; const ToastClose = React.forwardRef(({ className, ...props }, ref) => (_jsx("button", { ref: ref, className: cn("absolute right-2 top-2 rounded-md p-1 text-foreground/70 opacity-70 transition-opacity hover:text-foreground hover:opacity-100", className), "aria-label": "Close toast", ...props, children: _jsx(X, { className: "h-4 w-4" }) }))); ToastClose.displayName = "ToastClose"; const ToastTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx("h2", { ref: ref, className: cn("text-sm font-semibold", className), ...props }))); ToastTitle.displayName = "ToastTitle"; const ToastDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx("p", { ref: ref, className: cn("text-sm opacity-90", className), ...props }))); ToastDescription.displayName = "ToastDescription"; export { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, };