bigbuffet-rw/app/soapbox/components/ui/button/button.tsx
marcin mikołajczak 785c6b57e3 RTL support, use Stack and HStack in more places
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-11-25 18:04:11 +01:00

98 lines
2.3 KiB
TypeScript

import classNames from 'clsx';
import React from 'react';
import { Link } from 'react-router-dom';
import Icon from '../icon/icon';
import { useButtonStyles } from './useButtonStyles';
import type { ButtonSizes, ButtonThemes } from './useButtonStyles';
interface IButton {
/** Whether this button expands the width of its container. */
block?: boolean,
/** Elements inside the <button> */
children?: React.ReactNode,
/** Extra class names for the button. */
className?: string,
/** Prevent the button from being clicked. */
disabled?: boolean,
/** URL to an SVG icon to render inside the button. */
icon?: string,
/** Action when the button is clicked. */
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void,
/** A predefined button size. */
size?: ButtonSizes,
/** Text inside the button. Takes precedence over `children`. */
text?: React.ReactNode,
/** Makes the button into a navlink, if provided. */
to?: string,
/** Styles the button visually with a predefined theme. */
theme?: ButtonThemes,
/** Whether this button should submit a form by default. */
type?: 'button' | 'submit',
}
/** Customizable button element with various themes. */
const Button = React.forwardRef<HTMLButtonElement, IButton>((props, ref): JSX.Element => {
const {
block = false,
children,
disabled = false,
icon,
onClick,
size = 'md',
text,
theme = 'secondary',
to,
type = 'button',
className,
} = props;
const themeClass = useButtonStyles({
theme,
block,
disabled,
size,
});
const renderIcon = () => {
if (!icon) {
return null;
}
return <Icon src={icon} className='mr-2 w-4 h-4' />;
};
const handleClick = React.useCallback((event) => {
if (onClick && !disabled) {
onClick(event);
}
}, [onClick, disabled]);
const renderButton = () => (
<button
className={classNames(themeClass, className)}
disabled={disabled}
onClick={handleClick}
ref={ref}
type={type}
data-testid='button'
>
{renderIcon()}
{text || children}
</button>
);
if (to) {
return (
<Link to={to} tabIndex={-1} className='inline-flex'>
{renderButton()}
</Link>
);
}
return renderButton();
});
export default Button;