自动安装
npx tofu-ui-cli@latest add button
手动安装 (可选)
注意
如果你使用手动安装,将无法获取更新
在项目目录中创建
components/ui/tofu/button.tsx复制此代码
/**
* TofuUI Button 按钮组件
* @author shuakami
* @version 1.0.0
* @copyright ByteFreeze&TofuUI
*/
import React from 'react';
interface ButtonProps {
text: string; // 按钮文字
iconRight?: React.ReactNode; // 右侧图标
iconLeft?: React.ReactNode; // 左侧图标
onClick?: (event: any) => void; // 点击事件处理函数
disabled?: boolean; // 是否禁用
type?: 'button' | 'submit' | 'reset'; // 按钮类型
size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'; // 按钮大小
variant?: 'primary' | 'secondary' | 'outline'; // 按钮样式变体
fullWidth?: boolean; // 是否占据全部宽度
className?: string; // 自定义类名
url?: string; // 按钮链接
loading?: boolean; // 是否显示加载状态
loadingText?: string; // 加载状态下的文字
ariaLabel?: string; // 无障碍标签
title?: string; // 提示文字
}
const Button: React.FC<ButtonProps> = ({
text,
iconRight,
iconLeft,
onClick,
disabled = false,
type = 'button',
size = 'md',
variant = 'primary',
fullWidth = false,
className = '',
url,
loading = false,
loadingText = 'Loading...',
ariaLabel,
title,
}) => {
const buttonStyle = `
transition duration-200 ease-in-out
rounded-full px-4
flex items-center justify-center gap-1
font-medium
${
size === 'sm'
? 'px-3 min-h-[2rem] text-xs'
: size === 'md'
? 'px-4 min-h-[2.5rem] text-sm'
: size === 'lg'
? 'px-5 min-h-[2.7rem] text-base'
: size === 'xl'
? 'px-7 min-h-[3.15rem] text-lg'
: size === '2xl'
? 'px-10 min-h-[4rem] text-xl'
: 'px-12 min-h-[4.5rem] text-2xl'
}
${
variant === 'primary'
? '!bg-black !text-white dark:!bg-white dark:!text-black hover:bg-gray-800 dark:hover:bg-gray-100'
: variant === 'secondary'
? 'bg-gray-200 text-black dark:bg-gray-700 dark:text-white hover:bg-gray-300 dark:hover:bg-gray-600'
: 'bg-transparent text-black dark:text-white border border-black dark:border-white hover:bg-black hover:text-white dark:hover:bg-white dark:hover:text-black'
}
${fullWidth ? 'w-full' : ''}
${disabled || loading ? 'opacity-50 cursor-not-allowed' : ''}
${className}
`;
const iconStyle = `w-2.5 h-2.5 stroke-current stroke-[1.25] stroke-linecap-round stroke-linejoin-round`;
const content = (
<>
{iconLeft && iconLeft}
{loading ? loadingText : text}
{iconRight && (
<svg
width="0.625rem"
viewBox="0 0 10 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={iconStyle}
>
<path d="M1 9L9 1M9 1H2.5M9 1V7.22222" />
</svg>
)}
<span className="sr-only">(opens in a new window)</span>
</>
);
if (url) {
return (
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className={buttonStyle}
onClick={onClick}
aria-label={ariaLabel}
title={title}
>
{content}
</a>
);
}
return (
<button
className={buttonStyle}
onClick={onClick}
disabled={disabled || loading}
type={type}
aria-label={ariaLabel}
title={title}
>
{content}
</button>
);
};
export default Button;按钮大小
支持参数
| ⭐参数名 | 🤔类型 | 🐳默认值 | 🌎说明 |
|---|---|---|---|
| text | string | - | 按钮显示的文本 |
| iconRight | React.ReactNode | undefined | 右侧图标,若设置true则显示 |
| iconLeft | React.ReactNode | undefined | 左侧图标,若设置true则显示 |
| onClick | function | undefined | 点击事件处理函数 |
| disabled | boolean | false | 设置按钮是否禁用 |
| type | 'button' | 'submit' | 'reset' | 'button' | 指定按钮类型 |
| size | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'xl' | 按钮大小设置 |
| variant | 'primary' | 'secondary' | 'outline' | 'primary' | 按钮的样式变体 |
| fullWidth | boolean | false | 是否占据全部宽度 |
| className | string | - | 自定义类名,用于覆盖或添加额外的样式 |
| url | string | undefined | 如果设置,按钮将作为链接使用,并打开新窗口 |
| loading | boolean | false | 是否显示加载状态,若为true则显示loadingText |
| loadingText | string | 'Loading...' | 加载状态下显示的文本 |
| ariaLabel | string | undefined | 无障碍标签,用于提高可访问性 |
| title | string | undefined | 提示文本,通常用作鼠标悬停提示 |