import {useTheme} from '../../theme/ThemeProvider'; import {memo, useCallback, useEffect, useState} from 'react'; import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; import {Pressable, StyleSheet, Text, View} from 'react-native'; import {renderIcon} from '../../helpers/renderIcon'; import {useDirection} from '../../hooks'; import type {IconProp, RadioProps} from '../../types'; import {RadioGlyph} from '../glyphs/Glyphs'; type OptionProps = { value: string | number; checkedIcon?: IconProp; unCheckedIcon?: IconProp; text?: string; checked: boolean; disabled?: boolean; border?: boolean; borderColor: string; iconColor: string; iconSize: number; iconPosition?: 'left' | 'bottom' | 'top' | 'right'; flexDirection: ViewStyle['flexDirection']; gap: ViewStyle['gap']; marginVertical: ViewStyle['marginVertical']; textColor?: string; textStyle?: StyleProp; testID?: string; onPress: (value: string | number) => void; }; const Option = memo( ({ value, text, checked, checkedIcon, unCheckedIcon, disabled, border, borderColor, iconColor, iconSize, iconPosition, flexDirection, gap, marginVertical, textColor, textStyle, testID, onPress, }: OptionProps) => ( onPress(value)} disabled={disabled} style={[ styles.option, { flexDirection, gap, justifyContent: iconPosition === 'right' ? 'space-between' : 'center', marginVertical, }, border && [ styles.border, {borderColor: disabled ? '#AAA' : borderColor}, ], ]}> {(checked ? checkedIcon : unCheckedIcon) ? ( renderIcon(checked ? checkedIcon : unCheckedIcon, { size: iconSize, color: disabled ? '#AAA' : iconColor, }) ) : ( )} {text ?? value} ), ); export const RadioButtons = (props: RadioProps) => { const {colors} = useTheme(); const { accessibilityLabel, border, borderColor = colors.primary, checkedIcon, unCheckedIcon, defaultChecked, disabled, fullWidth, gap, gapHorizontal = 10, iconColor = colors.primary, iconPosition, iconSize = 20, marginVertical = 8, onChange, orientation = 'vertical', style, testID, textColor, textStyle, values, } = props; const [checked, setChecked] = useState(); const {flexDirection, spacing} = useDirection( iconPosition, typeof gap === 'number' ? gap : undefined, ); // Derive a primitive so inline `values` arrays do not re-run the effect. const defaultValue = defaultChecked !== undefined ? values[defaultChecked]?.value : undefined; useEffect(() => { setChecked(defaultValue); }, [defaultValue]); const handlePress = useCallback( (value: string | number) => { setChecked(value); onChange?.(value); }, [onChange], ); return ( {values.map(({value, text}, index) => ( ); }; const styles = StyleSheet.create({ horizontal: { flexDirection: 'row', justifyContent: 'space-between', }, option: { alignItems: 'center', }, border: { borderWidth: 1, borderRadius: 3, paddingVertical: 5, paddingHorizontal: 10, }, });