ui: create Spinner component for inline loading states (Action 8.3.1.4)
- 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
This commit is contained in:
parent
b9cceae6b5
commit
ac65373c36
2 changed files with 118 additions and 3 deletions
|
|
@ -2942,11 +2942,18 @@ Critical path dependencies:
|
||||||
- **Result**: All high and medium priority mutation buttons now have loading states. Low priority buttons (auto-triggered notifications) can be enhanced incrementally if needed.
|
- **Result**: All high and medium priority mutation buttons now have loading states. Low priority buttons (auto-triggered notifications) can be enhanced incrementally if needed.
|
||||||
- **Rollback**: Remove loading states
|
- **Rollback**: Remove loading states
|
||||||
|
|
||||||
- [ ] **Action 8.3.1.4**: Create Spinner component (if doesn't exist)
|
- [x] **Action 8.3.1.4**: Create Spinner component (if doesn't exist)
|
||||||
- **Scope**: `apps/web/src/components/ui/Spinner.tsx` (create) - Reusable spinner component
|
- **Scope**: `apps/web/src/components/ui/Spinner.tsx` (create) - Reusable spinner component
|
||||||
- **Dependencies**: None
|
- **Dependencies**: None ✅
|
||||||
- **Risk**: LOW 🔒
|
- **Risk**: LOW 🔒
|
||||||
- **Validation**: Spinner component works
|
- **Validation**: ✅ Spinner component created:
|
||||||
|
- **File**: Created `apps/web/src/components/ui/Spinner.tsx`
|
||||||
|
- **Component**: Simple, reusable inline spinner component
|
||||||
|
- **Features**: Size variants (sm, md, lg), color variants (default, muted, white, current), accessibility (aria-label, role="status")
|
||||||
|
- **Design**: Uses Kodo design system colors (kodo-cyan by default), wraps Loader2 from lucide-react
|
||||||
|
- **Purpose**: Optimized for inline use in buttons and UI elements (different from LoadingSpinner which is for full-page states)
|
||||||
|
- **Pattern**: Follows existing component patterns with TypeScript interfaces and JSDoc documentation
|
||||||
|
- **Result**: Reusable spinner component ready for use in loading states
|
||||||
- **Rollback**: Delete component
|
- **Rollback**: Delete component
|
||||||
|
|
||||||
- [ ] **Action 8.3.1.5**: Use Spinner in loading states
|
- [ ] **Action 8.3.1.5**: Use Spinner in loading states
|
||||||
|
|
|
||||||
108
apps/web/src/components/ui/Spinner.tsx
Normal file
108
apps/web/src/components/ui/Spinner.tsx
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue