68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
import { cn } from '@/shared/lib/cn';
|
|
|
|
type ButtonVariant = 'primary' | 'secondary' | 'ghost';
|
|
type ButtonSize = 'sm' | 'md';
|
|
|
|
type BaseProps = {
|
|
children: ReactNode;
|
|
className?: string;
|
|
size?: ButtonSize;
|
|
variant?: ButtonVariant;
|
|
};
|
|
|
|
type LinkProps = BaseProps &
|
|
AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
href: string;
|
|
};
|
|
|
|
type NativeButtonProps = BaseProps &
|
|
ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
href?: undefined;
|
|
};
|
|
|
|
type ButtonProps = LinkProps | NativeButtonProps;
|
|
|
|
const variantClasses: Record<ButtonVariant, string> = {
|
|
primary:
|
|
'border-[var(--accent)] bg-[var(--accent)] text-[var(--text-on-accent)] hover:bg-[var(--accent-strong)] hover:border-[var(--accent-strong)]',
|
|
secondary:
|
|
'border-[var(--border-strong)] bg-[var(--surface-1)] text-[var(--text-primary)] hover:bg-[var(--surface-2)]',
|
|
ghost:
|
|
'border-transparent bg-transparent text-[var(--text-muted)] hover:bg-[var(--surface-2)] hover:text-[var(--text-primary)]',
|
|
};
|
|
|
|
const sizeClasses: Record<ButtonSize, string> = {
|
|
sm: 'min-h-9 px-3 text-xs',
|
|
md: 'min-h-11 px-4 text-sm',
|
|
};
|
|
|
|
export function Button(props: ButtonProps) {
|
|
const { children, className, size = 'md', variant = 'primary' } = props;
|
|
const classes = cn(
|
|
'inline-flex items-center justify-center gap-2 rounded-[var(--radius-md)] border font-semibold transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--focus)]',
|
|
sizeClasses[size],
|
|
variantClasses[variant],
|
|
className,
|
|
);
|
|
|
|
if (props.href) {
|
|
const { href, ...linkProps } = props;
|
|
|
|
return (
|
|
<a {...linkProps} className={classes} href={href}>
|
|
{children}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
const buttonProps = props as NativeButtonProps;
|
|
const { type = 'button', ...restButtonProps } = buttonProps;
|
|
|
|
return (
|
|
<button {...restButtonProps} className={classes} type={type}>
|
|
{children}
|
|
</button>
|
|
);
|
|
}
|