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>
);
};
|