@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
@@ -8,6 +8,15 @@ import {
8
8
  FormDebugger,
9
9
  } from 'ui'
10
10
 
11
+ import { fruits } from '../utils/testData'
12
+
13
+ import {
14
+ RelayEnvironmentProvider,
15
+ mockRelayOperation,
16
+ } from '../utils/relay'
17
+
18
+ import generateNodeId from '../utils/generateNodeId'
19
+
11
20
  export default {
12
21
  title :'f/FormInput',
13
22
  component :FormInput,
@@ -25,6 +34,11 @@ export default {
25
34
  </Form>
26
35
  </Formik>
27
36
  ),
37
+ (storyfn) => (
38
+ <RelayEnvironmentProvider>
39
+ { storyfn() }
40
+ </RelayEnvironmentProvider>
41
+ ),
28
42
  ],
29
43
  argTypes:{
30
44
  backgroundColor:{ control: 'color' },
@@ -99,6 +113,107 @@ export const Base = () => {
99
113
  )
100
114
  }
101
115
 
116
+ const allTeamsMockData = {
117
+ PageInfo() {
118
+ return {
119
+ hasNextPage :true,
120
+ hasPreviousPage:true,
121
+ }
122
+ },
123
+ TeamNodeConnection:(args) => {
124
+ const edges = fruits.map((fruit) => ({
125
+ node:{
126
+ id :generateNodeId('TeamNode'),
127
+ name:fruit,
128
+ },
129
+ }))
130
+
131
+ // eslint-disable-next-line camelcase
132
+ const { name_Icontains } = args?.args || {}
133
+
134
+ return ({
135
+ pageInfo:{
136
+ hasNextPage :true,
137
+ hasPreviousPage:true,
138
+ },
139
+ // eslint-disable-next-line camelcase
140
+ edges:name_Icontains?.trim()
141
+ ? edges.filter(({ node }) => node.name
142
+ .toLowerCase()
143
+ .includes(name_Icontains.toLowerCase()))
144
+ : [],
145
+ })
146
+ },
147
+ }
148
+
149
+ const FETCH_TEAMS_QUERY = graphql`
150
+ query FormInputAllTeamsQuery($name_Icontains: String) {
151
+ allTeams(name_Icontains: $name_Icontains) {
152
+ edges {
153
+ node {
154
+ id
155
+ name
156
+ }
157
+ }
158
+ }
159
+ }
160
+ `
161
+
162
+ export const WithQueryCombobox = () => {
163
+ const inputMap = [
164
+ {
165
+ type :'text',
166
+ name :'firstName',
167
+ label:"What's your first name ?",
168
+ },
169
+ {
170
+ type :'choices',
171
+ name :'colors',
172
+ label :'What are your favourite colors ?',
173
+ options:[
174
+ {
175
+ value:'red',
176
+ label:'Color Red',
177
+ },
178
+ {
179
+ value:'blue',
180
+ label:'Color Blue',
181
+ },
182
+ {
183
+ value:'green',
184
+ label:'Color Green',
185
+ },
186
+ ],
187
+ },
188
+ {
189
+ type :'query-combobox',
190
+ name :'team',
191
+ query :FETCH_TEAMS_QUERY,
192
+ label :'Search for a team',
193
+ optionsKeyMap:{
194
+ value:'id',
195
+ label:'name',
196
+ },
197
+ graphQlNode :'allTeams',
198
+ searchVariable:'name_Icontains',
199
+ },
200
+ ]
201
+
202
+ mockRelayOperation(allTeamsMockData)
203
+ mockRelayOperation(allTeamsMockData)
204
+ mockRelayOperation(allTeamsMockData)
205
+
206
+ return (
207
+ <>
208
+ {
209
+ inputMap.map((input) => <FormInput {...input} key={input.name} />)
210
+ }
211
+ <FormDebugger />
212
+
213
+ </>
214
+ )
215
+ }
216
+
102
217
  export const ExtensibleFormInput = () => {
103
218
  const ExtendedTextInput = (props) => (
104
219
  <TextInput
@@ -0,0 +1,267 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ import * as React from 'react'
3
+
4
+ import { Formik, Form, useField } from 'formik'
5
+
6
+ import { Button, FormDebugger, QueryCombobox } from 'ui'
7
+
8
+ import { fruits } from '../utils/testData'
9
+
10
+ import generateNodeId from '../utils/generateNodeId'
11
+
12
+ import {
13
+ RelayEnvironmentProvider,
14
+ mockRelayOperation,
15
+ // environment,
16
+ } from '../utils/relay'
17
+
18
+ export default {
19
+ title :'f/fields/QueryCombobox',
20
+ component :QueryCombobox,
21
+ subcomponents:{
22
+ // Item:QueryCombobox.Item
23
+ },
24
+ decorators:[
25
+ (storyfn) => (
26
+ <RelayEnvironmentProvider>
27
+ { storyfn() }
28
+ </RelayEnvironmentProvider>
29
+ ),
30
+ ],
31
+ argTypes:{
32
+ backgroundColor:{ control: 'color' },
33
+ },
34
+ }
35
+
36
+ const allTeamsMockData = {
37
+ PageInfo() {
38
+ return {
39
+ hasNextPage :true,
40
+ hasPreviousPage:true,
41
+ }
42
+ },
43
+ TeamNodeConnection:(args) => {
44
+ const edges = fruits.map((fruit) => ({
45
+ node:{
46
+ id :generateNodeId('TeamNode'),
47
+ name:fruit,
48
+ },
49
+ }))
50
+
51
+ // eslint-disable-next-line camelcase
52
+ const { name_Icontains } = args?.args || {}
53
+
54
+ return ({
55
+ pageInfo:{
56
+ hasNextPage :true,
57
+ hasPreviousPage:true,
58
+ },
59
+ // eslint-disable-next-line camelcase
60
+ edges:name_Icontains?.trim()
61
+ ? edges.filter(({ node }) => node.name
62
+ .toLowerCase()
63
+ .includes(name_Icontains.toLowerCase()))
64
+ : [],
65
+ })
66
+ },
67
+ }
68
+
69
+ const FETCH_TEAMS_QUERY = graphql`
70
+ query QueryComboboxAllTeamsQuery($name_Icontains: String) {
71
+ allTeams(name_Icontains: $name_Icontains) {
72
+ edges {
73
+ node {
74
+ id
75
+ name
76
+ }
77
+ }
78
+ }
79
+ }
80
+ `
81
+
82
+ // eslint-disable-next-line react/prop-types
83
+ const ResolvedTemplate = ({ multiple, defaultFormikState }) => {
84
+ mockRelayOperation(allTeamsMockData)
85
+ mockRelayOperation(allTeamsMockData)
86
+ mockRelayOperation(allTeamsMockData)
87
+
88
+ const Content = () => {
89
+ const name = multiple ? 'teams' : 'team'
90
+
91
+ const [, meta, helpers] = useField(name)
92
+
93
+ const { value } = meta
94
+
95
+ const { setValue } = helpers
96
+
97
+ const updateFormikState = () => {
98
+ if (multiple) {
99
+ setValue([
100
+ ...(value || []),
101
+ {
102
+ value:'VGVhbU5vZGU6MDAxZTIyOGEtYzA5My00MGI0LWE1MTUtYTNkMTM1NTE1MDNk',
103
+ label:'Matomoko',
104
+ },
105
+ {
106
+ value:'VGVhbU5vZGU6MDAxZTIyOGEtYzA5My00MGI0LWE1MTUtYTNkMTM1NTE1MDNp',
107
+ label:'Chungwa',
108
+ },
109
+ ])
110
+ } else {
111
+ setValue({
112
+ value:'VGVhbU5vZGU6MDAxZTIyOGEtYzA5My00MGI0LWE1MTUtYTNkMTM1NTE1MDNk',
113
+ label:'Kafagoho',
114
+ })
115
+ }
116
+ }
117
+
118
+ return (
119
+ <>
120
+ <QueryCombobox
121
+ query={FETCH_TEAMS_QUERY}
122
+ label="Search for a team"
123
+ optionsKeyMap={{
124
+ value:'id',
125
+ label:'name',
126
+ }}
127
+ name={name}
128
+ multiple={multiple}
129
+ graphQlNode="allTeams"
130
+ searchVariable="name_Icontains"
131
+ />
132
+ <div
133
+ style={{
134
+ display :'flex',
135
+ alignItems :'flex-end',
136
+ flexDirection:'column',
137
+ }}
138
+ >
139
+ <FormDebugger />
140
+ <Button
141
+ onClick={updateFormikState}
142
+ >
143
+ {multiple ? 'Add formik values' : 'Replace formik value'}
144
+ </Button>
145
+ </div>
146
+ </>
147
+ )
148
+ }
149
+
150
+ let initialValues = defaultFormikState
151
+
152
+ if (!defaultFormikState && multiple) {
153
+ initialValues = []
154
+ } else if (!defaultFormikState && !multiple) {
155
+ initialValues = {}
156
+ }
157
+
158
+ return (
159
+ <Formik
160
+ initialValues={initialValues}
161
+ >
162
+ <Form>
163
+ <Content />
164
+ </Form>
165
+ </Formik>
166
+ )
167
+ }
168
+
169
+ export const SingleSelect = ResolvedTemplate.bind({})
170
+ SingleSelect.args = {
171
+ multiple:false,
172
+ }
173
+
174
+ export const SingleSelectWithDefaultFormikState = ResolvedTemplate.bind({})
175
+ SingleSelectWithDefaultFormikState.args = {
176
+ multiple :false,
177
+ defaultFormikState:{
178
+ team:{
179
+ value:'VGVhbU5vZGU6MDAxZTIyOGEtYzA5My00MGI0LWE1MTUtYTNkMTM1NTE1MDNl',
180
+ label:'Apple',
181
+ },
182
+ },
183
+ }
184
+
185
+ export const MultipleSelect = ResolvedTemplate.bind({})
186
+ MultipleSelect.args = {
187
+ multiple :true,
188
+ defaultFormikState:{ teams: [] },
189
+ }
190
+
191
+ export const MultipleSelectWithDefaultFormikState = ResolvedTemplate.bind({})
192
+ MultipleSelectWithDefaultFormikState.args = {
193
+ multiple :true,
194
+ defaultFormikState:{
195
+ teams:[
196
+ {
197
+ value:'VGVhbU5vZGU6MDAxZTIyOGEtYzA5My00MGI0LWE1MTUtYTNkMTM1NTE1MDNl',
198
+ label:'Apple',
199
+ },
200
+ {
201
+ value:'VGVhbU5vZGU6MDA0N2U4MzktODY0Zi00N2U5LTg3ZjgtZGUwMmM2Yzg1YWJm',
202
+ label:'Pear',
203
+ },
204
+ ],
205
+ },
206
+ }
207
+
208
+ // eslint-disable-next-line react/prop-types
209
+ // const RejectedTemplate = ({ multiple }) => {
210
+ // const Content = () => {
211
+ // environment.mock.queuePendingOperation(
212
+ // FETCH_TEAMS_QUERY,
213
+ // { name_Icontains: 'a' },
214
+ // )
215
+
216
+ // environment.mock.rejectMostRecentOperation('An error has occured while fetching the teams')
217
+
218
+ // const name = multiple ? 'teams' : 'team'
219
+
220
+ // const [, meta, helpers] = useField(name)
221
+
222
+ // const { setValue, setError } = helpers
223
+
224
+ // const { error } = meta
225
+
226
+ // return (
227
+ // <>
228
+ // <QueryCombobox
229
+ // query={FETCH_TEAMS_QUERY}
230
+ // label="Search for a team"
231
+ // optionsKeyMap={{
232
+ // value:'id',
233
+ // label:'name',
234
+ // }}
235
+ // error={error}
236
+ // setValue={setValue}
237
+ // setError={setError}
238
+ // name={name}
239
+ // multiple={multiple}
240
+ // graphQlNode="allTeams"
241
+ // searchVariable="name_Icontains"
242
+ // />
243
+ // <FormDebugger />
244
+ // </>
245
+ // )
246
+ // }
247
+
248
+ // return (
249
+ // <Formik
250
+ // initialValues={{ team: '' }}
251
+ // >
252
+ // <Form>
253
+ // <Content />
254
+ // </Form>
255
+ // </Formik>
256
+ // )
257
+ // }
258
+
259
+ // export const SingleSelectWithError = RejectedTemplate.bind({})
260
+ // SingleSelectWithError.args = {
261
+ // multiple:false,
262
+ // }
263
+
264
+ // export const MultipleSelectWithError = RejectedTemplate.bind({})
265
+ // MultipleSelectWithError.args = {
266
+ // multiple:true,
267
+ // }
@@ -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 FormInputAllTeamsQueryVariables = {|
12
+ name_Icontains?: ?string
13
+ |};
14
+ export type FormInputAllTeamsQueryResponse = {|
15
+ +allTeams: ?{|
16
+ +edges: $ReadOnlyArray<?{|
17
+ +node: ?{|
18
+ +id: string,
19
+ +name: string,
20
+ |}
21
+ |}>
22
+ |}
23
+ |};
24
+ export type FormInputAllTeamsQuery = {|
25
+ variables: FormInputAllTeamsQueryVariables,
26
+ response: FormInputAllTeamsQueryResponse,
27
+ |};
28
+ */
29
+
30
+
31
+ /*
32
+ query FormInputAllTeamsQuery(
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": "FormInputAllTeamsQuery",
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": "FormInputAllTeamsQuery",
124
+ "selections": (v1/*: any*/)
125
+ },
126
+ "params": {
127
+ "cacheID": "dc9287c6d087d0f0e1be2e8ef405cb1f",
128
+ "id": null,
129
+ "metadata": {},
130
+ "name": "FormInputAllTeamsQuery",
131
+ "operationKind": "query",
132
+ "text": "query FormInputAllTeamsQuery(\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 = 'c76b6f84436895e8a6d0725bdd41cfe0';
138
+
139
+ module.exports = node;
@@ -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