taro-material
Version:
Mini Program components that implement Google's Material Design.
451 lines (411 loc) • 10.9 kB
JavaScript
import Taro, { Component } from '@tarojs/taro';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { View } from '@tarojs/components';
import AtButton from '../components/button/index';
import AtActivityIndicator from '../components/activity-indicator';
import RMIcon from '../Icon';
import theme from '../styles/theme';
import './Button.scss';
class RMButton extends Component {
state = {
status: {
status: '',
},
second: 3,
};
status = {
status: '',
text: '',
timer: null,
};
componentWillMount() {}
componentDidMount() {}
componentWillUnmount() {}
componentDidShow() {}
componentDidHide() {}
onHandler = e => {
const { onClick } = this.props;
if (!onClick) {
return void 0;
}
if (typeof onClick !== 'function') {
return void 0;
}
if (this.status.status === 'progress' || this.status.status === 'success') {
return void 0;
}
this.status.status = 'progress';
let resolve = null,
reject = null;
e.resultPromise = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
try {
onClick(e);
} catch (e) {
this.status.status = 'failed';
this.setState({
status: {
status: 'failed',
},
});
reject && reject(e);
return void 0;
}
const promise = e.returnValue;
if (promise instanceof Promise) {
this.status.status = 'progress';
this.setState({
status: {
status: 'progress',
},
});
promise
.then(r => {
this.status.status = 'success';
this.setState({
status: {
status: 'success',
},
});
return this.reset().then(() => {
resolve && resolve();
});
})
.catch(r => {
this.status.status = 'failed';
this.setState({
status: {
status: 'failed',
},
});
reject && reject(r);
throw r;
});
} else {
this.status.status = '';
resolve && resolve();
}
};
reset = () => {
const { delay } = this.props;
return new Promise((resolve, reject) => {
if (delay === 0) {
this.status = {
status: '',
text: '',
timer: null,
};
this.setState(
{
status: {
status: '',
},
second: 3,
},
() => {
resolve();
},
);
}
this.status.timer = setInterval(() => {
if (this.state.second > 0) {
this.setState({
second: this.state.second - 1,
});
} else {
this.status.timer && clearInterval(this.status.timer);
this.status = {
status: '',
text: '',
timer: null,
};
this.setState(
{
status: {
status: '',
},
second: 3,
},
() => {
resolve();
},
);
}
}, delay);
});
};
render() {
const {
size,
variant,
color,
disabled,
customStyle,
countdown,
block,
formType,
openType,
lang,
sessionFrom,
sendMessageTitle,
sendMessagePath,
sendMessageImg,
showMessageCard,
appParameter,
onGetUserInfo,
onGetPhoneNumber,
onOpenSetting,
onError,
onContact,
} = this.props;
// const common = theme.palette.common.white
const progress = theme.palette.progress.main;
const success = theme.palette.success.main;
const error = theme.palette.error.main;
// const primary = theme.palette.primary.main
const grey = theme.palette.grey['300'];
const { status, second } = this.state;
let loading = false;
let circle = false;
let _color = null;
let _fontColor = null;
let icon = null;
let _customStyle = {};
const _status = status.status;
let _size = null;
let _diameter = 56;
let iconSize = 20;
const _reverse = variant === 'outlined' || variant === 'text';
switch (size) {
case 'small':
_size = 'small';
_diameter = variant === 'fab' ? 40 : 32;
iconSize = 16;
_customStyle.padding = `0 ${theme.spacing.unit / 2}px`;
break;
case 'medium':
case 'normal':
default:
_size = 'normal';
_diameter = variant === 'fab' ? 56 : 48;
iconSize = 20;
_customStyle.padding = `0 ${theme.spacing.unit}px`;
break;
}
_customStyle.height = `${_diameter}px`;
_customStyle.lineHeight = `${_diameter - 2}px`;
_customStyle.fontSize = `${iconSize}px`;
switch (color) {
case 'default':
if (_reverse) {
_color = theme.palette.text.primary;
_fontColor = grey;
} else {
_color = grey;
_fontColor = theme.palette.text.primary;
}
break;
case 'inherit':
_color = 'inherit';
_fontColor = 'inherit';
break;
default:
_color = theme.palette[color].main;
_fontColor = theme.palette[color].contrastText;
break;
}
switch (_status) {
case 'progress':
_color = progress;
_fontColor = theme.palette.progress.contrastText;
loading = true;
break;
case 'success':
_color = success;
_fontColor = theme.palette.success.contrastText;
icon = 'check';
break;
case 'failed':
_color = error;
_fontColor = theme.palette.error.contrastText;
icon = 'replay';
break;
default:
break;
}
switch (variant) {
case 'extendedFab':
circle = true;
_customStyle.boxShadow = theme.shadows[6];
_customStyle.width = 'auto';
_customStyle.minWidth = `${_diameter}px`;
_customStyle.height = `${_diameter}px`;
_customStyle.padding = `0 ${theme.spacing.unit}px`;
_customStyle.borderRadius = `${_diameter / 2}px`;
_customStyle.color = _fontColor;
_customStyle.border = `1px solid ${_color}`;
_customStyle.background = _color;
break;
case 'fab':
circle = true;
_customStyle.boxShadow = theme.shadows[6];
_customStyle.width = `${_diameter}px`;
_customStyle.height = `${_diameter}px`;
_customStyle.lineHeight = `${_diameter}px`;
_customStyle.borderRadius = '50%';
_customStyle.color = _fontColor;
_customStyle.border = `1px solid ${_color}`;
_customStyle.background = _color;
_customStyle.minWidth = 'auto';
break;
case 'outlined':
_customStyle.color = _color;
_customStyle.border = `1px solid ${_color}`;
_customStyle.background = 'transparent';
break;
case 'contained':
_customStyle.color = _fontColor;
_customStyle.border = `1px solid ${_color}`;
_customStyle.background = _color;
_customStyle.boxShadow = theme.shadows[1];
break;
case 'text':
default:
_customStyle.color = _color;
_customStyle.border = `1px none`;
_customStyle.background = 'transparent';
break;
}
_customStyle = {
..._customStyle,
...customStyle,
};
if (block) {
_customStyle.display = 'block';
}
const classes = classNames({
text: true,
fat: variant === 'fab',
});
const _countdown = second >= 0 && second < 3;
const _second = second + 1;
return (
<AtButton
size={_size}
className="status-button"
type="primary"
circle={circle}
loading={false}
disabled={disabled}
customStyle={_customStyle}
formType={formType}
openType={openType}
lang={lang}
sessionFrom={sessionFrom}
sendMessageTitle={sendMessageTitle}
sendMessagePath={sendMessagePath}
sendMessageImg={sendMessageImg}
showMessageCard={showMessageCard}
appParameter={appParameter}
onGetUserInfo={onGetUserInfo}
onGetPhoneNumber={onGetPhoneNumber}
onOpenSetting={onOpenSetting}
onError={onError}
onContact={onContact}
onClick={this.onHandler}
>
<View className="box">
{loading && (
<View>
<AtActivityIndicator size={iconSize * 1.5} color={_reverse ? _color : _fontColor} />
</View>
)}
{_countdown && countdown && <View>{_second}</View>}
{(!_countdown || (_countdown && !countdown)) &&
!loading &&
icon && (
<RMIcon fontSize="inherit" color="inherit" block>
{icon}
</RMIcon>
)}
{!(variant === 'fab' && (loading || icon)) && (
<View className={classes}>{this.props.children}</View>
)}
</View>
</AtButton>
);
}
}
RMButton.defaultProps = {
variant: 'text',
size: 'medium',
color: 'default',
disabled: false,
customStyle: {},
onClick: () => {},
// Button props
formType: '',
openType: '',
lang: 'en',
sessionFrom: '',
sendMessageTitle: '',
sendMessagePath: '',
sendMessageImg: '',
showMessageCard: false,
appParameter: '',
onGetUserInfo: () => {},
onContact: () => {},
onGetPhoneNumber: () => {},
onError: () => {},
onOpenSetting: () => {},
delay: 2040,
countdown: false,
};
RMButton.propTypes = {
appParameter: PropTypes.string,
color: PropTypes.oneOf([
'default',
'inherit',
'primary',
'secondary',
'error',
'success',
'warning',
'progress',
]),
countdown: PropTypes.bool,
customStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
delay: PropTypes.number,
disabled: PropTypes.bool,
formType: PropTypes.oneOf(['submit', 'reset', '']),
lang: PropTypes.string,
onClick: PropTypes.func,
onContact: PropTypes.func,
onError: PropTypes.func,
onGetPhoneNumber: PropTypes.func,
onGetUserInfo: PropTypes.func,
onOpenSetting: PropTypes.func,
openType: PropTypes.oneOf([
'contact',
'share',
'getUserInfo',
'getPhoneNumber',
'launchApp',
'openSetting',
'feedback',
'getRealnameAuthInfo',
'',
]),
sendMessageImg: PropTypes.string,
sendMessagePath: PropTypes.string,
sendMessageTitle: PropTypes.string,
sessionFrom: PropTypes.string,
showMessageCard: PropTypes.bool,
size: PropTypes.oneOf(['medium', 'normal', 'small']),
variant: PropTypes.oneOf(['text', 'outlined', 'contained', 'fab', 'extendedFab']),
block: PropTypes.bool,
};
export default RMButton;