1
1
import React , { useState , useEffect } from 'react' ;
2
2
import SchemaObject from './VisualEditor/SchemaObject' ;
3
3
import _ from 'lodash' ;
4
+ import { getColorForType } from './VisualEditor/SchemaProperty' ;
5
+ import { DropdownMenu , DropdownMenuItem } from './DropdownMenu' ;
6
+ import { IoIosArrowDropdown } from 'react-icons/io' ;
4
7
5
8
interface VisualEditorProps {
6
9
schema : string ;
@@ -15,14 +18,7 @@ interface SchemaObjectInterface {
15
18
}
16
19
17
20
export const VisualEditor : React . FC < VisualEditorProps > = ( { schema, onSchemaChange } ) => {
18
- const selectStyle = {
19
- backgroundColor : '#0F172A' ,
20
- color : 'white' ,
21
- borderRadius : '3px' ,
22
- fontSize : '12px' ,
23
- fontFamily : 'Inter, sans-serif'
24
- } ;
25
-
21
+
26
22
const [ schemaObject , setSchemaObject ] = useState < SchemaObjectInterface > ( { } ) ;
27
23
28
24
useEffect ( ( ) => {
@@ -36,64 +32,157 @@ export const VisualEditor: React.FC<VisualEditorProps> = ({ schema, onSchemaChan
36
32
} , [ schema ] ) ;
37
33
38
34
const handleSchemaChange = ( updatedPart : any ) => {
39
- const updatedSchema = { ...schemaObject , ...updatedPart } ;
35
+ let updatedSchema = _ . cloneDeep ( schemaObject ) ;
36
+ console . log ( "updatedPart.type" , updatedPart . type )
37
+
38
+ if ( updatedSchema . type === 'array' ) {
39
+ if ( updatedPart . items && updatedPart . items . type === 'object' ) {
40
+ updatedSchema . items = updatedPart . items ;
41
+ } else if ( updatedPart ?. items ?. properties ) {
42
+ updatedSchema . items = {
43
+ ...updatedSchema . items ,
44
+ properties : {
45
+ ...updatedSchema . items . properties ,
46
+ ...updatedPart . items . properties ,
47
+ } ,
48
+ } ;
49
+ } else if ( updatedPart . type !== 'object' ) {
50
+ updatedSchema = { ...schemaObject , ...updatedPart } ;
51
+ } else if ( Object . keys ( updatedPart . properties ) . length === 0 && updatedPart ?. required === undefined ) {
52
+ updatedSchema = { ...schemaObject , ...updatedPart } ;
53
+ } else {
54
+ updatedSchema . items = { ...updatedSchema . items , ...updatedPart } ;
55
+ }
56
+ } else {
57
+ updatedSchema = { ...schemaObject , ...updatedPart } ;
58
+ }
59
+
40
60
const newSchemaString = JSON . stringify ( updatedSchema ) ;
41
61
console . log ( 'Schema updated:' , newSchemaString ) ;
42
62
setSchemaObject ( updatedSchema ) ;
43
63
onSchemaChange ( newSchemaString ) ;
44
64
} ;
45
65
46
- const renderRootTypeSelector = ( ) => (
47
- < div >
48
- < select
49
- value = { schemaObject . type || '' }
50
- onChange = { ( e ) => handleSchemaChange ( { type : e . target . value } ) }
51
- style = { selectStyle }
52
- >
53
- < option value = "" > Select root type</ option >
54
- < option value = "object" > Object</ option >
55
- < option value = "array" > Array</ option >
56
- < option value = "string" > String</ option >
57
- < option value = "number" > Number</ option >
58
- < option value = "boolean" > Boolean</ option >
59
- </ select >
60
- </ div >
61
- ) ;
66
+ const handleRootTypeDropdownSelect = ( selectedOption : string ) => {
67
+ if ( selectedOption === 'array' ) {
68
+ handleSchemaChange ( { type : 'array' , items : { type : 'string' } , properties : undefined , required : undefined } ) ;
69
+ } else {
70
+ handleSchemaChange ( { type : selectedOption , properties : undefined , required : undefined } ) ;
71
+ }
72
+ } ;
73
+
74
+ const handleArrayItemTypeDropdownSelect = ( selectedOption : string ) => {
75
+ handleSchemaChange ( { items : schemaObject . items ? { ...schemaObject . items , type : selectedOption } : { type : selectedOption } } ) ;
76
+ } ;
77
+
78
+ const rootTypeOptions : DropdownMenuItem [ ] = [
79
+ { title : 'Select Root Type' , onSelect : ( ) => { } } ,
80
+ { type : 'separator' } ,
81
+ { type : 'regular' , title : 'Object' , onSelect : ( ) => handleRootTypeDropdownSelect ( 'object' ) } ,
82
+ { type : 'regular' , title : 'Array' , onSelect : ( ) => handleRootTypeDropdownSelect ( 'array' ) } ,
83
+ { type : 'regular' , title : 'String' , onSelect : ( ) => handleRootTypeDropdownSelect ( 'string' ) } ,
84
+ { type : 'regular' , title : 'Number' , onSelect : ( ) => handleRootTypeDropdownSelect ( 'number' ) } ,
85
+ { type : 'regular' , title : 'Boolean' , onSelect : ( ) => handleRootTypeDropdownSelect ( 'boolean' ) } ,
86
+ ] ;
87
+
88
+ const itemTypeOptions : DropdownMenuItem [ ] = [
89
+ { title : 'Select Items Type' , onSelect : ( ) => { } } ,
90
+ { type : 'separator' } ,
91
+ { type : 'regular' , title : 'String' , onSelect : ( ) => handleArrayItemTypeDropdownSelect ( 'string' ) } ,
92
+ { type : 'regular' , title : 'Number' , onSelect : ( ) => handleArrayItemTypeDropdownSelect ( 'number' ) } ,
93
+ { type : 'regular' , title : 'Boolean' , onSelect : ( ) => handleArrayItemTypeDropdownSelect ( 'boolean' ) } ,
94
+ { type : 'regular' , title : 'Object' , onSelect : ( ) => handleArrayItemTypeDropdownSelect ( 'object' ) } ,
95
+ ] ;
62
96
63
- const renderArrayItemTypeSelector = ( ) => {
64
- if ( schemaObject . type === 'array' ) {
97
+ const renderRootTypeDisplay = ( ) => {
98
+ if ( schemaObject . type === 'array' ) {
99
+ return null ;
100
+ }
101
+ const rootType = schemaObject . type || '' ;
102
+ const displayRootType = rootType . charAt ( 0 ) . toUpperCase ( ) + rootType . slice ( 1 ) ;
103
+ return (
104
+ < div className = "flex items-center" >
105
+ < span
106
+ style = { {
107
+ color : getColorForType ( rootType ) ,
108
+ borderRadius : '3px' ,
109
+ padding : '2px 4px' ,
110
+ fontSize : '14px' ,
111
+ fontFamily : 'Inter, Helvetica' ,
112
+ } }
113
+ >
114
+ { displayRootType }
115
+ </ span >
116
+ </ div >
117
+ ) ;
118
+ } ;
119
+
120
+ const renderArrayItemTypeDisplay = ( ) => {
121
+ if ( schemaObject . type === 'array' && schemaObject . items ) {
122
+ const itemType = schemaObject . items ?. type || '' ;
65
123
return (
66
- < div >
67
- < strong > Array Item Type:</ strong >
68
- < select
69
- value = { schemaObject . items ?. type || '' }
70
- onChange = { ( e ) => handleSchemaChange ( { items : { ...schemaObject . items , type : e . target . value } } ) }
71
- style = { selectStyle }
124
+ < div className = "flex items-center" >
125
+ < span
126
+ style = { {
127
+ color : getColorForType ( 'array' , itemType ) ,
128
+ borderRadius : '3px' ,
129
+ padding : '2px 4px' ,
130
+ fontSize : '14px' ,
131
+ fontFamily : 'Inter, Helvetica' ,
132
+ } }
72
133
>
73
- < option value = "" > Select item type</ option >
74
- < option value = "string" > String</ option >
75
- < option value = "number" > Number</ option >
76
- < option value = "boolean" > Boolean</ option >
77
- < option value = "object" > Object</ option >
78
- < option value = "array" > Array</ option >
79
- </ select >
134
+ { `Array<${ itemType } >` }
135
+ </ span >
80
136
</ div >
81
137
) ;
82
138
}
83
139
return null ;
84
140
} ;
85
141
86
142
return (
87
- < div className = "visual-editor" style = { { width : '45vw' , minWidth : '550px' , background : '#0F172A' , color : '#CBD5E1' , fontFamily : 'Inter, sans-serif' , padding : '20px' } } >
88
- { renderRootTypeSelector ( ) }
89
- { renderArrayItemTypeSelector ( ) }
90
-
91
- < SchemaObject
92
- schema = { schemaObject . type === 'array' ? schemaObject . items : schemaObject }
93
- onSchemaChange = { ( newSchema : any ) => handleSchemaChange ( newSchema ) }
94
- path = { schemaObject . type === 'array' ? 'items' : '' }
95
- level = { 0 }
96
- />
143
+ < div
144
+ className = "visual-editor"
145
+ style = { {
146
+ width : "45vw" ,
147
+ minWidth : "550px" ,
148
+ background : "#0F172A" ,
149
+ color : "#CBD5E1" ,
150
+ fontFamily : "Inter, sans-serif" ,
151
+ padding : "20px" ,
152
+ } }
153
+ >
154
+ < div className = "flex items-center gap-2" >
155
+ { renderRootTypeDisplay ( ) }
156
+ { renderArrayItemTypeDisplay ( ) }
157
+ < DropdownMenu
158
+ trigger = {
159
+ < button >
160
+ < IoIosArrowDropdown />
161
+ </ button >
162
+ }
163
+ items = { rootTypeOptions }
164
+ />
165
+ { schemaObject . type === "array" && (
166
+ < DropdownMenu
167
+ trigger = {
168
+ < button >
169
+ < IoIosArrowDropdown />
170
+ </ button >
171
+ }
172
+ items = { itemTypeOptions }
173
+ />
174
+ ) }
175
+ </ div >
176
+ { ( schemaObject . type === "object" || ( schemaObject . type === "array" && schemaObject . items . type === "object" ) ) && (
177
+ < SchemaObject
178
+ schema = {
179
+ schemaObject . type === "array" ? schemaObject . items : schemaObject
180
+ }
181
+ onSchemaChange = { ( newSchema : any ) => handleSchemaChange ( newSchema ) }
182
+ path = { schemaObject . type === "array" ? "items" : "" }
183
+ level = { 0 }
184
+ />
185
+ ) }
97
186
</ div >
98
187
) ;
99
188
} ;
0 commit comments