import { forwardRef, useMemo } from 'react';
import { classNames } from '@utils/classNames';
const VARIANTS = {
primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-500',
danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',
ghost: 'bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-500',
};
const SIZES = {
sm: 'px-3 py-1.5 text-sm',
md: 'px-4 py-2 text-base',
lg: 'px-6 py-3 text-lg',
};
export const Button = forwardRef(function Button(
{
children,
variant = 'primary',
size = 'md',
disabled = false,
loading = false,
fullWidth = false,
type = 'button',
className,
onClick,
...props
},
ref
) {
const computedClassName = useMemo(() => {
return classNames(
'inline-flex items-center justify-center font-medium rounded-md',
'focus:outline-none focus:ring-2 focus:ring-offset-2',
'transition-colors duration-200',
VARIANTS[variant],
SIZES[size],
fullWidth && 'w-full',
(disabled || loading) && 'opacity-50 cursor-not-allowed',
className
);
}, [variant, size, fullWidth, disabled, loading, className]);
const handleClick = (event) => {
if (disabled || loading) {
event.preventDefault();
return;
}
onClick?.(event);
};
return (
<button
ref={ref}
type={type}
className={computedClassName}
disabled={disabled || loading}
onClick={handleClick}
{...props}
>
{loading && (
<svg
className="animate-spin -ml-1 mr-2 h-4 w-4"
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 12h4z"
/>
</svg>
)}
{children}
</button>
);
});
export default Button;