@pareto-engineering/design-system 2.0.0-alpha.46 → 2.0.0-alpha.49
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 +7 -0
- package/dist/cjs/f/fields/QueryCombobox/QueryCombobox.js +33 -11
- package/dist/cjs/f/fields/QueryCombobox/common/Combobox/Combobox.js +20 -9
- package/dist/cjs/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +40 -17
- package/dist/cjs/f/fields/QueryCombobox/common/index.js +9 -1
- package/dist/cjs/f/fields/QueryCombobox/styles.scss +11 -5
- package/dist/cjs/f/fields/QuerySelect/QuerySelect.js +201 -0
- package/dist/cjs/f/fields/QuerySelect/index.js +15 -0
- package/dist/cjs/f/fields/QuerySelect/styles.scss +21 -0
- package/dist/cjs/f/fields/SelectInput/SelectInput.js +15 -3
- package/dist/cjs/f/fields/SelectInput/styles.scss +27 -14
- package/dist/cjs/f/fields/index.js +9 -1
- package/dist/es/f/FormInput/FormInput.js +8 -1
- package/dist/es/f/fields/QueryCombobox/QueryCombobox.js +34 -12
- package/dist/es/f/fields/QueryCombobox/common/Combobox/Combobox.js +20 -9
- package/dist/es/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +40 -17
- package/dist/es/f/fields/QueryCombobox/common/index.js +2 -1
- package/dist/es/f/fields/QueryCombobox/styles.scss +11 -5
- package/dist/es/f/fields/QuerySelect/QuerySelect.js +179 -0
- package/dist/es/f/fields/QuerySelect/index.js +2 -0
- package/dist/es/f/fields/QuerySelect/styles.scss +21 -0
- package/dist/es/f/fields/SelectInput/SelectInput.js +14 -3
- package/dist/es/f/fields/SelectInput/styles.scss +27 -14
- package/dist/es/f/fields/index.js +2 -1
- package/package.json +2 -2
- package/src/__snapshots__/Storyshots.test.js.snap +783 -237
- package/src/local.scss +3 -3
- package/src/stories/f/FormInput.stories.jsx +122 -4
- package/src/stories/f/QueryCombobox.stories.jsx +59 -10
- package/src/stories/f/QuerySelect.stories.jsx +134 -0
- package/src/stories/f/__generated__/FormInputAllTaskStatusesQuery.graphql.js +122 -0
- package/src/stories/f/__generated__/QuerySelectAllTaskStatusesQuery.graphql.js +122 -0
- package/src/ui/f/FormInput/FormInput.jsx +10 -0
- package/src/ui/f/fields/QueryCombobox/QueryCombobox.jsx +34 -14
- package/src/ui/f/fields/QueryCombobox/common/Combobox/Combobox.jsx +15 -7
- package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.jsx +318 -0
- package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/index.js +2 -0
- package/src/ui/f/fields/QueryCombobox/common/index.js +1 -0
- package/src/ui/f/fields/QueryCombobox/styles.scss +11 -5
- package/src/ui/f/fields/QuerySelect/QuerySelect.jsx +200 -0
- package/src/ui/f/fields/QuerySelect/index.js +2 -0
- package/src/ui/f/fields/SelectInput/SelectInput.jsx +16 -3
- package/src/ui/f/fields/SelectInput/styles.scss +27 -14
- package/src/ui/f/fields/index.js +1 -0
|
@@ -39,6 +39,12 @@ Object.defineProperty(exports, "QueryCombobox", {
|
|
|
39
39
|
return _QueryCombobox.QueryCombobox;
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
|
+
Object.defineProperty(exports, "QuerySelect", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function get() {
|
|
45
|
+
return _QuerySelect.QuerySelect;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
42
48
|
|
|
43
49
|
var _TextInput = require("./TextInput");
|
|
44
50
|
|
|
@@ -50,4 +56,6 @@ var _TextareaInput = require("./TextareaInput");
|
|
|
50
56
|
|
|
51
57
|
var _RatingsInput = require("./RatingsInput");
|
|
52
58
|
|
|
53
|
-
var _QueryCombobox = require("./QueryCombobox");
|
|
59
|
+
var _QueryCombobox = require("./QueryCombobox");
|
|
60
|
+
|
|
61
|
+
var _QuerySelect = require("./QuerySelect");
|
|
@@ -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, QueryCombobox } from "../fields"; // Local Definitions
|
|
7
|
+
import { TextInput, TextareaInput, ChoicesInput, SelectInput, QueryCombobox, QuerySelect } from "../fields"; // Local Definitions
|
|
8
8
|
// const baseClassName = styleNames.base
|
|
9
9
|
|
|
10
10
|
const componentClassName = 'form-input';
|
|
@@ -52,6 +52,13 @@ const FormInput = ({
|
|
|
52
52
|
}, otherProps));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
if (type === 'query-select') {
|
|
56
|
+
return /*#__PURE__*/React.createElement(QuerySelect, _extends({
|
|
57
|
+
className: newClassName,
|
|
58
|
+
disabled: disabled
|
|
59
|
+
}, otherProps));
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
if (extraTypes !== null && extraTypes !== void 0 && extraTypes[type]) {
|
|
56
63
|
const Component = extraTypes[type];
|
|
57
64
|
return /*#__PURE__*/React.createElement(Component, _extends({
|
|
@@ -5,7 +5,7 @@ import { useField } from 'formik';
|
|
|
5
5
|
import { useRelayEnvironment, fetchQuery } from 'react-relay';
|
|
6
6
|
import PropTypes from 'prop-types'; // Local Definitions
|
|
7
7
|
|
|
8
|
-
import { Combobox } from "./common";
|
|
8
|
+
import { Combobox, MultipleCombobox } from "./common";
|
|
9
9
|
/**
|
|
10
10
|
* This is the component description.
|
|
11
11
|
*/
|
|
@@ -15,17 +15,18 @@ const QueryCombobox = ({
|
|
|
15
15
|
style,
|
|
16
16
|
className,
|
|
17
17
|
query,
|
|
18
|
-
|
|
18
|
+
multiple,
|
|
19
19
|
name,
|
|
20
20
|
label,
|
|
21
21
|
color,
|
|
22
22
|
description,
|
|
23
23
|
disabled,
|
|
24
24
|
debounceMs,
|
|
25
|
-
graphQlNode,
|
|
26
25
|
searchVariable,
|
|
27
26
|
extraVariables,
|
|
28
|
-
optionsKeyMap
|
|
27
|
+
optionsKeyMap,
|
|
28
|
+
minLength,
|
|
29
|
+
transformSearch // ...otherProps
|
|
29
30
|
|
|
30
31
|
}) => {
|
|
31
32
|
useLayoutEffect(() => {
|
|
@@ -43,6 +44,10 @@ const QueryCombobox = ({
|
|
|
43
44
|
const environment = useRelayEnvironment();
|
|
44
45
|
const [isFetching, setIsFetching] = useState(false);
|
|
45
46
|
const [options, setOptions] = useState([]);
|
|
47
|
+
const {
|
|
48
|
+
graphql,
|
|
49
|
+
accessor
|
|
50
|
+
} = query;
|
|
46
51
|
|
|
47
52
|
const getOptions = inputValue => {
|
|
48
53
|
if (isFetching) return;
|
|
@@ -56,7 +61,7 @@ const QueryCombobox = ({
|
|
|
56
61
|
};
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
fetchQuery(environment,
|
|
64
|
+
fetchQuery(environment, graphql, variables).subscribe({
|
|
60
65
|
start: () => {
|
|
61
66
|
setIsFetching(true);
|
|
62
67
|
},
|
|
@@ -68,7 +73,7 @@ const QueryCombobox = ({
|
|
|
68
73
|
if (setError) setError(fetchError.message);
|
|
69
74
|
},
|
|
70
75
|
next: data => {
|
|
71
|
-
setOptions(data[
|
|
76
|
+
setOptions(data[accessor].edges.map(({
|
|
72
77
|
node
|
|
73
78
|
}) => ({
|
|
74
79
|
value: node[optionsKeyMap.value],
|
|
@@ -93,9 +98,11 @@ const QueryCombobox = ({
|
|
|
93
98
|
value,
|
|
94
99
|
color,
|
|
95
100
|
isFetching,
|
|
96
|
-
className
|
|
101
|
+
className,
|
|
102
|
+
minLength,
|
|
103
|
+
transformSearch
|
|
97
104
|
};
|
|
98
|
-
const Input = Combobox;
|
|
105
|
+
const Input = multiple ? MultipleCombobox : Combobox;
|
|
99
106
|
return /*#__PURE__*/React.createElement(Input, comboboxProps);
|
|
100
107
|
};
|
|
101
108
|
|
|
@@ -146,9 +153,12 @@ QueryCombobox.propTypes = {
|
|
|
146
153
|
debounceMs: PropTypes.number,
|
|
147
154
|
|
|
148
155
|
/**
|
|
149
|
-
* The query to fetch the options
|
|
156
|
+
* The graphql query to fetch the options and the accessor to destructure the results from
|
|
150
157
|
*/
|
|
151
|
-
query: PropTypes.
|
|
158
|
+
query: PropTypes.shape({
|
|
159
|
+
accessor: PropTypes.string,
|
|
160
|
+
graphql: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired
|
|
161
|
+
}),
|
|
152
162
|
|
|
153
163
|
/**
|
|
154
164
|
* The extra variables required to be used in the query.
|
|
@@ -177,7 +187,17 @@ QueryCombobox.propTypes = {
|
|
|
177
187
|
/**
|
|
178
188
|
* The variable to be used to search the data
|
|
179
189
|
*/
|
|
180
|
-
searchVariable: PropTypes.string
|
|
190
|
+
searchVariable: PropTypes.string,
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The minimum length of the search input to start fetching the options
|
|
194
|
+
*/
|
|
195
|
+
minLength: PropTypes.number,
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The function to transform the search input
|
|
199
|
+
*/
|
|
200
|
+
transformSearch: PropTypes.func
|
|
181
201
|
};
|
|
182
202
|
QueryCombobox.defaultProps = {
|
|
183
203
|
optionsKeyMap: {
|
|
@@ -186,6 +206,8 @@ QueryCombobox.defaultProps = {
|
|
|
186
206
|
},
|
|
187
207
|
multiple: false,
|
|
188
208
|
color: 'background2',
|
|
189
|
-
searchVariable: 'search'
|
|
209
|
+
searchVariable: 'search',
|
|
210
|
+
transformSearch: search => search,
|
|
211
|
+
minLength: 2
|
|
190
212
|
};
|
|
191
213
|
export default QueryCombobox;
|
|
@@ -29,8 +29,9 @@ const Combobox = ({
|
|
|
29
29
|
description,
|
|
30
30
|
value,
|
|
31
31
|
color,
|
|
32
|
-
|
|
33
|
-
isFetching
|
|
32
|
+
minLength,
|
|
33
|
+
isFetching,
|
|
34
|
+
transformSearch // ...otherProps
|
|
34
35
|
|
|
35
36
|
}) => {
|
|
36
37
|
const {
|
|
@@ -50,7 +51,11 @@ const Combobox = ({
|
|
|
50
51
|
onInputValueChange: ({
|
|
51
52
|
inputValue
|
|
52
53
|
}) => {
|
|
53
|
-
|
|
54
|
+
const transformedInput = transformSearch(inputValue);
|
|
55
|
+
|
|
56
|
+
if (transformedInput.length > minLength) {
|
|
57
|
+
getOptions(transformedInput);
|
|
58
|
+
}
|
|
54
59
|
}
|
|
55
60
|
}); // If the user has selected an item, we'll set the value of the field
|
|
56
61
|
// or if the combobox state has a selected item, we'll set the value to the formik state
|
|
@@ -69,7 +74,7 @@ const Combobox = ({
|
|
|
69
74
|
const parentRef = useRef(null);
|
|
70
75
|
return /*#__PURE__*/React.createElement("div", {
|
|
71
76
|
id: id,
|
|
72
|
-
className: [baseClassName, componentClassName, userClassName, `y-${color}
|
|
77
|
+
className: [baseClassName, componentClassName, userClassName, `y-${color}`].filter(e => e).join(' '),
|
|
73
78
|
style: style,
|
|
74
79
|
ref: parentRef
|
|
75
80
|
}, /*#__PURE__*/React.createElement(FormLabel, _extends({}, getLabelProps(), {
|
|
@@ -78,7 +83,9 @@ const Combobox = ({
|
|
|
78
83
|
className: "input-wrapper"
|
|
79
84
|
}), /*#__PURE__*/React.createElement("input", _extends({}, getInputProps(), {
|
|
80
85
|
className: "input"
|
|
81
|
-
})), isFetching && /*#__PURE__*/React.createElement(LoadingCircle,
|
|
86
|
+
})), isFetching && /*#__PURE__*/React.createElement(LoadingCircle, {
|
|
87
|
+
className: "x-main2"
|
|
88
|
+
})), /*#__PURE__*/React.createElement(Popover, {
|
|
82
89
|
isOpen: isOpen,
|
|
83
90
|
parentRef: parentRef
|
|
84
91
|
}, /*#__PURE__*/React.createElement(Menu, _extends({
|
|
@@ -164,11 +171,15 @@ Combobox.propTypes = {
|
|
|
164
171
|
isFetching: PropTypes.bool.isRequired,
|
|
165
172
|
|
|
166
173
|
/**
|
|
167
|
-
* The
|
|
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
|
|
168
180
|
*/
|
|
169
|
-
|
|
181
|
+
transformSearch: PropTypes.func
|
|
170
182
|
};
|
|
171
|
-
Combobox.defaultProps = {
|
|
172
|
-
loadingCircleColor: 'main2'
|
|
183
|
+
Combobox.defaultProps = {// someProp: false
|
|
173
184
|
};
|
|
174
185
|
export default Combobox;
|
|
@@ -40,7 +40,8 @@ const MultipleCombobox = ({
|
|
|
40
40
|
value,
|
|
41
41
|
color,
|
|
42
42
|
isFetching,
|
|
43
|
-
|
|
43
|
+
minLength,
|
|
44
|
+
transformSearch // ...otherProps
|
|
44
45
|
|
|
45
46
|
}) => {
|
|
46
47
|
const [searchInputValue, setSearchInputValue] = useState('');
|
|
@@ -54,8 +55,12 @@ const MultipleCombobox = ({
|
|
|
54
55
|
} = useMultipleSelection({
|
|
55
56
|
initialSelectedItems: value || []
|
|
56
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
|
+
*/
|
|
57
62
|
|
|
58
|
-
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);
|
|
59
64
|
|
|
60
65
|
const {
|
|
61
66
|
isOpen,
|
|
@@ -99,9 +104,16 @@ const MultipleCombobox = ({
|
|
|
99
104
|
}) => {
|
|
100
105
|
switch (type) {
|
|
101
106
|
case useCombobox.stateChangeTypes.InputChange:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
{
|
|
108
|
+
const transformedInput = transformSearch(newSearchInputValue);
|
|
109
|
+
|
|
110
|
+
if (transformedInput.length > minLength) {
|
|
111
|
+
getOptions(transformedInput);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
setSearchInputValue(newSearchInputValue);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
105
117
|
|
|
106
118
|
case useCombobox.stateChangeTypes.InputKeyDownEnter:
|
|
107
119
|
case useCombobox.stateChangeTypes.ItemClick:
|
|
@@ -131,33 +143,40 @@ const MultipleCombobox = ({
|
|
|
131
143
|
const parentRef = useRef(null);
|
|
132
144
|
return /*#__PURE__*/React.createElement("div", {
|
|
133
145
|
id: id,
|
|
134
|
-
className: [baseClassName, componentClassName, userClassName, `y-${color}
|
|
146
|
+
className: [baseClassName, componentClassName, userClassName, `y-${color}`].filter(e => e).join(' '),
|
|
135
147
|
style: style
|
|
136
148
|
}, /*#__PURE__*/React.createElement(FormLabel, _extends({}, getLabelProps(), {
|
|
137
149
|
name: name
|
|
138
|
-
}), label), /*#__PURE__*/React.createElement("div", {
|
|
150
|
+
}), label), (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) > 0 && /*#__PURE__*/React.createElement("div", {
|
|
139
151
|
className: "selected-items"
|
|
140
|
-
}, selectedItems
|
|
152
|
+
}, selectedItems.map((selectedItem, index) => /*#__PURE__*/React.createElement("div", _extends({
|
|
141
153
|
key: selectedItem.label
|
|
142
154
|
}, getSelectedItemProps({
|
|
143
155
|
selectedItem,
|
|
144
156
|
index
|
|
145
|
-
})
|
|
146
|
-
className: "
|
|
157
|
+
}), {
|
|
158
|
+
className: "item"
|
|
159
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
147
160
|
onClick: e => {
|
|
148
161
|
e.stopPropagation();
|
|
149
162
|
removeSelectedItem(selectedItem);
|
|
150
163
|
},
|
|
151
164
|
isCompact: true,
|
|
152
165
|
isSimple: true,
|
|
153
|
-
color:
|
|
154
|
-
},
|
|
166
|
+
color: color
|
|
167
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
168
|
+
className: "v25 mr-v"
|
|
169
|
+
}, selectedItem.label), /*#__PURE__*/React.createElement("span", {
|
|
170
|
+
className: "f-icons close"
|
|
171
|
+
}, "Y"))))), /*#__PURE__*/React.createElement("div", _extends({}, getComboboxProps(), {
|
|
155
172
|
className: "input-wrapper"
|
|
156
173
|
}), /*#__PURE__*/React.createElement("input", _extends({}, getInputProps(getDropdownProps({
|
|
157
174
|
preventKeyAction: isOpen
|
|
158
175
|
})), {
|
|
159
176
|
className: "input"
|
|
160
|
-
})), isFetching && /*#__PURE__*/React.createElement(LoadingCircle,
|
|
177
|
+
})), isFetching && /*#__PURE__*/React.createElement(LoadingCircle, {
|
|
178
|
+
className: "x-main2"
|
|
179
|
+
})), /*#__PURE__*/React.createElement(Popover, {
|
|
161
180
|
isOpen: isOpen,
|
|
162
181
|
parentRef: parentRef
|
|
163
182
|
}, /*#__PURE__*/React.createElement(Menu, _extends({
|
|
@@ -243,11 +262,15 @@ MultipleCombobox.propTypes = {
|
|
|
243
262
|
isFetching: PropTypes.bool.isRequired,
|
|
244
263
|
|
|
245
264
|
/**
|
|
246
|
-
* The
|
|
265
|
+
* The minimum length of the search input to start fetching the options
|
|
266
|
+
*/
|
|
267
|
+
minLength: PropTypes.number,
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* The function to transform the search input
|
|
247
271
|
*/
|
|
248
|
-
|
|
272
|
+
transformSearch: PropTypes.func
|
|
249
273
|
};
|
|
250
|
-
MultipleCombobox.defaultProps = {
|
|
251
|
-
loadingCircleColor: 'main2'
|
|
274
|
+
MultipleCombobox.defaultProps = {// someProp: false
|
|
252
275
|
};
|
|
253
276
|
export default MultipleCombobox;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
$default-input-padding: .75em .75em .55em;
|
|
6
6
|
$default-padding: 1em;
|
|
7
7
|
$default-margin: 1em;
|
|
8
|
+
$default-gap: 1em;
|
|
8
9
|
$default-loading-circle-displacement: 1em;
|
|
9
10
|
|
|
10
11
|
.#{bem.$base}.combobox,
|
|
@@ -73,12 +74,17 @@ $default-loading-circle-displacement: 1em;
|
|
|
73
74
|
.#{bem.$base}.multiple-combobox {
|
|
74
75
|
>.selected-items {
|
|
75
76
|
display: flex;
|
|
77
|
+
gap: $default-gap / 2;
|
|
78
|
+
flex-wrap: wrap;
|
|
79
|
+
margin-bottom: $default-margin / 2;
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
+
>.item {
|
|
82
|
+
background-color: var(--main2);
|
|
83
|
+
padding: $default-padding / 4;
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
.close {
|
|
86
|
+
font-size: calc(var(--s-3) * 1em);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
83
89
|
}
|
|
84
90
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/* @pareto-engineering/generator-front 1.0.12 */
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { useRelayEnvironment, fetchQuery } from 'react-relay';
|
|
5
|
+
import { useField } from 'formik';
|
|
6
|
+
import PropTypes from 'prop-types'; // Local Definitions
|
|
7
|
+
|
|
8
|
+
import { SelectInput } from "../..";
|
|
9
|
+
/**
|
|
10
|
+
* This is the component description.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const QuerySelect = ({
|
|
14
|
+
id,
|
|
15
|
+
className: userClassName,
|
|
16
|
+
style,
|
|
17
|
+
name,
|
|
18
|
+
label,
|
|
19
|
+
query,
|
|
20
|
+
variables,
|
|
21
|
+
optionsKeyMap,
|
|
22
|
+
description,
|
|
23
|
+
disabled,
|
|
24
|
+
color,
|
|
25
|
+
loadingOption,
|
|
26
|
+
defaultOption // ...otherProps
|
|
27
|
+
|
|
28
|
+
}) => {
|
|
29
|
+
const [,, helpers] = useField(name);
|
|
30
|
+
const {
|
|
31
|
+
setError
|
|
32
|
+
} = helpers;
|
|
33
|
+
const environment = useRelayEnvironment();
|
|
34
|
+
const [isFetching, setIsFetching] = useState(false);
|
|
35
|
+
const [options, setOptions] = useState([]);
|
|
36
|
+
const {
|
|
37
|
+
graphql,
|
|
38
|
+
accessor
|
|
39
|
+
} = query;
|
|
40
|
+
|
|
41
|
+
const getOptions = () => {
|
|
42
|
+
if (isFetching) return;
|
|
43
|
+
fetchQuery(environment, graphql, variables).subscribe({
|
|
44
|
+
start: () => {
|
|
45
|
+
setIsFetching(true);
|
|
46
|
+
setOptions([loadingOption]);
|
|
47
|
+
},
|
|
48
|
+
complete: () => {
|
|
49
|
+
setIsFetching(false);
|
|
50
|
+
},
|
|
51
|
+
error: fetchError => {
|
|
52
|
+
setIsFetching(false);
|
|
53
|
+
if (setError) setError(fetchError.message);
|
|
54
|
+
},
|
|
55
|
+
next: data => {
|
|
56
|
+
setOptions([defaultOption, ...data[accessor].edges.map(({
|
|
57
|
+
node
|
|
58
|
+
}) => ({
|
|
59
|
+
value: node[optionsKeyMap.value],
|
|
60
|
+
label: node[optionsKeyMap.label]
|
|
61
|
+
}))]);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
getOptions();
|
|
68
|
+
}, [variables]);
|
|
69
|
+
return /*#__PURE__*/React.createElement(SelectInput, {
|
|
70
|
+
id: id,
|
|
71
|
+
className: userClassName,
|
|
72
|
+
style: style,
|
|
73
|
+
name: name,
|
|
74
|
+
label: label,
|
|
75
|
+
color: color,
|
|
76
|
+
description: description,
|
|
77
|
+
disabled: isFetching || disabled,
|
|
78
|
+
options: options,
|
|
79
|
+
isLoading: isFetching
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
QuerySelect.propTypes = {
|
|
84
|
+
/**
|
|
85
|
+
* The HTML id for this element
|
|
86
|
+
*/
|
|
87
|
+
id: PropTypes.string,
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The HTML class names for this element
|
|
91
|
+
*/
|
|
92
|
+
className: PropTypes.string,
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The React-written, css properties for this element.
|
|
96
|
+
*/
|
|
97
|
+
style: PropTypes.objectOf(PropTypes.string),
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The name of the custom select input
|
|
101
|
+
*/
|
|
102
|
+
name: PropTypes.string,
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The label of the custom select input
|
|
106
|
+
*/
|
|
107
|
+
label: PropTypes.string,
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The custom select input description
|
|
111
|
+
*/
|
|
112
|
+
description: PropTypes.string,
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Whether the input should be disabled
|
|
116
|
+
*/
|
|
117
|
+
disabled: PropTypes.bool,
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The base color of the custom select input
|
|
121
|
+
*/
|
|
122
|
+
color: PropTypes.string,
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The graphql query to fetch the options and the accessor to destructure the results from
|
|
126
|
+
*/
|
|
127
|
+
query: PropTypes.shape({
|
|
128
|
+
accessor: PropTypes.string,
|
|
129
|
+
graphql: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired
|
|
130
|
+
}),
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The variables that might be required to be used in the query to fetch
|
|
134
|
+
* select options.
|
|
135
|
+
*/
|
|
136
|
+
variables: PropTypes.objectOf(PropTypes.string),
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The select option keys to be used to map the data to the select options.
|
|
140
|
+
* i.e `{ value: 'id', label: 'name' }`
|
|
141
|
+
*/
|
|
142
|
+
optionsKeyMap: PropTypes.shape({
|
|
143
|
+
value: PropTypes.string.isRequired,
|
|
144
|
+
label: PropTypes.string.isRequired
|
|
145
|
+
}),
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The default select option for the query select
|
|
149
|
+
*/
|
|
150
|
+
defaultOption: PropTypes.shape({
|
|
151
|
+
value: PropTypes.string.isRequired,
|
|
152
|
+
label: PropTypes.string.isRequired,
|
|
153
|
+
disabled: PropTypes.bool.isRequired
|
|
154
|
+
}),
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The option to dipslayed when the select options are being fetched
|
|
158
|
+
*/
|
|
159
|
+
loadingOption: PropTypes.shape({
|
|
160
|
+
value: PropTypes.string.isRequired,
|
|
161
|
+
label: PropTypes.string.isRequired,
|
|
162
|
+
disabled: PropTypes.bool.isRequired
|
|
163
|
+
})
|
|
164
|
+
};
|
|
165
|
+
QuerySelect.defaultProps = {
|
|
166
|
+
disabled: false,
|
|
167
|
+
color: 'background2',
|
|
168
|
+
defaultOption: {
|
|
169
|
+
value: '',
|
|
170
|
+
label: 'Select an option',
|
|
171
|
+
disabled: true
|
|
172
|
+
},
|
|
173
|
+
loadingOption: {
|
|
174
|
+
value: '',
|
|
175
|
+
label: 'Fetching Options',
|
|
176
|
+
disabled: true
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
export default QuerySelect;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* @pareto-engineering/generator-front 1.0.12 */
|
|
2
|
+
@use "@pareto-engineering/bem";
|
|
3
|
+
|
|
4
|
+
$default-loading-circle-displacement: .8em;
|
|
5
|
+
|
|
6
|
+
.#{bem.$base}.query-select {
|
|
7
|
+
position: relative;
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
>.#{bem.$base}.select-input {
|
|
11
|
+
select:disabled {
|
|
12
|
+
appearance: none;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
>.#{bem.$base}.loading-circle {
|
|
17
|
+
position: absolute;
|
|
18
|
+
right: $default-loading-circle-displacement;
|
|
19
|
+
bottom: $default-loading-circle-displacement;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -6,6 +6,7 @@ import { useLayoutEffect, memo } from 'react';
|
|
|
6
6
|
import { useField } from 'formik';
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
8
|
import styleNames from '@pareto-engineering/bem';
|
|
9
|
+
import { LoadingCircle } from "../../../a";
|
|
9
10
|
import { FormLabel, FormDescription } from "../../common"; // Local Definitions
|
|
10
11
|
|
|
11
12
|
const baseClassName = styleNames.base;
|
|
@@ -24,7 +25,8 @@ const SelectInput = ({
|
|
|
24
25
|
options,
|
|
25
26
|
validate,
|
|
26
27
|
description,
|
|
27
|
-
disabled
|
|
28
|
+
disabled,
|
|
29
|
+
isLoading // ...otherProps
|
|
28
30
|
|
|
29
31
|
}) => {
|
|
30
32
|
useLayoutEffect(() => {
|
|
@@ -41,7 +43,9 @@ const SelectInput = ({
|
|
|
41
43
|
|
|
42
44
|
}, /*#__PURE__*/React.createElement(FormLabel, {
|
|
43
45
|
name: name
|
|
44
|
-
}, label), /*#__PURE__*/React.createElement("
|
|
46
|
+
}, label), /*#__PURE__*/React.createElement("div", {
|
|
47
|
+
className: "select-wrapper"
|
|
48
|
+
}, /*#__PURE__*/React.createElement("select", _extends({
|
|
45
49
|
className: "input"
|
|
46
50
|
}, field, {
|
|
47
51
|
value: field.value || '',
|
|
@@ -58,6 +62,8 @@ const SelectInput = ({
|
|
|
58
62
|
value: newOption.value,
|
|
59
63
|
disabled: (newOption === null || newOption === void 0 ? void 0 : newOption.disabled) || false
|
|
60
64
|
}, newOption.label);
|
|
65
|
+
})), isLoading && /*#__PURE__*/React.createElement(LoadingCircle, {
|
|
66
|
+
className: "x-main2"
|
|
61
67
|
})), (description || meta.touched && meta.error) && /*#__PURE__*/React.createElement(FormDescription, {
|
|
62
68
|
isError: !!meta.error,
|
|
63
69
|
className: "v50 mt-v s-1"
|
|
@@ -117,7 +123,12 @@ SelectInput.propTypes = {
|
|
|
117
123
|
/**
|
|
118
124
|
* The color of the select input
|
|
119
125
|
*/
|
|
120
|
-
color: PropTypes.string
|
|
126
|
+
color: PropTypes.string,
|
|
127
|
+
|
|
128
|
+
/*
|
|
129
|
+
* Whether the query that is fetching the select options is still in flight
|
|
130
|
+
*/
|
|
131
|
+
isLoading: PropTypes.bool
|
|
121
132
|
};
|
|
122
133
|
SelectInput.defaultProps = {
|
|
123
134
|
disabled: false,
|
|
@@ -16,22 +16,35 @@ $default-margin: 1em;
|
|
|
16
16
|
margin-bottom: $default-margin
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
.select-wrapper {
|
|
20
|
+
position: relative;
|
|
21
|
+
|
|
22
|
+
>.#{bem.$base}.loading-circle {
|
|
23
|
+
position: absolute;
|
|
24
|
+
right: 0;
|
|
25
|
+
top: 50%;
|
|
26
|
+
transform: translateY(-50%);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
>.input {
|
|
30
|
+
width: 100%;
|
|
31
|
+
border: var(--theme-border-style) var(--dark-y);
|
|
32
|
+
background: var(--light-y);
|
|
33
|
+
color: var(--on-y);
|
|
34
|
+
padding: $default-padding;
|
|
35
|
+
|
|
36
|
+
&:not(:disabled):hover {
|
|
37
|
+
border: var(--theme-border-style) var(--light-background4);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&:disabled {
|
|
41
|
+
background-color: var(--dark-y);
|
|
42
|
+
appearance: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&:focus {
|
|
46
|
+
background: var(--y);
|
|
47
|
+
}
|
|
35
48
|
}
|
|
36
49
|
}
|
|
37
50
|
}
|
|
@@ -3,4 +3,5 @@ export { SelectInput } from "./SelectInput";
|
|
|
3
3
|
export { ChoicesInput } from "./ChoicesInput";
|
|
4
4
|
export { TextareaInput } from "./TextareaInput";
|
|
5
5
|
export { RatingsInput } from "./RatingsInput";
|
|
6
|
-
export { QueryCombobox } from "./QueryCombobox";
|
|
6
|
+
export { QueryCombobox } from "./QueryCombobox";
|
|
7
|
+
export { QuerySelect } from "./QuerySelect";
|