@bundle-stats/ui 4.2.5-beta.0 → 4.2.5-beta.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 (108) hide show
  1. package/globals.d.ts +4 -0
  2. package/lib/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js +7 -5
  3. package/lib/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js.map +1 -1
  4. package/lib/components/index.js +5 -3
  5. package/lib/components/index.js.map +1 -1
  6. package/lib/components/insight-icon/insight-icon.js.map +1 -1
  7. package/lib/components/insights/insights.js.map +1 -1
  8. package/lib/components/metric/index.js.map +1 -1
  9. package/lib/components/metric/metric.js +7 -64
  10. package/lib/components/metric/metric.js.map +1 -1
  11. package/lib/components/metric/metric.module.css +2 -2
  12. package/lib/components/metric-run-info/index.js +18 -0
  13. package/lib/components/metric-run-info/index.js.map +1 -0
  14. package/lib/components/metric-run-info/metric-run-info.js +59 -0
  15. package/lib/components/metric-run-info/metric-run-info.js.map +1 -0
  16. package/lib/components/metric-run-info/metric-run-info.module.css +18 -0
  17. package/lib/components/metrics-table-title/metrics-table-title.module.css +1 -0
  18. package/lib/components/{summary-item → run-info}/index.js +1 -1
  19. package/lib/components/run-info/index.js.map +1 -0
  20. package/lib/components/run-info/run-info.js +45 -0
  21. package/lib/components/run-info/run-info.js.map +1 -0
  22. package/lib/components/{summary-item/summary-item.module.css → run-info/run-info.module.css} +3 -20
  23. package/lib/components/summary/index.js.map +1 -1
  24. package/lib/components/summary/summary.js +10 -30
  25. package/lib/components/summary/summary.js.map +1 -1
  26. package/lib/components/summary/summary.module.css +19 -0
  27. package/lib/layout/box/box.js.map +1 -1
  28. package/lib/layout/flex-stack/flex-stack.js.map +1 -1
  29. package/lib/ui/container/container.js.map +1 -1
  30. package/lib/ui/tooltip/tooltip.js.map +1 -1
  31. package/lib-esm/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js +6 -6
  32. package/lib-esm/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js.map +1 -1
  33. package/lib-esm/components/index.js +2 -1
  34. package/lib-esm/components/index.js.map +1 -1
  35. package/lib-esm/components/insight-icon/insight-icon.js.map +1 -1
  36. package/lib-esm/components/insights/insights.js.map +1 -1
  37. package/lib-esm/components/metric/index.js.map +1 -1
  38. package/lib-esm/components/metric/metric.js +7 -41
  39. package/lib-esm/components/metric/metric.js.map +1 -1
  40. package/lib-esm/components/metric/metric.module.css +2 -2
  41. package/lib-esm/components/metric-run-info/index.js +2 -0
  42. package/lib-esm/components/metric-run-info/index.js.map +1 -0
  43. package/lib-esm/components/metric-run-info/metric-run-info.js +29 -0
  44. package/lib-esm/components/metric-run-info/metric-run-info.js.map +1 -0
  45. package/lib-esm/components/metric-run-info/metric-run-info.module.css +18 -0
  46. package/lib-esm/components/metrics-table-title/metrics-table-title.module.css +1 -0
  47. package/lib-esm/components/run-info/index.js +2 -0
  48. package/lib-esm/components/run-info/index.js.map +1 -0
  49. package/lib-esm/components/run-info/run-info.js +38 -0
  50. package/lib-esm/components/run-info/run-info.js.map +1 -0
  51. package/lib-esm/components/{summary-item/summary-item.module.css → run-info/run-info.module.css} +3 -20
  52. package/lib-esm/components/summary/index.js.map +1 -1
  53. package/lib-esm/components/summary/summary.js +9 -29
  54. package/lib-esm/components/summary/summary.js.map +1 -1
  55. package/lib-esm/components/summary/summary.module.css +19 -0
  56. package/lib-esm/layout/box/box.js.map +1 -1
  57. package/lib-esm/layout/flex-stack/flex-stack.js.map +1 -1
  58. package/lib-esm/ui/container/container.js.map +1 -1
  59. package/lib-esm/ui/tooltip/tooltip.js.map +1 -1
  60. package/package.json +10 -9
  61. package/src/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.jsx +18 -15
  62. package/src/components/index.js +2 -1
  63. package/src/components/insight-icon/insight-icon.tsx +0 -2
  64. package/src/components/insights/insights.tsx +0 -1
  65. package/src/components/metric/metric.module.css +2 -2
  66. package/src/components/metric/metric.stories.tsx +41 -0
  67. package/src/components/metric/metric.tsx +42 -0
  68. package/src/components/metric-run-info/index.ts +1 -0
  69. package/src/components/metric-run-info/metric-run-info.module.css +18 -0
  70. package/src/components/metric-run-info/metric-run-info.stories.tsx +33 -0
  71. package/src/components/metric-run-info/metric-run-info.tsx +67 -0
  72. package/src/components/metrics-table-title/metrics-table-title.module.css +1 -0
  73. package/src/components/run-info/index.ts +1 -0
  74. package/src/components/{summary-item/summary-item.module.css → run-info/run-info.module.css} +3 -20
  75. package/src/components/run-info/run-info.stories.tsx +49 -0
  76. package/src/components/run-info/run-info.tsx +100 -0
  77. package/src/components/summary/summary.module.css +19 -0
  78. package/src/components/summary/summary.stories.tsx +56 -0
  79. package/src/components/summary/summary.tsx +97 -0
  80. package/src/layout/box/box.tsx +0 -1
  81. package/src/layout/flex-stack/flex-stack.tsx +1 -2
  82. package/src/ui/container/container.tsx +0 -1
  83. package/src/ui/tooltip/tooltip.tsx +0 -1
  84. package/types/components/index.d.ts +2 -1
  85. package/types/components/metric/index.d.ts +1 -1
  86. package/types/components/metric/metric.d.ts +6 -32
  87. package/types/components/metric-run-info/index.d.ts +1 -0
  88. package/types/components/metric-run-info/metric-run-info.d.ts +12 -0
  89. package/types/components/run-info/index.d.ts +1 -0
  90. package/types/components/run-info/run-info.d.ts +14 -0
  91. package/types/components/summary/index.d.ts +1 -1
  92. package/types/components/summary/summary.d.ts +15 -36
  93. package/types/layout/flex-stack/flex-stack.d.ts +2 -1
  94. package/lib/components/summary-item/index.js.map +0 -1
  95. package/lib/components/summary-item/summary-item.js +0 -97
  96. package/lib/components/summary-item/summary-item.js.map +0 -1
  97. package/lib-esm/components/summary-item/index.js +0 -2
  98. package/lib-esm/components/summary-item/index.js.map +0 -1
  99. package/lib-esm/components/summary-item/summary-item.js +0 -67
  100. package/lib-esm/components/summary-item/summary-item.js.map +0 -1
  101. package/src/components/metric/metric.jsx +0 -63
  102. package/src/components/summary/summary.jsx +0 -74
  103. package/src/components/summary-item/index.js +0 -1
  104. package/src/components/summary-item/summary-item.jsx +0 -142
  105. package/types/components/summary-item/index.d.ts +0 -1
  106. package/types/components/summary-item/summary-item.d.ts +0 -40
  107. /package/src/components/metric/{index.js → index.ts} +0 -0
  108. /package/src/components/summary/{index.js → index.ts} +0 -0
@@ -3,7 +3,6 @@ import cx from 'classnames';
3
3
  import { InsightType } from '@bundle-stats/utils';
4
4
 
5
5
  import { Icon } from '../../ui/icon';
6
- // @ts-ignore
7
6
  import css from './insight-icon.module.css';
8
7
 
9
8
  const InsightTypeIconMap = new Map([
@@ -24,4 +23,3 @@ export const InsightIcon = (props: InsightIconProps) => {
24
23
 
25
24
  return <Icon glyph={glyph} className={rootClassName} />;
26
25
  };
27
-
@@ -5,7 +5,6 @@ import { FlexStack } from '../../layout/flex-stack';
5
5
  import { Stack } from '../../layout/stack';
6
6
  import { ComponentLink } from '../component-link';
7
7
  import { InsightIcon } from '../insight-icon';
8
- // @ts-ignore
9
8
  import css from './insights.module.css';
10
9
 
11
10
  interface InsightsProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -6,7 +6,7 @@
6
6
  font-size: var(--size-small);
7
7
  }
8
8
 
9
- .delta {
9
+ .content {
10
10
  font-size: var(--size-small);
11
11
  }
12
12
 
@@ -14,7 +14,7 @@
14
14
  display: inline-block;
15
15
  }
16
16
 
17
- .inline .delta {
17
+ .inline .content {
18
18
  display: inline-block;
19
19
  margin: 0 0 0 var(--space-xxxsmall);
20
20
  }
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { Meta, Story } from '@storybook/react';
3
+
4
+ import { getWrapperDecorator } from '../../stories';
5
+ import { Delta } from '../delta';
6
+ import { Metric } from '.';
7
+
8
+ export default {
9
+ title: 'Components/Metric',
10
+ component: Metric,
11
+ decorators: [getWrapperDecorator({ maxWidth: '200px' })],
12
+ } as Meta;
13
+
14
+ const Template: Story = (args) => <Metric {...args} />;
15
+
16
+ export const Default = Template.bind({});
17
+
18
+ Default.args = {
19
+ value: '100',
20
+ };
21
+
22
+ export const WithUnit = Template.bind({});
23
+
24
+ WithUnit.args = {
25
+ value: '100',
26
+ unit: 'KiB',
27
+ };
28
+
29
+ export const WithDelta = Template.bind({});
30
+
31
+ WithDelta.args = {
32
+ ...WithUnit.args,
33
+ children: <Delta displayValue="+10%" deltaType="POSITIVE" />,
34
+ };
35
+
36
+ export const Inline = Template.bind({});
37
+
38
+ Inline.args = {
39
+ ...WithDelta.args,
40
+ inline: true,
41
+ };
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import cx from 'classnames';
3
+
4
+ import css from './metric.module.css';
5
+
6
+ export interface MetricProps {
7
+ /**
8
+ * Metric value
9
+ */
10
+ value?: string;
11
+ /**
12
+ * Metric value unit
13
+ */
14
+ unit?: string;
15
+ /**
16
+ * Inline variant - render children inline
17
+ */
18
+ inline?: boolean;
19
+ }
20
+
21
+ export const Metric = (props: MetricProps & React.ComponentProps<'div'>) => {
22
+ const {
23
+ className = '',
24
+ value = '0',
25
+ unit = '',
26
+ inline = false,
27
+ children = null,
28
+ ...restProps
29
+ } = props;
30
+
31
+ const rootClassName = cx(className, css.root, inline && css.inline);
32
+
33
+ return (
34
+ <div className={rootClassName} {...restProps}>
35
+ <div className={css.display}>
36
+ <span className={css.displayValue}>{value}</span>
37
+ {unit && <span className={css.displayUnit}>{unit}</span>}
38
+ </div>
39
+ {children && <div className={css.content}>{children}</div>}
40
+ </div>
41
+ );
42
+ };
@@ -0,0 +1 @@
1
+ export * from './metric-run-info';
@@ -0,0 +1,18 @@
1
+ .readMoreLink {
2
+ appearance: none;
3
+ background: none;
4
+ margin: 0;
5
+ border: 0;
6
+ padding: 0;
7
+ color: var(--color-primary);
8
+ text-decoration: underline;
9
+ cursor: pointer;
10
+ }
11
+
12
+ .readMoreLink:hover,
13
+ .readMoreLink:active,
14
+ .readMoreLink:focus {
15
+ color: var(--color-primary-dark);
16
+ text-decoration: none;
17
+ }
18
+
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+
3
+ import { Meta, Story } from '@storybook/react';
4
+ import { MetricRunInfo } from '.';
5
+
6
+ export default {
7
+ title: 'Components/MetricRunInfo',
8
+ component: MetricRunInfo,
9
+ } as Meta;
10
+
11
+ const Template: Story = (args: any) => <MetricRunInfo {...args} />;
12
+
13
+ export const Default = Template.bind({});
14
+
15
+ Default.args = {
16
+ metricId: 'webpack.totalSizeByTypeALL',
17
+ current: 120 * 1024,
18
+ baseline: 100 * 1024,
19
+ };
20
+
21
+ export const NoBaseline = Template.bind({});
22
+
23
+ NoBaseline.args = {
24
+ metricId: 'webpack.totalSizeByTypeALL',
25
+ current: 120 * 1024,
26
+ };
27
+
28
+ export const NoDelta = Template.bind({});
29
+
30
+ NoDelta.args = {
31
+ ...Default.args,
32
+ showDelta: false,
33
+ };
@@ -0,0 +1,67 @@
1
+ import React, { useCallback } from 'react';
2
+ import { getGlobalMetricType, getMetricRunInfo } from '@bundle-stats/utils';
3
+
4
+ import { Stack } from '../../layout/stack';
5
+ import { RunInfo, RunInfoProps } from '../run-info';
6
+ import css from './metric-run-info.module.css';
7
+
8
+ interface MetricInfoProps {
9
+ description: string;
10
+ url?: string;
11
+ }
12
+
13
+ const MetricHoverCard = ({ description, url }: MetricInfoProps) => {
14
+ // The component parent can be rendered inside a link, use button to avoid using nested links
15
+ const onClick = useCallback(() => {
16
+ if (url) {
17
+ window.open(url);
18
+ }
19
+ }, [url]);
20
+
21
+ return (
22
+ <Stack space="xxxsmall">
23
+ <p>{description}</p>
24
+ {url && (
25
+ <p>
26
+ <button type="button" onClick={onClick} className={css.readMoreLink}>
27
+ Read more
28
+ </button>
29
+ </p>
30
+ )}
31
+ </Stack>
32
+ );
33
+ };
34
+
35
+ export interface MetricRunInfoProps {
36
+ metricId: string;
37
+ current: number;
38
+ baseline?: number;
39
+ showDelta?: boolean;
40
+ showMetridDescription?: boolean;
41
+ size?: RunInfoProps['size'];
42
+ loading?: RunInfoProps['loading'];
43
+ }
44
+
45
+ export const MetricRunInfo = (props: MetricRunInfoProps & React.ComponentProps<'div'>) => {
46
+ const { metricId, current, baseline = undefined, showDelta = true, showMetridDescription = true, ...restProps } = props;
47
+
48
+ const metric = getGlobalMetricType(metricId);
49
+ const metricRunInfo = getMetricRunInfo(metric, current, baseline || 0);
50
+ const showBaseline = typeof baseline !== 'undefined';
51
+
52
+ return (
53
+ <RunInfo
54
+ title={metric.label}
55
+ titleHoverCard={showMetridDescription && <MetricHoverCard description={metric.description} url={metric.url} />}
56
+ current={metricRunInfo.displayValue}
57
+ {...(showBaseline && {
58
+ baseline: metric.formatter(baseline),
59
+ })}
60
+ {...(showDelta && showBaseline && {
61
+ delta: metricRunInfo.displayDeltaPercentage,
62
+ deltaType: metricRunInfo.deltaType,
63
+ })}
64
+ {...restProps}
65
+ />
66
+ );
67
+ };
@@ -14,6 +14,7 @@
14
14
 
15
15
  .anchorIcon {
16
16
  display: block;
17
+ margin: -2px 0; /* compensate for the vertical space */
17
18
  }
18
19
 
19
20
  .info {
@@ -0,0 +1 @@
1
+ export * from './run-info';
@@ -7,13 +7,14 @@
7
7
  }
8
8
 
9
9
  .titleIcon {
10
+ flex: 0 0 var(--space-small);
10
11
  margin-top: -4px !important;
11
12
  margin-bottom: -4px !important;
12
13
  }
13
14
 
14
15
  .currentMetric {
15
16
  color: var(--color-heading);
16
- font-size: var(--size-large);
17
+ font-size: var(--size-xlarge);
17
18
  line-height: var(--line-height-heading);
18
19
  white-space: nowrap;
19
20
  font-weight: bold;
@@ -21,28 +22,10 @@
21
22
 
22
23
  .baselineMetric {
23
24
  color: var(--color-text-light);
24
- font-size: var(--size-small);
25
+ font-size: var(--size-medium);
25
26
  line-height: var(--line-height-heading);
26
27
  }
27
28
 
28
- .readMoreLink {
29
- appearance: none;
30
- background: none;
31
- margin: 0;
32
- border: 0;
33
- padding: 0;
34
- color: var(--color-primary);
35
- text-decoration: underline;
36
- cursor: pointer;
37
- }
38
-
39
- .readMoreLink:hover,
40
- .readMoreLink:active,
41
- .readMoreLink:focus {
42
- color: var(--color-primary-dark);
43
- text-decoration: none;
44
- }
45
-
46
29
  /* Loading state */
47
30
  .loading.currentMetric {
48
31
  width: 8em;
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import { Meta, Story } from '@storybook/react';
3
+
4
+ import { RunInfo } from './run-info';
5
+
6
+ export default {
7
+ title: 'Components/RunInfo',
8
+ component: RunInfo,
9
+ } as Meta;
10
+
11
+ const Template: Story = (args) => <RunInfo id="webpack.totalSizeByTypeALL" {...args} />;
12
+
13
+ export const Default = Template.bind({});
14
+
15
+ Default.args = {
16
+ title: 'Bundle Size',
17
+ current: '120KiB',
18
+ baseline: '100KiB',
19
+ delta: '+20%',
20
+ deltaType: 'HIGH_NEGATIVE',
21
+ };
22
+
23
+ export const SizeLarge = Template.bind({});
24
+
25
+ SizeLarge.args = {
26
+ ...Default.args,
27
+ size: 'large',
28
+ };
29
+
30
+ export const TitleHoverCard = Template.bind({});
31
+
32
+ TitleHoverCard.args = {
33
+ ...Default.args,
34
+ titleHoverCard: 'Info',
35
+ };
36
+
37
+ export const TitleTooltip = Template.bind({});
38
+
39
+ TitleTooltip.args = {
40
+ ...Default.args,
41
+ titleTooltip: 'Info',
42
+ };
43
+
44
+ export const Loading = Template.bind({});
45
+
46
+ Loading.args = {
47
+ title: 'Bundle Size',
48
+ loading: true,
49
+ };
@@ -0,0 +1,100 @@
1
+ import React from 'react';
2
+ import cx from 'classnames';
3
+
4
+ import { Icon } from '../../ui/icon';
5
+ import { HoverCard } from '../../ui/hover-card';
6
+ import { Tooltip } from '../../ui/tooltip';
7
+ import { Skeleton } from '../../ui/skeleton';
8
+ import { FlexStack } from '../../layout/flex-stack';
9
+ import { Stack } from '../../layout/stack';
10
+ import { Metric } from '../metric';
11
+ import { Delta } from '../delta';
12
+ import css from './run-info.module.css';
13
+
14
+ // Separate value and unit
15
+ const EXTRACT_VALUE_UNIT_PATTERN = /([\d|.|,| ]*)(\w*|%)$/;
16
+
17
+ const getMetricParams = (value: string) => {
18
+ const matches = value.match(EXTRACT_VALUE_UNIT_PATTERN);
19
+
20
+ if (!matches) {
21
+ return { value, unit: '' };
22
+ }
23
+
24
+ return {
25
+ value: matches[1],
26
+ unit: matches[2],
27
+ };
28
+ };
29
+
30
+ export interface RunInfoProps {
31
+ title?: string;
32
+ titleHoverCard?: React.ReactNode;
33
+ titleTooltip?: React.ReactNode;
34
+ current?: string;
35
+ baseline?: string;
36
+ delta?: string;
37
+ deltaType?: string;
38
+
39
+ as?: React.ElementType;
40
+ size?: 'medium' | 'large';
41
+
42
+ loading?: boolean;
43
+ }
44
+
45
+ export const RunInfo = ({
46
+ className = '',
47
+ title = '',
48
+ titleHoverCard = null,
49
+ titleTooltip = null,
50
+ current = '',
51
+ baseline = '',
52
+ delta = '',
53
+ deltaType = '',
54
+ as: Component = 'div',
55
+ size = 'medium',
56
+ loading = false,
57
+ ...restProps
58
+ }: RunInfoProps & React.ComponentProps<'div'>) => {
59
+ const metricParams = getMetricParams(current);
60
+ const rootClassName = cx(css.root, className, css[size], delta && css.showDelta);
61
+
62
+ return (
63
+ <Stack space="xxsmall" as={Component} className={rootClassName} {...restProps}>
64
+ {title && (
65
+ <FlexStack space="xxxsmall" alignItems="center" as="h3" className={css.title}>
66
+ <span>{title}</span>
67
+ {titleHoverCard && (
68
+ <HoverCard label={<Icon glyph={Icon.ICONS.HELP} />} className={css.titleIcon}>
69
+ {titleHoverCard}
70
+ </HoverCard>
71
+ )}
72
+ {titleTooltip && (
73
+ <Tooltip title={titleTooltip} className={css.titleIcon}>
74
+ <Icon glyph={Icon.ICONS.HELP} />
75
+ </Tooltip>
76
+ )}
77
+ </FlexStack>
78
+ )}
79
+
80
+ {!loading ? (
81
+ <Stack>
82
+ <Metric
83
+ className={css.currentMetric}
84
+ value={metricParams.value}
85
+ unit={metricParams.unit}
86
+ inline
87
+ >
88
+ {delta && <Delta className={css.delta} displayValue={delta} deltaType={deltaType} />}
89
+ </Metric>
90
+ <Metric className={css.baselineMetric} value={baseline} />
91
+ </Stack>
92
+ ) : (
93
+ <Stack>
94
+ <Skeleton as="p" className={cx(css.currentMetric, css.loading)} />
95
+ <Skeleton as="p" className={cx(css.baselineMetric, css.loading)} />
96
+ </Stack>
97
+ )}
98
+ </Stack>
99
+ );
100
+ };
@@ -7,3 +7,22 @@
7
7
  min-width: 16em;
8
8
  text-decoration: none;
9
9
  }
10
+
11
+ .readMoreLink {
12
+ appearance: none;
13
+ background: none;
14
+ margin: 0;
15
+ border: 0;
16
+ padding: 0;
17
+ color: var(--color-primary);
18
+ text-decoration: underline;
19
+ cursor: pointer;
20
+ }
21
+
22
+ .readMoreLink:hover,
23
+ .readMoreLink:active,
24
+ .readMoreLink:focus {
25
+ color: var(--color-primary-dark);
26
+ text-decoration: none;
27
+ }
28
+
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { Meta, Story } from '@storybook/react';
3
+ import { createJobs } from '@bundle-stats/utils';
4
+
5
+ import baselineData from '../../../__mocks__/webpack-stats.baseline.json';
6
+ import currentData from '../../../__mocks__/webpack-stats.current.json';
7
+ import { METRICS_WEBPACK_ASSETS } from '../../constants';
8
+ import { getWrapperDecorator } from '../../stories';
9
+ import { Summary } from '.';
10
+
11
+ const MULTIPLE_JOBS = createJobs([{ webpack: currentData }, { webpack: baselineData }]);
12
+
13
+ const SINGLE_JOB = createJobs([{ webpack: currentData }]);
14
+
15
+ export default {
16
+ title: 'Components/Summary',
17
+ component: Summary,
18
+ decorators: [getWrapperDecorator()],
19
+ } as Meta;
20
+
21
+ const Template: Story = (args) => <Summary {...args} />;
22
+
23
+ export const Default = Template.bind({});
24
+
25
+ Default.args = {
26
+ data: MULTIPLE_JOBS[0].summary,
27
+ };
28
+
29
+ export const CustomKeys = Template.bind({});
30
+
31
+ CustomKeys.args = {
32
+ keys: METRICS_WEBPACK_ASSETS,
33
+ data: MULTIPLE_JOBS[0].summary,
34
+ };
35
+
36
+ export const Loading = Template.bind({});
37
+
38
+ Loading.args = {
39
+ loading: true,
40
+ };
41
+
42
+ export const SingleRun = Template.bind({});
43
+
44
+ SingleRun.args = {
45
+ data: SINGLE_JOB[0].summary,
46
+ showSummaryItemDelta: false,
47
+ };
48
+
49
+ export const WithLink = Template.bind({});
50
+
51
+ WithLink.args = {
52
+ data: MULTIPLE_JOBS[0].summary,
53
+ summaryItemLink: (linkProps: React.ComponentProps<'button'>) => (
54
+ <button {...linkProps} type="button" onClick={() => alert(JSON.stringify(linkProps))} />
55
+ ),
56
+ };
@@ -0,0 +1,97 @@
1
+ import React, { useCallback } from 'react';
2
+ import cx from 'classnames';
3
+ import get from 'lodash/get';
4
+ import { METRIC_COMPONENT_LINKS } from '@bundle-stats/utils';
5
+
6
+ import { METRICS_WEBPACK_GENERAL } from '../../constants';
7
+ import { Box } from '../../layout/box';
8
+ import { FlexStack } from '../../layout/flex-stack';
9
+ import { ComponentLink } from '../component-link';
10
+ import { MetricRunInfo, MetricRunInfoProps } from '../metric-run-info';
11
+ import css from './summary.module.css';
12
+
13
+ interface SummaryItemData {
14
+ current: number;
15
+ baseline: number;
16
+ }
17
+
18
+ interface SummaryProps {
19
+ size?: MetricRunInfoProps['size'];
20
+ keys?: Array<string>;
21
+ data?: Record<string, SummaryItemData> | null;
22
+ loading?: boolean;
23
+ showSummaryItemDelta?: boolean;
24
+ summaryItemLink?: React.ElementType;
25
+ }
26
+
27
+ interface SummaryItemProps {
28
+ metricId: string;
29
+ data?: SummaryProps['data'];
30
+ summaryItemLink: SummaryProps['summaryItemLink'];
31
+ size: SummaryProps['size'];
32
+ loading: SummaryProps['loading'];
33
+ showSummaryItemDelta: SummaryProps['showSummaryItemDelta'];
34
+ }
35
+
36
+ const SummaryItem = (props: SummaryItemProps & React.ComponentProps<'div'>) => {
37
+ const {
38
+ className = '',
39
+ metricId,
40
+ data,
41
+ summaryItemLink: SummaryItemCustomLink,
42
+ size,
43
+ loading,
44
+ showSummaryItemDelta,
45
+ } = props;
46
+
47
+ const componentLink = METRIC_COMPONENT_LINKS.get(metricId);
48
+ const metricData = get(data, metricId, { current: 0, baseline: 0 });
49
+
50
+ return (
51
+ <Box
52
+ key={metricId}
53
+ outline
54
+ outlineHover
55
+ padding="small"
56
+ as={SummaryItemCustomLink}
57
+ {...componentLink?.link}
58
+ className={className}
59
+ >
60
+ <MetricRunInfo
61
+ metricId={metricId}
62
+ current={metricData.current}
63
+ baseline={metricData.baseline}
64
+ showDelta={showSummaryItemDelta && componentLink?.showDelta}
65
+ size={size}
66
+ loading={loading}
67
+ />
68
+ </Box>
69
+ );
70
+ };
71
+
72
+ export const Summary = ({
73
+ className = '',
74
+ size = 'medium',
75
+ keys = METRICS_WEBPACK_GENERAL,
76
+ data = null,
77
+ loading = false,
78
+ showSummaryItemDelta = true,
79
+ summaryItemLink = ComponentLink,
80
+ }: SummaryProps & React.ComponentProps<'div'>) => (
81
+ <Box className={cx(css.root, className)}>
82
+ <FlexStack space="small" className={css.items}>
83
+ {keys.map((metricId) => (
84
+ <SummaryItem
85
+ key={metricId}
86
+ className={css.item}
87
+ metricId={metricId}
88
+ data={data}
89
+ summaryItemLink={summaryItemLink}
90
+ size={size}
91
+ loading={loading}
92
+ showSummaryItemDelta={showSummaryItemDelta}
93
+ />
94
+ ))}
95
+ </FlexStack>
96
+ </Box>
97
+ );
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import cx from 'classnames';
3
3
 
4
4
  import { NO_SPACE, SPACES } from '../../tokens';
5
- // @ts-ignore
6
5
  import css from './box.module.css';
7
6
 
8
7
  type SpaceValue = (typeof SPACES)[number];
@@ -3,14 +3,13 @@ import cx from 'classnames';
3
3
 
4
4
  import { NO_SPACE, SPACES } from '../../tokens';
5
5
  import { getRenderChildWithClassName } from '../../utils';
6
- // @ts-ignore
7
6
  import css from './flex-stack.module.css';
8
7
 
9
8
  type SpaceValue = (typeof SPACES)[number];
10
9
 
11
10
  interface FlexStackProps<T extends React.ElementType> {
12
11
  as?: T;
13
- space?: typeof SPACES[number];
12
+ space?: SpaceValue;
14
13
  inline?: boolean;
15
14
  alignItems?: 'top' | 'center' | 'bottom';
16
15
  }
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import cx from 'classnames';
3
3
 
4
- // @ts-ignore
5
4
  import css from './container.module.css';
6
5
 
7
6
  interface ContainerProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -7,7 +7,6 @@ import {
7
7
  useTooltipState,
8
8
  } from 'ariakit/tooltip';
9
9
 
10
- // @ts-ignore
11
10
  import css from './tooltip.module.css';
12
11
 
13
12
  interface TooltipProps<T extends React.ElementType> {
@@ -18,6 +18,7 @@ export { MetricsTableOptions } from "./metrics-table-options";
18
18
  export { MetricsTableSearch } from "./metrics-table-search";
19
19
  export { MetricsTableTitle } from "./metrics-table-title";
20
20
  export { ModuleInfo } from "./module-info";
21
- export { SummaryItem } from "./summary-item";
22
21
  export { Summary } from "./summary";
23
22
  export { TotalSizeTypeTitle } from "./total-size-type-title";
23
+ export { MetricRunInfo, MetricRunInfoProps } from "./metric-run-info";
24
+ export { RunInfo, RunInfoProps } from "./run-info";