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