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