11import * as React from 'react' ;
2- import { Responsive , WidthProvider , Layout as RGLLayout } from 'react-grid-layout' ;
2+ import { ResponsiveGridLayout , useContainerWidth , type LayoutItem as RGLLayout , type Layout , type ResponsiveLayouts } from 'react-grid-layout' ;
33import 'react-grid-layout/css/styles.css' ;
44import { cn , Card , CardHeader , CardTitle , CardContent , Button } from '@object-ui/components' ;
55import { Edit , GripVertical , Save , X } from 'lucide-react' ;
66import { SchemaRenderer } from '@object-ui/react' ;
77import type { DashboardSchema , DashboardWidgetSchema } from '@object-ui/types' ;
88
9- const ResponsiveGridLayout = WidthProvider ( Responsive ) ;
10-
119const CHART_COLORS = [
1210 'hsl(var(--chart-1))' ,
1311 'hsl(var(--chart-2))' ,
@@ -29,6 +27,7 @@ export const DashboardGridLayout: React.FC<DashboardGridLayoutProps> = ({
2927 onLayoutChange,
3028 persistLayoutKey = 'dashboard-layout' ,
3129} ) => {
30+ const { width, containerRef, mounted } = useContainerWidth ( ) ;
3231 const [ editMode , setEditMode ] = React . useState ( false ) ;
3332 const [ layouts , setLayouts ] = React . useState < { lg : RGLLayout [ ] } > ( ( ) => {
3433 // Try to load saved layout
@@ -56,9 +55,9 @@ export const DashboardGridLayout: React.FC<DashboardGridLayoutProps> = ({
5655 } ) ;
5756
5857 const handleLayoutChange = React . useCallback (
59- ( layout : RGLLayout [ ] , allLayouts : { lg : RGLLayout [ ] } ) => {
60- setLayouts ( allLayouts ) ;
61- onLayoutChange ?.( layout ) ;
58+ ( layout : Layout , allLayouts : ResponsiveLayouts ) => {
59+ setLayouts ( allLayouts as { lg : RGLLayout [ ] } ) ;
60+ onLayoutChange ?.( layout as RGLLayout [ ] ) ;
6261 } ,
6362 [ onLayoutChange ]
6463 ) ;
@@ -122,7 +121,7 @@ export const DashboardGridLayout: React.FC<DashboardGridLayoutProps> = ({
122121 } , [ ] ) ;
123122
124123 return (
125- < div className = { cn ( "w-full" , className ) } data-testid = "grid-layout" >
124+ < div ref = { containerRef } className = { cn ( "w-full" , className ) } data-testid = "grid-layout" >
126125 < div className = "mb-4 flex items-center justify-between" >
127126 < h2 className = "text-2xl font-bold" > { schema . title || 'Dashboard' } </ h2 >
128127 < div className = "flex gap-2" >
@@ -149,62 +148,64 @@ export const DashboardGridLayout: React.FC<DashboardGridLayoutProps> = ({
149148 </ div >
150149 </ div >
151150
152- < ResponsiveGridLayout
153- className = "layout"
154- layouts = { layouts }
155- breakpoints = { { lg : 1200 , md : 996 , sm : 768 , xs : 480 , xxs : 0 } }
156- cols = { { lg : 12 , md : 10 , sm : 6 , xs : 4 , xxs : 2 } }
157- rowHeight = { 60 }
158- isDraggable = { editMode }
159- isResizable = { editMode }
160- onLayoutChange = { handleLayoutChange }
161- draggableHandle = ".drag-handle"
162- >
163- { schema . widgets ?. map ( ( widget , index ) => {
164- const widgetId = widget . id || `widget-${ index } ` ;
165- const componentSchema = getComponentSchema ( widget ) ;
166- const isSelfContained = ( widget as any ) . type === 'metric' ;
151+ { mounted && (
152+ < ResponsiveGridLayout
153+ className = "layout"
154+ width = { width }
155+ layouts = { layouts }
156+ breakpoints = { { lg : 1200 , md : 996 , sm : 768 , xs : 480 , xxs : 0 } }
157+ cols = { { lg : 12 , md : 10 , sm : 6 , xs : 4 , xxs : 2 } }
158+ rowHeight = { 60 }
159+ dragConfig = { { enabled : editMode , handle : ".drag-handle" } }
160+ resizeConfig = { { enabled : editMode } }
161+ onLayoutChange = { handleLayoutChange }
162+ >
163+ { schema . widgets ?. map ( ( widget , index ) => {
164+ const widgetId = widget . id || `widget-${ index } ` ;
165+ const componentSchema = getComponentSchema ( widget ) ;
166+ const isSelfContained = ( widget as any ) . type === 'metric' ;
167167
168- return (
169- < div key = { widgetId } className = "h-full" >
170- { isSelfContained ? (
171- < div className = "h-full w-full relative" >
172- { editMode && (
173- < div className = "drag-handle absolute top-2 right-2 z-10 cursor-move p-1 bg-background/80 rounded border border-border" >
174- < GripVertical className = "h-4 w-4" />
175- </ div >
176- ) }
177- < SchemaRenderer schema = { componentSchema } className = "h-full w-full" />
178- </ div >
179- ) : (
180- < Card className = { cn (
181- "h-full overflow-hidden border-border/50 shadow-sm transition-all" ,
182- "bg-card/50 backdrop-blur-sm" ,
183- editMode && "ring-2 ring-primary/20"
184- ) } >
185- { widget . title && (
186- < CardHeader className = "pb-2 border-b border-border/40 bg-muted/20 flex flex-row items-center justify-between" >
187- < CardTitle className = "text-base font-medium tracking-tight truncate" title = { widget . title } >
188- { widget . title }
189- </ CardTitle >
190- { editMode && (
191- < div className = "drag-handle cursor-move p-1 hover:bg-muted/40 rounded" >
192- < GripVertical className = "h-4 w-4" />
193- </ div >
194- ) }
195- </ CardHeader >
196- ) }
197- < CardContent className = "p-0 h-full" >
198- < div className = { cn ( "h-full w-full overflow-auto" , ! widget . title ? "p-4" : "p-4" ) } >
199- < SchemaRenderer schema = { componentSchema } />
200- </ div >
201- </ CardContent >
202- </ Card >
203- ) }
204- </ div >
205- ) ;
206- } ) }
207- </ ResponsiveGridLayout >
168+ return (
169+ < div key = { widgetId } className = "h-full" >
170+ { isSelfContained ? (
171+ < div className = "h-full w-full relative" >
172+ { editMode && (
173+ < div className = "drag-handle absolute top-2 right-2 z-10 cursor-move p-1 bg-background/80 rounded border border-border" >
174+ < GripVertical className = "h-4 w-4" />
175+ </ div >
176+ ) }
177+ < SchemaRenderer schema = { componentSchema } className = "h-full w-full" />
178+ </ div >
179+ ) : (
180+ < Card className = { cn (
181+ "h-full overflow-hidden border-border/50 shadow-sm transition-all" ,
182+ "bg-card/50 backdrop-blur-sm" ,
183+ editMode && "ring-2 ring-primary/20"
184+ ) } >
185+ { widget . title && (
186+ < CardHeader className = "pb-2 border-b border-border/40 bg-muted/20 flex flex-row items-center justify-between" >
187+ < CardTitle className = "text-base font-medium tracking-tight truncate" title = { widget . title } >
188+ { widget . title }
189+ </ CardTitle >
190+ { editMode && (
191+ < div className = "drag-handle cursor-move p-1 hover:bg-muted/40 rounded" >
192+ < GripVertical className = "h-4 w-4" />
193+ </ div >
194+ ) }
195+ </ CardHeader >
196+ ) }
197+ < CardContent className = "p-0 h-full" >
198+ < div className = { cn ( "h-full w-full overflow-auto p-4" ) } >
199+ < SchemaRenderer schema = { componentSchema } />
200+ </ div >
201+ </ CardContent >
202+ </ Card >
203+ ) }
204+ </ div >
205+ ) ;
206+ } ) }
207+ </ ResponsiveGridLayout >
208+ ) }
208209 </ div >
209210 ) ;
210211} ;
0 commit comments