veza/apps/web/src/components/ui/button-loading.tsx

100 lines
2.3 KiB
TypeScript

import { Button, ButtonProps } from './button';
import { Loader2 } from 'lucide-react';
import { cn } from '@/lib/utils';
// FE-COMP-001: Add loading states to all async operations
/**
* ButtonLoadingProps - Propriétés du composant ButtonLoading
*
* @interface ButtonLoadingProps
* @extends ButtonProps
*/
interface ButtonLoadingProps extends ButtonProps {
/**
* Si `true`, affiche un spinner et désactive le bouton
*
* @default false
*
* @example
* ```tsx
* <ButtonLoading isLoading={isSubmitting}>
* Envoyer
* </ButtonLoading>
* ```
*/
isLoading?: boolean;
/**
* Texte à afficher pendant le chargement (remplace le contenu du bouton)
* Si non fourni, le contenu original est conservé avec le spinner
*
* @example
* ```tsx
* <ButtonLoading
* isLoading={isSubmitting}
* loadingText="Envoi en cours..."
* >
* Envoyer
* </ButtonLoading>
* ```
*/
loadingText?: string;
}
/**
* ButtonLoading - Composant de bouton avec état de chargement intégré
*
* Extension du composant Button avec support pour l'état de chargement.
* Affiche automatiquement un spinner et désactive le bouton pendant le chargement.
*
* FE-COMP-001: Add loading states to all async operations
*
* @example
* ```tsx
* // Bouton avec état de chargement
* <ButtonLoading
* isLoading={isSubmitting}
* onClick={handleSubmit}
* >
* Envoyer
* </ButtonLoading>
* ```
*
* @example
* ```tsx
* // Avec texte de chargement personnalisé
* <ButtonLoading
* isLoading={isProcessing}
* loadingText="Traitement..."
* variant="primary"
* >
* Traiter
* </ButtonLoading>
* ```
*
* @component
* @param {ButtonLoadingProps} props - Propriétés du composant (hérite de ButtonProps)
* @returns {JSX.Element} Bouton avec spinner et état disabled pendant le chargement
*/
export function ButtonLoading({
isLoading = false,
loadingText,
children,
disabled,
className,
...props
}: ButtonLoadingProps) {
return (
<Button
disabled={disabled || isLoading}
className={cn(className)}
{...props}
>
{isLoading && (
<Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden="true" />
)}
{isLoading && loadingText ? loadingText : children}
</Button>
);
}