import React, { DetailedHTMLProps, HTMLAttributes } from "react"; import { twMerge } from "tailwind-merge"; import Card from "./Card"; import { X } from "lucide-react"; import ReactDOM from "react-dom"; import Span from "../layout/Span"; export const ToastStyles = ["normal", "success", "error"] as const; export const ToastColors = ToastStyles; export type TWUIToastProps = DetailedHTMLProps< HTMLAttributes, HTMLDivElement > & { open?: boolean; setOpen?: React.Dispatch>; closeDelay?: number; color?: (typeof ToastStyles)[number]; }; let interval: any; let timeout: any; /** * # Toast Component * @className twui-toast-root * @className twui-toast * @className twui-toast-success * @className twui-toast-error */ export default function Toast({ open, setOpen, closeDelay = 4000, color, ...props }: TWUIToastProps) { const [ready, setReady] = React.useState(false); const IDName = "twui-toast-root"; React.useEffect(() => { const toastRoot = document.getElementById(IDName); if (toastRoot) { setReady(true); } else { const newToastRootEl = document.createElement("div"); newToastRootEl.id = IDName; document.body.appendChild(newToastRootEl); setReady(true); } }, []); React.useEffect(() => { if (!ready || !open) return; timeout = setTimeout(() => { setOpen?.(false); }, closeDelay); return function () { setOpen?.(false); }; }, [ready, open]); if (!ready) return null; if (!open) return null; return ReactDOM.createPortal( { window.clearTimeout(timeout); }} onMouseLeave={(e) => { timeout = setTimeout(() => { setOpen?.(false); }, closeDelay); }} > { setOpen?.(false); }} > {props.children} , document.getElementById(IDName) as HTMLElement ); }