@bundle-stats/ui 4.22.2 → 4.23.0-beta.1

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 (227) hide show
  1. package/.babelrc.js +65 -24
  2. package/globals.d.ts +13 -0
  3. package/lib/app/app.js +3 -0
  4. package/lib/app/app.js.map +1 -1
  5. package/lib/app/app.module.css +11 -1
  6. package/lib/components/bundle-modules/index.js.map +1 -1
  7. package/lib/components/delta/delta.js +3 -13
  8. package/lib/components/delta/delta.js.map +1 -1
  9. package/lib/components/delta/delta.module.css +13 -12
  10. package/lib/components/delta/index.js.map +1 -1
  11. package/lib/components/index.js +3 -1
  12. package/lib/components/index.js.map +1 -1
  13. package/lib/components/insight-icon/insight-icon.module.css +6 -6
  14. package/lib/components/job-name/job-name.js +1 -2
  15. package/lib/components/job-name/job-name.js.map +1 -1
  16. package/lib/components/metric-change-legend/index.js +18 -0
  17. package/lib/components/metric-change-legend/index.js.map +1 -0
  18. package/lib/components/metric-change-legend/metric-change-legend.js +91 -0
  19. package/lib/components/metric-change-legend/metric-change-legend.js.map +1 -0
  20. package/lib/components/metric-change-legend/metric-change-legend.module.css +69 -0
  21. package/lib/components/metric-run-info/metric-run-info.js +30 -7
  22. package/lib/components/metric-run-info/metric-run-info.js.map +1 -1
  23. package/lib/components/metrics-display-selector/metrics-display-selector.js +7 -9
  24. package/lib/components/metrics-display-selector/metrics-display-selector.js.map +1 -1
  25. package/lib/components/metrics-display-selector/metrics-display-selector.module.css +0 -25
  26. package/lib/components/metrics-table-header/metrics-table-header.js +8 -8
  27. package/lib/components/metrics-table-header/metrics-table-header.js.map +1 -1
  28. package/lib/components/metrics-table-header/metrics-table-header.module.css +8 -12
  29. package/lib/components/metrics-table-options/metrics-table-options.js +1 -1
  30. package/lib/components/metrics-table-options/metrics-table-options.js.map +1 -1
  31. package/lib/components/metrics-table-title/metrics-table-title.js +1 -1
  32. package/lib/components/metrics-table-title/metrics-table-title.js.map +1 -1
  33. package/lib/components/run-info/run-info.js +26 -14
  34. package/lib/components/run-info/run-info.js.map +1 -1
  35. package/lib/components/run-info/run-info.module.css +35 -26
  36. package/lib/components/summary/summary.js +9 -10
  37. package/lib/components/summary/summary.js.map +1 -1
  38. package/lib/components/summary/summary.module.css +60 -10
  39. package/lib/constants.js +13 -1
  40. package/lib/constants.js.map +1 -1
  41. package/lib/css/default.css +1 -1
  42. package/lib/css/variables.css +71 -58
  43. package/lib/hooks/rows-sort.js +13 -12
  44. package/lib/hooks/rows-sort.js.map +1 -1
  45. package/lib/ui/button/button.js.map +1 -1
  46. package/lib/ui/dialog/dialog.js +4 -2
  47. package/lib/ui/dialog/dialog.js.map +1 -1
  48. package/lib/ui/dialog/dialog.module.css +22 -0
  49. package/lib/ui/dropdown/dropdown.js +4 -3
  50. package/lib/ui/dropdown/dropdown.js.map +1 -1
  51. package/lib/ui/dropdown/dropdown.module.css +11 -0
  52. package/lib/ui/empty-set/empty-set.js +3 -3
  53. package/lib/ui/empty-set/empty-set.js.map +1 -1
  54. package/lib/ui/hover-card/hover-card.js +1 -1
  55. package/lib/ui/hover-card/hover-card.js.map +1 -1
  56. package/lib/ui/hover-card/hover-card.module.css +14 -0
  57. package/lib/ui/table/table.module.css +0 -1
  58. package/lib/ui/tooltip/tooltip.js +1 -1
  59. package/lib/ui/tooltip/tooltip.js.map +1 -1
  60. package/lib/ui/tooltip/tooltip.module.css +11 -0
  61. package/lib-esm/app/app.js +4 -1
  62. package/lib-esm/app/app.js.map +1 -1
  63. package/lib-esm/app/app.module.css +11 -1
  64. package/lib-esm/components/bundle-modules/index.js.map +1 -1
  65. package/lib-esm/components/delta/delta.js +3 -13
  66. package/lib-esm/components/delta/delta.js.map +1 -1
  67. package/lib-esm/components/delta/delta.module.css +13 -12
  68. package/lib-esm/components/delta/index.js.map +1 -1
  69. package/lib-esm/components/index.js +1 -0
  70. package/lib-esm/components/index.js.map +1 -1
  71. package/lib-esm/components/insight-icon/insight-icon.module.css +6 -6
  72. package/lib-esm/components/job-name/job-name.js +1 -2
  73. package/lib-esm/components/job-name/job-name.js.map +1 -1
  74. package/lib-esm/components/metric-change-legend/index.js +2 -0
  75. package/lib-esm/components/metric-change-legend/index.js.map +1 -0
  76. package/lib-esm/components/metric-change-legend/metric-change-legend.js +84 -0
  77. package/lib-esm/components/metric-change-legend/metric-change-legend.js.map +1 -0
  78. package/lib-esm/components/metric-change-legend/metric-change-legend.module.css +69 -0
  79. package/lib-esm/components/metric-run-info/metric-run-info.js +31 -8
  80. package/lib-esm/components/metric-run-info/metric-run-info.js.map +1 -1
  81. package/lib-esm/components/metrics-display-selector/metrics-display-selector.js +7 -9
  82. package/lib-esm/components/metrics-display-selector/metrics-display-selector.js.map +1 -1
  83. package/lib-esm/components/metrics-display-selector/metrics-display-selector.module.css +0 -25
  84. package/lib-esm/components/metrics-table-header/metrics-table-header.js +8 -8
  85. package/lib-esm/components/metrics-table-header/metrics-table-header.js.map +1 -1
  86. package/lib-esm/components/metrics-table-header/metrics-table-header.module.css +8 -12
  87. package/lib-esm/components/metrics-table-options/metrics-table-options.js +1 -1
  88. package/lib-esm/components/metrics-table-options/metrics-table-options.js.map +1 -1
  89. package/lib-esm/components/metrics-table-title/metrics-table-title.js +1 -1
  90. package/lib-esm/components/metrics-table-title/metrics-table-title.js.map +1 -1
  91. package/lib-esm/components/run-info/run-info.js +26 -14
  92. package/lib-esm/components/run-info/run-info.js.map +1 -1
  93. package/lib-esm/components/run-info/run-info.module.css +35 -26
  94. package/lib-esm/components/summary/summary.js +10 -11
  95. package/lib-esm/components/summary/summary.js.map +1 -1
  96. package/lib-esm/components/summary/summary.module.css +60 -10
  97. package/lib-esm/constants.js +12 -0
  98. package/lib-esm/constants.js.map +1 -1
  99. package/lib-esm/css/default.css +1 -1
  100. package/lib-esm/css/variables.css +71 -58
  101. package/lib-esm/hooks/rows-sort.js +10 -8
  102. package/lib-esm/hooks/rows-sort.js.map +1 -1
  103. package/lib-esm/ui/button/button.js.map +1 -1
  104. package/lib-esm/ui/dialog/dialog.js +4 -2
  105. package/lib-esm/ui/dialog/dialog.js.map +1 -1
  106. package/lib-esm/ui/dialog/dialog.module.css +22 -0
  107. package/lib-esm/ui/dropdown/dropdown.js +4 -3
  108. package/lib-esm/ui/dropdown/dropdown.js.map +1 -1
  109. package/lib-esm/ui/dropdown/dropdown.module.css +11 -0
  110. package/lib-esm/ui/empty-set/empty-set.js +3 -3
  111. package/lib-esm/ui/empty-set/empty-set.js.map +1 -1
  112. package/lib-esm/ui/hover-card/hover-card.js +1 -1
  113. package/lib-esm/ui/hover-card/hover-card.js.map +1 -1
  114. package/lib-esm/ui/hover-card/hover-card.module.css +14 -0
  115. package/lib-esm/ui/table/table.module.css +0 -1
  116. package/lib-esm/ui/tooltip/tooltip.js +1 -1
  117. package/lib-esm/ui/tooltip/tooltip.js.map +1 -1
  118. package/lib-esm/ui/tooltip/tooltip.module.css +11 -0
  119. package/package.json +26 -15
  120. package/src/app/app.jsx +6 -1
  121. package/src/app/app.module.css +11 -1
  122. package/src/app/app.stories.tsx +2 -2
  123. package/src/components/asset-info/asset-info.stories.tsx +47 -39
  124. package/src/components/asset-name/asset-name.stories.tsx +1 -3
  125. package/src/components/asset-not-predictive/asset-not-predictive.stories.tsx +22 -15
  126. package/src/components/browsertime-table/browsertime-table.stories.tsx +45 -0
  127. package/src/components/bundle-assets-totals/bundle-assets-totals.stories.tsx +47 -0
  128. package/src/components/bundle-modules/bundle-modules.stories.tsx +191 -0
  129. package/src/components/bundle-modules/bundle-modules.tsx +1 -1
  130. package/src/components/bundle-modules/index.tsx +4 -0
  131. package/src/components/bundle-packages/bundle-packages.stories.tsx +87 -0
  132. package/src/components/delta/delta.module.css +13 -12
  133. package/src/components/delta/delta.stories.tsx +57 -0
  134. package/src/components/delta/delta.tsx +32 -0
  135. package/src/components/entry-info/entry-info.stories.tsx +49 -54
  136. package/src/components/{index.js → index.ts} +7 -2
  137. package/src/components/insight-icon/insight-icon.module.css +6 -6
  138. package/src/components/insights/insights.stories.tsx +36 -33
  139. package/src/components/job-name/job-name.jsx +2 -3
  140. package/src/components/job-name/job-name.stories.tsx +46 -0
  141. package/src/components/jobs-header/jobs-header.stories.tsx +19 -15
  142. package/src/components/lighthouse-table/lighthouse-table.stories.tsx +30 -0
  143. package/src/components/metric/metric.stories.tsx +24 -22
  144. package/src/components/metric-change-legend/index.ts +1 -0
  145. package/src/components/metric-change-legend/metric-change-legend.module.css +69 -0
  146. package/src/components/metric-change-legend/metric-change-legend.stories.tsx +13 -0
  147. package/src/components/metric-change-legend/metric-change-legend.tsx +148 -0
  148. package/src/components/metric-run-info/metric-run-info.stories.tsx +45 -41
  149. package/src/components/metric-run-info/metric-run-info.tsx +41 -17
  150. package/src/components/metrics-display-selector/metrics-display-selector.module.css +0 -25
  151. package/src/components/metrics-display-selector/metrics-display-selector.tsx +25 -37
  152. package/src/components/metrics-table/metrics-table.stories.tsx +33 -13
  153. package/src/components/metrics-table/metrics-table.tsx +1 -1
  154. package/src/components/metrics-table-header/metrics-table-header.module.css +8 -12
  155. package/src/components/metrics-table-header/metrics-table-header.tsx +14 -10
  156. package/src/components/metrics-table-options/metrics-table-options.tsx +1 -1
  157. package/src/components/metrics-table-title/metrics-table-title.jsx +1 -1
  158. package/src/components/module-info/module-info.stories.tsx +41 -30
  159. package/src/components/package-info/package-info.stories.tsx +20 -15
  160. package/src/components/run-info/run-info.module.css +35 -26
  161. package/src/components/run-info/run-info.stories.tsx +47 -39
  162. package/src/components/run-info/run-info.tsx +132 -73
  163. package/src/components/summary/summary.module.css +60 -10
  164. package/src/components/summary/summary.stories.tsx +26 -32
  165. package/src/components/summary/summary.tsx +47 -50
  166. package/src/constants.ts +13 -0
  167. package/src/css/default.css +1 -1
  168. package/src/css/variables.css +71 -58
  169. package/src/hooks/rows-sort.ts +9 -6
  170. package/src/layout/box/box.stories.tsx +35 -28
  171. package/src/layout/flex-stack/flex-stack.stories.tsx +79 -48
  172. package/src/layout/footer/footer.stories.tsx +30 -0
  173. package/src/layout/stack/stack.stories.tsx +68 -44
  174. package/src/ui/alert/alert.stories.tsx +25 -21
  175. package/src/ui/button/button.stories.tsx +181 -176
  176. package/src/ui/button/button.tsx +8 -1
  177. package/src/ui/container/container.stories.tsx +28 -21
  178. package/src/ui/control-group/control-group.stories.tsx +23 -16
  179. package/src/ui/dialog/dialog.module.css +22 -0
  180. package/src/ui/dialog/dialog.tsx +9 -2
  181. package/src/ui/dropdown/dropdown.module.css +11 -0
  182. package/src/ui/dropdown/dropdown.stories.tsx +23 -15
  183. package/src/ui/dropdown/dropdown.tsx +5 -1
  184. package/src/ui/empty-set/empty-set.jsx +16 -4
  185. package/src/ui/empty-set/empty-set.stories.tsx +41 -0
  186. package/src/ui/file-name/file-name.stories.tsx +45 -0
  187. package/src/ui/filters/filters.stories.tsx +29 -26
  188. package/src/ui/hover-card/hover-card.module.css +14 -0
  189. package/src/ui/hover-card/hover-card.stories.tsx +35 -26
  190. package/src/ui/hover-card/hover-card.tsx +1 -1
  191. package/src/ui/icon/icon.stories.tsx +36 -28
  192. package/src/ui/input/input.stories.tsx +17 -5
  193. package/src/ui/input-search/input-search.stories.tsx +31 -0
  194. package/src/ui/loader/loader.stories.tsx +22 -0
  195. package/src/ui/skeleton/skeleton.stories.tsx +42 -0
  196. package/src/ui/table/table.module.css +0 -1
  197. package/src/ui/table/table.stories.tsx +244 -218
  198. package/src/ui/tag/tag.stories.tsx +11 -10
  199. package/src/ui/toolbar/toolbar.stories.tsx +41 -0
  200. package/src/ui/tooltip/tooltip.module.css +11 -0
  201. package/src/ui/tooltip/tooltip.tsx +1 -1
  202. package/types/components/bundle-modules/bundle-modules.d.ts +1 -1
  203. package/types/components/bundle-modules/index.d.ts +2 -1
  204. package/types/components/delta/delta.d.ts +7 -21
  205. package/types/components/delta/index.d.ts +1 -1
  206. package/types/components/index.d.ts +25 -20
  207. package/types/components/metric-change-legend/index.d.ts +1 -0
  208. package/types/components/metric-change-legend/metric-change-legend.d.ts +4 -0
  209. package/types/components/metric-run-info/metric-run-info.d.ts +2 -6
  210. package/types/components/metrics-table/metrics-table.d.ts +1 -1
  211. package/types/components/metrics-table-header/metrics-table-header.d.ts +1 -1
  212. package/types/components/run-info/run-info.d.ts +16 -7
  213. package/types/constants.d.ts +12 -0
  214. package/types/hooks/rows-sort.d.ts +2 -2
  215. package/types/ui/button/button.d.ts +1 -1
  216. package/types/ui/dialog/dialog.d.ts +3 -2
  217. package/types/ui/dropdown/dropdown.d.ts +1 -0
  218. package/vitest.config.ts +47 -0
  219. package/vitest.setup.ts +26 -0
  220. package/lib/assets/icons.svg.js +0 -100
  221. package/lib/assets/icons.svg.js.map +0 -1
  222. package/lib-esm/assets/icons.svg.js +0 -63
  223. package/lib-esm/assets/icons.svg.js.map +0 -1
  224. package/src/assets/icons.svg.jsx +0 -279
  225. package/src/components/delta/delta.jsx +0 -22
  226. package/types/assets/icons.svg.d.ts +0 -2
  227. /package/src/components/delta/{index.js → index.ts} +0 -0
@@ -0,0 +1,47 @@
1
+ import type React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { createJobs, Job } from '@bundle-stats/utils';
4
+
5
+ /* eslint-disable import/no-relative-packages */
6
+ import baselineStats from '../../../../../fixtures/webpack-stats.baseline.json';
7
+ import currentStats from '../../../../../fixtures/webpack-stats.current.json';
8
+ /* eslint-enable import/no-relative-packages */
9
+ import { getWrapperDecorator } from '../../stories';
10
+ import { BundleAssetsTotals } from '.';
11
+
12
+ // BundleAssetsTotals is a plain .jsx component with defaultProps instead of
13
+ // inline destructuring defaults, so TS can't infer its props as optional on its own.
14
+ const TypedBundleAssetsTotals = BundleAssetsTotals as unknown as React.ComponentType<{
15
+ className?: string;
16
+ jobs?: Array<Job>;
17
+ customComponentLink?: React.ElementType;
18
+ onTreemapItemClick?: (entryId: string) => void;
19
+ }>;
20
+
21
+ const meta = {
22
+ title: 'Components/BundleAssetsTotals',
23
+ component: TypedBundleAssetsTotals,
24
+ decorators: [getWrapperDecorator()],
25
+ } satisfies Meta<typeof TypedBundleAssetsTotals>;
26
+
27
+ export default meta;
28
+
29
+ type Story = StoryObj<typeof meta>;
30
+
31
+ export const SingleJob: Story = {
32
+ args: {
33
+ jobs: createJobs([{ webpack: currentStats }]),
34
+ },
35
+ };
36
+
37
+ export const MultipleJobs: Story = {
38
+ args: {
39
+ jobs: createJobs([{ webpack: currentStats }, { webpack: baselineStats }]),
40
+ },
41
+ };
42
+
43
+ export const EmptyBaseline: Story = {
44
+ args: {
45
+ jobs: createJobs([{ webpack: currentStats }, {}]),
46
+ },
47
+ };
@@ -0,0 +1,191 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { createJobs } from '@bundle-stats/utils';
3
+
4
+ /* eslint-disable import/no-relative-packages */
5
+ import baselineStatsFixtures from '../../../../../fixtures/webpack-stats.baseline.json';
6
+ import currentStatsFixtures from '../../../../../fixtures/webpack-stats.current.json';
7
+ /* eslint-enable import/no-relative-packages */
8
+ import { getWrapperDecorator } from '../../stories';
9
+ import { BundleModules } from '.';
10
+
11
+ // Limit the side of the modules when not in dev mode (chromatic limit, snapshot too large)
12
+ const { baselineStats, currentStats } =
13
+ process.env.NODE_ENV !== 'development'
14
+ ? {
15
+ // eslint-disable-next-line prefer-object-spread
16
+ baselineStats: Object.assign({}, baselineStatsFixtures, {
17
+ modules: baselineStatsFixtures.modules.slice(0, 100),
18
+ }),
19
+ // eslint-disable-next-line prefer-object-spread
20
+ currentStats: Object.assign({}, currentStatsFixtures, {
21
+ modules: currentStatsFixtures.modules.slice(0, 100),
22
+ }),
23
+ }
24
+ : { baselineStats: baselineStatsFixtures, currentStats: currentStatsFixtures };
25
+
26
+ const JOBS = createJobs([{ webpack: currentStats }, { webpack: baselineStats }]);
27
+
28
+ const meta = {
29
+ title: 'Components/BundleModules',
30
+ component: BundleModules,
31
+ decorators: [getWrapperDecorator()],
32
+ args: {
33
+ filters: {},
34
+ setState: () => {},
35
+ },
36
+ } satisfies Meta<typeof BundleModules>;
37
+
38
+ export default meta;
39
+
40
+ type Story = StoryObj<typeof meta>;
41
+
42
+ export const Default: Story = {
43
+ args: {
44
+ jobs: [JOBS[1]],
45
+ },
46
+ };
47
+
48
+ export const MultipleJobs: Story = {
49
+ args: {
50
+ jobs: JOBS,
51
+ },
52
+ };
53
+
54
+ const JOBS_EMPTY_BASELINE = createJobs([{ webpack: currentStats }, {}]);
55
+
56
+ export const EmptyBaseline: Story = {
57
+ args: {
58
+ jobs: JOBS_EMPTY_BASELINE,
59
+ },
60
+ };
61
+
62
+ // Module moved between chunks
63
+ const JOBS_MOVED_MODULE = createJobs([
64
+ {
65
+ webpack: {
66
+ chunks: [
67
+ {
68
+ id: 1,
69
+ names: ['chunk-1'],
70
+ },
71
+ {
72
+ id: 2,
73
+ names: ['chunk-2'],
74
+ },
75
+ ],
76
+ modules: [
77
+ {
78
+ name: 'module-1a.js',
79
+ size: 1100,
80
+ chunks: [1],
81
+ },
82
+ {
83
+ name: 'module-1b.js',
84
+ size: 1200,
85
+ chunks: [1],
86
+ },
87
+ {
88
+ name: 'module-moved-from-chunk-2-to-1.js',
89
+ size: 2300,
90
+ chunks: [1],
91
+ },
92
+ {
93
+ name: 'module-2b.js',
94
+ size: 2200,
95
+ chunks: [2],
96
+ },
97
+ {
98
+ name: 'module-moved-from-chunk-3-to-1.js',
99
+ size: 3300,
100
+ chunks: [1],
101
+ },
102
+ ],
103
+ },
104
+ },
105
+ {
106
+ webpack: {
107
+ chunks: [
108
+ {
109
+ id: 1,
110
+ names: ['chunk-1'],
111
+ },
112
+ {
113
+ id: 2,
114
+ names: ['chunk-2'],
115
+ },
116
+ {
117
+ id: 3,
118
+ names: ['chunk-3'],
119
+ },
120
+ ],
121
+ modules: [
122
+ {
123
+ name: 'module-1a.js',
124
+ size: 1000,
125
+ chunks: [1],
126
+ },
127
+ {
128
+ name: 'module-1b.js',
129
+ size: 1100,
130
+ chunks: [1],
131
+ },
132
+ {
133
+ name: 'module-moved-from-chunk-2-to-1.js',
134
+ size: 2000,
135
+ chunks: [2],
136
+ },
137
+ {
138
+ name: 'module-2b.js',
139
+ size: 2200,
140
+ chunks: [2],
141
+ },
142
+ {
143
+ name: 'module-moved-from-chunk-3-to-1.js',
144
+ size: 3300,
145
+ chunks: [3],
146
+ },
147
+ {
148
+ name: 'module-removed-from-all-chunks.js',
149
+ size: 3300,
150
+ chunks: [3],
151
+ },
152
+ ],
153
+ },
154
+ },
155
+ ]);
156
+
157
+ export const ChunkFiltersWithModuleMovedIn: Story = {
158
+ args: {
159
+ filters: {
160
+ changed: false,
161
+ 'c.1': true,
162
+ 'c.2': false,
163
+ 'c.3': false,
164
+ },
165
+ jobs: [...JOBS_MOVED_MODULE],
166
+ },
167
+ };
168
+
169
+ export const ChunkFiltersWithModuleMovedOut: Story = {
170
+ args: {
171
+ filters: {
172
+ changed: false,
173
+ 'c.1': false,
174
+ 'c.2': true,
175
+ 'c.3': false,
176
+ },
177
+ jobs: [...JOBS_MOVED_MODULE],
178
+ },
179
+ };
180
+
181
+ export const ChunkFiltersWithRemovedChunk: Story = {
182
+ args: {
183
+ filters: {
184
+ changed: false,
185
+ 'c.1': false,
186
+ 'c.2': false,
187
+ 'c.3': true,
188
+ },
189
+ jobs: [...JOBS_MOVED_MODULE],
190
+ },
191
+ };
@@ -164,7 +164,7 @@ interface BundleModulesProps extends React.ComponentProps<'div'> {
164
164
  moduleMetric: ModuleSizeMetric;
165
165
  setModuleMetric: (newValue: ModuleSizeMetric) => void;
166
166
 
167
- customComponentLink: React.ElementType;
167
+ customComponentLink?: React.ElementType;
168
168
  }
169
169
 
170
170
  export const BundleModules = (props: BundleModulesProps) => {
@@ -65,6 +65,9 @@ interface BundleModulesProps extends Omit<
65
65
  | 'totalRowCount'
66
66
  | 'hideEntryInfo'
67
67
  | 'showEntryInfo'
68
+ | 'moduleMetric'
69
+ | 'setModuleMetric'
70
+ | 'customComponentLink'
68
71
  > {
69
72
  jobs: Array<Job>;
70
73
  filters: Record<string, boolean>;
@@ -73,6 +76,7 @@ interface BundleModulesProps extends Omit<
73
76
  setState: (params: any) => void;
74
77
  sortBy?: string;
75
78
  direction?: SortAction['direction'];
79
+ customComponentLink?: React.ElementType;
76
80
  }
77
81
 
78
82
  export const BundleModules = (props: BundleModulesProps) => {
@@ -0,0 +1,87 @@
1
+ import type React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import merge from 'lodash/merge';
4
+ import set from 'lodash/set';
5
+ import { PACKAGE_FILTERS, createJobs, Job } from '@bundle-stats/utils';
6
+
7
+ /* eslint-disable import/no-relative-packages */
8
+ import baselineStats from '../../../../../fixtures/webpack-stats.baseline.json';
9
+ import currentStats from '../../../../../fixtures/webpack-stats.current.json';
10
+ /* eslint-enable import/no-relative-packages */
11
+ import { getWrapperDecorator } from '../../stories';
12
+ import { BundlePackages } from '.';
13
+
14
+ const JOBS = createJobs([{ webpack: currentStats }, { webpack: baselineStats }]);
15
+ const [currentJob, baselineJob] = JOBS;
16
+
17
+ // BundlePackages is a plain .jsx component with no inline destructuring
18
+ // defaults, so TS can't infer its optional props on its own.
19
+ const TypedBundlePackages = BundlePackages as unknown as React.ComponentType<{
20
+ jobs: Array<Job>;
21
+ filters?: Record<string, boolean>;
22
+ search?: string;
23
+ sortBy?: string;
24
+ direction?: string;
25
+ setState: (params: any) => void;
26
+ }>;
27
+
28
+ const meta = {
29
+ title: 'Components/BundlePackages',
30
+ component: TypedBundlePackages,
31
+ decorators: [getWrapperDecorator()],
32
+ args: {
33
+ setState: () => {},
34
+ },
35
+ } satisfies Meta<typeof TypedBundlePackages>;
36
+
37
+ export default meta;
38
+
39
+ type Story = StoryObj<typeof meta>;
40
+
41
+ export const Default: Story = {
42
+ args: {
43
+ jobs: [baselineJob],
44
+ },
45
+ };
46
+
47
+ export const MultipleJobs: Story = {
48
+ args: {
49
+ jobs: JOBS,
50
+ },
51
+ };
52
+
53
+ export const CustomFilters: Story = {
54
+ args: {
55
+ jobs: JOBS,
56
+ filters: {
57
+ [PACKAGE_FILTERS.CHANGED]: false,
58
+ [PACKAGE_FILTERS.DUPLICATE]: true,
59
+ },
60
+ },
61
+ };
62
+
63
+ export const EmptyPackages: Story = {
64
+ args: {
65
+ jobs: [
66
+ set(merge({}, currentJob), 'metrics.webpack.packages', {}),
67
+ set(merge({}, baselineJob), 'metrics.webpack.packages', {}),
68
+ ],
69
+ },
70
+ };
71
+
72
+ export const EmptyFilteredPackages: Story = {
73
+ args: {
74
+ jobs: [
75
+ set(merge({}, currentJob), 'metrics.webpack.packages', { 'package-a': { value: 100 } }),
76
+ set(merge({}, baselineJob), 'metrics.webpack.packages', { 'package-a': { value: 100 } }),
77
+ ],
78
+ },
79
+ };
80
+
81
+ const JOBS_EMPTY_BASELINE = createJobs([{ webpack: currentStats }, { webpack: null }]);
82
+
83
+ export const EmptyBaseline: Story = {
84
+ args: {
85
+ jobs: JOBS_EMPTY_BASELINE,
86
+ },
87
+ };
@@ -8,16 +8,16 @@
8
8
  color: var(--color-info);
9
9
  }
10
10
 
11
- .HIGH_NEGATIVE {
12
- color: var(--color-red-dark);
11
+ .LOW_NEGATIVE {
12
+ color: var(--color-red-light);
13
13
  }
14
14
 
15
15
  .NEGATIVE {
16
- color: var(--color-red-dark);
16
+ color: var(--color-red);
17
17
  }
18
18
 
19
- .LOW_NEGATIVE {
20
- color: var(--color-red-light);
19
+ .HIGH_NEGATIVE {
20
+ color: var(--color-red-dark);
21
21
  }
22
22
 
23
23
  .LOW_POSITIVE {
@@ -25,7 +25,7 @@
25
25
  }
26
26
 
27
27
  .POSITIVE {
28
- color: var(--color-green-dark);
28
+ color: var(--color-green);
29
29
  }
30
30
 
31
31
  .HIGH_POSITIVE {
@@ -43,24 +43,25 @@
43
43
  background: var(--color-info-light);
44
44
  }
45
45
 
46
- .inverted.HIGH_NEGATIVE {
47
- background: var(--color-red-dark);
46
+ .inverted.LOW_NEGATIVE {
47
+ background: var(--color-red-light);
48
48
  }
49
49
 
50
50
  .inverted.NEGATIVE {
51
- background: var(--color-red-dark);
51
+ background: var(--color-red);
52
52
  }
53
53
 
54
- .inverted.LOW_NEGATIVE {
55
- background: var(--color-red-light);
54
+ .inverted.HIGH_NEGATIVE {
55
+ background: var(--color-red-dark);
56
56
  }
57
57
 
58
+
58
59
  .inverted.LOW_POSITIVE {
59
60
  background: var(--color-green-light);
60
61
  }
61
62
 
62
63
  .inverted.POSITIVE {
63
- background: var(--color-green-dark);
64
+ background: var(--color-green);
64
65
  }
65
66
 
66
67
  .inverted.HIGH_POSITIVE {
@@ -0,0 +1,57 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { getWrapperDecorator } from '../../stories';
4
+ import { Delta } from '.';
5
+
6
+ const meta = {
7
+ title: 'Components/Delta',
8
+ component: Delta,
9
+ decorators: [getWrapperDecorator()],
10
+ } satisfies Meta<typeof Delta>;
11
+
12
+ export default meta;
13
+
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Default: Story = {
17
+ args: {
18
+ displayValue: '20%',
19
+ deltaType: 'POSITIVE',
20
+ },
21
+ };
22
+
23
+ export const Negative: Story = {
24
+ args: {
25
+ displayValue: '20%',
26
+ deltaType: 'NEGATIVE',
27
+ },
28
+ };
29
+
30
+ export const SlightlyNegative: Story = {
31
+ args: {
32
+ displayValue: '1%',
33
+ deltaType: 'LOW_NEGATIVE',
34
+ },
35
+ };
36
+
37
+ export const SlightlyPositive: Story = {
38
+ args: {
39
+ displayValue: '1%',
40
+ deltaType: 'LOW_POSITIVE',
41
+ },
42
+ };
43
+
44
+ export const Empty: Story = {
45
+ args: {
46
+ displayValue: '0%',
47
+ deltaType: 'NO_CHANGE',
48
+ },
49
+ };
50
+
51
+ export const Inverted: Story = {
52
+ args: {
53
+ displayValue: '1%',
54
+ deltaType: 'LOW_NEGATIVE',
55
+ inverted: true,
56
+ },
57
+ };
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import cx from 'classnames';
3
+ import type { MetricRunInfoDeltaType } from '@bundle-stats/utils';
4
+
5
+ import css from './delta.module.css';
6
+
7
+ export interface DeltaProps {
8
+ /**
9
+ * Formatted delta value
10
+ */
11
+ displayValue: string;
12
+ /**
13
+ * Delta type - drives the color scale
14
+ */
15
+ deltaType: MetricRunInfoDeltaType;
16
+ /**
17
+ * Inverted variant - render the delta type as background color
18
+ */
19
+ inverted?: boolean;
20
+ }
21
+
22
+ export const Delta = (props: DeltaProps & React.ComponentProps<'span'>) => {
23
+ const { className = '', displayValue, deltaType, inverted = false, ...restProps } = props;
24
+
25
+ const rootClassName = cx(css.root, className, inverted && css.inverted, css[deltaType]);
26
+
27
+ return (
28
+ <span className={rootClassName} {...restProps}>
29
+ {displayValue}
30
+ </span>
31
+ );
32
+ };
@@ -1,15 +1,10 @@
1
1
  import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
2
3
  import { action } from 'storybook/actions';
3
4
 
4
5
  import { getWrapperDecorator } from '../../stories';
5
6
  import { EntryInfo } from '.';
6
7
 
7
- export default {
8
- title: 'Components/EntryInfo',
9
- component: EntryInfo,
10
- decorators: [getWrapperDecorator()],
11
- };
12
-
13
8
  const RUNS = [
14
9
  {
15
10
  name: 'static/vendor.abcd1234.js',
@@ -22,54 +17,54 @@ const RUNS = [
22
17
  },
23
18
  ];
24
19
 
25
- export const Default = () => (
26
- <EntryInfo
27
- item={{
28
- label: 'static/vendor.js',
29
- runs: RUNS as any,
30
- }}
31
- labels={['Job #2', 'Job #1']}
32
- onClose={action('CLOSE')}
33
- />
34
- );
20
+ const ITEM = {
21
+ key: 'static/vendor.js',
22
+ label: 'static/vendor.js',
23
+ biggerIsBetter: false,
24
+ changed: true,
25
+ };
26
+
27
+ const meta = {
28
+ title: 'Components/EntryInfo',
29
+ component: EntryInfo,
30
+ decorators: [getWrapperDecorator()],
31
+ args: {
32
+ item: { ...ITEM, runs: RUNS as any },
33
+ labels: ['Job #2', 'Job #1'],
34
+ onClose: action('CLOSE'),
35
+ },
36
+ } satisfies Meta<typeof EntryInfo>;
37
+
38
+ export default meta;
39
+
40
+ type Story = StoryObj<typeof meta>;
35
41
 
36
- export const Added = () => (
37
- <EntryInfo
38
- item={{
39
- label: 'static/vendor.js',
40
- runs: [RUNS[0], null] as any,
41
- }}
42
- labels={['Job #2', 'Job #1']}
43
- onClose={action('CLOSE')}
44
- />
45
- );
42
+ export const Default: Story = {};
43
+
44
+ export const Added: Story = {
45
+ args: {
46
+ item: { ...ITEM, runs: [RUNS[0], null] as any },
47
+ },
48
+ };
46
49
 
47
- export const Removed = () => (
48
- <EntryInfo
49
- item={{
50
- label: 'static/vendor.js',
51
- runs: [null, RUNS[1]] as any,
52
- }}
53
- labels={['Job #2', 'Job #1']}
54
- onClose={action('CLOSE')}
55
- />
56
- );
50
+ export const Removed: Story = {
51
+ args: {
52
+ item: { ...ITEM, runs: [null, RUNS[1]] as any },
53
+ },
54
+ };
57
55
 
58
- export const WithCustomContent = () => (
59
- <EntryInfo
60
- item={{
61
- label: 'static/vendor.js',
62
- runs: RUNS as any,
63
- }}
64
- labels={['Job #2', 'Job #1']}
65
- tags={<span>Critical tags</span>}
66
- onClose={action('CLOSE')}
67
- >
68
- <div>
69
- <EntryInfo.Meta label="Meta 1">value 1</EntryInfo.Meta>
70
- <EntryInfo.Meta label="Meta 2">value 2</EntryInfo.Meta>
71
- </div>
72
- <div>custom entry info 1</div>
73
- <div>custom entry info 2</div>
74
- </EntryInfo>
75
- );
56
+ export const WithCustomContent: Story = {
57
+ args: {
58
+ tags: <span>Critical tags</span>,
59
+ },
60
+ render: (args) => (
61
+ <EntryInfo {...args}>
62
+ <div>
63
+ <EntryInfo.Meta label="Meta 1">value 1</EntryInfo.Meta>
64
+ <EntryInfo.Meta label="Meta 2">value 2</EntryInfo.Meta>
65
+ </div>
66
+ <div>custom entry info 1</div>
67
+ <div>custom entry info 2</div>
68
+ </EntryInfo>
69
+ ),
70
+ };
@@ -5,16 +5,21 @@ export { BundlePackages } from './bundle-packages';
5
5
  export { BundleModules } from './bundle-modules';
6
6
  export { ComponentLink } from './component-link';
7
7
  export { Delta } from './delta';
8
+ export type { DeltaProps } from './delta';
8
9
  export { InsightIcon } from './insight-icon';
9
10
  export { Insights } from './insights';
10
11
  export { JobName } from './job-name';
11
12
  export { JobsHeader } from './jobs-header';
12
13
  export { LighthouseTable } from './lighthouse-table';
13
14
  export { Metric } from './metric';
14
- export { MetricRunInfo, MetricRunInfoProps } from './metric-run-info';
15
+ export { MetricChangeLegend } from './metric-change-legend';
16
+ export type { MetricChangeLegendProps } from './metric-change-legend';
17
+ export { MetricRunInfo } from './metric-run-info';
18
+ export type { MetricRunInfoProps } from './metric-run-info';
15
19
  export { MetricsTable } from './metrics-table';
16
20
  export { MetricsTableOptions } from './metrics-table-options';
17
21
  export { MetricsTableTitle } from './metrics-table-title';
18
22
  export { ModuleInfo } from './module-info';
19
- export { RunInfo, RunInfoProps } from './run-info';
23
+ export { RunInfo } from './run-info';
24
+ export type { RunInfoProps } from './run-info';
20
25
  export { Summary } from './summary';
@@ -1,20 +1,20 @@
1
1
  .root {
2
- width: calc(var(--space-small) + 6px);
3
- height: calc(var(--space-small) + 6px);
4
- padding: 3px;
2
+ width: calc(var(--space-small) + var(--space-xxsmall));
3
+ height: calc(var(--space-small) + var(--space-xxsmall));
4
+ padding: var(--space-xxxsmall);
5
5
  border-radius: 50%;
6
6
  background: var(--color-highlight);
7
7
  }
8
8
 
9
9
  .error {
10
- background: var(--color-red-50);
10
+ background: var(--color-highlight-danger);
11
11
  color: var(--color-danger);
12
12
  }
13
13
 
14
14
  .warning {
15
15
  padding-top: 1px;
16
- background: var(--color-yellow-100);
17
- color: var(--color-yellow-900);
16
+ background: var(--color-highlight-warning);
17
+ color: var(--color-warning);
18
18
  }
19
19
 
20
20
  .info {