Sprint 1 — Quick A11y wins: - progress.tsx: role=progressbar + aria-value* + aria-label - switch.tsx: role=switch + aria-checked - skeleton.tsx: aria-hidden=true - alert.tsx, Toast.tsx, SelectTrigger.tsx: aria-labels on close buttons - PostCard.tsx: alt on images + aria-labels on icon buttons - ProductCard.tsx: aria-labels on play/view buttons - modal.tsx: role=dialog + aria-modal + aria-labelledby - input.tsx: error state + aria-invalid + aria-describedby - FAB.tsx: forward aria-label from label prop Sprint 2 — Structural A11y + View States: - tabs/: full ARIA tablist/tab/tabpanel + arrow key navigation - radio-group.tsx: role=radio + arrow key navigation - select/: aria-activedescendant + full keyboard navigation - List.tsx + card.tsx: focus-visible states on interactive elements - DashboardPage, LibraryPage, LiveView, QueueView: error states - WishlistView, AdminDashboard, AnalyticsView, SellerDashboard: loading/empty states Co-authored-by: Cursor <cursoragent@cursor.com>
111 lines
2.7 KiB
TypeScript
111 lines
2.7 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-success text-foreground bg-card/90',
|
|
error: 'border-destructive text-foreground bg-card/90',
|
|
info: 'border-border text-foreground bg-card/90',
|
|
};
|
|
|
|
const icons = {
|
|
success: <CheckCircle className="w-5 h-5 text-success" />,
|
|
error: <AlertCircle className="w-5 h-5 text-destructive" />,
|
|
info: <Info className="w-5 h-5 text-muted-foreground" />,
|
|
};
|
|
|
|
return (
|
|
<div
|
|
role="alert"
|
|
className={`flex items-center gap-4 p-4 rounded-lg border shadow-2xl min-w-72 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-muted-foreground hover:text-foreground transition-colors"
|
|
aria-label="Fermer la notification"
|
|
>
|
|
<X className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
);
|
|
};
|