Files
flint/apps/web/components/ui/Button.tsx
T

76 lines
2.0 KiB
TypeScript

import type { ButtonHTMLAttributes } from "react";
import { cn } from "./cn";
type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
type ButtonSize = "sm" | "md" | "lg";
const baseStyles =
"inline-flex items-center justify-center gap-2 rounded-xl border font-semibold transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg)] disabled:cursor-not-allowed disabled:opacity-50";
const variantStyles: Record<ButtonVariant, string> = {
primary:
"border-transparent bg-[var(--primary)] text-white hover:bg-[var(--primary-hover)]",
secondary:
"border-[var(--border-subtle)] bg-[var(--surface-subtle)] text-[var(--foreground)] hover:bg-[var(--surface-strong)]",
ghost:
"border-transparent bg-transparent text-[var(--foreground-muted)] hover:bg-[var(--surface-subtle)] hover:text-[var(--foreground)]",
danger:
"border-transparent bg-[var(--danger)] text-white hover:brightness-95",
};
const sizeStyles: Record<ButtonSize, string> = {
sm: "h-9 px-3 text-xs",
md: "h-10 px-4 text-sm",
lg: "h-11 px-5 text-sm",
};
type ButtonClassNameOptions = {
variant?: ButtonVariant;
size?: ButtonSize;
fullWidth?: boolean;
className?: string;
};
export function buttonClassName({
variant = "primary",
size = "md",
fullWidth = false,
className,
}: ButtonClassNameOptions = {}) {
return cn(
baseStyles,
variantStyles[variant],
sizeStyles[size],
fullWidth ? "w-full" : "",
className,
);
}
export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: ButtonVariant;
size?: ButtonSize;
fullWidth?: boolean;
};
export function Button({
className,
variant,
size,
fullWidth,
type = "button",
...props
}: ButtonProps) {
return (
<button
className={buttonClassName({
variant: variant ?? "primary",
size: size ?? "md",
fullWidth: fullWidth ?? false,
className: className ?? "",
})}
type={type}
{...props}
/>
);
}