v2/Action/Button/index.tsx
import React, { useCallback } from 'react';
import { _cs } from '@togglecorp/fujs';
import Spinner from '../../View/Spinner';
import Icon from '../../../components/General/Icon';
/*
eslint css-modules/no-unused-class: [
1,
{
markAsUsed: [
'button-default', 'button-accent', 'button-primary', 'button-danger',
'button-warning', 'button-success'
],
camelCase: true
}
]
*/
import styles from './styles.scss';
/*
# Breaking Change
- Removed PrimaryButton, DangerButton, SuccessButton, WarningButton, AccentButton components
- Removed changeDelay prop
- onClickParams doesn't resolve functions by default
# Todo
- Remove smallHorizontalPadding and smallVerticalPadding
- Introduce small, medium and large buttons
*/
export type ButtonType = 'button-default' | 'button-accent' | 'button-primary' | 'button-danger' | 'button-success' | 'button-warning';
type RawButtonType = 'button' | 'submit' | 'reset';
export interface Props<T> extends Omit<React.HTMLProps<HTMLButtonElement>, 'onClick' | 'ref'> {
buttonType?: ButtonType;
children?: React.ReactNode;
className?: string;
disabled?: boolean;
iconName?: string;
onClick?: (value: { event: React.MouseEvent; params?: T }) => void;
onClickParams?: T;
pending?: boolean;
smallHorizontalPadding?: boolean;
smallVerticalPadding?: boolean;
transparent: boolean;
type?: RawButtonType;
}
function Button<T>(props: Props<T>) {
const {
buttonType,
children,
className: classNameFromProps,
disabled,
iconName,
pending,
smallHorizontalPadding,
smallVerticalPadding,
transparent,
type,
onClick,
onClickParams,
...otherProps
} = props;
const handleClick = useCallback(
(e: React.MouseEvent) => {
if (onClick) {
onClick({
event: e,
params: onClickParams,
});
}
},
[
onClick,
onClickParams,
],
);
const buttonClassName = _cs(
classNameFromProps,
'button',
styles.button,
buttonType,
buttonType && styles[buttonType],
iconName && !!children && 'with-icon-and-children',
iconName && !!children && styles.withIconAndChildren,
smallHorizontalPadding && 'small-horizontal-padding',
smallHorizontalPadding && styles.smallHorizontalPadding,
smallVerticalPadding && 'small-vertical-padding',
smallVerticalPadding && styles.smallVerticalPadding,
transparent && 'transparent',
transparent && styles.transparent,
);
const iconClassName = _cs(
'icon',
styles.icon,
);
/* eslint-disable react/button-has-type */
return (
<button
className={buttonClassName}
disabled={disabled || pending}
onClick={handleClick}
type={type}
{...otherProps}
>
{pending ? (
<Spinner
className={_cs(styles.spinner, 'tc-v2-button-spinner')}
size="small"
/>
) : (
<Icon
name={iconName}
className={iconClassName}
/>
)}
{ children }
</button>
);
/* eslint-enable react/button-has-type */
}
Button.defaultProps = {
buttonType: 'button-default' as ButtonType,
disabled: false,
pending: false,
smallHorizontalPadding: false,
smallVerticalPadding: false,
transparent: false,
type: 'button',
};
export default Button;