Files
Geradores/geradoresfe/src/components/ui/Button.tsx
Marco Santos dec8bd3909 Novo layout
2025-07-24 00:07:59 +01:00

67 lines
2.0 KiB
TypeScript

// components/ui/Button.tsx
import type { ReactNode } from "react";
import { Loader2 } from "lucide-react";
import { twMerge } from "tailwind-merge";
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
icon?: ReactNode;
variant?: "primary" | "secondary" | "ghost" | "danger";
loading?: boolean;
loadingText?: string;
fullWidth?: boolean;
rounded?: boolean | "md" | "lg" | "xl" | "2xl" | "full";
};
export function Button({
icon,
variant = "primary",
children,
className = "",
type = "button",
loading = false,
loadingText,
disabled,
fullWidth = false,
rounded = "2xl",
...rest
}: ButtonProps) {
const base = twMerge(
"inline-flex items-center justify-center gap-2 px-5 py-2.5 font-medium text-sm transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed shadow-sm hover:shadow-md",
fullWidth && "w-full",
typeof rounded === "string" ? `rounded-${rounded}` : rounded === true ? "rounded-md" : "rounded-2xl"
);
const variants = {
primary:
"bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500 dark:bg-blue-600 dark:hover:bg-blue-500",
secondary:
"bg-zinc-100 text-zinc-900 hover:bg-zinc-200 focus:ring-zinc-400 dark:bg-zinc-700 dark:text-white dark:hover:bg-zinc-600",
ghost:
"bg-transparent text-zinc-700 hover:bg-zinc-100 focus:ring-zinc-300 dark:text-zinc-200 dark:hover:bg-zinc-800",
danger:
"bg-red-600 text-white hover:bg-red-700 focus:ring-red-500 dark:bg-red-600 dark:hover:bg-red-500",
};
return (
<button
type={type}
className={twMerge(base, variants[variant], className)}
disabled={disabled || loading}
aria-busy={loading}
{...rest}
>
{loading ? (
<>
<Loader2 className="animate-spin w-4 h-4" />
{loadingText && <span>{loadingText}</span>}
</>
) : (
<>
{icon && <span className="flex items-center">{icon}</span>}
{children}
</>
)}
</button>
);
}