eletrotupi / tcc/ frontend/components/ui/EmojiSelectors.tsxebb9f22f58004bd59460381e60090d37c17329fb
3.1 KB | 125 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: T<{
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 =>
87
    typeof icon === "string";
88

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

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