@@ -8,11 +8,13 @@ import {
8
8
CustomTextDefinitions ,
9
9
LinkCustomNodeDefinition ,
10
10
assign ,
11
+ matchNode ,
11
12
} from '../JsonEditImport'
12
13
import {
13
14
CollectionKey ,
14
15
DataType ,
15
16
DefaultValueFunction ,
17
+ SearchFilterFunction ,
16
18
ThemeStyles ,
17
19
UpdateFunction ,
18
20
} from '../json-edit-react/src/types'
@@ -28,6 +30,8 @@ interface DemoData {
28
30
restrictDelete ?: FilterFunction
29
31
restrictAdd ?: FilterFunction
30
32
restrictTypeSelection ?: boolean | DataType [ ]
33
+ searchFilter ?: 'key' | 'value' | 'all' | SearchFilterFunction
34
+ searchPlaceholder ?: string
31
35
onUpdate ?: UpdateFunction
32
36
onAdd ?: ( props : {
33
37
newData : object
@@ -141,16 +145,36 @@ export const demoData: Record<string, DemoData> = {
141
145
to the main "Person" objects.
142
146
</ Text >
143
147
< Text >
144
- Also, notice that when a new item is added at the top level, a correctly structured{ ' ' }
148
+ Also, notice that when you add a new item in the top level array , a correctly structured{ ' ' }
145
149
"Person" object is added, but adding new items elsewhere adds simple string values. This
146
150
is done by specifying a function for the < span className = "code" > defaultValue</ span > prop.
147
151
</ Text >
152
+ < Text >
153
+ We've also changed the behaviour of the "Search" input, so that it matches specific people
154
+ (on < span className = "code" > name</ span > and < span className = "code" > username</ span > ) and
155
+ displays all fields associated with the matching people. This is achieved by specifying a
156
+ custom{ ' ' }
157
+ < Link href = "https://github.com./CarlosNZ/json-edit-react#searchfiltering" isExternal >
158
+ Search filter function
159
+ </ Link >
160
+ .
161
+ </ Text >
148
162
</ Flex >
149
163
) ,
150
164
restrictEdit : ( { key, level } ) => key === 'id' || level === 0 || level === 1 ,
151
165
restrictAdd : ( { level } ) => level === 1 ,
152
166
restrictDelete : ( { key } ) => key === 'id' ,
153
167
collapse : 2 ,
168
+ searchFilter : ( { path, fullData } , searchText ) => {
169
+ if ( path ?. length >= 2 ) {
170
+ const index = path ?. [ 0 ]
171
+ return (
172
+ matchNode ( { value : fullData [ index ] . name } , searchText ) ||
173
+ matchNode ( { value : fullData [ index ] . username } , searchText )
174
+ )
175
+ } else return false
176
+ } ,
177
+ searchPlaceholder : 'Search by name or username' ,
154
178
defaultValue : ( { level } ) => {
155
179
if ( level === 0 )
156
180
return {
@@ -183,51 +207,70 @@ export const demoData: Record<string, DemoData> = {
183
207
vsCode : {
184
208
name : '⚙️ VSCode settings file' ,
185
209
description : (
186
- < >
210
+ < Flex flexDir = "column" gap = { 2 } >
187
211
< Text >
188
212
A typical{ ' ' }
189
213
< Link href = "https://code.visualstudio.com/" isExternal >
190
214
VSCode
191
215
</ Link > { ' ' }
192
216
config file.
193
217
</ Text >
194
- < Text mt = { 3 } >
218
+ < Text >
195
219
The only restriction here is that you can't set any boolean values to{ ' ' }
196
220
< span className = "code" > false</ span > . It uses a custom{ ' ' }
197
221
< span className = "code" > onUpdate</ span > function to return an error string when you attempt
198
222
to do so, and the value is reset to < span className = "code" > true</ span > .
199
223
</ Text >
200
- </ >
224
+ < Text >
225
+ Note the "Search" input is configured to filter for object < em > properties</ em > rather than{ ' ' }
226
+ < em > values</ em > (by setting < span className = "code" > searchFilter: "key"</ span > ).
227
+ </ Text >
228
+ </ Flex >
201
229
) ,
202
230
collapse : 2 ,
203
231
data : data . vsCode ,
204
232
onUpdate : ( { newValue } ) => {
205
233
if ( newValue === false ) return "Don't use FALSE, just delete the value"
206
234
} ,
235
+ searchFilter : 'key' ,
236
+ searchPlaceholder : 'Search properties' ,
207
237
} ,
208
238
liveData : {
209
239
name : '📖 Live Data (from database)' ,
210
240
description : (
211
- < >
241
+ < Flex flexDir = "column" gap = { 2 } >
212
242
< Text >
213
243
Here's a live "guestbook" — your changes can be saved permanently to the cloud. However,
214
244
there are restrictions:
215
- < UnorderedList >
216
- < ListItem > You can only add new messages, or fields within your message</ ListItem >
217
- < ListItem > Only the most recent message is editable, and only for five minutes</ ListItem >
218
- </ UnorderedList >
219
245
</ Text >
220
- < Text mt = { 3 } >
246
+ < UnorderedList >
247
+ < ListItem >
248
+ < Text > You can only add new messages, or fields within your message</ Text >
249
+ </ ListItem >
250
+ < ListItem >
251
+ < Text > Only the most recent message is editable, and only for five minutes</ Text >
252
+ </ ListItem >
253
+ </ UnorderedList >
254
+ < Text >
221
255
Notice also (these are achieved by customising the < span className = "code" > onEdit</ span > { ' ' }
222
256
and < span className = "code" > onAdd</ span > props):
223
- < UnorderedList >
224
- < ListItem >
257
+ </ Text >
258
+ < UnorderedList >
259
+ < ListItem >
260
+ < Text >
225
261
The messages list gets sorted so the most recent is at the < em > top</ em >
226
- </ ListItem >
227
- < ListItem > The timestamps get updated automatically after each edit</ ListItem >
228
- </ UnorderedList >
262
+ </ Text >
263
+ </ ListItem >
264
+ < ListItem >
265
+ < Text > The timestamps get updated automatically after each edit</ Text >
266
+ </ ListItem >
267
+ </ UnorderedList >
268
+ < Text >
269
+ You can also filter full "Message" objects by searching any text value (
270
+ < span className = "code" > message</ span > , < span className = "code" > name</ span > ,{ ' ' }
271
+ < span className = "code" > from</ span > ).
229
272
</ Text >
230
- </ >
273
+ </ Flex >
231
274
) ,
232
275
rootName : 'liveData' ,
233
276
collapse : 3 ,
@@ -290,6 +333,18 @@ export const demoData: Record<string, DemoData> = {
290
333
}
291
334
return 'New value'
292
335
} ,
336
+ searchFilter : ( { path, fullData } , searchText ) => {
337
+ if ( path ?. length >= 2 && path [ 0 ] === 'messages' ) {
338
+ const index = path ?. [ 1 ]
339
+ const messages = ( fullData as { messages : unknown [ ] } ) ?. messages
340
+ return (
341
+ matchNode ( { value : messages [ index ] . message } , searchText ) ||
342
+ matchNode ( { value : messages [ index ] . name } , searchText ) ||
343
+ matchNode ( { value : messages [ index ] . from } , searchText )
344
+ )
345
+ } else return true
346
+ } ,
347
+ searchPlaceholder : 'Search guestbook' ,
293
348
data : { } ,
294
349
customNodeDefinitions : [
295
350
{
@@ -337,6 +392,8 @@ export const demoData: Record<string, DemoData> = {
337
392
restrictAdd : ( { level } ) => level === 0 ,
338
393
restrictTypeSelection : [ 'string' , 'object' , 'array' ] ,
339
394
collapse : 2 ,
395
+ searchFilter : 'key' ,
396
+ searchPlaceholder : 'Search Theme keys' ,
340
397
data : { } ,
341
398
} ,
342
399
customNodes : {
@@ -373,6 +430,13 @@ export const demoData: Record<string, DemoData> = {
373
430
) ,
374
431
rootName : 'Superheroes' ,
375
432
collapse : 2 ,
433
+ searchFilter : ( { path, fullData } , searchText = '' ) => {
434
+ if ( path ?. length >= 2 ) {
435
+ const index = path ?. [ 0 ]
436
+ return matchNode ( { value : fullData [ index ] . name } , searchText )
437
+ } else return false
438
+ } ,
439
+ searchPlaceholder : 'Search by character name' ,
376
440
data : data . customNodes ,
377
441
customNodeDefinitions : [
378
442
{
0 commit comments