2023-02-06 10:01:03 -08:00
|
|
|
import clsx from 'clsx';
|
2022-11-25 09:04:11 -08:00
|
|
|
import React from 'react';
|
2022-03-21 11:09:01 -07:00
|
|
|
import { Link } from 'react-router-dom';
|
|
|
|
|
2022-04-05 07:42:19 -07:00
|
|
|
import Icon from '../icon/icon';
|
2022-03-21 11:09:01 -07:00
|
|
|
|
|
|
|
import { useButtonStyles } from './useButtonStyles';
|
|
|
|
|
|
|
|
import type { ButtonSizes, ButtonThemes } from './useButtonStyles';
|
|
|
|
|
2022-11-19 14:08:58 -08:00
|
|
|
interface IButton {
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Whether this button expands the width of its container. */
|
2023-02-15 13:26:27 -08:00
|
|
|
block?: boolean
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Elements inside the <button> */
|
2023-02-15 13:26:27 -08:00
|
|
|
children?: React.ReactNode
|
2022-08-25 19:21:03 -07:00
|
|
|
/** Extra class names for the button. */
|
2023-02-15 13:26:27 -08:00
|
|
|
className?: string
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Prevent the button from being clicked. */
|
2023-02-15 13:26:27 -08:00
|
|
|
disabled?: boolean
|
2022-04-30 21:39:58 -07:00
|
|
|
/** URL to an SVG icon to render inside the button. */
|
2023-02-15 13:26:27 -08:00
|
|
|
icon?: string
|
2022-11-19 14:08:58 -08:00
|
|
|
/** Action when the button is clicked. */
|
2023-02-15 13:26:27 -08:00
|
|
|
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void
|
2022-04-30 21:39:58 -07:00
|
|
|
/** A predefined button size. */
|
2023-02-15 13:26:27 -08:00
|
|
|
size?: ButtonSizes
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Text inside the button. Takes precedence over `children`. */
|
2023-02-15 13:26:27 -08:00
|
|
|
text?: React.ReactNode
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Makes the button into a navlink, if provided. */
|
2023-02-15 13:26:27 -08:00
|
|
|
to?: string
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Styles the button visually with a predefined theme. */
|
2023-02-15 13:26:27 -08:00
|
|
|
theme?: ButtonThemes
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Whether this button should submit a form by default. */
|
2023-02-15 13:26:27 -08:00
|
|
|
type?: 'button' | 'submit'
|
2022-03-21 11:09:01 -07:00
|
|
|
}
|
|
|
|
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Customizable button element with various themes. */
|
2022-03-21 11:09:01 -07:00
|
|
|
const Button = React.forwardRef<HTMLButtonElement, IButton>((props, ref): JSX.Element => {
|
|
|
|
const {
|
|
|
|
block = false,
|
|
|
|
children,
|
|
|
|
disabled = false,
|
|
|
|
icon,
|
|
|
|
onClick,
|
|
|
|
size = 'md',
|
|
|
|
text,
|
2022-07-22 10:30:16 -07:00
|
|
|
theme = 'secondary',
|
2022-03-21 11:09:01 -07:00
|
|
|
to,
|
|
|
|
type = 'button',
|
2022-08-25 19:21:03 -07:00
|
|
|
className,
|
2022-03-21 11:09:01 -07:00
|
|
|
} = props;
|
|
|
|
|
2022-12-23 13:22:41 -08:00
|
|
|
const body = text || children;
|
|
|
|
|
2022-03-21 11:09:01 -07:00
|
|
|
const themeClass = useButtonStyles({
|
|
|
|
theme,
|
|
|
|
block,
|
|
|
|
disabled,
|
|
|
|
size,
|
|
|
|
});
|
|
|
|
|
|
|
|
const renderIcon = () => {
|
|
|
|
if (!icon) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-02-01 14:13:42 -08:00
|
|
|
return <Icon src={icon} className='h-4 w-4' />;
|
2022-03-21 11:09:01 -07:00
|
|
|
};
|
|
|
|
|
2023-01-10 15:03:15 -08:00
|
|
|
const handleClick: React.MouseEventHandler<HTMLButtonElement> = React.useCallback((event) => {
|
2022-03-21 11:09:01 -07:00
|
|
|
if (onClick && !disabled) {
|
|
|
|
onClick(event);
|
|
|
|
}
|
|
|
|
}, [onClick, disabled]);
|
|
|
|
|
|
|
|
const renderButton = () => (
|
|
|
|
<button
|
2023-02-06 10:01:03 -08:00
|
|
|
className={clsx('space-x-2 rtl:space-x-reverse', themeClass, className)}
|
2022-03-21 11:09:01 -07:00
|
|
|
disabled={disabled}
|
|
|
|
onClick={handleClick}
|
|
|
|
ref={ref}
|
|
|
|
type={type}
|
2022-04-04 08:53:47 -07:00
|
|
|
data-testid='button'
|
2022-03-21 11:09:01 -07:00
|
|
|
>
|
|
|
|
{renderIcon()}
|
2022-12-23 13:22:41 -08:00
|
|
|
|
|
|
|
{body && (
|
|
|
|
<span>{body}</span>
|
|
|
|
)}
|
2022-03-21 11:09:01 -07:00
|
|
|
</button>
|
|
|
|
);
|
|
|
|
|
|
|
|
if (to) {
|
|
|
|
return (
|
|
|
|
<Link to={to} tabIndex={-1} className='inline-flex'>
|
|
|
|
{renderButton()}
|
|
|
|
</Link>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return renderButton();
|
|
|
|
});
|
|
|
|
|
2023-02-02 21:00:51 -08:00
|
|
|
export {
|
|
|
|
Button as default,
|
|
|
|
Button,
|
|
|
|
};
|