import clsx from "clsx"; import { forwardRef, HTMLAttributes, useEffect, useImperativeHandle, useState, } from "react"; import { createPortal } from "react-dom"; import XMark from "@dndbeyond/fontawesome-cache/svgs/regular/xmark.svg"; import { Toast } from "@dndbeyond/ttui/components/Toast"; import { Notification } from "~/tools/js/Shared/stores/typings"; import styles from "./styles.module.css"; export interface NotificationSystemHandlers { addNotification: (notification: Notification) => void; removeNotification: (notification: Notification) => void; } const timeoutDuration = 5000; interface NotificationSystemProps extends Omit, "open" | "contentEditable"> {} /** * NotificationSystem is a component that manages the display of notifications * in toast messages which appear in the character sheet. */ export const NotificationSystem = forwardRef< HTMLDialogElement, NotificationSystemProps >(({ className, ...props }, ref) => { const [isOpen, setIsOpen] = useState(true); const [notifications, setNotifications] = useState>([]); const [notificationTimeoutHandle, setNotificationTimeoutHandle] = useState< number | undefined >(); const [portal, setPortal] = useState(null); const addNotification = (notification) => { if (notifications.filter((n) => n.uid === notification.uid).length === 0) { setNotifications([...notifications, notification]); } clearTimeout(notificationTimeoutHandle); (function openNotification() { if (!isOpen) { setIsOpen(true); } else { setNotificationTimeoutHandle(() => { const handle = window.setTimeout(() => { openNotification(); }, timeoutDuration + 100); return handle; }); } })(); }; const removeNotification = (notification) => { notifications[0].onRemove?.(); setNotifications(notifications.filter((n) => n.uid !== notification.uid)); }; useImperativeHandle( ref, (): NotificationSystemHandlers => ({ addNotification, removeNotification, }) ); const handleClose = () => { setIsOpen(false); removeNotification(notifications[0]); }; useEffect(() => { const portalEl = document.createElement("div"); portalEl.classList.add("ct-notification__portal"); portalEl.style.zIndex = "100000"; portalEl.style.position = "fixed"; document.body.appendChild(portalEl); setPortal(portalEl); return () => { document.body.removeChild(portalEl); }; }, []); return notifications[0] && portal ? createPortal(

{notifications[0].title}

{notifications[0].message}

, portal ) : null; });