@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.
Files changed (44) hide show
  1. package/dist/cjs/f/FormInput/FormInput.js +7 -0
  2. package/dist/cjs/f/fields/QueryCombobox/QueryCombobox.js +33 -11
  3. package/dist/cjs/f/fields/QueryCombobox/common/Combobox/Combobox.js +20 -9
  4. package/dist/cjs/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +40 -17
  5. package/dist/cjs/f/fields/QueryCombobox/common/index.js +9 -1
  6. package/dist/cjs/f/fields/QueryCombobox/styles.scss +11 -5
  7. package/dist/cjs/f/fields/QuerySelect/QuerySelect.js +201 -0
  8. package/dist/cjs/f/fields/QuerySelect/index.js +15 -0
  9. package/dist/cjs/f/fields/QuerySelect/styles.scss +21 -0
  10. package/dist/cjs/f/fields/SelectInput/SelectInput.js +15 -3
  11. package/dist/cjs/f/fields/SelectInput/styles.scss +27 -14
  12. package/dist/cjs/f/fields/index.js +9 -1
  13. package/dist/es/f/FormInput/FormInput.js +8 -1
  14. package/dist/es/f/fields/QueryCombobox/QueryCombobox.js +34 -12
  15. package/dist/es/f/fields/QueryCombobox/common/Combobox/Combobox.js +20 -9
  16. package/dist/es/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +40 -17
  17. package/dist/es/f/fields/QueryCombobox/common/index.js +2 -1
  18. package/dist/es/f/fields/QueryCombobox/styles.scss +11 -5
  19. package/dist/es/f/fields/QuerySelect/QuerySelect.js +179 -0
  20. package/dist/es/f/fields/QuerySelect/index.js +2 -0
  21. package/dist/es/f/fields/QuerySelect/styles.scss +21 -0
  22. package/dist/es/f/fields/SelectInput/SelectInput.js +14 -3
  23. package/dist/es/f/fields/SelectInput/styles.scss +27 -14
  24. package/dist/es/f/fields/index.js +2 -1
  25. package/package.json +2 -2
  26. package/src/__snapshots__/Storyshots.test.js.snap +783 -237
  27. package/src/local.scss +3 -3
  28. package/src/stories/f/FormInput.stories.jsx +122 -4
  29. package/src/stories/f/QueryCombobox.stories.jsx +59 -10
  30. package/src/stories/f/QuerySelect.stories.jsx +134 -0
  31. package/src/stories/f/__generated__/FormInputAllTaskStatusesQuery.graphql.js +122 -0
  32. package/src/stories/f/__generated__/QuerySelectAllTaskStatusesQuery.graphql.js +122 -0
  33. package/src/ui/f/FormInput/FormInput.jsx +10 -0
  34. package/src/ui/f/fields/QueryCombobox/QueryCombobox.jsx +34 -14
  35. package/src/ui/f/fields/QueryCombobox/common/Combobox/Combobox.jsx +15 -7
  36. package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.jsx +318 -0
  37. package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/index.js +2 -0
  38. package/src/ui/f/fields/QueryCombobox/common/index.js +1 -0
  39. package/src/ui/f/fields/QueryCombobox/styles.scss +11 -5
  40. package/src/ui/f/fields/QuerySelect/QuerySelect.jsx +200 -0
  41. package/src/ui/f/fields/QuerySelect/index.js +2 -0
  42. package/src/ui/f/fields/SelectInput/SelectInput.jsx +16 -3
  43. package/src/ui/f/fields/SelectInput/styles.scss +27 -14
  44. 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
- // multiple,
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 // ...otherProps
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, query, variables).subscribe({
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[graphQlNode].edges.map(({
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.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
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
- loadingCircleColor,
33
- isFetching // ...otherProps
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
- getOptions(inputValue);
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}`, `x-${loadingCircleColor}`].filter(e => e).join(' '),
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, null)), /*#__PURE__*/React.createElement(Popover, {
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 loading circle color
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
- loadingCircleColor: PropTypes.string
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
- loadingCircleColor // ...otherProps
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 && item.label.toLowerCase().startsWith(searchInputValue.toLowerCase()));
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
- getOptions(newSearchInputValue);
103
- setSearchInputValue(newSearchInputValue);
104
- break;
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}`, `x-${loadingCircleColor}`].filter(e => e).join(' '),
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 && selectedItems.map((selectedItem, index) => /*#__PURE__*/React.createElement("div", _extends({
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
- })), selectedItem.label, /*#__PURE__*/React.createElement(Button, {
146
- className: "f-icons",
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: "main2"
154
- }, "X")))), /*#__PURE__*/React.createElement("div", _extends({}, getComboboxProps(), {
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, null)), /*#__PURE__*/React.createElement(Popover, {
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 loading circle color
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
- loadingCircleColor: PropTypes.string
272
+ transformSearch: PropTypes.func
249
273
  };
250
- MultipleCombobox.defaultProps = {
251
- loadingCircleColor: 'main2'
274
+ MultipleCombobox.defaultProps = {// someProp: false
252
275
  };
253
276
  export default MultipleCombobox;
@@ -1,2 +1,3 @@
1
1
  export { Menu } from "./Menu";
2
- export { Combobox } from "./Combobox";
2
+ export { Combobox } from "./Combobox";
3
+ export { MultipleCombobox } from "./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
- /* stylelint-disable selector-max-universal -- Allow */
78
- >*:not(:first-child) {
79
- margin-left: $default-margin;
80
- }
81
+ >.item {
82
+ background-color: var(--main2);
83
+ padding: $default-padding / 4;
81
84
 
82
- /* stylelint-enable selector-max-universal */
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,2 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ export { default as QuerySelect } from "./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 // ...otherProps
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("select", _extends({
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
- .input {
20
- border: var(--theme-border-style) var(--dark-y);
21
- background: var(--light-y);
22
- color: var(--on-y);
23
- padding: $default-padding;
24
-
25
- &:not(:disabled):hover {
26
- border: var(--theme-border-style) var(--light-background4);
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
- &:disabled {
30
- background-color: var(--dark-y);
31
- }
32
-
33
- &:focus {
34
- background: var(--y);
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";