import { type ReactNode, useEffect } from "react"; import { TouchableOpacity, type TouchableOpacityProps } from "react-native"; import { select } from "../dialog/select"; import { Flex } from "../flex"; import { isArrayOfStrings } from "../helpers/is-array-of-strings"; import { Icon } from "../icon"; import { DEFAULT_STRINGS } from "../lang/default-strings"; import { Text } from "../text"; import { makeStyles } from "../theme"; import { useDisabledStyles } from "../theme/default-styles"; import FieldErrors from "./field-errors"; type SelectProps = { onChange: (selected: T | string | null) => void; label?: string; errors?: string[]; disabled?: boolean; defaultSelectedIndex?: number; allowDeselect?: boolean; style?: TouchableOpacityProps["style"]; } & ( | { data: string[]; selected: string } | { data: { values: T[]; renderItem: (item: T, key: React.Key) => ReactNode }; selected: T; } ); export function Select({ data, selected, onChange, label, errors, disabled = false, defaultSelectedIndex, allowDeselect = false, style, }: SelectProps) { const styles = useStyles(); const disabledStyles = useDisabledStyles(); useEffect(() => { if (allowDeselect && defaultSelectedIndex === undefined) { return; } if (isArrayOfStrings(data)) { if (data.length === 0) { return; } if (defaultSelectedIndex !== undefined) { onChange(data[defaultSelectedIndex]!); } else { onChange(data[0]!); } } else { if (data.values.length === 0) { return; } if (defaultSelectedIndex !== undefined) { onChange(data.values[defaultSelectedIndex]!); } else { onChange(data.values[0]!); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const openSelect = () => { // Dialog.select causes require cycle, so keep import from source function here. select( label || DEFAULT_STRINGS.select, data, (item: T | string) => { onChange(item); }, { cancelable: false, } ); }; return ( {label && {label}} {isArrayOfStrings(data) ? ( {selected as string} ) : ( data.renderItem(selected as T, 0) )} {allowDeselect && selected && ( onChange(null)} disabled={disabled} > )} ); } const useStyles = makeStyles((theme) => ({ input: { borderWidth: 1, borderRadius: theme.radius("default"), borderColor: theme.colors.get("gray", [4, 6]), padding: theme.spacing("default"), color: theme.colors.get("gray", [8, 2]), }, upperIcon: { marginBottom: -4, }, lowerIcon: { marginTop: -4, }, }));