57 lines
1.3 KiB
TypeScript
57 lines
1.3 KiB
TypeScript
import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react';
|
|
import './Button.css';
|
|
|
|
type Variant = 'primary' | 'secondary' | 'ghost' | 'white';
|
|
type Size = 'sm' | 'md' | 'lg';
|
|
|
|
interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
variant?: Variant;
|
|
size?: Size;
|
|
loading?: boolean;
|
|
iconLeft?: ReactNode;
|
|
iconRight?: ReactNode;
|
|
fullWidth?: boolean;
|
|
}
|
|
|
|
export const Button = forwardRef<HTMLButtonElement, Props>(function Button(
|
|
{
|
|
variant = 'primary',
|
|
size = 'md',
|
|
loading = false,
|
|
iconLeft,
|
|
iconRight,
|
|
fullWidth = false,
|
|
disabled,
|
|
className,
|
|
children,
|
|
...rest
|
|
},
|
|
ref,
|
|
) {
|
|
const classes = [
|
|
'ui-btn',
|
|
`ui-btn--${variant}`,
|
|
`ui-btn--${size}`,
|
|
fullWidth ? 'ui-btn--full' : '',
|
|
loading ? 'ui-btn--loading' : '',
|
|
className ?? '',
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ');
|
|
|
|
return (
|
|
<button
|
|
ref={ref}
|
|
className={classes}
|
|
disabled={disabled || loading}
|
|
aria-busy={loading || undefined}
|
|
{...rest}
|
|
>
|
|
{loading ? <span className="ui-btn__spinner" aria-hidden="true" /> : null}
|
|
{!loading && iconLeft ? <span className="ui-btn__icon">{iconLeft}</span> : null}
|
|
<span className="ui-btn__label">{children}</span>
|
|
{!loading && iconRight ? <span className="ui-btn__icon">{iconRight}</span> : null}
|
|
</button>
|
|
);
|
|
});
|