eletrotupi / tcc/ frontend/components/ui/Button.tsxfe2deb48e4d91c97820de01dec6dd464c725329f
3.8 KB | 176 lines Raw
1
import React from 'react';
2
import {
3
  TouchableOpacity,
4
  Text,
5
  StyleSheet,
6
  ActivityIndicator,
7
  TouchableOpacityProps,
8
  ViewStyle,
9
  TextStyle,
10
} from 'react-native';
11
import { useThemeColor } from '@/hooks/use-theme-color';
12

13
interface ButtonProps extends TouchableOpacityProps {
14
  title: string;
15
  variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'dashed' | 'danger';
16
  size?: 'small' | 'medium' | 'large';
17
  loading?: boolean;
18
  disabled?: boolean;
19
  style?: ViewStyle;
20
  textStyle?: TextStyle;
21
}
22

23
export const Button: React.FC<ButtonProps> = ({
24
  title,
25
  variant = 'primary',
26
  size = 'medium',
27
  loading = false,
28
  disabled = false,
29
  style,
30
  textStyle,
31
  onPress,
32
  ...props
33
}) => {
34
  const primaryColor = useThemeColor({}, 'tint');
35
  const textColor = useThemeColor({}, 'text');
36
  const textSecondaryColor = useThemeColor({}, 'textSecondary');
37
  const backgroundColor = useThemeColor({}, 'background');
38
  const borderColor = useThemeColor({}, 'border');
39
  const borderDashedColor = useThemeColor({}, 'borderDashed');
40

41
  const getBackgroundColor = () => {
42
    if (disabled) return useThemeColor({ light: '#e5e5e5', dark: '#404040' }, 'background');
43
    switch (variant) {
44
      case 'primary':
45
        return primaryColor;
46
      case 'secondary':
47
        return useThemeColor({ light: '#f3f4f6', dark: '#374151' }, 'background');
48
      case 'danger':
49
        return useThemeColor({}, 'danger');
50
      case 'outline':
51
      case 'ghost':
52
      case 'dashed':
53
        return 'transparent';
54
      default:
55
        return primaryColor;
56
    }
57
  };
58

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

62
    switch (variant) {
63
      case 'primary':
64
      case 'secondary':
65
      case 'outline':
66
      case 'ghost':
67
        return textColor;
68
      case 'dashed':
69
        return textSecondaryColor;
70
      default:
71
        return '#fff';
72
    }
73
  };
74

75
  const getBorderWidth = () => {
76
    if (variant === 'outline' || variant === 'dashed') {
77
      return 1;
78
    } else {
79
      return 0;
80
    }
81
  };
82

83
  const getBorderColor = () => {
84
    if (variant === 'outline' || variant === 'dashed') {
85
      if (disabled) {
86
        return borderColor;
87
      } else if (variant === 'dashed') {
88
        return borderDashedColor;
89
      } else {
90
        return primaryColor;
91
      }
92
    }
93

94
    return 'transparent';
95
  };
96

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

101
  const getHeight = () => {
102
    switch (size) {
103
      case 'small':
104
        return 36;
105
      case 'medium':
106
        return 44;
107
      case 'large':
108
        return 52;
109
      default:
110
        return 44;
111
    }
112
  };
113

114
  const getFontSize = () => {
115
    switch (size) {
116
      case 'small':
117
        return 14;
118
      case 'medium':
119
        return 16;
120
      case 'large':
121
        return 18;
122
      default:
123
        return 16;
124
    }
125
  };
126

127
  return (
128
    <TouchableOpacity
129
      style={[
130
        styles.button,
131
        {
132
          backgroundColor: getBackgroundColor(),
133
          borderWidth: getBorderWidth(),
134
          borderColor: getBorderColor(),
135
          borderStyle: getBorderStyle(),
136
          height: getHeight(),
137
          opacity: disabled || loading ? 0.6 : 1,
138
        },
139
        style,
140
      ]}
141
      disabled={disabled || loading}
142
      onPress={onPress}
143
      {...props}
144
    >
145
      {loading ? (
146
        <ActivityIndicator color={getTextColor()} />
147
      ) : (
148
        <Text
149
          style={[
150
            styles.text,
151
            {
152
              color: getTextColor(),
153
              fontSize: getFontSize(),
154
            },
155
            textStyle,
156
          ]}
157
        >
158
          {title}
159
        </Text>
160
      )}
161
    </TouchableOpacity>
162
  );
163
};
164

165
const styles = StyleSheet.create({
166
  button: {
167
    borderRadius: 8,
168
    paddingHorizontal: 20,
169
    alignItems: 'center',
170
    justifyContent: 'center',
171
    marginVertical: 8,
172
  },
173
  text: {
174
    fontWeight: '600',
175
  },
176
});