Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | 2x 12x 12x | import React from 'react';
/**
* Props for LoadingSpinner component
*/
export interface LoadingSpinnerProps {
/**
* Size of the spinner
* @default 'md'
*/
size?: 'sm' | 'md' | 'lg';
/**
* Optional test ID for automated testing
*/
testId?: string;
/**
* Optional CSS class name
*/
className?: string;
}
/**
* Loading spinner component for indicating loading states
*
* ## Business Perspective
*
* Provides consistent visual feedback during data loading operations,
* improving user experience by clearly indicating that the application
* is working on their request. 🔄
*
* ## Technical Perspective
*
* Reusable loading indicator component that maintains visual consistency
* across all widgets and screens. Uses Tailwind CSS for styling with
* support for different sizes.
*
* @example
* ```tsx
* // Small spinner
* <LoadingSpinner size="sm" />
*
* // Default medium spinner
* <LoadingSpinner />
*
* // Large spinner with custom test ID
* <LoadingSpinner size="lg" testId="widget-loader" />
* ```
*/
export const LoadingSpinner: React.FC<LoadingSpinnerProps> = ({
size = 'md',
testId = 'loading-spinner',
className = ''
}) => {
const sizeClasses: Record<'sm' | 'md' | 'lg', string> = {
sm: 'w-4 h-4 border-2',
md: 'w-8 h-8 border-4',
lg: 'w-12 h-12 border-4',
};
return (
<div
className={`flex justify-center items-center p-4 ${className}`}
data-testid={`${testId}-container`}
role="status"
aria-label="Loading"
>
<div
className={`${sizeClasses[size]} border-blue-200 dark:border-blue-800 border-t-blue-600 dark:border-t-blue-400 rounded-full animate-spin`}
data-testid={testId}
aria-hidden="true"
/>
<span className="sr-only">Loading...</span>
</div>
);
};
export default LoadingSpinner;
|