micro/packages/web/src/components/button.tsx

65 lines
1.9 KiB
TypeScript

/* eslint-disable react/button-has-type */
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { forwardRef } from 'react';
import { Link } from './link';
import { Spinner } from './spinner';
export interface ButtonProps extends Omit<HTMLAttributes<HTMLButtonElement | HTMLAnchorElement>, 'prefix' | 'style'> {
href?: string;
disabled?: boolean;
style?: ButtonStyle;
loading?: boolean;
type?: 'submit' | 'reset' | 'button';
}
export enum ButtonStyle {
Primary = 'bg-purple-500 hover:bg-purple-400',
Secondary = 'bg-dark-600 hover:bg-dark-900',
Disabled = 'bg-dark-300 hover:bg-dark-400',
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
{ href, disabled, className, type, children, loading, style = ButtonStyle.Primary, onClick, onKeyDown, ...rest },
ref
) => {
if (disabled) style = ButtonStyle.Disabled;
const onClickWrap = disabled ? undefined : onClick;
const onKeyDownWrap = disabled ? undefined : onKeyDown;
const classes = classNames(
'flex items-center justify-center gap-2 w-full px-3 py-2 text-sm font-medium transition rounded truncate max-h-[2.65em]',
disabled && 'cursor-not-allowed',
className,
style
);
if (href) {
if (ref) {
throw new Error('Button cannot have ref and href');
}
return (
<Link href={href} className={classes} onClick={onClickWrap} onKeyDown={onKeyDownWrap} {...rest}>
{children} {loading && <Spinner size="small" />}
</Link>
);
}
return (
<button
type={type}
className={classes}
disabled={disabled}
onClick={onClickWrap}
onKeyDown={onKeyDownWrap}
style={{ height: '2.5rem' }}
{...rest}
ref={ref}
>
{children} {loading && <Spinner size="small" />}
</button>
);
}
);