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

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 (27) hide show
  1. package/dist/cjs/f/fields/QueryCombobox/QueryCombobox.js +36 -51
  2. package/dist/cjs/f/fields/QueryCombobox/common/Combobox/Combobox.js +47 -14
  3. package/dist/cjs/f/fields/QueryCombobox/common/Menu/Menu.js +1 -1
  4. package/dist/cjs/f/fields/QueryCombobox/common/index.js +1 -9
  5. package/dist/cjs/f/fields/QueryCombobox/styles.scss +45 -39
  6. package/dist/cjs/f/fields/index.js +9 -1
  7. package/dist/es/f/fields/QueryCombobox/QueryCombobox.js +40 -53
  8. package/dist/es/f/fields/QueryCombobox/common/Combobox/Combobox.js +48 -16
  9. package/dist/es/f/fields/QueryCombobox/common/Menu/Menu.js +1 -1
  10. package/dist/es/f/fields/QueryCombobox/common/index.js +1 -2
  11. package/dist/es/f/fields/QueryCombobox/styles.scss +45 -39
  12. package/dist/es/f/fields/index.js +2 -1
  13. package/package.json +3 -2
  14. package/src/__snapshots__/Storyshots.test.js.snap +158 -0
  15. package/src/stories/f/QueryCombobox.stories.jsx +220 -0
  16. package/src/stories/f/__generated__/QueryComboboxAllTeamsQuery.graphql.js +139 -0
  17. package/src/stories/utils/generateNodeId.js +12 -0
  18. package/src/stories/utils/testData.js +63 -0
  19. package/src/ui/f/fields/QueryCombobox/QueryCombobox.jsx +200 -0
  20. package/src/ui/f/fields/QueryCombobox/common/Combobox/Combobox.jsx +198 -0
  21. package/src/ui/f/fields/QueryCombobox/common/Combobox/index.js +2 -0
  22. package/src/ui/f/fields/QueryCombobox/common/Menu/Menu.jsx +103 -0
  23. package/src/ui/f/fields/QueryCombobox/common/Menu/index.js +2 -0
  24. package/src/ui/f/fields/QueryCombobox/common/index.js +2 -0
  25. package/src/ui/f/fields/QueryCombobox/index.js +2 -0
  26. package/src/ui/f/fields/QueryCombobox/styles.scss +71 -0
  27. package/src/ui/f/fields/index.js +1 -0
@@ -0,0 +1,139 @@
1
+ /**
2
+ * @flow
3
+ */
4
+
5
+ /* eslint-disable */
6
+
7
+ 'use strict';
8
+
9
+ /*::
10
+ import type { ConcreteRequest } from 'relay-runtime';
11
+ export type QueryComboboxAllTeamsQueryVariables = {|
12
+ name_Icontains?: ?string
13
+ |};
14
+ export type QueryComboboxAllTeamsQueryResponse = {|
15
+ +allTeams: ?{|
16
+ +edges: $ReadOnlyArray<?{|
17
+ +node: ?{|
18
+ +id: string,
19
+ +name: string,
20
+ |}
21
+ |}>
22
+ |}
23
+ |};
24
+ export type QueryComboboxAllTeamsQuery = {|
25
+ variables: QueryComboboxAllTeamsQueryVariables,
26
+ response: QueryComboboxAllTeamsQueryResponse,
27
+ |};
28
+ */
29
+
30
+
31
+ /*
32
+ query QueryComboboxAllTeamsQuery(
33
+ $name_Icontains: String
34
+ ) {
35
+ allTeams(name_Icontains: $name_Icontains) {
36
+ edges {
37
+ node {
38
+ id
39
+ name
40
+ }
41
+ }
42
+ }
43
+ }
44
+ */
45
+
46
+ const node/*: ConcreteRequest*/ = (function(){
47
+ var v0 = [
48
+ {
49
+ "defaultValue": null,
50
+ "kind": "LocalArgument",
51
+ "name": "name_Icontains"
52
+ }
53
+ ],
54
+ v1 = [
55
+ {
56
+ "alias": null,
57
+ "args": [
58
+ {
59
+ "kind": "Variable",
60
+ "name": "name_Icontains",
61
+ "variableName": "name_Icontains"
62
+ }
63
+ ],
64
+ "concreteType": "TeamNodeConnection",
65
+ "kind": "LinkedField",
66
+ "name": "allTeams",
67
+ "plural": false,
68
+ "selections": [
69
+ {
70
+ "alias": null,
71
+ "args": null,
72
+ "concreteType": "TeamNodeEdge",
73
+ "kind": "LinkedField",
74
+ "name": "edges",
75
+ "plural": true,
76
+ "selections": [
77
+ {
78
+ "alias": null,
79
+ "args": null,
80
+ "concreteType": "TeamNode",
81
+ "kind": "LinkedField",
82
+ "name": "node",
83
+ "plural": false,
84
+ "selections": [
85
+ {
86
+ "alias": null,
87
+ "args": null,
88
+ "kind": "ScalarField",
89
+ "name": "id",
90
+ "storageKey": null
91
+ },
92
+ {
93
+ "alias": null,
94
+ "args": null,
95
+ "kind": "ScalarField",
96
+ "name": "name",
97
+ "storageKey": null
98
+ }
99
+ ],
100
+ "storageKey": null
101
+ }
102
+ ],
103
+ "storageKey": null
104
+ }
105
+ ],
106
+ "storageKey": null
107
+ }
108
+ ];
109
+ return {
110
+ "fragment": {
111
+ "argumentDefinitions": (v0/*: any*/),
112
+ "kind": "Fragment",
113
+ "metadata": null,
114
+ "name": "QueryComboboxAllTeamsQuery",
115
+ "selections": (v1/*: any*/),
116
+ "type": "Query",
117
+ "abstractKey": null
118
+ },
119
+ "kind": "Request",
120
+ "operation": {
121
+ "argumentDefinitions": (v0/*: any*/),
122
+ "kind": "Operation",
123
+ "name": "QueryComboboxAllTeamsQuery",
124
+ "selections": (v1/*: any*/)
125
+ },
126
+ "params": {
127
+ "cacheID": "a507170c1616920d93ea7ceb061097d1",
128
+ "id": null,
129
+ "metadata": {},
130
+ "name": "QueryComboboxAllTeamsQuery",
131
+ "operationKind": "query",
132
+ "text": "query QueryComboboxAllTeamsQuery(\n $name_Icontains: String\n) {\n allTeams(name_Icontains: $name_Icontains) {\n edges {\n node {\n id\n name\n }\n }\n }\n}\n"
133
+ }
134
+ };
135
+ })();
136
+ // prettier-ignore
137
+ (node/*: any*/).hash = '243f007a2e8d0c359ad2976f1c68a472';
138
+
139
+ module.exports = node;
@@ -0,0 +1,12 @@
1
+ /* eslint-disable no-bitwise */
2
+ /* eslint-disable no-mixed-operators */
3
+ const uuidv4 = () => ([1e7] + -1e3 + -4e3 + -8e3 + -1e11)
4
+ .replace(
5
+ /[018]/g,
6
+ (c) => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4)
7
+ .toString(16),
8
+ )
9
+
10
+ const generateNodeId = (objectNode) => btoa(`${objectNode}:${uuidv4()}`)
11
+
12
+ export default generateNodeId
@@ -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
+ ]
@@ -0,0 +1,200 @@
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 } from './common'
15
+
16
+ /**
17
+ * This is the component description.
18
+ */
19
+ const QueryCombobox = ({
20
+ query,
21
+ // multiple,
22
+ name,
23
+ label,
24
+ color,
25
+ description,
26
+ disabled,
27
+ debounceMs,
28
+ graphQlNode,
29
+ searchVariable,
30
+ extraVariables,
31
+ optionsKeyMap,
32
+ // ...otherProps
33
+ }) => {
34
+ useLayoutEffect(() => {
35
+ import('./styles.scss')
36
+ }, [])
37
+
38
+ const [, meta, helpers] = useField(name)
39
+
40
+ const { setValue, setError } = helpers
41
+
42
+ const { error, value } = meta
43
+
44
+ const environment = useRelayEnvironment()
45
+
46
+ const [isFetching, setIsFetching] = useState(false)
47
+
48
+ const [options, setOptions] = useState([])
49
+
50
+ const getOptions = (inputValue) => {
51
+ if (isFetching) return
52
+
53
+ let variables = { [searchVariable]: inputValue }
54
+
55
+ if (extraVariables) {
56
+ variables = {
57
+ ...variables,
58
+ ...extraVariables,
59
+ }
60
+ }
61
+
62
+ fetchQuery(
63
+ environment,
64
+ query,
65
+ variables,
66
+ )
67
+ .subscribe({
68
+ start:() => {
69
+ setIsFetching(true)
70
+ },
71
+ complete:() => {
72
+ setIsFetching(false)
73
+ },
74
+ error:(fetchError) => {
75
+ setIsFetching(false)
76
+ if (setError)setError(fetchError.message)
77
+ },
78
+ next:(data) => {
79
+ setOptions(data[graphQlNode].edges.map(({ node }) => ({
80
+ value:node[optionsKeyMap.value],
81
+ label:node[optionsKeyMap.label],
82
+ })))
83
+ },
84
+ })
85
+ }
86
+
87
+ const comboboxProps = {
88
+ options,
89
+ getOptions,
90
+ debounceMs,
91
+ disabled,
92
+ name,
93
+ label,
94
+ description,
95
+ setValue,
96
+ error,
97
+ value,
98
+ color,
99
+ }
100
+
101
+ const Input = Combobox
102
+
103
+ return <Input {...comboboxProps} />
104
+ }
105
+
106
+ QueryCombobox.propTypes = {
107
+ /**
108
+ * The HTML id for this element
109
+ */
110
+ id:PropTypes.string,
111
+
112
+ /**
113
+ * The HTML class names for this element
114
+ */
115
+ className:PropTypes.string,
116
+
117
+ /**
118
+ * The React-written, css properties for this element.
119
+ */
120
+ style:PropTypes.objectOf(PropTypes.string),
121
+
122
+ /**
123
+ * The name of the custom select input
124
+ */
125
+ name:PropTypes.string,
126
+
127
+ /**
128
+ * The label of the custom select input
129
+ */
130
+ label:PropTypes.string,
131
+
132
+ /**
133
+ * The custom select input description
134
+ */
135
+ description:PropTypes.string,
136
+
137
+ /**
138
+ * Whether the input should be disabled
139
+ */
140
+ disabled:PropTypes.bool,
141
+
142
+ /**
143
+ * The base color of the custom select input
144
+ */
145
+ color:PropTypes.string,
146
+
147
+ /**
148
+ * The debounce time in milliseconds
149
+ */
150
+ debounceMs:PropTypes.number,
151
+
152
+ /**
153
+ * The query to fetch the options
154
+ */
155
+ query:PropTypes.oneOfType([
156
+ PropTypes.string,
157
+ PropTypes.object,
158
+ ]).isRequired,
159
+
160
+ /**
161
+ * The extra variables required to be used in the query.
162
+ */
163
+ extraVariables:PropTypes.objectOf(PropTypes.string),
164
+
165
+ /**
166
+ * The select option keys to be used to map the data to the select options.
167
+ * i.e `{ value: 'id', label: 'name' }`
168
+ */
169
+ optionsKeyMap:PropTypes.shape({
170
+ value:PropTypes.string.isRequired,
171
+ label:PropTypes.string.isRequired,
172
+ }),
173
+
174
+ /**
175
+ * Whether to allow multiple items selection
176
+ */
177
+ multiple:PropTypes.bool,
178
+
179
+ /**
180
+ * The graphql node to be used to destructure the fetched data
181
+ */
182
+ graphQlNode:PropTypes.string.isRequired,
183
+
184
+ /**
185
+ * The variable to be used to search the data
186
+ */
187
+ searchVariable:PropTypes.string,
188
+ }
189
+
190
+ QueryCombobox.defaultProps = {
191
+ optionsKeyMap:{
192
+ value:'id',
193
+ label:'name',
194
+ },
195
+ multiple :false,
196
+ color :'background2',
197
+ searchVariable:'search',
198
+ }
199
+
200
+ export default QueryCombobox
@@ -0,0 +1,198 @@
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 } 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
+ // ...otherProps
41
+ }) => {
42
+ const {
43
+ isOpen,
44
+ selectItem,
45
+ selectedItem,
46
+ getLabelProps,
47
+ getMenuProps,
48
+ getInputProps,
49
+ highlightedIndex,
50
+ getComboboxProps,
51
+ getItemProps,
52
+ } = useCombobox({
53
+ items,
54
+ initialSelectedItem:value,
55
+ itemToString :(item) => (item ? item.label : ''),
56
+ onInputValueChange :({ inputValue }) => {
57
+ getOptions(inputValue)
58
+ },
59
+ })
60
+
61
+ // If the user has selected an item, we'll set the value of the field
62
+ // or if the combobox state has a selected item, we'll set the value to the formik state
63
+ useEffect(() => {
64
+ if (selectedItem) {
65
+ setValue(selectedItem)
66
+ }
67
+ }, [selectedItem])
68
+
69
+ // If the formik state has a value, we'll set the selected item to the combobox state
70
+ useEffect(() => {
71
+ if (value?.value !== selectedItem?.value) {
72
+ selectItem(value)
73
+ }
74
+ }, [value])
75
+
76
+ const parentRef = useRef(null)
77
+
78
+ return (
79
+ <div
80
+ id={id}
81
+ className={[
82
+
83
+ baseClassName,
84
+
85
+ componentClassName,
86
+ userClassName,
87
+ `y-${color}`,
88
+ ]
89
+ .filter((e) => e)
90
+ .join(' ')}
91
+ style={style}
92
+ ref={parentRef}
93
+ >
94
+ <FormLabel {...getLabelProps()} name={name}>
95
+ {label}
96
+ </FormLabel>
97
+
98
+ <div {...getComboboxProps()} className="input-wrapper">
99
+ <input {...getInputProps()} className="input" />
100
+ </div>
101
+
102
+ <Popover
103
+ isOpen={isOpen}
104
+ parentRef={parentRef}
105
+ >
106
+ <Menu
107
+ isOpen={isOpen}
108
+ getItemProps={getItemProps}
109
+ highlightedIndex={highlightedIndex}
110
+ items={items}
111
+ {...getMenuProps()}
112
+ />
113
+ </Popover>
114
+
115
+ {(description || error) && (
116
+ <FormDescription isError={!!error}>
117
+ { error || description }
118
+ </FormDescription>
119
+ )}
120
+ </div>
121
+ )
122
+ }
123
+
124
+ Combobox.propTypes = {
125
+ /**
126
+ * The HTML id for this element
127
+ */
128
+ id:PropTypes.string,
129
+
130
+ /**
131
+ * The HTML class names for this element
132
+ */
133
+ className:PropTypes.string,
134
+
135
+ /**
136
+ * The React-written, css properties for this element.
137
+ */
138
+ style:PropTypes.objectOf(PropTypes.string),
139
+
140
+ /**
141
+ * The label of the custom select input
142
+ */
143
+ label:PropTypes.string,
144
+
145
+ /**
146
+ * The custom select input options from the backend
147
+ */
148
+ options:PropTypes.arrayOf(
149
+ PropTypes.shape({
150
+ value:PropTypes.string,
151
+ label:PropTypes.string,
152
+ }),
153
+ ),
154
+
155
+ /**
156
+ * The name of the custom select input
157
+ */
158
+ name:PropTypes.string,
159
+
160
+ /**
161
+ * The function to fetch the options from the backend
162
+ */
163
+ getOptions:PropTypes.func,
164
+
165
+ /**
166
+ * The function to set the value of the custom select input
167
+ */
168
+ setValue:PropTypes.func.isRequired,
169
+
170
+ /**
171
+ * The custom select input description
172
+ */
173
+ description:PropTypes.string,
174
+
175
+ /**
176
+ * The error object
177
+ */
178
+ error:PropTypes.objectOf(PropTypes.string),
179
+
180
+ /**
181
+ * The value of the custom select input
182
+ */
183
+ value:PropTypes.shape({
184
+ value:PropTypes.string,
185
+ label:PropTypes.string,
186
+ }),
187
+
188
+ /**
189
+ * The base color of the combobox custom select input
190
+ */
191
+ color:PropTypes.string,
192
+ }
193
+
194
+ Combobox.defaultProps = {
195
+ // someProp:false
196
+ }
197
+
198
+ 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'