@pareto-engineering/design-system 2.0.0-alpha.45 → 2.0.0-alpha.48

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 (25) hide show
  1. package/dist/cjs/f/FormInput/FormInput.js +8 -1
  2. package/dist/cjs/f/fields/QueryCombobox/QueryCombobox.js +29 -6
  3. package/dist/cjs/f/fields/QueryCombobox/common/Combobox/Combobox.js +29 -5
  4. package/dist/cjs/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +101 -26
  5. package/dist/cjs/f/fields/QueryCombobox/common/index.js +9 -1
  6. package/dist/cjs/f/fields/QueryCombobox/styles.scss +24 -5
  7. package/dist/es/f/FormInput/FormInput.js +9 -2
  8. package/dist/es/f/fields/QueryCombobox/QueryCombobox.js +30 -7
  9. package/dist/es/f/fields/QueryCombobox/common/Combobox/Combobox.js +30 -6
  10. package/dist/es/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +101 -27
  11. package/dist/es/f/fields/QueryCombobox/common/index.js +2 -1
  12. package/dist/es/f/fields/QueryCombobox/styles.scss +24 -5
  13. package/package.json +2 -2
  14. package/src/__snapshots__/Storyshots.test.js.snap +379 -14
  15. package/src/local.scss +3 -3
  16. package/src/stories/f/FormInput.stories.jsx +115 -0
  17. package/src/stories/f/QueryCombobox.stories.jsx +55 -8
  18. package/src/stories/f/__generated__/FormInputAllTeamsQuery.graphql.js +139 -0
  19. package/src/ui/f/FormInput/FormInput.jsx +11 -0
  20. package/src/ui/f/fields/QueryCombobox/QueryCombobox.jsx +29 -6
  21. package/src/ui/f/fields/QueryCombobox/common/Combobox/Combobox.jsx +27 -3
  22. package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.jsx +318 -0
  23. package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/index.js +2 -0
  24. package/src/ui/f/fields/QueryCombobox/common/index.js +1 -0
  25. package/src/ui/f/fields/QueryCombobox/styles.scss +24 -5
@@ -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
- fetchOptions,
36
+ getOptions,
27
37
  setValue,
28
38
  error,
29
- description // ...otherProps
39
+ description,
40
+ value,
41
+ color,
42
+ isFetching,
43
+ minLength,
44
+ transformSearch // ...otherProps
30
45
 
31
46
  }) => {
32
- const [inputValue, setInputValue] = useState('');
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 && item.label.toLowerCase().startsWith(inputValue.toLowerCase()));
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
- inputValue,
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: newInputValue,
101
+ inputValue: newSearchInputValue,
80
102
  type,
81
103
  selectedItem
82
104
  }) => {
83
105
  switch (type) {
84
106
  case useCombobox.stateChangeTypes.InputChange:
85
- fetchOptions(newInputValue);
86
- setInputValue(newInputValue);
87
- break;
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
- setInputValue('');
122
+ setSearchInputValue('');
94
123
  addSelectedItem(selectedItem);
95
124
  }
96
125
 
@@ -102,43 +131,60 @@ const MultipleCombobox = ({
102
131
  }
103
132
  });
104
133
  useEffect(() => {
105
- if (selectedItems.length > 0) {
106
- setValue(selectedItems.map(e => e.value));
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
- }), label), /*#__PURE__*/React.createElement("div", {
150
+ }), label), (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) > 0 && /*#__PURE__*/React.createElement("div", {
117
151
  className: "selected-items"
118
- }, selectedItems && selectedItems.map((selectedItem, index) => /*#__PURE__*/React.createElement("div", _extends({
152
+ }, selectedItems.map((selectedItem, index) => /*#__PURE__*/React.createElement("div", _extends({
119
153
  key: selectedItem.label
120
154
  }, getSelectedItemProps({
121
155
  selectedItem,
122
156
  index
123
- })), selectedItem.label, /*#__PURE__*/React.createElement(Button, {
124
- className: "f-icons",
157
+ }), {
158
+ className: "item"
159
+ }), /*#__PURE__*/React.createElement(Button, {
125
160
  onClick: e => {
126
161
  e.stopPropagation();
127
162
  removeSelectedItem(selectedItem);
128
163
  },
129
164
  isCompact: true,
130
165
  isSimple: true,
131
- color: "main2"
132
- }, "X")))), /*#__PURE__*/React.createElement("div", getComboboxProps(), /*#__PURE__*/React.createElement("input", _extends({}, getInputProps(getDropdownProps({
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(), {
172
+ className: "input-wrapper"
173
+ }), /*#__PURE__*/React.createElement("input", _extends({}, getInputProps(getDropdownProps({
133
174
  preventKeyAction: isOpen
134
175
  })), {
135
176
  className: "input"
136
- }))), /*#__PURE__*/React.createElement(Menu, _extends({
177
+ })), isFetching && /*#__PURE__*/React.createElement(LoadingCircle, {
178
+ className: "x-main2"
179
+ })), /*#__PURE__*/React.createElement(Popover, {
180
+ isOpen: isOpen,
181
+ parentRef: parentRef
182
+ }, /*#__PURE__*/React.createElement(Menu, _extends({
137
183
  isOpen: isOpen,
138
184
  getItemProps: getItemProps,
139
185
  highlightedIndex: highlightedIndex,
140
186
  items: getFilteredItems()
141
- }, getMenuProps())), (description || error) && /*#__PURE__*/React.createElement(FormDescription, {
187
+ }, getMenuProps()))), (description || error) && /*#__PURE__*/React.createElement(FormDescription, {
142
188
  isError: !!error
143
189
  }, error || description));
144
190
  };
@@ -180,7 +226,7 @@ MultipleCombobox.propTypes = {
180
226
  /**
181
227
  * The function to fetch the options from the backend
182
228
  */
183
- fetchOptions: PropTypes.func,
229
+ getOptions: PropTypes.func,
184
230
 
185
231
  /**
186
232
  * The function to set the value of the custom select input
@@ -195,8 +241,36 @@ MultipleCombobox.propTypes = {
195
241
  /**
196
242
  * The error object
197
243
  */
198
- error: PropTypes.objectOf(PropTypes.string)
244
+ error: PropTypes.objectOf(PropTypes.string),
245
+
246
+ /**
247
+ * The value of the custom select input
248
+ */
249
+ value: PropTypes.arrayOf(PropTypes.shape({
250
+ value: PropTypes.string,
251
+ label: PropTypes.string
252
+ })),
253
+
254
+ /**
255
+ * The base color of the custom select input
256
+ */
257
+ color: PropTypes.string,
258
+
259
+ /**
260
+ * Whether the query getting the combobox options is inFlight
261
+ */
262
+ isFetching: PropTypes.bool.isRequired,
263
+
264
+ /**
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
271
+ */
272
+ transformSearch: PropTypes.func
199
273
  };
200
- MultipleCombobox.defaultProps = {// someProp:false
274
+ MultipleCombobox.defaultProps = {// someProp: false
201
275
  };
202
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,11 +5,17 @@
5
5
  $default-input-padding: .75em .75em .55em;
6
6
  $default-padding: 1em;
7
7
  $default-margin: 1em;
8
+ $default-gap: 1em;
9
+ $default-loading-circle-displacement: 1em;
8
10
 
9
11
  .#{bem.$base}.combobox,
10
12
  .#{bem.$base}.multiple-combobox {
11
13
  position: relative;
12
14
 
15
+ .#{bem.$base}.label {
16
+ margin-bottom: $default-margin
17
+ }
18
+
13
19
  .#{bem.$base}.popover {
14
20
  width: 100%;
15
21
 
@@ -30,6 +36,14 @@ $default-margin: 1em;
30
36
  }
31
37
 
32
38
  >.input-wrapper {
39
+ position: relative;
40
+
41
+ >.#{bem.$base}.loading-circle {
42
+ position: absolute;
43
+ top: $default-loading-circle-displacement;
44
+ right: $default-loading-circle-displacement;
45
+ }
46
+
33
47
  >.input {
34
48
  background: var(--light-y);
35
49
  border: var(--theme-border-style) var(--dark-y);
@@ -60,12 +74,17 @@ $default-margin: 1em;
60
74
  .#{bem.$base}.multiple-combobox {
61
75
  >.selected-items {
62
76
  display: flex;
77
+ gap: $default-gap / 2;
78
+ flex-wrap: wrap;
79
+ margin-bottom: $default-margin / 2;
63
80
 
64
- /* stylelint-disable selector-max-universal -- Allow */
65
- >*:not(:first-child) {
66
- margin-left: $default-margin;
67
- }
81
+ >.item {
82
+ background-color: var(--main2);
83
+ padding: $default-padding / 4;
68
84
 
69
- /* stylelint-enable selector-max-universal */
85
+ .close {
86
+ font-size: calc(var(--s-3) * 1em);
87
+ }
88
+ }
70
89
  }
71
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pareto-engineering/design-system",
3
- "version": "2.0.0-alpha.45",
3
+ "version": "2.0.0-alpha.48",
4
4
  "description": "",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/es/index.js",
@@ -88,7 +88,7 @@
88
88
  "stylelint-config-palantir": "^5.1.0"
89
89
  },
90
90
  "dependencies": {
91
- "@pareto-engineering/assets": "^2.0.0-alpha.21",
91
+ "@pareto-engineering/assets": "^2.0.0-alpha.22",
92
92
  "@pareto-engineering/bem": "^0.1.5",
93
93
  "@pareto-engineering/styles": "^2.0.0-alpha.8",
94
94
  "date-fns": "^2.22.1",