@bitrise/bitkit 13.318.0 → 13.320.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 (39) hide show
  1. package/package.json +19 -19
  2. package/src/Components/DatePicker/DatePicker.tsx +59 -54
  3. package/src/Components/Dialog/DialogProps.ts +1 -2
  4. package/src/Components/Drawer/Drawer.tsx +23 -7
  5. package/src/Components/ExpandableCard/ExpandableCard.tsx +23 -24
  6. package/src/Components/Filter/Desktop/Filter.tsx +92 -0
  7. package/src/Components/Filter/Desktop/FilterAdd/FilterAdd.tsx +89 -0
  8. package/src/Components/Filter/{FilterDate → Desktop/FilterDate}/FilterDate.tsx +21 -10
  9. package/src/Components/Filter/{FilterForm → Desktop}/FilterForm.tsx +24 -115
  10. package/src/Components/Filter/{FilterItem → Desktop}/FilterItem.tsx +1 -1
  11. package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitch.theme.ts +1 -1
  12. package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitch.tsx +4 -4
  13. package/src/Components/Filter/{FilterSwitchAdapter → Desktop/FilterSwitch}/FilterSwitchAdapter.tsx +5 -5
  14. package/src/Components/Filter/Filter.storyData.ts +14 -1
  15. package/src/Components/Filter/Filter.tsx +16 -106
  16. package/src/Components/Filter/Filter.types.ts +34 -1
  17. package/src/Components/Filter/Filter.utils.ts +13 -0
  18. package/src/Components/Filter/Mobile/DateSelectOption.tsx +53 -0
  19. package/src/Components/Filter/Mobile/Filter.tsx +57 -0
  20. package/src/Components/Filter/Mobile/FilterAdd.tsx +97 -0
  21. package/src/Components/Filter/Mobile/FilterDrawer.tsx +96 -0
  22. package/src/Components/Filter/Mobile/FilterForm.tsx +236 -0
  23. package/src/Components/Filter/Mobile/FilterItem.tsx +95 -0
  24. package/src/Components/Filter/Mobile/MultiSelectOptions.tsx +69 -0
  25. package/src/Components/Filter/Mobile/SingleSelectOptions.tsx +136 -0
  26. package/src/Components/Filter/hooks/useFilterAdd.ts +68 -0
  27. package/src/Components/Filter/hooks/useFilterForm.ts +131 -0
  28. package/src/Components/Filter/hooks/useIsScrollable.ts +35 -0
  29. package/src/Components/Filter/hooks/useListBox.ts +66 -0
  30. package/src/Components/Form/Checkbox/Checkbox.tsx +4 -2
  31. package/src/Components/Form/Input/Input.theme.ts +27 -11
  32. package/src/Components/Form/Input/Input.tsx +4 -1
  33. package/src/Components/Form/Radio/Radio.tsx +4 -2
  34. package/src/Components/SearchInput/SearchInput.tsx +3 -2
  35. package/src/Components/components.theme.ts +1 -1
  36. package/src/index.ts +3 -4
  37. package/src/Components/Filter/FilterAdd/FilterAdd.tsx +0 -111
  38. /package/src/Components/Filter/{FilterSearch → Desktop}/FilterSearch.tsx +0 -0
  39. /package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitchGroup.tsx +0 -0
@@ -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;
@@ -0,0 +1,236 @@
1
+ import { useRef } from 'react';
2
+ import ProgressSpinner from '../../ProgressSpinner/ProgressSpinner';
3
+ import Divider from '../../Divider/Divider';
4
+ import SearchInput from '../../SearchInput/SearchInput';
5
+ import ControlButton from '../../ControlButton/ControlButton';
6
+ import Text from '../../Text/Text';
7
+ import type { DialogProps } from '../../Dialog/DialogProps';
8
+ import Box from '../../Box/Box';
9
+ import Button from '../../Button/Button';
10
+ import Drawer from '../../Drawer/Drawer';
11
+ import { useFilterContext } from '../Filter.context';
12
+ import useFilterForm from '../hooks/useFilterForm';
13
+ import { FilterValue } from '../Filter.types';
14
+ import ButtonGroup from '../../ButtonGroup/ButtonGroup';
15
+ import useIsScrollable from '../hooks/useIsScrollable';
16
+ import DateSelectOption from './DateSelectOption';
17
+ import MultiSelectOptions from './MultiSelectOptions';
18
+ import SingleSelectOptions from './SingleSelectOptions';
19
+
20
+ type FilterFormProps = Pick<DialogProps, 'isOpen' | 'onClose'> & { selectedCategory: string };
21
+
22
+ const FilterForm = ({ isOpen, onClose, selectedCategory }: FilterFormProps) => {
23
+ const { data, onFilterChange } = useFilterContext();
24
+
25
+ const bodyRef = useRef<HTMLDivElement>(null);
26
+
27
+ const categoryData = data[selectedCategory || ''];
28
+
29
+ const categoryName = categoryData?.categoryName;
30
+ const categoryNamePlural = categoryData?.categoryNamePlural;
31
+ const hasNotFilteredOption =
32
+ categoryData?.hasNotFilteredOption === undefined ? true : categoryData?.hasNotFilteredOption;
33
+ const isMultiple = categoryData?.isMultiple;
34
+ const loadingText = categoryData?.loadingText;
35
+ const type = categoryData?.type;
36
+ const name = categoryData?.categoryName;
37
+
38
+ const onChange = (newCategory: string, newValue: FilterValue) => {
39
+ if (isMultiple) {
40
+ onFilterChange(newCategory, newValue);
41
+ } else {
42
+ onFilterChange(newCategory, newValue);
43
+ onClose();
44
+ }
45
+ };
46
+
47
+ const {
48
+ currentOptionMap,
49
+ getEmptyText,
50
+ isAsync,
51
+ isLoading,
52
+ isSubmitDisabled,
53
+ onClearClick,
54
+ onSearchChange,
55
+ onSubmit,
56
+ items,
57
+ searchValue,
58
+ selected,
59
+ setSelected,
60
+ withSearch,
61
+ } = useFilterForm({
62
+ category: selectedCategory,
63
+ categoryName,
64
+ categoryNamePlural,
65
+ loadingText,
66
+ onChange,
67
+ });
68
+
69
+ const { isScrollable } = useIsScrollable({
70
+ items,
71
+ hasNotFilteredOption,
72
+ ref: bodyRef,
73
+ });
74
+
75
+ const onClear = () => {
76
+ onClearClick();
77
+ onClose();
78
+ };
79
+
80
+ const count = selected.length || 0;
81
+ const showCount = isMultiple && type !== 'dateRange';
82
+
83
+ const clearText = type === 'dateRange' ? 'Reset' : `Clear ${isMultiple ? 'all' : ''}`;
84
+
85
+ const showFooter = selected.length > 0;
86
+
87
+ return (
88
+ <Drawer
89
+ bodyPadding="0"
90
+ bodyProps={{ overflowY: 'auto' }}
91
+ bodyRef={bodyRef}
92
+ contentProps={{ zIndex: 'dialog', top: '0' }}
93
+ headerPadding={16}
94
+ hideCloseButton
95
+ isOpen={isOpen}
96
+ maxWidth="100%"
97
+ onClose={onClose}
98
+ padding={0}
99
+ title={
100
+ <Box display="flex" alignItems="center" gap="12">
101
+ <ControlButton
102
+ aria-label="Back"
103
+ color="icon/secondary"
104
+ iconName="ArrowLeft"
105
+ isTooltipDisabled
106
+ onClick={onClose}
107
+ size="sm"
108
+ />
109
+ <Box display="flex" flexDirection="column">
110
+ <Text as="h6" color="text/tertiary" textStyle="heading/h6">
111
+ Filter
112
+ </Text>
113
+ <Text as="h3" color="text/primary" textStyle="heading/mobile/h3">
114
+ {name}
115
+ </Text>
116
+ </Box>
117
+ </Box>
118
+ }
119
+ footer={
120
+ showFooter && (hasNotFilteredOption || isMultiple) ? (
121
+ <Box width="100%">
122
+ <Divider />
123
+ <ButtonGroup
124
+ backgroundColor="background/primary"
125
+ display="flex"
126
+ gap="12"
127
+ justifyContent="space-between"
128
+ paddingBlock="12"
129
+ paddingInline="16"
130
+ width="100%"
131
+ >
132
+ {hasNotFilteredOption && (
133
+ <Button variant="secondary" onClick={onClear} flex="1" maxWidth="calc(50% - 0.5rem)" size="md">
134
+ {clearText}
135
+ </Button>
136
+ )}
137
+ {isMultiple && (
138
+ <Button
139
+ alignSelf="flex-end"
140
+ flex="1"
141
+ isDisabled={isSubmitDisabled}
142
+ onClick={() => {
143
+ onSubmit();
144
+ onClose();
145
+ }}
146
+ size="md"
147
+ type="submit"
148
+ >
149
+ Apply {showCount && count ? `(${count})` : undefined}
150
+ </Button>
151
+ )}
152
+ </ButtonGroup>
153
+ </Box>
154
+ ) : null
155
+ }
156
+ >
157
+ <Box display="flex" flexDirection="column" gap="16">
158
+ <Box
159
+ backgroundColor="background/primary"
160
+ display="flex"
161
+ flexDirection="column"
162
+ gap="8"
163
+ marginBottom="8"
164
+ position="sticky"
165
+ top="0"
166
+ >
167
+ {(withSearch || isAsync) && (
168
+ <>
169
+ <Divider />
170
+ <SearchInput
171
+ marginInline="12"
172
+ onChange={onSearchChange}
173
+ placeholder="Search for options"
174
+ value={searchValue}
175
+ variant="mobile"
176
+ />
177
+ </>
178
+ )}
179
+ <Divider />
180
+ </Box>
181
+ <Box display="flex" flexDirection="column" gap="8">
182
+ {isLoading && (
183
+ <Box display="flex" alignItems="center" padding="24">
184
+ <ProgressSpinner color="sys/primary/base" marginRight="12" size="16" />
185
+ <Text color="text/secondary">{loadingText || 'Loading...'}</Text>
186
+ </Box>
187
+ )}
188
+ {type === 'dateRange' && (
189
+ <DateSelectOption
190
+ key={selectedCategory}
191
+ onChange={setSelected}
192
+ onClear={onClear}
193
+ selectedItems={selected}
194
+ />
195
+ )}
196
+ {type !== 'dateRange' && isMultiple && (
197
+ <MultiSelectOptions
198
+ currentOptionMap={currentOptionMap}
199
+ emptyText={getEmptyText()}
200
+ isLoading={isLoading}
201
+ items={items}
202
+ onChange={setSelected}
203
+ selectedItems={selected}
204
+ />
205
+ )}
206
+ {type !== 'dateRange' && !isMultiple && (
207
+ <SingleSelectOptions
208
+ currentOptionMap={currentOptionMap}
209
+ emptyText={getEmptyText()}
210
+ hasNotFilteredOption={hasNotFilteredOption}
211
+ isLoading={isLoading}
212
+ items={items}
213
+ onChange={(option: string) => {
214
+ onChange(selectedCategory, [option]);
215
+ }}
216
+ selectedItems={selected}
217
+ />
218
+ )}
219
+ {isScrollable && (
220
+ <Box
221
+ background="linear-gradient(0deg, white 0%, rgba(255, 255, 255, 0) 100%)"
222
+ bottom="0"
223
+ height="32"
224
+ left="0"
225
+ pointerEvents="none"
226
+ position="sticky"
227
+ right="0"
228
+ />
229
+ )}
230
+ </Box>
231
+ </Box>
232
+ </Drawer>
233
+ );
234
+ };
235
+
236
+ export default FilterForm;
@@ -0,0 +1,95 @@
1
+ import { useId } from 'react';
2
+ import { FormControl } from 'chakra-ui-2--react';
3
+ import FormLabel from '../../Form/FormLabel';
4
+ import Button from '../../Button/Button';
5
+ import Box from '../../Box/Box';
6
+ import Icon from '../../Icon/Icon';
7
+ import IconButton from '../../IconButton/IconButton';
8
+ import { useFilterContext } from '../Filter.context';
9
+ import { getDateRangeLabel, getOptionLabel } from '../Filter.utils';
10
+
11
+ export type FilterItemProps = {
12
+ category: string;
13
+ };
14
+
15
+ const FilterItem = ({ category }: FilterItemProps) => {
16
+ const { data, onFilterClear, setSelectedCategory, state } = useFilterContext();
17
+
18
+ const value = state[category];
19
+
20
+ const { categoryName, categoryNamePlural, isMultiple, optionsMap, unfilteredLabel, type } = data[category];
21
+
22
+ const pluralCategoryString = (categoryNamePlural || `${category}s`).toLowerCase();
23
+
24
+ const getText = () => {
25
+ if (!value || value.length === 0) {
26
+ return unfilteredLabel || `All ${pluralCategoryString}`;
27
+ }
28
+
29
+ if (value.length === 2 && type === 'dateRange') {
30
+ return getDateRangeLabel(value);
31
+ }
32
+
33
+ if (value.length > 1) {
34
+ return `${value.length} ${pluralCategoryString}`;
35
+ }
36
+
37
+ return getOptionLabel(value[0], optionsMap);
38
+ };
39
+
40
+ const buttonId = useId();
41
+ return (
42
+ <FormControl flex="1" isRequired>
43
+ <FormLabel htmlFor={buttonId}>{isMultiple && type !== 'dateRange' ? categoryNamePlural : categoryName}</FormLabel>
44
+ {type === 'tag' && (
45
+ <Box display="flex" alignItems="center">
46
+ <Button
47
+ borderRight="0"
48
+ borderRightRadius="0"
49
+ fontWeight="normal"
50
+ id={buttonId}
51
+ justifyContent="flex-start"
52
+ onClick={() => setSelectedCategory(category)}
53
+ rightIconName={type !== 'tag' ? 'ChevronRight' : undefined}
54
+ size="lg"
55
+ variant="secondary"
56
+ width="100%"
57
+ >
58
+ {getText()}
59
+ </Button>
60
+ <IconButton
61
+ aria-label="Clear"
62
+ borderLeft="0"
63
+ borderLeftRadius="0"
64
+ iconName="Cross"
65
+ onClick={() => onFilterClear(category)}
66
+ variant="secondary"
67
+ />
68
+ </Box>
69
+ )}
70
+ {type !== 'tag' && (
71
+ <Button
72
+ fontWeight="normal"
73
+ id={buttonId}
74
+ justifyContent="space-between"
75
+ onClick={() => setSelectedCategory(category)}
76
+ rightIconName="ChevronRight"
77
+ size="lg"
78
+ variant="secondary"
79
+ width="100%"
80
+ >
81
+ {type === 'dateRange' ? (
82
+ <Box display="flex" alignItems="center" gap="8">
83
+ <Icon color="icon/tertiary" name="Calendar" />
84
+ {getText()}
85
+ </Box>
86
+ ) : (
87
+ getText()
88
+ )}
89
+ </Button>
90
+ )}
91
+ </FormControl>
92
+ );
93
+ };
94
+
95
+ export default FilterItem;
@@ -0,0 +1,69 @@
1
+ import { Checkbox, CheckboxGroup } from 'chakra-ui-2--react';
2
+ import Box from '../../Box/Box';
3
+ import Text from '../../Text/Text';
4
+ import { FilterOptionsMap } from '../Filter.types';
5
+ import { getOptionLabel } from '../Filter.utils';
6
+ import { MAX_ITEMS } from '../hooks/useFilterForm';
7
+
8
+ type MultiSelectOptionsProps = {
9
+ currentOptionMap?: FilterOptionsMap;
10
+ emptyText?: string;
11
+ isLoading: boolean;
12
+ items: string[];
13
+ onChange: (option: string[]) => void;
14
+ selectedItems: string[];
15
+ };
16
+
17
+ const MultiSelectOptions = ({
18
+ currentOptionMap,
19
+ emptyText,
20
+ isLoading,
21
+ items,
22
+ onChange,
23
+ selectedItems,
24
+ }: MultiSelectOptionsProps) => {
25
+ if (isLoading) {
26
+ return null;
27
+ }
28
+
29
+ return (
30
+ <CheckboxGroup onChange={onChange} value={selectedItems}>
31
+ <Box>
32
+ {items.length ? (
33
+ items?.slice(0, MAX_ITEMS).map((option) => {
34
+ const id = `checkbox-${option}`;
35
+ const isSelected = selectedItems.includes(option);
36
+
37
+ return (
38
+ <Box
39
+ alignItems="center"
40
+ as="label"
41
+ backgroundColor={isSelected ? 'background/selected' : 'transparent'}
42
+ display="flex"
43
+ gap="16"
44
+ htmlFor={id}
45
+ paddingBlock="12"
46
+ paddingInlineStart="24"
47
+ paddingInlineEnd="24"
48
+ cursor="pointer"
49
+ role="option"
50
+ _focusWithin={{
51
+ backgroundColor: isSelected ? 'background/selected-hover' : 'background/hover',
52
+ }}
53
+ _hover={{ backgroundColor: isSelected ? 'background/selected-hover' : 'background/hover' }}
54
+ _active={{ backgroundColor: 'background/active' }}
55
+ >
56
+ <Checkbox id={id} key={option} value={option} position="static" />
57
+ {getOptionLabel(option, currentOptionMap)}
58
+ </Box>
59
+ );
60
+ })
61
+ ) : (
62
+ <Text paddingInline={16}>{emptyText}</Text>
63
+ )}
64
+ </Box>
65
+ </CheckboxGroup>
66
+ );
67
+ };
68
+
69
+ export default MultiSelectOptions;