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