UNPKG

react-metric-card

Version:

A metric card component that provides data display with icons, loaders and comparisons, along with custom text segments

496 lines (469 loc) 12.6 kB
import React from 'react'; import { makeStyles, ThemeProvider } from '@material-ui/styles'; import { colors, createMuiTheme, Card, ButtonBase, CardContent, Grid, Typography, Icon, CircularProgress, Tooltip } from '@material-ui/core'; import PropTypes from 'prop-types'; import TrendingFlatIcon from '@material-ui/icons/TrendingFlat'; import TrendingUpIcon from '@material-ui/icons/TrendingUp'; import TrendingDownIcon from '@material-ui/icons/TrendingDown'; import InsertChartIcon from '@material-ui/icons/InsertChartOutlined'; import ErrorIcon from '@material-ui/icons/Error'; var white = '#FFFFFF'; var black = '#000000'; var green = '#00e676'; var palette = { black: black, white: white, primary: { contrastText: white, dark: colors.indigo[900], main: colors.indigo[500], light: colors.indigo[100] }, secondary: { contrastText: white, dark: colors.blue[900], main: colors.blue.A400, light: colors.blue.A400 }, success: { contrastText: white, dark: colors.green[900], main: colors.green[600], light: colors.green[400] }, info: { contrastText: white, dark: colors.blue[900], main: colors.blue[600], light: colors.blue[400] }, warning: { contrastText: white, dark: colors.orange[900], main: colors.orange[600], light: colors.orange[400] }, error: { contrastText: white, dark: colors.red[900], main: colors.red[600], light: colors.red[400] }, text: { primary: colors.blueGrey[900], secondary: colors.blueGrey[600], link: colors.blue[600] }, background: { "default": '#F4F6F8', paper: white }, icon: { primary: '#006066', secondary: green }, divider: colors.grey[200] }; var typography = { h1: { color: palette.text.primary, fontWeight: 500, fontSize: '35px', letterSpacing: '-0.24px', lineHeight: '40px' }, h2: { color: palette.text.primary, fontWeight: 500, fontSize: '29px', letterSpacing: '-0.24px', lineHeight: '32px' }, h3: { color: palette.text.primary, fontWeight: 500, fontSize: '24px', letterSpacing: '-0.06px', lineHeight: '28px' }, h4: { color: palette.text.primary, fontWeight: 500, fontSize: '20px', letterSpacing: '-0.06px', lineHeight: '24px' }, h5: { color: palette.text.primary, fontWeight: 500, fontSize: '16px', letterSpacing: '-0.05px', lineHeight: '20px' }, h6: { color: palette.text.primary, fontWeight: 500, fontSize: '14px', letterSpacing: '-0.05px', lineHeight: '20px' }, subtitle1: { color: palette.text.primary, fontSize: '16px', letterSpacing: '-0.05px', lineHeight: '25px' }, subtitle2: { color: palette.text.secondary, fontWeight: 400, fontSize: '14px', letterSpacing: '-0.05px', lineHeight: '21px' }, body1: { color: palette.text.primary, fontSize: '14px', letterSpacing: '-0.05px', lineHeight: '21px' }, body2: { color: palette.text.secondary, fontSize: '12px', letterSpacing: '-0.04px', lineHeight: '18px' }, button: { color: palette.text.primary, fontSize: '14px' }, caption: { color: palette.text.secondary, fontSize: '11px', letterSpacing: '0.33px', lineHeight: '13px' }, overline: { color: palette.text.secondary, fontSize: '11px', fontWeight: 500, letterSpacing: '0.33px', lineHeight: '13px', textTransform: 'uppercase' } }; var MuiButton = { contained: { boxShadow: '0 1px 1px 0 rgba(0,0,0,0.14), 0 2px 1px -1px rgba(0,0,0,0.12), 0 1px 3px 0 rgba(0,0,0,0.20)', backgroundColor: '#FFFFFF' } }; var MuiIconButton = { root: { color: palette.icon, '&:hover': { backgroundColor: 'rgba(0, 0, 0, 0.03)' } } }; var MuiPaper = { elevation1: { boxShadow: '0 0 0 1px rgba(63,63,68,0.05), 0 1px 3px 0 rgba(63,63,68,0.15)' } }; function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } var MuiTableCell = { root: _extends({}, typography.body1, { borderBottom: "1px solid " + palette.divider }) }; var MuiTableHead = { root: { backgroundColor: colors.grey[50] } }; var MuiTypography = { gutterBottom: { marginBottom: 8 } }; var overrides = { MuiButton: MuiButton, MuiIconButton: MuiIconButton, MuiPaper: MuiPaper, MuiTableCell: MuiTableCell, MuiTableHead: MuiTableHead, MuiTypography: MuiTypography }; var theme = createMuiTheme({ palette: palette, typography: typography, overrides: overrides, zIndex: { appBar: 100, drawer: 1200 } }); function toVal(mix) { var k, y, str=''; if (typeof mix === 'string' || typeof mix === 'number') { str += mix; } else if (typeof mix === 'object') { if (Array.isArray(mix)) { for (k=0; k < mix.length; k++) { if (mix[k]) { if (y = toVal(mix[k])) { str && (str += ' '); str += y; } } } } else { for (k in mix) { if (mix[k]) { str && (str += ' '); str += k; } } } } return str; } function clsx () { var i=0, tmp, x, str=''; while (i < arguments.length) { if (tmp = arguments[i++]) { if (x = toVal(tmp)) { str && (str += ' '); str += x; } } } return str; } var useStyles = makeStyles(function (theme) { return { content: { alignItems: 'center', display: 'flex' }, cardAction: { display: 'block', textAlign: 'initial', height: '100%', width: '100%' }, title: { fontWeight: 800, color: '#ff0000', font: 'Courier New' }, avatar: { backgroundColor: theme.palette.error.main, height: 56, width: 56 }, difference: { marginTop: theme.spacing(2), display: 'flex', alignItems: 'center' }, differenceIconSuccess: { color: theme.palette.success.main }, differenceIconInfo: { color: theme.palette.info.main }, differenceIconError: { color: theme.palette.error.main }, differenceValueSuccess: { color: theme.palette.success.main, marginRight: theme.spacing(1) }, differenceValueInfo: { color: theme.palette.info.main, marginRight: theme.spacing(1) }, differenceValueError: { color: theme.palette.error.main, marginRight: theme.spacing(1) }, error: { color: theme.palette.error.main } }; }); var renderMetricTrend = function renderMetricTrend(trend, classes) { var _trend$slope = trend.slope, slope = _trend$slope === void 0 ? 0 : _trend$slope, _trend$description = trend.description, description = _trend$description === void 0 ? '' : _trend$description; var trendValueClass = ''; var trendIcon = ''; if (slope > 0) { trendValueClass = classes.differenceValueSuccess; trendIcon = /*#__PURE__*/React.createElement(TrendingUpIcon, { className: classes.differenceIconSuccess }); } else if (slope < 0) { trendValueClass = classes.differenceValueError; trendIcon = /*#__PURE__*/React.createElement(TrendingDownIcon, { className: classes.differenceIconError }); } else { trendValueClass = classes.differenceValueInfo; trendIcon = /*#__PURE__*/React.createElement(TrendingFlatIcon, { className: classes.differenceIconInfo }); } var text = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Typography, { className: trendValueClass, variant: "body2" }, trend.value || ''), /*#__PURE__*/React.createElement(Typography, { className: classes.caption, variant: "caption" }, description || '')); return /*#__PURE__*/React.createElement(React.Fragment, null, trendIcon, text); }; var MetricCard = function MetricCard(props) { var classes = useStyles(); var fetching = props.fetching, errorMessage = props.errorMessage, errorTooltip = props.errorTooltip, value = props.value, spinnerColor = props.spinnerColor, spinnerSize = props.spinnerSize, spinnerThickness = props.spinnerThickness, title = props.title, titleColor = props.titleColor, titleFontFamily = props.titleFontFamily, titleFontSize = props.titleFontSize, valueColor = props.valueColor, valueFontFamily = props.valueFontFamily, valueFontSize = props.valueFontSize, trend = props.trend, icon = props.icon, iconBgColor = props.iconBgColor, iconColor = props.iconColor, iconBorderRadius = props.iconBorderRadius, iconHeight = props.iconHeight, iconWidth = props.iconWidth, cardBgColor = props.cardBgColor, cardClick = props.cardClick, cardClickFunction = props.cardClickFunction; var customClasses = makeStyles(function (theme) { return { root: { backgroundColor: cardBgColor || theme.palette.primary.white, height: '100%', width: '100%' }, spinner: { color: spinnerColor }, title: { fontWeight: 800, color: titleColor, fontFamily: titleFontFamily, fontSize: titleFontSize }, value: { color: valueColor, font: valueFontFamily, fontSize: valueFontSize }, icon: { backgroundColor: iconBgColor || theme.palette.icon.primary, height: iconHeight || 56, width: iconWidth || 56, borderRadius: iconBorderRadius || '50%', display: 'flex', justifyContent: 'center', alignItems: 'center', color: iconColor || theme.palette.white } }; })(); return /*#__PURE__*/React.createElement(Card, { className: clsx(customClasses.root) }, /*#__PURE__*/React.createElement(ButtonBase, { className: classes.cardAction, onClick: cardClickFunction, disabled: !cardClick }, /*#__PURE__*/React.createElement(CardContent, null, /*#__PURE__*/React.createElement(Grid, { container: true, justify: "space-between" }, /*#__PURE__*/React.createElement(Grid, { item: true }, /*#__PURE__*/React.createElement(Typography, { className: customClasses.title, gutterBottom: true, variant: "body2" }, title), /*#__PURE__*/React.createElement(Typography, { variant: "h3", className: customClasses.value }, fetching ? '' : errorMessage ? '' : value)), /*#__PURE__*/React.createElement(Grid, { item: true }, /*#__PURE__*/React.createElement(Icon, { className: customClasses.icon }, icon || /*#__PURE__*/React.createElement(InsertChartIcon, null)))), /*#__PURE__*/React.createElement("div", { className: classes.difference }, fetching ? /*#__PURE__*/React.createElement(CircularProgress, { className: customClasses.spinner, size: spinnerSize, thickness: spinnerThickness }) : errorMessage ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Tooltip, { title: errorTooltip || errorMessage }, /*#__PURE__*/React.createElement(ErrorIcon, { color: "error" })), /*#__PURE__*/React.createElement(Typography, { variant: "caption" }, errorMessage)) : trend && renderMetricTrend(trend, classes))))); }; MetricCard.propTypes = { title: PropTypes.string, fetching: PropTypes.bool, errorMessage: PropTypes.string, errorTooltip: PropTypes.string, value: PropTypes.string, spinnerColor: PropTypes.string, spinnerSize: PropTypes.number, spinnerThickness: PropTypes.number, titleColor: PropTypes.string, titleFontFamily: PropTypes.string, titleFontSize: PropTypes.string, valueColor: PropTypes.string, valueFontFamily: PropTypes.string, valueFontSize: PropTypes.string, trend: PropTypes.object, icon: PropTypes.object, iconBgColor: PropTypes.string, iconColor: PropTypes.string, iconBorderRadius: PropTypes.string, iconHeight: PropTypes.string, iconWidth: PropTypes.string, cardBgColor: PropTypes.string, cardClick: PropTypes.bool, cardClickFunction: PropTypes.func }; var MetricCard$1 = function MetricCard$1(props) { return /*#__PURE__*/React.createElement(ThemeProvider, { theme: theme }, /*#__PURE__*/React.createElement(MetricCard, props)); }; export default MetricCard$1; export { MetricCard$1 as MetricCard }; //# sourceMappingURL=index.modern.js.map