react-resizable-panels 0.0.43 → 0.0.45
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/CHANGELOG.md +8 -0
- package/dist/react-resizable-panels.d.ts.map +1 -1
- package/dist/react-resizable-panels.js +89 -73
- package/dist/react-resizable-panels.js.map +1 -1
- package/dist/react-resizable-panels.module.js +89 -73
- package/dist/react-resizable-panels.module.js.map +1 -1
- package/package.json +1 -1
- package/src/Panel.ts +41 -30
- package/src/PanelContexts.ts +1 -1
- package/src/PanelGroup.ts +31 -15
- package/src/hooks/useWindowSplitterBehavior.ts +7 -7
- package/src/types.ts +14 -10
- package/src/utils/coordinates.ts +5 -5
- package/src/utils/group.ts +20 -18
- package/src/utils/serialization.ts +1 -1
- package/src/utils/ssr.ts +7 -0
package/src/PanelGroup.ts
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
panelsMapToSortedArray,
|
|
46
46
|
} from "./utils/group";
|
|
47
47
|
import { loadPanelLayout, savePanelGroupLayout } from "./utils/serialization";
|
|
48
|
+
import { isServerRendering } from "./utils/ssr";
|
|
48
49
|
|
|
49
50
|
const debounceMap: {
|
|
50
51
|
[key: string]: (
|
|
@@ -260,12 +261,12 @@ function PanelGroupWithForwardedRef({
|
|
|
260
261
|
// For now, these logic edge cases are left to the user to handle via props.
|
|
261
262
|
|
|
262
263
|
panelsArray.forEach((panel) => {
|
|
263
|
-
totalMinSize += panel.minSize;
|
|
264
|
+
totalMinSize += panel.current.minSize;
|
|
264
265
|
|
|
265
|
-
if (panel.defaultSize === null) {
|
|
266
|
+
if (panel.current.defaultSize === null) {
|
|
266
267
|
panelsWithNullDefaultSize++;
|
|
267
268
|
} else {
|
|
268
|
-
totalDefaultSize += panel.defaultSize;
|
|
269
|
+
totalDefaultSize += panel.current.defaultSize;
|
|
269
270
|
}
|
|
270
271
|
});
|
|
271
272
|
|
|
@@ -281,11 +282,11 @@ function PanelGroupWithForwardedRef({
|
|
|
281
282
|
|
|
282
283
|
setSizes(
|
|
283
284
|
panelsArray.map((panel) => {
|
|
284
|
-
if (panel.defaultSize === null) {
|
|
285
|
+
if (panel.current.defaultSize === null) {
|
|
285
286
|
return (100 - totalDefaultSize) / panelsWithNullDefaultSize;
|
|
286
287
|
}
|
|
287
288
|
|
|
288
|
-
return panel.defaultSize;
|
|
289
|
+
return panel.current.defaultSize;
|
|
289
290
|
})
|
|
290
291
|
);
|
|
291
292
|
}
|
|
@@ -309,16 +310,22 @@ function PanelGroupWithForwardedRef({
|
|
|
309
310
|
}, [autoSaveId, panels, sizes, storage]);
|
|
310
311
|
|
|
311
312
|
const getPanelStyle = useCallback(
|
|
312
|
-
(id: string): CSSProperties => {
|
|
313
|
+
(id: string, defaultSize: number | null): CSSProperties => {
|
|
313
314
|
const { panels } = committedValuesRef.current;
|
|
314
315
|
|
|
315
316
|
// Before mounting, Panels will not yet have registered themselves.
|
|
316
317
|
// This includes server rendering.
|
|
317
318
|
// At this point the best we can do is render everything with the same size.
|
|
318
319
|
if (panels.size === 0) {
|
|
320
|
+
if (isServerRendering() && defaultSize == null) {
|
|
321
|
+
console.warn(
|
|
322
|
+
`WARNING: Panel defaultSize prop recommended to avoid layout shift after server rendering`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
319
326
|
return {
|
|
320
|
-
flexBasis:
|
|
321
|
-
flexGrow:
|
|
327
|
+
flexBasis: 0,
|
|
328
|
+
flexGrow: defaultSize != null ? defaultSize : undefined,
|
|
322
329
|
flexShrink: 1,
|
|
323
330
|
|
|
324
331
|
// Without this, Panel sizes may be unintentionally overridden by their content.
|
|
@@ -347,14 +354,14 @@ function PanelGroupWithForwardedRef({
|
|
|
347
354
|
[activeHandleId, disablePointerEventsDuringResize, sizes]
|
|
348
355
|
);
|
|
349
356
|
|
|
350
|
-
const registerPanel = useCallback((id: string,
|
|
357
|
+
const registerPanel = useCallback((id: string, panelRef: PanelData) => {
|
|
351
358
|
setPanels((prevPanels) => {
|
|
352
359
|
if (prevPanels.has(id)) {
|
|
353
360
|
return prevPanels;
|
|
354
361
|
}
|
|
355
362
|
|
|
356
363
|
const nextPanels = new Map(prevPanels);
|
|
357
|
-
nextPanels.set(id,
|
|
364
|
+
nextPanels.set(id, panelRef);
|
|
358
365
|
|
|
359
366
|
return nextPanels;
|
|
360
367
|
});
|
|
@@ -382,7 +389,7 @@ function PanelGroupWithForwardedRef({
|
|
|
382
389
|
return;
|
|
383
390
|
}
|
|
384
391
|
|
|
385
|
-
|
|
392
|
+
let movement = getMovement(
|
|
386
393
|
event,
|
|
387
394
|
groupId,
|
|
388
395
|
handleId,
|
|
@@ -398,6 +405,12 @@ function PanelGroupWithForwardedRef({
|
|
|
398
405
|
const groupElement = getPanelGroup(groupId)!;
|
|
399
406
|
const rect = groupElement.getBoundingClientRect();
|
|
400
407
|
const isHorizontal = direction === "horizontal";
|
|
408
|
+
|
|
409
|
+
// Support RTL layouts
|
|
410
|
+
if (document.dir === "rtl" && isHorizontal) {
|
|
411
|
+
movement = -movement;
|
|
412
|
+
}
|
|
413
|
+
|
|
401
414
|
const size = isHorizontal ? rect.width : rect.height;
|
|
402
415
|
const delta = (movement / size) * 100;
|
|
403
416
|
|
|
@@ -473,7 +486,7 @@ function PanelGroupWithForwardedRef({
|
|
|
473
486
|
const { panels, sizes: prevSizes } = committedValuesRef.current;
|
|
474
487
|
|
|
475
488
|
const panel = panels.get(id);
|
|
476
|
-
if (panel == null || !panel.collapsible) {
|
|
489
|
+
if (panel == null || !panel.current.collapsible) {
|
|
477
490
|
return;
|
|
478
491
|
}
|
|
479
492
|
|
|
@@ -527,7 +540,7 @@ function PanelGroupWithForwardedRef({
|
|
|
527
540
|
}
|
|
528
541
|
|
|
529
542
|
const sizeBeforeCollapse =
|
|
530
|
-
panelSizeBeforeCollapse.current.get(id) || panel.minSize;
|
|
543
|
+
panelSizeBeforeCollapse.current.get(id) || panel.current.minSize;
|
|
531
544
|
if (!sizeBeforeCollapse) {
|
|
532
545
|
return;
|
|
533
546
|
}
|
|
@@ -591,10 +604,13 @@ function PanelGroupWithForwardedRef({
|
|
|
591
604
|
return;
|
|
592
605
|
}
|
|
593
606
|
|
|
594
|
-
if (panel.collapsible && nextSize === 0) {
|
|
607
|
+
if (panel.current.collapsible && nextSize === 0) {
|
|
595
608
|
// This is a valid resize state.
|
|
596
609
|
} else {
|
|
597
|
-
nextSize = Math.min(
|
|
610
|
+
nextSize = Math.min(
|
|
611
|
+
panel.current.maxSize,
|
|
612
|
+
Math.max(panel.current.minSize, nextSize)
|
|
613
|
+
);
|
|
598
614
|
}
|
|
599
615
|
|
|
600
616
|
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
@@ -61,12 +61,12 @@ export function useWindowSplitterPanelGroupBehavior({
|
|
|
61
61
|
|
|
62
62
|
// A panel's effective min/max sizes also need to account for other panel's sizes.
|
|
63
63
|
panelsArray.forEach((panelData) => {
|
|
64
|
-
if (panelData.id === idBefore) {
|
|
65
|
-
maxSize = panelData.maxSize;
|
|
66
|
-
minSize = panelData.minSize;
|
|
64
|
+
if (panelData.current.id === idBefore) {
|
|
65
|
+
maxSize = panelData.current.maxSize;
|
|
66
|
+
minSize = panelData.current.minSize;
|
|
67
67
|
} else {
|
|
68
|
-
totalMinSize += panelData.minSize;
|
|
69
|
-
totalMaxSize += panelData.maxSize;
|
|
68
|
+
totalMinSize += panelData.current.minSize;
|
|
69
|
+
totalMaxSize += panelData.current.maxSize;
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
|
|
@@ -92,7 +92,7 @@ export function useWindowSplitterPanelGroupBehavior({
|
|
|
92
92
|
event.preventDefault();
|
|
93
93
|
|
|
94
94
|
const index = panelsArray.findIndex(
|
|
95
|
-
(panel) => panel.id === idBefore
|
|
95
|
+
(panel) => panel.current.id === idBefore
|
|
96
96
|
);
|
|
97
97
|
if (index >= 0) {
|
|
98
98
|
const panelData = panelsArray[index];
|
|
@@ -101,7 +101,7 @@ export function useWindowSplitterPanelGroupBehavior({
|
|
|
101
101
|
let delta = 0;
|
|
102
102
|
if (
|
|
103
103
|
size.toPrecision(PRECISION) <=
|
|
104
|
-
panelData.minSize.toPrecision(PRECISION)
|
|
104
|
+
panelData.current.minSize.toPrecision(PRECISION)
|
|
105
105
|
) {
|
|
106
106
|
delta = direction === "horizontal" ? width : height;
|
|
107
107
|
} else {
|
package/src/types.ts
CHANGED
|
@@ -12,17 +12,21 @@ export type PanelOnCollapse = (collapsed: boolean) => void;
|
|
|
12
12
|
export type PanelOnResize = (size: number) => void;
|
|
13
13
|
export type PanelResizeHandleOnDragging = (isDragging: boolean) => void;
|
|
14
14
|
|
|
15
|
+
export type PanelCallbackRef = RefObject<{
|
|
16
|
+
onCollapse: PanelOnCollapse | null;
|
|
17
|
+
onResize: PanelOnResize | null;
|
|
18
|
+
}>;
|
|
19
|
+
|
|
15
20
|
export type PanelData = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
order: number | null;
|
|
21
|
+
current: {
|
|
22
|
+
callbacksRef: PanelCallbackRef;
|
|
23
|
+
collapsible: boolean;
|
|
24
|
+
defaultSize: number | null;
|
|
25
|
+
id: string;
|
|
26
|
+
maxSize: number;
|
|
27
|
+
minSize: number;
|
|
28
|
+
order: number | null;
|
|
29
|
+
};
|
|
26
30
|
};
|
|
27
31
|
|
|
28
32
|
export type ResizeEvent = KeyboardEvent | MouseEvent | TouchEvent;
|
package/src/utils/coordinates.ts
CHANGED
|
@@ -107,20 +107,20 @@ export function getMovement(
|
|
|
107
107
|
);
|
|
108
108
|
const targetPanelId = movement < 0 ? idBefore : idAfter;
|
|
109
109
|
const targetPanelIndex = panelsArray.findIndex(
|
|
110
|
-
(panel) => panel.id === targetPanelId
|
|
110
|
+
(panel) => panel.current.id === targetPanelId
|
|
111
111
|
);
|
|
112
112
|
const targetPanel = panelsArray[targetPanelIndex];
|
|
113
|
-
if (targetPanel.collapsible) {
|
|
113
|
+
if (targetPanel.current.collapsible) {
|
|
114
114
|
const baseSize = baseSizes[targetPanelIndex];
|
|
115
115
|
if (
|
|
116
116
|
baseSize === 0 ||
|
|
117
117
|
baseSize.toPrecision(PRECISION) ===
|
|
118
|
-
targetPanel.minSize.toPrecision(PRECISION)
|
|
118
|
+
targetPanel.current.minSize.toPrecision(PRECISION)
|
|
119
119
|
) {
|
|
120
120
|
movement =
|
|
121
121
|
movement < 0
|
|
122
|
-
? -targetPanel.minSize * groupSizeInPixels
|
|
123
|
-
: targetPanel.minSize * groupSizeInPixels;
|
|
122
|
+
? -targetPanel.current.minSize * groupSizeInPixels
|
|
123
|
+
: targetPanel.current.minSize * groupSizeInPixels;
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
package/src/utils/group.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PRECISION } from "../constants";
|
|
2
1
|
import { InitialDragState } from "../PanelGroup";
|
|
2
|
+
import { PRECISION } from "../constants";
|
|
3
3
|
import { PanelData, ResizeEvent } from "../types";
|
|
4
4
|
|
|
5
5
|
export function adjustByDelta(
|
|
@@ -39,7 +39,9 @@ export function adjustByDelta(
|
|
|
39
39
|
// Max-bounds check the panel being expanded first.
|
|
40
40
|
{
|
|
41
41
|
const pivotId = delta < 0 ? idAfter : idBefore;
|
|
42
|
-
const index = panelsArray.findIndex(
|
|
42
|
+
const index = panelsArray.findIndex(
|
|
43
|
+
(panel) => panel.current.id === pivotId
|
|
44
|
+
);
|
|
43
45
|
const panel = panelsArray[index];
|
|
44
46
|
const baseSize = baseSizes[index];
|
|
45
47
|
|
|
@@ -57,7 +59,7 @@ export function adjustByDelta(
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
let pivotId = delta < 0 ? idBefore : idAfter;
|
|
60
|
-
let index = panelsArray.findIndex((panel) => panel.id === pivotId);
|
|
62
|
+
let index = panelsArray.findIndex((panel) => panel.current.id === pivotId);
|
|
61
63
|
while (true) {
|
|
62
64
|
const panel = panelsArray[index];
|
|
63
65
|
const baseSize = baseSizes[index];
|
|
@@ -72,7 +74,7 @@ export function adjustByDelta(
|
|
|
72
74
|
);
|
|
73
75
|
if (baseSize !== nextSize) {
|
|
74
76
|
if (nextSize === 0 && baseSize > 0) {
|
|
75
|
-
panelSizeBeforeCollapse.set(panel.id, baseSize);
|
|
77
|
+
panelSizeBeforeCollapse.set(panel.current.id, baseSize);
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
deltaApplied += baseSize - nextSize;
|
|
@@ -109,7 +111,7 @@ export function adjustByDelta(
|
|
|
109
111
|
|
|
110
112
|
// Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
|
|
111
113
|
pivotId = delta < 0 ? idAfter : idBefore;
|
|
112
|
-
index = panelsArray.findIndex((panel) => panel.id === pivotId);
|
|
114
|
+
index = panelsArray.findIndex((panel) => panel.current.id === pivotId);
|
|
113
115
|
nextSizes[index] = baseSizes[index] + deltaApplied;
|
|
114
116
|
|
|
115
117
|
return nextSizes;
|
|
@@ -123,7 +125,7 @@ export function callPanelCallbacks(
|
|
|
123
125
|
nextSizes.forEach((nextSize, index) => {
|
|
124
126
|
const prevSize = prevSizes[index];
|
|
125
127
|
if (prevSize !== nextSize) {
|
|
126
|
-
const { callbacksRef, collapsible } = panelsArray[index];
|
|
128
|
+
const { callbacksRef, collapsible } = panelsArray[index].current;
|
|
127
129
|
const { onCollapse, onResize } = callbacksRef.current!;
|
|
128
130
|
|
|
129
131
|
if (onResize) {
|
|
@@ -151,14 +153,14 @@ export function getBeforeAndAfterIds(
|
|
|
151
153
|
return [null, null];
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
const index = panelsArray.findIndex((panel) => panel.id === id);
|
|
156
|
+
const index = panelsArray.findIndex((panel) => panel.current.id === id);
|
|
155
157
|
if (index < 0) {
|
|
156
158
|
return [null, null];
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
const isLastPanel = index === panelsArray.length - 1;
|
|
160
|
-
const idBefore = isLastPanel ? panelsArray[index - 1].id : id;
|
|
161
|
-
const idAfter = isLastPanel ? id : panelsArray[index + 1].id;
|
|
162
|
+
const idBefore = isLastPanel ? panelsArray[index - 1].current.id : id;
|
|
163
|
+
const idAfter = isLastPanel ? id : panelsArray[index + 1].current.id;
|
|
162
164
|
|
|
163
165
|
return [idBefore, idAfter];
|
|
164
166
|
}
|
|
@@ -176,7 +178,7 @@ export function getFlexGrow(
|
|
|
176
178
|
|
|
177
179
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
178
180
|
|
|
179
|
-
const index = panelsArray.findIndex((panel) => panel.id === id);
|
|
181
|
+
const index = panelsArray.findIndex((panel) => panel.current.id === id);
|
|
180
182
|
const size = sizes[index];
|
|
181
183
|
if (size == null) {
|
|
182
184
|
return "0";
|
|
@@ -240,8 +242,8 @@ export function getResizeHandlePanelIds(
|
|
|
240
242
|
const handles = getResizeHandlesForGroup(groupId);
|
|
241
243
|
const index = handle ? handles.indexOf(handle) : -1;
|
|
242
244
|
|
|
243
|
-
const idBefore: string | null = panelsArray[index]?.id ?? null;
|
|
244
|
-
const idAfter: string | null = panelsArray[index + 1]?.id ?? null;
|
|
245
|
+
const idBefore: string | null = panelsArray[index]?.current?.id ?? null;
|
|
246
|
+
const idAfter: string | null = panelsArray[index + 1]?.current?.id ?? null;
|
|
245
247
|
|
|
246
248
|
return [idBefore, idAfter];
|
|
247
249
|
}
|
|
@@ -250,8 +252,8 @@ export function panelsMapToSortedArray(
|
|
|
250
252
|
panels: Map<string, PanelData>
|
|
251
253
|
): PanelData[] {
|
|
252
254
|
return Array.from(panels.values()).sort((panelA, panelB) => {
|
|
253
|
-
const orderA = panelA.order;
|
|
254
|
-
const orderB = panelB.order;
|
|
255
|
+
const orderA = panelA.current.order;
|
|
256
|
+
const orderB = panelB.current.order;
|
|
255
257
|
if (orderA == null && orderB == null) {
|
|
256
258
|
return 0;
|
|
257
259
|
} else if (orderA == null) {
|
|
@@ -272,7 +274,7 @@ function safeResizePanel(
|
|
|
272
274
|
): number {
|
|
273
275
|
const nextSizeUnsafe = prevSize + delta;
|
|
274
276
|
|
|
275
|
-
if (panel.collapsible) {
|
|
277
|
+
if (panel.current.collapsible) {
|
|
276
278
|
if (prevSize > 0) {
|
|
277
279
|
if (nextSizeUnsafe <= 0) {
|
|
278
280
|
return 0;
|
|
@@ -283,7 +285,7 @@ function safeResizePanel(
|
|
|
283
285
|
// Keyboard events should expand a collapsed panel to the min size,
|
|
284
286
|
// but mouse events should wait until the panel has reached its min size
|
|
285
287
|
// to avoid a visual flickering when dragging between collapsed and min size.
|
|
286
|
-
if (nextSizeUnsafe < panel.minSize) {
|
|
288
|
+
if (nextSizeUnsafe < panel.current.minSize) {
|
|
287
289
|
return 0;
|
|
288
290
|
}
|
|
289
291
|
}
|
|
@@ -291,8 +293,8 @@ function safeResizePanel(
|
|
|
291
293
|
}
|
|
292
294
|
|
|
293
295
|
const nextSize = Math.min(
|
|
294
|
-
panel.maxSize,
|
|
295
|
-
Math.max(panel.minSize, nextSizeUnsafe)
|
|
296
|
+
panel.current.maxSize,
|
|
297
|
+
Math.max(panel.current.minSize, nextSizeUnsafe)
|
|
296
298
|
);
|
|
297
299
|
|
|
298
300
|
return nextSize;
|
|
@@ -9,7 +9,7 @@ type SerializedPanelGroupState = { [panelIds: string]: number[] };
|
|
|
9
9
|
function getSerializationKey(panels: PanelData[]): string {
|
|
10
10
|
return panels
|
|
11
11
|
.map((panel) => {
|
|
12
|
-
const { minSize, order } = panel;
|
|
12
|
+
const { minSize, order } = panel.current;
|
|
13
13
|
return order ? `${order}:${minSize}` : `${minSize}`;
|
|
14
14
|
})
|
|
15
15
|
.sort((a, b) => a.localeCompare(b))
|