({
variant = 'primary',
size = 'md',
disabled = false,
loading = false,
children,
icon,
iconElement,
className = '',
...props
}: ButtonProps)
| 31 | } |
| 32 | |
| 33 | function Button({ |
| 34 | variant = 'primary', |
| 35 | size = 'md', |
| 36 | disabled = false, |
| 37 | loading = false, |
| 38 | children, |
| 39 | icon, |
| 40 | iconElement, |
| 41 | className = '', |
| 42 | ...props |
| 43 | }: ButtonProps) { |
| 44 | const baseClasses = |
| 45 | 'inline-flex items-center justify-center font-medium rounded-md transition-[background-color,opacity,border-color] duration-200 focus:outline-none focus-visible:ring-2 disabled:opacity-50 disabled:cursor-not-allowed' |
| 46 | |
| 47 | const variants = { |
| 48 | primary: |
| 49 | 'bg-accent text-white hover:opacity-90 focus-visible:ring-accent/40', |
| 50 | secondary: |
| 51 | 'bg-background-secondary text-text border border-border hover:bg-fill focus-visible:ring-accent/40', |
| 52 | outline: |
| 53 | 'border border-border text-text hover:bg-fill focus-visible:ring-accent/40', |
| 54 | ghost: 'text-text hover:bg-fill focus-visible:ring-accent/40', |
| 55 | destructive: 'bg-red text-white hover:opacity-90 focus-visible:ring-red/40', |
| 56 | } |
| 57 | |
| 58 | const sizes = { |
| 59 | sm: 'text-xs h-6 px-2 gap-1.5', |
| 60 | md: 'text-[13px] h-7 px-2.5 gap-1.5', |
| 61 | lg: 'text-sm h-8 px-3.5 gap-2', |
| 62 | } |
| 63 | |
| 64 | const iconSizes = { |
| 65 | sm: 'w-3 h-3', |
| 66 | md: 'w-3.5 h-3.5', |
| 67 | lg: 'w-4 h-4', |
| 68 | } |
| 69 | |
| 70 | return ( |
| 71 | <button |
| 72 | className={`${baseClasses} ${variants[variant]} ${sizes[size]} ${className}`} |
| 73 | disabled={disabled || loading} |
| 74 | {...props} |
| 75 | > |
| 76 | {loading && <Loader2 className={`${iconSizes[size]} animate-spin`} />} |
| 77 | {!loading && iconElement && icon === 'left' && ( |
| 78 | <span className={iconSizes[size]}>{iconElement}</span> |
| 79 | )} |
| 80 | <span>{children}</span> |
| 81 | {!loading && iconElement && icon === 'right' && ( |
| 82 | <span className={iconSizes[size]}>{iconElement}</span> |
| 83 | )} |
| 84 | </button> |
| 85 | ) |
| 86 | } |
| 87 | |
| 88 | export function ButtonExamples() { |
| 89 | const [isLoading, setIsLoading] = useState(false) |
nothing calls this directly
no outgoing calls
no test coverage detected