@bundle-stats/ui 3.3.0-alpha.1 → 3.4.0-alpha.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 (178) hide show
  1. package/CHANGELOG.md +94 -13
  2. package/lib/app/app.js +137 -102
  3. package/lib/app/app.module.css +11 -4
  4. package/lib/app/header/header.js +1 -10
  5. package/lib/components/asset-info/asset-info.module.css +1 -0
  6. package/lib/components/bundle-assets/bundle-assets.js +104 -52
  7. package/lib/components/bundle-assets/bundle-assets.module.css +24 -26
  8. package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.js +13 -3
  9. package/lib/components/bundle-modules/bundle-modules.js +53 -67
  10. package/lib/components/bundle-packages/bundle-packages.js +100 -44
  11. package/lib/components/bundle-packages/bundle-packages.module.css +17 -21
  12. package/lib/components/delta/delta.module.css +1 -0
  13. package/lib/components/job-header/job-header.js +3 -1
  14. package/lib/components/job-header/job-header.module.css +6 -8
  15. package/lib/components/jobs-header/jobs-header.module.css +5 -0
  16. package/lib/components/metrics-table/metrics-table.js +72 -59
  17. package/lib/components/metrics-table/metrics-table.module.css +18 -7
  18. package/lib/components/metrics-table-search/metrics-table-search.module.css +5 -4
  19. package/lib/components/metrics-table-title/metrics-table-title.js +9 -7
  20. package/lib/components/metrics-table-title/metrics-table-title.module.css +2 -0
  21. package/lib/components/module-info/module-info.js +2 -2
  22. package/lib/components/module-info/module-info.module.css +1 -0
  23. package/lib/components/summary/summary.js +1 -1
  24. package/lib/components/summary-item/summary-item.js +15 -18
  25. package/lib/components/summary-item/summary-item.module.css +1 -23
  26. package/lib/components/total-size-type-title/total-size-type-title.js +7 -3
  27. package/lib/css/default.css +14 -3
  28. package/lib/css/variables.css +17 -17
  29. package/lib/hooks/search-params.js +31 -31
  30. package/lib/layout/box/box.module.css +9 -0
  31. package/lib/layout/footer/footer.module.css +1 -1
  32. package/lib/layout/index.js +8 -0
  33. package/lib/layout/separator.js +48 -0
  34. package/lib/layout/separator.module.css +5 -0
  35. package/lib/ui/dropdown/dropdown.js +21 -26
  36. package/lib/ui/dropdown/dropdown.module.css +11 -12
  37. package/lib/ui/dropdown/dropdown.stories.js +2 -9
  38. package/lib/ui/empty-set/empty-set.js +5 -4
  39. package/lib/ui/empty-set/empty-set.module.css +2 -2
  40. package/lib/ui/filters/filters.container.js +1 -1
  41. package/lib/ui/filters/filters.js +22 -7
  42. package/lib/ui/filters/filters.module.css +3 -3
  43. package/lib/ui/horizontal-bar-chart/horizontal-bar-chart.js +1 -1
  44. package/lib/ui/hover-card/hover-card.js +102 -0
  45. package/lib/ui/hover-card/hover-card.module.css +29 -0
  46. package/lib/ui/hover-card/hover-card.stories.js +56 -0
  47. package/lib/ui/hover-card/index.js +18 -0
  48. package/lib/ui/icon/icon.js +6 -6
  49. package/lib/ui/icon/icon.module.css +1 -0
  50. package/lib/ui/index.js +8 -8
  51. package/lib/ui/table/table.js +5 -74
  52. package/lib/ui/table/table.module.css +41 -25
  53. package/lib/ui/table/table.stories.js +1 -1
  54. package/lib/ui/{popover → tag}/index.js +4 -4
  55. package/lib/ui/tag/tag.js +72 -0
  56. package/lib/ui/tag/tag.module.css +55 -0
  57. package/lib/ui/tag/tag.stories.js +38 -0
  58. package/lib/ui/tooltip/tooltip.js +10 -9
  59. package/lib/ui/tooltip/tooltip.module.css +2 -1
  60. package/lib-esm/app/app.js +132 -102
  61. package/lib-esm/app/app.module.css +11 -4
  62. package/lib-esm/app/header/header.js +1 -9
  63. package/lib-esm/components/asset-info/asset-info.module.css +1 -0
  64. package/lib-esm/components/bundle-assets/bundle-assets.js +97 -56
  65. package/lib-esm/components/bundle-assets/bundle-assets.module.css +24 -26
  66. package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.js +7 -3
  67. package/lib-esm/components/bundle-modules/bundle-modules.js +35 -50
  68. package/lib-esm/components/bundle-packages/bundle-packages.js +88 -41
  69. package/lib-esm/components/bundle-packages/bundle-packages.module.css +17 -21
  70. package/lib-esm/components/delta/delta.module.css +1 -0
  71. package/lib-esm/components/job-header/job-header.js +2 -1
  72. package/lib-esm/components/job-header/job-header.module.css +6 -8
  73. package/lib-esm/components/jobs-header/jobs-header.module.css +5 -0
  74. package/lib-esm/components/metrics-table/metrics-table.js +61 -53
  75. package/lib-esm/components/metrics-table/metrics-table.module.css +18 -7
  76. package/lib-esm/components/metrics-table-search/metrics-table-search.module.css +5 -4
  77. package/lib-esm/components/metrics-table-title/metrics-table-title.js +8 -7
  78. package/lib-esm/components/metrics-table-title/metrics-table-title.module.css +2 -0
  79. package/lib-esm/components/module-info/module-info.js +2 -2
  80. package/lib-esm/components/module-info/module-info.module.css +1 -0
  81. package/lib-esm/components/summary/summary.js +1 -1
  82. package/lib-esm/components/summary-item/summary-item.js +14 -18
  83. package/lib-esm/components/summary-item/summary-item.module.css +1 -23
  84. package/lib-esm/components/total-size-type-title/total-size-type-title.js +6 -3
  85. package/lib-esm/css/default.css +14 -3
  86. package/lib-esm/css/variables.css +17 -17
  87. package/lib-esm/hooks/search-params.js +27 -28
  88. package/lib-esm/layout/box/box.module.css +9 -0
  89. package/lib-esm/layout/footer/footer.module.css +1 -1
  90. package/lib-esm/layout/index.js +1 -0
  91. package/lib-esm/layout/separator.js +28 -0
  92. package/lib-esm/layout/separator.module.css +5 -0
  93. package/lib-esm/ui/dropdown/dropdown.js +20 -25
  94. package/lib-esm/ui/dropdown/dropdown.module.css +11 -12
  95. package/lib-esm/ui/dropdown/dropdown.stories.js +2 -7
  96. package/lib-esm/ui/empty-set/empty-set.js +4 -4
  97. package/lib-esm/ui/empty-set/empty-set.module.css +2 -2
  98. package/lib-esm/ui/filters/filters.js +20 -5
  99. package/lib-esm/ui/filters/filters.module.css +3 -3
  100. package/lib-esm/ui/hover-card/hover-card.js +83 -0
  101. package/lib-esm/ui/hover-card/hover-card.module.css +29 -0
  102. package/lib-esm/ui/hover-card/hover-card.stories.js +35 -0
  103. package/lib-esm/ui/hover-card/index.js +1 -0
  104. package/lib-esm/ui/icon/icon.js +3 -3
  105. package/lib-esm/ui/icon/icon.module.css +1 -0
  106. package/lib-esm/ui/index.js +1 -1
  107. package/lib-esm/ui/table/table.js +5 -65
  108. package/lib-esm/ui/table/table.module.css +41 -25
  109. package/lib-esm/ui/table/table.stories.js +1 -1
  110. package/lib-esm/ui/tag/index.js +1 -0
  111. package/lib-esm/ui/tag/tag.js +45 -0
  112. package/lib-esm/ui/tag/tag.module.css +55 -0
  113. package/lib-esm/ui/tag/tag.stories.js +23 -0
  114. package/lib-esm/ui/tooltip/tooltip.js +10 -9
  115. package/lib-esm/ui/tooltip/tooltip.module.css +2 -1
  116. package/package.json +33 -31
  117. package/src/app/app.jsx +142 -145
  118. package/src/app/app.module.css +11 -4
  119. package/src/app/header/header.jsx +0 -10
  120. package/src/components/asset-info/asset-info.module.css +1 -0
  121. package/src/components/bundle-assets/bundle-assets.jsx +85 -31
  122. package/src/components/bundle-assets/bundle-assets.module.css +24 -26
  123. package/src/components/bundle-assets-totals-table/bundle-assets-totals-table.jsx +2 -0
  124. package/src/components/bundle-modules/bundle-modules.jsx +36 -36
  125. package/src/components/bundle-packages/bundle-packages.jsx +89 -39
  126. package/src/components/bundle-packages/bundle-packages.module.css +17 -21
  127. package/src/components/delta/delta.module.css +1 -0
  128. package/src/components/job-header/job-header.jsx +2 -1
  129. package/src/components/job-header/job-header.module.css +6 -8
  130. package/src/components/jobs-header/jobs-header.module.css +5 -0
  131. package/src/components/metrics-table/metrics-table.jsx +53 -44
  132. package/src/components/metrics-table/metrics-table.module.css +18 -7
  133. package/src/components/metrics-table-search/metrics-table-search.module.css +5 -4
  134. package/src/components/metrics-table-title/metrics-table-title.jsx +20 -21
  135. package/src/components/metrics-table-title/metrics-table-title.module.css +2 -0
  136. package/src/components/module-info/module-info.jsx +3 -7
  137. package/src/components/module-info/module-info.module.css +1 -0
  138. package/src/components/summary/summary.jsx +1 -1
  139. package/src/components/summary-item/summary-item.jsx +21 -27
  140. package/src/components/summary-item/summary-item.module.css +1 -23
  141. package/src/components/total-size-type-title/total-size-type-title.jsx +6 -9
  142. package/src/css/default.css +14 -3
  143. package/src/css/variables.css +17 -17
  144. package/src/hooks/search-params.js +42 -33
  145. package/src/layout/box/box.module.css +9 -0
  146. package/src/layout/footer/footer.module.css +1 -1
  147. package/src/layout/index.js +1 -0
  148. package/src/layout/separator.jsx +25 -0
  149. package/src/layout/separator.module.css +5 -0
  150. package/src/ui/dropdown/dropdown.jsx +16 -22
  151. package/src/ui/dropdown/dropdown.module.css +11 -12
  152. package/src/ui/empty-set/empty-set.jsx +25 -21
  153. package/src/ui/empty-set/empty-set.module.css +2 -2
  154. package/src/ui/filters/filters.jsx +64 -53
  155. package/src/ui/filters/filters.module.css +3 -3
  156. package/src/ui/hover-card/hover-card.jsx +73 -0
  157. package/src/ui/hover-card/hover-card.module.css +29 -0
  158. package/src/ui/hover-card/index.js +1 -0
  159. package/src/ui/icon/icon.jsx +11 -7
  160. package/src/ui/icon/icon.module.css +1 -0
  161. package/src/ui/index.js +1 -1
  162. package/src/ui/table/table.jsx +5 -52
  163. package/src/ui/table/table.module.css +41 -25
  164. package/src/ui/tag/index.js +1 -0
  165. package/src/ui/tag/tag.jsx +49 -0
  166. package/src/ui/tag/tag.module.css +55 -0
  167. package/src/ui/tooltip/tooltip.jsx +10 -14
  168. package/src/ui/tooltip/tooltip.module.css +2 -1
  169. package/lib/ui/popover/popover.js +0 -92
  170. package/lib/ui/popover/popover.module.css +0 -66
  171. package/lib/ui/popover/popover.stories.js +0 -26
  172. package/lib-esm/ui/popover/index.js +0 -1
  173. package/lib-esm/ui/popover/popover.js +0 -71
  174. package/lib-esm/ui/popover/popover.module.css +0 -66
  175. package/lib-esm/ui/popover/popover.stories.js +0 -14
  176. package/src/ui/popover/index.js +0 -1
  177. package/src/ui/popover/popover.jsx +0 -79
  178. package/src/ui/popover/popover.module.css +0 -66
@@ -7,8 +7,11 @@ const ACTION_RESET_DEFAULT = 'RESET_DEFAULT';
7
7
  const ACTION_RESET_ALL = 'RESET_ALL';
8
8
  const ACTION_SET = 'SET';
9
9
 
10
+ const SEARCH_DEFAULT = '';
11
+ const SEARCH_DEFAULT_PATTERN = /.*/;
12
+
10
13
  const getSearchPattern = (search) => {
11
- let searchPattern = /.*/;
14
+ let searchPattern = SEARCH_DEFAULT_PATTERN;
12
15
 
13
16
  if (!search || !search.trim()) {
14
17
  return searchPattern;
@@ -25,57 +28,57 @@ const getSearchPattern = (search) => {
25
28
  };
26
29
 
27
30
  const getSearchReducer =
28
- ({ defaultFilters, allEntriesFilters, setParentState }) => (state, action) => {
31
+ ({ defaultFilters, allEntriesFilters, setParentState }) =>
32
+ (state, action) => {
29
33
  const { type, payload } = action;
30
34
 
31
35
  switch (type) {
32
36
  case ACTION_SET_FILTERS: {
33
- setParentState({
37
+ const newState = {
34
38
  filters: payload,
35
39
  search: state.search,
36
- });
37
-
38
- return {
39
- ...state,
40
- filters: payload,
41
40
  };
41
+ setParentState(newState);
42
+ return newState;
42
43
  }
43
44
 
44
45
  case ACTION_SET_SEARCH: {
45
- setParentState({
46
+ const newState = {
46
47
  filters: state.filters,
47
48
  search: payload,
48
- });
49
+ };
50
+
51
+ setParentState(newState);
49
52
 
50
53
  return {
51
- ...state,
52
- search: payload,
54
+ ...newState,
53
55
  searchPattern: getSearchPattern(payload),
54
56
  };
55
57
  }
56
58
 
57
59
  case ACTION_RESET_DEFAULT: {
58
- setParentState({
60
+ const newState = {
59
61
  filters: defaultFilters,
60
- search: '',
61
- });
62
+ search: SEARCH_DEFAULT,
63
+ };
64
+
65
+ setParentState(newState);
62
66
 
63
67
  return {
64
- filters: defaultFilters,
65
- search: '',
68
+ ...newState,
66
69
  searchPattern: getSearchPattern(),
67
70
  };
68
71
  }
69
72
 
70
73
  case ACTION_RESET_ALL: {
71
- setParentState({
74
+ const newState = {
72
75
  filters: allEntriesFilters,
73
- search: '',
74
- });
76
+ search: SEARCH_DEFAULT,
77
+ };
78
+ setParentState(newState);
75
79
 
76
80
  return {
77
- filters: allEntriesFilters,
78
- search: '',
81
+ ...newState,
79
82
  searchPattern: getSearchPattern(),
80
83
  };
81
84
  }
@@ -96,7 +99,7 @@ export const generateState = (filters, search) => ({
96
99
  });
97
100
 
98
101
  export const useSearchParams = ({
99
- search: parentSearch,
102
+ search: parentSearch = SEARCH_DEFAULT,
100
103
 
101
104
  filters: parentFilters,
102
105
  defaultFilters,
@@ -116,29 +119,35 @@ export const useSearchParams = ({
116
119
  // Update state when the custom filters/search are changing - initial load or route updates
117
120
  useLayoutEffect(() => {
118
121
  // Run a deep comparison to prevent circular setState triggering
119
- if (parentSearch === search || isEqual(parentFilters, filters)) {
122
+ if (parentSearch === search && isEqual(initialFilters, filters)) {
120
123
  return;
121
124
  }
122
125
 
123
126
  dispatch({ type: ACTION_SET, payload: generateState(initialFilters, parentSearch) });
124
- }, [search, filters, parentFilters, parentSearch]);
127
+ }, [dispatch, search, filters, parentSearch, initialFilters]);
125
128
 
126
129
  /** Callbacks */
127
- const handleUpdateSearch = useCallback((newValue) => {
128
- dispatch({ type: ACTION_SET_SEARCH, payload: newValue });
129
- }, []);
130
+ const handleUpdateSearch = useCallback(
131
+ (newValue) => {
132
+ dispatch({ type: ACTION_SET_SEARCH, payload: newValue });
133
+ },
134
+ [dispatch],
135
+ );
130
136
 
131
- const handleUpdateFilters = useCallback((newFilters) => {
132
- dispatch({ type: ACTION_SET_FILTERS, payload: newFilters });
133
- }, []);
137
+ const handleUpdateFilters = useCallback(
138
+ (newFilters) => {
139
+ dispatch({ type: ACTION_SET_FILTERS, payload: newFilters });
140
+ },
141
+ [dispatch],
142
+ );
134
143
 
135
144
  const handleResetFilters = useCallback(() => {
136
145
  dispatch({ type: ACTION_RESET_DEFAULT });
137
- }, []);
146
+ }, [dispatch]);
138
147
 
139
148
  const handleResetAllFilters = useCallback(() => {
140
149
  dispatch({ type: ACTION_RESET_ALL });
141
- }, []);
150
+ }, [dispatch]);
142
151
 
143
152
  return {
144
153
  search,
@@ -4,6 +4,15 @@
4
4
 
5
5
  .outline {
6
6
  border: 1px solid var(--color-outline);
7
+ border-radius: var(--radius-medium);
8
+ }
9
+
10
+ .outline > :first-child {
11
+ border-radius: var(--radius-medium) var(--radius-medium) 0 0;
12
+ }
13
+
14
+ .outline > :last-child {
15
+ border-radius: 0 0 var(--radius-medium) var(--radius-medium);
7
16
  }
8
17
 
9
18
  .padding-xxxsmall {
@@ -3,7 +3,7 @@
3
3
  }
4
4
 
5
5
  .inner {
6
- border-top: 2px solid var(--color-outline);
6
+ border-top: 1px solid var(--color-outline);
7
7
  }
8
8
 
9
9
  .navItem {
@@ -1,6 +1,7 @@
1
1
  export { Box } from './box';
2
2
  export { Footer } from './footer';
3
3
  export { Header } from './header';
4
+ export { Separator } from './separator';
4
5
  export { SubHeader } from './sub-header';
5
6
  export { Stack } from './stack';
6
7
  export { FlexStack } from './flex-stack';
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import cx from 'classnames';
4
+
5
+ import css from './separator.module.css';
6
+
7
+ const propTypes = {
8
+ className: PropTypes.string,
9
+ };
10
+
11
+ const defaultProps = {
12
+ className: '',
13
+ };
14
+
15
+ /**
16
+ * @param {PropTypes.InferProps<typeof propTypes>} props
17
+ * @return {React.FunctionComponentElement}
18
+ */
19
+ export const Separator = (props) => {
20
+ const { className, ...restProps } = props;
21
+ return <div className={cx(css.root, className)} {...restProps} />;
22
+ };
23
+
24
+ Separator.propTypes = propTypes;
25
+ Separator.defaultProps = defaultProps;
@@ -0,0 +1,5 @@
1
+ .root {
2
+ background: var(--color-outline);
3
+ width: 100%;
4
+ height: 1px;
5
+ }
@@ -1,54 +1,54 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import cx from 'classnames';
4
- import { Menu, MenuItem, MenuButton, useMenuState } from 'reakit/Menu';
4
+ import { Menu, MenuButton, MenuItem, useMenuState } from 'ariakit/menu';
5
5
 
6
6
  import { FlexStack } from '../../layout/flex-stack';
7
7
  import { Icon } from '../icon';
8
8
  import css from './dropdown.module.css';
9
9
 
10
10
  export const Dropdown = (props) => {
11
- const { className, label, ariaLabel, glyph, activeLabel, children } = props;
12
- const rootClassName = cx(css.root, activeLabel && css.activeLabel, className);
13
-
14
- const menu = useMenuState({baseId: process.env.NODE_ENV === 'test' && 'id-test', modal: true });
11
+ const { className, buttonClassName, label, ariaLabel, glyph, children } = props;
12
+ const rootClassName = cx(css.root, className);
13
+ const menuState = useMenuState();
15
14
 
16
15
  return (
17
- <>
18
- <MenuButton {...menu} className={rootClassName} tabIndex={null}>
19
- <FlexStack space="xxxsmall" className={css.label}>
16
+ <div className={rootClassName}>
17
+ <MenuButton state={menuState} className={cx(css.button, buttonClassName)} tabIndex={null}>
18
+ <FlexStack space="xxxsmall">
20
19
  {glyph && <Icon className={css.labelIcon} glyph={glyph} />}
21
20
  {label}
22
21
  </FlexStack>
23
22
  </MenuButton>
24
- <Menu {...menu} aria-label={ariaLabel || label} className={css.dropdown}>
23
+ <Menu state={menuState} aria-label={ariaLabel || label} className={css.dropdown}>
25
24
  {typeof children === 'function'
26
- ?
27
- children({
25
+ ? children({
28
26
  MenuItem,
29
- menu,
27
+ menu: menuState,
30
28
  menuItemClassName: css.menuItem,
31
29
  menuItemActiveClassName: css.menuItemActive,
32
30
  })
33
- : children
34
- }
31
+ : children}
35
32
  </Menu>
36
- </>
33
+ </div>
37
34
  );
38
35
  };
39
36
 
40
37
  Dropdown.defaultProps = {
41
38
  className: '',
39
+ buttonClassName: '',
42
40
  label: null,
43
41
  ariaLabel: '',
44
42
  glyph: null,
45
- activeLabel: false,
46
43
  };
47
44
 
48
45
  Dropdown.propTypes = {
49
46
  /** Adopted child class name */
50
47
  className: PropTypes.string,
51
48
 
49
+ /** Button adopted child class name */
50
+ buttonClassName: PropTypes.string,
51
+
52
52
  /** Button label */
53
53
  label: PropTypes.node,
54
54
 
@@ -58,12 +58,6 @@ Dropdown.propTypes = {
58
58
  /** Icon glyph */
59
59
  glyph: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
60
60
 
61
- /** Dropdown open state */
62
- open: PropTypes.bool.isRequired,
63
-
64
- /** Active label flag */
65
- activeLabel: PropTypes.bool,
66
-
67
61
  /** Content */
68
62
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.element, PropTypes.func]).isRequired,
69
63
  };
@@ -1,16 +1,14 @@
1
1
  .root {
2
+ display: inline-block;
3
+ }
4
+
5
+ .button {
2
6
  background: none;
3
7
  border: none;
4
8
  padding: 0;
5
- }
6
-
7
- .root:focus {
8
- outline: none;
9
- box-shadow: 0 0 var(--space-xxxsmall) var(--color-shadow);
10
- }
11
9
 
12
- .label {
13
10
  border: 1px solid var(--color-outline);
11
+ border-radius: var(--radius-small);
14
12
  padding: calc(var(--space-xxsmall) - 1px);
15
13
  display: flex;
16
14
  align-items: center;
@@ -24,7 +22,11 @@
24
22
  color: var(--color-text-light);
25
23
  }
26
24
 
27
- .label:hover {
25
+ .button:hover,
26
+ .button:focus,
27
+ .button:active {
28
+ outline: none;
29
+ box-shadow: 0 0 var(--space-xxxsmall) var(--color-shadow);
28
30
  border-color: var(--color-outline-dark);
29
31
  color: var(--color-text);
30
32
  }
@@ -33,6 +35,7 @@
33
35
  position: absolute;
34
36
  left: 0;
35
37
  top: 100%;
38
+ border-radius: var(--radius-medium);
36
39
  box-shadow: 0 2px var(--space-xxsmall) var(--color-shadow);
37
40
  background: var(--color-background);
38
41
  min-width: 180px;
@@ -45,10 +48,6 @@
45
48
  box-shadow: 0 2px var(--space-xsmall) var(--color-shadow);
46
49
  }
47
50
 
48
- .activeLabel .label {
49
- color: var(--color-text);
50
- }
51
-
52
51
  .menuItem {
53
52
  display: block;
54
53
  appearance: none;
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
 
4
+ import { Stack } from '../../layout/stack';
4
5
  import I18N from '../../i18n';
5
6
  import css from './empty-set.module.css';
6
7
 
@@ -9,30 +10,33 @@ export const EmptySet = (props) => {
9
10
 
10
11
  const message = filtered ? `No ${resources} found.` : `No ${resources} available.`;
11
12
  const actions = [
12
- ...handleResetFilters ? [
13
- (
14
- <button className={css.action} type="button" onClick={handleResetFilters}>
15
- {I18N.RESET_FILTERS}
16
- </button>
17
- )
18
- ] : [],
19
- ...handleViewAll ? [(
20
- <button className={css.action} type="button" onClick={handleViewAll}>
21
- {I18N.VIEW_ALL}
22
- </button>
23
- )] : [],
13
+ ...(handleResetFilters
14
+ ? [
15
+ <button className={css.action} type="button" onClick={handleResetFilters}>
16
+ {I18N.RESET_FILTERS}
17
+ </button>,
18
+ ]
19
+ : []),
20
+ ...(handleViewAll
21
+ ? [
22
+ <button className={css.action} type="button" onClick={handleViewAll}>
23
+ {I18N.VIEW_ALL}
24
+ </button>,
25
+ ]
26
+ : []),
24
27
  ];
25
28
 
26
29
  return (
27
- <div className={css.root}>
28
- <p className={css.text}>{message}</p>
29
- {filtered && actions.map((action, index) => (
30
- <>
31
- {index > 0 && ' or '}
32
- {action}
33
- </>
34
- ))}
35
- </div>
30
+ <Stack space="xxsmall" className={css.root}>
31
+ <p>{message}</p>
32
+ {filtered &&
33
+ actions.map((action, index) => (
34
+ <>
35
+ {index > 0 && ' or '}
36
+ {action}
37
+ </>
38
+ ))}
39
+ </Stack>
36
40
  );
37
41
  };
38
42
 
@@ -1,5 +1,5 @@
1
- .text {
2
- margin-bottom: 0;
1
+ .root {
2
+ color: var(--color-text-light);
3
3
  }
4
4
 
5
5
  .action {
@@ -9,7 +9,7 @@ import { getGroupFiltersLabelSuffix, LABELS } from './filters.utils';
9
9
  import css from './filters.module.css';
10
10
 
11
11
  const Filter = (props) => {
12
- const { className, label, name, getOnOnlyClick, ...inputProps } = props;
12
+ const { className, buttonClassName, label, name, getOnOnlyClick, ...inputProps } = props;
13
13
  const id = `filter-${name}`;
14
14
 
15
15
  const rootClassName = cx(css.filter, className);
@@ -17,26 +17,16 @@ const Filter = (props) => {
17
17
  return (
18
18
  <div className={rootClassName}>
19
19
  {/* eslint-disable */}
20
- <FlexStack space="xxxsmall" as="label" className={css.filterCheckbox}>
21
- {/* eslint-enabled */}
22
- <input
23
- className={css.filterInput}
24
- type="checkbox"
25
- id={id}
26
- name={name}
27
- {...inputProps}
28
- />
20
+ <FlexStack space="xxxsmall" as="label" className={cx(css.filterCheckbox, buttonClassName)}>
21
+ {/* eslint-enabled */}
22
+ <input className={css.filterInput} type="checkbox" id={id} name={name} {...inputProps} />
29
23
  <span className={css.filterLabel} title={label}>
30
24
  {label}
31
25
  </span>
32
26
  </FlexStack>
33
27
 
34
28
  {getOnOnlyClick && (
35
- <button
36
- className={css.filterOnlyButton}
37
- type="button"
38
- onClick={getOnOnlyClick(name)}
39
- >
29
+ <button className={css.filterOnlyButton} type="button" onClick={getOnOnlyClick(name)}>
40
30
  only
41
31
  </button>
42
32
  )}
@@ -46,6 +36,7 @@ const Filter = (props) => {
46
36
 
47
37
  Filter.propTypes = {
48
38
  className: PropTypes.string,
39
+ buttonClassName: PropTypes.string,
49
40
  name: PropTypes.string.isRequired,
50
41
  label: PropTypes.string.isRequired,
51
42
  getOnOnlyClick: PropTypes.func,
@@ -53,17 +44,23 @@ Filter.propTypes = {
53
44
 
54
45
  Filter.defaultProps = {
55
46
  className: '',
47
+ buttonClassName: '',
56
48
  getOnOnlyClick: null,
57
49
  };
58
50
 
59
51
  const FilterGroup = (props) => {
60
- const { groupKey, data, values, onCheckboxChange, toggleFilters } = props;
52
+ const { className, buttonClassName, groupKey, data, values, onCheckboxChange, toggleFilters } =
53
+ props;
61
54
 
62
55
  const { label: groupLabel, ...groupData } = data;
63
56
 
64
57
  const groupItems = Object.entries(groupData);
65
- const groupCheckboxes = groupItems.filter(([itemKey, item]) => typeof item?.defaultValue !== 'undefined');
66
- const isGroupChecked = groupCheckboxes.map(([itemKey]) => get(values, `${groupKey}.${itemKey}`)).reduce((agg, val) => agg && val, true);
58
+ const groupCheckboxes = groupItems.filter(
59
+ ([itemKey, item]) => typeof item?.defaultValue !== 'undefined',
60
+ );
61
+ const isGroupChecked = groupCheckboxes
62
+ .map(([itemKey]) => get(values, `${groupKey}.${itemKey}`))
63
+ .reduce((agg, val) => agg && val, true);
67
64
 
68
65
  const filterSuffix = getGroupFiltersLabelSuffix(groupItems);
69
66
  const hasCustomFilterSuffix = !Object.values(LABELS).includes(filterSuffix);
@@ -71,26 +68,34 @@ const FilterGroup = (props) => {
71
68
  <>
72
69
  {`${groupLabel}:`}
73
70
  &nbsp;
74
- <span className={cx(hasCustomFilterSuffix && css.labelSuffixCustom)}>
75
- {filterSuffix}
76
- </span>
71
+ <span className={cx(hasCustomFilterSuffix && css.labelSuffixCustom)}>{filterSuffix}</span>
77
72
  </>
78
73
  );
79
74
 
80
- const getOnGroupCheck = (value, overrides = {}) => () => {
81
- const newFilters = groupCheckboxes.reduce((agg, [itemKey]) => ({
82
- ...agg,
83
- [`${groupKey}.${itemKey}`]: value,
84
- }), {});
85
-
86
- toggleFilters({
87
- ...newFilters,
88
- ...overrides,
89
- });
90
- };
75
+ const getOnGroupCheck =
76
+ (value, overrides = {}) =>
77
+ () => {
78
+ const newFilters = groupCheckboxes.reduce(
79
+ (agg, [itemKey]) => ({
80
+ ...agg,
81
+ [`${groupKey}.${itemKey}`]: value,
82
+ }),
83
+ {},
84
+ );
85
+
86
+ toggleFilters({
87
+ ...newFilters,
88
+ ...overrides,
89
+ });
90
+ };
91
91
 
92
92
  return (
93
- <Dropdown label={dropdownLabel} ariaLabel={`${groupLabel}: ${filterSuffix}`}>
93
+ <Dropdown
94
+ className={className}
95
+ buttonClassName={buttonClassName}
96
+ label={dropdownLabel}
97
+ ariaLabel={`${groupLabel}: ${filterSuffix}`}
98
+ >
94
99
  {({ MenuItem, menu, menuItemClassName }) => {
95
100
  return (
96
101
  <>
@@ -100,7 +105,11 @@ const FilterGroup = (props) => {
100
105
  const getOnOnlyClick = () => getOnGroupCheck(false, { [id]: true });
101
106
 
102
107
  return (
103
- <MenuItem key={id} {...menu} className={cx(menuItemClassName, css.filterGroupItem)}>
108
+ <MenuItem
109
+ key={id}
110
+ {...menu}
111
+ className={cx(menuItemClassName, css.filterGroupItem)}
112
+ >
104
113
  <Filter
105
114
  name={id}
106
115
  label={itemData.label}
@@ -138,12 +147,14 @@ const FilterGroup = (props) => {
138
147
  </div>
139
148
  </>
140
149
  );
141
- }}
150
+ }}
142
151
  </Dropdown>
143
152
  );
144
153
  };
145
154
 
146
155
  FilterGroup.propTypes = {
156
+ className: PropTypes.string,
157
+ buttonClassName: PropTypes.string,
147
158
  groupKey: PropTypes.string.isRequired,
148
159
  data: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
149
160
  values: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
@@ -151,27 +162,27 @@ FilterGroup.propTypes = {
151
162
  toggleFilters: PropTypes.func.isRequired,
152
163
  };
153
164
 
165
+ FilterGroup.defaultProps = {
166
+ className: '',
167
+ buttonClassName: '',
168
+ };
169
+
154
170
  export const Filters = (props) => {
155
- const {
156
- className,
157
- values,
158
- filters,
159
- toggleFilter,
160
- toggleFilters,
161
- } = props;
171
+ const { className, values, filters, toggleFilter, toggleFilters } = props;
162
172
 
163
173
  const onCheckboxChange = ({ target }) => toggleFilter(target.name, target.checked);
164
174
  const rootClassName = cx(css.root, className);
165
175
 
166
176
  return (
167
177
  <form className={rootClassName}>
168
- <FlexStack className={css.items}>
178
+ <FlexStack space="xxsmall" className={css.items}>
169
179
  {Object.entries(filters).map(([name, data]) => {
170
180
  if (typeof data?.defaultValue !== 'undefined') {
171
181
  return (
172
182
  <Filter
173
183
  key={name}
174
184
  className={cx(css.item, css.filterStandalone)}
185
+ buttonClassName={css.itemButton}
175
186
  name={name}
176
187
  label={data.label}
177
188
  onChange={onCheckboxChange}
@@ -182,16 +193,16 @@ export const Filters = (props) => {
182
193
  }
183
194
 
184
195
  return (
185
- <div className={css.item}>
186
- <FilterGroup
187
- key={name}
188
- groupKey={name}
189
- data={data}
190
- values={values}
191
- onCheckboxChange={onCheckboxChange}
192
- toggleFilters={toggleFilters}
193
- />
194
- </div>
196
+ <FilterGroup
197
+ className={css.item}
198
+ buttonClassName={css.itemButton}
199
+ key={name}
200
+ groupKey={name}
201
+ data={data}
202
+ values={values}
203
+ onCheckboxChange={onCheckboxChange}
204
+ toggleFilters={toggleFilters}
205
+ />
195
206
  );
196
207
  })}
197
208
  </FlexStack>
@@ -11,6 +11,7 @@
11
11
  }
12
12
 
13
13
  .filterInput {
14
+ border-radius: var(--radius-small) 0 0 var(--radius-small);
14
15
  flex: 0 0 auto;
15
16
  height: 1em;
16
17
  cursor: pointer;
@@ -131,9 +132,8 @@
131
132
  .item {
132
133
  position: relative;
133
134
  flex: 0 0 auto;
134
- margin-right: -1px;
135
135
  }
136
136
 
137
- .item:hover {
138
- z-index: var(--layer-low); /* show collapsed border */
137
+ .itemButton {
138
+ border-radius: var(--radius-small);
139
139
  }