26
26
THE SOFTWARE.
27
27
*/
28
28
29
- import React , { useCallback } from 'react' ;
29
+ import React , { useCallback , useEffect , useRef } from 'react' ;
30
30
import { JsonFormsDispatch , JsonFormsReduxContext } from '@jsonforms/react' ;
31
- import {
32
- Heading ,
33
- Picker ,
34
- Item ,
35
- Section ,
36
- Content ,
37
- View ,
38
- } from '@adobe/react-spectrum' ;
31
+ import { useParams , useHistory } from 'react-router-dom' ;
32
+ import { Heading , Item , Content , View } from '@adobe/react-spectrum' ;
39
33
import { Tabs } from '@react-spectrum/tabs' ;
40
34
import './App.css' ;
41
- import { AppProps , initializedConnect } from './reduxUtil' ;
35
+ import {
36
+ initializedConnect ,
37
+ ExampleStateProps ,
38
+ ExampleDispatchProps ,
39
+ } from './reduxUtil' ;
42
40
import { TextArea } from './TextArea' ;
41
+ import { ReactExampleDescription } from './util' ;
42
+ import {
43
+ getExamplesFromLocalStorage ,
44
+ setExampleInLocalStorage ,
45
+ localPrefix ,
46
+ localLabelSuffix ,
47
+ } from './persistedExamples' ;
48
+ import { ExamplesPicker } from './ExamplesPicker' ;
43
49
44
- function App ( props : AppProps ) {
50
+ interface AppProps extends ExampleStateProps , ExampleDispatchProps { }
51
+
52
+ function App ( props : AppProps & { selectedExample : ReactExampleDescription } ) {
45
53
const setExampleByName = useCallback (
46
54
( exampleName : string | number ) => {
47
55
const example = props . examples . find (
@@ -56,30 +64,33 @@ function App(props: AppProps) {
56
64
57
65
const updateCurrentSchema = useCallback (
58
66
( newSchema : string ) => {
59
- props . changeExample ( {
60
- ...props . selectedExample ,
61
- schema : JSON . parse ( newSchema ) ,
62
- } ) ;
67
+ props . changeExample (
68
+ createExample ( props . selectedExample , {
69
+ schema : JSON . parse ( newSchema ) ,
70
+ } )
71
+ ) ;
63
72
} ,
64
73
[ props . changeExample , props . selectedExample ]
65
74
) ;
66
75
67
76
const updateCurrentUISchema = useCallback (
68
77
( newUISchema : string ) => {
69
- props . changeExample ( {
70
- ...props . selectedExample ,
71
- uischema : JSON . parse ( newUISchema ) ,
72
- } ) ;
78
+ props . changeExample (
79
+ createExample ( props . selectedExample , {
80
+ uischema : JSON . parse ( newUISchema ) ,
81
+ } )
82
+ ) ;
73
83
} ,
74
84
[ props . changeExample , props . selectedExample ]
75
85
) ;
76
86
77
87
const updateCurrentData = useCallback (
78
88
( newData : string ) => {
79
- props . changeExample ( {
80
- ...props . selectedExample ,
81
- data : JSON . parse ( newData ) ,
82
- } ) ;
89
+ props . changeExample (
90
+ createExample ( props . selectedExample , {
91
+ data : JSON . parse ( newData ) ,
92
+ } )
93
+ ) ;
83
94
} ,
84
95
[ props . changeExample , props . selectedExample ]
85
96
) ;
@@ -96,7 +107,7 @@ function App(props: AppProps) {
96
107
< div className = 'App-Form' >
97
108
< View padding = 'size-100' >
98
109
< Heading > { props . selectedExample . label } </ Heading >
99
- { props . getExtensionComponent ( ) }
110
+ { props . getComponent ( props . selectedExample ) }
100
111
< JsonFormsDispatch onChange = { props . onChange } />
101
112
</ View >
102
113
</ div >
@@ -105,7 +116,7 @@ function App(props: AppProps) {
105
116
< View padding = 'size-100' >
106
117
< Heading > JsonForms Examples</ Heading >
107
118
< ExamplesPicker { ...props } onChange = { setExampleByName } />
108
- < Tabs defaultSelectedKey = 'schema ' >
119
+ < Tabs defaultSelectedKey = 'boundData ' >
109
120
< Item key = 'boundData' title = 'Bound data' >
110
121
< Content margin = 'size-100' >
111
122
< TextArea
@@ -148,41 +159,74 @@ function App(props: AppProps) {
148
159
) ;
149
160
}
150
161
151
- export default initializedConnect ( App ) ;
162
+ function AppWithExampleInURL ( props : AppProps ) {
163
+ const urlParams = useParams < { name : string | undefined } > ( ) ;
164
+ const history = useHistory ( ) ;
165
+ const examplesRef = useRef ( [
166
+ ...props . examples ,
167
+ ...getExamplesFromLocalStorage ( ) ,
168
+ ] ) ;
169
+ const examples = examplesRef . current ;
152
170
153
- function ExamplesPicker (
154
- props : Omit < AppProps , 'onChange' > & {
155
- onChange : ( exampleName : string | number ) => void ;
156
- }
157
- ) {
158
- const options = [
159
- {
160
- name : 'React Spectrum Tests' ,
161
- children : props . examples
162
- . filter ( ( example ) => example . name . startsWith ( 'spectrum-' ) )
163
- . map ( ( item ) => ( { ...item , id : item . name } ) ) ,
164
- } ,
165
- {
166
- name : 'JSONForms Tests' ,
167
- children : props . examples
168
- . filter ( ( example ) => ! example . name . startsWith ( 'spectrum-' ) )
169
- . map ( ( item ) => ( { ...item , id : item . name } ) ) ,
171
+ const selectedExample = urlParams . name
172
+ ? examples . find ( ( { name } ) => urlParams . name === name )
173
+ : examples [ examples . length - 1 ] ;
174
+
175
+ const changeExample = useCallback (
176
+ ( example : ReactExampleDescription ) => {
177
+ // If we're trying to modify an item, save it to local storage and update the list of examples
178
+ if ( example . name . startsWith ( localPrefix ) ) {
179
+ setExampleInLocalStorage ( example ) ;
180
+ examplesRef . current = [
181
+ ...props . examples ,
182
+ ...getExamplesFromLocalStorage ( ) ,
183
+ ] ;
184
+ }
185
+ history . push ( `/${ example . name } ` ) ;
170
186
} ,
171
- ] ;
187
+ [ props . changeExample , history ]
188
+ ) ;
189
+
190
+ // When URL changes, we have to call changeExample to dispatch some jsonforms redux actions
191
+ useEffect ( ( ) => {
192
+ if ( selectedExample ) {
193
+ props . changeExample ( selectedExample ) ;
194
+ }
195
+ } , [ selectedExample ] ) ;
196
+
197
+ // If name is invalid, redirect to home
198
+ if ( ! selectedExample ) {
199
+ console . error (
200
+ `Could not find an example with name "${ urlParams . name } ", redirecting to /`
201
+ ) ;
202
+ history . push ( '/' ) ;
203
+ return null ;
204
+ }
172
205
173
206
return (
174
- < Picker
175
- aria-label = 'JSONForms Examples'
176
- items = { options }
177
- width = '100%'
178
- defaultSelectedKey = { props . selectedExample . name }
179
- onSelectionChange = { props . onChange }
180
- >
181
- { ( item ) => (
182
- < Section key = { item . name } items = { item . children } title = { item . name } >
183
- { ( item ) => < Item > { item . label } </ Item > }
184
- </ Section >
185
- ) }
186
- </ Picker >
207
+ < App
208
+ { ...props }
209
+ examples = { examples }
210
+ selectedExample = { selectedExample }
211
+ changeExample = { changeExample }
212
+ />
187
213
) ;
188
214
}
215
+
216
+ export const ConnectedApp = initializedConnect ( AppWithExampleInURL ) ;
217
+
218
+ function createExample (
219
+ example : ReactExampleDescription ,
220
+ part : Partial < ReactExampleDescription >
221
+ ) : ReactExampleDescription {
222
+ return {
223
+ ...example ,
224
+ name : example . name . startsWith ( localPrefix )
225
+ ? example . name
226
+ : `${ localPrefix } ${ example . name } ` ,
227
+ label : example . label . endsWith ( localLabelSuffix )
228
+ ? example . label
229
+ : `${ example . label } ${ localLabelSuffix } ` ,
230
+ ...part ,
231
+ } ;
232
+ }
0 commit comments