/// /** * ButtonGroup Component - Lynx 版 MUI ButtonGroup * 100% 一比一复刻 MUI ButtonGroup * * 按钮组容器,管理子按钮的样式和状态 * * 对应 MUI: packages/mui-material/src/ButtonGroup/ButtonGroup.js */ import './ButtonGroup.css' import buttonGroupClasses, { getButtonGroupUtilityClass } from './buttonGroupClasses' export { buttonGroupClasses, getButtonGroupUtilityClass } // ============================================= // 类型定义 // ============================================= export type ButtonGroupColor = 'inherit' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' export type ButtonGroupOrientation = 'horizontal' | 'vertical' export type ButtonGroupSize = 'small' | 'medium' | 'large' export type ButtonGroupVariant = 'text' | 'outlined' | 'contained' export interface ButtonGroupProps { /** 子元素 */ children?: any /** 自定义类名 */ className?: string /** 样式类覆盖 */ classes?: Partial /** 颜色 */ color?: ButtonGroupColor /** 是否禁用所有按钮 */ disabled?: boolean /** 是否禁用阴影 */ disableElevation?: boolean /** 是否禁用涟漪 */ disableRipple?: boolean /** 是否全宽 */ fullWidth?: boolean /** 方向 */ orientation?: ButtonGroupOrientation /** 尺寸 */ size?: ButtonGroupSize /** 变体 */ variant?: ButtonGroupVariant /** 内联样式 */ style?: Record /** sx 属性 */ sx?: Record } // ============================================= // 辅助函数 // ============================================= 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 ButtonGroupProps {} function useUtilityClasses(ownerState: OwnerState) { const { classes, color = 'primary', disabled, disableElevation, fullWidth, orientation = 'horizontal', variant = 'outlined' } = ownerState const slots = { root: [ 'root', variant, orientation, fullWidth && 'fullWidth', disableElevation && 'disableElevation', `color${capitalize(color)}`, ], grouped: [ 'grouped', `grouped${capitalize(orientation)}`, `grouped${capitalize(variant)}`, `grouped${capitalize(variant)}${capitalize(orientation)}`, `grouped${capitalize(variant)}${capitalize(color)}`, disabled && 'disabled', ], firstButton: ['firstButton'], lastButton: ['lastButton'], middleButton: ['middleButton'], } return composeClasses(slots, getButtonGroupUtilityClass, classes) } // ============================================= // ButtonGroup 组件 // ============================================= export function ButtonGroup(props: ButtonGroupProps) { const { children, className, classes: classesProp, color = 'primary', disabled = false, disableElevation = false, disableRipple = false, fullWidth = false, orientation = 'horizontal', size = 'medium', variant = 'outlined', style, sx, ...other } = props const ownerState: OwnerState = { ...props, color, disabled, disableElevation, fullWidth, orientation, variant, } const classes = useUtilityClasses(ownerState) // 在 Lynx 环境下,不进行子组件克隆 // 开发者需要手动管理 Button 的样式 const enhancedChildren = children // 构建类名 const rootClasses = [ classes.root, buttonGroupClasses.root, className, variant && buttonGroupClasses[variant as keyof typeof buttonGroupClasses], orientation === 'vertical' && buttonGroupClasses.vertical, fullWidth && buttonGroupClasses.fullWidth, disableElevation && buttonGroupClasses.disableElevation, color !== 'primary' && buttonGroupClasses[`color${capitalize(color)}` as keyof typeof buttonGroupClasses], ].filter(Boolean).join(' ') return ( {enhancedChildren} ) } export default ButtonGroup