///
/**
* 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