lead-to-policy/src/components/core/Button.tsx
Bhanu Prakash Sai Potteri 714f8ab8ff initial commit
2026-06-22 10:36:16 +05:30

66 lines
1.9 KiB
TypeScript

import type { ButtonHTMLAttributes, ReactNode } from 'react';
import { cn } from '../../lib/cn';
export type ButtonVariant = 'primary' | 'navy' | 'secondary' | 'ghost' | 'danger';
export type ButtonSize = 'sm' | 'md' | 'lg';
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
/** Visual style. @default "primary" */
variant?: ButtonVariant;
/** @default "md" */
size?: ButtonSize;
iconLeft?: ReactNode;
iconRight?: ReactNode;
/** Stretch to container width. @default false */
full?: boolean;
}
const SIZES: Record<ButtonSize, string> = {
sm: 'h-[34px] px-3.5 text-[13px] rounded-sm',
md: 'h-[42px] px-[18px] text-base rounded-md',
lg: 'h-[50px] px-6 text-md rounded-md',
};
const VARIANTS: Record<ButtonVariant, string> = {
primary: 'bg-sunrise text-white border border-transparent shadow-sunrise',
navy: 'bg-navy-900 text-on-navy border border-transparent shadow-sm',
secondary: 'bg-card text-strong border border-border-default shadow-xs',
ghost: 'bg-transparent text-body border border-transparent',
danger: 'bg-ruby-600 text-white border border-transparent shadow-sm',
};
/**
* Aria primary action button. Sunrise gradient for primary,
* solid navy for secondary, quiet ghost for tertiary.
*/
export function Button({
children,
variant = 'primary',
size = 'md',
iconLeft,
iconRight,
full = false,
className,
...rest
}: ButtonProps) {
return (
<button
className={cn(
'inline-flex items-center justify-center gap-2 font-sans font-semibold leading-none',
'cursor-pointer transition-[transform,filter,box-shadow] duration-150',
'hover:brightness-[0.98] active:scale-[0.97]',
'disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100',
SIZES[size],
VARIANTS[variant],
full ? 'w-full' : 'w-auto',
className,
)}
{...rest}
>
{iconLeft}
{children}
{iconRight}
</button>
);
}