import React, { ComponentPropsWithRef, forwardRef, ReactElement, ReactNode, useEffect, useState } from 'react'; import { Flex, FlexProps } from '../../components'; import { UIComponentWithRef, UIStyledComponentProps } from '../../components/types'; import { SizeVariant } from '../../variants'; import { RadioBase } from './radio-base'; type Props = Omit, 'size'> & { initialValue?: string; size?: SizeVariant; children?: ReactNode; }; export type RadioGroupProps = UIStyledComponentProps; export type RadioGroupComponent = UIComponentWithRef; export const RadioGroup: RadioGroupComponent = forwardRef(({ children, className, size, initialValue, onChange, ...props }, ref) => { const [value, setValue] = useState(initialValue || null); useEffect(() => { setValue(initialValue || null); }, [initialValue]); const onChange_ = (event: React.ChangeEvent) => { setValue(event.target.value); if (onChange) { onChange(event); } if (event.defaultPrevented) { return; } }; const mappedChildren = recursiveMap(children, (child: ReactElement) => { if (child.type === RadioBase) { const props = (child as React.ReactElement).props; return React.cloneElement(child as React.ReactElement, { ...props, size: props.size || size, checked: props.value === value, onChange: onChange_, }); } return child; }); // !!! ref to group return ( {mappedChildren} ); }); RadioGroup.displayName = 'RadioGroup'; function recursiveMap(children: React.ReactNode, fn: (child: ReactElement) => ReactElement): ReactElement[] { return React.Children.map(children as ReactElement[], child => { if (!React.isValidElement(child)) { return child; } if ((child as React.ReactElement).props.children) { const props = { children: recursiveMap((child as React.ReactElement).props.children, fn), }; child = React.cloneElement(child, props); } return fn(child); }); }