@bundle-stats/ui 4.13.0-rc.0 → 4.13.0-rc.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 (86) hide show
  1. package/lib/components/bundle-assets/bundle-assets.js +23 -22
  2. package/lib/components/bundle-assets/bundle-assets.js.map +1 -1
  3. package/lib/components/bundle-assets/index.js +3 -1
  4. package/lib/components/bundle-assets/index.js.map +1 -1
  5. package/lib/components/bundle-modules/bundle-modules.js +10 -6
  6. package/lib/components/bundle-modules/bundle-modules.js.map +1 -1
  7. package/lib/components/bundle-modules/bundle-modules.utils.js +2 -13
  8. package/lib/components/bundle-modules/bundle-modules.utils.js.map +1 -1
  9. package/lib/components/bundle-modules/index.js +2 -1
  10. package/lib/components/bundle-modules/index.js.map +1 -1
  11. package/lib/components/bundle-packages/bundle-packages.js +11 -6
  12. package/lib/components/bundle-packages/bundle-packages.js.map +1 -1
  13. package/lib/components/metrics-treemap/metrics-treemap.constants.js +7 -0
  14. package/lib/components/metrics-treemap/metrics-treemap.constants.js.map +1 -1
  15. package/lib/components/metrics-treemap/metrics-treemap.js +69 -71
  16. package/lib/components/metrics-treemap/metrics-treemap.js.map +1 -1
  17. package/lib/components/metrics-treemap/metrics-treemap.module.css +47 -10
  18. package/lib/components/metrics-treemap/metrics-treemap.utils.js +60 -1
  19. package/lib/components/metrics-treemap/metrics-treemap.utils.js.map +1 -1
  20. package/lib/utils/colors.js +22 -0
  21. package/lib/utils/colors.js.map +1 -0
  22. package/lib/{utils.js → utils/components.js} +2 -17
  23. package/lib/utils/components.js.map +1 -0
  24. package/lib/utils/index.js +20 -0
  25. package/lib/utils/index.js.map +1 -0
  26. package/lib/utils/jobs.js +18 -0
  27. package/lib/utils/jobs.js.map +1 -0
  28. package/lib-esm/components/bundle-assets/bundle-assets.js +23 -23
  29. package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
  30. package/lib-esm/components/bundle-assets/index.js +3 -1
  31. package/lib-esm/components/bundle-assets/index.js.map +1 -1
  32. package/lib-esm/components/bundle-modules/bundle-modules.js +10 -6
  33. package/lib-esm/components/bundle-modules/bundle-modules.js.map +1 -1
  34. package/lib-esm/components/bundle-modules/bundle-modules.utils.js +1 -11
  35. package/lib-esm/components/bundle-modules/bundle-modules.utils.js.map +1 -1
  36. package/lib-esm/components/bundle-modules/index.js +3 -2
  37. package/lib-esm/components/bundle-modules/index.js.map +1 -1
  38. package/lib-esm/components/bundle-packages/bundle-packages.js +11 -6
  39. package/lib-esm/components/bundle-packages/bundle-packages.js.map +1 -1
  40. package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js +6 -1
  41. package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js.map +1 -1
  42. package/lib-esm/components/metrics-treemap/metrics-treemap.js +65 -68
  43. package/lib-esm/components/metrics-treemap/metrics-treemap.js.map +1 -1
  44. package/lib-esm/components/metrics-treemap/metrics-treemap.module.css +47 -10
  45. package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js +57 -0
  46. package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js.map +1 -1
  47. package/lib-esm/utils/colors.js +15 -0
  48. package/lib-esm/utils/colors.js.map +1 -0
  49. package/lib-esm/utils/components.js +16 -0
  50. package/lib-esm/utils/components.js.map +1 -0
  51. package/lib-esm/utils/index.js +4 -0
  52. package/lib-esm/utils/index.js.map +1 -0
  53. package/lib-esm/utils/jobs.js +11 -0
  54. package/lib-esm/utils/jobs.js.map +1 -0
  55. package/package.json +3 -3
  56. package/src/components/bundle-assets/bundle-assets.jsx +72 -48
  57. package/src/components/bundle-assets/index.jsx +4 -0
  58. package/src/components/bundle-modules/bundle-modules.tsx +32 -11
  59. package/src/components/bundle-modules/bundle-modules.types.d.ts +2 -17
  60. package/src/components/bundle-modules/bundle-modules.utils.ts +7 -18
  61. package/src/components/bundle-modules/index.tsx +4 -3
  62. package/src/components/bundle-packages/bundle-packages.jsx +19 -7
  63. package/src/components/metrics-treemap/metrics-treemap.constants.ts +11 -0
  64. package/src/components/metrics-treemap/metrics-treemap.module.css +47 -10
  65. package/src/components/metrics-treemap/metrics-treemap.tsx +171 -110
  66. package/src/components/metrics-treemap/metrics-treemap.utils.ts +107 -1
  67. package/src/utils/colors.ts +19 -0
  68. package/src/utils/components.tsx +19 -0
  69. package/src/utils/index.ts +3 -0
  70. package/src/utils/jobs.ts +22 -0
  71. package/types/components/bundle-assets/bundle-assets.d.ts +1 -5
  72. package/types/components/bundle-modules/bundle-modules.d.ts +4 -2
  73. package/types/components/bundle-modules/bundle-modules.utils.d.ts +3 -7
  74. package/types/components/bundle-modules/index.d.ts +2 -2
  75. package/types/components/metrics-treemap/metrics-treemap.constants.d.ts +8 -0
  76. package/types/components/metrics-treemap/metrics-treemap.d.ts +1 -1
  77. package/types/components/metrics-treemap/metrics-treemap.utils.d.ts +11 -1
  78. package/types/utils/colors.d.ts +1 -0
  79. package/types/utils/components.d.ts +2 -0
  80. package/types/utils/index.d.ts +3 -0
  81. package/types/utils/jobs.d.ts +7 -0
  82. package/lib/utils.js.map +0 -1
  83. package/lib-esm/utils.js +0 -30
  84. package/lib-esm/utils.js.map +0 -1
  85. package/src/utils.jsx +0 -38
  86. package/types/utils.d.ts +0 -3
@@ -9,77 +9,43 @@ import React, {
9
9
  useMemo,
10
10
  useRef,
11
11
  } from 'react';
12
- import { useDebounce, useHoverDirty, useMeasure, useMouseHovered } from 'react-use';
12
+ import { useHoverDirty, useMeasure } from 'react-use';
13
13
  import cx from 'classnames';
14
14
  import { HierarchyRectangularNode, hierarchy, treemap, treemapSquarify } from 'd3';
15
- import { Tooltip, TooltipArrow, TooltipAnchor, useTooltipState } from 'ariakit/tooltip';
15
+ import { Tooltip, TooltipArrow, TooltipAnchor } from 'ariakit/tooltip';
16
16
  import {
17
17
  type ReportMetricRow,
18
18
  type MetricRunInfo,
19
19
  type MetricRunInfoBaseline,
20
- getMetricRunInfo,
21
20
  METRIC_TYPE_CONFIGS,
21
+ formatFileSize,
22
+ getMetricRunInfo,
22
23
  } from '@bundle-stats/utils';
23
24
 
24
25
  import { Stack } from '../../layout/stack';
25
26
  import { FileName } from '../../ui/file-name';
26
27
  import { Delta } from '../delta';
27
28
  import { RunInfo } from '../run-info';
28
- import type { TreeLeaf, TreeNode, Tree } from './metrics-treemap.constants';
29
+ import {
30
+ type TreeLeaf,
31
+ type TreeNode,
32
+ type Tree,
33
+ SQUARIFY_RATIO,
34
+ PADDING_OUTER,
35
+ PADDING_INNER,
36
+ NESTED_PADDING,
37
+ NESTED_PADDING_TOP,
38
+ NESTED_PADDING_LEFT,
39
+ TileSizeDisplay,
40
+ } from './metrics-treemap.constants';
29
41
  import * as I18N from './metrics-treemap.i18n';
30
42
  import css from './metrics-treemap.module.css';
31
- import { resolveGroupDeltaType } from './metrics-treemap.utils';
32
-
33
- const SQUARIFY_RATIO = 1.66;
34
- const PADDING_OUTER = 1;
35
- const PADDING_INNER = 2;
36
- const NESTED_PADDING = 4;
37
- const NESTED_PADDING_TOP = 16 + NESTED_PADDING * 2;
38
- const NESTED_PADDING_LEFT = 8;
39
-
40
- /**
41
- * Resolve the tile's size using predefined values to avoid
42
- * computing the size of the content for every tile
43
- */
44
- const PADDING_TOP = 4;
45
- const PADDING_BOTTOM = 2; // substracted to allow longer texts to appear
46
- const PADDING_LEFT = 2;
47
- const PADDING_RIGHT = 4; // substracted to allow longer texts to not break
48
- const VERTICAL_SPACING = 4;
49
- const LINE_HEIGHT = 16;
50
- const LINE_HEIGHT_SMALL = 13.3;
51
-
52
- function resolveTileGroupSizeDisplay(width: number, height: number): TileSizeDisplay {
53
- if (height < NESTED_PADDING_TOP || width < 24) {
54
- return 'minimal';
55
- }
56
-
57
- if (height < NESTED_PADDING_TOP + 8) {
58
- return 'small';
59
- }
60
-
61
- return 'default';
62
- }
63
-
64
- type TileSizeDisplay = 'minimal' | 'small' | 'default';
65
-
66
- function resolveTileSizeDisplay(width: number, height: number): TileSizeDisplay {
67
- if (
68
- height > PADDING_TOP + PADDING_BOTTOM + VERTICAL_SPACING + LINE_HEIGHT * 2 &&
69
- width > PADDING_LEFT + PADDING_RIGHT + 128
70
- ) {
71
- return 'default';
72
- }
73
-
74
- if (
75
- height > PADDING_TOP + PADDING_BOTTOM + LINE_HEIGHT_SMALL * 2 &&
76
- width > PADDING_LEFT + PADDING_BOTTOM + 48
77
- ) {
78
- return 'small';
79
- }
80
-
81
- return 'minimal';
82
- }
43
+ import {
44
+ resolveGroupDeltaType,
45
+ resolveTileSizeDisplay,
46
+ resolveTileGroupSizeDisplay,
47
+ useTooltipStateWithMouseFollow,
48
+ } from './metrics-treemap.utils';
83
49
 
84
50
  interface TileTooltipContentProps {
85
51
  item: ReportMetricRow;
@@ -118,7 +84,7 @@ interface TileContentProps {
118
84
  /**
119
85
  * The estimated size of the tile
120
86
  */
121
- sizeDisplay: 'minimal' | 'small' | 'default';
87
+ sizeDisplay: TileSizeDisplay;
122
88
  /**
123
89
  * Metric run info
124
90
  */
@@ -128,23 +94,33 @@ interface TileContentProps {
128
94
  const TileContent = forwardRef((props: TileContentProps, ref: Ref<HTMLDivElement>) => {
129
95
  const { label, sizeDisplay, item, runInfo } = props;
130
96
 
97
+ // Render only the container
131
98
  if (sizeDisplay === 'minimal') {
132
99
  return <div className={css.tileContent} ref={ref} />;
133
100
  }
134
101
 
102
+ const resolvedLabel = label || item.label;
103
+
104
+ // Render only the label
105
+ if (sizeDisplay === 'small') {
106
+ return (
107
+ <div className={css.tileContent} ref={ref}>
108
+ <p className={css.tileContentLabel}>{resolvedLabel}</p>
109
+ </div>
110
+ );
111
+ }
112
+
135
113
  return (
136
114
  <div className={css.tileContent} ref={ref}>
137
- <FileName as="p" className={css.tileContentLabel} name={label || item.label} />
138
- {sizeDisplay !== 'small' && (
139
- <p className={css.tileContentValue}>
140
- <span className={css.tileContentMetric}>{runInfo.displayValue}</span>
141
- <Delta
142
- className={css.tileContentDelta}
143
- displayValue={runInfo.displayDeltaPercentage}
144
- deltaType={runInfo.deltaType}
145
- />
146
- </p>
147
- )}
115
+ <p className={css.tileContentLabel}>{label || item.label}</p>
116
+ <p className={css.tileContentValue}>
117
+ <span className={css.tileContentMetric}>{runInfo.displayValue}</span>
118
+ <Delta
119
+ className={css.tileContentDelta}
120
+ displayValue={runInfo.displayDeltaPercentage}
121
+ deltaType={runInfo.deltaType}
122
+ />
123
+ </p>
148
124
  </div>
149
125
  );
150
126
  });
@@ -152,29 +128,7 @@ const TileContent = forwardRef((props: TileContentProps, ref: Ref<HTMLDivElement
152
128
  const TileContentWithTooltip = (props: TileContentProps & { parentRef: RefObject<Element> }) => {
153
129
  const { label, sizeDisplay, item, runInfo, parentRef } = props;
154
130
 
155
- const pointer = useMouseHovered(parentRef, { whenHovered: true });
156
-
157
- // Return custom rect based on the mouse position
158
- const getAnchorRect = useCallback(() => {
159
- // Skip custom component rect area if the pointer position is empty
160
- if (pointer.docX === 0 && pointer.docY === 0 && pointer.elW === 0 && pointer.elH === 0) {
161
- return null;
162
- }
163
-
164
- const newRect = {
165
- x: pointer.docX - (document?.defaultView?.scrollX ?? 0),
166
- y: pointer.docY - (document?.defaultView?.scrollY ?? 0),
167
- w: 1,
168
- h: 1,
169
- };
170
-
171
- return newRect;
172
- }, [pointer.docX, pointer.docY]);
173
-
174
- const tooltipState = useTooltipState({ gutter: 12, getAnchorRect, timeout: 120 });
175
-
176
- // Update tooltip position when poiner values are changing
177
- useDebounce(tooltipState.render, 5, [pointer.docX, pointer.docY]);
131
+ const tooltipState = useTooltipStateWithMouseFollow({ parentRef });
178
132
 
179
133
  return (
180
134
  <>
@@ -221,7 +175,7 @@ const Tile = (props: TileProps) => {
221
175
  css[`tile-${runInfo.deltaType}`],
222
176
  sizeDisplay === 'small' && css.tileSizeSmall,
223
177
  sizeDisplay === 'default' && css.tileSizeDefault,
224
- left === 0 && css.tileFirstCol,
178
+ left === PADDING_INNER && css.tileFirstCol,
225
179
  );
226
180
 
227
181
  /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/interactive-supports-focus */
@@ -249,6 +203,96 @@ const Tile = (props: TileProps) => {
249
203
  );
250
204
  };
251
205
 
206
+ interface TileGroupTitleTooltipContentProps {
207
+ title: string;
208
+ runInfo: MetricRunInfo;
209
+ baselineDisplayValue?: string;
210
+ }
211
+
212
+ const TileGroupTitleTooltipContent = (props: TileGroupTitleTooltipContentProps) => {
213
+ const { title, runInfo, baselineDisplayValue } = props;
214
+
215
+ return (
216
+ <Stack space="small" className={css.tileTooltip}>
217
+ <h3 className={css.tileTooltipContentTitle}>
218
+ <FileName as="code" name={title} />
219
+ </h3>
220
+ <RunInfo
221
+ current={runInfo.displayValue}
222
+ baseline={baselineDisplayValue}
223
+ delta={runInfo.displayDeltaPercentage}
224
+ deltaType={runInfo.deltaType}
225
+ />
226
+ </Stack>
227
+ );
228
+ };
229
+
230
+ interface TileGroupTitleContentProps {
231
+ title?: string;
232
+ runInfo?: MetricRunInfo;
233
+ }
234
+
235
+ const TileGroupTitleContent = (props: TileGroupTitleContentProps) => {
236
+ const { title, runInfo } = props;
237
+
238
+ return (
239
+ <div className={css.tileGroupTitleContent}>
240
+ {title && <span className={css.tileGroupTitleText}>{title}</span>}
241
+ {runInfo && (
242
+ <span className={css.tileGroupTitleTotal}>
243
+ {runInfo.displayValue}
244
+ {'displayDelta' in runInfo && `(${runInfo.displayDeltaPercentage})`}
245
+ </span>
246
+ )}
247
+ </div>
248
+ );
249
+ };
250
+
251
+ type TileGroupTitleContentWithTooltipProps = {
252
+ parentRef: RefObject<Element>;
253
+ tooltipContent: TileGroupTitleTooltipContentProps;
254
+ } & TileGroupTitleContentProps;
255
+
256
+ const TileGroupTitleContentWithTooltip = (props: TileGroupTitleContentWithTooltipProps) => {
257
+ const { parentRef, tooltipContent, ...restProps } = props;
258
+
259
+ const tooltipState = useTooltipStateWithMouseFollow({ parentRef });
260
+
261
+ return (
262
+ <>
263
+ <TooltipAnchor state={tooltipState} className={css.tileContentTooltipAnchor}>
264
+ <TileGroupTitleContent {...restProps} />
265
+ </TooltipAnchor>
266
+ <Tooltip state={tooltipState} className={css.tooltip}>
267
+ <TooltipArrow state={tooltipState} size={16} className={css.tileTooltipArrow} />
268
+ <TileGroupTitleTooltipContent {...tooltipContent} />
269
+ </Tooltip>
270
+ </>
271
+ );
272
+ };
273
+
274
+ type TileGroupTitleProps = Omit<TileGroupTitleContentWithTooltipProps, 'parentRef'>;
275
+
276
+ const TileGroupTitle = (props: TileGroupTitleProps) => {
277
+ const { tooltipContent, ...restProps } = props;
278
+ const contentRef = useRef<HTMLDivElement>(null);
279
+ const hover = useHoverDirty(contentRef);
280
+
281
+ return (
282
+ <div className={css.tileGroupTitle} ref={contentRef}>
283
+ {hover ? (
284
+ <TileGroupTitleContentWithTooltip
285
+ parentRef={contentRef}
286
+ tooltipContent={tooltipContent}
287
+ {...restProps}
288
+ />
289
+ ) : (
290
+ <TileGroupTitleContent {...restProps} />
291
+ )}
292
+ </div>
293
+ );
294
+ };
295
+
252
296
  interface TileGroupProps extends ComponentProps<'div'> {
253
297
  /**
254
298
  * Node title
@@ -323,11 +367,36 @@ const TileGroup = (props: TileGroupProps) => {
323
367
  [width, height],
324
368
  );
325
369
 
326
- const metricRunInfo =
327
- total &&
328
- getMetricRunInfo(METRIC_TYPE_CONFIGS.METRIC_TYPE_FILE_SIZE, total.current, total.baseline);
329
- const groupDeltaType = resolveGroupDeltaType(metricRunInfo);
330
- const rootClassName = cx(css.tileGroup, css[`tileGroup--${groupDeltaType}`]);
370
+ // Prepare data
371
+ const [runInfo, baselineDisplayValue, deltaType] = useMemo(() => {
372
+ if (!total) {
373
+ return [];
374
+ }
375
+
376
+ const resolvedRunInfo = getMetricRunInfo(
377
+ METRIC_TYPE_CONFIGS.METRIC_TYPE_FILE_SIZE,
378
+ total.current,
379
+ total.baseline,
380
+ ) as MetricRunInfo;
381
+ const resolvedBaselineDisplayValue = formatFileSize(total.baseline);
382
+ const resolvedDeltaType = resolveGroupDeltaType(resolvedRunInfo);
383
+
384
+ return [resolvedRunInfo, resolvedBaselineDisplayValue, resolvedDeltaType];
385
+ }, [total]);
386
+
387
+ const rootClassName = cx(
388
+ css.tileGroup,
389
+ css[`tileGroup--${deltaType}`],
390
+ css[`tileGroup--${displaySize}`],
391
+ );
392
+
393
+ // Tooltip data
394
+ // - by default show the node id (full path) as title
395
+ const tooltipContent = {
396
+ title: id || title,
397
+ runInfo,
398
+ baselineDisplayValue,
399
+ } as TileGroupTitleTooltipContentProps;
331
400
 
332
401
  if (title && displaySize === 'minimal') {
333
402
  return (
@@ -337,7 +406,9 @@ const TileGroup = (props: TileGroupProps) => {
337
406
  aria-label={I18N.TILE_GROUP_LABEL}
338
407
  className={rootClassName}
339
408
  style={{ left, top, width, height }}
340
- />
409
+ >
410
+ <TileGroupTitle tooltipContent={tooltipContent} />
411
+ </div>
341
412
  );
342
413
  }
343
414
 
@@ -350,7 +421,7 @@ const TileGroup = (props: TileGroupProps) => {
350
421
  style={{ left, top, width, height }}
351
422
  className={rootClassName}
352
423
  >
353
- <div className={css.tileGroupTitle}>{title}</div>
424
+ <TileGroupTitle title={title} tooltipContent={tooltipContent} />
354
425
  </div>
355
426
  );
356
427
  }
@@ -363,17 +434,7 @@ const TileGroup = (props: TileGroupProps) => {
363
434
  className={cx(rootClassName, css.tileGroupSizeDefault)}
364
435
  style={{ left, top, width, height }}
365
436
  >
366
- {title && (
367
- <div className={css.tileGroupTitle}>
368
- {title}
369
- {metricRunInfo && (
370
- <span className={css.tileGroupTitleTotal}>
371
- {`${metricRunInfo.displayValue}`}
372
- {'displayDelta' in metricRunInfo && ` (${metricRunInfo.displayDeltaPercentage})`}
373
- </span>
374
- )}
375
- </div>
376
- )}
437
+ <TileGroupTitle title={title} runInfo={runInfo} tooltipContent={tooltipContent} />
377
438
  {childNodes?.map((childNode) => {
378
439
  if ('children' in childNode) {
379
440
  const groupData = childNode.data as Tree;
@@ -1,3 +1,6 @@
1
+ import { type RefObject, useCallback } from 'react';
2
+ import { useDebounce, useMouseHovered } from 'react-use';
3
+ import { useTooltipState } from 'ariakit/tooltip';
1
4
  import {
2
5
  DeltaType,
3
6
  type MetricRunInfoBaseline,
@@ -5,7 +8,15 @@ import {
5
8
  type ReportMetricRow,
6
9
  } from '@bundle-stats/utils';
7
10
 
8
- import type { TreeLeaf, TreeNodeChildren, Tree, TreeTotal } from './metrics-treemap.constants';
11
+ import {
12
+ type TreeLeaf,
13
+ type TreeNodeChildren,
14
+ type Tree,
15
+ type TreeTotal,
16
+ type TileSizeDisplay,
17
+ type TileGroupSizeDisplay,
18
+ NESTED_PADDING_TOP,
19
+ } from './metrics-treemap.constants';
9
20
 
10
21
  const ROOT_LABEL = '(root)';
11
22
 
@@ -160,3 +171,98 @@ export function resolveGroupDeltaType(
160
171
 
161
172
  return DeltaType.NO_CHANGE;
162
173
  }
174
+
175
+ /**
176
+ * Resolve the tile's size using predefined values to avoid
177
+ * computing the size of the content for every tile
178
+ */
179
+ const PADDING_TOP = 8;
180
+ const PADDING_BOTTOM = 8;
181
+ const PADDING_LEFT = 8;
182
+ const PADDING_RIGHT = 8;
183
+ const LINE_HEIGHT = 16;
184
+ const LINE_HEIGHT_SMALL = 13.3;
185
+
186
+ export function resolveTileGroupSizeDisplay(width: number, height: number): TileGroupSizeDisplay {
187
+ if (height < NESTED_PADDING_TOP) {
188
+ return 'minimal';
189
+ }
190
+
191
+ if (width < 24) {
192
+ return 'minimal';
193
+ }
194
+
195
+ if (height < NESTED_PADDING_TOP + 8) {
196
+ return 'small';
197
+ }
198
+
199
+ return 'default';
200
+ }
201
+
202
+ export function resolveTileSizeDisplay(width: number, height: number): TileSizeDisplay {
203
+ if (height < PADDING_TOP + PADDING_BOTTOM + LINE_HEIGHT_SMALL) {
204
+ return 'minimal';
205
+ }
206
+
207
+ if (width < PADDING_LEFT + PADDING_RIGHT + 42) {
208
+ return 'minimal';
209
+ }
210
+
211
+ if (height < PADDING_TOP + PADDING_TOP + LINE_HEIGHT * 2) {
212
+ return 'small';
213
+ }
214
+
215
+ if (width < PADDING_LEFT + PADDING_RIGHT + 96) {
216
+ return 'small';
217
+ }
218
+
219
+ return 'default';
220
+ }
221
+
222
+ interface UseTooltipStateWithMouseFollowOptions {
223
+ /**
224
+ * React ref to parent div
225
+ */
226
+ parentRef: RefObject<Element>;
227
+ /**
228
+ * Tooltip gutter
229
+ */
230
+ gutter?: number;
231
+ /**
232
+ * Tooltip timeout
233
+ */
234
+ timeout?: number;
235
+ }
236
+
237
+ /**
238
+ * Ariakit tooltip state hook with mouse follow functionality
239
+ */
240
+ export function useTooltipStateWithMouseFollow(options: UseTooltipStateWithMouseFollowOptions) {
241
+ const { parentRef, gutter = 16, timeout = 180 } = options;
242
+
243
+ const pointer = useMouseHovered(parentRef, { whenHovered: true });
244
+
245
+ // Return custom rect based on the mouse position
246
+ const getAnchorRect = useCallback(() => {
247
+ // Skip custom component rect area if the pointer position is empty
248
+ if (pointer.docX === 0 && pointer.docY === 0 && pointer.elW === 0 && pointer.elH === 0) {
249
+ return null;
250
+ }
251
+
252
+ const newRect = {
253
+ x: pointer.docX - (document?.defaultView?.scrollX ?? 0),
254
+ y: pointer.docY - (document?.defaultView?.scrollY ?? 0),
255
+ w: 1,
256
+ h: 1,
257
+ };
258
+
259
+ return newRect;
260
+ }, [pointer.docX, pointer.docY]);
261
+
262
+ const tooltipState = useTooltipState({ gutter, getAnchorRect, timeout });
263
+
264
+ // Update tooltip position when pointer values change
265
+ useDebounce(tooltipState.render, 10, [pointer.docX, pointer.docY]);
266
+
267
+ return tooltipState;
268
+ }
@@ -0,0 +1,19 @@
1
+ import chunk from 'lodash/chunk';
2
+
3
+ import COLORS from '../chart-colors.json';
4
+
5
+ export function getColors(count = 2) {
6
+ const chunks = chunk(COLORS, Math.round(COLORS.length / count));
7
+
8
+ return chunks.map((chunkColors, index) => {
9
+ if (index === 0) {
10
+ return chunkColors[0];
11
+ }
12
+
13
+ if (index === chunks.length - 1) {
14
+ return chunkColors[chunkColors.length - 1];
15
+ }
16
+
17
+ return chunkColors[Math.floor(chunkColors.length / 2)];
18
+ });
19
+ }
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import cx from 'classnames';
3
+
4
+ export const getRenderChildWithClassName = (className: string) => (child: any) => {
5
+ if (child === null || child === '') {
6
+ return null;
7
+ }
8
+
9
+ const { props } = child;
10
+
11
+ if (!props) {
12
+ return <div className={className}>{child}</div>;
13
+ }
14
+
15
+ return React.cloneElement(child, {
16
+ ...props,
17
+ className: cx(className, props.className), // eslint-disable-line react/prop-types
18
+ });
19
+ };
@@ -0,0 +1,3 @@
1
+ export * from './colors';
2
+ export * from './jobs';
3
+ export * from './components';
@@ -0,0 +1,22 @@
1
+ import uniqBy from 'lodash/uniqBy';
2
+
3
+ import type { Job, WebpackChunk } from '@bundle-stats/utils';
4
+
5
+ interface GetJobsChunksData {
6
+ chunks: Array<WebpackChunk>;
7
+ chunkIds: Array<string>;
8
+ }
9
+
10
+ /**
11
+ * Get chunks data from all jobs
12
+ */
13
+ export function getJobsChunksData(jobs: Array<Job>): GetJobsChunksData {
14
+ const jobChunks = jobs.map((job) => job?.meta?.webpack?.chunks || []);
15
+ const chunks = uniqBy(jobChunks.flat(), ({ id }) => id);
16
+ const chunkIds = chunks?.map(({ id }) => id);
17
+
18
+ return {
19
+ chunks,
20
+ chunkIds,
21
+ };
22
+ }
@@ -13,12 +13,8 @@ export namespace BundleAssets {
13
13
  export let jobs: PropTypes.Validator<(PropTypes.InferProps<{
14
14
  internalBuildNumber: PropTypes.Requireable<number>;
15
15
  label: PropTypes.Requireable<string>;
16
- meta: PropTypes.Requireable<PropTypes.InferProps<{
17
- webpack: PropTypes.Requireable<PropTypes.InferProps<{
18
- chunks: PropTypes.Requireable<any[]>;
19
- }>>;
20
- }>>;
21
16
  }> | null | undefined)[]>;
17
+ export let chunks: PropTypes.Validator<any[]>;
22
18
  export let items: PropTypes.Validator<(PropTypes.InferProps<{
23
19
  key: PropTypes.Requireable<string>;
24
20
  label: PropTypes.Requireable<string>;
@@ -1,12 +1,14 @@
1
1
  import React from 'react';
2
+ import { type Job } from '@bundle-stats/utils';
3
+ import { WebpackChunk } from '@bundle-stats/utils';
2
4
  import { SortAction } from '../../types';
3
5
  import { ModuleMetric } from './bundle-modules.constants';
4
- import type { Chunk, Job, ReportMetricModuleRow } from './bundle-modules.types';
6
+ import type { ReportMetricModuleRow } from './bundle-modules.types';
5
7
  interface BundleModulesProps extends React.ComponentProps<'div'> {
6
8
  jobs?: Array<Job>;
7
9
  items?: Array<ReportMetricModuleRow>;
8
10
  allItems?: Array<ReportMetricModuleRow>;
9
- chunks?: Array<Chunk>;
11
+ chunks?: Array<WebpackChunk>;
10
12
  totalRowCount: number;
11
13
  updateFilters: () => void;
12
14
  resetFilters: () => void;
@@ -1,16 +1,12 @@
1
- import type { ReportMetricRow } from '@bundle-stats/utils';
1
+ import { type WebpackChunk, type ReportMetricRow } from '@bundle-stats/utils';
2
2
  import { type Module } from '@bundle-stats/utils/lib-esm/webpack';
3
3
  import type { FilterFieldsData } from '../../types';
4
- import type { Chunk, Job, ReportMetricModuleRow } from './bundle-modules.types';
4
+ import type { ReportMetricModuleRow } from './bundle-modules.types';
5
5
  export declare const addRowFlags: (row: Module & ReportMetricRow) => ReportMetricModuleRow;
6
6
  export declare const getCustomSort: (item: ReportMetricRow) => (string | boolean)[];
7
7
  export declare const generateGetRowFilter: ({ chunkIds }: {
8
8
  chunkIds: Array<string>;
9
9
  }) => (filters: Record<string, unknown>) => (row: ReportMetricModuleRow) => boolean;
10
- export declare const extractChunkData: (jobs: Array<Job>) => {
11
- chunks: Chunk[];
12
- chunkIds: string[];
13
- };
14
10
  export declare const generateFilters: (chunkIds: Array<string>, multipleJobs: boolean) => {
15
11
  defaultFilters: {
16
12
  [x: string]: boolean;
@@ -21,7 +17,7 @@ export declare const generateFilters: (chunkIds: Array<string>, multipleJobs: bo
21
17
  };
22
18
  interface GetFiltersFormDataParams {
23
19
  filters: Record<string, boolean>;
24
- chunks: Array<Chunk>;
20
+ chunks: Array<WebpackChunk>;
25
21
  compareMode: boolean;
26
22
  }
27
23
  export declare const generateFilterFieldsData: (params: GetFiltersFormDataParams) => FilterFieldsData;
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
+ import type { Job } from '@bundle-stats/utils';
2
3
  import type { SortAction } from '../../types';
3
4
  import { BundleModules as BaseComponent } from './bundle-modules';
4
- import * as types from './bundle-modules.types';
5
5
  interface BundleModulesProps extends Omit<React.ComponentProps<typeof BaseComponent>, 'jobs' | 'items' | 'chunks' | 'updateFilters' | 'resetFilters' | 'resetAllFilters' | 'filters' | 'sort' | 'updateSort' | 'search' | 'updateSearch' | 'allItems' | 'totalRowCount' | 'hideEntryInfo' | 'showEntryInfo'> {
6
- jobs: Array<types.Job>;
6
+ jobs: Array<Job>;
7
7
  filters: Record<string, boolean>;
8
8
  search?: string;
9
9
  metric?: string;
@@ -18,3 +18,11 @@ export interface Tree {
18
18
  }
19
19
  export type TreeNode = Tree | TreeLeaf;
20
20
  export type TreeNodeChildren = Array<TreeNode>;
21
+ export type TileGroupSizeDisplay = 'minimal' | 'small' | 'default';
22
+ export type TileSizeDisplay = 'minimal' | 'small' | 'default';
23
+ export declare const SQUARIFY_RATIO = 1.66;
24
+ export declare const PADDING_OUTER = 1;
25
+ export declare const PADDING_INNER = 2;
26
+ export declare const NESTED_PADDING = 4;
27
+ export declare const NESTED_PADDING_TOP: number;
28
+ export declare const NESTED_PADDING_LEFT = 8;
@@ -1,5 +1,5 @@
1
1
  import React, { type ComponentProps, type ReactNode } from 'react';
2
- import type { Tree } from './metrics-treemap.constants';
2
+ import { type Tree } from './metrics-treemap.constants';
3
3
  interface MetricsTreemapProps {
4
4
  treeNodes: Tree;
5
5
  emptyMessage?: ReactNode;
@@ -1,5 +1,15 @@
1
+ import { type RefObject } from 'react';
1
2
  import { DeltaType, type MetricRunInfoBaseline, type MetricRunInfo, type ReportMetricRow } from '@bundle-stats/utils';
2
- import type { Tree } from './metrics-treemap.constants';
3
+ import { type Tree, type TileSizeDisplay, type TileGroupSizeDisplay } from './metrics-treemap.constants';
3
4
  export declare function getTreemapNodes(items: Array<ReportMetricRow>): Tree;
4
5
  export declare function getTreemapNodesGroupedByPath(items: Array<ReportMetricRow>): Tree;
5
6
  export declare function resolveGroupDeltaType(metricRunInfo?: MetricRunInfo | MetricRunInfoBaseline): DeltaType.NO_CHANGE | DeltaType.NEGATIVE | DeltaType.POSITIVE;
7
+ export declare function resolveTileGroupSizeDisplay(width: number, height: number): TileGroupSizeDisplay;
8
+ export declare function resolveTileSizeDisplay(width: number, height: number): TileSizeDisplay;
9
+ interface UseTooltipStateWithMouseFollowOptions {
10
+ parentRef: RefObject<Element>;
11
+ gutter?: number;
12
+ timeout?: number;
13
+ }
14
+ export declare function useTooltipStateWithMouseFollow(options: UseTooltipStateWithMouseFollowOptions): import("ariakit/tooltip").TooltipState;
15
+ export {};
@@ -0,0 +1 @@
1
+ export declare function getColors(count?: number): string[];
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const getRenderChildWithClassName: (className: string) => (child: any) => React.JSX.Element | null;
@@ -0,0 +1,3 @@
1
+ export * from './colors';
2
+ export * from './jobs';
3
+ export * from './components';