eletrotupi / tcc/ frontend/components/ui/Button.tsxe859306d5d146d94a8a17ec574c428b9cb94792c
4.1 KB | 192 lines Raw
1
import React from 'react';
2
import {
3
  TouchableOpacity,
4
  StyleSheet,
5
  ActivityIndicator,
6
  TouchableOpacityProps,
7
  ViewStyle,
8
  TextStyle,
9
} from 'react-native';
10
import { Text } from '@/components/ui/Text';
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({}, 'secondaryBackground');
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
        return textColor;
65
      case 'secondary':
66
        return useThemeColor({}, 'white');
67
      case 'outline':
68
      case 'ghost':
69
        return textColor;
70
      case 'dashed':
71
        return textSecondaryColor;
72
      default:
73
        return '#fff';
74
    }
75
  };
76

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

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

96
    return 'transparent';
97
  };
98

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

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

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

129
  const getLineHeight = () => {
130
    switch (size) {
131
      case 'small':
132
        return 18;
133
      case 'medium':
134
        return 20;
135
      case 'large':
136
        return 22;
137
      default:
138
        return 20;
139
    }
140
  };
141

142
  return (
143
    <TouchableOpacity
144
      style={[
145
        styles.button,
146
        {
147
          backgroundColor: getBackgroundColor(),
148
          borderWidth: getBorderWidth(),
149
          borderColor: getBorderColor(),
150
          borderStyle: getBorderStyle(),
151
          height: getHeight(),
152
          opacity: disabled || loading ? 0.6 : 1,
153
        },
154
        style,
155
      ]}
156
      disabled={disabled || loading}
157
      onPress={onPress}
158
      {...props}
159
    >
160
      {loading ? (
161
        <ActivityIndicator color={getTextColor()} />
162
      ) : (
163
        <Text
164
          style={[
165
            styles.text,
166
            {
167
              color: getTextColor(),
168
              fontSize: getFontSize(),
169
              lineHeight: getLineHeight(),
170
            },
171
            textStyle,
172
          ]}
173
        >
174
          {title}
175
        </Text>
176
      )}
177
    </TouchableOpacity>
178
  );
179
};
180

181
const styles = StyleSheet.create({
182
  button: {
183
    borderRadius: 8,
184
    paddingHorizontal: 20,
185
    alignItems: 'center',
186
    justifyContent: 'center',
187
    marginVertical: 8,
188
  },
189
  text: {
190
    fontWeight: '600',
191
  },
192
});