104 lines
No EOL
2.6 KiB
TypeScript
104 lines
No EOL
2.6 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { X, CheckCircle, AlertCircle, Info } from 'lucide-react';
|
|
|
|
/**
|
|
* ToastMessage - Interface pour un message de toast
|
|
*
|
|
* @interface ToastMessage
|
|
*/
|
|
export interface ToastMessage {
|
|
/**
|
|
* Identifiant unique du toast
|
|
*/
|
|
id: string;
|
|
|
|
/**
|
|
* Type de toast
|
|
*
|
|
* - `success`: Message de succès (vert/lime)
|
|
* - `error`: Message d'erreur (rouge)
|
|
* - `info`: Message d'information (cyan)
|
|
*/
|
|
type: 'success' | 'error' | 'info';
|
|
|
|
/**
|
|
* Message à afficher
|
|
*/
|
|
message: string;
|
|
}
|
|
|
|
/**
|
|
* ToastProps - Propriétés du composant Toast
|
|
*
|
|
* @interface ToastProps
|
|
* @extends ToastMessage
|
|
*/
|
|
interface ToastProps extends ToastMessage {
|
|
/**
|
|
* Fonction appelée pour fermer le toast
|
|
*
|
|
* @param {string} id - Identifiant du toast à fermer
|
|
*/
|
|
onClose: (id: string) => void;
|
|
}
|
|
|
|
/**
|
|
* Toast - Composant de notification toast avec design system Kodo
|
|
*
|
|
* Composant de notification toast qui s'affiche temporairement et se ferme automatiquement
|
|
* après 4 secondes. Supporte trois types : success, error et info.
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* // Toast de succès
|
|
* <Toast
|
|
* id="1"
|
|
* type="success"
|
|
* message="Opération réussie"
|
|
* onClose={(id) => removeToast(id)}
|
|
* />
|
|
*
|
|
* // Toast d'erreur
|
|
* <Toast
|
|
* id="2"
|
|
* type="error"
|
|
* message="Une erreur s'est produite"
|
|
* onClose={(id) => removeToast(id)}
|
|
* />
|
|
* ```
|
|
*
|
|
* @component
|
|
* @param {ToastProps} props - Propriétés du composant
|
|
* @returns {JSX.Element} Élément div stylisé comme un toast avec animation
|
|
*/
|
|
|
|
export const Toast: React.FC<ToastProps> = ({ id, type, message, onClose }) => {
|
|
useEffect(() => {
|
|
const timer = setTimeout(() => {
|
|
onClose(id);
|
|
}, 4000);
|
|
return () => clearTimeout(timer);
|
|
}, [id, onClose]);
|
|
|
|
const styles = {
|
|
success: 'border-kodo-lime text-white bg-kodo-ink/90',
|
|
error: 'border-kodo-red text-white bg-kodo-ink/90',
|
|
info: 'border-kodo-cyan text-white bg-kodo-ink/90',
|
|
};
|
|
|
|
const icons = {
|
|
success: <CheckCircle className="w-5 h-5 text-kodo-lime" />,
|
|
error: <AlertCircle className="w-5 h-5 text-kodo-red" />,
|
|
info: <Info className="w-5 h-5 text-kodo-cyan" />,
|
|
};
|
|
|
|
return (
|
|
<div className={`flex items-center gap-3 p-4 rounded-lg border shadow-2xl min-w-[300px] animate-slideInRight backdrop-blur-md mb-3 ${styles[type]}`}>
|
|
{icons[type]}
|
|
<p className="flex-1 text-sm font-medium">{message}</p>
|
|
<button onClick={() => onClose(id)} className="text-gray-400 hover:text-white transition-colors">
|
|
<X className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
);
|
|
}; |