54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
import React, { ButtonHTMLAttributes, AnchorHTMLAttributes, ReactNode } from 'react';
|
|
|
|
type ButtonAsButton = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
as?: 'button';
|
|
href?: never;
|
|
};
|
|
|
|
type ButtonAsLink = AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
as: 'a';
|
|
href: string;
|
|
};
|
|
|
|
type ButtonProps = (ButtonAsButton | ButtonAsLink) & {
|
|
variant?: 'primary' | 'secondary' | 'danger';
|
|
children: ReactNode;
|
|
};
|
|
|
|
export default function Button({
|
|
variant = 'primary',
|
|
children,
|
|
className = '',
|
|
as = 'button',
|
|
...props
|
|
}: ButtonProps) {
|
|
const baseStyles = 'inline-flex items-center min-h-[44px] rounded-full px-6 py-3 text-sm font-semibold transition-all duration-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 hover:scale-[1.03] active:scale-95';
|
|
|
|
const variantStyles = {
|
|
primary: 'bg-primary-blue text-white shadow-[0_0_15px_rgba(25,140,255,0.4)] hover:shadow-[0_0_25px_rgba(25,140,255,0.6)] active:ring-2 active:ring-primary-blue focus-visible:outline-primary-blue',
|
|
secondary: 'bg-iron-gray text-white border border-charcoal-outline shadow-[0_0_10px_rgba(25,140,255,0.2)] hover:shadow-[0_0_20px_rgba(25,140,255,0.4)] hover:border-primary-blue focus-visible:outline-primary-blue',
|
|
danger: 'bg-red-600 text-white shadow-[0_0_15px_rgba(248,113,113,0.4)] hover:shadow-[0_0_25px_rgba(248,113,113,0.6)] active:ring-2 active:ring-red-600 focus-visible:outline-red-600'
|
|
} as const;
|
|
|
|
const classes = `${baseStyles} ${variantStyles[variant]} ${className}`;
|
|
|
|
if (as === 'a') {
|
|
return (
|
|
<a
|
|
className={classes}
|
|
{...(props as AnchorHTMLAttributes<HTMLAnchorElement>)}
|
|
>
|
|
{children}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<button
|
|
className={classes}
|
|
{...(props as ButtonHTMLAttributes<HTMLButtonElement>)}
|
|
>
|
|
{children}
|
|
</button>
|
|
);
|
|
} |