98 lines
2.2 KiB
TypeScript
98 lines
2.2 KiB
TypeScript
import {
|
|
createContext,
|
|
useContext,
|
|
useState,
|
|
useCallback,
|
|
ReactNode,
|
|
} from 'react';
|
|
import { Toast, ToastComponent } from './Toast';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface ToastContextValue {
|
|
toasts: Toast[];
|
|
addToast: (toast: Omit<Toast, 'id'>) => void;
|
|
removeToast: (id: string) => void;
|
|
}
|
|
|
|
const ToastContext = createContext<ToastContextValue | undefined>(undefined);
|
|
|
|
export function useToastContext() {
|
|
const context = useContext(ToastContext);
|
|
if (!context) {
|
|
throw new Error('useToastContext must be used within ToastProvider');
|
|
}
|
|
return context;
|
|
}
|
|
|
|
export interface ToastProviderProps {
|
|
children: ReactNode;
|
|
position?:
|
|
| 'top-right'
|
|
| 'top-left'
|
|
| 'bottom-right'
|
|
| 'bottom-left'
|
|
| 'top-center'
|
|
| 'bottom-center';
|
|
className?: string;
|
|
}
|
|
|
|
const POSITION_CLASSES = {
|
|
'top-right': 'top-4 right-4',
|
|
'top-left': 'top-4 left-4',
|
|
'bottom-right': 'bottom-4 right-4',
|
|
'bottom-left': 'bottom-4 left-4',
|
|
'top-center': 'top-4 left-1/2 -translate-x-1/2',
|
|
'bottom-center': 'bottom-4 left-1/2 -translate-x-1/2',
|
|
};
|
|
|
|
/**
|
|
* Provider pour gérer la queue des toasts.
|
|
*/
|
|
export function ToastProvider({
|
|
children,
|
|
position = 'top-right',
|
|
className,
|
|
}: ToastProviderProps) {
|
|
const [toasts, setToasts] = useState<Toast[]>([]);
|
|
|
|
const addToast = useCallback((toast: Omit<Toast, 'id'>) => {
|
|
const id = `toast-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
const newToast: Toast = {
|
|
...toast,
|
|
id,
|
|
};
|
|
|
|
setToasts((prev) => [...prev, newToast]);
|
|
}, []);
|
|
|
|
const removeToast = useCallback((id: string) => {
|
|
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
}, []);
|
|
|
|
const value: ToastContextValue = {
|
|
toasts,
|
|
addToast,
|
|
removeToast,
|
|
};
|
|
|
|
return (
|
|
<ToastContext.Provider value={value}>
|
|
{children}
|
|
<div
|
|
className={cn(
|
|
'fixed z-50 flex flex-col gap-2',
|
|
POSITION_CLASSES[position],
|
|
className,
|
|
)}
|
|
>
|
|
{toasts.map((toast) => (
|
|
<ToastComponent
|
|
key={toast.id}
|
|
toast={toast}
|
|
onDismiss={removeToast}
|
|
/>
|
|
))}
|
|
</div>
|
|
</ToastContext.Provider>
|
|
);
|
|
}
|