eletrotupi / tcc/ frontend/components/ui/EmojiSelectors.tsx164355ee693dc3ac93d11260eab56ea45a2a76e0
3.1 KB | 124 lines Raw
1
import React from 'react';
2
import {
3
  View,
4
  Pressable,
5
  StyleSheet,
6
  Image,
7
  Text,
8
  ImageSourcePropType,
9
  ViewStyle,
10
} from 'react-native';
11
import { Spacing, Typography, BorderRadius } from '@/constants/theme';
12
import { useThemeColor } from '@/hooks/use-theme-color';
13

14
type IconSource = string | ImageSourcePropType; // either string or a svg
15

16
// Specialized variant with labels below
17
interface MoodSelectorProps {
18
  items: Array<{
19
    id: string;
20
    icon: IconSource;
21
    label: string;
22
  }>;
23
  value?: string;
24
  onSelect: (id: string) => void;
25
  disabled?: boolean;
26
  style?: ViewStyle;
27
}
28

29
export const MoodSelector: React.FC<MoodSelectorProps> = ({
30
  items,
31
  value,
32
  onSelect,
33
  disabled = false,
34
  style,
35
}) => {
36
  const accentBlueColor = useThemeColor({}, 'accentBlue');
37
  const tintColor = useThemeColor({}, 'tint');
38
  const surfaceColor = useThemeColor({}, 'surface');
39
  const dividerColor = useThemeColor({}, 'divider');
40
  const textSecondaryColor = useThemeColor({}, 'textSecondary');
41

42
  const styles = StyleSheet.create({
43
    container: {
44
      flexDirection: 'row',
45
      gap: Spacing.inlineGapSm,
46
      justifyContent: 'space-around',
47
      alignItems: 'flex-start',
48
      flexWrap: 'wrap',
49
    },
50
    itemWrapper: {
51
      alignItems: 'center',
52
      gap: 8,
53
      flex: 1,
54
      minWidth: '8%',
55
    },
56
    itemButton: {
57
      width: 50,
58
      height: 50,
59
      borderRadius: BorderRadius.lg,
60
      justifyContent: 'center',
61
      alignItems: 'center',
62
      backgroundColor: surfaceColor,
63
      borderWidth: 1,
64
      borderColor: dividerColor,
65
    },
66
    itemButtonActive: {
67
      backgroundColor: accentBlueColor,
68
      borderColor: 'transparent',
69
    },
70
    icon: {
71
      fontSize: 48,
72
      lineHeight: 48,
73
    },
74
    emojiText: {
75
      fontSize: 36,
76
      lineHeight: 40,
77
    },
78
    label: {
79
      fontSize: Typography.labelSm.fontSize,
80
      fontWeight: '500',
81
      color: textSecondaryColor,
82
      textAlign: 'center',
83
    },
84
  });
85

86
  const isEmoji = (icon: IconSource): icon is string => typeof icon === 'string';
87

88
  return (
89
    <View style={[styles.container, style]}>
90
      {items.map((item) => {
91
        const isSelected = value === item.id;
92

93
        return (
94
          <View key={item.id} style={styles.itemWrapper}>
95
            <Pressable
96
              onPress={() => !disabled && onSelect(item.id)}
97
              disabled={disabled}
98
              style={({ pressed }) => [
99
                styles.itemButton,
100
                isSelected && styles.itemButtonActive,
101
                pressed && !disabled && { opacity: 0.7 },
102
                disabled && { opacity: 0.5 },
103
              ]}
104
            >
105
              {isEmoji(item.icon) ? (
106
                <Text style={styles.emojiText}>{item.icon}</Text>
107
              ) : (
108
                <Image
109
                  source={item.icon}
110
                  style={{
111
                    width: 48,
112
                    height: 48,
113
                  }}
114
                  resizeMode="contain"
115
                />
116
              )}
117
            </Pressable>
118
            <Text style={styles.label}>{item.label}</Text>
119
          </View>
120
        );
121
      })}
122
    </View>
123
  );
124
};