All files / molecules/Toast Toast.provider.tsx

12.5% Statements 2/16
100% Branches 0/0
0% Functions 0/9
15.38% Lines 2/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53            10x       10x                                                                                    
import { Toast } from './web/Toast';
import { createPortal } from 'react-dom';
import { AnimatePresence, motion } from 'framer-motion';
import { createContext, useCallback, useState, ReactNode } from 'react';
import { ToastProps, ToastInternal, ToastContextType } from './Toast.types';
 
export const ToastContext = createContext<ToastContextType>({
  showToast: () => {},
});
 
export const ToastProvider = ({ children }: { children: ReactNode }) => {
  const [toasts, setToasts] = useState<ToastInternal[]>([]);
 
  const showToast = useCallback((toast: Omit<ToastProps, 'id'>) => {
    const toastUUID = Math.random().toString(36).substring(2, 9);
    const newToast: ToastInternal = { ...toast, toastUUID };
    setToasts((prev) => [...prev, newToast]);
  }, []);
 
  const removeToast = useCallback((id: string) => {
    setToasts((prev) => prev.filter((t) => t.toastUUID !== id));
  }, []);
 
  return (
    <ToastContext.Provider value={{ showToast }}>
      {children}
      {createPortal(
        <div className="z-9999 fixed bottom-4 right-4 flex flex-col gap-3">
          <AnimatePresence initial={false}>
            {toasts.map((toast) => {
              const { toastUUID } = toast;
 
              return (
                <motion.div
                  key={toastUUID}
                  layout
                  initial={{ opacity: 0, x: 50, y: 10 }}
                  animate={{ opacity: 1, x: 0, y: 0 }}
                  exit={{ opacity: 0, x: 50, transition: { duration: 0.25 } }}
                  transition={{ type: 'spring', stiffness: 300, damping: 24 }}
                >
                  <Toast {...toast} onClose={() => removeToast(toastUUID)} />
                </motion.div>
              );
            })}
          </AnimatePresence>
        </div>,
        document.body
      )}
    </ToastContext.Provider>
  );
};