@6thquake/react-material
Version:
React components that implement Google's Material Design.
362 lines (332 loc) • 10 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 classNames from 'classnames';
import withStyles from '../styles/withStyles';
import { componentPropType } from '@material-ui/utils';
import { capitalize } from '../utils/helpers';
import Badge from '@material-ui/core/Badge';
export const styles = theme => ({
/* Styles applied to the root element. */
root: {
position: 'relative',
display: 'inline-flex',
// For correct alignment with the text.
verticalAlign: 'middle',
fontFamily: theme.typography.fontFamily,
fontWeight: theme.typography.fontWeightMedium,
fontSize: theme.typography.pxToRem(12)
},
/* Styles applied to the badge `span` element. */
badge: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
alignContent: 'center',
alignItems: 'center',
position: 'absolute',
top: 0,
right: 0,
boxSizing: 'border-box',
minWidth: RADIUS * 2,
padding: '0 4px',
height: RADIUS * 2,
borderRadius: RADIUS,
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
zIndex: 1,
// Render the badge on top of potential ripples.
transform: 'scale(1) translate(50%, -50%)',
transformOrigin: '100% 0%',
transition: theme.transitions.create('transform', {
easing: theme.transitions.easing.easeInOut,
duration: theme.transitions.duration.enteringScreen
})
},
/* Styles applied to the root element if `color="primary"`. */
colorPrimary: {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText
},
/* Styles applied to the root element if `color="secondary"`. */
colorSecondary: {
backgroundColor: theme.palette.secondary.main,
color: theme.palette.secondary.contrastText
},
/* Styles applied to the root element if `color="error"`. */
colorError: {
backgroundColor: theme.palette.error.main,
color: theme.palette.error.contrastText
},
/* Styles applied to the badge `span` element if `invisible={true}`. */
invisible: {
transition: theme.transitions.create('transform', {
easing: theme.transitions.easing.easeInOut,
duration: theme.transitions.duration.leavingScreen
}),
transform: 'scale(0) translate(50%, -50%)',
transformOrigin: '100% 0%'
},
/* Styles applied to the root element if `variant="dot"`. */
dot: {
height: 6,
minWidth: 6,
padding: 0
},
mark: {
position: 'absolute',
zIndex: 1,
display: 'inline-block',
textAlign: 'center',
top: 0,
right: theme.spacing(1),
padding: '4px 0px 0px 0px',
width: 24,
wordBreak: 'break-all',
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
'&:before': {
content: '""',
position: 'absolute',
zIndex: 1,
bottom: -theme.spacing(1),
left: 0,
right: 0,
borderLeft: `12px solid ${theme.palette.background.default}`,
borderRight: `12px solid ${theme.palette.background.default}`,
borderTop: `4px solid ${theme.palette.background.default}`,
borderBottom: '4px solid transparent'
}
},
/* Styles applied to the root element if `color="primary" and variant="mark"`. */
markColorPrimary: {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
'&:before': {
borderLeftColor: theme.palette.primary.main,
borderRightColor: theme.palette.primary.main,
borderTopColor: theme.palette.primary.main
}
},
/* Styles applied to the root element if `color="secondary" and variant="mark"`. */
markColorSecondary: {
backgroundColor: theme.palette.secondary.main,
color: theme.palette.secondary.contrastText,
'&:before': {
borderLeftColor: theme.palette.secondary.main,
borderRightColor: theme.palette.secondary.main,
borderTopColor: theme.palette.secondary.main
}
},
/* Styles applied to the root element if `color="error" and variant="mark"`. */
markColorError: {
backgroundColor: theme.palette.error.main,
color: theme.palette.error.contrastText,
'&:before': {
borderLeftColor: theme.palette.error.main,
borderRightColor: theme.palette.error.main,
borderTopColor: theme.palette.error.main
}
},
ribbon: {
position: 'absolute',
zIndex: 1,
width: 'auto',
height: 'auto',
top: 0,
right: 0
},
ribbonWrapper: {
position: 'absolute',
top: 0,
width: '100%',
height: '100%',
overflow: 'hidden'
},
ribbonContent: {
width: '100%',
height: '100%',
backgroundImage: 'none !important',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center center',
whiteSpace: 'nowrap',
padding: '4px 0px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
ribbonContentText: {
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
whiteSpace: 'nowrap',
textAlign: 'center',
// borderTop: `1px solid ${theme.palette.background.default}`,
// borderBottom: `1px solid ${theme.palette.background.default}`,
padding: '0px 32px',
height: '100%'
}
});
const RADIUS = 10;
class RMBadge extends React.Component {
constructor(...args) {
super(...args);
this.state = {};
}
componentDidMount() {
const {
variant
} = this.props;
if (variant === 'ribbon') {
const res = this.refElem.getBoundingClientRect();
const {
width,
height
} = res;
const w = Math.ceil(width);
const h = Math.ceil(height);
const top = Math.ceil(Math.sqrt(2) / 2 * h) + 2;
const right = Math.ceil((1 - 1 / Math.sqrt(2)) * w + h / Math.sqrt(2)) + 2;
this.setState({
width: `${w}px`,
height: `${h}px`,
top: `-${top}px`,
right: `-${right}px`,
transform: 'rotate(45deg)',
transformOrigin: 'left top'
});
}
}
render() {
const _this$props = this.props,
{
badgeContent,
children,
classes,
className,
color,
component: ComponentProp,
invisible: invisibleProp,
showZero,
max,
variant
} = _this$props,
other = _objectWithoutPropertiesLoose(_this$props, ["badgeContent", "children", "classes", "className", "color", "component", "invisible", "showZero", "max", "variant"]);
console.log(this.state);
let invisible = invisibleProp;
if (invisibleProp === null && Number(badgeContent) === 0 && !showZero) {
invisible = true;
}
const displayValue = variant === 'standard' && badgeContent > max ? `${max}+` : badgeContent;
switch (variant) {
case 'mark':
return React.createElement(ComponentProp, _extends({
className: classNames(classes.root, className)
}, other), children, React.createElement("span", {
className: classNames(classes.mark, {
[classes[`markColor${capitalize(color)}`]]: color !== 'default',
[classes.invisible]: invisible
})
}, displayValue));
case 'ribbon':
const {
width,
height,
top,
right,
transform,
transformOrigin
} = this.state;
const style = {
width,
height,
top,
right,
transform,
transformOrigin
};
return React.createElement(ComponentProp, _extends({
className: classNames(classes.root, className)
}, other), children, React.createElement("span", {
className: classes.ribbonWrapper
}, React.createElement("span", {
className: classNames(classes.ribbon, {
[classes[`color${capitalize(color)}`]]: color !== 'default',
[classes.invisible]: invisible
}),
style: style,
ref: node => {
this.refElem = node;
}
}, React.createElement("span", {
className: classes.ribbonContent
}, React.createElement("span", {
className: classes.ribbonContentText
}, displayValue)))));
case 'text':
case 'dot':
case 'standard':
default:
return React.createElement(Badge, this.props, children);
}
}
}
process.env.NODE_ENV !== "production" ? RMBadge.propTypes = {
/**
* The content rendered within the badge.
*/
badgeContent: PropTypes.node,
/**
* The badge will be added relative to this node.
*/
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', 'primary', 'secondary', 'error']),
/**
* The component used for the root node.
* Either a string to use a DOM element or a component.
*/
component: componentPropType,
/**
* If `true`, the badge will be invisible.
*/
invisible: PropTypes.bool,
/**
* Max count to show.
*/
max: PropTypes.number,
/**
* Controls whether the badge is hidden when `badgeContent` is zero.
*/
showZero: PropTypes.bool,
/**
* The variant to use.
*/
variant: PropTypes.oneOf(['standard', 'dot', 'text', 'ribbon', 'mark'])
} : void 0;
RMBadge.defaultProps = {
color: 'default',
component: 'span',
max: 99,
showZero: false,
variant: 'standard'
};
export default withStyles(styles, {
name: 'RMBadge',
withTheme: true
})(RMBadge);