UNPKG

braid-design-system

Version:
126 lines (125 loc) 3.55 kB
import { jsx, jsxs } from "react/jsx-runtime"; import { useContext, createContext, Fragment, useCallback, useReducer, useState, useEffect } from "react"; import { BraidPortal } from "../BraidPortal/BraidPortal.mjs"; import { Toaster } from "./Toaster.mjs"; let toastCounter = 0; const ToastControllerContext = createContext(null); const QUEUE_TOAST = 0; const REMOVE_TOAST = 1; function reducer(state, action) { switch (action.type) { case QUEUE_TOAST: { const { toast } = action; const hasExistingToast = state.toasts.some( (t) => t.dedupeKey === toast.dedupeKey ); if (hasExistingToast) { return { toasts: state.toasts.map((t) => { if (t.dedupeKey === toast.dedupeKey) { return { ...t, shouldRemove: true }; } return t; }), queuedToasts: { ...state.queuedToasts, [toast.dedupeKey]: toast } }; } return { ...state, toasts: [...state.toasts, action.toast] }; } case REMOVE_TOAST: { const toasts = state.toasts.filter( ({ dedupeKey }) => dedupeKey !== action.dedupeKey ); const queuedToast = state.queuedToasts[action.dedupeKey]; if (queuedToast) { return { queuedToasts: { ...state.queuedToasts, [action.dedupeKey]: void 0 }, toasts: [...toasts, queuedToast] }; } return { ...state, toasts }; } } } const InternalToastProvider = ({ children }) => { const [{ toasts }, dispatch] = useReducer(reducer, { toasts: [], queuedToasts: {} }); const addToast = useCallback( (toast) => dispatch({ type: QUEUE_TOAST, toast }), [] ); const removeToast = useCallback( (dedupeKey) => dispatch({ type: REMOVE_TOAST, dedupeKey }), [] ); return /* @__PURE__ */ jsxs(ToastControllerContext.Provider, { value: addToast, children: [ children, /* @__PURE__ */ jsx(ToastPortal, { children: /* @__PURE__ */ jsx(Toaster, { toasts, removeToast }) }) ] }); }; const ToastProvider = ({ children }) => { const currentContext = useContext(ToastControllerContext); if (currentContext !== null) { return /* @__PURE__ */ jsx(Fragment, { children }); } return /* @__PURE__ */ jsx(InternalToastProvider, { children }); }; const ToastPortal = ({ children }) => { const [toastElement, setElement] = useState(null); useEffect(() => { const toastContainerId = "braid-toast-container"; let element = document.getElementById(toastContainerId); if (!element) { element = document.createElement("div"); element.setAttribute("id", toastContainerId); element.setAttribute("class", ""); document.body.appendChild(element); } setElement(element); }, []); if (!toastElement) { return null; } return /* @__PURE__ */ jsx(BraidPortal, { container: toastElement, children }); }; const useToast = () => { const addToast = useContext(ToastControllerContext); if (addToast === null) { throw new Error('No "ToastProvider" configured'); } return useCallback( (toast) => { const toastKey = `${toastCounter++}`; const { key, ...rest } = toast; const dedupeKey = key ?? toastKey; addToast({ ...rest, toastKey, dedupeKey, shouldRemove: false }); }, [addToast] ); }; export { ToastProvider, useToast };