Spaces:
Running
Running
| import React from 'react'; | |
| import { classNames } from '@/utils/helpers'; | |
| interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { | |
| variant?: 'primary' | 'secondary' | 'ghost' | 'danger'; | |
| size?: 'sm' | 'md' | 'lg'; | |
| isLoading?: boolean; | |
| leftIcon?: React.ReactNode; | |
| rightIcon?: React.ReactNode; | |
| } | |
| export const Button: React.FC<ButtonProps> = ({ | |
| children, | |
| variant = 'primary', | |
| size = 'md', | |
| isLoading = false, | |
| leftIcon, | |
| rightIcon, | |
| className, | |
| disabled, | |
| ...props | |
| }) => { | |
| const baseStyles = 'btn'; | |
| const variantStyles = { | |
| primary: 'btn-primary', | |
| secondary: 'btn-secondary', | |
| ghost: 'btn-ghost', | |
| danger: 'btn-danger', | |
| }; | |
| const sizeStyles = { | |
| sm: 'px-3 py-1.5 text-xs', | |
| md: 'px-4 py-2 text-sm', | |
| lg: 'px-6 py-3 text-base', | |
| }; | |
| return ( | |
| <button | |
| className={classNames( | |
| baseStyles, | |
| variantStyles[variant], | |
| sizeStyles[size], | |
| className | |
| )} | |
| disabled={disabled || isLoading} | |
| {...props} | |
| > | |
| {isLoading && ( | |
| <svg | |
| className="animate-spin h-4 w-4" | |
| xmlns="http://www.w3.org/2000/svg" | |
| fill="none" | |
| viewBox="0 0 24 24" | |
| > | |
| <circle | |
| className="opacity-25" | |
| cx="12" | |
| cy="12" | |
| r="10" | |
| stroke="currentColor" | |
| strokeWidth="4" | |
| /> | |
| <path | |
| className="opacity-75" | |
| fill="currentColor" | |
| d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" | |
| /> | |
| </svg> | |
| )} | |
| {!isLoading && leftIcon} | |
| {children} | |
| {!isLoading && rightIcon} | |
| </button> | |
| ); | |
| }; | |
| export default Button; | |