forked from gridstack/gridstack.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgrid-stack-render-provider.tsx
More file actions
109 lines (100 loc) · 3.65 KB
/
grid-stack-render-provider.tsx
File metadata and controls
109 lines (100 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import {
PropsWithChildren,
useCallback,
useLayoutEffect,
useMemo,
useRef,
} from "react";
import { useGridStackContext } from "./grid-stack-context";
import { GridStack, GridStackOptions, GridStackWidget } from "gridstack";
import { GridStackRenderContext } from "./grid-stack-render-context";
import isEqual from "react-fast-compare";
// WeakMap to store widget containers for each grid instance
export const gridWidgetContainersMap = new WeakMap<GridStack, Map<string, HTMLElement>>();
export function GridStackRenderProvider({ children }: PropsWithChildren) {
const {
_gridStack: { value: gridStack, set: setGridStack },
initialOptions,
} = useGridStackContext();
const widgetContainersRef = useRef<Map<string, HTMLElement>>(new Map());
const containerRef = useRef<HTMLDivElement>(null);
const optionsRef = useRef<GridStackOptions>(initialOptions);
const renderCBFn = useCallback(
(element: HTMLElement, widget: GridStackWidget & { grid?: GridStack }) => {
if (widget.id && widget.grid) {
// Get or create the widget container map for this grid instance
let containers = gridWidgetContainersMap.get(widget.grid);
if (!containers) {
containers = new Map<string, HTMLElement>();
gridWidgetContainersMap.set(widget.grid, containers);
}
containers.set(widget.id, element);
// Also update the local ref for backward compatibility
widgetContainersRef.current.set(widget.id, element);
}
},
[]
);
const initGrid = useCallback(() => {
if (containerRef.current) {
GridStack.renderCB = renderCBFn;
return GridStack.init(optionsRef.current, containerRef.current);
// ! Change event not firing on nested grids (resize, move...) https://github.com/gridstack/gridstack.js/issues/2671
// .on("change", () => {
// console.log("changed");
// })
// .on("resize", () => {
// console.log("resize");
// })
}
return null;
}, [renderCBFn]);
useLayoutEffect(() => {
if (!isEqual(initialOptions, optionsRef.current) && gridStack) {
try {
gridStack.removeAll(false);
gridStack.destroy(false);
widgetContainersRef.current.clear();
// Clean up the WeakMap entry for this grid instance
gridWidgetContainersMap.delete(gridStack);
optionsRef.current = initialOptions;
setGridStack(initGrid());
} catch (e) {
console.error("Error reinitializing gridstack", e);
}
}
}, [initialOptions, gridStack, initGrid, setGridStack]);
useLayoutEffect(() => {
if (!gridStack) {
try {
setGridStack(initGrid());
} catch (e) {
console.error("Error initializing gridstack", e);
}
}
}, [gridStack, initGrid, setGridStack]);
return (
<GridStackRenderContext.Provider
value={useMemo(
() => ({
getWidgetContainer: (widgetId: string) => {
// First try to get from the current grid instance's map
if (gridStack) {
const containers = gridWidgetContainersMap.get(gridStack);
if (containers?.has(widgetId)) {
return containers.get(widgetId) || null;
}
}
// Fallback to local ref for backward compatibility
return widgetContainersRef.current.get(widgetId) || null;
},
}),
// ! gridStack is required to reinitialize the grid when the options change
// eslint-disable-next-line react-hooks/exhaustive-deps
[gridStack]
)}
>
<div ref={containerRef}>{gridStack ? children : null}</div>
</GridStackRenderContext.Provider>
);
}