react-resizable-panels 0.0.54 → 0.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +26 -0
- package/CHANGELOG.md +253 -80
- package/README.md +55 -49
- package/dist/declarations/src/Panel.d.ts +76 -20
- package/dist/declarations/src/PanelGroup.d.ts +29 -21
- package/dist/declarations/src/PanelResizeHandle.d.ts +1 -1
- package/dist/declarations/src/index.d.ts +5 -5
- package/dist/declarations/src/types.d.ts +3 -25
- package/dist/declarations/src/vendor/react.d.ts +4 -4
- package/dist/react-resizable-panels.browser.cjs.js +1279 -796
- package/dist/react-resizable-panels.browser.development.cjs.js +1404 -809
- package/dist/react-resizable-panels.browser.development.esm.js +1398 -803
- package/dist/react-resizable-panels.browser.esm.js +1279 -796
- package/dist/react-resizable-panels.cjs.js +1279 -796
- package/dist/react-resizable-panels.cjs.js.map +1 -0
- package/dist/react-resizable-panels.development.cjs.js +1399 -804
- package/dist/react-resizable-panels.development.esm.js +1400 -805
- package/dist/react-resizable-panels.development.node.cjs.js +1172 -755
- package/dist/react-resizable-panels.development.node.esm.js +1173 -756
- package/dist/react-resizable-panels.esm.js +1279 -796
- package/dist/react-resizable-panels.esm.js.map +1 -0
- package/dist/react-resizable-panels.node.cjs.js +1064 -749
- package/dist/react-resizable-panels.node.esm.js +1065 -750
- package/jest.config.js +10 -0
- package/package.json +3 -1
- package/src/Panel.test.tsx +308 -0
- package/src/Panel.ts +179 -127
- package/src/PanelGroup.test.tsx +210 -0
- package/src/PanelGroup.ts +751 -580
- package/src/PanelGroupContext.ts +33 -0
- package/src/PanelResizeHandle.ts +13 -8
- package/src/hooks/useUniqueId.ts +1 -1
- package/src/hooks/useWindowSplitterBehavior.ts +9 -161
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +185 -0
- package/src/index.ts +24 -11
- package/src/types.ts +3 -29
- package/src/utils/adjustLayoutByDelta.test.ts +1808 -0
- package/src/utils/adjustLayoutByDelta.ts +211 -0
- package/src/utils/calculateAriaValues.test.ts +111 -0
- package/src/utils/calculateAriaValues.ts +67 -0
- package/src/utils/calculateDeltaPercentage.ts +68 -0
- package/src/utils/calculateDragOffsetPercentage.ts +30 -0
- package/src/utils/calculateUnsafeDefaultLayout.test.ts +92 -0
- package/src/utils/calculateUnsafeDefaultLayout.ts +55 -0
- package/src/utils/callPanelCallbacks.ts +81 -0
- package/src/utils/compareLayouts.test.ts +9 -0
- package/src/utils/compareLayouts.ts +12 -0
- package/src/utils/computePanelFlexBoxStyle.ts +44 -0
- package/src/utils/computePercentagePanelConstraints.test.ts +71 -0
- package/src/utils/computePercentagePanelConstraints.ts +56 -0
- package/src/utils/convertPercentageToPixels.test.ts +9 -0
- package/src/utils/convertPercentageToPixels.ts +6 -0
- package/src/utils/convertPixelConstraintsToPercentages.ts +55 -0
- package/src/utils/convertPixelsToPercentage.test.ts +9 -0
- package/src/utils/convertPixelsToPercentage.ts +6 -0
- package/src/utils/determinePivotIndices.ts +10 -0
- package/src/utils/dom/calculateAvailablePanelSizeInPixels.ts +29 -0
- package/src/utils/dom/getAvailableGroupSizePixels.ts +29 -0
- package/src/utils/dom/getPanelElement.ts +7 -0
- package/src/utils/dom/getPanelGroupElement.ts +7 -0
- package/src/utils/dom/getResizeHandleElement.ts +9 -0
- package/src/utils/dom/getResizeHandleElementIndex.ts +12 -0
- package/src/utils/dom/getResizeHandleElementsForGroup.ts +9 -0
- package/src/utils/dom/getResizeHandlePanelIds.ts +18 -0
- package/src/utils/events.ts +13 -0
- package/src/utils/getPercentageSizeFromMixedSizes.test.ts +47 -0
- package/src/utils/getPercentageSizeFromMixedSizes.ts +15 -0
- package/src/utils/getResizeEventCursorPosition.ts +19 -0
- package/src/utils/initializeDefaultStorage.ts +26 -0
- package/src/utils/numbers/fuzzyCompareNumbers.test.ts +16 -0
- package/src/utils/numbers/fuzzyCompareNumbers.ts +17 -0
- package/src/utils/numbers/fuzzyNumbersEqual.ts +9 -0
- package/src/utils/resizePanel.ts +41 -0
- package/src/utils/serialization.ts +9 -4
- package/src/utils/shouldMonitorPixelBasedConstraints.test.ts +23 -0
- package/src/utils/shouldMonitorPixelBasedConstraints.ts +13 -0
- package/src/utils/test-utils.ts +136 -0
- package/src/utils/validatePanelConstraints.test.ts +151 -0
- package/src/utils/validatePanelConstraints.ts +103 -0
- package/src/utils/validatePanelGroupLayout.test.ts +233 -0
- package/src/utils/validatePanelGroupLayout.ts +88 -0
- package/src/vendor/react.ts +4 -0
- package/.eslintrc.json +0 -22
- package/src/PanelContexts.ts +0 -20
- package/src/utils/coordinates.ts +0 -149
- package/src/utils/group.ts +0 -315
package/src/Panel.ts
CHANGED
|
@@ -1,64 +1,100 @@
|
|
|
1
|
+
import { isBrowser } from "#is-browser";
|
|
2
|
+
import { isDevelopment } from "#is-development";
|
|
3
|
+
import { PanelGroupContext } from "./PanelGroupContext";
|
|
1
4
|
import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
|
|
2
5
|
import useUniqueId from "./hooks/useUniqueId";
|
|
6
|
+
import { MixedSizes } from "./types";
|
|
3
7
|
import {
|
|
4
|
-
createElement,
|
|
5
|
-
CSSProperties,
|
|
6
8
|
ElementType,
|
|
7
9
|
ForwardedRef,
|
|
10
|
+
PropsWithChildren,
|
|
11
|
+
createElement,
|
|
8
12
|
forwardRef,
|
|
9
|
-
ReactNode,
|
|
10
13
|
useContext,
|
|
11
|
-
useEffect,
|
|
12
14
|
useImperativeHandle,
|
|
13
15
|
useRef,
|
|
14
16
|
} from "./vendor/react";
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
18
|
+
export type PanelOnCollapse = () => void;
|
|
19
|
+
export type PanelOnExpand = () => void;
|
|
20
|
+
export type PanelOnResize = (
|
|
21
|
+
mixedSizes: MixedSizes,
|
|
22
|
+
prevMixedSizes: MixedSizes
|
|
23
|
+
) => void;
|
|
24
|
+
|
|
25
|
+
export type PanelCallbacks = {
|
|
26
|
+
onCollapse?: PanelOnCollapse;
|
|
27
|
+
onExpand?: PanelOnExpand;
|
|
28
|
+
onResize?: PanelOnResize;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type PanelConstraints = {
|
|
32
|
+
collapsedSizePercentage?: number | undefined;
|
|
33
|
+
collapsedSizePixels?: number | undefined;
|
|
34
|
+
collapsible?: boolean | undefined;
|
|
35
|
+
defaultSizePercentage?: number | undefined;
|
|
36
|
+
defaultSizePixels?: number | undefined;
|
|
37
|
+
maxSizePercentage?: number | undefined;
|
|
38
|
+
maxSizePixels?: number | undefined;
|
|
39
|
+
minSizePercentage?: number | undefined;
|
|
40
|
+
minSizePixels?: number | undefined;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type PanelData = {
|
|
44
|
+
callbacks: PanelCallbacks;
|
|
45
|
+
constraints: PanelConstraints;
|
|
46
|
+
id: string;
|
|
47
|
+
idIsFromProps: boolean;
|
|
48
|
+
order: number | undefined;
|
|
38
49
|
};
|
|
39
50
|
|
|
40
51
|
export type ImperativePanelHandle = {
|
|
41
52
|
collapse: () => void;
|
|
42
53
|
expand: () => void;
|
|
43
|
-
|
|
44
|
-
getSize():
|
|
45
|
-
resize: (
|
|
54
|
+
getId(): string;
|
|
55
|
+
getSize(): MixedSizes;
|
|
56
|
+
resize: (size: Partial<MixedSizes>) => void;
|
|
46
57
|
};
|
|
47
58
|
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
export type PanelProps = PropsWithChildren<{
|
|
60
|
+
className?: string;
|
|
61
|
+
collapsedSizePercentage?: number | undefined;
|
|
62
|
+
collapsedSizePixels?: number | undefined;
|
|
63
|
+
collapsible?: boolean | undefined;
|
|
64
|
+
defaultSizePercentage?: number | undefined;
|
|
65
|
+
defaultSizePixels?: number | undefined;
|
|
66
|
+
id?: string;
|
|
67
|
+
maxSizePercentage?: number | undefined;
|
|
68
|
+
maxSizePixels?: number | undefined;
|
|
69
|
+
minSizePercentage?: number | undefined;
|
|
70
|
+
minSizePixels?: number | undefined;
|
|
71
|
+
onCollapse?: PanelOnCollapse;
|
|
72
|
+
onExpand?: PanelOnExpand;
|
|
73
|
+
onResize?: PanelOnResize;
|
|
74
|
+
order?: number;
|
|
75
|
+
style?: object;
|
|
76
|
+
tagName?: ElementType;
|
|
77
|
+
}>;
|
|
78
|
+
|
|
79
|
+
export function PanelWithForwardedRef({
|
|
80
|
+
children,
|
|
50
81
|
className: classNameFromProps = "",
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
82
|
+
collapsedSizePercentage,
|
|
83
|
+
collapsedSizePixels,
|
|
84
|
+
collapsible,
|
|
85
|
+
defaultSizePercentage,
|
|
86
|
+
defaultSizePixels,
|
|
54
87
|
forwardedRef,
|
|
55
|
-
id: idFromProps
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
88
|
+
id: idFromProps,
|
|
89
|
+
maxSizePercentage,
|
|
90
|
+
maxSizePixels,
|
|
91
|
+
minSizePercentage,
|
|
92
|
+
minSizePixels,
|
|
93
|
+
onCollapse,
|
|
94
|
+
onExpand,
|
|
95
|
+
onResize,
|
|
96
|
+
order,
|
|
97
|
+
style: styleFromProps,
|
|
62
98
|
tagName: Type = "div",
|
|
63
99
|
}: PanelProps & {
|
|
64
100
|
forwardedRef: ForwardedRef<ImperativePanelHandle>;
|
|
@@ -70,126 +106,152 @@ function PanelWithForwardedRef({
|
|
|
70
106
|
);
|
|
71
107
|
}
|
|
72
108
|
|
|
73
|
-
const panelId = useUniqueId(idFromProps);
|
|
74
|
-
|
|
75
109
|
const {
|
|
76
110
|
collapsePanel,
|
|
77
111
|
expandPanel,
|
|
112
|
+
getPanelSize,
|
|
78
113
|
getPanelStyle,
|
|
114
|
+
isPanelCollapsed,
|
|
79
115
|
registerPanel,
|
|
80
116
|
resizePanel,
|
|
81
117
|
unregisterPanel,
|
|
82
118
|
} = context;
|
|
83
119
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
120
|
+
const panelId = useUniqueId(idFromProps);
|
|
121
|
+
|
|
122
|
+
const panelDataRef = useRef<PanelData>({
|
|
123
|
+
callbacks: {
|
|
124
|
+
onCollapse,
|
|
125
|
+
onExpand,
|
|
126
|
+
onResize,
|
|
127
|
+
},
|
|
128
|
+
constraints: {
|
|
129
|
+
collapsedSizePercentage,
|
|
130
|
+
collapsedSizePixels,
|
|
131
|
+
collapsible,
|
|
132
|
+
defaultSizePercentage,
|
|
133
|
+
defaultSizePixels,
|
|
134
|
+
maxSizePercentage,
|
|
135
|
+
maxSizePixels,
|
|
136
|
+
minSizePercentage,
|
|
137
|
+
minSizePixels,
|
|
138
|
+
},
|
|
139
|
+
id: panelId,
|
|
140
|
+
idIsFromProps: idFromProps !== undefined,
|
|
141
|
+
order,
|
|
92
142
|
});
|
|
93
143
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
} else {
|
|
100
|
-
if (defaultSize !== null) {
|
|
101
|
-
if (defaultSize < 0 || defaultSize > 100) {
|
|
102
|
-
throw Error(
|
|
103
|
-
`Panel defaultSize must be between 0 and 100, but was ${defaultSize}`
|
|
104
|
-
);
|
|
105
|
-
} else if (minSize > defaultSize && !collapsible) {
|
|
106
|
-
console.error(
|
|
107
|
-
`Panel minSize ${minSize} cannot be greater than defaultSize ${defaultSize}`
|
|
108
|
-
);
|
|
144
|
+
const devWarningsRef = useRef<{
|
|
145
|
+
didLogMissingDefaultSizeWarning: boolean;
|
|
146
|
+
}>({
|
|
147
|
+
didLogMissingDefaultSizeWarning: false,
|
|
148
|
+
});
|
|
109
149
|
|
|
110
|
-
|
|
150
|
+
// Normally we wouldn't log a warning during render,
|
|
151
|
+
// but effects don't run on the server, so we can't do it there
|
|
152
|
+
if (isDevelopment) {
|
|
153
|
+
if (!devWarningsRef.current.didLogMissingDefaultSizeWarning) {
|
|
154
|
+
if (
|
|
155
|
+
!isBrowser &&
|
|
156
|
+
defaultSizePercentage == null &&
|
|
157
|
+
defaultSizePixels == null
|
|
158
|
+
) {
|
|
159
|
+
devWarningsRef.current.didLogMissingDefaultSizeWarning = true;
|
|
160
|
+
console.warn(
|
|
161
|
+
`WARNING: Panel defaultSizePercentage or defaultSizePixels prop recommended to avoid layout shift after server rendering`
|
|
162
|
+
);
|
|
111
163
|
}
|
|
112
164
|
}
|
|
113
165
|
}
|
|
114
166
|
|
|
115
|
-
const style = getPanelStyle(panelId, defaultSize);
|
|
116
|
-
|
|
117
|
-
const committedValuesRef = useRef<{
|
|
118
|
-
size: number;
|
|
119
|
-
}>({
|
|
120
|
-
size: parseSizeFromStyle(style),
|
|
121
|
-
});
|
|
122
|
-
const panelDataRef = useRef<{
|
|
123
|
-
callbacksRef: PanelCallbackRef;
|
|
124
|
-
collapsedSize: number;
|
|
125
|
-
collapsible: boolean;
|
|
126
|
-
defaultSize: number | null;
|
|
127
|
-
id: string;
|
|
128
|
-
idWasAutoGenerated: boolean;
|
|
129
|
-
maxSize: number;
|
|
130
|
-
minSize: number;
|
|
131
|
-
order: number | null;
|
|
132
|
-
}>({
|
|
133
|
-
callbacksRef,
|
|
134
|
-
collapsedSize,
|
|
135
|
-
collapsible,
|
|
136
|
-
defaultSize,
|
|
137
|
-
id: panelId,
|
|
138
|
-
idWasAutoGenerated: idFromProps == null,
|
|
139
|
-
maxSize,
|
|
140
|
-
minSize,
|
|
141
|
-
order,
|
|
142
|
-
});
|
|
143
167
|
useIsomorphicLayoutEffect(() => {
|
|
144
|
-
|
|
168
|
+
const { callbacks, constraints } = panelDataRef.current;
|
|
145
169
|
|
|
146
|
-
panelDataRef.current.callbacksRef = callbacksRef;
|
|
147
|
-
panelDataRef.current.collapsedSize = collapsedSize;
|
|
148
|
-
panelDataRef.current.collapsible = collapsible;
|
|
149
|
-
panelDataRef.current.defaultSize = defaultSize;
|
|
150
170
|
panelDataRef.current.id = panelId;
|
|
151
|
-
panelDataRef.current.
|
|
152
|
-
panelDataRef.current.maxSize = maxSize;
|
|
153
|
-
panelDataRef.current.minSize = minSize;
|
|
171
|
+
panelDataRef.current.idIsFromProps = idFromProps !== undefined;
|
|
154
172
|
panelDataRef.current.order = order;
|
|
173
|
+
|
|
174
|
+
callbacks.onCollapse = onCollapse;
|
|
175
|
+
callbacks.onExpand = onExpand;
|
|
176
|
+
callbacks.onResize = onResize;
|
|
177
|
+
|
|
178
|
+
constraints.collapsedSizePercentage = collapsedSizePercentage;
|
|
179
|
+
constraints.collapsedSizePixels = collapsedSizePixels;
|
|
180
|
+
constraints.collapsible = collapsible;
|
|
181
|
+
constraints.defaultSizePercentage = defaultSizePercentage;
|
|
182
|
+
constraints.defaultSizePixels = defaultSizePixels;
|
|
183
|
+
constraints.maxSizePercentage = maxSizePercentage;
|
|
184
|
+
constraints.maxSizePixels = maxSizePixels;
|
|
185
|
+
constraints.minSizePercentage = minSizePercentage;
|
|
186
|
+
constraints.minSizePixels = minSizePixels;
|
|
155
187
|
});
|
|
156
188
|
|
|
157
189
|
useIsomorphicLayoutEffect(() => {
|
|
158
|
-
|
|
190
|
+
const panelData = panelDataRef.current;
|
|
191
|
+
|
|
192
|
+
registerPanel(panelData);
|
|
159
193
|
|
|
160
194
|
return () => {
|
|
161
|
-
unregisterPanel(
|
|
195
|
+
unregisterPanel(panelData);
|
|
162
196
|
};
|
|
163
197
|
}, [order, panelId, registerPanel, unregisterPanel]);
|
|
164
198
|
|
|
165
199
|
useImperativeHandle(
|
|
166
200
|
forwardedRef,
|
|
167
201
|
() => ({
|
|
168
|
-
collapse: () =>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
202
|
+
collapse: () => {
|
|
203
|
+
collapsePanel(panelDataRef.current);
|
|
204
|
+
},
|
|
205
|
+
expand: () => {
|
|
206
|
+
expandPanel(panelDataRef.current);
|
|
207
|
+
},
|
|
208
|
+
getId() {
|
|
209
|
+
return panelId;
|
|
172
210
|
},
|
|
173
211
|
getSize() {
|
|
174
|
-
return
|
|
212
|
+
return getPanelSize(panelDataRef.current);
|
|
213
|
+
},
|
|
214
|
+
isCollapsed() {
|
|
215
|
+
return isPanelCollapsed(panelDataRef.current);
|
|
216
|
+
},
|
|
217
|
+
isExpanded() {
|
|
218
|
+
return !isPanelCollapsed(panelDataRef.current);
|
|
219
|
+
},
|
|
220
|
+
resize: (mixedSizes: Partial<MixedSizes>) => {
|
|
221
|
+
resizePanel(panelDataRef.current, mixedSizes);
|
|
175
222
|
},
|
|
176
|
-
resize: (percentage: number) => resizePanel(panelId, percentage),
|
|
177
223
|
}),
|
|
178
|
-
[
|
|
224
|
+
[
|
|
225
|
+
collapsePanel,
|
|
226
|
+
expandPanel,
|
|
227
|
+
getPanelSize,
|
|
228
|
+
isPanelCollapsed,
|
|
229
|
+
panelId,
|
|
230
|
+
resizePanel,
|
|
231
|
+
]
|
|
179
232
|
);
|
|
180
233
|
|
|
234
|
+
const style = getPanelStyle(panelDataRef.current);
|
|
235
|
+
|
|
181
236
|
return createElement(Type, {
|
|
182
237
|
children,
|
|
183
238
|
className: classNameFromProps,
|
|
184
|
-
"data-panel": "",
|
|
185
|
-
"data-panel-collapsible": collapsible || undefined,
|
|
186
|
-
"data-panel-id": panelId,
|
|
187
|
-
"data-panel-size": parseFloat("" + style.flexGrow).toFixed(1),
|
|
188
|
-
id: `data-panel-id-${panelId}`,
|
|
189
239
|
style: {
|
|
190
240
|
...style,
|
|
191
241
|
...styleFromProps,
|
|
192
242
|
},
|
|
243
|
+
|
|
244
|
+
// CSS selectors
|
|
245
|
+
"data-panel": "",
|
|
246
|
+
|
|
247
|
+
// e2e test attributes
|
|
248
|
+
"data-panel-collapsible": isDevelopment
|
|
249
|
+
? collapsible || undefined
|
|
250
|
+
: undefined,
|
|
251
|
+
"data-panel-id": isDevelopment ? panelId : undefined,
|
|
252
|
+
"data-panel-size": isDevelopment
|
|
253
|
+
? parseFloat("" + style.flexGrow).toFixed(1)
|
|
254
|
+
: undefined,
|
|
193
255
|
});
|
|
194
256
|
}
|
|
195
257
|
|
|
@@ -200,13 +262,3 @@ export const Panel = forwardRef<ImperativePanelHandle, PanelProps>(
|
|
|
200
262
|
|
|
201
263
|
PanelWithForwardedRef.displayName = "Panel";
|
|
202
264
|
Panel.displayName = "forwardRef(Panel)";
|
|
203
|
-
|
|
204
|
-
// HACK
|
|
205
|
-
function parseSizeFromStyle(style: CSSProperties): number {
|
|
206
|
-
const { flexGrow } = style;
|
|
207
|
-
if (typeof flexGrow === "string") {
|
|
208
|
-
return parseFloat(flexGrow);
|
|
209
|
-
} else {
|
|
210
|
-
return flexGrow as number;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { Root, createRoot } from "react-dom/client";
|
|
2
|
+
import { act } from "react-dom/test-utils";
|
|
3
|
+
import {
|
|
4
|
+
ImperativePanelGroupHandle,
|
|
5
|
+
MixedSizes,
|
|
6
|
+
Panel,
|
|
7
|
+
PanelGroup,
|
|
8
|
+
PanelResizeHandle,
|
|
9
|
+
} from ".";
|
|
10
|
+
import { mockPanelGroupOffsetWidthAndHeight } from "./utils/test-utils";
|
|
11
|
+
import { createRef } from "./vendor/react";
|
|
12
|
+
|
|
13
|
+
describe("PanelGroup", () => {
|
|
14
|
+
let expectedWarnings: string[] = [];
|
|
15
|
+
let root: Root;
|
|
16
|
+
let uninstallMockOffsetWidthAndHeight: () => void;
|
|
17
|
+
|
|
18
|
+
function expectWarning(expectedMessage: string) {
|
|
19
|
+
expectedWarnings.push(expectedMessage);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
// @ts-expect-error
|
|
24
|
+
global.IS_REACT_ACT_ENVIRONMENT = true;
|
|
25
|
+
|
|
26
|
+
// JSDom doesn't support element sizes
|
|
27
|
+
uninstallMockOffsetWidthAndHeight = mockPanelGroupOffsetWidthAndHeight();
|
|
28
|
+
|
|
29
|
+
const container = document.createElement("div");
|
|
30
|
+
document.body.appendChild(container);
|
|
31
|
+
|
|
32
|
+
expectedWarnings = [];
|
|
33
|
+
root = createRoot(container);
|
|
34
|
+
|
|
35
|
+
jest.spyOn(console, "warn").mockImplementation((actualMessage: string) => {
|
|
36
|
+
const match = expectedWarnings.findIndex((expectedMessage) => {
|
|
37
|
+
return actualMessage.includes(expectedMessage);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (match >= 0) {
|
|
41
|
+
expectedWarnings.splice(match, 1);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw Error(`Unexpected warning: ${actualMessage}`);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
uninstallMockOffsetWidthAndHeight();
|
|
51
|
+
|
|
52
|
+
jest.clearAllMocks();
|
|
53
|
+
jest.resetModules();
|
|
54
|
+
|
|
55
|
+
act(() => {
|
|
56
|
+
root.unmount();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(expectedWarnings).toHaveLength(0);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("imperative handle API", () => {
|
|
63
|
+
it("should report the most recently rendered group id", () => {
|
|
64
|
+
const ref = createRef<ImperativePanelGroupHandle>();
|
|
65
|
+
|
|
66
|
+
act(() => {
|
|
67
|
+
root.render(<PanelGroup direction="horizontal" id="one" ref={ref} />);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(ref.current!.getId()).toBe("one");
|
|
71
|
+
|
|
72
|
+
act(() => {
|
|
73
|
+
root.render(<PanelGroup direction="horizontal" id="two" ref={ref} />);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(ref.current!.getId()).toBe("two");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should get and set layouts", () => {
|
|
80
|
+
const ref = createRef<ImperativePanelGroupHandle>();
|
|
81
|
+
|
|
82
|
+
let mostRecentLayout: MixedSizes[] | null = null;
|
|
83
|
+
|
|
84
|
+
const onLayout = (layout: MixedSizes[]) => {
|
|
85
|
+
mostRecentLayout = layout;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
act(() => {
|
|
89
|
+
root.render(
|
|
90
|
+
<PanelGroup direction="horizontal" onLayout={onLayout} ref={ref}>
|
|
91
|
+
<Panel defaultSizePercentage={50} id="a" />
|
|
92
|
+
<PanelResizeHandle />
|
|
93
|
+
<Panel defaultSizePercentage={50} id="b" />
|
|
94
|
+
</PanelGroup>
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(mostRecentLayout).toEqual([
|
|
99
|
+
{
|
|
100
|
+
sizePercentage: 50,
|
|
101
|
+
sizePixels: 500,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
sizePercentage: 50,
|
|
105
|
+
sizePixels: 500,
|
|
106
|
+
},
|
|
107
|
+
]);
|
|
108
|
+
|
|
109
|
+
act(() => {
|
|
110
|
+
ref.current!.setLayout([
|
|
111
|
+
{ sizePercentage: 25 },
|
|
112
|
+
{ sizePercentage: 75 },
|
|
113
|
+
]);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
expect(mostRecentLayout).toEqual([
|
|
117
|
+
{
|
|
118
|
+
sizePercentage: 25,
|
|
119
|
+
sizePixels: 250,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
sizePercentage: 75,
|
|
123
|
+
sizePixels: 750,
|
|
124
|
+
},
|
|
125
|
+
]);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("DEV warnings", () => {
|
|
130
|
+
it("should warn about unstable layouts without id and order props", () => {
|
|
131
|
+
act(() => {
|
|
132
|
+
root.render(
|
|
133
|
+
<PanelGroup direction="horizontal">
|
|
134
|
+
<Panel defaultSizePercentage={100} id="a" />
|
|
135
|
+
</PanelGroup>
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
expectWarning(
|
|
140
|
+
"Panel id and order props recommended when panels are dynamically rendered"
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
act(() => {
|
|
144
|
+
root.render(
|
|
145
|
+
<PanelGroup direction="horizontal">
|
|
146
|
+
<Panel defaultSizePercentage={50} id="a" />
|
|
147
|
+
<PanelResizeHandle />
|
|
148
|
+
<Panel defaultSizePercentage={50} id="b" />
|
|
149
|
+
</PanelGroup>
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should warn about missing resize handles", () => {
|
|
155
|
+
expectWarning(
|
|
156
|
+
'Missing resize handle for PanelGroup "group-without-handle"'
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
act(() => {
|
|
160
|
+
root.render(
|
|
161
|
+
<PanelGroup direction="horizontal" id="group-without-handle">
|
|
162
|
+
<Panel />
|
|
163
|
+
<Panel />
|
|
164
|
+
</PanelGroup>
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should warn about an invalid declarative layout", () => {
|
|
170
|
+
expectWarning("Invalid layout total size: 60%, 80%");
|
|
171
|
+
|
|
172
|
+
act(() => {
|
|
173
|
+
root.render(
|
|
174
|
+
<PanelGroup direction="horizontal" id="group-without-handle">
|
|
175
|
+
<Panel defaultSizePercentage={60} />
|
|
176
|
+
<PanelResizeHandle />
|
|
177
|
+
<Panel defaultSizePercentage={80} />
|
|
178
|
+
</PanelGroup>
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should warn about an invalid layout set via the imperative api", () => {
|
|
184
|
+
const ref = createRef<ImperativePanelGroupHandle>();
|
|
185
|
+
|
|
186
|
+
act(() => {
|
|
187
|
+
root.render(
|
|
188
|
+
<PanelGroup
|
|
189
|
+
direction="horizontal"
|
|
190
|
+
id="group-without-handle"
|
|
191
|
+
ref={ref}
|
|
192
|
+
>
|
|
193
|
+
<Panel defaultSizePercentage={30} />
|
|
194
|
+
<PanelResizeHandle />
|
|
195
|
+
<Panel defaultSizePercentage={70} />
|
|
196
|
+
</PanelGroup>
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
expectWarning("Invalid layout total size: 60%, 80%");
|
|
201
|
+
|
|
202
|
+
act(() => {
|
|
203
|
+
ref.current!.setLayout([
|
|
204
|
+
{ sizePercentage: 60 },
|
|
205
|
+
{ sizePercentage: 80 },
|
|
206
|
+
]);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|