/// /** * FormControlLabel Component - Lynx 版 MUI FormControlLabel * 100% 一比一复刻 MUI FormControlLabel * * 将表单控件(Checkbox、Radio、Switch)与标签组合在一起 * * 对应 MUI: packages/mui-material/src/FormControlLabel/FormControlLabel.js */ import './FormControlLabel.css' import formControlLabelClasses, { getFormControlLabelUtilityClass } from './formControlLabelClasses' import { useFormControl, formControlState } from '../FormControl' export { formControlLabelClasses, getFormControlLabelUtilityClass } // ============================================= // 类型定义 // ============================================= export type FormControlLabelLabelPlacement = 'end' | 'start' | 'top' | 'bottom' export interface FormControlLabelProps { /** 表单控件 */ control: any /** 标签文本 */ label: any /** 自定义类名 */ className?: string /** 样式类覆盖 */ classes?: Partial /** 是否选中 - 传递给 control */ checked?: boolean /** 是否禁用 */ disabled?: boolean /** 是否禁用排版 */ disableTypography?: boolean /** input 元素的 ref */ inputRef?: any /** 标签位置 */ labelPlacement?: FormControlLabelLabelPlacement /** name 属性 */ name?: string /** 变化回调 */ onChange?: (event: any, checked: boolean) => void /** 是否必填 */ required?: boolean /** 内联样式 */ style?: Record /** sx 属性 */ sx?: Record /** 值 */ value?: string } // ============================================= // 辅助函数 // ============================================= function composeClasses( slots: Record, getUtilityClass: (slot: string) => string, classes?: Record ): Record { const output: Record = {} Object.keys(slots).forEach((slot) => { output[slot] = slots[slot] .filter(Boolean) .map((key) => { if (classes && classes[key as string]) { return `${getUtilityClass(key as string)} ${classes[key as string]}` } return getUtilityClass(key as string) }) .join(' ') }) return output } // ============================================= // useUtilityClasses // ============================================= interface OwnerState extends FormControlLabelProps {} function useUtilityClasses(ownerState: OwnerState & { error?: boolean }) { const { classes, disabled, error, required, labelPlacement = 'end' } = ownerState const slots = { root: [ 'root', disabled && 'disabled', error && 'error', required && 'required', labelPlacement !== 'end' && `labelPlacement${labelPlacement.charAt(0).toUpperCase() + labelPlacement.slice(1)}`, ], label: ['label', disabled && 'disabled'], asterisk: ['asterisk', error && 'error'], } return composeClasses(slots, getFormControlLabelUtilityClass, classes) } // ============================================= // FormControlLabel 组件 // ============================================= export function FormControlLabel(props: FormControlLabelProps) { const { control, label, className, classes: classesProp, checked, disabled: disabledProp, disableTypography = false, inputRef, labelPlacement = 'end', name, onChange, required: requiredProp, style, sx, value, ...other } = props const muiFormControl = useFormControl() const fcs = formControlState({ props, muiFormControl, states: ['disabled', 'error', 'required'], }) const disabled = disabledProp ?? control?.props?.disabled ?? fcs.disabled const required = requiredProp ?? control?.props?.required ?? fcs.required const ownerState: OwnerState & { error?: boolean } = { ...props, disabled, labelPlacement, required, error: fcs.error, } const classes = useUtilityClasses(ownerState) // 增强控件,注入必要的 props const controlProps: Record = { disabled, required, } // 传递可选 props if (checked !== undefined && control?.props?.checked === undefined) { controlProps.checked = checked } if (name !== undefined && control?.props?.name === undefined) { controlProps.name = name } if (onChange !== undefined && control?.props?.onChange === undefined) { controlProps.onChange = onChange } if (value !== undefined && control?.props?.value === undefined) { controlProps.value = value } if (inputRef !== undefined && control?.props?.inputRef === undefined) { controlProps.inputRef = inputRef } const enhancedControl = control ? { ...control, props: { ...control.props, ...controlProps, } } : null // 构建类名 const rootClasses = [ classes.root, formControlLabelClasses.root, className, disabled && formControlLabelClasses.disabled, fcs.error && formControlLabelClasses.error, labelPlacement !== 'end' && formControlLabelClasses[`labelPlacement${labelPlacement.charAt(0).toUpperCase() + labelPlacement.slice(1)}` as keyof typeof formControlLabelClasses], ].filter(Boolean).join(' ') const labelClasses = [ classes.label, formControlLabelClasses.label, disabled && formControlLabelClasses.disabled, ].filter(Boolean).join(' ') // 根据标签位置渲染不同布局 const renderContent = () => { switch (labelPlacement) { case 'start': return ( <> {label} {enhancedControl} ) case 'top': return ( {label} {enhancedControl} ) case 'bottom': return ( {enhancedControl} {label} ) case 'end': default: return ( <> {enhancedControl} {label} ) } } return ( {renderContent()} ) } export default FormControlLabel