top-tran/toptran-app/src/components/Select.tsx

178 lines
4.3 KiB
TypeScript
Raw Normal View History

import { BORDER_RADIUS, COLORS, SPACING } from "@/constants/theme";
import React, { useState } from "react";
import {
FlatList,
Modal,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
2026-05-03 01:16:25 -03:00
type SelectProps = {
label?: string;
value: string;
onValueChange: (value: string) => void;
items: { label: string; value: string }[];
};
export function Select({ label, value, onValueChange, items }: SelectProps) {
const [open, setOpen] = useState(false);
const selected = items.find((i) => i.value === value);
2026-05-03 01:16:25 -03:00
return (
<View style={styles.container}>
{label && <Text style={styles.label}>{label}</Text>}
<TouchableOpacity
style={styles.trigger}
onPress={() => setOpen(true)}
activeOpacity={0.7}
>
<Text
style={[
styles.triggerText,
!selected?.value && styles.triggerPlaceholder,
]}
numberOfLines={1}
2026-05-03 01:16:25 -03:00
>
{selected?.label ?? "Selecione"}
</Text>
<Text style={styles.arrow}></Text>
</TouchableOpacity>
<Modal visible={open} transparent animationType="fade">
<TouchableOpacity
style={styles.backdrop}
activeOpacity={1}
onPress={() => setOpen(false)}
>
<SafeAreaView style={styles.sheet} onStartShouldSetResponder={() => true}>
<View style={styles.sheetHandle} />
<FlatList
data={items}
keyExtractor={(item) => item.value}
renderItem={({ item }) => (
<TouchableOpacity
style={[
styles.option,
item.value === value && styles.optionSelected,
]}
onPress={() => {
onValueChange(item.value);
setOpen(false);
}}
activeOpacity={0.7}
>
<Text
style={[
styles.optionText,
item.value === value && styles.optionTextSelected,
!item.value && styles.optionPlaceholder,
]}
>
{item.label}
</Text>
{item.value === value && (
<Text style={styles.checkmark}></Text>
)}
</TouchableOpacity>
)}
2026-05-03 01:16:25 -03:00
/>
</SafeAreaView>
</TouchableOpacity>
</Modal>
2026-05-03 01:16:25 -03:00
</View>
);
}
const styles = StyleSheet.create({
container: {
width: "100%",
},
label: {
color: COLORS.text,
fontSize: 14,
fontWeight: "600",
marginBottom: SPACING.sm,
},
trigger: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
height: 48,
2026-05-03 01:16:25 -03:00
borderWidth: 1,
borderColor: COLORS.inputBorder,
backgroundColor: COLORS.inputBackground,
borderRadius: BORDER_RADIUS.md,
paddingHorizontal: SPACING.md,
2026-05-03 01:16:25 -03:00
},
triggerText: {
flex: 1,
fontSize: 15,
2026-05-03 01:16:25 -03:00
color: COLORS.inputText,
},
triggerPlaceholder: {
color: COLORS.inputPlaceholder,
},
arrow: {
fontSize: 14,
color: COLORS.textSecondary,
marginLeft: SPACING.sm,
},
// Modal
backdrop: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.6)",
justifyContent: "flex-end",
},
sheet: {
backgroundColor: COLORS.surface,
borderTopLeftRadius: BORDER_RADIUS.xl,
borderTopRightRadius: BORDER_RADIUS.xl,
maxHeight: "60%",
paddingBottom: SPACING.lg,
},
sheetHandle: {
width: 40,
height: 4,
backgroundColor: COLORS.border,
borderRadius: 2,
alignSelf: "center",
marginTop: SPACING.md,
marginBottom: SPACING.sm,
},
option: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingVertical: SPACING.md,
paddingHorizontal: SPACING.lg,
borderBottomWidth: 1,
borderBottomColor: COLORS.border,
},
optionSelected: {
backgroundColor: COLORS.surfaceLight,
},
optionText: {
fontSize: 15,
color: COLORS.text,
flex: 1,
},
optionTextSelected: {
fontWeight: "700",
color: COLORS.success,
},
optionPlaceholder: {
color: COLORS.textTertiary,
},
checkmark: {
fontSize: 16,
color: COLORS.success,
fontWeight: "700",
},
2026-05-03 01:16:25 -03:00
});