import React, { forwardRef, ButtonHTMLAttributes } from 'react'; import { clsx } from 'clsx'; export interface ButtonProps extends ButtonHTMLAttributes { variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'success' | 'warning'; size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; isLoading?: boolean; isFullWidth?: boolean; leftIcon?: React.ReactNode; rightIcon?: React.ReactNode; loadingText?: string; } const Button = forwardRef(({ variant = 'primary', size = 'md', isLoading = false, isFullWidth = false, leftIcon, rightIcon, loadingText, className, children, disabled, ...props }, ref) => { const baseClasses = [ 'inline-flex items-center justify-center font-medium', 'transition-all duration-200 ease-in-out', 'focus:outline-none focus:ring-2 focus:ring-offset-2', 'disabled:opacity-50 disabled:cursor-not-allowed', 'border rounded-lg' ]; const variantClasses = { primary: [ 'bg-[var(--color-primary)] text-[var(--text-inverse)] border-[var(--color-primary)]', 'hover:bg-[var(--color-primary-dark)] hover:border-[var(--color-primary-dark)]', 'focus:ring-[var(--color-primary)]/20', 'active:bg-[var(--color-primary-dark)]' ], secondary: [ 'bg-[var(--color-secondary)] text-[var(--text-inverse)] border-[var(--color-secondary)]', 'hover:bg-[var(--color-secondary-dark)] hover:border-[var(--color-secondary-dark)]', 'focus:ring-[var(--color-secondary)]/20', 'active:bg-[var(--color-secondary-dark)]' ], outline: [ 'bg-transparent text-[var(--color-primary)] border-[var(--color-primary)]', 'hover:bg-[var(--color-primary)] hover:text-[var(--text-inverse)]', 'focus:ring-[var(--color-primary)]/20', 'active:bg-[var(--color-primary-dark)] active:border-[var(--color-primary-dark)]' ], ghost: [ 'bg-transparent text-[var(--color-primary)] border-transparent', 'hover:bg-[var(--color-primary)]/10 hover:text-[var(--color-primary-dark)]', 'focus:ring-[var(--color-primary)]/20', 'active:bg-[var(--color-primary)]/20' ], danger: [ 'bg-[var(--color-error)] text-[var(--text-inverse)] border-[var(--color-error)]', 'hover:bg-[var(--color-error-dark)] hover:border-[var(--color-error-dark)]', 'focus:ring-[var(--color-error)]/20', 'active:bg-[var(--color-error-dark)]' ], success: [ 'bg-[var(--color-success)] text-[var(--text-inverse)] border-[var(--color-success)]', 'hover:bg-[var(--color-success-dark)] hover:border-[var(--color-success-dark)]', 'focus:ring-[var(--color-success)]/20', 'active:bg-[var(--color-success-dark)]' ], warning: [ 'bg-[var(--color-warning)] text-[var(--text-inverse)] border-[var(--color-warning)]', 'hover:bg-[var(--color-warning-dark)] hover:border-[var(--color-warning-dark)]', 'focus:ring-[var(--color-warning)]/20', 'active:bg-[var(--color-warning-dark)]' ] }; const sizeClasses = { xs: 'px-2 py-1 text-xs gap-1 min-h-6', sm: 'px-3 py-1.5 text-sm gap-1.5 min-h-8 sm:min-h-10', // Better touch target on mobile md: 'px-4 py-2 text-sm gap-2 min-h-10 sm:min-h-12', lg: 'px-6 py-2.5 text-base gap-2 min-h-12 sm:min-h-14', xl: 'px-8 py-3 text-lg gap-3 min-h-14 sm:min-h-16' }; const loadingSpinner = ( ); const classes = clsx( baseClasses, variantClasses[variant], sizeClasses[size], { 'w-full': isFullWidth, 'cursor-wait': isLoading }, className ); return ( ); }); Button.displayName = 'Button'; export default Button;