veza/apps/web/src/components/ui/skeleton.tsx
senke 128a160196 feat(a11y): comprehensive accessibility & view states improvements
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>
2026-02-09 23:04:35 +01:00

93 lines
2.3 KiB
TypeScript

import * as React from 'react';
import { cn } from '@/lib/utils';
/**
* SkeletonProps - Propriétés du composant Skeleton
*
* @interface SkeletonProps
* @extends React.HTMLAttributes<HTMLDivElement>
*/
export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* Variant de forme du skeleton
*
* - `text`: Forme de texte (arrondi, hauteur fixe)
* - `circular`: Forme circulaire (pour avatars)
* - `rectangular`: Forme rectangulaire arrondie (par défaut)
*
* @default 'rectangular'
*/
variant?: 'text' | 'circular' | 'rectangular';
/**
* Largeur du skeleton (string CSS ou nombre)
*
* @example
* ```tsx
* <Skeleton width="100%" height={20} />
* <Skeleton width={200} height={100} />
* ```
*/
width?: string | number;
/**
* Hauteur du skeleton (string CSS ou nombre)
*/
height?: string | number;
}
/**
* Skeleton - Composant de placeholder animé avec design system Kodo
*
* Composant de skeleton pour afficher des placeholders pendant le chargement.
* Utilise une animation pulse pour indiquer le chargement.
*
* @example
* ```tsx
* // Skeleton rectangulaire
* <Skeleton width="100%" height={100} />
*
* // Skeleton de texte
* <Skeleton variant="text" width="80%" />
*
* // Skeleton circulaire (avatar)
* <Skeleton variant="circular" width={40} height={40} />
* ```
*
* @component
* @param {SkeletonProps} props - Propriétés du composant
* @returns {JSX.Element} Élément div avec animation pulse
*/
const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
({ variant = 'rectangular', width, height, className, ...props }, ref) => {
const baseClasses = 'relative overflow-hidden bg-muted/50';
const variantClasses = {
text: 'rounded h-4 w-full',
circular: 'rounded-full',
rectangular: 'rounded-lg',
};
const style = {
width,
height,
};
return (
<div
ref={ref}
className={cn(baseClasses, variantClasses[variant], className)}
style={style}
aria-hidden="true"
{...props}
>
{/* Shimmer overlay — sweeping gradient for premium loading feel */}
<div className="absolute inset-0 skeleton-shimmer" />
</div>
);
},
);
Skeleton.displayName = 'Skeleton';
export { Skeleton };