@auth0/quantum-charts 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/LICENSE +186 -0
  2. package/bar-chart/index.d.ts +7 -0
  3. package/bar-chart/index.js +115 -0
  4. package/chart-card/index.d.ts +6 -0
  5. package/chart-card/index.js +36 -0
  6. package/chart-summary/data-table-chart.d.ts +8 -0
  7. package/chart-summary/data-table-chart.js +84 -0
  8. package/chart-summary/index.d.ts +10 -0
  9. package/chart-summary/index.js +83 -0
  10. package/common/chart.d.ts +24 -0
  11. package/common/chart.js +2 -0
  12. package/compare-aggregate/compare-aggregate.d.ts +19 -0
  13. package/compare-aggregate/compare-aggregate.js +40 -0
  14. package/compare-aggregate/index.d.ts +2 -0
  15. package/compare-aggregate/index.js +5 -0
  16. package/custom-color-status-dot.d.ts +12 -0
  17. package/custom-color-status-dot.js +17 -0
  18. package/delta/delta.d.ts +18 -0
  19. package/delta/delta.js +99 -0
  20. package/delta/index.d.ts +2 -0
  21. package/delta/index.js +6 -0
  22. package/donut-chart/center.d.ts +8 -0
  23. package/donut-chart/center.js +61 -0
  24. package/donut-chart/decoupled-legend.d.ts +9 -0
  25. package/donut-chart/decoupled-legend.js +72 -0
  26. package/donut-chart/index.d.ts +12 -0
  27. package/donut-chart/index.js +82 -0
  28. package/esm/bar-chart/index.js +85 -0
  29. package/esm/chart-card/index.js +9 -0
  30. package/esm/chart-summary/data-table-chart.js +54 -0
  31. package/esm/chart-summary/index.js +56 -0
  32. package/esm/common/chart.js +1 -0
  33. package/esm/compare-aggregate/compare-aggregate.js +13 -0
  34. package/esm/compare-aggregate/index.js +1 -0
  35. package/esm/custom-color-status-dot.js +15 -0
  36. package/esm/delta/delta.js +71 -0
  37. package/esm/delta/index.js +1 -0
  38. package/esm/donut-chart/center.js +36 -0
  39. package/esm/donut-chart/decoupled-legend.js +44 -0
  40. package/esm/donut-chart/index.js +52 -0
  41. package/esm/helpers/dataSampleFactory.js +55 -0
  42. package/esm/helpers/format-number.js +30 -0
  43. package/esm/index.js +10 -0
  44. package/esm/line-chart/custom-active-dot.js +19 -0
  45. package/esm/line-chart/custom-tooltip.js +20 -0
  46. package/esm/line-chart/index.js +65 -0
  47. package/esm/scorecard/index.js +12 -0
  48. package/esm/styles.js +37 -0
  49. package/esm/theme.js +22 -0
  50. package/helpers/dataSampleFactory.d.ts +1 -0
  51. package/helpers/dataSampleFactory.js +59 -0
  52. package/helpers/format-number.d.ts +7 -0
  53. package/helpers/format-number.js +39 -0
  54. package/index.d.ts +10 -0
  55. package/index.js +26 -0
  56. package/line-chart/custom-active-dot.d.ts +4 -0
  57. package/line-chart/custom-active-dot.js +44 -0
  58. package/line-chart/custom-tooltip.d.ts +6 -0
  59. package/line-chart/custom-tooltip.js +48 -0
  60. package/line-chart/index.d.ts +6 -0
  61. package/line-chart/index.js +95 -0
  62. package/package.json +49 -0
  63. package/scorecard/index.d.ts +7 -0
  64. package/scorecard/index.js +39 -0
  65. package/styles.d.ts +8 -0
  66. package/styles.js +43 -0
  67. package/theme.d.ts +3 -0
  68. package/theme.js +27 -0
@@ -0,0 +1,15 @@
1
+ import { get } from 'lodash';
2
+ import { rootShouldForwardProp, StatusDot, statusDotClasses, styled } from '@auth0/quantum-product';
3
+ var CustomColorStatusDot = styled(StatusDot, {
4
+ shouldForwardProp: function (prop) { return rootShouldForwardProp(prop) && prop !== 'dotColor'; },
5
+ })(function (_a) {
6
+ var _b;
7
+ var theme = _a.theme, dotColor = _a.dotColor;
8
+ var backgroundColor = get(theme.palette, dotColor, dotColor);
9
+ return _b = {},
10
+ _b["& .".concat(statusDotClasses.dot)] = {
11
+ backgroundColor: typeof backgroundColor === 'object' ? backgroundColor[500] : backgroundColor,
12
+ },
13
+ _b;
14
+ });
15
+ export default CustomColorStatusDot;
@@ -0,0 +1,71 @@
1
+ import * as React from 'react';
2
+ import { inRange } from 'lodash';
3
+ import { toPercentage, toPercentageAdaptive } from '../helpers/format-number';
4
+ import { Label } from '@auth0/quantum-product';
5
+ var deltaFromAggregates = function (displayType, value, comparedValue) {
6
+ /*
7
+ - When absolute, (50 becoming 75) is 1.5 (meaning 150%, which is +50% when displayed)
8
+ - When percent, (0.50 becoming 0.75) is 0.25 (meaning +25%)
9
+ This function returns the 1.5 and 0.25 of those examples.
10
+ Note that when dealing with percentages we use `static percentage`,
11
+ but when dealing with absolutes we use `relative percentage`.
12
+ */
13
+ return displayType === 'percent' ? value - comparedValue : value / comparedValue;
14
+ };
15
+ var isDeltaUp = function (displayType, delta) {
16
+ return Number.isNaN(delta) || delta > (displayType === 'percent' ? 0 : 1);
17
+ };
18
+ var cleanUpDelta = function (displayType, deltaIsUp, delta) {
19
+ if (displayType === 'percent') {
20
+ return delta;
21
+ }
22
+ /*
23
+ Following up on our example in deltaFromAggregates:
24
+ - When absolute, (50 becoming 75) is 1.5 (meaning 150%, which is +50% when displayed)
25
+ - When percent, (0.50 becoming 0.75) is 0.25 (meaning +25%)
26
+ Since the logic for finding the delta of and absolute metric includes a division,
27
+ we need to be prepared for NaN and infinite values.
28
+ If it's NaN or infinite, we fallback to some reasonnable defaults:
29
+ - NaN is 0%
30
+ - Infinite -> -100% or +100% depending on whether deltaIsUp
31
+ For all other happy-path cases, we want to go from this 150% result to +50% displayed value,
32
+ so we add or remove 100% to adjust properly:
33
+ - 150% is up so we remove 100%, which gives us our 50%
34
+ - 75% is down so we remove it from 100%, which gives us our 25%.
35
+ The + or - symbol is handled later, we don't need to care about it here.
36
+ */
37
+ var adjustedDelta = deltaIsUp ? delta - 1 : 1 - delta;
38
+ if (Number.isNaN(adjustedDelta)) {
39
+ return 0;
40
+ }
41
+ if (Number.isFinite(adjustedDelta)) {
42
+ return adjustedDelta;
43
+ }
44
+ return deltaIsUp ? 1 : -1;
45
+ };
46
+ var hasNoSignificantChanges = function (aggregate, comparedAggregate) {
47
+ return (aggregate === comparedAggregate ||
48
+ inRange(aggregate, comparedAggregate - 0.001 * comparedAggregate, comparedAggregate + 0.001 * comparedAggregate));
49
+ };
50
+ var findEmphasis = function (direction, deltaIsUp, noSignificantChanges) {
51
+ if (direction === 'neutral' || noSignificantChanges) {
52
+ return 'neutral';
53
+ }
54
+ return (deltaIsUp && direction === 'upIsGood') || (!deltaIsUp && direction === 'upIsBad') ? 'good' : 'bad';
55
+ };
56
+ export var computeDelta = function (props) {
57
+ var displayType = props.displayType, value = props.value, comparedValue = props.comparedValue;
58
+ var delta = deltaFromAggregates(displayType, value, comparedValue);
59
+ var deltaIsUp = isDeltaUp(displayType, delta);
60
+ var usableDelta = cleanUpDelta(displayType, deltaIsUp, delta);
61
+ var noSignificantChanges = hasNoSignificantChanges(value, comparedValue);
62
+ var emphasis = findEmphasis(props.direction, deltaIsUp, noSignificantChanges);
63
+ var symbol = noSignificantChanges ? '' : deltaIsUp ? '+' : '-';
64
+ var percentFormatter = props.useAdaptivePercentage ? toPercentageAdaptive : toPercentage;
65
+ var finalDelta = symbol + percentFormatter(Math.abs(usableDelta));
66
+ return { emphasis: emphasis, delta: finalDelta };
67
+ };
68
+ export var Delta = function (props) {
69
+ var delta = computeDelta(props).delta;
70
+ return (React.createElement(Label, { color: props.direction === 'upIsGood' ? 'success' : props.direction === 'upIsBad' ? 'danger' : 'default' }, delta));
71
+ };
@@ -0,0 +1 @@
1
+ export { Delta, computeDelta } from './delta';
@@ -0,0 +1,36 @@
1
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
2
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
3
+ return cooked;
4
+ };
5
+ import * as React from 'react';
6
+ import { Box, styled } from '@auth0/quantum-product';
7
+ import { toPercentageAdaptive, toShortCompactNotation } from '../helpers/format-number';
8
+ var sumValues = function (data) {
9
+ return data.reduce(function (accum, item) { return accum + item.value; }, 0);
10
+ };
11
+ var findAggregate = function (data, isTotal, activeIndex) { var _a; return (isTotal ? sumValues(data) : (_a = data === null || data === void 0 ? void 0 : data[activeIndex]) === null || _a === void 0 ? void 0 : _a.value); };
12
+ var Aggregate = styled('h4')(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n font-weight: ", ";\n font-size: ", ";\n"], ["\n font-weight: ", ";\n font-size: ", ";\n"])), function (_a) {
13
+ var theme = _a.theme;
14
+ return theme.typography.fontWeightRegular;
15
+ }, function (_a) {
16
+ var theme = _a.theme;
17
+ return theme.typography.h4.fontSize;
18
+ });
19
+ var CenterPositioning = styled(Box)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n display: grid;\n place-items: center;\n height: 100%;\n text-align: center;\n"], ["\n display: grid;\n place-items: center;\n height: 100%;\n text-align: center;\n"])));
20
+ var Center = function (props) {
21
+ var activeIndex = props.activeIndex, data = props.data, displayType = props.displayType;
22
+ var hasNoData = data.length === 0;
23
+ var aggregate = findAggregate(data, activeIndex === undefined, activeIndex);
24
+ var percentage = function (partialValue, totalValue) {
25
+ return (100 * partialValue) / totalValue;
26
+ };
27
+ return (React.createElement(CenterPositioning, null,
28
+ React.createElement(Box, null,
29
+ React.createElement(Aggregate, null, hasNoData
30
+ ? 'No data'
31
+ : displayType === 'absolute'
32
+ ? toShortCompactNotation(aggregate)
33
+ : toPercentageAdaptive(percentage(aggregate, sumValues(data)) / 100)))));
34
+ };
35
+ export default Center;
36
+ var templateObject_1, templateObject_2;
@@ -0,0 +1,44 @@
1
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
2
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
3
+ return cooked;
4
+ };
5
+ import * as React from 'react';
6
+ import styled from 'styled-components';
7
+ import { StackLayout, StackLayoutItem, useTheme } from '@auth0/quantum-product';
8
+ import { getBaseColorScale } from '../theme';
9
+ function DecoupledLegend(props) {
10
+ var data = props.data, activeIndex = props.activeIndex, setActiveIndex = props.setActiveIndex;
11
+ var theme = useTheme();
12
+ var BASE_COLORS = getBaseColorScale(theme);
13
+ return (React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: '8px', height: '150px', flexWrap: 'wrap' } }, data.map(function (datum, index) {
14
+ var isActive = activeIndex !== undefined && activeIndex === index;
15
+ var color = BASE_COLORS[index % BASE_COLORS.length];
16
+ return (React.createElement(React.Fragment, { key: index },
17
+ React.createElement(StackLayout, { gutter: 1, onMouseEnter: function () {
18
+ setActiveIndex(index);
19
+ }, onMouseLeave: function () {
20
+ setActiveIndex(undefined);
21
+ }, sx: {
22
+ flexWrap: 'nowrap',
23
+ } },
24
+ React.createElement(StackLayoutItem, { sx: {
25
+ alignSelf: 'center',
26
+ } },
27
+ React.createElement(LegendDotWrapper, { style: {
28
+ border: '2px solid ' + (isActive ? color : 'white'),
29
+ } },
30
+ React.createElement(LegendDot, { style: { backgroundColor: color } }))),
31
+ React.createElement(StackLayoutItem, { sx: {
32
+ alignSelf: 'center',
33
+ } },
34
+ React.createElement(LegendText, { color: isActive ? 'primary' : 'secondary' }, datum.name)))));
35
+ })));
36
+ }
37
+ var LegendDot = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n height: 12px;\n width: 12px;\n border: 2px solid white;\n border-radius: 2px;\n"], ["\n height: 12px;\n width: 12px;\n border: 2px solid white;\n border-radius: 2px;\n"])));
38
+ var LegendDotWrapper = styled.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n border-radius: 4px;\n"], ["\n border-radius: 4px;\n"])));
39
+ var LegendText = styled.span(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n color: ", ";\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: default;\n"], ["\n color: ", ";\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: default;\n"])), function (_a) {
40
+ var theme = _a.theme, color = _a.color;
41
+ return theme.palette.text[color !== null && color !== void 0 ? color : 'secondary'];
42
+ });
43
+ export default DecoupledLegend;
44
+ var templateObject_1, templateObject_2, templateObject_3;
@@ -0,0 +1,52 @@
1
+ var __read = (this && this.__read) || function (o, n) {
2
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
3
+ if (!m) return o;
4
+ var i = m.call(o), r, ar = [], e;
5
+ try {
6
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
7
+ }
8
+ catch (error) { e = { error: error }; }
9
+ finally {
10
+ try {
11
+ if (r && !r.done && (m = i["return"])) m.call(i);
12
+ }
13
+ finally { if (e) throw e.error; }
14
+ }
15
+ return ar;
16
+ };
17
+ import * as React from 'react';
18
+ import { Cell, Pie, PieChart as RechartsPieChart, ResponsiveContainer } from 'recharts';
19
+ import { StackLayout, StackLayoutItem, useTheme } from '@auth0/quantum-product';
20
+ import { getBaseColorScale } from '../theme';
21
+ import Center from './center';
22
+ import DecoupledLegend from './decoupled-legend';
23
+ import { ChartCard } from '../chart-card';
24
+ export function DonutChart(props) {
25
+ var data = props.data, displayType = props.displayType, title = props.title, value = props.value, label = props.label, helperText = props.helperText;
26
+ var _a = __read(React.useState(undefined), 2), activeIndex = _a[0], setActiveIndex = _a[1];
27
+ var theme = useTheme();
28
+ var BASE_COLORS = getBaseColorScale(theme);
29
+ return (React.createElement(ChartCard, { title: title, value: value, dataTable: data, label: label, helperText: helperText },
30
+ React.createElement(StackLayout, { sx: {
31
+ height: '150px',
32
+ flexWrap: 'nowrap',
33
+ mt: '24px',
34
+ } },
35
+ React.createElement(StackLayoutItem, { sx: {
36
+ height: '150px',
37
+ width: '150px',
38
+ } },
39
+ React.createElement(ResponsiveContainer, { width: '100%', height: 150 },
40
+ React.createElement(RechartsPieChart, { height: 150, width: 150 },
41
+ React.createElement("foreignObject", { x: 0, y: 0, width: '100%', height: '100%' },
42
+ React.createElement(Center, { activeIndex: activeIndex, data: data, displayType: displayType })),
43
+ React.createElement(Pie, { dataKey: 'value', data: data, innerRadius: 55, outerRadius: 75, paddingAngle: 2, animationDuration: 750, animationBegin: 0, activeIndex: activeIndex, onMouseEnter: function (_, index) {
44
+ setActiveIndex(index);
45
+ }, onMouseLeave: function () {
46
+ setActiveIndex(undefined);
47
+ } }, data.map(function (_, index) {
48
+ return (React.createElement(Cell, { key: "cell-".concat(index), fill: BASE_COLORS[index % BASE_COLORS.length], opacity: activeIndex === undefined ? 1 : activeIndex === index ? 1 : 0.5 }));
49
+ }))))),
50
+ React.createElement(StackLayoutItem, null,
51
+ React.createElement(DecoupledLegend, { activeIndex: activeIndex, setActiveIndex: setActiveIndex, data: data })))));
52
+ }
@@ -0,0 +1,55 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __read = (this && this.__read) || function (o, n) {
13
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
14
+ if (!m) return o;
15
+ var i = m.call(o), r, ar = [], e;
16
+ try {
17
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
18
+ }
19
+ catch (error) { e = { error: error }; }
20
+ finally {
21
+ try {
22
+ if (r && !r.done && (m = i["return"])) m.call(i);
23
+ }
24
+ finally { if (e) throw e.error; }
25
+ }
26
+ return ar;
27
+ };
28
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
29
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
30
+ if (ar || !(i in from)) {
31
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
32
+ ar[i] = from[i];
33
+ }
34
+ }
35
+ return to.concat(ar || Array.prototype.slice.call(from));
36
+ };
37
+ export var dataSampleFactory = function (numberOfGroups, numberOfTicks) {
38
+ var count = numberOfTicks;
39
+ var precision = 60 * 60 * 24 * 30.4;
40
+ var dates = Array.from(Array(count).keys()).map(function (x) { return ({
41
+ date: new Date(1412969747858 - precision * x * 1000), // only last timestamp is constant, generate toward past
42
+ }); });
43
+ var groups = ['y1', 'y2', 'y3', 'y4', 'y5'];
44
+ var graphs = [];
45
+ var _loop_1 = function (index) {
46
+ var graph = dates.map(function (x) {
47
+ return __assign(__assign({}, x), { group: groups[index], value: Math.ceil(Math.random() * 100 + 100) });
48
+ });
49
+ graphs.push.apply(graphs, __spreadArray([], __read(graph), false));
50
+ };
51
+ for (var index = 0; index < numberOfGroups; index++) {
52
+ _loop_1(index);
53
+ }
54
+ return graphs;
55
+ };
@@ -0,0 +1,30 @@
1
+ /*
2
+ If you're unclear about which to use, take a look at the tests
3
+ and see if something fits the kind of formating you're looking for!
4
+
5
+ The shortCompactNotation uses ES2020 and is not yet available everywhere,
6
+ so we have to use "@formatjs/intl's polyfill or build it ourselve.
7
+ Since the raw Intl is assumed faster (being native and all),
8
+ things that do not require the polyfill should use it (percent, longForm, etc.)
9
+ */
10
+ import { createIntl, createIntlCache } from '@formatjs/intl';
11
+ var percent = Intl.NumberFormat('en-US', { style: 'percent' });
12
+ var percentTwoDecimals = Intl.NumberFormat('en-US', {
13
+ style: 'percent',
14
+ minimumFractionDigits: 2,
15
+ maximumFractionDigits: 2,
16
+ });
17
+ export var toPercentage = function (s) { return percent.format(s); };
18
+ export var toPercentageAdaptive = function (s) {
19
+ var n = Math.abs(s);
20
+ return n > 0.1 || n < 0.00005 ? toPercentage(s) : percentTwoDecimals.format(s);
21
+ };
22
+ var longForm = Intl.NumberFormat('en-US');
23
+ export var toLongForm = function (s) { return longForm.format(s); };
24
+ export var toLongFormRounded = function (s) { return toLongForm(Math.round(s)); };
25
+ var cache = createIntlCache();
26
+ export var polyfill = createIntl({ locale: 'en-US' }, cache);
27
+ export var toShortCompactNotation = function (s) {
28
+ return polyfill.formatNumber(s, { notation: 'compact', compactDisplay: 'short' });
29
+ };
30
+ export var toBasicNotation = function (s) { return polyfill.formatNumber(s); };
package/esm/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export * from './bar-chart';
2
+ export * from './chart-card';
3
+ export * from './chart-summary';
4
+ export * from './common/chart';
5
+ export * from './compare-aggregate';
6
+ export * from './donut-chart';
7
+ export * from './helpers/format-number';
8
+ export * from './line-chart';
9
+ export * from './scorecard';
10
+ export * from './delta';
@@ -0,0 +1,19 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import * as React from 'react';
13
+ import { Dot } from 'recharts';
14
+ var CustomActiveDot = function (onMouseOver) { return function (props) {
15
+ return (React.createElement(React.Fragment, null,
16
+ React.createElement(Dot, __assign({}, props, { key: "outerDot", r: 10, strokeWidth: 0 }, (onMouseOver ? { onMouseOver: onMouseOver } : {}))),
17
+ React.createElement(Dot, __assign({}, props, { key: "innerDot", r: 4, style: { fill: 'white' } }, (onMouseOver ? { onMouseOver: onMouseOver } : {})))));
18
+ }; };
19
+ export default CustomActiveDot;
@@ -0,0 +1,20 @@
1
+ import * as React from 'react';
2
+ import { Box, RowLayout } from '@auth0/quantum-product';
3
+ import StatusDot from '../custom-color-status-dot';
4
+ import { format } from 'date-fns';
5
+ import { CustomTooltip as CustomTooltipStyled, CustomTooltipLabel } from '../styles';
6
+ // -------------------------------- Component --------------------------------
7
+ var CustomTooltip = function (_a) {
8
+ var _b;
9
+ var active = _a.active, payload = _a.payload;
10
+ if (!active || !payload.length) {
11
+ return null;
12
+ }
13
+ return (React.createElement(CustomTooltipStyled, null,
14
+ React.createElement(CustomTooltipLabel, null, "".concat(format(new Date(payload && ((_b = payload[0].payload) === null || _b === void 0 ? void 0 : _b.date)), 'LLL d p'))),
15
+ React.createElement(Box, null,
16
+ React.createElement(RowLayout, { gutter: 1 }, payload.map(function (x, index) {
17
+ return React.createElement(StatusDot, { key: index, dotColor: 'grey', label: "".concat(x.name, ": ").concat(x.payload[x.name]) });
18
+ })))));
19
+ };
20
+ export default CustomTooltip;
@@ -0,0 +1,65 @@
1
+ import _ from 'lodash';
2
+ import * as React from 'react';
3
+ import { CartesianGrid, Legend, Line, LineChart as RechartsLineChart, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts';
4
+ import { format } from 'date-fns';
5
+ import { useTheme, Text } from '@auth0/quantum-product';
6
+ import { getBaseColorScale } from '../theme';
7
+ import CustomActiveDot from './custom-active-dot';
8
+ import CustomTooltip from './custom-tooltip';
9
+ import { ChartCard } from '../chart-card';
10
+ export function LineChart(props) {
11
+ var _a = props, data = _a.data, leftAxis = _a.leftAxis, bottomAxis = _a.bottomAxis, _b = _a.height, height = _b === void 0 ? 300 : _b, title = _a.title, value = _a.value, label = _a.label, helperText = _a.helperText, _c = _a.legend, legend = _c === void 0 ? true : _c, syncId = _a.syncId;
12
+ var theme = useTheme();
13
+ // Function to know how many lines we need based of how much different group values are.
14
+ var groups = _.uniqBy(data, 'group').map(function (item) { return item.group; });
15
+ var bottomAxisDataKey = bottomAxis.mapsTo || 'date';
16
+ var leftAxisDataKey = leftAxis.mapsTo || 'value';
17
+ var entries = {};
18
+ data.forEach(function (entry) {
19
+ var _a, _b;
20
+ var entrytKey = entry[bottomAxisDataKey];
21
+ if (entries[entrytKey]) {
22
+ entries[entrytKey][entry.group] = entry[leftAxisDataKey];
23
+ }
24
+ else {
25
+ entries[entrytKey] = (_a = {},
26
+ _a[bottomAxisDataKey] = entry[bottomAxisDataKey],
27
+ _a[entry.group] = entry[leftAxisDataKey],
28
+ _a);
29
+ }
30
+ return _b = {},
31
+ _b[bottomAxisDataKey] = entry[bottomAxisDataKey],
32
+ _b[entry.group] = entry[leftAxisDataKey],
33
+ _b;
34
+ });
35
+ var formatBottomTick = function (value) {
36
+ if (bottomAxis.scaleType === 'date') {
37
+ return format(new Date(value), 'LLL d');
38
+ }
39
+ if (bottomAxis.scaleType === 'datetime') {
40
+ return format(new Date(value), 'LLL d p');
41
+ }
42
+ return value;
43
+ };
44
+ return (React.createElement(ChartCard, { title: title, value: value, dataTable: data, label: label, helperText: helperText },
45
+ React.createElement(ResponsiveContainer, { width: '100%', height: height }, data.length ? (React.createElement(RechartsLineChart, { data: Object.values(entries), height: height, width: 500, syncId: syncId, margin: {
46
+ top: 24,
47
+ right: 10,
48
+ left: -24,
49
+ bottom: 0,
50
+ } },
51
+ React.createElement(XAxis, { tickFormatter: formatBottomTick, dataKey: bottomAxisDataKey, height: 30, interval: "preserveStartEnd" }),
52
+ React.createElement(CartesianGrid, { vertical: false, stroke: theme.tokens.color_border_default }),
53
+ React.createElement(YAxis, { domain: ['auto', 'auto'] }),
54
+ React.createElement(Tooltip, { content: React.createElement(CustomTooltip, { active: undefined, payload: undefined }) }),
55
+ legend && React.createElement(Legend, { align: "center", iconType: "square", iconSize: 14, wrapperStyle: { paddingTop: 16 } }),
56
+ groups.map(function (group, index) {
57
+ return (React.createElement(Line, { key: group, dataKey: group, name: group, strokeWidth: 3, stroke: getBaseColorScale(theme)[index], dot: false, activeDot: CustomActiveDot() }));
58
+ }))) : (React.createElement("div", { style: {
59
+ display: 'grid',
60
+ placeItems: 'center',
61
+ height: '100%',
62
+ textAlign: 'center',
63
+ } },
64
+ React.createElement(Text, { variant: "subtitle1" }, "No data"))))));
65
+ }
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import { ChartSummary } from '../chart-summary';
3
+ import { ChartCard } from '../chart-card';
4
+ import { GalleryLayout, GalleryLayoutItem } from '@auth0/quantum-product';
5
+ export function ScoreCard(props) {
6
+ var data = props.data;
7
+ return (React.createElement(ChartCard, null,
8
+ React.createElement(GalleryLayout, null, data.map(function (summary, index) {
9
+ return (React.createElement(GalleryLayoutItem, { key: index },
10
+ React.createElement(ChartSummary, { title: summary.title, value: summary.value, helperText: summary.helperText, label: summary.label })));
11
+ }))));
12
+ }
package/esm/styles.js ADDED
@@ -0,0 +1,37 @@
1
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
2
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
3
+ return cooked;
4
+ };
5
+ import styled from 'styled-components';
6
+ import { Box } from '@auth0/quantum-product';
7
+ export var ChartContainer = styled.div(function (_a) {
8
+ var theme = _a.theme, height = _a.height, marginTop = _a.marginTop;
9
+ var props = {
10
+ marginTop: theme.spacing(3),
11
+ height: 'initial',
12
+ };
13
+ if (height !== 'initial') {
14
+ props.height = "".concat(height !== null && height !== void 0 ? height : 220, "px");
15
+ }
16
+ if (marginTop !== undefined) {
17
+ props.marginTop = "".concat(marginTop, "px");
18
+ }
19
+ return props;
20
+ });
21
+ export var CustomTooltip = styled.div(function (_a) {
22
+ var theme = _a.theme;
23
+ return ({
24
+ backgroundColor: theme.tokens.color_bg_layer_boldest,
25
+ borderRadius: theme.shape.borderRadius,
26
+ padding: theme.spacing(1, 3),
27
+ color: theme.tokens.color_fg_inverse,
28
+ fontSize: theme.typography.caption.fontSize,
29
+ fontWeight: theme.typography.caption.fontWeight,
30
+ lineHeight: theme.typography.caption.lineHeight,
31
+ letterSpacing: theme.typography.caption.letterSpacing,
32
+ });
33
+ });
34
+ // `textSecondary` doesn't have enough contrast for the black background of the tooltip
35
+ export var CustomTooltipLabel = styled.span(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n color: lightgrey;\n"], ["\n color: lightgrey;\n"])));
36
+ export var DefaultCursorBox = styled(Box)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n cursor: default;\n"], ["\n cursor: default;\n"])));
37
+ var templateObject_1, templateObject_2;
package/esm/theme.js ADDED
@@ -0,0 +1,22 @@
1
+ export var getBaseColorScale = function (_a) {
2
+ var palette = _a.palette;
3
+ return [
4
+ palette.purple[500],
5
+ palette.magenta[500],
6
+ palette.green[500],
7
+ palette.yellow[500],
8
+ palette.red[500],
9
+ palette.neutral[500],
10
+ ];
11
+ };
12
+ export var getBaseColorScaleMuted = function (_a) {
13
+ var palette = _a.palette;
14
+ return [
15
+ palette.purple[300],
16
+ palette.yellow[300],
17
+ palette.green[300],
18
+ palette.red[300],
19
+ palette.neutral[300],
20
+ palette.magenta[300],
21
+ ];
22
+ };
@@ -0,0 +1 @@
1
+ export declare const dataSampleFactory: (numberOfGroups: any, numberOfTicks: any) => any;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __read = (this && this.__read) || function (o, n) {
14
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
15
+ if (!m) return o;
16
+ var i = m.call(o), r, ar = [], e;
17
+ try {
18
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
19
+ }
20
+ catch (error) { e = { error: error }; }
21
+ finally {
22
+ try {
23
+ if (r && !r.done && (m = i["return"])) m.call(i);
24
+ }
25
+ finally { if (e) throw e.error; }
26
+ }
27
+ return ar;
28
+ };
29
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
30
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
31
+ if (ar || !(i in from)) {
32
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
33
+ ar[i] = from[i];
34
+ }
35
+ }
36
+ return to.concat(ar || Array.prototype.slice.call(from));
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.dataSampleFactory = void 0;
40
+ var dataSampleFactory = function (numberOfGroups, numberOfTicks) {
41
+ var count = numberOfTicks;
42
+ var precision = 60 * 60 * 24 * 30.4;
43
+ var dates = Array.from(Array(count).keys()).map(function (x) { return ({
44
+ date: new Date(1412969747858 - precision * x * 1000), // only last timestamp is constant, generate toward past
45
+ }); });
46
+ var groups = ['y1', 'y2', 'y3', 'y4', 'y5'];
47
+ var graphs = [];
48
+ var _loop_1 = function (index) {
49
+ var graph = dates.map(function (x) {
50
+ return __assign(__assign({}, x), { group: groups[index], value: Math.ceil(Math.random() * 100 + 100) });
51
+ });
52
+ graphs.push.apply(graphs, __spreadArray([], __read(graph), false));
53
+ };
54
+ for (var index = 0; index < numberOfGroups; index++) {
55
+ _loop_1(index);
56
+ }
57
+ return graphs;
58
+ };
59
+ exports.dataSampleFactory = dataSampleFactory;
@@ -0,0 +1,7 @@
1
+ export declare const toPercentage: (s: number) => string;
2
+ export declare const toPercentageAdaptive: (s: number) => string;
3
+ export declare const toLongForm: (s: number) => string;
4
+ export declare const toLongFormRounded: (s: number) => string;
5
+ export declare const polyfill: import("@formatjs/intl").IntlShape<string>;
6
+ export declare const toShortCompactNotation: (s: number) => string;
7
+ export declare const toBasicNotation: (s: number) => string;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toBasicNotation = exports.toShortCompactNotation = exports.polyfill = exports.toLongFormRounded = exports.toLongForm = exports.toPercentageAdaptive = exports.toPercentage = void 0;
4
+ /*
5
+ If you're unclear about which to use, take a look at the tests
6
+ and see if something fits the kind of formating you're looking for!
7
+
8
+ The shortCompactNotation uses ES2020 and is not yet available everywhere,
9
+ so we have to use "@formatjs/intl's polyfill or build it ourselve.
10
+ Since the raw Intl is assumed faster (being native and all),
11
+ things that do not require the polyfill should use it (percent, longForm, etc.)
12
+ */
13
+ var intl_1 = require("@formatjs/intl");
14
+ var percent = Intl.NumberFormat('en-US', { style: 'percent' });
15
+ var percentTwoDecimals = Intl.NumberFormat('en-US', {
16
+ style: 'percent',
17
+ minimumFractionDigits: 2,
18
+ maximumFractionDigits: 2,
19
+ });
20
+ var toPercentage = function (s) { return percent.format(s); };
21
+ exports.toPercentage = toPercentage;
22
+ var toPercentageAdaptive = function (s) {
23
+ var n = Math.abs(s);
24
+ return n > 0.1 || n < 0.00005 ? (0, exports.toPercentage)(s) : percentTwoDecimals.format(s);
25
+ };
26
+ exports.toPercentageAdaptive = toPercentageAdaptive;
27
+ var longForm = Intl.NumberFormat('en-US');
28
+ var toLongForm = function (s) { return longForm.format(s); };
29
+ exports.toLongForm = toLongForm;
30
+ var toLongFormRounded = function (s) { return (0, exports.toLongForm)(Math.round(s)); };
31
+ exports.toLongFormRounded = toLongFormRounded;
32
+ var cache = (0, intl_1.createIntlCache)();
33
+ exports.polyfill = (0, intl_1.createIntl)({ locale: 'en-US' }, cache);
34
+ var toShortCompactNotation = function (s) {
35
+ return exports.polyfill.formatNumber(s, { notation: 'compact', compactDisplay: 'short' });
36
+ };
37
+ exports.toShortCompactNotation = toShortCompactNotation;
38
+ var toBasicNotation = function (s) { return exports.polyfill.formatNumber(s); };
39
+ exports.toBasicNotation = toBasicNotation;
package/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './bar-chart';
2
+ export * from './chart-card';
3
+ export * from './chart-summary';
4
+ export * from './common/chart';
5
+ export * from './compare-aggregate';
6
+ export * from './donut-chart';
7
+ export * from './helpers/format-number';
8
+ export * from './line-chart';
9
+ export * from './scorecard';
10
+ export * from './delta';