eletrotupi / tcc/ frontend/components/ui/Button.tsx17dd47ad86ed5f8c9bc9360a4eb3917a7a635c8d
3.7 KB | 174 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';
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 'outline':
49
      case 'ghost':
50
      case 'dashed':
51
        return 'transparent';
52
      default:
53
        return primaryColor;
54
    }
55
  };
56

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

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

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

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

92
    return 'transparent';
93
  };
94

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

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

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

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

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