- Created Spinner.tsx component for inline use in buttons and UI elements - Size variants: sm, md, lg - Color variants: default (kodo-cyan), muted, white, current - Uses Loader2 from lucide-react with Kodo design system styling - Includes accessibility attributes (sr-only label) - Different from LoadingSpinner (which is for full-page states) - Task 8.3.1.4 complete
108 lines
2.5 KiB
TypeScript
108 lines
2.5 KiB
TypeScript
import { Loader2 } from 'lucide-react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
/**
|
|
* SpinnerProps - Propriétés du composant Spinner
|
|
*
|
|
* @interface SpinnerProps
|
|
*/
|
|
export interface SpinnerProps {
|
|
/**
|
|
* Taille du spinner
|
|
*
|
|
* - `sm`: Petit (h-4 w-4) - pour les boutons et éléments compacts
|
|
* - `md`: Moyen (h-5 w-5) - par défaut
|
|
* - `lg`: Grand (h-6 w-6) - pour les éléments plus grands
|
|
*
|
|
* @default 'md'
|
|
*/
|
|
size?: 'sm' | 'md' | 'lg';
|
|
|
|
/**
|
|
* Couleur du spinner
|
|
*
|
|
* - `default`: Couleur par défaut (kodo-cyan pour le thème Kodo)
|
|
* - `muted`: Couleur atténuée (text-muted-foreground)
|
|
* - `white`: Blanc
|
|
* - `current`: Utilise la couleur du texte parent
|
|
*
|
|
* @default 'default'
|
|
*/
|
|
variant?: 'default' | 'muted' | 'white' | 'current';
|
|
|
|
/**
|
|
* Classes CSS personnalisées
|
|
*/
|
|
className?: string;
|
|
|
|
/**
|
|
* Label d'accessibilité
|
|
*
|
|
* @default 'Chargement en cours'
|
|
*/
|
|
'aria-label'?: string;
|
|
}
|
|
|
|
/**
|
|
* Spinner - Composant de spinner réutilisable pour les états de chargement inline
|
|
*
|
|
* Composant de spinner optimisé pour l'utilisation inline dans les boutons,
|
|
* formulaires et autres éléments UI. Utilise le design system Kodo.
|
|
*
|
|
* Différences avec LoadingSpinner:
|
|
* - LoadingSpinner: Pour les états de chargement de page complète avec conteneur
|
|
* - Spinner: Pour les spinners inline dans les boutons et éléments UI
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* // Spinner simple dans un bouton
|
|
* <Button disabled={isLoading}>
|
|
* {isLoading && <Spinner size="sm" className="mr-2" />}
|
|
* Enregistrer
|
|
* </Button>
|
|
*
|
|
* // Spinner avec couleur personnalisée
|
|
* <Spinner size="lg" variant="muted" />
|
|
*
|
|
* // Spinner avec classes personnalisées
|
|
* <Spinner className="text-kodo-cyan" />
|
|
* ```
|
|
*
|
|
* @component
|
|
* @param {SpinnerProps} props - Propriétés du composant
|
|
* @returns {JSX.Element} Spinner animé
|
|
*/
|
|
export function Spinner({
|
|
size = 'md',
|
|
variant = 'default',
|
|
className,
|
|
'aria-label': ariaLabel = 'Chargement en cours',
|
|
}: SpinnerProps) {
|
|
const sizeClasses = {
|
|
sm: 'h-4 w-4',
|
|
md: 'h-5 w-5',
|
|
lg: 'h-6 w-6',
|
|
};
|
|
|
|
const variantClasses = {
|
|
default: 'text-kodo-cyan',
|
|
muted: 'text-muted-foreground',
|
|
white: 'text-white',
|
|
current: 'text-current',
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Loader2
|
|
className={cn(
|
|
'animate-spin',
|
|
sizeClasses[size],
|
|
variantClasses[variant],
|
|
className,
|
|
)}
|
|
aria-hidden="true"
|
|
/>
|
|
<span className="sr-only">{ariaLabel}</span>
|
|
</>
|
|
);
|
|
}
|