/// /** * Fab Component - Lynx 版 MUI Fab * 100% 一比一复刻 MUI Fab * * 浮动操作按钮,圆形或扩展形状 * * 对应 MUI: packages/mui-material/src/Fab/Fab.js */ import './Fab.css' import fabClasses, { getFabUtilityClass } from './fabClasses' export { fabClasses, getFabUtilityClass } // ============================================= // 类型定义 // ============================================= export type FabColor = 'inherit' | 'primary' | 'secondary' | 'default' | 'error' | 'info' | 'success' | 'warning' export type FabSize = 'small' | 'medium' | 'large' export type FabVariant = 'circular' | 'extended' export interface FabProps { /** 子元素 */ children?: any /** 自定义类名 */ className?: string /** 样式类覆盖 */ classes?: Partial /** 颜色 */ color?: FabColor /** 是否禁用 */ disabled?: boolean /** 是否禁用涟漪 */ disableRipple?: boolean /** 组件根元素 */ component?: string /** href 属性 */ href?: string /** 尺寸 */ size?: FabSize /** 变体 */ variant?: FabVariant /** 内联样式 */ style?: Record /** sx 属性 */ sx?: Record /** 点击事件 */ bindtap?: (event?: any) => void onClick?: (event: any) => 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 FabProps {} function useUtilityClasses(ownerState: OwnerState) { const { classes, color = 'default', variant = 'circular', size = 'large' } = ownerState const slots = { root: [ 'root', variant, `size${capitalize(size)}`, color === 'inherit' ? 'colorInherit' : color, ], } return composeClasses(slots, getFabUtilityClass, classes) } // ============================================= // Fab 组件 // ============================================= export function Fab(props: FabProps) { const { children, className, classes: classesProp, color = 'default', disabled = false, disableRipple = false, component = 'button', href, size = 'large', variant = 'circular', style, sx, bindtap, onClick, ...other } = props const ownerState: OwnerState = { ...props, color, disabled, variant, size, } const classes = useUtilityClasses(ownerState) // 处理点击事件 const handleTap = (event?: any) => { if (disabled) return if (bindtap) bindtap(event) if (onClick) onClick(event) } // 构建类名 const rootClasses = [ classes.root, fabClasses.root, className, color !== 'default' && fabClasses[`color${capitalize(color)}` as keyof typeof fabClasses], variant === 'extended' && fabClasses.extended, variant === 'circular' && fabClasses.circular, fabClasses[`size${capitalize(size)}` as keyof typeof fabClasses], disabled && fabClasses.disabled, ].filter(Boolean).join(' ') // 确定根元素类型 const Component = href ? 'a' : component return ( {children} ) } export default Fab