@wfp/ui
Version:
WFP UI Kit
219 lines (192 loc) • 5.13 kB
JavaScript
import PropTypes from 'prop-types';
import React, { useEffect, useState } from 'react';
import Icon from '../Icon';
import classNames from 'classnames';
import settings from '../../globals/js/settings';
const { prefix } = settings;
/**
* Buttons express what action will occur when the user clicks or touches it. Buttons are used to initialize an action, either in the background or foreground of an experience. */
const Button = ({
children,
className,
disabled,
small,
large,
kind,
href,
iconReverse,
tabIndex,
type,
useFlexbox,
icon,
iconDescription,
onClick,
...other
}) => {
const [count, setCount] = useState(0);
useEffect(() => {
let timer = setTimeout(() => endAnimation(), 500);
return () => {
clearTimeout(timer);
};
}, [count]);
const buttonClasses = classNames(className, {
[`${prefix}--btn`]: true,
[`${prefix}--btn--sm`]: small,
[`${prefix}--btn--lg`]: large,
[`${prefix}--btn--icon-reverse`]: iconReverse,
[`${prefix}--btn--flexbox`]: useFlexbox,
[`${prefix}--btn--icon-only`]: icon && children === undefined,
[`${prefix}--btn--primary`]: kind === 'primary',
[`${prefix}--btn--danger`]: kind === 'danger',
[`${prefix}--btn--accent`]: kind === 'accent',
[`${prefix}--btn--secondary`]: kind === 'secondary',
[`${prefix}--btn--navigation`]: kind === 'navigation',
[`${prefix}--btn--ghost`]: kind === 'ghost',
[`${prefix}--btn--inverse--primary`]: kind === 'inverse--primary',
[`${prefix}--btn--inverse`]: kind === 'inverse',
[`${prefix}--btn--danger--primary`]: kind === 'danger--primary',
[`${prefix}--btn--danger--secondary`]: kind === 'danger--secondary',
[`${prefix}--btn--tertiary`]: kind === 'tertiary',
[`${prefix}--btn--animating`]: count,
});
const commonProps = {
tabIndex,
className: buttonClasses,
};
const buttonImage = icon ? (
<Icon
icon={Object(icon) === icon ? icon : undefined}
name={Object(icon) !== icon ? icon : undefined}
description={iconDescription}
className={`${prefix}--btn__icon`}
/>
) : null;
const endAnimation = () => {
setCount(false);
};
const onClickAnimation = (e) => {
if (onClick) {
onClick(e);
}
setCount(true);
};
const button = (
<button
{...other}
{...commonProps}
disabled={disabled}
type={type}
onClick={onClickAnimation}
ref={other.inputRef}>
{iconReverse && buttonImage}
{children}
{!iconReverse && buttonImage}
</button>
);
const anchor = (
<a
{...other}
{...commonProps}
href={href}
role="button"
onClick={onClickAnimation}
ref={other.inputRef}>
{children}
{buttonImage}
</a>
);
return href ? anchor : button;
};
Button.propTypes = {
/**
* Specify the content of your Button
*/
children: PropTypes.node,
/**
* Specify an optional className to be added to your Button
*/
className: PropTypes.string,
/**
* Specify whether the Button should be disabled, or not
*/
disabled: PropTypes.bool,
/**
* FOR DESIGNERS
* Specify whether the Button should be a small variant
*/
small: PropTypes.bool,
/**
* FOR DESIGNERS
* Specify whether the Button should be a large variant
*/
large: PropTypes.bool,
/**
* FOR DESIGNERS
* Specify the kind of Button you want to create
*/
kind: PropTypes.oneOf([
'primary',
'secondary',
'accent',
'danger',
'ghost',
'inverse--primary',
'inverse',
'danger--primary',
'tertiary',
'navigation',
]),
//ButtonTypes.buttonKind.isRequired,
/**
* Optionally specify an href for your Button to become an <a> element
*/
href: PropTypes.string,
/**
* Optional prop to specify the tabIndex of the Button
*/
tabIndex: PropTypes.number,
/**
* Optional prop to specify the type of the Button
*/
type: PropTypes.oneOf(['button', 'reset', 'submit']),
/**
* Optional prop to specify the role of the Button
*/
role: PropTypes.string,
/**
* Specify an `icon` to include in the Button through an object representing the SVG data of the icon, similar to the `Icon` component
*/
icon: PropTypes.shape({
width: PropTypes.string,
height: PropTypes.string,
viewBox: PropTypes.string.isRequired,
svgData: PropTypes.object.isRequired,
}),
/**
* If specifying the `icon` prop, provide a description for that icon that can
* be read by screen readers
*/
iconDescription: (props) => {
if (props.icon && !props.iconDescription) {
return new Error(
'icon property specified without also providing an iconDescription property.'
);
}
return undefined;
},
/**
* Optionally specify an href for your Button to become an <a> element
*/
iconReverse: PropTypes.bool,
};
Button.defaultProps = {
iconReverse: false,
iconDescription: 'Provide icon description if icon is used',
tabIndex: 0,
type: 'button',
disabled: false,
small: false,
kind: 'primary',
};
export default Button;