components/Action/Button/index.js
import PropTypes from 'prop-types';
import React from 'react';
import { resolve, _cs } from '@togglecorp/fujs';
import { FaramActionElement } from '@togglecorp/faram';
import Spinner from '../../../v2/View/Spinner';
import Icon from '../../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';
const propTypes = {
/**
* buttonType is used to categorize a button:
* default, primary, danger, warning, success
* Generally user doesn't explicitly pass buttonType
*/
buttonType: PropTypes.string,
/**
* required for style override
*/
className: PropTypes.string,
/**
* children can contain a simple string or a react element
*/
children: PropTypes.oneOfType([
PropTypes.node,
PropTypes.arrayOf(PropTypes.node),
]),
/**
* if disabled is true, the action is blocked
*/
disabled: PropTypes.bool,
/**
* if pending is true, the action is blocked and it is indicated
*/
pending: PropTypes.bool,
/**
* iconName is the name of the icon in Ionicons 2
*/
iconName: PropTypes.string,
/**
* action to invoke when the button is clicked
*/
onClick: PropTypes.func,
onClickParams: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
/**
* show small horizontal padding
*/
smallHorizontalPadding: PropTypes.bool,
/**
* show small vertical padding
*/
smallVerticalPadding: PropTypes.bool,
/**
* show small vertical padding
*/
transparent: PropTypes.bool,
type: PropTypes.string,
changeDelay: PropTypes.number,
};
const defaultProps = {
buttonType: 'button-default',
type: 'button',
className: '',
disabled: false,
pending: false,
iconName: undefined,
onClick: undefined,
children: undefined,
smallHorizontalPadding: false,
smallVerticalPadding: false,
transparent: false,
changeDelay: 0,
onClickParams: undefined,
};
/**
* Basic button component
*/
class Button extends React.PureComponent {
static propTypes = propTypes;
static defaultProps = defaultProps;
componentWillUnmount() {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
}
handleClick = (e) => {
clearTimeout(this.changeTimeout);
const {
onClick,
onClickParams,
changeDelay,
} = this.props;
if (!onClick) {
return;
}
this.changeTimeout = setTimeout(
() => {
onClick({
event: e,
params: resolve(onClickParams),
});
},
changeDelay,
);
}
render() {
const {
iconName,
children,
disabled,
pending,
type,
buttonType,
className: classNameFromProps,
smallHorizontalPadding,
smallVerticalPadding,
transparent,
onClick, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars
onClickParams, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars
changeDelay, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars
...otherProps
} = this.props;
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,
// pending && styles.pendingIcon,
);
/* eslint-disable react/button-has-type */
return (
<button
className={buttonClassName}
disabled={disabled || pending}
onClick={this.handleClick}
type={type}
{...otherProps}
>
{pending ? (
<Spinner
className={styles.spinner}
size="small"
/>
) : (
<Icon
name={iconName}
className={iconClassName}
/>
)}
{ children }
</button>
);
/* eslint-enable react/button-has-type */
}
}
export default FaramActionElement(Button);