eletrotupi / tcc / frontend/components/ui/Button.tsx master
3.8 KB Raw
import React from 'react';
import {
  TouchableOpacity,
  Text,
  StyleSheet,
  ActivityIndicator,
  TouchableOpacityProps,
  ViewStyle,
  TextStyle,
} from 'react-native';
import { useThemeColor } from '@/hooks/use-theme-color';

interface ButtonProps extends TouchableOpacityProps {
  title: string;
  variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'dashed' | 'danger';
  size?: 'small' | 'medium' | 'large';
  loading?: boolean;
  disabled?: boolean;
  style?: ViewStyle;
  textStyle?: TextStyle;
}

export const Button: React.FC<ButtonProps> = ({
  title,
  variant = 'primary',
  size = 'medium',
  loading = false,
  disabled = false,
  style,
  textStyle,
  onPress,
  ...props
}) => {
  const primaryColor = useThemeColor({}, 'tint');
  const textColor = useThemeColor({}, 'text');
  const textSecondaryColor = useThemeColor({}, 'textSecondary');
  const backgroundColor = useThemeColor({}, 'background');
  const borderColor = useThemeColor({}, 'border');
  const borderDashedColor = useThemeColor({}, 'borderDashed');

  const getBackgroundColor = () => {
    if (disabled) return useThemeColor({ light: '#e5e5e5', dark: '#404040' }, 'background');
    switch (variant) {
      case 'primary':
        return primaryColor;
      case 'secondary':
        return useThemeColor({ light: '#f3f4f6', dark: '#374151' }, 'background');
      case 'danger':
        return useThemeColor({}, 'danger');
      case 'outline':
      case 'ghost':
      case 'dashed':
        return 'transparent';
      default:
        return primaryColor;
    }
  };

  const getTextColor = () => {
    if (disabled) return useThemeColor({}, 'text');

    switch (variant) {
      case 'primary':
      case 'secondary':
      case 'outline':
      case 'ghost':
        return textColor;
      case 'dashed':
        return textSecondaryColor;
      default:
        return '#fff';
    }
  };

  const getBorderWidth = () => {
    if (variant === 'outline' || variant === 'dashed') {
      return 1;
    } else {
      return 0;
    }
  };

  const getBorderColor = () => {
    if (variant === 'outline' || variant === 'dashed') {
      if (disabled) {
        return borderColor;
      } else if (variant === 'dashed') {
        return borderDashedColor;
      } else {
        return primaryColor;
      }
    }

    return 'transparent';
  };

  const getBorderStyle = () => {
    return variant === 'dashed' ? 'dashed' : 'solid';
  }

  const getHeight = () => {
    switch (size) {
      case 'small':
        return 36;
      case 'medium':
        return 44;
      case 'large':
        return 52;
      default:
        return 44;
    }
  };

  const getFontSize = () => {
    switch (size) {
      case 'small':
        return 14;
      case 'medium':
        return 16;
      case 'large':
        return 18;
      default:
        return 16;
    }
  };

  return (
    <TouchableOpacity
      style={[
        styles.button,
        {
          backgroundColor: getBackgroundColor(),
          borderWidth: getBorderWidth(),
          borderColor: getBorderColor(),
          borderStyle: getBorderStyle(),
          height: getHeight(),
          opacity: disabled || loading ? 0.6 : 1,
        },
        style,
      ]}
      disabled={disabled || loading}
      onPress={onPress}
      {...props}
    >
      {loading ? (
        <ActivityIndicator color={getTextColor()} />
      ) : (
        <Text
          style={[
            styles.text,
            {
              color: getTextColor(),
              fontSize: getFontSize(),
            },
            textStyle,
          ]}
        >
          {title}
        </Text>
      )}
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  button: {
    borderRadius: 8,
    paddingHorizontal: 20,
    alignItems: 'center',
    justifyContent: 'center',
    marginVertical: 8,
  },
  text: {
    fontWeight: '600',
  },
});