eletrotupi / tcc/ frontend/components/ui/EmojiSelectors.tsxdccd3efd61467f2a76eb2773b7e114f1199d46d2
3.1 KB | 126 lines Raw
1
import React from "react";
2
import {
3
  View,
4
  Pressable,
5
  StyleSheet,
6
  Image,
7
  ImageSourcePropType,
8
  ViewStyle,
9
} from "react-native";
10
import { Text } from "@/components/ui/Text";
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: {
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 surfaceColor = useThemeColor({}, "surface");
38
  const dividerColor = useThemeColor({}, "divider");
39
  const textSecondaryColor = useThemeColor({}, "textSecondary");
40

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

85
  const isEmoji = (icon: IconSource): icon is string =>
86
    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
              testID={`mood-${item.id}`}
99
              accessibilityLabel={item.label}
100
              style={({ pressed }) => [
101
                styles.itemButton,
102
                isSelected && styles.itemButtonActive,
103
                pressed && !disabled && { opacity: 0.7 },
104
                disabled && { opacity: 0.5 },
105
              ]}
106
            >
107
              {isEmoji(item.icon) ? (
108
                <Text style={styles.emojiText}>{item.icon}</Text>
109
              ) : (
110
                <Image
111
                  source={item.icon}
112
                  style={{
113
                    width: 48,
114
                    height: 48,
115
                  }}
116
                  resizeMode="contain"
117
                />
118
              )}
119
            </Pressable>
120
            <Text style={styles.label}>{item.label}</Text>
121
          </View>
122
        );
123
      })}
124
    </View>
125
  );
126
};