@bitrise/bitkit 12.70.0-alpha-filter-1.1 → 12.70.0-alpha-filter-2.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/package.json +30 -30
- package/src/Components/Avatar/Avatar.tsx +4 -1
- package/src/Components/Filter/Filter.storyData.ts +14 -2
- package/src/Components/Filter/Filter.tsx +57 -40
- package/src/Components/Filter/Filter.types.ts +5 -1
- package/src/Components/Filter/Filter.utils.ts +1 -1
- package/src/Components/Filter/FilterAdd/FilterAdd.tsx +2 -2
- package/src/Components/Filter/FilterDate/FilterDate.tsx +7 -8
- package/src/Components/Filter/FilterItem/FilterItem.tsx +14 -17
- package/src/Components/Filter/FilterSearch/FilterSearch.tsx +7 -6
- package/src/Components/Filter/FilterSwitchAdapter/FilterSwitchAdapter.tsx +31 -0
- package/src/Components/Form/Input/Input.tsx +1 -0
- package/src/Components/Form/Textarea/Textarea.tsx +10 -1
- package/src/Components/Select/Select.tsx +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitrise/bitkit",
|
|
3
3
|
"description": "Bitrise React component library",
|
|
4
|
-
"version": "12.70.0-alpha-filter-
|
|
4
|
+
"version": "12.70.0-alpha-filter-2.1",
|
|
5
5
|
"repository": "git@github.com:bitrise-io/bitkit.git",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"license": "UNLICENSED",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@emotion/react": "^11.11.1",
|
|
29
29
|
"@emotion/styled": "^11.11.0",
|
|
30
30
|
"@floating-ui/react-dom-interactions": "^0.8.1",
|
|
31
|
-
"framer-motion": "^10.16.
|
|
31
|
+
"framer-motion": "^10.16.16",
|
|
32
32
|
"luxon": "^3.4.4",
|
|
33
33
|
"react": "^18.2.0",
|
|
34
34
|
"react-dom": "^18.2.0",
|
|
@@ -40,38 +40,38 @@
|
|
|
40
40
|
"react-dom": "^18.2.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@babel/core": "^7.23.
|
|
44
|
-
"@babel/preset-env": "^7.23.
|
|
43
|
+
"@babel/core": "^7.23.6",
|
|
44
|
+
"@babel/preset-env": "^7.23.6",
|
|
45
45
|
"@babel/preset-react": "^7.23.3",
|
|
46
46
|
"@babel/preset-typescript": "^7.23.3",
|
|
47
|
-
"@bitrise/eslint-plugin": "^2.3.
|
|
47
|
+
"@bitrise/eslint-plugin": "^2.3.3",
|
|
48
48
|
"@commitlint/cli": "^17.8.0",
|
|
49
49
|
"@commitlint/config-conventional": "^17.8.0",
|
|
50
|
-
"@google-cloud/storage": "^7.
|
|
50
|
+
"@google-cloud/storage": "^7.7.0",
|
|
51
51
|
"@semantic-release/commit-analyzer": "^11.1.0",
|
|
52
52
|
"@semantic-release/git": "^10.0.1",
|
|
53
|
-
"@storybook/addon-actions": "^7.
|
|
54
|
-
"@storybook/addon-essentials": "^7.
|
|
55
|
-
"@storybook/addon-interactions": "^7.
|
|
56
|
-
"@storybook/addon-links": "^7.
|
|
57
|
-
"@storybook/addons": "^7.
|
|
58
|
-
"@storybook/blocks": "^7.
|
|
59
|
-
"@storybook/react": "^7.
|
|
60
|
-
"@storybook/react-webpack5": "^7.
|
|
53
|
+
"@storybook/addon-actions": "^7.6.4",
|
|
54
|
+
"@storybook/addon-essentials": "^7.6.4",
|
|
55
|
+
"@storybook/addon-interactions": "^7.6.4",
|
|
56
|
+
"@storybook/addon-links": "^7.6.4",
|
|
57
|
+
"@storybook/addons": "^7.6.4",
|
|
58
|
+
"@storybook/blocks": "^7.6.4",
|
|
59
|
+
"@storybook/react": "^7.6.4",
|
|
60
|
+
"@storybook/react-webpack5": "^7.6.4",
|
|
61
61
|
"@storybook/testing-library": "^0.2.2",
|
|
62
|
-
"@storybook/theming": "^7.
|
|
62
|
+
"@storybook/theming": "^7.6.4",
|
|
63
63
|
"@testing-library/dom": "^9.3.3",
|
|
64
|
-
"@testing-library/jest-dom": "^6.1.
|
|
65
|
-
"@testing-library/react": "^14.1.
|
|
64
|
+
"@testing-library/jest-dom": "^6.1.5",
|
|
65
|
+
"@testing-library/react": "^14.1.2",
|
|
66
66
|
"@testing-library/user-event": "^14.5.1",
|
|
67
|
-
"@types/jest": "^29.5.
|
|
68
|
-
"@types/luxon": "^3.3.
|
|
69
|
-
"@types/react": "^18.2.
|
|
70
|
-
"@types/react-dom": "^18.2.
|
|
71
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
72
|
-
"@typescript-eslint/parser": "^6.
|
|
67
|
+
"@types/jest": "^29.5.11",
|
|
68
|
+
"@types/luxon": "^3.3.7",
|
|
69
|
+
"@types/react": "^18.2.43",
|
|
70
|
+
"@types/react-dom": "^18.2.17",
|
|
71
|
+
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
|
72
|
+
"@typescript-eslint/parser": "^6.14.0",
|
|
73
73
|
"axios": "^1.6.2",
|
|
74
|
-
"eslint": "^8.
|
|
74
|
+
"eslint": "^8.55.0",
|
|
75
75
|
"eslint-plugin-import": "^2.29.0",
|
|
76
76
|
"eslint-plugin-jest": "^27.6.0",
|
|
77
77
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
|
@@ -79,15 +79,15 @@
|
|
|
79
79
|
"eslint-plugin-react": "^7.33.2",
|
|
80
80
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
81
81
|
"eslint-plugin-storybook": "^0.6.15",
|
|
82
|
-
"eslint-plugin-testing-library": "^6.
|
|
82
|
+
"eslint-plugin-testing-library": "^6.2.0",
|
|
83
83
|
"glob": "^10.3.10",
|
|
84
84
|
"jest": "^29.7.0",
|
|
85
85
|
"jest-environment-jsdom": "^29.7.0",
|
|
86
|
-
"jsdom": "^
|
|
87
|
-
"prettier": "^3.1.
|
|
88
|
-
"react-hook-form": "^7.
|
|
89
|
-
"semantic-release": "^22.0.
|
|
90
|
-
"storybook": "^7.
|
|
86
|
+
"jsdom": "^23.0.1",
|
|
87
|
+
"prettier": "^3.1.1",
|
|
88
|
+
"react-hook-form": "^7.49.0",
|
|
89
|
+
"semantic-release": "^22.0.12",
|
|
90
|
+
"storybook": "^7.6.4",
|
|
91
91
|
"ts-jest": "^29.1.1",
|
|
92
92
|
"typescript": "^4.8.4"
|
|
93
93
|
},
|
|
@@ -12,7 +12,10 @@ const getInitials = (name: string) => {
|
|
|
12
12
|
if (name.length < 3) {
|
|
13
13
|
return name;
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
const nameArray = Array.from(name);
|
|
17
|
+
|
|
18
|
+
return `${nameArray[0]}${nameArray[nameArray.length - 1]}`;
|
|
16
19
|
};
|
|
17
20
|
|
|
18
21
|
const Avatar = forwardRef<AvatarProps, 'span'>((props, ref) => (
|
|
@@ -9,23 +9,26 @@ export const FILTER_STORY_DATA: FilterData = {
|
|
|
9
9
|
date_range: {
|
|
10
10
|
categoryName: 'Date',
|
|
11
11
|
categoryNamePlural: 'dates',
|
|
12
|
-
|
|
12
|
+
type: 'dateRange',
|
|
13
13
|
},
|
|
14
14
|
pipeline: {
|
|
15
15
|
categoryName: 'Pipeline',
|
|
16
16
|
categoryNamePlural: 'Pipelines',
|
|
17
17
|
options: FILTER_STORY_OPTIONS,
|
|
18
|
+
type: 'tag',
|
|
18
19
|
},
|
|
19
20
|
stage: {
|
|
20
21
|
categoryName: 'Stage',
|
|
21
22
|
categoryNamePlural: 'Stages',
|
|
22
23
|
options: FILTER_STORY_OPTIONS,
|
|
23
24
|
dependsOn: ['pipeline'],
|
|
25
|
+
type: 'tag',
|
|
24
26
|
},
|
|
25
27
|
workflow: {
|
|
26
28
|
categoryName: 'Workflow',
|
|
27
29
|
isMultiple: true,
|
|
28
30
|
options: FILTER_STORY_OPTIONS,
|
|
31
|
+
type: 'tag',
|
|
29
32
|
},
|
|
30
33
|
branch: {
|
|
31
34
|
options: [
|
|
@@ -34,16 +37,17 @@ export const FILTER_STORY_DATA: FilterData = {
|
|
|
34
37
|
'master',
|
|
35
38
|
'CI-2264-consolidate-other-provider-type-to-custom',
|
|
36
39
|
],
|
|
40
|
+
type: 'tag',
|
|
37
41
|
},
|
|
38
42
|
app: {
|
|
39
43
|
categoryName: 'App',
|
|
40
|
-
isPermanent: true,
|
|
41
44
|
options: ['46b6b9a78a418ee8', '32b14416be4b7b24', '0a248b278e135ea7'],
|
|
42
45
|
optionsMap: {
|
|
43
46
|
'46b6b9a78a418ee8': 'bitrise-website',
|
|
44
47
|
'32b14416be4b7b24': 'bitkit',
|
|
45
48
|
'0a248b278e135ea7': 'pipeline-service',
|
|
46
49
|
},
|
|
50
|
+
type: 'select',
|
|
47
51
|
},
|
|
48
52
|
test_case: {
|
|
49
53
|
categoryName: 'Test case',
|
|
@@ -56,16 +60,24 @@ export const FILTER_STORY_DATA: FilterData = {
|
|
|
56
60
|
});
|
|
57
61
|
},
|
|
58
62
|
options: ['default 1', 'default 2', 'default 3'],
|
|
63
|
+
type: 'tag',
|
|
64
|
+
},
|
|
65
|
+
cache_type: {
|
|
66
|
+
options: ['gradle', 'bazel'],
|
|
67
|
+
type: 'switch',
|
|
59
68
|
},
|
|
60
69
|
};
|
|
61
70
|
|
|
62
71
|
export const FILTER_STORY_INIT_STATE: FilterState = {
|
|
63
72
|
pipeline: ['ipsum'],
|
|
64
73
|
app: ['46b6b9a78a418ee8'],
|
|
74
|
+
cache_type: ['gradle'],
|
|
65
75
|
};
|
|
66
76
|
|
|
67
77
|
export const FILTER_STORY_CONTEXT: FilterContextType = {
|
|
68
78
|
data: FILTER_STORY_DATA,
|
|
69
79
|
setPopoverOpen: () => {},
|
|
70
80
|
state: FILTER_STORY_INIT_STATE,
|
|
81
|
+
onFilterChange: () => {},
|
|
82
|
+
onFilterClear: () => {},
|
|
71
83
|
};
|
|
@@ -6,29 +6,47 @@ import Divider from '../Divider/Divider';
|
|
|
6
6
|
import Icon from '../Icon/Icon';
|
|
7
7
|
import { FilterContext } from './Filter.context';
|
|
8
8
|
import { FilterStyle } from './Filter.theme';
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import {
|
|
10
|
+
FilterCategoryProps,
|
|
11
|
+
FilterContextType,
|
|
12
|
+
FilterData,
|
|
13
|
+
FilterState,
|
|
14
|
+
FilterType,
|
|
15
|
+
FilterValue,
|
|
16
|
+
} from './Filter.types';
|
|
17
|
+
import { getDependents } from './Filter.utils';
|
|
11
18
|
import FilterAdd from './FilterAdd/FilterAdd';
|
|
12
19
|
import FilterItem from './FilterItem/FilterItem';
|
|
13
20
|
import FilterSearch from './FilterSearch/FilterSearch';
|
|
14
21
|
import FilterDate from './FilterDate/FilterDate';
|
|
22
|
+
import FilterSwitchAdapter from './FilterSwitchAdapter/FilterSwitchAdapter';
|
|
15
23
|
|
|
16
24
|
export interface FilterProps extends Omit<BoxProps, 'onChange'> {
|
|
17
25
|
filtersDependOn?: string[];
|
|
18
26
|
initialData: FilterData;
|
|
27
|
+
initialState: FilterState;
|
|
19
28
|
isLoading?: boolean;
|
|
20
29
|
onChange: (state: FilterState) => void;
|
|
21
30
|
showSearch?: boolean;
|
|
22
|
-
state: FilterState;
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
const Filter = (props: FilterProps) => {
|
|
26
|
-
const { filtersDependOn, initialData, isLoading, onChange, showSearch,
|
|
34
|
+
const { filtersDependOn, initialData, initialState, isLoading, onChange, showSearch, ...rest } = props;
|
|
27
35
|
|
|
28
36
|
const isInited = useRef<boolean>(false);
|
|
29
37
|
|
|
30
38
|
const filterStyle = useMultiStyleConfig('Filter') as FilterStyle;
|
|
31
39
|
|
|
40
|
+
const state: FilterState = {};
|
|
41
|
+
Object.entries(initialState).forEach(([category, values]) => {
|
|
42
|
+
if (values?.length) {
|
|
43
|
+
const cleanValues = values.filter((v) => v !== null && v !== '' && v !== undefined);
|
|
44
|
+
if (cleanValues.length) {
|
|
45
|
+
state[category] = cleanValues;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
32
50
|
const [data] = useState<FilterData>(initialData);
|
|
33
51
|
const [isPopoverOpen, setPopoverOpen] = useState<boolean>(false);
|
|
34
52
|
|
|
@@ -58,7 +76,7 @@ const Filter = (props: FilterProps) => {
|
|
|
58
76
|
onChange(newState);
|
|
59
77
|
};
|
|
60
78
|
|
|
61
|
-
const
|
|
79
|
+
const onFilterClear = (category: string) => {
|
|
62
80
|
onChange(deleteFromState(category, state));
|
|
63
81
|
};
|
|
64
82
|
|
|
@@ -66,14 +84,19 @@ const Filter = (props: FilterProps) => {
|
|
|
66
84
|
onChange({});
|
|
67
85
|
};
|
|
68
86
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
const filters = {
|
|
88
|
+
search: {},
|
|
89
|
+
select: {},
|
|
90
|
+
switch: {},
|
|
91
|
+
dateRange: {},
|
|
92
|
+
tag: {},
|
|
93
|
+
} as Record<FilterType, Record<string, FilterCategoryProps>>;
|
|
72
94
|
|
|
73
|
-
|
|
74
|
-
|
|
95
|
+
Object.entries(data).forEach(([category, value]) => {
|
|
96
|
+
filters[value.type || 'tag'][category] = value;
|
|
97
|
+
});
|
|
75
98
|
|
|
76
|
-
const
|
|
99
|
+
const stateCategories = Object.keys(state).filter((c) => !['date_range', 'search'].includes(c));
|
|
77
100
|
|
|
78
101
|
const showClearFilters = stateCategories.length > 0 || (state.search && state.search.length > 0);
|
|
79
102
|
|
|
@@ -82,10 +105,12 @@ const Filter = (props: FilterProps) => {
|
|
|
82
105
|
data: initialData,
|
|
83
106
|
filtersDependOn,
|
|
84
107
|
isLoading,
|
|
108
|
+
onFilterChange,
|
|
109
|
+
onFilterClear,
|
|
85
110
|
setPopoverOpen,
|
|
86
111
|
state,
|
|
87
112
|
}),
|
|
88
|
-
[filtersDependOn, isLoading, initialData, setPopoverOpen, state],
|
|
113
|
+
[filtersDependOn, isLoading, initialData, onFilterChange, onFilterClear, setPopoverOpen, state],
|
|
89
114
|
);
|
|
90
115
|
|
|
91
116
|
useEffect(() => {
|
|
@@ -102,27 +127,25 @@ const Filter = (props: FilterProps) => {
|
|
|
102
127
|
</Modal>
|
|
103
128
|
<Box sx={filterStyle.content}>
|
|
104
129
|
<Icon name="Filter" sx={filterStyle.icon} />
|
|
105
|
-
|
|
106
|
-
{
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return null;
|
|
125
|
-
})}
|
|
130
|
+
|
|
131
|
+
{Object.keys(filters.switch).map((category) => (
|
|
132
|
+
<FilterSwitchAdapter category={category} key={category} />
|
|
133
|
+
))}
|
|
134
|
+
|
|
135
|
+
{Object.keys(filters.dateRange).map((category) => (
|
|
136
|
+
<FilterDate category={category} key={category} />
|
|
137
|
+
))}
|
|
138
|
+
|
|
139
|
+
{Object.keys(filters.select).map((category) => (
|
|
140
|
+
<FilterItem category={category} key={category} />
|
|
141
|
+
))}
|
|
142
|
+
{Object.keys(filters.tag).map((category) => {
|
|
143
|
+
if (!state[category]) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
return <FilterItem category={category} key={category} />;
|
|
147
|
+
})}
|
|
148
|
+
|
|
126
149
|
<FilterAdd onChange={onFilterChange} />
|
|
127
150
|
</Box>
|
|
128
151
|
{(showClearFilters || showSearch) && (
|
|
@@ -142,13 +165,7 @@ const Filter = (props: FilterProps) => {
|
|
|
142
165
|
{showClearFilters && showSearch && (
|
|
143
166
|
<Divider orientation="vertical" size="1" variant="solid" flexShrink="0" />
|
|
144
167
|
)}
|
|
145
|
-
{showSearch && (
|
|
146
|
-
<FilterSearch
|
|
147
|
-
onChange={onFilterChange}
|
|
148
|
-
onClear={onClear}
|
|
149
|
-
value={(state.Search && state.Search[0]) || ''}
|
|
150
|
-
/>
|
|
151
|
-
)}
|
|
168
|
+
{showSearch && <FilterSearch onChange={onFilterChange} value={(state.Search && state.Search[0]) || ''} />}
|
|
152
169
|
</Box>
|
|
153
170
|
)}
|
|
154
171
|
</Box>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Dispatch, SetStateAction } from 'react';
|
|
2
2
|
|
|
3
|
+
export type FilterType = 'dateRange' | 'search' | 'select' | 'switch' | 'tag';
|
|
4
|
+
|
|
3
5
|
export type FilterOptions = string[];
|
|
4
6
|
export type FilterValue = string[];
|
|
5
7
|
export type FilterOptionsMap = Record<string, string>;
|
|
@@ -11,10 +13,10 @@ export type FilterCategoryProps = {
|
|
|
11
13
|
categoryNamePlural?: string;
|
|
12
14
|
dependsOn?: string[];
|
|
13
15
|
isMultiple?: boolean;
|
|
14
|
-
isPermanent?: boolean;
|
|
15
16
|
onAsyncSearch?: FilterSearchCallback;
|
|
16
17
|
options?: FilterOptions;
|
|
17
18
|
optionsMap?: FilterOptionsMap;
|
|
19
|
+
type?: FilterType;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export type FilterData = Record<string, FilterCategoryProps>;
|
|
@@ -24,6 +26,8 @@ export interface FilterContextType {
|
|
|
24
26
|
data: FilterData;
|
|
25
27
|
filtersDependOn?: string[];
|
|
26
28
|
isLoading?: boolean;
|
|
29
|
+
onFilterClear: (category: string) => void;
|
|
30
|
+
onFilterChange: (category: string, value: FilterValue) => void;
|
|
27
31
|
setPopoverOpen: Dispatch<SetStateAction<boolean>>;
|
|
28
32
|
state: FilterState;
|
|
29
33
|
}
|
|
@@ -11,7 +11,7 @@ export const getDependents = (data: FilterData, categoryKey: string, filtersDepe
|
|
|
11
11
|
const dependents: string[] = [];
|
|
12
12
|
if (filtersDependOn && filtersDependOn.includes(categoryKey)) {
|
|
13
13
|
Object.keys(data).forEach((category) => {
|
|
14
|
-
if (
|
|
14
|
+
if (data[category].type !== 'select') {
|
|
15
15
|
dependents.push(category);
|
|
16
16
|
}
|
|
17
17
|
});
|
|
@@ -67,8 +67,8 @@ const FilterAdd = (props: FilterAddProps) => {
|
|
|
67
67
|
<FilterForm category={selectedCategory} onChange={onFilterChange} onCancel={onClose} />
|
|
68
68
|
) : (
|
|
69
69
|
Object.keys(data).map((category) => {
|
|
70
|
-
const { categoryName, dependsOn,
|
|
71
|
-
if (
|
|
70
|
+
const { categoryName, dependsOn, type } = data[category];
|
|
71
|
+
if (type !== 'tag') {
|
|
72
72
|
return null;
|
|
73
73
|
}
|
|
74
74
|
return (
|
|
@@ -9,30 +9,29 @@ import Text from '../../Text/Text';
|
|
|
9
9
|
import Tooltip from '../../Tooltip/Tooltip';
|
|
10
10
|
import { useFilterContext } from '../Filter.context';
|
|
11
11
|
import { FilterStyle } from '../Filter.theme';
|
|
12
|
-
import { FilterValue } from '../Filter.types';
|
|
13
12
|
|
|
14
13
|
export type FilterDateProps = {
|
|
15
|
-
|
|
16
|
-
onClear: (category: string) => void;
|
|
17
|
-
value: FilterValue;
|
|
14
|
+
category: string;
|
|
18
15
|
};
|
|
19
16
|
|
|
20
17
|
const FilterDate = (props: FilterDateProps) => {
|
|
21
|
-
const {
|
|
18
|
+
const { category } = props;
|
|
22
19
|
const filterStyle = useMultiStyleConfig('Filter') as FilterStyle;
|
|
23
20
|
|
|
24
|
-
const { isLoading, setPopoverOpen } = useFilterContext();
|
|
21
|
+
const { isLoading, onFilterChange, onFilterClear, setPopoverOpen, state } = useFilterContext();
|
|
25
22
|
|
|
26
23
|
const { isOpen, onClose, onToggle } = useDisclosure();
|
|
27
24
|
|
|
25
|
+
const value = state[category];
|
|
26
|
+
|
|
28
27
|
const onDateRangeApply = (range: DateRange) => {
|
|
29
28
|
if (range.from && range.to) {
|
|
30
|
-
|
|
29
|
+
onFilterChange('date_range', [String(range.from.toMillis()), String(range.to.toMillis())]);
|
|
31
30
|
}
|
|
32
31
|
};
|
|
33
32
|
|
|
34
33
|
const onClearClick = () => {
|
|
35
|
-
|
|
34
|
+
onFilterClear('date_range');
|
|
36
35
|
onClose();
|
|
37
36
|
};
|
|
38
37
|
|
|
@@ -9,24 +9,23 @@ import PopoverTrigger from '../../Popover/PopoverTrigger';
|
|
|
9
9
|
import Text from '../../Text/Text';
|
|
10
10
|
import Tooltip from '../../Tooltip/Tooltip';
|
|
11
11
|
import { FilterStyle } from '../Filter.theme';
|
|
12
|
-
import {
|
|
12
|
+
import { FilterValue } from '../Filter.types';
|
|
13
13
|
import FilterForm from '../FilterForm/FilterForm';
|
|
14
14
|
import { useFilterContext } from '../Filter.context';
|
|
15
15
|
import { getOptionLabel } from '../Filter.utils';
|
|
16
16
|
|
|
17
17
|
export type FilterItemProps = {
|
|
18
18
|
category: string;
|
|
19
|
-
categoryName?: string;
|
|
20
|
-
categoryNamePlural?: string;
|
|
21
|
-
isPermanent?: boolean;
|
|
22
|
-
onChange: (category: string, value: FilterValue) => void;
|
|
23
|
-
onClear: (category: string) => void;
|
|
24
|
-
optionsMap?: FilterOptionsMap;
|
|
25
|
-
value: FilterValue;
|
|
26
19
|
};
|
|
27
20
|
|
|
28
21
|
const FilterItem = (props: FilterItemProps) => {
|
|
29
|
-
const { category
|
|
22
|
+
const { category } = props;
|
|
23
|
+
|
|
24
|
+
const { data, isLoading, onFilterChange, onFilterClear, setPopoverOpen, state } = useFilterContext();
|
|
25
|
+
|
|
26
|
+
const { categoryName, categoryNamePlural, optionsMap, type } = data[category];
|
|
27
|
+
|
|
28
|
+
const value = state[category];
|
|
30
29
|
|
|
31
30
|
const pluralCategoryString = (categoryNamePlural || `${category}s`).toLowerCase();
|
|
32
31
|
|
|
@@ -34,8 +33,6 @@ const FilterItem = (props: FilterItemProps) => {
|
|
|
34
33
|
|
|
35
34
|
const filterStyle = useMultiStyleConfig('Filter') as FilterStyle;
|
|
36
35
|
|
|
37
|
-
const { isLoading, setPopoverOpen } = useFilterContext();
|
|
38
|
-
|
|
39
36
|
const onToggle = () => {
|
|
40
37
|
togglePopover();
|
|
41
38
|
};
|
|
@@ -45,9 +42,9 @@ const FilterItem = (props: FilterItemProps) => {
|
|
|
45
42
|
setPopoverOpen(false);
|
|
46
43
|
};
|
|
47
44
|
|
|
48
|
-
const
|
|
45
|
+
const onChange = (newCategory: string, newValue: FilterValue) => {
|
|
49
46
|
onClose();
|
|
50
|
-
|
|
47
|
+
onFilterChange(newCategory, newValue);
|
|
51
48
|
};
|
|
52
49
|
|
|
53
50
|
const getText = () => {
|
|
@@ -73,15 +70,15 @@ const FilterItem = (props: FilterItemProps) => {
|
|
|
73
70
|
<Tooltip isDisabled={isLoading} label="Edit">
|
|
74
71
|
<Text as="button" disabled={isLoading} onClick={onToggle} size="2" sx={filterStyle.tagEdit}>
|
|
75
72
|
{getText()}
|
|
76
|
-
{
|
|
73
|
+
{type === 'select' && <Icon name="ChevronDown" size="16" />}
|
|
77
74
|
</Text>
|
|
78
75
|
</Tooltip>
|
|
79
|
-
{
|
|
76
|
+
{type !== 'select' && (
|
|
80
77
|
<IconButton
|
|
81
78
|
aria-label={isLoading ? '' : 'Clear'}
|
|
82
79
|
iconName="CloseSmall"
|
|
83
80
|
isDisabled={isLoading}
|
|
84
|
-
onClick={() =>
|
|
81
|
+
onClick={() => onFilterClear(category)}
|
|
85
82
|
size="small"
|
|
86
83
|
variant="tertiary"
|
|
87
84
|
sx={filterStyle.tagClear}
|
|
@@ -91,7 +88,7 @@ const FilterItem = (props: FilterItemProps) => {
|
|
|
91
88
|
</Box>
|
|
92
89
|
</PopoverTrigger>
|
|
93
90
|
<PopoverContent>
|
|
94
|
-
<FilterForm category={category} categoryName={categoryName} onChange={
|
|
91
|
+
<FilterForm category={category} categoryName={categoryName} onChange={onChange} onCancel={onClose} />
|
|
95
92
|
</PopoverContent>
|
|
96
93
|
</Popover>
|
|
97
94
|
);
|
|
@@ -15,12 +15,11 @@ import { FilterValue } from '../Filter.types';
|
|
|
15
15
|
|
|
16
16
|
export interface FilterSearchProps extends Omit<InputProps, 'onChange' | 'value'> {
|
|
17
17
|
onChange: (category: string, selected: FilterValue) => void;
|
|
18
|
-
onClear: (category: string) => void;
|
|
19
18
|
value: string;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
const FilterSearch = (props: FilterSearchProps) => {
|
|
23
|
-
const { onChange,
|
|
22
|
+
const { onChange, value, ...rest } = props;
|
|
24
23
|
const filterStyle = useMultiStyleConfig('Filter') as FilterStyle;
|
|
25
24
|
|
|
26
25
|
const [searchValue, setSearchValue] = useState(value);
|
|
@@ -31,7 +30,7 @@ const FilterSearch = (props: FilterSearchProps) => {
|
|
|
31
30
|
};
|
|
32
31
|
|
|
33
32
|
const onClearClick = () => {
|
|
34
|
-
|
|
33
|
+
setSearchValue('');
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
useEffect(() => {
|
|
@@ -55,9 +54,11 @@ const FilterSearch = (props: FilterSearchProps) => {
|
|
|
55
54
|
<Icon color="neutral.60" name="Magnifier" size="16" />
|
|
56
55
|
</InputLeftElement>
|
|
57
56
|
<Input {...inputProps} />
|
|
58
|
-
|
|
59
|
-
<
|
|
60
|
-
|
|
57
|
+
{!!searchValue && (
|
|
58
|
+
<InputRightElement>
|
|
59
|
+
<IconButton aria-label="Clear" iconName="CloseSmall" onClick={onClearClick} size="small" variant="tertiary" />
|
|
60
|
+
</InputRightElement>
|
|
61
|
+
)}
|
|
61
62
|
</InputGroup>
|
|
62
63
|
);
|
|
63
64
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useFilterContext } from '../Filter.context';
|
|
2
|
+
import FilterSwitch from '../FilterSwitch/FilterSwitch';
|
|
3
|
+
import FilterSwitchGroup from '../FilterSwitch/FilterSwitchGroup';
|
|
4
|
+
|
|
5
|
+
type FilterSwitchAdapterProps = {
|
|
6
|
+
category: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const FilterSwitchAdapter = (props: FilterSwitchAdapterProps) => {
|
|
10
|
+
const { category } = props;
|
|
11
|
+
const { data, onFilterChange, state } = useFilterContext();
|
|
12
|
+
const { options } = data[category];
|
|
13
|
+
|
|
14
|
+
if (!options?.length) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const value = state[category]?.[0] || '';
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<FilterSwitchGroup onChange={(newValue) => onFilterChange(category, [newValue])} value={value}>
|
|
22
|
+
{options.map((opt) => (
|
|
23
|
+
<FilterSwitch key={opt} value={opt}>
|
|
24
|
+
{opt}
|
|
25
|
+
</FilterSwitch>
|
|
26
|
+
))}
|
|
27
|
+
</FilterSwitchGroup>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default FilterSwitchAdapter;
|
|
@@ -17,7 +17,16 @@ import Tooltip, { TooltipProps } from '../../Tooltip/Tooltip';
|
|
|
17
17
|
type UsedFormControlProps = Omit<FormControlProps, 'label' | 'onBlur' | 'onChange'>;
|
|
18
18
|
type UsedChakraTextProps = Pick<
|
|
19
19
|
ChakraTextareaProps,
|
|
20
|
-
|
|
20
|
+
| 'onBlur'
|
|
21
|
+
| 'onChange'
|
|
22
|
+
| 'role'
|
|
23
|
+
| 'name'
|
|
24
|
+
| 'value'
|
|
25
|
+
| 'autoComplete'
|
|
26
|
+
| 'autoFocus'
|
|
27
|
+
| 'maxLength'
|
|
28
|
+
| 'minLength'
|
|
29
|
+
| 'placeholder'
|
|
21
30
|
>;
|
|
22
31
|
|
|
23
32
|
export interface TextareaProps extends UsedFormControlProps, UsedChakraTextProps {
|
|
@@ -20,6 +20,7 @@ export interface SelectProps extends Omit<FormControlProps, 'label' | 'onBlur' |
|
|
|
20
20
|
isLoading?: boolean;
|
|
21
21
|
label?: ReactNode;
|
|
22
22
|
name?: string;
|
|
23
|
+
placeholder?: ChakraSelectProps['placeholder'];
|
|
23
24
|
onBlur?: ChakraSelectProps['onBlur'];
|
|
24
25
|
onChange?: ChakraSelectProps['onChange'];
|
|
25
26
|
size?: 'small' | 'medium';
|