(template);
// Sync external template changes to internal state
@@ -115,20 +118,19 @@ const GridLayout = ({
setInternalTemplate(template);
}, [template]);
- const droppingItemTemplate: ReactGridLayoutProps['droppingItem'] = useMemo(() => {
- if (currentDropInItem && isWidgetType(widgetMapping, currentDropInItem)) {
- const widget = widgetMapping[currentDropInItem];
+ const droppingItemTemplate = useMemo(() => {
+ if (droppingWidgetType && isWidgetType(widgetMapping, droppingWidgetType)) {
+ const widget = widgetMapping[droppingWidgetType];
if (!widget) {return undefined;}
return {
...widget.defaults,
i: droppingElemId,
- widgetType: currentDropInItem,
- title: 'New title',
- config: createSerializableConfig(widget.config)
+ x: 0,
+ y: 0,
};
}
return undefined;
- }, [currentDropInItem, widgetMapping]);
+ }, [droppingWidgetType, widgetMapping]);
const setWidgetAttribute: SetWidgetAttribute = (id, attributeName, value) => {
const newTemplate = Object.entries(internalTemplate).reduce(
@@ -154,10 +156,11 @@ const GridLayout = ({
onTemplateChange?.(newTemplate);
};
- const onDrop: ReactGridLayoutProps['onDrop'] = (_layout: ExtendedLayoutItem[], layoutItem: ExtendedLayoutItem, event: DragEvent) => {
- const data = event.dataTransfer?.getData('text') || '';
+ const onDrop = (_layout: readonly LayoutItem[], layoutItem: LayoutItem | undefined, event: Event) => {
+ if (!layoutItem) { return; }
+ const dragEvent = event as DragEvent;
+ const data = dragEvent.dataTransfer?.getData('text') || '';
if (isWidgetType(widgetMapping, data)) {
- setCurrentDropInItem(undefined);
const widget = widgetMapping[data];
if (!widget) {return;}
const newTemplate = Object.entries(internalTemplate).reduce((acc, [size, layout]) => {
@@ -193,21 +196,22 @@ const GridLayout = ({
onTemplateChange?.(newTemplate);
analytics?.('widget-layout.widget-add', { data });
}
- event.preventDefault();
+ dragEvent.preventDefault();
};
- const onLayoutChange = (currentLayout: Layout[]) => {
+ const onLayoutChange = (currentLayout: readonly LayoutItem[]) => {
if (isInitialRender) {
setIsInitialRender(false);
const activeWidgets = activeLayout.map((item) => item.widgetType);
onActiveWidgetsChange?.(activeWidgets);
return;
}
- if (isLayoutLocked || currentDropInItem) {
+ if (isLayoutLocked || droppingWidgetType) {
return;
}
- const newTemplate = extendLayout({ ...internalTemplate, [layoutVariant]: currentLayout });
+ // Create mutable copy of readonly layout for extendLayout
+ const newTemplate = extendLayout({ ...internalTemplate, [layoutVariant]: [...currentLayout] });
const activeWidgets = activeLayout.map((item) => item.widgetType);
onActiveWidgetsChange?.(activeWidgets);
@@ -215,54 +219,47 @@ const GridLayout = ({
onTemplateChange?.(newTemplate);
};
+ // Update layout variant when container width changes
useEffect(() => {
- const currentWidth = layoutRef.current?.getBoundingClientRect().width ?? 1200;
- const variant: Variants = getGridDimensions(currentWidth);
- setLayoutVariant(variant);
- setLayoutWidth(currentWidth);
-
- const observer = new ResizeObserver((entries) => {
- if (!entries[0]) {return;}
-
- const currentWidth = entries[0].contentRect.width;
- const variant: Variants = getGridDimensions(currentWidth);
+ if (mounted && layoutWidth > 0) {
+ const variant: Variants = getGridDimensions(layoutWidth);
setLayoutVariant(variant);
- setLayoutWidth(currentWidth);
- });
-
- if (layoutRef.current) {
- observer.observe(layoutRef.current);
}
-
- return () => {
- observer.disconnect();
- };
- }, []);
+ }, [layoutWidth, mounted]);
const activeLayout = internalTemplate[layoutVariant] || [];
+ // Use default width before mount, actual width after
+ const effectiveWidth = mounted && layoutWidth > 0 ? layoutWidth : 1200;
+
return (
-