11import React , { useEffect , useRef , useState } from "react" ;
2- import { Row , Col } from "antd" ;
3- import {
4- ObjectFieldTemplateProps ,
5- getTemplate ,
6- getUiOptions ,
7- descriptionId ,
8- titleId ,
9- canExpand ,
10- } from "@rjsf/utils" ;
11- import { ConfigConsumer } from "antd/es/config-provider/context" ;
2+ import { Row , Col } from 'antd' ;
3+ import { ObjectFieldTemplateProps , getTemplate , getUiOptions , descriptionId , titleId , canExpand } from '@rjsf/utils' ;
4+ import { ConfigConsumer } from 'antd/es/config-provider/context' ;
5+ import { useContainerWidth } from "./jsonSchemaFormComp" ;
6+ import styled from "styled-components" ;
127
138const DESCRIPTION_COL_STYLE = {
14- paddingBottom : " 8px" ,
9+ paddingBottom : ' 8px' ,
1510} ;
1611
17- interface ColSpan {
18- xs : number ;
19- sm : number ;
20- md : number ;
21- lg : number ;
22- xl : number ;
23- }
24-
25- interface UiOptions {
26- colSpan : ColSpan ;
27- rowGutter : number ;
28- // other properties...
29- }
30-
3112const ObjectFieldTemplate = ( props : ObjectFieldTemplateProps ) => {
3213 const {
3314 title,
@@ -42,59 +23,62 @@ const ObjectFieldTemplate = (props: ObjectFieldTemplateProps) => {
4223 readonly,
4324 registry,
4425 } = props ;
45-
46- const containerRef = useRef < HTMLDivElement > ( null ) ;
47- const [ containerWidth , setContainerWidth ] = useState ( 0 ) ;
48-
49- // Monitor the container's width
50- useEffect ( ( ) => {
51- const updateWidth = ( ) => {
52- if ( containerRef . current ) {
53- setContainerWidth ( containerRef . current . offsetWidth ) ;
54- }
55- } ;
56-
57- // Create a ResizeObserver to watch for width changes
58- const resizeObserver = new ResizeObserver ( ( ) => {
59- updateWidth ( ) ;
60- } ) ;
61-
62- if ( containerRef . current ) {
63- resizeObserver . observe ( containerRef . current ) ;
64- }
65-
66- // Initial update
67- updateWidth ( ) ;
68-
69- // Cleanup observer on unmount
70- return ( ) => {
71- resizeObserver . disconnect ( ) ;
72- } ;
73- } , [ ] ) ;
26+ const containerWidth = useContainerWidth ( ) ;
7427
7528 const uiOptions = getUiOptions ( uiSchema ) ;
76- const TitleFieldTemplate = getTemplate ( " TitleFieldTemplate" , registry , uiOptions ) ;
77- const DescriptionFieldTemplate = getTemplate ( " DescriptionFieldTemplate" , registry , uiOptions ) ;
29+ const TitleFieldTemplate = getTemplate ( ' TitleFieldTemplate' , registry , uiOptions ) ;
30+ const DescriptionFieldTemplate = getTemplate ( ' DescriptionFieldTemplate' , registry , uiOptions ) ;
7831 const {
7932 ButtonTemplates : { AddButton } ,
8033 } = registry . templates ;
8134
82- const defaultResponsiveColSpan = ( width : number ) => {
83- if ( width > 1200 ) return 8 ; // Wide screens
84- if ( width > 768 ) return 12 ; // Tablets
85- return 24 ; // Mobile
35+ // Define responsive column spans based on the ui:props or fallback to defaults
36+ const defaultResponsiveColSpan = {
37+ xs : 24 , // Extra small devices
38+ sm : 24 , // Small devices
39+ md : 12 , // Medium devices
40+ lg : 12 , // Large devices
41+ xl : 8 , // Extra large devices
8642 } ;
8743
88- const { rowGutter = 4 } = uiSchema ?. [ "ui:props" ] || { } ;
89-
90- const calculateResponsiveColSpan = ( element : any ) : { span : number } => {
44+ const { rowGutter = 4 } = uiSchema ?. [ 'ui:props' ] || { } ;
45+
46+ const calculateResponsiveColSpan = ( element : any , level : number ) : { span : number } => {
47+
48+ console . log ( "Calculating span for" , element . name , "at level" , level ) ;
49+
50+ // root level
51+ if ( level === 0 ) return { span : 24 } ;
52+
53+ // Check if the element has a layout definition in ui:grid
54+ const gridColSpan = uiSchema ?. [ 'ui:grid' ]
55+ ?. find ( ( row : Record < string , any > ) => row [ element . name ] )
56+ ?. [ element . name ] ;
57+
58+ if ( gridColSpan ) {
59+ if ( typeof gridColSpan === "number" ) {
60+ return { span : gridColSpan } ;
61+ } else if ( typeof gridColSpan === "object" ) {
62+ if ( containerWidth > 1200 && gridColSpan . xl !== undefined ) {
63+ return { span : gridColSpan . xl } ;
64+ } else if ( containerWidth > 992 && gridColSpan . lg !== undefined ) {
65+ return { span : gridColSpan . lg } ;
66+ } else if ( containerWidth > 768 && gridColSpan . md !== undefined ) {
67+ return { span : gridColSpan . md } ;
68+ } else if ( containerWidth > 576 && gridColSpan . sm !== undefined ) {
69+ return { span : gridColSpan . sm } ;
70+ } else if ( gridColSpan . xs !== undefined ) {
71+ return { span : gridColSpan . xs } ;
72+ }
73+ }
74+ }
9175
76+ // Fallback to default colSpan or ui:props.colSpan
9277 const uiSchemaProps = getUiOptions ( element . content . props . uiSchema ) ?. [ "ui:props" ] as
9378 | { colSpan ?: Record < string , number > | number }
9479 | undefined ;
9580
9681 const uiSchemaColSpan = uiSchemaProps ?. colSpan ;
97- const defaultSpan = containerWidth > 1200 ? 8 : containerWidth > 768 ? 12 : 24 ;
9882
9983 if ( uiSchemaColSpan ) {
10084 if ( typeof uiSchemaColSpan === "number" ) {
@@ -114,133 +98,94 @@ const ObjectFieldTemplate = (props: ObjectFieldTemplateProps) => {
11498 }
11599 }
116100
101+ // Default responsive behavior
102+ const defaultSpan = containerWidth > 1200 ? 8 : containerWidth > 768 ? 12 : 24 ;
117103 return { span : defaultSpan } ;
118104 } ;
119105
120- const renderSectionLayout = ( properties : any [ ] , uiGrid : any , section : string ) => {
121-
122- if ( uiGrid && Array . isArray ( uiGrid ) ) {
123- return (
124- < Row gutter = { rowGutter } key = { section } >
125- { uiGrid . map ( ( ui_row : Record < string , any > ) =>
126- Object . keys ( ui_row ) . map ( ( row_item ) => {
127- const element = properties . find ( ( p ) => p . name === row_item ) ;
128- if ( element ) {
129- const span = calculateResponsiveColSpan ( element ) . span ;
130- return (
131- < Col key = { element . name } span = { span } >
132- { element . content }
133- </ Col >
134- ) ;
135- }
136- return null ;
137- } )
138- ) }
139- </ Row >
140- ) ;
141- }
142-
143- // Default layout if no grid is provided
106+ const renderProperties = ( properties : any [ ] , level : number ) => {
107+ console . log ( "Rendering level:" , level ) ; // Debugging level
144108 return (
145- < Row gutter = { rowGutter } key = { section } >
146- { properties . map ( ( element ) => (
147- < Col key = { element . name } { ...calculateResponsiveColSpan ( element ) } >
148- { element . content }
149- </ Col >
150- ) ) }
109+ < Row
110+ gutter = { rowGutter }
111+ style = { level === 0 ? { width : "100%" } : { marginLeft : - 8 , marginRight : - 8 } }
112+ >
113+ { properties . map ( ( element ) => {
114+ const span = calculateResponsiveColSpan ( element , level ) ;
115+
116+ // Check if the element is an object or array and has nested properties
117+ if ( element . content ?. props ?. schema ?. type === "object" && element . content . props . properties ) {
118+ // Render nested objects with an incremented level
119+ return (
120+ < Col key = { element . name } span = { 24 } >
121+ < fieldset >
122+ < legend > { element . content . props . title || element . name } </ legend >
123+ { renderProperties ( element . content . props . properties , level + 1 ) }
124+ </ fieldset >
125+ </ Col >
126+ ) ;
127+ }
128+
129+ // Render normal elements
130+ return (
131+ < Col key = { element . name } span = { span . span } >
132+ { element . content }
133+ </ Col >
134+ ) ;
135+ } ) }
151136 </ Row >
152137 ) ;
153138 } ;
154-
155- const renderCustomLayout = ( ) => {
156- const schemaType = schema . type as string ;
157- switch ( schemaType ) {
158- case "Group" :
159- return (
160- < div style = { { border : "1px solid #ccc" , padding : "15px" , marginBottom : "10px" } } >
161- < h3 > { schema . label || "Group" } </ h3 >
162- { renderSectionLayout ( properties , uiSchema ?. [ "ui:grid" ] , schema . label ) }
163- </ div >
164- ) ;
165- case "HorizontalLayout" :
166- return (
167- < Row gutter = { rowGutter } style = { { display : "flex" , gap : "10px" } } >
168- { properties . map ( ( element ) => (
169- < Col key = { element . name } { ...calculateResponsiveColSpan ( element ) } >
170- { element . content }
171- </ Col >
172- ) ) }
173- </ Row >
174- ) ;
175- case "VerticalLayout" :
176- return (
177- < div style = { { display : "flex" , flexDirection : "column" , gap : "10px" } } >
178- { properties . map ( ( element ) => (
179- < div key = { element . name } > { element . content } </ div >
180- ) ) }
181- </ div >
182- ) ;
183- default :
184- return null ; // Fall back to default rendering if no match
185- }
186- } ;
187-
188- // Check if the schema is a custom layout type
189- const schemaType = schema . type as string ; // Extract schema type safely
190- const isCustomLayout = [ "Group" , "HorizontalLayout" , "VerticalLayout" ] . includes ( schemaType ) ;
191-
139+
192140 return (
193- < div ref = { containerRef } >
194- < ConfigConsumer >
195- { ( configProps ) => (
196- < fieldset id = { idSchema . $id } className = "form-section" >
197- { ! isCustomLayout && (
198- < >
199- { schema . type === "object" && title && (
200- < legend >
201- < TitleFieldTemplate
202- id = { titleId ( idSchema ) }
203- title = { title }
204- required = { props . required }
205- schema = { schema }
206- uiSchema = { uiSchema }
207- registry = { registry }
208- />
209- </ legend >
210- ) }
211- { description && (
212- < Col span = { 24 } style = { DESCRIPTION_COL_STYLE } >
213- < DescriptionFieldTemplate
214- id = { descriptionId ( idSchema ) }
215- description = { description }
216- schema = { schema }
217- uiSchema = { uiSchema }
218- registry = { registry }
219- />
220- </ Col >
221- ) }
222- { renderSectionLayout ( properties , uiSchema ?. [ "ui:grid" ] , "root" ) }
223- </ >
224- ) }
225-
226- { isCustomLayout && renderCustomLayout ( ) }
227-
228- { canExpand ( schema , uiSchema , formData ) && (
229- < Row justify = "end" style = { { marginTop : "24px" } } >
230- < Col >
231- < AddButton
232- className = "object-property-expand"
233- onClick = { onAddClick ( schema ) }
234- disabled = { disabled || readonly }
235- registry = { registry }
236- />
237- </ Col >
238- </ Row >
239- ) }
240- </ fieldset >
241- ) }
242- </ ConfigConsumer >
243- </ div >
141+ < ConfigConsumer >
142+ { ( configProps ) => (
143+ < fieldset id = { idSchema . $id } className = "form-section" >
144+ { /* Render Title */ }
145+ { schema . type === "object" && title && (
146+ < legend >
147+ < TitleFieldTemplate
148+ id = { titleId ( idSchema ) }
149+ title = { title }
150+ required = { props . required }
151+ schema = { schema }
152+ uiSchema = { uiSchema }
153+ registry = { registry }
154+ />
155+ </ legend >
156+ ) }
157+ { /* Render Description */ }
158+ { description && (
159+ < Row >
160+ < Col span = { 24 } style = { DESCRIPTION_COL_STYLE } >
161+ < DescriptionFieldTemplate
162+ id = { descriptionId ( idSchema ) }
163+ description = { description }
164+ schema = { schema }
165+ uiSchema = { uiSchema }
166+ registry = { registry }
167+ />
168+ </ Col >
169+ </ Row >
170+ ) }
171+ { /* Render Properties */ }
172+ { renderProperties ( properties , 0 ) }
173+ { /* Expand Button */ }
174+ { canExpand ( schema , uiSchema , formData ) && (
175+ < Row justify = "end" style = { { width : "100%" , marginTop : "24px" } } >
176+ < Col >
177+ < AddButton
178+ className = "object-property-expand"
179+ onClick = { onAddClick ( schema ) }
180+ disabled = { disabled || readonly }
181+ registry = { registry }
182+ />
183+ </ Col >
184+ </ Row >
185+ ) }
186+ </ fieldset >
187+ ) }
188+ </ ConfigConsumer >
244189 ) ;
245190} ;
246191
0 commit comments