/// /** * InputLabel Component - Lynx 版 MUI InputLabel * 100% 一比一复刻 MUI InputLabel * * 对应 MUI: packages/mui-material/src/InputLabel/InputLabel.js */ import './InputLabel.css' import inputLabelClasses, { getInputLabelUtilityClass } from './inputLabelClasses' import { useFormControl, formControlState } from '../FormControl' export { inputLabelClasses, getInputLabelUtilityClass } // ============================================= // 类型定义 // ============================================= export type InputLabelColor = 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' export type InputLabelMargin = 'dense' export type InputLabelSize = 'small' | 'normal' export type InputLabelVariant = 'standard' | 'outlined' | 'filled' export interface InputLabelProps { /** 子元素 */ children?: any /** 自定义类名 */ className?: string /** 样式类覆盖 */ classes?: Partial /** 颜色 */ color?: InputLabelColor /** 是否禁用动画 */ disableAnimation?: boolean /** 是否禁用 */ disabled?: boolean /** 是否错误状态 */ error?: boolean /** 是否聚焦 */ focused?: boolean /** htmlFor */ htmlFor?: string /** 边距 */ margin?: InputLabelMargin /** 是否必填 */ required?: boolean /** 是否收缩 */ shrink?: boolean /** 尺寸 */ size?: InputLabelSize /** 内联样式 */ style?: Record /** sx 属性 */ sx?: Record /** 变体 */ variant?: InputLabelVariant } // ============================================= // 辅助函数 // ============================================= function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1) } 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 InputLabelProps { formControl?: boolean } function useUtilityClasses(ownerState: OwnerState) { const { classes, disabled, error, focused, formControl, required, shrink, size, variant, disableAnimation, } = ownerState const slots = { root: [ 'root', formControl && 'formControl', !disableAnimation && 'animated', shrink && 'shrink', size && size !== 'normal' && `size${capitalize(size)}`, variant, ], asterisk: [required && 'asterisk'], } return composeClasses(slots, getInputLabelUtilityClass, classes) } // ============================================= // InputLabel 组件 // ============================================= export function InputLabel(props: InputLabelProps) { const { children, className, classes: classesProp, color, disableAnimation = false, disabled, error, focused, htmlFor, margin, required, shrink, size, style, sx, variant, ...other } = props const muiFormControl = useFormControl() const fcs = formControlState({ props, muiFormControl, states: ['color', 'disabled', 'error', 'focused', 'hiddenLabel', 'required', 'size', 'variant'], }) const computedShrink = shrink ?? (fcs.filled || fcs.focused || fcs.adornedStart) const ownerState: OwnerState = { ...props, color: fcs.color || 'primary', disabled: fcs.disabled, error: fcs.error, focused: fcs.focused, formControl: !!muiFormControl, required: fcs.required, shrink: computedShrink, size: fcs.size, variant: fcs.variant || 'outlined', disableAnimation, } const classes = useUtilityClasses(ownerState) // 构建类名 const rootClasses = [ classes.root, className, fcs.disabled && 'Mui-disabled', fcs.error && 'Mui-error', fcs.focused && 'Mui-focused', fcs.required && 'Mui-required', ].filter(Boolean).join(' ') return ( {children} {fcs.required && ( * )} ) } export default InputLabel