/// /** * Checkbox Component - Lynx 版 MUI Checkbox * 100% 一比一复刻 MUI Checkbox * * 支持三种状态:unchecked、checked、indeterminate * 使用 CSS 实现图标而非 SVG * * 对应 MUI: packages/mui-material/src/Checkbox/Checkbox.js */ import './Checkbox.css' import checkboxClasses, { getCheckboxUtilityClass } from './checkboxClasses' export { checkboxClasses, getCheckboxUtilityClass } // ============================================= // 类型定义 // ============================================= export type CheckboxColor = 'primary' | 'secondary' | 'default' | 'error' | 'info' | 'success' | 'warning' export type CheckboxSize = 'small' | 'medium' export interface CheckboxProps { /** 自定义类名 */ className?: string /** 样式类覆盖 */ classes?: Partial /** 是否选中 */ checked?: boolean /** 选中图标 */ checkedIcon?: any /** 默认是否选中 */ defaultChecked?: boolean /** 是否禁用 */ disabled?: boolean /** 是否禁用涟漪 */ disableRipple?: boolean /** 未选中图标 */ icon?: any /** ID 属性 */ id?: string /** 是否 indeterminate 状态 */ indeterminate?: boolean /** indeterminate 图标 */ indeterminateIcon?: any /** 默认是否 indeterminate */ defaultIndeterminate?: boolean /** 传递给 input 元素的 props */ inputProps?: Record /** input 元素的 ref */ inputRef?: any /** name 属性 */ name?: string /** 是否必填 */ required?: boolean /** 颜色 - 默认 primary */ color?: CheckboxColor /** 尺寸 */ size?: CheckboxSize /** 内联样式 */ style?: Record /** sx 属性 */ sx?: Record /** 值 */ value?: string /** 点击事件 */ bindtap?: (event?: any) => void onChange?: (event: any, checked: boolean) => void } // ============================================= // 辅助函数 // ============================================= 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 CheckboxProps {} function useUtilityClasses(ownerState: OwnerState) { const { classes, checked, disabled, indeterminate, color = 'primary', size = 'medium' } = ownerState const slots = { root: [ 'root', checked && 'checked', disabled && 'disabled', indeterminate && 'indeterminate', color !== 'default' && `color${capitalize(color)}`, `size${capitalize(size)}`, ], } return composeClasses(slots, getCheckboxUtilityClass, classes) } // ============================================= // Checkbox 组件 // ============================================= export function Checkbox(props: CheckboxProps) { const { className, classes: classesProp, checked: checkedProp, defaultChecked = false, disabled = false, disableRipple = false, indeterminate: indeterminateProp, defaultIndeterminate = false, icon, checkedIcon, indeterminateIcon, id, inputProps, inputRef, name, required, color = 'primary', size = 'medium', style, sx, value, bindtap, onChange, ...other } = props // 在 Lynx 环境下,组件必须是受控的 // 如果没有提供 checked 属性,使用默认值 const checked = checkedProp !== undefined ? checkedProp : defaultChecked const indeterminate = indeterminateProp !== undefined ? indeterminateProp : defaultIndeterminate const ownerState: OwnerState = { ...props, checked, disabled, indeterminate, color, size, } const classes = useUtilityClasses(ownerState) // 处理点击 const handleTap = (event?: any) => { if (disabled) return const newChecked = !checked const newIndeterminate = false // 点击后清除 indeterminate 状态 // 在 Lynx 环境下,组件是受控的,不需要内部状态更新 // 状态由父组件管理 // 触发回调 if (bindtap) bindtap(event) if (onChange) onChange(event, newChecked) } // 构建类名 const rootClasses = [ classes.root, checkboxClasses.root, className, checked && checkboxClasses.checked, disabled && checkboxClasses.disabled, indeterminate && checkboxClasses.indeterminate, color !== 'default' && checkboxClasses[`color${capitalize(color)}` as keyof typeof checkboxClasses], checkboxClasses[`size${capitalize(size)}` as keyof typeof checkboxClasses], ].filter(Boolean).join(' ') return ( {/* Checkbox 图标 - 使用 CSS 实现 */} ) } export default Checkbox