@bitrise/bitkit 13.317.0 → 13.319.0

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 (36) hide show
  1. package/package.json +1 -1
  2. package/src/Components/DatePicker/DatePicker.tsx +59 -54
  3. package/src/Components/Drawer/Drawer.tsx +19 -5
  4. package/src/Components/Dropdown/DropdownOption.tsx +1 -1
  5. package/src/Components/Filter/Desktop/Filter.tsx +92 -0
  6. package/src/Components/Filter/Desktop/FilterAdd/FilterAdd.tsx +89 -0
  7. package/src/Components/Filter/{FilterDate → Desktop/FilterDate}/FilterDate.tsx +21 -10
  8. package/src/Components/Filter/{FilterForm → Desktop}/FilterForm.tsx +24 -115
  9. package/src/Components/Filter/{FilterItem → Desktop}/FilterItem.tsx +1 -1
  10. package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitch.theme.ts +1 -1
  11. package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitch.tsx +4 -4
  12. package/src/Components/Filter/{FilterSwitchAdapter → Desktop/FilterSwitch}/FilterSwitchAdapter.tsx +5 -5
  13. package/src/Components/Filter/Filter.storyData.ts +14 -1
  14. package/src/Components/Filter/Filter.tsx +16 -106
  15. package/src/Components/Filter/Filter.types.ts +34 -1
  16. package/src/Components/Filter/Filter.utils.ts +13 -0
  17. package/src/Components/Filter/Mobile/DateSelectOption.tsx +53 -0
  18. package/src/Components/Filter/Mobile/Filter.tsx +57 -0
  19. package/src/Components/Filter/Mobile/FilterAdd.tsx +97 -0
  20. package/src/Components/Filter/Mobile/FilterDrawer.tsx +96 -0
  21. package/src/Components/Filter/Mobile/FilterForm.tsx +236 -0
  22. package/src/Components/Filter/Mobile/FilterItem.tsx +95 -0
  23. package/src/Components/Filter/Mobile/MultiSelectOptions.tsx +69 -0
  24. package/src/Components/Filter/Mobile/SingleSelectOptions.tsx +136 -0
  25. package/src/Components/Filter/hooks/useFilterAdd.ts +68 -0
  26. package/src/Components/Filter/hooks/useFilterForm.ts +131 -0
  27. package/src/Components/Filter/hooks/useIsScrollable.ts +35 -0
  28. package/src/Components/Filter/hooks/useListBox.ts +66 -0
  29. package/src/Components/Form/Input/Input.theme.ts +27 -11
  30. package/src/Components/Form/Input/Input.tsx +4 -1
  31. package/src/Components/SearchInput/SearchInput.tsx +3 -2
  32. package/src/Components/components.theme.ts +1 -1
  33. package/src/index.ts +3 -4
  34. package/src/Components/Filter/FilterAdd/FilterAdd.tsx +0 -111
  35. /package/src/Components/Filter/{FilterSearch → Desktop}/FilterSearch.tsx +0 -0
  36. /package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitchGroup.tsx +0 -0
@@ -1,9 +1,9 @@
1
1
  import { useMemo } from 'react';
2
- import { useFilterContext } from '../Filter.context';
3
- import { getOptionLabel } from '../Filter.utils';
4
- import FilterSwitch from '../FilterSwitch/FilterSwitch';
5
- import FilterSwitchGroup from '../FilterSwitch/FilterSwitchGroup';
6
- import { FilterCategoryProps } from '../Filter.types';
2
+ import { useFilterContext } from '../../Filter.context';
3
+ import { getOptionLabel } from '../../Filter.utils';
4
+ import { FilterCategoryProps } from '../../Filter.types';
5
+ import FilterSwitch from './FilterSwitch';
6
+ import FilterSwitchGroup from './FilterSwitchGroup';
7
7
 
8
8
  type FilterSwitchAdapterProps = {
9
9
  category: string;
@@ -49,6 +49,8 @@ export const FILTER_STORY_DATA: FilterData = {
49
49
  type: 'tag',
50
50
  },
51
51
  cache_type: {
52
+ categoryName: 'Cache type',
53
+ categoryNamePlural: 'Cache types',
52
54
  allOptionLabel: 'All items',
53
55
  iconsMap: {
54
56
  bazel: 'Bazel',
@@ -63,7 +65,7 @@ export const FILTER_STORY_DATA: FilterData = {
63
65
  },
64
66
  date_range: {
65
67
  categoryName: 'Date',
66
- categoryNamePlural: 'dates',
68
+ categoryNamePlural: 'Dates',
67
69
  isMultiple: true,
68
70
  dayTooltip: ({ date }) => (date > DateTime.now() ? 'Date must be in the past' : undefined),
69
71
  selectable: new DateRange(DateTime.now().minus({ days: 15 }), DateTime.now()),
@@ -97,6 +99,7 @@ export const FILTER_STORY_DATA: FilterData = {
97
99
  },
98
100
  workflow: {
99
101
  categoryName: 'Workflow',
102
+ categoryNamePlural: 'Workflows',
100
103
  isMultiple: true,
101
104
  options: FILTER_STORY_OPTIONS,
102
105
  type: 'tag',
@@ -115,4 +118,14 @@ export const FILTER_STORY_CONTEXT: FilterContextType = {
115
118
  onFilterClear: () => {},
116
119
  setPopoverOpen: () => {},
117
120
  state: FILTER_STORY_INIT_STATE,
121
+ filters: {
122
+ dateRange: {},
123
+ search: {},
124
+ select: {},
125
+ switch: {},
126
+ tag: {},
127
+ },
128
+ isPopoverOpen: false,
129
+ onClearFilters: () => {},
130
+ setSelectedCategory: () => {},
118
131
  };
@@ -1,58 +1,15 @@
1
- import { ReactNode, useMemo, useState } from 'react';
2
- import { Modal, ModalOverlay, useMultiStyleConfig } from 'chakra-ui-2--react';
1
+ import { useMemo, useState } from 'react';
3
2
  import { isEqual } from '../../utils/utils';
4
- import Box, { BoxProps } from '../Box/Box';
5
- import Button from '../Button/Button';
6
- import Divider from '../Divider/Divider';
7
- import Icon from '../Icon/Icon';
8
3
  import { FilterContext } from './Filter.context';
9
- import { FilterStyle } from './Filter.theme';
10
- import {
11
- FilterCategoryProps,
12
- FilterContextType,
13
- FilterData,
14
- FilterState,
15
- FilterType,
16
- FilterValue,
17
- } from './Filter.types';
4
+ import { FilterContextType, FilterProps, Filters, FilterState, FilterValue } from './Filter.types';
18
5
  import { getDependents } from './Filter.utils';
19
- import FilterAdd from './FilterAdd/FilterAdd';
20
- import FilterItem from './FilterItem/FilterItem';
21
- import FilterSearch from './FilterSearch/FilterSearch';
22
- import FilterDate from './FilterDate/FilterDate';
23
- import FilterSwitchAdapter from './FilterSwitchAdapter/FilterSwitchAdapter';
24
-
25
- export interface FilterProps extends Omit<BoxProps, 'onChange'> {
26
- data: FilterData;
27
- defaultState?: FilterState;
28
- filtersDependOn?: string[];
29
- isLoading?: boolean;
30
- onChange: (state: FilterState) => void;
31
- searchTooltip?: ReactNode;
32
- showAdd?: boolean;
33
- showFilterIcon?: boolean;
34
- showClearFilters?: boolean;
35
- showSearch?: boolean;
36
- state: FilterState;
37
- }
6
+ import FilterMobile from './Mobile/Filter';
7
+ import FilterDesktop from './Desktop/Filter';
38
8
 
39
9
  const Filter = (props: FilterProps) => {
40
- const {
41
- data,
42
- defaultState,
43
- filtersDependOn,
44
- isLoading,
45
- onChange,
46
- searchTooltip,
47
- showAdd = true,
48
- showFilterIcon = true,
49
- showClearFilters = true,
50
- showSearch,
51
- state,
52
- ...rest
53
- } = props;
54
-
55
- const filterStyle = useMultiStyleConfig('Filter') as FilterStyle;
10
+ const { data, defaultState, filtersDependOn, isLoading, isMobile, onChange, showClearFilters = true, state } = props;
11
+
12
+ const [selectedCategory, setSelectedCategory] = useState<string | undefined>();
56
13
 
57
14
  const cleanState: FilterState = {};
58
15
  Object.entries(state).forEach(([category, values]) => {
@@ -106,13 +63,13 @@ const Filter = (props: FilterProps) => {
106
63
  onChange(stateToRestore || {});
107
64
  };
108
65
 
109
- const filters = {
66
+ const filters: Filters = {
110
67
  dateRange: {},
111
68
  search: {},
112
69
  select: {},
113
70
  switch: {},
114
71
  tag: {},
115
- } as Record<FilterType, Record<string, FilterCategoryProps>>;
72
+ };
116
73
 
117
74
  Object.entries(data).forEach(([category, value]) => {
118
75
  filters[value.type || 'tag'][category] = value;
@@ -123,11 +80,17 @@ const Filter = (props: FilterProps) => {
123
80
  const contextValue: FilterContextType = useMemo(
124
81
  () => ({
125
82
  data,
83
+ filters,
126
84
  filtersDependOn,
85
+ isPopoverOpen,
127
86
  isLoading,
87
+ onClearFilters,
128
88
  onFilterChange,
129
89
  onFilterClear,
90
+ selectedCategory,
91
+ showClearButton,
130
92
  setPopoverOpen,
93
+ setSelectedCategory,
131
94
  state: cleanState,
132
95
  }),
133
96
  [data, filtersDependOn, isLoading, onFilterChange, onFilterClear, setPopoverOpen, cleanState],
@@ -135,60 +98,7 @@ const Filter = (props: FilterProps) => {
135
98
 
136
99
  return (
137
100
  <FilterContext value={contextValue}>
138
- <Box sx={filterStyle.container} {...rest}>
139
- <Modal isOpen={isPopoverOpen} onClose={() => {}}>
140
- {isPopoverOpen && <ModalOverlay />}
141
- </Modal>
142
- <Box sx={filterStyle.content}>
143
- {showFilterIcon && <Icon name="Filter" sx={filterStyle.icon} />}
144
-
145
- {Object.keys(filters.switch).map((category) => (
146
- <FilterSwitchAdapter key={category} category={category} />
147
- ))}
148
-
149
- {Object.keys(filters.dateRange).map((category) => (
150
- <FilterDate key={category} category={category} />
151
- ))}
152
-
153
- {Object.keys(filters.select).map((category) => (
154
- <FilterItem key={category} category={category} />
155
- ))}
156
- {Object.keys(filters.tag).map((category) => {
157
- if (!cleanState[category]) {
158
- return;
159
- }
160
- return <FilterItem key={category} category={category} />;
161
- })}
162
-
163
- {showAdd && <FilterAdd onChange={onFilterChange} />}
164
- </Box>
165
- {(showClearButton || showSearch) && (
166
- <Box sx={filterStyle.rightContent}>
167
- {showClearButton && (
168
- <Button
169
- isDisabled={isLoading}
170
- leftIconName="Cross"
171
- minWidth="7.5rem"
172
- onClick={onClearFilters}
173
- size="sm"
174
- variant="tertiary"
175
- >
176
- Clear filters
177
- </Button>
178
- )}
179
- {showSearch && (
180
- <>
181
- <Divider flexShrink="0" orientation="vertical" size="1" variant="solid" />
182
- <FilterSearch
183
- onChange={onFilterChange}
184
- value={cleanState.search?.length ? cleanState.search[0] : ''}
185
- searchTooltip={searchTooltip}
186
- />
187
- </>
188
- )}
189
- </Box>
190
- )}
191
- </Box>
101
+ {isMobile ? <FilterMobile {...props} /> : <FilterDesktop {...props} />}
192
102
  </FilterContext>
193
103
  );
194
104
  };
@@ -1,6 +1,7 @@
1
- import { Dispatch, SetStateAction } from 'react';
1
+ import { Dispatch, ReactNode, SetStateAction } from 'react';
2
2
  import { TypeIconName } from '../Icon/Icon';
3
3
  import { DatePickerProps, DateRange } from '../DatePicker/DatePicker';
4
+ import { BoxProps } from '../Box/Box';
4
5
 
5
6
  export type FilterType = 'dateRange' | 'search' | 'select' | 'switch' | 'tag';
6
7
 
@@ -58,10 +59,42 @@ export type FilterState = Record<string, FilterValue>;
58
59
 
59
60
  export interface FilterContextType {
60
61
  data: FilterData;
62
+ filters: Filters;
61
63
  filtersDependOn?: string[];
62
64
  isLoading?: boolean;
65
+ isPopoverOpen: boolean;
66
+ onClearFilters: () => void;
63
67
  onFilterClear: (category: string) => void;
64
68
  onFilterChange: (category: string, value: FilterValue) => void;
69
+ selectedCategory?: string;
65
70
  setPopoverOpen: Dispatch<SetStateAction<boolean>>;
71
+ setSelectedCategory: Dispatch<SetStateAction<string | undefined>>;
72
+ showClearButton?: boolean;
66
73
  state: FilterState;
67
74
  }
75
+
76
+ export type Filters = Record<FilterType, Record<string, FilterCategoryProps>>;
77
+
78
+ export interface FilterProps extends Omit<BoxProps, 'onChange'> {
79
+ data: FilterData;
80
+ defaultState?: FilterState;
81
+ filtersDependOn?: string[];
82
+ isLoading?: boolean;
83
+ isMobile?: boolean;
84
+ onChange: (state: FilterState) => void;
85
+ searchTooltip?: ReactNode;
86
+ showAdd?: boolean;
87
+ showFilterIcon?: boolean;
88
+ showClearFilters?: boolean;
89
+ showSearch?: boolean;
90
+ state: FilterState;
91
+ }
92
+
93
+ export type FilterFormProps = {
94
+ category: string;
95
+ categoryName?: string;
96
+ categoryNamePlural?: string;
97
+ loadingText?: string;
98
+ onChange: (category: string, selected: FilterValue, previousValue: FilterValue) => void;
99
+ onCancel: () => void;
100
+ };
@@ -1,3 +1,5 @@
1
+ import { DateTime } from 'luxon';
2
+ import { DateRange } from '../DatePicker/DatePicker';
1
3
  import { FilterData, FilterOptionsMap } from './Filter.types';
2
4
 
3
5
  export const hasAllDependencies = (stateKeys: string[], dependsOn?: string[]): boolean => {
@@ -38,3 +40,14 @@ export const getOptionLabel = (option: string, optionsMap?: FilterOptionsMap) =>
38
40
  }
39
41
  return optionsMap[option] || option;
40
42
  };
43
+
44
+ export const getDateRangeLabel = (value: string[] | undefined): string => {
45
+ const selectedRange: DateRange | undefined =
46
+ value && value[0]
47
+ ? new DateRange(DateTime.fromMillis(Number(value[0])), DateTime.fromMillis(Number(value[1])))
48
+ : undefined;
49
+
50
+ return selectedRange
51
+ ? `${selectedRange.from?.toFormat('LLL dd')} - ${selectedRange.to?.toFormat('LLL dd')}`
52
+ : 'All dates';
53
+ };
@@ -0,0 +1,53 @@
1
+ import { DateTime } from 'luxon';
2
+ import Box from '../../Box/Box';
3
+ import DatePicker, { DatePickerProps, DateRange, useDateRange } from '../../DatePicker/DatePicker';
4
+ import { useFilterContext } from '../Filter.context';
5
+ import { FilterCategoryProps } from '../Filter.types';
6
+
7
+ type DateSelectOptionProps = {
8
+ onClear: () => void;
9
+ onChange: (dateRange: string[]) => void;
10
+ selectedItems: string[];
11
+ };
12
+
13
+ const DateSelectOption = ({ onClear, onChange, selectedItems }: DateSelectOptionProps) => {
14
+ const { data } = useFilterContext();
15
+
16
+ const dateRangeData = data.date_range as FilterCategoryProps & {
17
+ dayTooltip?: DatePickerProps['dayTooltip'];
18
+ selectable?: DateRange;
19
+ };
20
+
21
+ const handleChange = (range: DateRange) => {
22
+ if (range.from && range.to) {
23
+ onChange([String(range.from.toMillis()), String(range.to.endOf('day').toMillis())]);
24
+ }
25
+ };
26
+
27
+ const now = DateTime.local();
28
+ const twoYearsAgo = now.minus({ years: 2 });
29
+
30
+ const selectable = useDateRange(twoYearsAgo, now);
31
+
32
+ const selectedRange: DateRange | undefined =
33
+ selectedItems && selectedItems[0]
34
+ ? new DateRange(DateTime.fromMillis(Number(selectedItems[0])), DateTime.fromMillis(Number(selectedItems[1])))
35
+ : undefined;
36
+
37
+ return (
38
+ <Box display="flex" justifyContent="center">
39
+ <DatePicker
40
+ dayTooltip={dateRangeData.dayTooltip}
41
+ mode="range"
42
+ onApply={handleChange}
43
+ onClear={selectedItems?.length ? onClear : undefined}
44
+ selectable={dateRangeData.selectable || selectable}
45
+ selected={selectedRange}
46
+ variant="inline"
47
+ visible
48
+ />
49
+ </Box>
50
+ );
51
+ };
52
+
53
+ export default DateSelectOption;
@@ -0,0 +1,57 @@
1
+ import Badge from '../../Badge/Badge';
2
+ import Text from '../../Text/Text';
3
+ import Button from '../../Button/Button';
4
+ import Box from '../../Box/Box';
5
+ import { useFilterContext } from '../Filter.context';
6
+ import { FilterProps } from '../Filter.types';
7
+ import FilterDrawer from './FilterDrawer';
8
+ import FilterForm from './FilterForm';
9
+
10
+ const Filter = ({ isLoading, showAdd = true }: FilterProps) => {
11
+ const {
12
+ isPopoverOpen,
13
+ onClearFilters,
14
+ selectedCategory,
15
+ setSelectedCategory,
16
+ setPopoverOpen,
17
+ showClearButton,
18
+ state,
19
+ } = useFilterContext();
20
+
21
+ const count = Object.values(state).filter((item) => item?.length > 0).length;
22
+
23
+ return (
24
+ <>
25
+ <Box alignItems="center" display="flex" justifyContent="space-between">
26
+ <Button leftIconName="Filter" onClick={() => setPopoverOpen(true)} size="sm" variant="secondary">
27
+ <Text alignItems="center" display="flex" gap="8">
28
+ Filters
29
+ <Badge colorScheme={count > 0 ? 'progress' : 'neutral'} variant="subtle">
30
+ {String(count)}
31
+ </Badge>
32
+ </Text>
33
+ </Button>
34
+ {showClearButton && (
35
+ <Button
36
+ isDisabled={isLoading}
37
+ leftIconName="Cross"
38
+ minWidth="7.5rem"
39
+ onClick={onClearFilters}
40
+ size="sm"
41
+ variant="tertiary"
42
+ >
43
+ Clear filters
44
+ </Button>
45
+ )}
46
+ </Box>
47
+ <FilterDrawer isOpen={isPopoverOpen} onClose={() => setPopoverOpen(false)} showAdd={showAdd} />
48
+ <FilterForm
49
+ isOpen={Boolean(selectedCategory)}
50
+ onClose={() => setSelectedCategory(undefined)}
51
+ selectedCategory={selectedCategory || ''}
52
+ />
53
+ </>
54
+ );
55
+ };
56
+
57
+ export default Filter;
@@ -0,0 +1,97 @@
1
+ import { Modal, ModalOverlay, Portal } from 'chakra-ui-2--react';
2
+ import Menu from '../../Menu/Menu';
3
+ import MenuItem from '../../Menu/MenuItem';
4
+ import Button from '../../Button/Button';
5
+ import Box from '../../Box/Box';
6
+ import Text from '../../Text/Text';
7
+ import { getMissingDependencies } from '../Filter.utils';
8
+ import useFilterAdd from '../hooks/useFilterAdd';
9
+ import { useFilterContext } from '../Filter.context';
10
+ import FilterForm from './FilterForm';
11
+
12
+ const FilterAdd = () => {
13
+ const { data } = useFilterContext();
14
+
15
+ const {
16
+ categoryList,
17
+ closeMenu,
18
+ isDisabled,
19
+ isMenuOpen,
20
+ onCategorySelect,
21
+ onOpen,
22
+ selectedCategory,
23
+ setSelectedCategory,
24
+ stateKeys,
25
+ } = useFilterAdd({ isMobile: true });
26
+
27
+ return (
28
+ <>
29
+ <Modal isOpen={isMenuOpen} onClose={() => closeMenu()} trapFocus={false} autoFocus={false}>
30
+ {isMenuOpen && <ModalOverlay onClick={() => closeMenu()} zIndex="popover" />}
31
+ </Modal>
32
+ <Button alignSelf="flex-start" isDisabled={isDisabled} variant="tertiary" leftIconName="Plus" onClick={onOpen}>
33
+ Add filter
34
+ </Button>
35
+ <FilterForm
36
+ isOpen={Boolean(selectedCategory)}
37
+ onClose={() => setSelectedCategory(undefined)}
38
+ selectedCategory={selectedCategory || ''}
39
+ />
40
+ {isMenuOpen && (
41
+ <Portal>
42
+ <Box
43
+ bg="white"
44
+ borderRadius="8px"
45
+ bottom="12px"
46
+ boxShadow="0 4px 12px rgba(0, 0, 0, 0.15)"
47
+ left="12px"
48
+ maxHeight="75vh"
49
+ overflowY="auto"
50
+ paddingY="8"
51
+ position="fixed"
52
+ right="12px"
53
+ sx={{
54
+ '@keyframes slideUp': {
55
+ from: { transform: 'translateY(100%)', opacity: 0 },
56
+ to: { transform: 'translateY(0)', opacity: 1 },
57
+ },
58
+ animation: 'slideUp 0.3s ease-out',
59
+ }}
60
+ zIndex="tooltip"
61
+ >
62
+ <Menu>
63
+ <Text
64
+ color="text/tertiary"
65
+ paddingBlock="8"
66
+ paddingInline="16"
67
+ textStyle="heading/h6"
68
+ textTransform="uppercase"
69
+ >
70
+ Select filter
71
+ </Text>
72
+ {categoryList.map((category) => {
73
+ const { categoryName, dependsOn } = data[category];
74
+ const missingDependencies = getMissingDependencies(stateKeys, Object.keys(dependsOn || []));
75
+ const isCategoryDisabled = missingDependencies.length > 0 || !data[category]?.options?.length;
76
+ return (
77
+ <MenuItem
78
+ isDisabled={isCategoryDisabled}
79
+ key={category}
80
+ onClick={() => onCategorySelect(category)}
81
+ pointerEvents="all"
82
+ rightIconName="ChevronRight"
83
+ rightIconColor="neutral.60"
84
+ >
85
+ {categoryName || category}
86
+ </MenuItem>
87
+ );
88
+ })}
89
+ </Menu>
90
+ </Box>
91
+ </Portal>
92
+ )}
93
+ </>
94
+ );
95
+ };
96
+
97
+ export default FilterAdd;
@@ -0,0 +1,96 @@
1
+ import { useRef } from 'react';
2
+ import ButtonGroup from '../../ButtonGroup/ButtonGroup';
3
+ import type { DialogProps } from '../../Dialog/DialogProps';
4
+ import Box from '../../Box/Box';
5
+ import Button from '../../Button/Button';
6
+ import Drawer from '../../Drawer/Drawer';
7
+ import Divider from '../../Divider/Divider';
8
+ import Text from '../../Text/Text';
9
+ import { useFilterContext } from '../Filter.context';
10
+ import FilterItem from './FilterItem';
11
+ import FilterAdd from './FilterAdd';
12
+
13
+ const FilterDrawer = ({
14
+ isOpen,
15
+ onClose,
16
+ showAdd,
17
+ }: Pick<DialogProps, 'isOpen' | 'onClose'> & { showAdd?: boolean }) => {
18
+ const { filters, state, onClearFilters, showClearButton } = useFilterContext();
19
+
20
+ const initialFocusRef = useRef(null);
21
+
22
+ const onClear = () => {
23
+ onClearFilters();
24
+ onClose();
25
+ };
26
+
27
+ return (
28
+ <Drawer
29
+ blockScrollOnMount={false}
30
+ bodyPadding={16}
31
+ bodyProps={{ overflowY: 'auto' }}
32
+ contentProps={{ zIndex: 'fullDialog', top: '0' }}
33
+ headerPadding={0}
34
+ initialFocusRef={initialFocusRef}
35
+ isOpen={isOpen}
36
+ maxWidth="100%"
37
+ onClose={onClose}
38
+ overlayProps={{ zIndex: 'fullDialogOverlay' }}
39
+ padding={0}
40
+ title={
41
+ <>
42
+ <Text color="text/primary" padding="16" textStyle="heading/mobile/h2" textTransform="none">
43
+ Filters
44
+ </Text>
45
+ <Divider />
46
+ </>
47
+ }
48
+ footer={
49
+ <Box width="100%">
50
+ <Divider />
51
+ <ButtonGroup
52
+ display="flex"
53
+ justifyContent="space-between"
54
+ gap="12"
55
+ paddingBlock="12"
56
+ paddingInline="16"
57
+ width="100%"
58
+ ref={initialFocusRef}
59
+ >
60
+ <Button isDisabled={!showClearButton} variant="secondary" onClick={onClear} flex="1" size="md">
61
+ Clear filters
62
+ </Button>
63
+ <Button type="submit" flex="1" size="md" onClick={onClose}>
64
+ Show results
65
+ </Button>
66
+ </ButtonGroup>
67
+ </Box>
68
+ }
69
+ >
70
+ <Box display="flex" flexDirection="column" gap="16">
71
+ {Object.keys(filters.dateRange).map((category) => (
72
+ <FilterItem key={category} category={category} />
73
+ ))}
74
+
75
+ {Object.keys(filters.switch).map((category) => (
76
+ <FilterItem key={category} category={category} />
77
+ ))}
78
+
79
+ {Object.keys(filters.select).map((category) => (
80
+ <FilterItem key={category} category={category} />
81
+ ))}
82
+
83
+ {Object.keys(filters.tag).map((category) => {
84
+ if (!state[category]) {
85
+ return;
86
+ }
87
+ return <FilterItem key={category} category={category} />;
88
+ })}
89
+
90
+ {showAdd && <FilterAdd />}
91
+ </Box>
92
+ </Drawer>
93
+ );
94
+ };
95
+
96
+ export default FilterDrawer;