import React, { createContext, ReactNode, useCallback, useContext, useMemo } from 'react' import { CommonCheckboxProps, InternalCheckbox } from '../Checkbox/InternalCheckbox' import { ComponentSize, usePrefix } from '../ConfigProvider' import { concat, isDev } from '../utils' import { BaseCommonProps } from '../Input/input' import { useValue } from '../utils/hooks' interface InternalRadioProps extends CommonCheckboxProps { /** * radio 选项的样式类型 * @default default */ radioType?: 'default' | 'button' } function InternalRadio({ radioType, ...restProps }: InternalRadioProps) { let prefix = usePrefix('radio') if (radioType === 'button') { prefix = concat(prefix, 'btn') } return } type Value = string | number | boolean export type RadioValue = Value export interface RadioGroupProps extends Omit, 'onChange'> { /** 输入值发生变更时的回调, value 不可能出现 null */ onChange?: (value: T) => void /** * radio 选项的样式类型 * @default default */ radioType?: 'default' | 'button' /** 内容(包含 `Radio` ) */ children: ReactNode } interface RadioGroupContext { value?: T disabled?: boolean onRadioChange: (val: T) => void radioType: 'default' | 'button' size?: ComponentSize } const groupContext = createContext | null>(null) export function RadioGroup({ value: valueFromProps, defaultValue = null, disabled, onChange: onChangeFromProps, radioType = 'default', size, children }: RadioGroupProps) { const onChange = useCallback((v: T | null) => { onChangeFromProps?.(v!) }, [onChangeFromProps]) const { value, setValue } = useValue({ valueFromProps, defaultValue, onChange }) const onRadioChange = useCallback((v: T) => { setValue(v) }, [setValue]) const context: RadioGroupContext = useMemo(() => ({ value: value ?? undefined, disabled, onRadioChange, radioType, size }), [value, disabled, onRadioChange, radioType, size]) return ( {children} ) } export interface RadioProps extends InternalRadioProps { /** 该选项对应的值,在 Group 中使用时需要设置,Radio 单独使用时将被忽略 */ value?: T } export function Radio({ value, ...restProps }: RadioProps) { const radioGroup = useContext(groupContext) if (radioGroup) { if (isDev && value === undefined) { // eslint-disable-next-line no-console console.warn('`value` must be set when `` used in ``') } const radioProps: InternalRadioProps = { ...restProps } // 只有未选中的 radio 被点击时才会触发 onchange 事件,实际传入的 checked 参数只可能是 `true` radioProps.onChange = checked => { restProps.onChange?.(checked) radioGroup.onRadioChange(value) } radioProps.checked = radioGroup.value === value radioProps.disabled = restProps.disabled || radioGroup.disabled radioProps.radioType = radioGroup.radioType radioProps.size = radioProps.size ?? radioGroup.size return } return }