@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.
Files changed (35) hide show
  1. package/dist/cjs/f/FormInput/FormInput.js +8 -1
  2. package/dist/cjs/f/fields/QueryCombobox/QueryCombobox.js +49 -41
  3. package/dist/cjs/f/fields/QueryCombobox/common/Combobox/Combobox.js +72 -15
  4. package/dist/cjs/f/fields/QueryCombobox/common/Menu/Menu.js +1 -1
  5. package/dist/cjs/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +91 -21
  6. package/dist/cjs/f/fields/QueryCombobox/styles.scss +52 -39
  7. package/dist/cjs/f/fields/index.js +9 -1
  8. package/dist/es/f/FormInput/FormInput.js +9 -2
  9. package/dist/es/f/fields/QueryCombobox/QueryCombobox.js +53 -43
  10. package/dist/es/f/fields/QueryCombobox/common/Combobox/Combobox.js +73 -17
  11. package/dist/es/f/fields/QueryCombobox/common/Menu/Menu.js +1 -1
  12. package/dist/es/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.js +91 -22
  13. package/dist/es/f/fields/QueryCombobox/styles.scss +52 -39
  14. package/dist/es/f/fields/index.js +2 -1
  15. package/package.json +3 -2
  16. package/src/__snapshots__/Storyshots.test.js.snap +508 -0
  17. package/src/local.scss +3 -3
  18. package/src/stories/f/FormInput.stories.jsx +115 -0
  19. package/src/stories/f/QueryCombobox.stories.jsx +267 -0
  20. package/src/stories/f/__generated__/FormInputAllTeamsQuery.graphql.js +139 -0
  21. package/src/stories/f/__generated__/QueryComboboxAllTeamsQuery.graphql.js +139 -0
  22. package/src/stories/utils/generateNodeId.js +12 -0
  23. package/src/stories/utils/testData.js +63 -0
  24. package/src/ui/f/FormInput/FormInput.jsx +11 -0
  25. package/src/ui/f/fields/QueryCombobox/QueryCombobox.jsx +223 -0
  26. package/src/ui/f/fields/QueryCombobox/common/Combobox/Combobox.jsx +222 -0
  27. package/src/ui/f/fields/QueryCombobox/common/Combobox/index.js +2 -0
  28. package/src/ui/f/fields/QueryCombobox/common/Menu/Menu.jsx +103 -0
  29. package/src/ui/f/fields/QueryCombobox/common/Menu/index.js +2 -0
  30. package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/MultipleCombobox.jsx +317 -0
  31. package/src/ui/f/fields/QueryCombobox/common/MultipleCombobox/index.js +2 -0
  32. package/src/ui/f/fields/QueryCombobox/common/index.js +3 -0
  33. package/src/ui/f/fields/QueryCombobox/index.js +2 -0
  34. package/src/ui/f/fields/QueryCombobox/styles.scss +78 -0
  35. package/src/ui/f/fields/index.js +1 -0
@@ -0,0 +1,63 @@
1
+ export const fruits = [
2
+ 'Apple',
3
+ 'Apricot',
4
+ 'Avocado',
5
+ 'Banana',
6
+ 'Bilberry',
7
+ 'Blackberry',
8
+ 'Blackcurrant',
9
+ 'Blueberry',
10
+ 'Currant',
11
+ 'Cherry',
12
+ 'Cherimoya',
13
+ 'Clementine',
14
+ 'Date',
15
+ 'Damson',
16
+ 'Durian',
17
+ 'Eggplant',
18
+ 'Elderberry',
19
+ 'Feijoa',
20
+ 'Gooseberry',
21
+ 'Grape',
22
+ 'Grapefruit',
23
+ 'Guava',
24
+ 'Huckleberry',
25
+ 'Jackfruit',
26
+ 'Jambul',
27
+ 'Kiwi fruit',
28
+ 'Kumquat',
29
+ 'Legume',
30
+ 'Lemon',
31
+ 'Lime',
32
+ 'Lychee',
33
+ 'Mango',
34
+ 'Mangostine',
35
+ 'Melon',
36
+ 'Cantaloupe',
37
+ 'Honeydew melon',
38
+ 'Rock melon',
39
+ 'Nectarine',
40
+ 'Orange',
41
+ 'Peach',
42
+ 'Pear',
43
+ 'Williams pear or Bartlett pear',
44
+ 'Pitaya',
45
+ 'Physalis',
46
+ 'Plum/prune (dried plum)',
47
+ 'Pineapple',
48
+ 'Pomegranate',
49
+ 'Raisin',
50
+ 'Raspberry',
51
+ 'Western raspberry (blackcap)',
52
+ 'Rambutan',
53
+ 'Redcurrant',
54
+ 'Salal berry',
55
+ 'Satsuma',
56
+ 'Star fruit',
57
+ 'Strawberry',
58
+ 'Tangerine',
59
+ 'Tomato',
60
+ 'Ugli fruit',
61
+ 'Watermelon',
62
+ 'Ziziphus mauritiana',
63
+ ]
@@ -10,6 +10,7 @@ import {
10
10
  TextareaInput,
11
11
  ChoicesInput,
12
12
  SelectInput,
13
+ QueryCombobox,
13
14
  } from '../fields'
14
15
 
15
16
  // Local Definitions
@@ -64,6 +65,15 @@ const FormInput = ({
64
65
  />
65
66
  )
66
67
  }
68
+ if (type === 'query-combobox') {
69
+ return (
70
+ <QueryCombobox
71
+ className={newClassName}
72
+ disabled={disabled}
73
+ {...otherProps}
74
+ />
75
+ )
76
+ }
67
77
  if (extraTypes?.[type]) {
68
78
  const Component = extraTypes[type]
69
79
  return (
@@ -106,6 +116,7 @@ FormInput.propTypes = {
106
116
  'select',
107
117
  'choices',
108
118
  'textarea',
119
+ 'query-combobox',
109
120
  // to be removed
110
121
  'extendedTypeInput',
111
122
  ]),
@@ -0,0 +1,223 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ import * as React from 'react'
3
+
4
+ import { useState, useLayoutEffect } from 'react'
5
+
6
+ import { useField } from 'formik'
7
+
8
+ import { useRelayEnvironment, fetchQuery } from 'react-relay'
9
+
10
+ import PropTypes from 'prop-types'
11
+
12
+ // Local Definitions
13
+
14
+ import { Combobox, MultipleCombobox } from './common'
15
+
16
+ /**
17
+ * This is the component description.
18
+ */
19
+ const QueryCombobox = ({
20
+ id,
21
+ style,
22
+ className,
23
+ query,
24
+ multiple,
25
+ name,
26
+ label,
27
+ color,
28
+ description,
29
+ disabled,
30
+ debounceMs,
31
+ graphQlNode,
32
+ searchVariable,
33
+ extraVariables,
34
+ optionsKeyMap,
35
+ minLength,
36
+ transformSearch,
37
+ // ...otherProps
38
+ }) => {
39
+ useLayoutEffect(() => {
40
+ import('./styles.scss')
41
+ }, [])
42
+
43
+ const [, meta, helpers] = useField(name)
44
+
45
+ const { setValue, setError } = helpers
46
+
47
+ const { error, value } = meta
48
+
49
+ const environment = useRelayEnvironment()
50
+
51
+ const [isFetching, setIsFetching] = useState(false)
52
+
53
+ const [options, setOptions] = useState([])
54
+
55
+ const getOptions = (inputValue) => {
56
+ if (isFetching) return
57
+
58
+ let variables = { [searchVariable]: inputValue }
59
+
60
+ if (extraVariables) {
61
+ variables = {
62
+ ...variables,
63
+ ...extraVariables,
64
+ }
65
+ }
66
+
67
+ fetchQuery(
68
+ environment,
69
+ query,
70
+ variables,
71
+ )
72
+ .subscribe({
73
+ start:() => {
74
+ setIsFetching(true)
75
+ },
76
+ complete:() => {
77
+ setIsFetching(false)
78
+ },
79
+ error:(fetchError) => {
80
+ setIsFetching(false)
81
+ if (setError)setError(fetchError.message)
82
+ },
83
+ next:(data) => {
84
+ setOptions(data[graphQlNode].edges.map(({ node }) => ({
85
+ value:node[optionsKeyMap.value],
86
+ label:node[optionsKeyMap.label],
87
+ })))
88
+ },
89
+ })
90
+ }
91
+
92
+ const comboboxProps = {
93
+ id,
94
+ style,
95
+ options,
96
+ getOptions,
97
+ debounceMs,
98
+ disabled,
99
+ name,
100
+ label,
101
+ description,
102
+ setValue,
103
+ error,
104
+ value,
105
+ color,
106
+ isFetching,
107
+ className,
108
+ minLength,
109
+ transformSearch,
110
+ }
111
+
112
+ const Input = multiple ? MultipleCombobox : Combobox
113
+
114
+ return <Input {...comboboxProps} />
115
+ }
116
+
117
+ QueryCombobox.propTypes = {
118
+ /**
119
+ * The HTML id for this element
120
+ */
121
+ id:PropTypes.string,
122
+
123
+ /**
124
+ * The HTML class names for this element
125
+ */
126
+ className:PropTypes.string,
127
+
128
+ /**
129
+ * The React-written, css properties for this element.
130
+ */
131
+ style:PropTypes.objectOf(PropTypes.string),
132
+
133
+ /**
134
+ * The name of the custom select input
135
+ */
136
+ name:PropTypes.string,
137
+
138
+ /**
139
+ * The label of the custom select input
140
+ */
141
+ label:PropTypes.string,
142
+
143
+ /**
144
+ * The custom select input description
145
+ */
146
+ description:PropTypes.string,
147
+
148
+ /**
149
+ * Whether the input should be disabled
150
+ */
151
+ disabled:PropTypes.bool,
152
+
153
+ /**
154
+ * The base color of the custom select input
155
+ */
156
+ color:PropTypes.string,
157
+
158
+ /**
159
+ * The debounce time in milliseconds
160
+ */
161
+ debounceMs:PropTypes.number,
162
+
163
+ /**
164
+ * The query to fetch the options
165
+ */
166
+ query:PropTypes.oneOfType([
167
+ PropTypes.string,
168
+ PropTypes.object,
169
+ ]).isRequired,
170
+
171
+ /**
172
+ * The extra variables required to be used in the query.
173
+ */
174
+ extraVariables:PropTypes.objectOf(PropTypes.string),
175
+
176
+ /**
177
+ * The select option keys to be used to map the data to the select options.
178
+ * i.e `{ value: 'id', label: 'name' }`
179
+ */
180
+ optionsKeyMap:PropTypes.shape({
181
+ value:PropTypes.string.isRequired,
182
+ label:PropTypes.string.isRequired,
183
+ }),
184
+
185
+ /**
186
+ * Whether to allow multiple items selection
187
+ */
188
+ multiple:PropTypes.bool,
189
+
190
+ /**
191
+ * The graphql node to be used to destructure the fetched data
192
+ */
193
+ graphQlNode:PropTypes.string.isRequired,
194
+
195
+ /**
196
+ * The variable to be used to search the data
197
+ */
198
+ searchVariable:PropTypes.string,
199
+
200
+ /**
201
+ * The minimum length of the search input to start fetching the options
202
+ */
203
+ minLength:PropTypes.number,
204
+
205
+ /**
206
+ * The function to transform the search input
207
+ */
208
+ transformSearch:PropTypes.func,
209
+ }
210
+
211
+ QueryCombobox.defaultProps = {
212
+ optionsKeyMap:{
213
+ value:'id',
214
+ label:'name',
215
+ },
216
+ multiple :false,
217
+ color :'background2',
218
+ searchVariable :'search',
219
+ transformSearch:(search) => search,
220
+ minLength :2,
221
+ }
222
+
223
+ export default QueryCombobox
@@ -0,0 +1,222 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ import * as React from 'react'
3
+
4
+ import { useEffect, useRef } from 'react'
5
+
6
+ import PropTypes from 'prop-types'
7
+
8
+ import { useCombobox } from 'downshift'
9
+
10
+ import styleNames from '@pareto-engineering/bem'
11
+
12
+ import { FormLabel, FormDescription } from 'ui/f'
13
+
14
+ import { Popover, LoadingCircle } from 'ui/a'
15
+
16
+ // Local Definitions
17
+
18
+ import { Menu } from '../Menu'
19
+
20
+ const baseClassName = styleNames.base
21
+
22
+ const componentClassName = 'combobox'
23
+
24
+ /**
25
+ * This is the component description.
26
+ */
27
+ const Combobox = ({
28
+ id,
29
+ className:userClassName,
30
+ style,
31
+ label,
32
+ name,
33
+ options:items,
34
+ getOptions,
35
+ setValue,
36
+ error,
37
+ description,
38
+ value,
39
+ color,
40
+ minLength,
41
+ isFetching,
42
+ transformSearch,
43
+ // ...otherProps
44
+ }) => {
45
+ const {
46
+ isOpen,
47
+ selectItem,
48
+ selectedItem,
49
+ getLabelProps,
50
+ getMenuProps,
51
+ getInputProps,
52
+ highlightedIndex,
53
+ getComboboxProps,
54
+ getItemProps,
55
+ } = useCombobox({
56
+ items,
57
+ initialSelectedItem:value,
58
+ itemToString :(item) => (item ? item.label : ''),
59
+ onInputValueChange :({ inputValue }) => {
60
+ const transformedInput = transformSearch(inputValue)
61
+ if (transformedInput.length > minLength) {
62
+ getOptions(transformedInput)
63
+ }
64
+ },
65
+ })
66
+
67
+ // If the user has selected an item, we'll set the value of the field
68
+ // or if the combobox state has a selected item, we'll set the value to the formik state
69
+ useEffect(() => {
70
+ if (selectedItem) {
71
+ setValue(selectedItem)
72
+ }
73
+ }, [selectedItem])
74
+
75
+ // If the formik state has a value, we'll set the selected item to the combobox state
76
+ useEffect(() => {
77
+ if (value?.value !== selectedItem?.value) {
78
+ selectItem(value)
79
+ }
80
+ }, [value])
81
+
82
+ const parentRef = useRef(null)
83
+
84
+ return (
85
+ <div
86
+ id={id}
87
+ className={[
88
+
89
+ baseClassName,
90
+
91
+ componentClassName,
92
+ userClassName,
93
+ `y-${color}`,
94
+ ]
95
+ .filter((e) => e)
96
+ .join(' ')}
97
+ style={style}
98
+ ref={parentRef}
99
+ >
100
+ <FormLabel {...getLabelProps()} name={name}>
101
+ {label}
102
+ </FormLabel>
103
+
104
+ <div {...getComboboxProps()} className="input-wrapper">
105
+ <input {...getInputProps()} className="input" />
106
+ {isFetching && (
107
+ <LoadingCircle className="x-main2" />
108
+ )}
109
+ </div>
110
+
111
+ <Popover
112
+ isOpen={isOpen}
113
+ parentRef={parentRef}
114
+ >
115
+ <Menu
116
+ isOpen={isOpen}
117
+ getItemProps={getItemProps}
118
+ highlightedIndex={highlightedIndex}
119
+ items={items}
120
+ {...getMenuProps()}
121
+ />
122
+ </Popover>
123
+
124
+ {(description || error) && (
125
+ <FormDescription isError={!!error}>
126
+ { error || description }
127
+ </FormDescription>
128
+ )}
129
+ </div>
130
+ )
131
+ }
132
+
133
+ Combobox.propTypes = {
134
+ /**
135
+ * The HTML id for this element
136
+ */
137
+ id:PropTypes.string,
138
+
139
+ /**
140
+ * The HTML class names for this element
141
+ */
142
+ className:PropTypes.string,
143
+
144
+ /**
145
+ * The React-written, css properties for this element.
146
+ */
147
+ style:PropTypes.objectOf(PropTypes.string),
148
+
149
+ /**
150
+ * The label of the custom select input
151
+ */
152
+ label:PropTypes.string,
153
+
154
+ /**
155
+ * The custom select input options from the backend
156
+ */
157
+ options:PropTypes.arrayOf(
158
+ PropTypes.shape({
159
+ value:PropTypes.string,
160
+ label:PropTypes.string,
161
+ }),
162
+ ),
163
+
164
+ /**
165
+ * The name of the custom select input
166
+ */
167
+ name:PropTypes.string,
168
+
169
+ /**
170
+ * The function to fetch the options from the backend
171
+ */
172
+ getOptions:PropTypes.func,
173
+
174
+ /**
175
+ * The function to set the value of the custom select input
176
+ */
177
+ setValue:PropTypes.func.isRequired,
178
+
179
+ /**
180
+ * The custom select input description
181
+ */
182
+ description:PropTypes.string,
183
+
184
+ /**
185
+ * The error object
186
+ */
187
+ error:PropTypes.objectOf(PropTypes.string),
188
+
189
+ /**
190
+ * The value of the custom select input
191
+ */
192
+ value:PropTypes.shape({
193
+ value:PropTypes.string,
194
+ label:PropTypes.string,
195
+ }),
196
+
197
+ /**
198
+ * The base color of the combobox custom select input
199
+ */
200
+ color:PropTypes.string,
201
+
202
+ /**
203
+ * Whether the query getting the combobox options is inFlight
204
+ */
205
+ isFetching:PropTypes.bool.isRequired,
206
+
207
+ /**
208
+ * The minimum length of the search input to start fetching the options
209
+ */
210
+ minLength:PropTypes.number,
211
+
212
+ /**
213
+ * The function to transform the search input
214
+ */
215
+ transformSearch:PropTypes.func,
216
+ }
217
+
218
+ Combobox.defaultProps = {
219
+ // someProp: false
220
+ }
221
+
222
+ export default Combobox
@@ -0,0 +1,2 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ export { default as Combobox } from './Combobox'
@@ -0,0 +1,103 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ import * as React from 'react'
3
+
4
+ import PropTypes from 'prop-types'
5
+
6
+ import styleNames from '@pareto-engineering/bem'
7
+
8
+ // Local Definitions
9
+
10
+ const baseClassName = styleNames.base
11
+
12
+ const componentClassName = 'menu'
13
+
14
+ /**
15
+ * This is the component description.
16
+ */
17
+ const Menu = React.forwardRef(({
18
+ id,
19
+ className:userClassName,
20
+ style,
21
+ items,
22
+ isOpen,
23
+ highlightedIndex,
24
+ getItemProps,
25
+ ...otherProps
26
+ }, ref) => (
27
+ <ul
28
+ id={id}
29
+ className={[
30
+
31
+ baseClassName,
32
+
33
+ componentClassName,
34
+ userClassName,
35
+ ]
36
+ .filter((e) => e)
37
+ .join(' ')}
38
+ style={style}
39
+ ref={ref}
40
+ {...otherProps}
41
+ >
42
+ {isOpen && items.map((item, index) => (
43
+ <li
44
+ key={item.label}
45
+ {...getItemProps({ item, index })}
46
+ className={[
47
+ 'item',
48
+ highlightedIndex === index && styleNames.modifierActive,
49
+ ].filter(Boolean)
50
+ .join(' ')}
51
+ >
52
+ <p>
53
+ {item.label}
54
+ </p>
55
+ </li>
56
+ ))}
57
+ </ul>
58
+ ))
59
+ Menu.propTypes = {
60
+ /**
61
+ * The HTML id for this element
62
+ */
63
+ id:PropTypes.string,
64
+
65
+ /**
66
+ * The HTML class names for this element
67
+ */
68
+ className:PropTypes.string,
69
+
70
+ /**
71
+ * The React-written, css properties for this element.
72
+ */
73
+ style:PropTypes.objectOf(PropTypes.string),
74
+
75
+ /**
76
+ * The items to be displayed in the menu
77
+ */
78
+ items:PropTypes.arrayOf(PropTypes.shape({
79
+ value:PropTypes.string,
80
+ label:PropTypes.string,
81
+ })),
82
+
83
+ /**
84
+ * Whether or not the menu is open
85
+ */
86
+ isOpen:PropTypes.bool,
87
+
88
+ /**
89
+ * The index of the highlighted item
90
+ */
91
+ highlightedIndex:PropTypes.number,
92
+
93
+ /**
94
+ * The function to get the item props
95
+ */
96
+ getItemProps:PropTypes.func,
97
+ }
98
+
99
+ Menu.defaultProps = {
100
+ // someProp:false
101
+ }
102
+
103
+ export default Menu
@@ -0,0 +1,2 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ export { default as Menu } from './Menu'