33import React , { useState } from 'react' ;
44import { ObjectView } from './ObjectView/ObjectView' ;
55import { allExamples , quickExamples , performanceTestData } from './exampleData' ;
6+ import { JSONViewProps , Constructor } from './ObjectView/JSONViewProps' ;
67import './style.css' ;
8+ import "./Test.css" ;
9+ // Custom classes for demonstration
10+ class User {
11+ constructor ( public name : string , public email : string , public role : string = 'user' ) { }
12+ }
13+
14+ class APIEndpoint {
15+ constructor (
16+ public method : string ,
17+ public url : string ,
18+ public status : number ,
19+ public responseTime : number ,
20+ public data ?: any
21+ ) { }
22+ }
23+
24+ // Custom renderer for User class
25+ const UserRenderer : React . FC < JSONViewProps > = ( { value, name, displayName, seperator = ":" } ) => (
26+ < div className = "custom-user-view" style = { {
27+ padding : '4px 8px' ,
28+ borderRadius : '4px' ,
29+ backgroundColor : '#f0f8ff' ,
30+ border : '1px solid #e0e8f0'
31+ } } >
32+ { displayName && < span className = "jv-name" > { name } </ span > }
33+ { displayName && < span > { seperator } </ span > }
34+ < span style = { { marginRight : '8px' } } > 👤</ span >
35+ < strong > { value . name } </ strong >
36+ < span style = { { color : '#666' , marginLeft : '8px' } } > ({ value . email } )</ span >
37+ { value . role !== 'user' && (
38+ < span style = { {
39+ backgroundColor : '#ffd700' ,
40+ padding : '2px 6px' ,
41+ borderRadius : '3px' ,
42+ fontSize : '10px' ,
43+ marginLeft : '8px' ,
44+ textTransform : 'uppercase'
45+ } } >
46+ { value . role }
47+ </ span >
48+ ) }
49+ </ div >
50+ ) ;
51+
52+ // Custom renderer for API endpoints
53+ const APIRenderer : React . FC < JSONViewProps > = ( { value, name, displayName, seperator = ":" } ) => {
54+ const getStatusColor = ( status : number ) => {
55+ if ( status < 300 ) return '#28a745' ;
56+ if ( status < 400 ) return '#ffc107' ;
57+ return '#dc3545' ;
58+ } ;
59+
60+ const getMethodColor = ( method : string ) => {
61+ switch ( method ) {
62+ case 'GET' : return '#007bff' ;
63+ case 'POST' : return '#28a745' ;
64+ case 'PUT' : return '#ffc107' ;
65+ case 'DELETE' : return '#dc3545' ;
66+ default : return '#6c757d' ;
67+ }
68+ } ;
69+
70+ return (
71+ < div style = { {
72+ padding : '6px 10px' ,
73+ borderRadius : '4px' ,
74+ backgroundColor : '#f8f9fa' ,
75+ border : '1px solid #dee2e6' ,
76+ fontFamily : 'monospace'
77+ } } >
78+ { displayName && < span className = "jv-name" > { name } </ span > }
79+ { displayName && < span > { seperator } </ span > }
80+ < span style = { {
81+ backgroundColor : getMethodColor ( value . method ) ,
82+ color : 'white' ,
83+ padding : '2px 6px' ,
84+ borderRadius : '3px' ,
85+ fontSize : '11px' ,
86+ marginRight : '8px'
87+ } } >
88+ { value . method }
89+ </ span >
90+ < span style = { { marginRight : '8px' } } > { value . url } </ span >
91+ < span style = { {
92+ color : getStatusColor ( value . status ) ,
93+ fontWeight : 'bold' ,
94+ marginRight : '8px'
95+ } } >
96+ { value . status }
97+ </ span >
98+ < span style = { { color : '#666' , fontSize : '12px' } } >
99+ { value . responseTime } ms
100+ </ span >
101+ </ div >
102+ ) ;
103+ } ;
104+
105+ // Create custom data with new classes
106+ const createCustomExampleData = ( ) => ( {
107+ users : {
108+ admin : new User ( "Admin User" , "admin@example.com" , "admin" ) ,
109+ moderator : new User ( "Mod User" , "mod@example.com" , "moderator" ) ,
110+ regular : new User ( "John Doe" , "john@example.com" )
111+ } ,
112+ apiCalls : {
113+ getUsersAPI : new APIEndpoint ( 'GET' , '/api/users' , 200 , 145 ) ,
114+ loginAPI : new APIEndpoint ( 'POST' , '/api/auth/login' , 401 , 89 ) ,
115+ createUserAPI : new APIEndpoint ( 'POST' , '/api/users' , 201 , 234 ) ,
116+ deleteUserAPI : new APIEndpoint ( 'DELETE' , '/api/users/123' , 204 , 156 )
117+ } ,
118+ keywordDemo : {
119+ isActive : true ,
120+ isDisabled : false ,
121+ data : null ,
122+ config : undefined ,
123+ emptyString : "" ,
124+ zeroNumber : 0
125+ }
126+ } ) ;
7127
8128// Create a flat list of all available test data for the dropdown
9129const testDataOptions = [
@@ -12,6 +132,16 @@ const testDataOptions = [
12132 { label : 'Quick - Moderate Nested' , value : quickExamples . moderate , category : 'Quick' } ,
13133 { label : 'Quick - Complex Mixed Types' , value : quickExamples . complex , category : 'Quick' } ,
14134
135+ // NEW: Custom renderer demos
136+ { label : 'Demo - Custom Renderers' , value : createCustomExampleData ( ) , category : 'Demo' } ,
137+ {
138+ label : 'Demo - Keyword Styling' , value : {
139+ booleans : { isTrue : true , isFalse : false } ,
140+ nullish : { nullValue : null , undefinedValue : undefined } ,
141+ emptyValues : { emptyString : "" , zeroNumber : 0 , emptyArray : [ ] , emptyObject : { } }
142+ } , category : 'Demo'
143+ } ,
144+
15145 // Primitives
16146 {
17147 label : 'Primitives - Basic Types' , value : {
@@ -70,6 +200,18 @@ export const Test = () => {
70200 const [ customDataParsed , setCustomDataParsed ] = useState < any > ( null ) ;
71201 const [ parseError , setParseError ] = useState < string > ( '' ) ;
72202
203+ // NEW: State for new features
204+ const [ enableCustomRenderers , setEnableCustomRenderers ] = useState ( true ) ;
205+ const [ enableHighlighting , setEnableHighlighting ] = useState ( true ) ;
206+ const [ objectGrouped , setObjectGrouped ] = useState ( 25 ) ;
207+ const [ arrayGrouped , setArrayGrouped ] = useState ( 10 ) ;
208+
209+ // Create custom renderer map
210+ const customRenderers = enableCustomRenderers ? new Map < Constructor , React . FC < JSONViewProps > > ( [
211+ [ User as Constructor , UserRenderer ] ,
212+ [ APIEndpoint as Constructor , APIRenderer ]
213+ ] ) : undefined ;
214+
73215 const handleDataChange = ( event : React . ChangeEvent < HTMLSelectElement > ) => {
74216 const selectedIndex = parseInt ( event . target . value ) ;
75217 setSelectedData ( testDataOptions [ selectedIndex ] ) ;
@@ -143,6 +285,20 @@ export const Test = () => {
143285 < div style = { { padding : '20px' , fontFamily : 'Arial, sans-serif' } } >
144286 < h1 > ObjectView Test Interface</ h1 >
145287
288+ < div style = { {
289+ marginBottom : '20px' ,
290+ padding : '15px' ,
291+ backgroundColor : '#e8f4fd' ,
292+ borderRadius : '8px' ,
293+ border : '1px solid #bee5eb'
294+ } } >
295+ < h3 style = { { margin : '0 0 10px 0' , color : '#0c5460' } } > 🆕 New Features Demo</ h3 >
296+ < p style = { { margin : '0' , fontSize : '14px' , color : '#0c5460' } } >
297+ This demo showcases the latest features: Custom Renderers, Keyword Styling, and Configurable Highlighting.
298+ Try selecting "Demo - Custom Renderers" to see custom User and API endpoint visualizations!
299+ </ p >
300+ </ div >
301+
146302 < div style = { { marginBottom : '20px' , display : 'flex' , gap : '20px' , alignItems : 'flex-start' , flexWrap : 'wrap' } } >
147303 < div style = { { display : 'flex' , gap : '20px' , alignItems : 'center' , flexWrap : 'wrap' } } >
148304 < div >
@@ -206,6 +362,65 @@ export const Test = () => {
206362 </ div >
207363 </ div >
208364
365+ { /* NEW: Additional controls for new features */ }
366+ < div style = { { display : 'flex' , gap : '20px' , alignItems : 'center' , flexWrap : 'wrap' } } >
367+ < div >
368+ < label style = { { display : 'block' , marginBottom : '5px' , fontWeight : 'bold' } } >
369+ 🎨 Features:
370+ </ label >
371+ < div style = { { display : 'flex' , gap : '15px' , flexWrap : 'wrap' } } >
372+ < label style = { { display : 'flex' , alignItems : 'center' } } >
373+ < input
374+ type = "checkbox"
375+ checked = { enableCustomRenderers }
376+ onChange = { ( e ) => setEnableCustomRenderers ( e . target . checked ) }
377+ style = { { marginRight : '6px' } }
378+ />
379+ Custom Renderers
380+ </ label >
381+ < label style = { { display : 'flex' , alignItems : 'center' } } >
382+ < input
383+ type = "checkbox"
384+ checked = { enableHighlighting }
385+ onChange = { ( e ) => setEnableHighlighting ( e . target . checked ) }
386+ style = { { marginRight : '6px' } }
387+ />
388+ Change Highlighting
389+ </ label >
390+ </ div >
391+ </ div >
392+
393+ < div >
394+ < label style = { { display : 'block' , marginBottom : '5px' , fontWeight : 'bold' } } >
395+ 📦 Grouping:
396+ </ label >
397+ < div style = { { display : 'flex' , gap : '10px' , alignItems : 'center' } } >
398+ < label style = { { fontSize : '12px' } } >
399+ Objects:
400+ < input
401+ type = "number"
402+ value = { objectGrouped }
403+ onChange = { ( e ) => setObjectGrouped ( parseInt ( e . target . value ) || 25 ) }
404+ style = { { width : '50px' , marginLeft : '4px' , padding : '2px' } }
405+ min = "1"
406+ max = "100"
407+ />
408+ </ label >
409+ < label style = { { fontSize : '12px' } } >
410+ Arrays:
411+ < input
412+ type = "number"
413+ value = { arrayGrouped }
414+ onChange = { ( e ) => setArrayGrouped ( parseInt ( e . target . value ) || 10 ) }
415+ style = { { width : '50px' , marginLeft : '4px' , padding : '2px' } }
416+ min = "1"
417+ max = "100"
418+ />
419+ </ label >
420+ </ div >
421+ </ div >
422+ </ div >
423+
209424 < div style = { { minWidth : '300px' } } >
210425 < label style = { { display : 'block' , marginBottom : '5px' , fontWeight : 'bold' } } >
211426 < input
@@ -264,7 +479,10 @@ export const Test = () => {
264479 Status: { parseError ? 'Invalid' : 'Valid' } |
265480 </ >
266481 ) }
267- Expand Level: { expandLevel === true ? 'Full' : expandLevel === false ? 'None' : expandLevel }
482+ Expand Level: { expandLevel === true ? 'Full' : expandLevel === false ? 'None' : expandLevel } |
483+ Custom Renderers: { enableCustomRenderers ? 'ON' : 'OFF' } |
484+ Change Highlighting: { enableHighlighting ? 'ON' : 'OFF' } |
485+ Grouping: Objects({ objectGrouped } ) Arrays({ arrayGrouped } )
268486 </ p >
269487 </ div >
270488
@@ -288,6 +506,10 @@ export const Test = () => {
288506 value = { getCurrentData ( ) }
289507 name = "testData"
290508 expandLevel = { expandLevel }
509+ customRender = { customRenderers }
510+ highlightUpdate = { enableHighlighting }
511+ objectGrouped = { objectGrouped }
512+ arrayGrouped = { arrayGrouped }
291513 />
292514 </ div >
293515 </ div >
0 commit comments