diff --git a/components/SwitchButtonGroup.tsx b/components/SwitchButtonGroup.tsx index 016c93c..cf4c8ee 100644 --- a/components/SwitchButtonGroup.tsx +++ b/components/SwitchButtonGroup.tsx @@ -1,53 +1,75 @@ +import React from 'react'; +import { cn } from '@/lib/utils'; // 1. 引入标准的 shadcn 工具函数 + export interface SwitchOption { value: T; label: React.ReactNode; } -export interface SwitchButtonGroupProps { +// 2. 移除内联 sx,继承标准 HTML 属性,并使用标准的类名注入机制 +export interface SwitchButtonGroupProps extends Omit< + React.HTMLAttributes, + 'onChange' +> { value: T; options: SwitchOption[]; onChange: (value: T) => void; - sx?: React.CSSProperties; size?: 'small' | 'medium' | 'large'; - buttonSx?: React.CSSProperties; + buttonClassName?: string; // 替换原有的 buttonSx } export default function SwitchButtonGroup({ value, options, onChange, - sx, size = 'medium', - buttonSx, + className, + buttonClassName, + ...props }: SwitchButtonGroupProps) { + // 3. 将尺寸和高度、内边距等整体对齐,保证按钮和背景容器成比例缩放 const sizeClasses = { - small: 'text-xs', - medium: 'text-sm', - large: 'text-base', + small: 'text-xs h-8 px-2 py-1 rounded-md', + medium: 'text-sm h-9 px-3 py-1.5 rounded-md', + large: 'text-base h-11 px-4 py-2 rounded-lg', }; + const containerPadding = size === 'large' ? 'p-1' : 'p-1'; + return (
- {options.map((option) => ( - - ))} + {options.map((option) => { + const isSelected = value === option.value; + + return ( + + ); + })}
); } diff --git a/components/__tests__/SwitchButtonGroup.test.tsx b/components/__tests__/SwitchButtonGroup.test.tsx index 0bd9737..cc108ac 100644 --- a/components/__tests__/SwitchButtonGroup.test.tsx +++ b/components/__tests__/SwitchButtonGroup.test.tsx @@ -21,10 +21,10 @@ describe('SwitchButtonGroup 组件', () => { const buttonA = screen.getByRole('button', { name: /选项A/i }); const buttonB = screen.getByRole('button', { name: /选项B/i }); - // 选中的按钮有 bg-background text-primary shadow-sm 类 - expect(buttonA).toHaveClass('bg-primary', 'text-primary-foreground', 'shadow-md'); - // 未选中的按钮有 text-muted-foreground 类 - expect(buttonB).toHaveClass('text-muted-foreground'); + // 选中的按钮有 bg-background text-foreground shadow-sm 类 + expect(buttonA).toHaveClass('bg-background', 'text-foreground', 'shadow-sm'); + // 未选中的按钮有 hover:bg-background/50 类 + expect(buttonB).toHaveClass('hover:bg-background/50'); }); it('点击未选中按钮时应触发 onChange 并传入选中值', () => { @@ -45,13 +45,13 @@ describe('SwitchButtonGroup 组件', () => { expect(handleChange).toHaveBeenCalledWith('a'); }); - it('应支持通过 sx 自定义样式', () => { + it('应支持通过 className 自定义样式', () => { const { container } = render( - , + , ); - const group = container.querySelector('.flex.gap-1'); - expect(group).toBeInTheDocument(); + const group = container.firstChild; + expect(group).toHaveClass('custom-group'); }); it('应支持 size 属性', () => { @@ -62,14 +62,7 @@ describe('SwitchButtonGroup 组件', () => { }); it('应支持 buttonSx 自定义按钮样式', () => { - render( - , - ); + render(); const button = screen.getByRole('button', { name: /选项A/i }); expect(button).toBeInTheDocument(); @@ -90,14 +83,7 @@ describe('SwitchButtonGroup 组件', () => { }); it('buttonSx 传入时应覆盖默认换行样式', () => { - render( - , - ); + render(); const button = screen.getByRole('button', { name: /选项A/i }); expect(button).toBeInTheDocument(); @@ -122,8 +108,8 @@ describe('SwitchButtonGroup 组件', () => { const button2 = screen.getByRole('button', { name: /^2$/i }); const button4 = screen.getByRole('button', { name: /^4$/i }); - expect(button2).toHaveClass('text-muted-foreground'); - expect(button4).toHaveClass('bg-primary', 'text-primary-foreground', 'shadow-md'); + expect(button2).toHaveClass('hover:bg-background/50'); + expect(button4).toHaveClass('bg-background', 'text-foreground', 'shadow-sm'); }); it('点击 number 选项时应传回 number 值', () => {