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
}