1import { useCallback, useMemo } from 'react'; 2import { View, StyleSheet, TouchableOpacity, Text } from 'react-native'; 3 4import { PrimitiveArgument } from './index.types'; 5import Colors from '../../constants/Colors'; 6 7// Exclude boolean as this type should not be handled by this component. 8type Value = Exclude<PrimitiveArgument, boolean>; 9type EnumValue = { name: string; value: Value }; 10 11type Props = { 12 value: Value; 13 onChange: (value: Value) => void; 14 values: Value[] | EnumValue[]; 15 disabled?: boolean; 16}; 17 18function valuesAreEnumValues(values: (Value | EnumValue)[]): values is EnumValue[] { 19 return values.every((value) => typeof value === 'object' && 'name' in value && 'value' in value); 20} 21 22function useEnumValues(values: Value[] | EnumValue[]): values is EnumValue[] { 23 return useMemo(() => valuesAreEnumValues(values), [values]); 24} 25 26function getSuccessorCyclically(values: Value[], value: Value) { 27 const valueIdx = values.findIndex((v) => v === value); 28 const successorIdx = (valueIdx + 1) % values.length; 29 return values[successorIdx]; 30} 31 32/** 33 * Button component that upon every press switches to the next value from the array. 34 */ 35export default function EnumButton({ value, onChange, values, disabled }: Props) { 36 const valuesAreEnums = useEnumValues(values); 37 38 const handleOnPress = useCallback(() => { 39 const plainValues = valuesAreEnums ? values.map((v) => v.value) : values; 40 const newValue = getSuccessorCyclically(plainValues, value); 41 return onChange(newValue); 42 }, [valuesAreEnums, onChange, value, values]); 43 44 return ( 45 <TouchableOpacity disabled={disabled} onPress={handleOnPress}> 46 <View style={[styles.button, disabled && styles.buttonDisabled]}> 47 <Text style={styles.text}> 48 {valuesAreEnums ? values.find((element) => element.value === value)?.name : value} 49 </Text> 50 </View> 51 </TouchableOpacity> 52 ); 53} 54 55const styles = StyleSheet.create({ 56 button: { 57 marginLeft: 5, 58 paddingVertical: 3, 59 paddingHorizontal: 6, 60 backgroundColor: Colors.tintColor, 61 borderRadius: 5, 62 minWidth: 30, 63 alignItems: 'center', 64 }, 65 text: { 66 fontSize: 10, 67 padding: 2, 68 fontWeight: '500', 69 color: 'white', 70 }, 71 buttonDisabled: { 72 backgroundColor: '#CCD6DD', 73 }, 74}); 75