@6thquake/react-material
Version:
React components that implement Google's Material Design.
426 lines (386 loc) • 11.3 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import withStyles from '../styles/withStyles';
import { fade } from '../styles/colorManipulator';
import Button from '@material-ui/core/Button/Button';
import classNames from 'classnames';
import Done from '@material-ui/icons/Done';
import Replay from '@material-ui/icons/Replay';
import CircularProgress from '../CircularProgress';
import common from '../colors/common';
const styles = theme => {
const defaultStyle = {
flat: {
warning: {
color: theme.palette.warning.main,
'&:hover': {
backgroundColor: fade(theme.palette.warning.main, theme.palette.action.hoverOpacity),
'@media (hover: none)': {
backgroundColor: 'transparent'
}
}
},
error: {
color: theme.palette.error.main,
'&:hover': {
backgroundColor: fade(theme.palette.error.main, theme.palette.action.hoverOpacity),
'@media (hover: none)': {
backgroundColor: 'transparent'
}
}
},
success: {
color: theme.palette.success.main,
'&:hover': {
backgroundColor: fade(theme.palette.success.main, theme.palette.action.hoverOpacity),
'@media (hover: none)': {
backgroundColor: 'transparent'
}
}
},
progress: {
color: theme.palette.progress.main,
'&:hover': {
backgroundColor: fade(theme.palette.progress.main, theme.palette.action.hoverOpacity),
'@media (hover: none)': {
backgroundColor: 'transparent'
}
}
}
},
raised: {
warning: {
color: theme.palette.warning.contrastText,
backgroundColor: theme.palette.warning.main,
'&:hover': {
backgroundColor: theme.palette.warning.dark,
'@media (hover: none)': {
backgroundColor: theme.palette.warning.main
}
}
},
success: {
color: theme.palette.success.contrastText,
backgroundColor: theme.palette.success.main,
'&:hover': {
backgroundColor: theme.palette.success.dark,
'@media (hover: none)': {
backgroundColor: theme.palette.success.main
}
}
},
error: {
color: theme.palette.error.contrastText,
backgroundColor: theme.palette.error.main,
'&:hover': {
backgroundColor: theme.palette.error.dark,
'@media (hover: none)': {
backgroundColor: theme.palette.error.main
}
}
},
progress: {
color: theme.palette.progress.contrastText,
backgroundColor: theme.palette.progress.main,
'&:hover': {
backgroundColor: theme.palette.progress.dark,
'@media (hover: none)': {
backgroundColor: theme.palette.progress.main
}
}
}
}
};
return {
// todo remove
root: {},
label: {},
flatPrimary: {},
flatSecondary: {},
colorInherit: {},
raised: {},
raisedPrimary: {},
raisedSecondary: {},
focusVisible: {},
disabled: {},
fab: {},
mini: {},
sizeSmall: {},
sizeLarge: {},
fullWidth: {},
// ...styles(theme),
flatWaring: defaultStyle.flat.warning,
flatError: defaultStyle.flat.error,
flatSuccess: defaultStyle.flat.success,
flatProgress: defaultStyle.flat.progress,
raisedWaring: defaultStyle.raised.warning,
raisedError: defaultStyle.raised.error,
raisedSuccess: defaultStyle.raised.success,
raisedProgress: defaultStyle.raised.progress,
icon: {
fontSize: theme.typography.pxToRem(15),
marginRight: theme.spacing(1)
},
fabStatus: {
fontSize: theme.typography.pxToRem(24)
},
progress: {
color: common.white
},
fish: {
transform: 'scale3d(1,1,1)',
'-ms-transform': 'scale3d(1,1,1)'
/* IE 9 */
,
'-moz-transform': 'scale3d(1,1,1)'
/* Firefox */
,
'-webkit-transform': 'scale3d(1,1,1)'
/* Safari 和 Chrome */
,
'-o-transform': 'scale3d(1,1,1)',
transition: 'all 86ms ease-out',
'&:hover': {
transform: 'scale3d(1.2, 1.2, 1.2)',
'-ms-transform': 'scale3d(1.2, 1.2, 1.2)'
/* IE 9 */
,
'-moz-transform': 'scale3d(1.2, 1.2, 1.2)'
/* Firefox */
,
'-webkit-transform': 'scale3d(1.2, 1.2, 1.2)'
/* Safari 和 Chrome */
,
'-o-transform': 'scale3d(1.2, 1.2, 1.2)'
}
}
};
};
class RMButton extends Component {
constructor(..._args) {
super(..._args);
this.firstRender = true;
this.state = {
color: this.props.color
};
this.status = {
status: '',
text: ''
};
this.onHandler = (...args) => {
const {
onClick
} = this.props;
let result;
if (this.status.status === 'progress') {
return void 0;
}
if (typeof onClick === 'function') {
result = onClick.apply(this, args);
}
if (result) {
if (result instanceof Promise || typeof result.then === 'function') {
this.status.status = 'progress';
this.setState({
color: 'progress'
});
result.then(r => {
this.status.status = 'success';
this.setState({
color: 'success'
});
}).catch(r => {
this.status.status = 'false';
this.setState({
color: 'error'
});
});
}
}
};
}
getStatusIcon(classes) {
const {
variant
} = this.props;
const className = classNames({
[classes.icon]: variant !== 'fab',
[classes.fabStatus]: variant === 'fab'
});
switch (this.status.status) {
case 'progress':
// todo button loading styles
return this.renderProgress(className);
case 'success':
return React.createElement(Done, {
className: className
});
case 'false':
return React.createElement(Replay, {
className: className
});
default:
return null;
}
}
renderProgress(className) {
const {
variant,
classes
} = this.props;
const size = variant === 'fab' ? 24 : 15;
const classesPro = classNames({
[classes.progress]: variant !== 'flat' && variant !== 'outlined',
[classes.flatProgress]: variant === 'flat' || variant === 'outlined'
}, className);
return React.createElement(CircularProgress, {
className: classesPro,
size: size
});
}
resetActive() {
this.setState({
active: false
});
}
renderChildren() {
const {
children,
variant
} = this.props;
if (variant === 'fab') {
if (this.status.status !== '') {
return null;
}
}
return children;
}
render() {
const _this$props = this.props,
{
className: classNamePro,
classes
} = _this$props,
props = _objectWithoutPropertiesLoose(_this$props, ["children", "className", "classes", "onClick"]);
const classesPro = _objectWithoutPropertiesLoose(classes, ["raisedProgress", "raisedError", "raisedSuccess", "raisedWaring", "flatProgress", "flatError", "flatSuccess", "flatWaring", "icon", "fabStatus", "progress", "fish"]);
props.color = this.state.color;
const {
color
} = props;
const customColors = ['warning', 'error', 'success', 'progress'];
if (customColors.indexOf(color) !== -1) {
props.color = 'default';
}
this.firstRender = false;
const flat = this.props.variant === 'flat';
const className = classNames({
[classes.raisedProgress]: !flat && color === 'progress',
[classes.raisedError]: !flat && color === 'error',
[classes.raisedSuccess]: !flat && color === 'success',
[classes.raisedWaring]: !flat && color === 'warning',
[classes.flatProgress]: flat && color === 'progress',
[classes.flatError]: flat && color === 'error',
[classes.flatSuccess]: flat && color === 'success',
[classes.flatWaring]: flat && color === 'warning',
[classes.fish]: props.variant === 'fish'
}, classNamePro);
if (props.variant === 'fish') {
props.variant = 'fab';
}
return React.createElement(Button, _extends({}, props, {
classes: classesPro,
className: className,
onClick: this.onHandler
}), this.getStatusIcon(classes), this.renderChildren());
}
}
process.env.NODE_ENV !== "production" ? RMButton.propTypes = {
/**
* The content of the button.
*/
children: PropTypes.node.isRequired,
/**
* Override or extend the styles applied to the component.
* See [CSS API](#css-api) below for more details.
*/
classes: PropTypes.object.isRequired,
/**
* @ignore
*/
className: PropTypes.string,
/**
* The color of the component. It supports those theme colors that make sense for this component.
*/
color: PropTypes.oneOf(['default', 'inherit', 'primary', 'secondary', 'error', 'success', 'warning', 'progress']),
/**
* The component used for the root node.
* Either a string to use a DOM element or a component.
*/
component: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.object]),
/**
* If `true`, the button will be disabled.
*/
disabled: PropTypes.bool,
/**
* If `true`, the keyboard focus ripple will be disabled.
* `disableRipple` must also be true.
*/
disableFocusRipple: PropTypes.bool,
/**
* If `true`, the ripple effect will be disabled.
*/
disableRipple: PropTypes.bool,
/**
* @ignore
*/
focusVisibleClassName: PropTypes.string,
/**
* If `true`, the button will take up the full width of its container.
*/
fullWidth: PropTypes.bool,
/**
* The URL to link to when the button is clicked.
* If defined, an `a` element will be used as the root node.
*/
href: PropTypes.string,
/**
* If `true`, and `variant` is `'fab'`, will use mini floating action button styling.
*/
mini: PropTypes.bool,
/**
* Button 的回掉函数,函数的返回值如果是Promise,Button变为带反馈的样子。
*/
onClick: PropTypes.func,
/**
* The size of the button.
* `small` is equivalent to the dense button styling.
*/
size: PropTypes.oneOf(['small', 'medium', 'large']),
/**
* The type of button.
*/
type: PropTypes.string,
/**
* The variant to use.
*/
variant: PropTypes.oneOf(['text', 'flat', 'outlined', 'contained', 'raised', 'fab', 'extendedFab', 'fish'])
} : void 0;
RMButton.defaultProps = {
color: 'default',
component: 'button',
disabled: false,
disableFocusRipple: false,
fullWidth: false,
mini: false,
size: 'medium',
type: 'button',
variant: 'text'
};
RMButton.contextTypes = {
resetActive: PropTypes.func
};
export default withStyles(styles, {
name: 'RMButton'
})(RMButton);