72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
/**
|
|
* Button Component
|
|
*
|
|
* 🔒 STYLE LOCKED - See DESIGN_SYSTEM.md for available variants and sizes.
|
|
* Do not modify variants or add new ones without updating DESIGN_SYSTEM.md first.
|
|
*/
|
|
import { ReactNode, forwardRef } from "react";
|
|
|
|
interface ButtonProps {
|
|
children: ReactNode; // Button text or content
|
|
size?: "sm" | "md"; // Button size
|
|
variant?: "primary" | "outline" | "secondary" | "success"; // Button variant
|
|
startIcon?: ReactNode; // Icon before the text
|
|
endIcon?: ReactNode; // Icon after the text
|
|
onClick?: () => void; // Click handler
|
|
disabled?: boolean; // Disabled state
|
|
className?: string; // Additional classes
|
|
type?: "button" | "submit" | "reset"; // Button type
|
|
}
|
|
|
|
const Button = forwardRef<HTMLButtonElement, ButtonProps>(({
|
|
children,
|
|
size = "md",
|
|
variant = "primary",
|
|
startIcon,
|
|
endIcon,
|
|
onClick,
|
|
className = "",
|
|
disabled = false,
|
|
type = "button",
|
|
}, ref) => {
|
|
// Size Classes
|
|
const sizeClasses = {
|
|
sm: "px-3 py-1.5 text-xs h-8",
|
|
md: "px-3 py-2 text-sm h-9",
|
|
};
|
|
|
|
// Variant Classes
|
|
const variantClasses = {
|
|
primary:
|
|
"bg-brand-500 text-white shadow-theme-xs hover:bg-brand-600 disabled:bg-brand-300",
|
|
outline:
|
|
"bg-white text-gray-700 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-400 dark:ring-gray-700 dark:hover:bg-white/[0.03] dark:hover:text-gray-300",
|
|
secondary:
|
|
"bg-gray-500 text-white border border-gray-500 hover:bg-gray-600 hover:border-gray-600 dark:bg-gray-500 dark:border-gray-500 dark:hover:bg-gray-600 dark:hover:border-gray-600",
|
|
success:
|
|
"bg-success-500 text-white shadow-theme-xs hover:bg-success-600 disabled:bg-success-300",
|
|
};
|
|
|
|
return (
|
|
<button
|
|
ref={ref}
|
|
type={type}
|
|
className={`inline-flex items-center justify-center gap-2 rounded-lg transition ${className} ${
|
|
sizeClasses[size]
|
|
} ${variantClasses[variant]} ${
|
|
disabled ? "cursor-not-allowed opacity-50" : ""
|
|
}`}
|
|
onClick={onClick}
|
|
disabled={disabled}
|
|
>
|
|
{startIcon && <span className="flex items-center">{startIcon}</span>}
|
|
{children}
|
|
{endIcon && <span className="flex items-center">{endIcon}</span>}
|
|
</button>
|
|
);
|
|
});
|
|
|
|
Button.displayName = "Button";
|
|
|
|
export default Button;
|