fix(CopyButton): use shadcn buttonVariants instead of duplicated variant classes

Remove hand-written variantClasses/sizeClasses that duplicated shadcn's
buttonVariants. Now extends ButtonProps and imports buttonVariants from
components/ui/button for consistent styling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
雨霖铃
2026-05-27 13:48:02 +08:00
parent c61b599287
commit 601260797e
+11 -32
View File
@@ -1,23 +1,20 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { Check, Copy } from 'lucide-react'; import { Check, Copy } from 'lucide-react';
import { copyTextToClipboard } from '@/utils/clipboard'; import { copyTextToClipboard } from '@/utils/clipboard';
import { cn } from '@/lib/utils'; // 1. 必须使用 cn 工具函数 import { cn } from '@/lib/utils';
import { toast } from 'sonner'; // 2. 推荐使用 shadcn 默认的全局 toast import { buttonVariants, type ButtonProps } from '@/components/ui/button';
import { toast } from 'sonner';
// 3. 继承原生按钮属性,允许外部自由扩展 className、variant 等 interface CopyButtonProps extends Omit<ButtonProps, 'children' | 'onClick'> {
interface CopyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
text: string; text: string;
tooltip?: string; tooltip?: string;
size?: 'small' | 'medium' | 'large';
// 移除复杂的自定义颜色变体,交由 Tailwind 类名或 shadcn 的 variant 解决
variant?: 'default' | 'secondary' | 'ghost' | 'outline';
} }
export const CopyButton: React.FC<CopyButtonProps> = ({ export const CopyButton: React.FC<CopyButtonProps> = ({
text, text,
tooltip = '复制', tooltip = '复制',
size = 'small',
variant = 'ghost', variant = 'ghost',
size = 'sm',
className, className,
...props ...props
}) => { }) => {
@@ -31,7 +28,7 @@ export const CopyButton: React.FC<CopyButtonProps> = ({
}, []); }, []);
const handleCopy = async (e: React.MouseEvent<HTMLButtonElement>) => { const handleCopy = async (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation(); // 基础组件防冒泡,避免触发父级点击事件 e.stopPropagation();
if (!text) { if (!text) {
toast.error('无内容可复制'); toast.error('无内容可复制');
@@ -49,35 +46,17 @@ export const CopyButton: React.FC<CopyButtonProps> = ({
} }
}; };
// 4. 将控制尺寸的类名标准化
const sizeClasses = {
small: 'h-8 w-8 text-xs',
medium: 'h-10 w-10 text-sm',
large: 'h-12 w-12 text-base',
};
// 5. 映射 shadcn 的底层通用 Variant 类名
const variantClasses = {
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
outline:
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
};
return ( return (
<button <button
type="button" type="button"
onClick={handleCopy} onClick={handleCopy}
title={tooltip} title={tooltip}
// 6. 使用 cn() 合并类名,并完美支持暗黑模式的语义化变量 (destructive/muted等)
className={cn( className={cn(
'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', buttonVariants({ variant, size }),
sizeClasses[size], 'h-8 w-8',
copied copied &&
? 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400' // 兼顾暗黑模式的成功色 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 hover:bg-emerald-500/10',
: variantClasses[variant], className,
className, // 允许外部直接传入 text-red-500 等覆盖样式
)} )}
{...props} {...props}
> >