@pareto-engineering/design-system 2.0.0-alpha.44 → 2.0.0-alpha.47
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/dist/cjs/f/FormInput/FormInput.js +8 -1
- package/dist/cjs/f/fields/QueryCombobox/QueryCombobox.js +49 -41
- package/dist/cjs/f/fields/QueryCombobox/common/Combobox/Combobox.js +72 -15
- package/dist/cjs/f/fields/QueryCombobox/common/Menu/Menu.js +1 -1
- package/dist/cjs/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +91 -21
- package/dist/cjs/f/fields/QueryCombobox/styles.scss +52 -39
- package/dist/cjs/f/fields/index.js +9 -1
- package/dist/es/f/FormInput/FormInput.js +9 -2
- package/dist/es/f/fields/QueryCombobox/QueryCombobox.js +53 -43
- package/dist/es/f/fields/QueryCombobox/common/Combobox/Combobox.js +73 -17
- package/dist/es/f/fields/QueryCombobox/common/Menu/Menu.js +1 -1
- package/dist/es/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +91 -22
- package/dist/es/f/fields/QueryCombobox/styles.scss +52 -39
- package/dist/es/f/fields/index.js +2 -1
- package/package.json +3 -2
- package/src/__snapshots__/Storyshots.test.js.snap +508 -0
- package/src/local.scss +3 -3
- package/src/stories/f/FormInput.stories.jsx +115 -0
- package/src/stories/f/QueryCombobox.stories.jsx +267 -0
- package/src/stories/f/__generated__/FormInputAllTeamsQuery.graphql.js +139 -0
- package/src/stories/f/__generated__/QueryComboboxAllTeamsQuery.graphql.js +139 -0
- package/src/stories/utils/generateNodeId.js +12 -0
- package/src/stories/utils/testData.js +63 -0
- package/src/ui/f/FormInput/FormInput.jsx +11 -0
- package/src/ui/f/fields/QueryCombobox/QueryCombobox.jsx +223 -0
- package/src/ui/f/fields/QueryCombobox/common/Combobox/Combobox.jsx +222 -0
- package/src/ui/f/fields/QueryCombobox/common/Combobox/index.js +2 -0
- package/src/ui/f/fields/QueryCombobox/common/Menu/Menu.jsx +103 -0
- package/src/ui/f/fields/QueryCombobox/common/Menu/index.js +2 -0
- package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.jsx +317 -0
- package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/index.js +2 -0
- package/src/ui/f/fields/QueryCombobox/common/index.js +3 -0
- package/src/ui/f/fields/QueryCombobox/index.js +2 -0
- package/src/ui/f/fields/QueryCombobox/styles.scss +78 -0
- package/src/ui/f/fields/index.js +1 -0
|
@@ -33,6 +33,12 @@ Object.defineProperty(exports, "RatingsInput", {
|
|
|
33
33
|
return _RatingsInput.RatingsInput;
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
|
+
Object.defineProperty(exports, "QueryCombobox", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function get() {
|
|
39
|
+
return _QueryCombobox.QueryCombobox;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
36
42
|
|
|
37
43
|
var _TextInput = require("./TextInput");
|
|
38
44
|
|
|
@@ -42,4 +48,6 @@ var _ChoicesInput = require("./ChoicesInput");
|
|
|
42
48
|
|
|
43
49
|
var _TextareaInput = require("./TextareaInput");
|
|
44
50
|
|
|
45
|
-
var _RatingsInput = require("./RatingsInput");
|
|
51
|
+
var _RatingsInput = require("./RatingsInput");
|
|
52
|
+
|
|
53
|
+
var _QueryCombobox = require("./QueryCombobox");
|
|
@@ -4,7 +4,7 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { memo, useLayoutEffect } from 'react';
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
|
-
import { TextInput, TextareaInput, ChoicesInput, SelectInput } from "../fields"; // Local Definitions
|
|
7
|
+
import { TextInput, TextareaInput, ChoicesInput, SelectInput, QueryCombobox } from "../fields"; // Local Definitions
|
|
8
8
|
// const baseClassName = styleNames.base
|
|
9
9
|
|
|
10
10
|
const componentClassName = 'form-input';
|
|
@@ -45,6 +45,13 @@ const FormInput = ({
|
|
|
45
45
|
}, otherProps));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
if (type === 'query-combobox') {
|
|
49
|
+
return /*#__PURE__*/React.createElement(QueryCombobox, _extends({
|
|
50
|
+
className: newClassName,
|
|
51
|
+
disabled: disabled
|
|
52
|
+
}, otherProps));
|
|
53
|
+
}
|
|
54
|
+
|
|
48
55
|
if (extraTypes !== null && extraTypes !== void 0 && extraTypes[type]) {
|
|
49
56
|
const Component = extraTypes[type];
|
|
50
57
|
return /*#__PURE__*/React.createElement(Component, _extends({
|
|
@@ -69,7 +76,7 @@ FormInput.propTypes = {
|
|
|
69
76
|
/**
|
|
70
77
|
* The HTML class names for this element
|
|
71
78
|
*/
|
|
72
|
-
type: PropTypes.oneOf(['text', 'email', 'password', 'number', 'date', 'datetime', 'month', 'tel', 'hidden', 'select', 'choices', 'textarea', // to be removed
|
|
79
|
+
type: PropTypes.oneOf(['text', 'email', 'password', 'number', 'date', 'datetime', 'month', 'tel', 'hidden', 'select', 'choices', 'textarea', 'query-combobox', // to be removed
|
|
73
80
|
'extendedTypeInput']),
|
|
74
81
|
|
|
75
82
|
/**
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
/* @pareto-engineering/generator-front 1.0.12 */
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { useState, useLayoutEffect } from 'react';
|
|
4
|
+
import { useField } from 'formik';
|
|
4
5
|
import { useRelayEnvironment, fetchQuery } from 'react-relay';
|
|
5
|
-
import PropTypes from 'prop-types';
|
|
6
|
-
import styleNames from '@pareto-engineering/bem'; // Local Definitions
|
|
6
|
+
import PropTypes from 'prop-types'; // Local Definitions
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
const baseClassName = styleNames.base;
|
|
10
|
-
const componentClassName = 'query-combobox';
|
|
8
|
+
import { Combobox, MultipleCombobox } from "./common";
|
|
11
9
|
/**
|
|
12
10
|
* This is the component description.
|
|
13
11
|
*/
|
|
14
12
|
|
|
15
13
|
const QueryCombobox = ({
|
|
16
14
|
id,
|
|
17
|
-
className: userClassName,
|
|
18
15
|
style,
|
|
16
|
+
className,
|
|
19
17
|
query,
|
|
20
18
|
multiple,
|
|
21
19
|
name,
|
|
@@ -28,34 +26,48 @@ const QueryCombobox = ({
|
|
|
28
26
|
searchVariable,
|
|
29
27
|
extraVariables,
|
|
30
28
|
optionsKeyMap,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
error // ...otherProps
|
|
29
|
+
minLength,
|
|
30
|
+
transformSearch // ...otherProps
|
|
34
31
|
|
|
35
32
|
}) => {
|
|
36
33
|
useLayoutEffect(() => {
|
|
37
34
|
import("./styles.scss");
|
|
38
35
|
}, []);
|
|
36
|
+
const [, meta, helpers] = useField(name);
|
|
37
|
+
const {
|
|
38
|
+
setValue,
|
|
39
|
+
setError
|
|
40
|
+
} = helpers;
|
|
41
|
+
const {
|
|
42
|
+
error,
|
|
43
|
+
value
|
|
44
|
+
} = meta;
|
|
39
45
|
const environment = useRelayEnvironment();
|
|
40
46
|
const [isFetching, setIsFetching] = useState(false);
|
|
41
47
|
const [options, setOptions] = useState([]);
|
|
42
48
|
|
|
43
|
-
const
|
|
49
|
+
const getOptions = inputValue => {
|
|
44
50
|
if (isFetching) return;
|
|
45
|
-
|
|
46
|
-
[searchVariable]: inputValue
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
let variables = {
|
|
52
|
+
[searchVariable]: inputValue
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (extraVariables) {
|
|
56
|
+
variables = { ...variables,
|
|
57
|
+
...extraVariables
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fetchQuery(environment, query, variables).subscribe({
|
|
49
62
|
start: () => {
|
|
50
63
|
setIsFetching(true);
|
|
51
64
|
},
|
|
52
65
|
complete: () => {
|
|
53
66
|
setIsFetching(false);
|
|
54
67
|
},
|
|
55
|
-
error:
|
|
56
|
-
console.log(theError);
|
|
68
|
+
error: fetchError => {
|
|
57
69
|
setIsFetching(false);
|
|
58
|
-
if (setError) setError(
|
|
70
|
+
if (setError) setError(fetchError.message);
|
|
59
71
|
},
|
|
60
72
|
next: data => {
|
|
61
73
|
setOptions(data[graphQlNode].edges.map(({
|
|
@@ -69,23 +81,26 @@ const QueryCombobox = ({
|
|
|
69
81
|
};
|
|
70
82
|
|
|
71
83
|
const comboboxProps = {
|
|
84
|
+
id,
|
|
85
|
+
style,
|
|
72
86
|
options,
|
|
73
|
-
|
|
87
|
+
getOptions,
|
|
74
88
|
debounceMs,
|
|
75
89
|
disabled,
|
|
76
90
|
name,
|
|
77
91
|
label,
|
|
78
92
|
description,
|
|
79
93
|
setValue,
|
|
80
|
-
error
|
|
94
|
+
error,
|
|
95
|
+
value,
|
|
96
|
+
color,
|
|
97
|
+
isFetching,
|
|
98
|
+
className,
|
|
99
|
+
minLength,
|
|
100
|
+
transformSearch
|
|
81
101
|
};
|
|
82
|
-
const
|
|
83
|
-
return /*#__PURE__*/React.createElement(
|
|
84
|
-
id: id,
|
|
85
|
-
className: [baseClassName, componentClassName, userClassName, `y-${color}`].filter(e => e).join(' '),
|
|
86
|
-
style: style // {...otherProps}
|
|
87
|
-
|
|
88
|
-
}, /*#__PURE__*/React.createElement(Component, comboboxProps));
|
|
102
|
+
const Input = multiple ? MultipleCombobox : Combobox;
|
|
103
|
+
return /*#__PURE__*/React.createElement(Input, comboboxProps);
|
|
89
104
|
};
|
|
90
105
|
|
|
91
106
|
QueryCombobox.propTypes = {
|
|
@@ -114,11 +129,6 @@ QueryCombobox.propTypes = {
|
|
|
114
129
|
*/
|
|
115
130
|
label: PropTypes.string,
|
|
116
131
|
|
|
117
|
-
/**
|
|
118
|
-
* The input field validator function
|
|
119
|
-
*/
|
|
120
|
-
validate: PropTypes.func,
|
|
121
|
-
|
|
122
132
|
/**
|
|
123
133
|
* The custom select input description
|
|
124
134
|
*/
|
|
@@ -156,7 +166,7 @@ QueryCombobox.propTypes = {
|
|
|
156
166
|
optionsKeyMap: PropTypes.shape({
|
|
157
167
|
value: PropTypes.string.isRequired,
|
|
158
168
|
label: PropTypes.string.isRequired
|
|
159
|
-
})
|
|
169
|
+
}),
|
|
160
170
|
|
|
161
171
|
/**
|
|
162
172
|
* Whether to allow multiple items selection
|
|
@@ -174,24 +184,24 @@ QueryCombobox.propTypes = {
|
|
|
174
184
|
searchVariable: PropTypes.string,
|
|
175
185
|
|
|
176
186
|
/**
|
|
177
|
-
* The
|
|
178
|
-
*/
|
|
179
|
-
setValue: PropTypes.func.isRequired,
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* The function to be called with an error when the it occurs
|
|
187
|
+
* The minimum length of the search input to start fetching the options
|
|
183
188
|
*/
|
|
184
|
-
|
|
189
|
+
minLength: PropTypes.number,
|
|
185
190
|
|
|
186
191
|
/**
|
|
187
|
-
* The
|
|
192
|
+
* The function to transform the search input
|
|
188
193
|
*/
|
|
189
|
-
|
|
194
|
+
transformSearch: PropTypes.func
|
|
190
195
|
};
|
|
191
196
|
QueryCombobox.defaultProps = {
|
|
192
|
-
|
|
197
|
+
optionsKeyMap: {
|
|
198
|
+
value: 'id',
|
|
199
|
+
label: 'name'
|
|
200
|
+
},
|
|
193
201
|
multiple: false,
|
|
194
202
|
color: 'background2',
|
|
195
|
-
searchVariable: 'search'
|
|
203
|
+
searchVariable: 'search',
|
|
204
|
+
transformSearch: search => search,
|
|
205
|
+
minLength: 2
|
|
196
206
|
};
|
|
197
207
|
export default QueryCombobox;
|
|
@@ -2,11 +2,12 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
|
|
2
2
|
|
|
3
3
|
/* @pareto-engineering/generator-front 1.0.12 */
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import { useEffect } from 'react';
|
|
5
|
+
import { useEffect, useRef } from 'react';
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
7
|
import { useCombobox } from 'downshift';
|
|
8
8
|
import styleNames from '@pareto-engineering/bem';
|
|
9
|
-
import { FormLabel, FormDescription } from "../../../..";
|
|
9
|
+
import { FormLabel, FormDescription } from "../../../..";
|
|
10
|
+
import { Popover, LoadingCircle } from "../../../../../a"; // Local Definitions
|
|
10
11
|
|
|
11
12
|
import { Menu } from "../Menu";
|
|
12
13
|
const baseClassName = styleNames.base;
|
|
@@ -22,14 +23,20 @@ const Combobox = ({
|
|
|
22
23
|
label,
|
|
23
24
|
name,
|
|
24
25
|
options: items,
|
|
25
|
-
|
|
26
|
+
getOptions,
|
|
26
27
|
setValue,
|
|
27
28
|
error,
|
|
28
|
-
description
|
|
29
|
+
description,
|
|
30
|
+
value,
|
|
31
|
+
color,
|
|
32
|
+
minLength,
|
|
33
|
+
isFetching,
|
|
34
|
+
transformSearch // ...otherProps
|
|
29
35
|
|
|
30
36
|
}) => {
|
|
31
37
|
const {
|
|
32
38
|
isOpen,
|
|
39
|
+
selectItem,
|
|
33
40
|
selectedItem,
|
|
34
41
|
getLabelProps,
|
|
35
42
|
getMenuProps,
|
|
@@ -39,33 +46,54 @@ const Combobox = ({
|
|
|
39
46
|
getItemProps
|
|
40
47
|
} = useCombobox({
|
|
41
48
|
items,
|
|
49
|
+
initialSelectedItem: value,
|
|
42
50
|
itemToString: item => item ? item.label : '',
|
|
43
51
|
onInputValueChange: ({
|
|
44
52
|
inputValue
|
|
45
53
|
}) => {
|
|
46
|
-
|
|
54
|
+
const transformedInput = transformSearch(inputValue);
|
|
55
|
+
|
|
56
|
+
if (transformedInput.length > minLength) {
|
|
57
|
+
getOptions(transformedInput);
|
|
58
|
+
}
|
|
47
59
|
}
|
|
48
|
-
});
|
|
60
|
+
}); // If the user has selected an item, we'll set the value of the field
|
|
61
|
+
// or if the combobox state has a selected item, we'll set the value to the formik state
|
|
62
|
+
|
|
49
63
|
useEffect(() => {
|
|
50
64
|
if (selectedItem) {
|
|
51
|
-
setValue(selectedItem
|
|
65
|
+
setValue(selectedItem);
|
|
66
|
+
}
|
|
67
|
+
}, [selectedItem]); // If the formik state has a value, we'll set the selected item to the combobox state
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if ((value === null || value === void 0 ? void 0 : value.value) !== (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.value)) {
|
|
71
|
+
selectItem(value);
|
|
52
72
|
}
|
|
53
|
-
}, [
|
|
73
|
+
}, [value]);
|
|
74
|
+
const parentRef = useRef(null);
|
|
54
75
|
return /*#__PURE__*/React.createElement("div", {
|
|
55
76
|
id: id,
|
|
56
|
-
className: [baseClassName, componentClassName, userClassName].filter(e => e).join(' '),
|
|
57
|
-
style: style
|
|
77
|
+
className: [baseClassName, componentClassName, userClassName, `y-${color}`].filter(e => e).join(' '),
|
|
78
|
+
style: style,
|
|
79
|
+
ref: parentRef
|
|
58
80
|
}, /*#__PURE__*/React.createElement(FormLabel, _extends({}, getLabelProps(), {
|
|
59
|
-
className: "input-label",
|
|
60
81
|
name: name
|
|
61
|
-
}), label), /*#__PURE__*/React.createElement("div",
|
|
82
|
+
}), label), /*#__PURE__*/React.createElement("div", _extends({}, getComboboxProps(), {
|
|
83
|
+
className: "input-wrapper"
|
|
84
|
+
}), /*#__PURE__*/React.createElement("input", _extends({}, getInputProps(), {
|
|
62
85
|
className: "input"
|
|
63
|
-
}))
|
|
86
|
+
})), isFetching && /*#__PURE__*/React.createElement(LoadingCircle, {
|
|
87
|
+
className: "x-main2"
|
|
88
|
+
})), /*#__PURE__*/React.createElement(Popover, {
|
|
89
|
+
isOpen: isOpen,
|
|
90
|
+
parentRef: parentRef
|
|
91
|
+
}, /*#__PURE__*/React.createElement(Menu, _extends({
|
|
64
92
|
isOpen: isOpen,
|
|
65
93
|
getItemProps: getItemProps,
|
|
66
94
|
highlightedIndex: highlightedIndex,
|
|
67
95
|
items: items
|
|
68
|
-
}, getMenuProps())), (description || error) && /*#__PURE__*/React.createElement(FormDescription, {
|
|
96
|
+
}, getMenuProps()))), (description || error) && /*#__PURE__*/React.createElement(FormDescription, {
|
|
69
97
|
isError: !!error
|
|
70
98
|
}, error || description));
|
|
71
99
|
};
|
|
@@ -107,7 +135,7 @@ Combobox.propTypes = {
|
|
|
107
135
|
/**
|
|
108
136
|
* The function to fetch the options from the backend
|
|
109
137
|
*/
|
|
110
|
-
|
|
138
|
+
getOptions: PropTypes.func,
|
|
111
139
|
|
|
112
140
|
/**
|
|
113
141
|
* The function to set the value of the custom select input
|
|
@@ -122,8 +150,36 @@ Combobox.propTypes = {
|
|
|
122
150
|
/**
|
|
123
151
|
* The error object
|
|
124
152
|
*/
|
|
125
|
-
error: PropTypes.objectOf(PropTypes.string)
|
|
153
|
+
error: PropTypes.objectOf(PropTypes.string),
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The value of the custom select input
|
|
157
|
+
*/
|
|
158
|
+
value: PropTypes.shape({
|
|
159
|
+
value: PropTypes.string,
|
|
160
|
+
label: PropTypes.string
|
|
161
|
+
}),
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The base color of the combobox custom select input
|
|
165
|
+
*/
|
|
166
|
+
color: PropTypes.string,
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Whether the query getting the combobox options is inFlight
|
|
170
|
+
*/
|
|
171
|
+
isFetching: PropTypes.bool.isRequired,
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* The minimum length of the search input to start fetching the options
|
|
175
|
+
*/
|
|
176
|
+
minLength: PropTypes.number,
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The function to transform the search input
|
|
180
|
+
*/
|
|
181
|
+
transformSearch: PropTypes.func
|
|
126
182
|
};
|
|
127
|
-
Combobox.defaultProps = {// someProp:false
|
|
183
|
+
Combobox.defaultProps = {// someProp: false
|
|
128
184
|
};
|
|
129
185
|
export default Combobox;
|
|
@@ -31,7 +31,7 @@ const Menu = /*#__PURE__*/React.forwardRef(({
|
|
|
31
31
|
item,
|
|
32
32
|
index
|
|
33
33
|
}), {
|
|
34
|
-
className:
|
|
34
|
+
className: ['item', highlightedIndex === index && styleNames.modifierActive].filter(Boolean).join(' ')
|
|
35
35
|
}), /*#__PURE__*/React.createElement("p", null, item.label)))));
|
|
36
36
|
Menu.propTypes = {
|
|
37
37
|
/**
|
|
@@ -2,20 +2,30 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
|
|
2
2
|
|
|
3
3
|
/* @pareto-engineering/generator-front 1.0.12 */
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import { useState, useEffect } from 'react';
|
|
5
|
+
import { useState, useEffect, useRef } from 'react';
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
7
|
import styleNames from '@pareto-engineering/bem';
|
|
8
8
|
import { useCombobox, useMultipleSelection } from 'downshift';
|
|
9
9
|
import { Button } from "../../../../../b";
|
|
10
|
+
import { Popover, LoadingCircle } from "../../../../../a";
|
|
10
11
|
import { FormDescription, FormLabel } from "../../../.."; // Local Definitions
|
|
11
12
|
|
|
12
13
|
import { Menu } from "../Menu";
|
|
13
14
|
const baseClassName = styleNames.base;
|
|
14
15
|
const componentClassName = 'multiple-combobox';
|
|
16
|
+
/**
|
|
17
|
+
* @param {Array[Object]} first - first array to check if it has an item not in the second array.
|
|
18
|
+
* @param {Array[Object]} second - second array to check against the first array.
|
|
19
|
+
*
|
|
20
|
+
* @returns {Boolean} - true if the first array has an item not in the second array.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const testIfArraysAreUnique = (first, second) => first.filter(objInFirstArray => !second.some(objInSecondArray => objInFirstArray.value === objInSecondArray.value)).length > 0;
|
|
15
24
|
/**
|
|
16
25
|
* This is the component description.
|
|
17
26
|
*/
|
|
18
27
|
|
|
28
|
+
|
|
19
29
|
const MultipleCombobox = ({
|
|
20
30
|
id,
|
|
21
31
|
className: userClassName,
|
|
@@ -23,22 +33,34 @@ const MultipleCombobox = ({
|
|
|
23
33
|
label,
|
|
24
34
|
name,
|
|
25
35
|
options: items,
|
|
26
|
-
|
|
36
|
+
getOptions,
|
|
27
37
|
setValue,
|
|
28
38
|
error,
|
|
29
|
-
description
|
|
39
|
+
description,
|
|
40
|
+
value,
|
|
41
|
+
color,
|
|
42
|
+
isFetching,
|
|
43
|
+
minLength,
|
|
44
|
+
transformSearch // ...otherProps
|
|
30
45
|
|
|
31
46
|
}) => {
|
|
32
|
-
const [
|
|
47
|
+
const [searchInputValue, setSearchInputValue] = useState('');
|
|
33
48
|
const {
|
|
34
49
|
getSelectedItemProps,
|
|
35
50
|
getDropdownProps,
|
|
36
51
|
addSelectedItem,
|
|
37
52
|
removeSelectedItem,
|
|
53
|
+
setSelectedItems,
|
|
38
54
|
selectedItems
|
|
39
|
-
} = useMultipleSelection(
|
|
55
|
+
} = useMultipleSelection({
|
|
56
|
+
initialSelectedItems: value || []
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* @returns {Boolean} - Unique items from the options array so that the combobox
|
|
60
|
+
* shows only the options that are not yet selected.
|
|
61
|
+
*/
|
|
40
62
|
|
|
41
|
-
const getFilteredItems = () => items.filter(item => selectedItems.findIndex(e => e.label === item.label) < 0
|
|
63
|
+
const getFilteredItems = () => items.filter(item => selectedItems.findIndex(e => e.label === item.label) < 0);
|
|
42
64
|
|
|
43
65
|
const {
|
|
44
66
|
isOpen,
|
|
@@ -49,7 +71,7 @@ const MultipleCombobox = ({
|
|
|
49
71
|
highlightedIndex,
|
|
50
72
|
getItemProps
|
|
51
73
|
} = useCombobox({
|
|
52
|
-
|
|
74
|
+
searchInputValue,
|
|
53
75
|
defaultHighlightedIndex: 0,
|
|
54
76
|
// after selection, highlight the first item.
|
|
55
77
|
selectedItem: null,
|
|
@@ -76,21 +98,28 @@ const MultipleCombobox = ({
|
|
|
76
98
|
return changes;
|
|
77
99
|
},
|
|
78
100
|
onStateChange: ({
|
|
79
|
-
inputValue:
|
|
101
|
+
inputValue: newSearchInputValue,
|
|
80
102
|
type,
|
|
81
103
|
selectedItem
|
|
82
104
|
}) => {
|
|
83
105
|
switch (type) {
|
|
84
106
|
case useCombobox.stateChangeTypes.InputChange:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
107
|
+
{
|
|
108
|
+
const transformedInput = transformSearch(newSearchInputValue);
|
|
109
|
+
|
|
110
|
+
if (transformedInput.length > minLength) {
|
|
111
|
+
getOptions(transformedInput);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
setSearchInputValue(newSearchInputValue);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
88
117
|
|
|
89
118
|
case useCombobox.stateChangeTypes.InputKeyDownEnter:
|
|
90
119
|
case useCombobox.stateChangeTypes.ItemClick:
|
|
91
120
|
case useCombobox.stateChangeTypes.InputBlur:
|
|
92
121
|
if (selectedItem) {
|
|
93
|
-
|
|
122
|
+
setSearchInputValue('');
|
|
94
123
|
addSelectedItem(selectedItem);
|
|
95
124
|
}
|
|
96
125
|
|
|
@@ -102,16 +131,21 @@ const MultipleCombobox = ({
|
|
|
102
131
|
}
|
|
103
132
|
});
|
|
104
133
|
useEffect(() => {
|
|
105
|
-
if (selectedItems.length > 0) {
|
|
106
|
-
setValue(selectedItems
|
|
134
|
+
if ((selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) > 0) {
|
|
135
|
+
setValue(selectedItems);
|
|
107
136
|
}
|
|
108
137
|
}, [selectedItems]);
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if ((value === null || value === void 0 ? void 0 : value.length) > 0 && (testIfArraysAreUnique(value, selectedItems) || testIfArraysAreUnique(selectedItems, value))) {
|
|
140
|
+
setSelectedItems(value);
|
|
141
|
+
}
|
|
142
|
+
}, [value]);
|
|
143
|
+
const parentRef = useRef(null);
|
|
109
144
|
return /*#__PURE__*/React.createElement("div", {
|
|
110
145
|
id: id,
|
|
111
|
-
className: [baseClassName, componentClassName, userClassName].filter(e => e).join(' '),
|
|
146
|
+
className: [baseClassName, componentClassName, userClassName, `y-${color}`].filter(e => e).join(' '),
|
|
112
147
|
style: style
|
|
113
148
|
}, /*#__PURE__*/React.createElement(FormLabel, _extends({}, getLabelProps(), {
|
|
114
|
-
className: "input-label",
|
|
115
149
|
name: name
|
|
116
150
|
}), label), /*#__PURE__*/React.createElement("div", {
|
|
117
151
|
className: "selected-items"
|
|
@@ -129,16 +163,23 @@ const MultipleCombobox = ({
|
|
|
129
163
|
isCompact: true,
|
|
130
164
|
isSimple: true,
|
|
131
165
|
color: "main2"
|
|
132
|
-
}, "X")))), /*#__PURE__*/React.createElement("div",
|
|
166
|
+
}, "X")))), /*#__PURE__*/React.createElement("div", _extends({}, getComboboxProps(), {
|
|
167
|
+
className: "input-wrapper"
|
|
168
|
+
}), /*#__PURE__*/React.createElement("input", _extends({}, getInputProps(getDropdownProps({
|
|
133
169
|
preventKeyAction: isOpen
|
|
134
170
|
})), {
|
|
135
171
|
className: "input"
|
|
136
|
-
}))
|
|
172
|
+
})), isFetching && /*#__PURE__*/React.createElement(LoadingCircle, {
|
|
173
|
+
className: "x-main2"
|
|
174
|
+
})), /*#__PURE__*/React.createElement(Popover, {
|
|
175
|
+
isOpen: isOpen,
|
|
176
|
+
parentRef: parentRef
|
|
177
|
+
}, /*#__PURE__*/React.createElement(Menu, _extends({
|
|
137
178
|
isOpen: isOpen,
|
|
138
179
|
getItemProps: getItemProps,
|
|
139
180
|
highlightedIndex: highlightedIndex,
|
|
140
181
|
items: getFilteredItems()
|
|
141
|
-
}, getMenuProps())), (description || error) && /*#__PURE__*/React.createElement(FormDescription, {
|
|
182
|
+
}, getMenuProps()))), (description || error) && /*#__PURE__*/React.createElement(FormDescription, {
|
|
142
183
|
isError: !!error
|
|
143
184
|
}, error || description));
|
|
144
185
|
};
|
|
@@ -180,7 +221,7 @@ MultipleCombobox.propTypes = {
|
|
|
180
221
|
/**
|
|
181
222
|
* The function to fetch the options from the backend
|
|
182
223
|
*/
|
|
183
|
-
|
|
224
|
+
getOptions: PropTypes.func,
|
|
184
225
|
|
|
185
226
|
/**
|
|
186
227
|
* The function to set the value of the custom select input
|
|
@@ -195,8 +236,36 @@ MultipleCombobox.propTypes = {
|
|
|
195
236
|
/**
|
|
196
237
|
* The error object
|
|
197
238
|
*/
|
|
198
|
-
error: PropTypes.objectOf(PropTypes.string)
|
|
239
|
+
error: PropTypes.objectOf(PropTypes.string),
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* The value of the custom select input
|
|
243
|
+
*/
|
|
244
|
+
value: PropTypes.arrayOf(PropTypes.shape({
|
|
245
|
+
value: PropTypes.string,
|
|
246
|
+
label: PropTypes.string
|
|
247
|
+
})),
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* The base color of the custom select input
|
|
251
|
+
*/
|
|
252
|
+
color: PropTypes.string,
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Whether the query getting the combobox options is inFlight
|
|
256
|
+
*/
|
|
257
|
+
isFetching: PropTypes.bool.isRequired,
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The minimum length of the search input to start fetching the options
|
|
261
|
+
*/
|
|
262
|
+
minLength: PropTypes.number,
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* The function to transform the search input
|
|
266
|
+
*/
|
|
267
|
+
transformSearch: PropTypes.func
|
|
199
268
|
};
|
|
200
|
-
MultipleCombobox.defaultProps = {// someProp:false
|
|
269
|
+
MultipleCombobox.defaultProps = {// someProp: false
|
|
201
270
|
};
|
|
202
271
|
export default MultipleCombobox;
|