import { Radio } from '@ankhorage/surface'; import React from 'react'; import { StyleSheet } from 'react-native'; import type { RadioGroupProps } from '../../../../../types/radio'; import { View } from '../../../../layout/public'; import { withZoraThemeScope } from '../../../../theme/adapters/inbound/withZoraThemeScope'; import { useZoraThemeRecipe } from '../../../../theme/composition/useZoraThemeRecipe'; import { Text } from '../../../../typography/public'; import { resolveRadioGroupThemeRecipe } from '../../utils/resolveRadioGroupThemeRecipe'; import { RadioOptionControl } from './RadioOptionControl'; /*** Present one controlled single-choice group as inline radios or icon radio options. */ export const RadioGroup = withZoraThemeScope(RadioGroupInner); /*** Resolve shared presentation once and preserve a single interaction boundary per option. */ function RadioGroupInner({ themeId: _themeId, mode: _mode, ...props }: RadioGroupProps) { const [localValue, setLocalValue] = React.useState(props.defaultValue); const onValueChange = (next: TValue) => { if (props.value === undefined) setLocalValue(next); props.onValueChange?.(next); }; const selectedProps = { ...props, value: props.value ?? localValue, onValueChange }; const themeFields = useZoraThemeRecipe('RadioGroup'); const recipe = resolveRadioGroupThemeRecipe({ ...props, themeFields }); if (props.presentation !== 'card') return ; const columns = props.columns ?? (props.orientation === 'horizontal' ? Math.max(1, props.options.length) : 1); const rows = Array.from({ length: Math.ceil(props.options.length / columns) }, (_, index) => props.options.slice(index * columns, (index + 1) * columns), ); return ( {rows.map((options, index) => ( {options.map((option) => ( ))} {Array.from({ length: columns - options.length }, (_, slot) => ( ))} ))} ); } /*** Preserve ordinary radio wrapping independently of the icon-option grid. */ function RadioGroupInline(props: RadioGroupProps) { return ( {props.options.map((option) => ( ))} ); } /*** Delegate icon options to their composed radio boundary and ordinary options to Surface Radio. */ function RadioGroupItem( props: RadioGroupProps & { option: RadioGroupProps['options'][number]; }, ) { const { option, value, onValueChange, interactionPolicy, color, size } = props; const checked = value === option.value; const inactive = props.disabled === true || option.disabled === true; const readOnly = props.readOnly === true; const invalid = props.invalid === true; const onSelect = () => { if (!inactive && !readOnly && interactionPolicy !== 'passive' && !checked) onValueChange?.(option.value); }; if (props.presentation === 'card') { return ( ); } return ( {option.label} {option.description ? ( {option.description} ) : null} ); } const styles = StyleSheet.create({ option: { flex: 1, minWidth: 0 } });