import React, { DetailedHTMLProps, HTMLAttributes } from "react"; import { twMerge } from "tailwind-merge"; import { createRoot } from "react-dom/client"; import Card from "./Card"; import { X } from "lucide-react"; import Span from "../layout/Span"; export const ToastStyles = ["normal", "success", "error"] as const; export const ToastColors = ToastStyles; type Props = DetailedHTMLProps< HTMLAttributes, HTMLDivElement > & { open?: boolean; setOpen?: React.Dispatch>; closeDelay?: number; color?: (typeof ToastStyles)[number]; }; /** * # 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 }: Props) { if (!open) return null; const toastEl = ( { const targetEl = e.target as HTMLElement; const rootWrapperEl = targetEl.closest(".twui-toast-root"); if (rootWrapperEl) { rootWrapperEl.parentElement?.removeChild(rootWrapperEl); setOpen?.(false); } }} > {props.children} ); React.useEffect(() => { const wrapperEl = document.createElement("div"); wrapperEl.className = twMerge( "fixed z-[200000] bottom-10 right-10", "flex flex-col items-center justify-center", "twui-toast-root" ); document.body.appendChild(wrapperEl); const root = createRoot(wrapperEl); root.render(toastEl); setTimeout(() => { closeToast({ wrapperEl }); setOpen?.(false); }, closeDelay); return function () { closeToast({ wrapperEl }); }; }, []); return null; } function closeToast({ wrapperEl }: { wrapperEl: HTMLDivElement | null }) { if (!wrapperEl) return; wrapperEl.parentElement?.removeChild(wrapperEl); }