@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.
- package/CHANGELOG.md +94 -13
- package/lib/app/app.js +137 -102
- package/lib/app/app.module.css +11 -4
- package/lib/app/header/header.js +1 -10
- package/lib/components/asset-info/asset-info.module.css +1 -0
- package/lib/components/bundle-assets/bundle-assets.js +104 -52
- package/lib/components/bundle-assets/bundle-assets.module.css +24 -26
- package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.js +13 -3
- package/lib/components/bundle-modules/bundle-modules.js +53 -67
- package/lib/components/bundle-packages/bundle-packages.js +100 -44
- package/lib/components/bundle-packages/bundle-packages.module.css +17 -21
- package/lib/components/delta/delta.module.css +1 -0
- package/lib/components/job-header/job-header.js +3 -1
- package/lib/components/job-header/job-header.module.css +6 -8
- package/lib/components/jobs-header/jobs-header.module.css +5 -0
- package/lib/components/metrics-table/metrics-table.js +72 -59
- package/lib/components/metrics-table/metrics-table.module.css +18 -7
- package/lib/components/metrics-table-search/metrics-table-search.module.css +5 -4
- package/lib/components/metrics-table-title/metrics-table-title.js +9 -7
- package/lib/components/metrics-table-title/metrics-table-title.module.css +2 -0
- package/lib/components/module-info/module-info.js +2 -2
- package/lib/components/module-info/module-info.module.css +1 -0
- package/lib/components/summary/summary.js +1 -1
- package/lib/components/summary-item/summary-item.js +15 -18
- package/lib/components/summary-item/summary-item.module.css +1 -23
- package/lib/components/total-size-type-title/total-size-type-title.js +7 -3
- package/lib/css/default.css +14 -3
- package/lib/css/variables.css +17 -17
- package/lib/hooks/search-params.js +31 -31
- package/lib/layout/box/box.module.css +9 -0
- package/lib/layout/footer/footer.module.css +1 -1
- package/lib/layout/index.js +8 -0
- package/lib/layout/separator.js +48 -0
- package/lib/layout/separator.module.css +5 -0
- package/lib/ui/dropdown/dropdown.js +21 -26
- package/lib/ui/dropdown/dropdown.module.css +11 -12
- package/lib/ui/dropdown/dropdown.stories.js +2 -9
- package/lib/ui/empty-set/empty-set.js +5 -4
- package/lib/ui/empty-set/empty-set.module.css +2 -2
- package/lib/ui/filters/filters.container.js +1 -1
- package/lib/ui/filters/filters.js +22 -7
- package/lib/ui/filters/filters.module.css +3 -3
- package/lib/ui/horizontal-bar-chart/horizontal-bar-chart.js +1 -1
- package/lib/ui/hover-card/hover-card.js +102 -0
- package/lib/ui/hover-card/hover-card.module.css +29 -0
- package/lib/ui/hover-card/hover-card.stories.js +56 -0
- package/lib/ui/hover-card/index.js +18 -0
- package/lib/ui/icon/icon.js +6 -6
- package/lib/ui/icon/icon.module.css +1 -0
- package/lib/ui/index.js +8 -8
- package/lib/ui/table/table.js +5 -74
- package/lib/ui/table/table.module.css +41 -25
- package/lib/ui/table/table.stories.js +1 -1
- package/lib/ui/{popover → tag}/index.js +4 -4
- package/lib/ui/tag/tag.js +72 -0
- package/lib/ui/tag/tag.module.css +55 -0
- package/lib/ui/tag/tag.stories.js +38 -0
- package/lib/ui/tooltip/tooltip.js +10 -9
- package/lib/ui/tooltip/tooltip.module.css +2 -1
- package/lib-esm/app/app.js +132 -102
- package/lib-esm/app/app.module.css +11 -4
- package/lib-esm/app/header/header.js +1 -9
- package/lib-esm/components/asset-info/asset-info.module.css +1 -0
- package/lib-esm/components/bundle-assets/bundle-assets.js +97 -56
- package/lib-esm/components/bundle-assets/bundle-assets.module.css +24 -26
- package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.js +7 -3
- package/lib-esm/components/bundle-modules/bundle-modules.js +35 -50
- package/lib-esm/components/bundle-packages/bundle-packages.js +88 -41
- package/lib-esm/components/bundle-packages/bundle-packages.module.css +17 -21
- package/lib-esm/components/delta/delta.module.css +1 -0
- package/lib-esm/components/job-header/job-header.js +2 -1
- package/lib-esm/components/job-header/job-header.module.css +6 -8
- package/lib-esm/components/jobs-header/jobs-header.module.css +5 -0
- package/lib-esm/components/metrics-table/metrics-table.js +61 -53
- package/lib-esm/components/metrics-table/metrics-table.module.css +18 -7
- package/lib-esm/components/metrics-table-search/metrics-table-search.module.css +5 -4
- package/lib-esm/components/metrics-table-title/metrics-table-title.js +8 -7
- package/lib-esm/components/metrics-table-title/metrics-table-title.module.css +2 -0
- package/lib-esm/components/module-info/module-info.js +2 -2
- package/lib-esm/components/module-info/module-info.module.css +1 -0
- package/lib-esm/components/summary/summary.js +1 -1
- package/lib-esm/components/summary-item/summary-item.js +14 -18
- package/lib-esm/components/summary-item/summary-item.module.css +1 -23
- package/lib-esm/components/total-size-type-title/total-size-type-title.js +6 -3
- package/lib-esm/css/default.css +14 -3
- package/lib-esm/css/variables.css +17 -17
- package/lib-esm/hooks/search-params.js +27 -28
- package/lib-esm/layout/box/box.module.css +9 -0
- package/lib-esm/layout/footer/footer.module.css +1 -1
- package/lib-esm/layout/index.js +1 -0
- package/lib-esm/layout/separator.js +28 -0
- package/lib-esm/layout/separator.module.css +5 -0
- package/lib-esm/ui/dropdown/dropdown.js +20 -25
- package/lib-esm/ui/dropdown/dropdown.module.css +11 -12
- package/lib-esm/ui/dropdown/dropdown.stories.js +2 -7
- package/lib-esm/ui/empty-set/empty-set.js +4 -4
- package/lib-esm/ui/empty-set/empty-set.module.css +2 -2
- package/lib-esm/ui/filters/filters.js +20 -5
- package/lib-esm/ui/filters/filters.module.css +3 -3
- package/lib-esm/ui/hover-card/hover-card.js +83 -0
- package/lib-esm/ui/hover-card/hover-card.module.css +29 -0
- package/lib-esm/ui/hover-card/hover-card.stories.js +35 -0
- package/lib-esm/ui/hover-card/index.js +1 -0
- package/lib-esm/ui/icon/icon.js +3 -3
- package/lib-esm/ui/icon/icon.module.css +1 -0
- package/lib-esm/ui/index.js +1 -1
- package/lib-esm/ui/table/table.js +5 -65
- package/lib-esm/ui/table/table.module.css +41 -25
- package/lib-esm/ui/table/table.stories.js +1 -1
- package/lib-esm/ui/tag/index.js +1 -0
- package/lib-esm/ui/tag/tag.js +45 -0
- package/lib-esm/ui/tag/tag.module.css +55 -0
- package/lib-esm/ui/tag/tag.stories.js +23 -0
- package/lib-esm/ui/tooltip/tooltip.js +10 -9
- package/lib-esm/ui/tooltip/tooltip.module.css +2 -1
- package/package.json +33 -31
- package/src/app/app.jsx +142 -145
- package/src/app/app.module.css +11 -4
- package/src/app/header/header.jsx +0 -10
- package/src/components/asset-info/asset-info.module.css +1 -0
- package/src/components/bundle-assets/bundle-assets.jsx +85 -31
- package/src/components/bundle-assets/bundle-assets.module.css +24 -26
- package/src/components/bundle-assets-totals-table/bundle-assets-totals-table.jsx +2 -0
- package/src/components/bundle-modules/bundle-modules.jsx +36 -36
- package/src/components/bundle-packages/bundle-packages.jsx +89 -39
- package/src/components/bundle-packages/bundle-packages.module.css +17 -21
- package/src/components/delta/delta.module.css +1 -0
- package/src/components/job-header/job-header.jsx +2 -1
- package/src/components/job-header/job-header.module.css +6 -8
- package/src/components/jobs-header/jobs-header.module.css +5 -0
- package/src/components/metrics-table/metrics-table.jsx +53 -44
- package/src/components/metrics-table/metrics-table.module.css +18 -7
- package/src/components/metrics-table-search/metrics-table-search.module.css +5 -4
- package/src/components/metrics-table-title/metrics-table-title.jsx +20 -21
- package/src/components/metrics-table-title/metrics-table-title.module.css +2 -0
- package/src/components/module-info/module-info.jsx +3 -7
- package/src/components/module-info/module-info.module.css +1 -0
- package/src/components/summary/summary.jsx +1 -1
- package/src/components/summary-item/summary-item.jsx +21 -27
- package/src/components/summary-item/summary-item.module.css +1 -23
- package/src/components/total-size-type-title/total-size-type-title.jsx +6 -9
- package/src/css/default.css +14 -3
- package/src/css/variables.css +17 -17
- package/src/hooks/search-params.js +42 -33
- package/src/layout/box/box.module.css +9 -0
- package/src/layout/footer/footer.module.css +1 -1
- package/src/layout/index.js +1 -0
- package/src/layout/separator.jsx +25 -0
- package/src/layout/separator.module.css +5 -0
- package/src/ui/dropdown/dropdown.jsx +16 -22
- package/src/ui/dropdown/dropdown.module.css +11 -12
- package/src/ui/empty-set/empty-set.jsx +25 -21
- package/src/ui/empty-set/empty-set.module.css +2 -2
- package/src/ui/filters/filters.jsx +64 -53
- package/src/ui/filters/filters.module.css +3 -3
- package/src/ui/hover-card/hover-card.jsx +73 -0
- package/src/ui/hover-card/hover-card.module.css +29 -0
- package/src/ui/hover-card/index.js +1 -0
- package/src/ui/icon/icon.jsx +11 -7
- package/src/ui/icon/icon.module.css +1 -0
- package/src/ui/index.js +1 -1
- package/src/ui/table/table.jsx +5 -52
- package/src/ui/table/table.module.css +41 -25
- package/src/ui/tag/index.js +1 -0
- package/src/ui/tag/tag.jsx +49 -0
- package/src/ui/tag/tag.module.css +55 -0
- package/src/ui/tooltip/tooltip.jsx +10 -14
- package/src/ui/tooltip/tooltip.module.css +2 -1
- package/lib/ui/popover/popover.js +0 -92
- package/lib/ui/popover/popover.module.css +0 -66
- package/lib/ui/popover/popover.stories.js +0 -26
- package/lib-esm/ui/popover/index.js +0 -1
- package/lib-esm/ui/popover/popover.js +0 -71
- package/lib-esm/ui/popover/popover.module.css +0 -66
- package/lib-esm/ui/popover/popover.stories.js +0 -14
- package/src/ui/popover/index.js +0 -1
- package/src/ui/popover/popover.jsx +0 -79
- 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 }) =>
|
|
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
|
-
|
|
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
|
-
|
|
46
|
+
const newState = {
|
|
46
47
|
filters: state.filters,
|
|
47
48
|
search: payload,
|
|
48
|
-
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
setParentState(newState);
|
|
49
52
|
|
|
50
53
|
return {
|
|
51
|
-
...
|
|
52
|
-
search: payload,
|
|
54
|
+
...newState,
|
|
53
55
|
searchPattern: getSearchPattern(payload),
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
case ACTION_RESET_DEFAULT: {
|
|
58
|
-
|
|
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
|
-
|
|
65
|
-
search: '',
|
|
68
|
+
...newState,
|
|
66
69
|
searchPattern: getSearchPattern(),
|
|
67
70
|
};
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
case ACTION_RESET_ALL: {
|
|
71
|
-
|
|
74
|
+
const newState = {
|
|
72
75
|
filters: allEntriesFilters,
|
|
73
|
-
search:
|
|
74
|
-
}
|
|
76
|
+
search: SEARCH_DEFAULT,
|
|
77
|
+
};
|
|
78
|
+
setParentState(newState);
|
|
75
79
|
|
|
76
80
|
return {
|
|
77
|
-
|
|
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
|
|
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,
|
|
127
|
+
}, [dispatch, search, filters, parentSearch, initialFilters]);
|
|
125
128
|
|
|
126
129
|
/** Callbacks */
|
|
127
|
-
const handleUpdateSearch = useCallback(
|
|
128
|
-
|
|
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(
|
|
132
|
-
|
|
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 {
|
package/src/layout/index.js
CHANGED
|
@@ -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;
|
|
@@ -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,
|
|
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,
|
|
12
|
-
const rootClassName = cx(css.root,
|
|
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 {
|
|
19
|
-
<FlexStack space="xxxsmall"
|
|
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 {
|
|
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
|
-
.
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
...handleViewAll
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
<
|
|
28
|
-
<p
|
|
29
|
-
{filtered &&
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
|
@@ -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
|
-
|
|
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 } =
|
|
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(
|
|
66
|
-
|
|
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
|
|
|
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 =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
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
|
|
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
|
-
<
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
.
|
|
138
|
-
|
|
137
|
+
.itemButton {
|
|
138
|
+
border-radius: var(--radius-small);
|
|
139
139
|
}
|