2017-06-04 10:40:14 +08:00
|
|
|
import React from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2016-05-20 21:37:19 +08:00
|
|
|
import cx from 'classnames';
|
2022-02-16 02:07:09 +08:00
|
|
|
import TooltipContainer from '/imports/ui/components/common/tooltip/container';
|
2021-11-10 19:37:08 +08:00
|
|
|
import Styled from './styles';
|
2017-08-21 08:16:39 +08:00
|
|
|
import BaseButton from './base/component';
|
2021-07-01 05:39:32 +08:00
|
|
|
import ButtonEmoji from './button-emoji/ButtonEmoji';
|
2016-05-20 21:37:19 +08:00
|
|
|
|
|
|
|
const SIZES = [
|
2016-10-12 03:04:50 +08:00
|
|
|
'jumbo', 'lg', 'md', 'sm',
|
2016-05-20 21:37:19 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
const COLORS = [
|
2022-08-29 20:39:20 +08:00
|
|
|
'default', 'primary', 'danger', 'warning', 'success', 'dark', 'light', 'offline', 'muted', 'secondary',
|
2016-05-20 21:37:19 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
const propTypes = {
|
|
|
|
...BaseButton.propTypes,
|
|
|
|
/**
|
|
|
|
* Defines the button size style
|
|
|
|
* @type {("lg"|"md"|"sm")}
|
|
|
|
* @defaultValue 'md'
|
|
|
|
*/
|
|
|
|
size: PropTypes.oneOf(SIZES),
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines the button color style
|
|
|
|
* @type {("default"|"primary"|"danger"|"success")}
|
|
|
|
* @defaultValue 'md'
|
|
|
|
*/
|
|
|
|
color: PropTypes.oneOf(COLORS),
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines if the button should be styled as a ghost (outline)
|
|
|
|
* @defaultValue false
|
|
|
|
*/
|
|
|
|
ghost: PropTypes.bool,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines if the button should be styled as circle
|
|
|
|
* @defaultValue false
|
|
|
|
*/
|
|
|
|
circle: PropTypes.bool,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines if the button should have `display: block`
|
|
|
|
* @defaultValue false
|
|
|
|
*/
|
|
|
|
block: PropTypes.bool,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines the button icon
|
|
|
|
* @defaultValue undefined
|
|
|
|
*/
|
|
|
|
icon: PropTypes.string,
|
|
|
|
|
2016-05-20 22:49:28 +08:00
|
|
|
/**
|
|
|
|
* Defines the button icon is on the right side
|
|
|
|
* @defaultValue false
|
|
|
|
*/
|
|
|
|
iconRight: PropTypes.bool,
|
|
|
|
|
2016-05-20 21:37:19 +08:00
|
|
|
/**
|
2016-06-18 00:42:17 +08:00
|
|
|
* Defines the button label should be visible
|
2024-08-08 00:26:20 +08:00
|
|
|
* @defaultValue false
|
2016-05-20 21:37:19 +08:00
|
|
|
*/
|
2016-06-18 00:42:17 +08:00
|
|
|
hideLabel: PropTypes.bool,
|
2017-04-19 08:46:01 +08:00
|
|
|
|
|
|
|
/**
|
2017-06-03 07:41:28 +08:00
|
|
|
* Optional SVG / html object can be passed to the button as an icon
|
2017-04-19 08:46:01 +08:00
|
|
|
* Has to be styled before being sent to the Button
|
|
|
|
* (e.g width, height, position and percentage-based object's coordinates)
|
|
|
|
* @defaultvalue undefined
|
|
|
|
*/
|
2017-06-03 07:41:28 +08:00
|
|
|
customIcon: PropTypes.node,
|
2024-08-06 01:05:04 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines the buttom loading state
|
|
|
|
* @defaultValue false
|
|
|
|
*/
|
|
|
|
loading: PropTypes.bool,
|
2016-05-20 21:37:19 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const defaultProps = {
|
|
|
|
...BaseButton.defaultProps,
|
|
|
|
size: 'md',
|
|
|
|
color: 'default',
|
|
|
|
ghost: false,
|
|
|
|
circle: false,
|
|
|
|
block: false,
|
2016-05-20 22:49:28 +08:00
|
|
|
iconRight: false,
|
2016-06-18 00:42:17 +08:00
|
|
|
hideLabel: false,
|
2019-06-27 20:06:19 +08:00
|
|
|
tooltipLabel: '',
|
2024-08-06 01:05:04 +08:00
|
|
|
loading: false,
|
2016-05-20 21:37:19 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export default class Button extends BaseButton {
|
2020-06-18 23:47:52 +08:00
|
|
|
_cleanProps(otherProps) {
|
|
|
|
const remainingProps = Object.assign({}, otherProps);
|
|
|
|
delete remainingProps.icon;
|
|
|
|
delete remainingProps.customIcon;
|
|
|
|
delete remainingProps.size;
|
|
|
|
delete remainingProps.color;
|
|
|
|
delete remainingProps.ghost;
|
|
|
|
delete remainingProps.circle;
|
|
|
|
delete remainingProps.block;
|
|
|
|
delete remainingProps.hideLabel;
|
|
|
|
delete remainingProps.tooltipLabel;
|
|
|
|
|
|
|
|
return remainingProps;
|
|
|
|
}
|
|
|
|
|
2021-05-10 19:58:52 +08:00
|
|
|
hasButtonEmojiComponent() {
|
|
|
|
const { children } = this.props;
|
|
|
|
|
|
|
|
if (!children) return false;
|
|
|
|
|
|
|
|
const buttonEmoji = React.Children.only(children);
|
|
|
|
|
|
|
|
return (buttonEmoji && buttonEmoji.type && buttonEmoji.type.name)
|
|
|
|
? (buttonEmoji.type.name === ButtonEmoji.name)
|
|
|
|
: false;
|
|
|
|
}
|
|
|
|
|
2016-05-20 21:37:19 +08:00
|
|
|
render() {
|
2017-12-05 03:43:08 +08:00
|
|
|
const {
|
|
|
|
circle,
|
|
|
|
hideLabel,
|
|
|
|
label,
|
2018-01-15 02:19:13 +08:00
|
|
|
'aria-label': ariaLabel,
|
2018-12-12 22:01:33 +08:00
|
|
|
'aria-expanded': ariaExpanded,
|
2019-06-27 20:06:19 +08:00
|
|
|
tooltipLabel,
|
2023-04-04 11:09:45 +08:00
|
|
|
tooltipdelay,
|
|
|
|
tooltipplacement,
|
2017-12-05 03:43:08 +08:00
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
const renderFuncName = circle ? 'renderCircle' : 'renderDefault';
|
|
|
|
|
2019-06-27 20:06:19 +08:00
|
|
|
if ((hideLabel && !ariaExpanded) || tooltipLabel) {
|
|
|
|
const buttonLabel = label || ariaLabel;
|
2018-02-13 23:51:13 +08:00
|
|
|
return (
|
2020-07-23 06:08:55 +08:00
|
|
|
<TooltipContainer
|
2019-06-27 20:06:19 +08:00
|
|
|
title={tooltipLabel || buttonLabel}
|
2023-04-04 11:09:45 +08:00
|
|
|
delay={tooltipdelay}
|
|
|
|
placement={tooltipplacement}
|
2017-12-05 03:43:08 +08:00
|
|
|
>
|
|
|
|
{this[renderFuncName]()}
|
2020-07-23 06:08:55 +08:00
|
|
|
</TooltipContainer>
|
2018-02-13 23:51:13 +08:00
|
|
|
);
|
2017-12-05 03:43:08 +08:00
|
|
|
}
|
2016-05-20 21:37:19 +08:00
|
|
|
|
|
|
|
return this[renderFuncName]();
|
|
|
|
}
|
|
|
|
|
|
|
|
renderDefault() {
|
|
|
|
const {
|
|
|
|
className,
|
2016-05-20 22:49:28 +08:00
|
|
|
iconRight,
|
2021-11-10 22:41:55 +08:00
|
|
|
size,
|
|
|
|
color,
|
|
|
|
ghost,
|
|
|
|
circle,
|
|
|
|
block,
|
2024-08-06 01:05:04 +08:00
|
|
|
loading,
|
2017-08-21 08:16:39 +08:00
|
|
|
...otherProps
|
2016-05-20 21:37:19 +08:00
|
|
|
} = this.props;
|
|
|
|
|
2020-06-18 23:47:52 +08:00
|
|
|
const remainingProps = this._cleanProps(otherProps);
|
2016-07-12 04:10:55 +08:00
|
|
|
|
2016-05-20 21:37:19 +08:00
|
|
|
return (
|
2021-11-10 22:41:55 +08:00
|
|
|
<Styled.Button
|
|
|
|
size={size}
|
|
|
|
color={color}
|
|
|
|
ghost={ghost}
|
|
|
|
circle={circle}
|
|
|
|
block={block}
|
|
|
|
className={className}
|
2021-11-18 02:28:00 +08:00
|
|
|
iconRight={iconRight}
|
2024-08-06 01:05:04 +08:00
|
|
|
loading={loading}
|
2016-07-12 04:10:55 +08:00
|
|
|
{...remainingProps}
|
|
|
|
>
|
2021-11-18 02:28:00 +08:00
|
|
|
{this.renderIcon()}
|
|
|
|
{this.renderLabel()}
|
2021-11-10 22:41:55 +08:00
|
|
|
</Styled.Button>
|
2016-05-20 21:37:19 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderCircle() {
|
|
|
|
const {
|
|
|
|
className,
|
|
|
|
size,
|
2016-05-27 08:13:53 +08:00
|
|
|
iconRight,
|
2021-05-10 19:58:52 +08:00
|
|
|
children,
|
2021-11-10 22:41:55 +08:00
|
|
|
color,
|
|
|
|
ghost,
|
|
|
|
circle,
|
|
|
|
block,
|
2024-08-06 01:05:04 +08:00
|
|
|
loading,
|
2017-08-21 08:16:39 +08:00
|
|
|
...otherProps
|
2016-05-20 21:37:19 +08:00
|
|
|
} = this.props;
|
|
|
|
|
2020-06-18 23:47:52 +08:00
|
|
|
const remainingProps = this._cleanProps(otherProps);
|
2016-07-12 04:10:55 +08:00
|
|
|
|
2016-05-20 21:37:19 +08:00
|
|
|
return (
|
2021-11-10 22:41:55 +08:00
|
|
|
<Styled.ButtonWrapper
|
|
|
|
size={size}
|
|
|
|
className={cx(size, 'buttonWrapper', className)}
|
|
|
|
color={color}
|
|
|
|
ghost={ghost}
|
|
|
|
circle={circle}
|
|
|
|
block={block}
|
2024-08-06 01:05:04 +08:00
|
|
|
loading={loading}
|
2016-07-12 04:10:55 +08:00
|
|
|
{...remainingProps}
|
|
|
|
>
|
2021-05-13 03:43:48 +08:00
|
|
|
{this.renderButtonEmojiSibling()}
|
2016-06-18 00:42:17 +08:00
|
|
|
{!iconRight ? null : this.renderLabel()}
|
2021-11-10 22:41:55 +08:00
|
|
|
<Styled.ButtonSpan
|
|
|
|
size={size}
|
|
|
|
color={color}
|
|
|
|
ghost={ghost}
|
|
|
|
circle={circle}
|
|
|
|
block={block}
|
|
|
|
>
|
2016-05-20 21:37:19 +08:00
|
|
|
{this.renderIcon()}
|
2021-11-10 22:41:55 +08:00
|
|
|
</Styled.ButtonSpan>
|
2016-06-18 00:42:17 +08:00
|
|
|
{iconRight ? null : this.renderLabel()}
|
2021-05-10 19:58:52 +08:00
|
|
|
{this.hasButtonEmojiComponent() ? children : null}
|
2021-11-10 22:41:55 +08:00
|
|
|
</Styled.ButtonWrapper>
|
2016-05-20 21:37:19 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-13 03:43:48 +08:00
|
|
|
renderButtonEmojiSibling() {
|
|
|
|
if (!this.hasButtonEmojiComponent()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-11-10 22:41:55 +08:00
|
|
|
return (<Styled.EmojiButtonSibling />);
|
2021-05-13 03:43:48 +08:00
|
|
|
}
|
|
|
|
|
2016-05-20 21:37:19 +08:00
|
|
|
renderIcon() {
|
2019-03-09 08:33:04 +08:00
|
|
|
const {
|
|
|
|
icon: iconName,
|
|
|
|
customIcon,
|
|
|
|
} = this.props;
|
2016-05-20 21:37:19 +08:00
|
|
|
|
|
|
|
if (iconName) {
|
2021-11-10 19:37:08 +08:00
|
|
|
return (<Styled.ButtonIcon iconName={iconName} />);
|
2018-12-06 01:42:31 +08:00
|
|
|
} if (customIcon) {
|
2017-06-03 07:41:28 +08:00
|
|
|
return customIcon;
|
2016-05-20 21:37:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-06-18 00:42:17 +08:00
|
|
|
renderLabel() {
|
|
|
|
const { label, hideLabel } = this.props;
|
2016-05-20 21:37:19 +08:00
|
|
|
|
2024-02-24 03:05:21 +08:00
|
|
|
if (!label) return null;
|
|
|
|
|
2016-06-18 00:42:17 +08:00
|
|
|
return (
|
2021-11-10 22:41:55 +08:00
|
|
|
<Styled.ButtonLabel hideLabel={hideLabel}>
|
2016-06-18 00:42:17 +08:00
|
|
|
{label}
|
2021-06-28 01:50:20 +08:00
|
|
|
{!this.hasButtonEmojiComponent() ? this.props.children : null}
|
2021-11-10 22:41:55 +08:00
|
|
|
</Styled.ButtonLabel>
|
2016-06-18 00:42:17 +08:00
|
|
|
);
|
2016-05-20 21:37:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Button.propTypes = propTypes;
|
|
|
|
Button.defaultProps = defaultProps;
|