react-resizable-panels 0.0.58 → 0.0.60
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 +12 -0
- package/dist/declarations/src/PanelGroup.d.ts +2 -2
- package/dist/react-resizable-panels.browser.cjs.js +189 -98
- package/dist/react-resizable-panels.browser.development.cjs.js +192 -101
- package/dist/react-resizable-panels.browser.development.esm.js +192 -101
- package/dist/react-resizable-panels.browser.esm.js +189 -98
- package/dist/react-resizable-panels.cjs.js +189 -98
- package/dist/react-resizable-panels.cjs.js.map +1 -1
- package/dist/react-resizable-panels.development.cjs.js +192 -101
- package/dist/react-resizable-panels.development.esm.js +192 -101
- package/dist/react-resizable-panels.development.node.cjs.js +237 -49
- package/dist/react-resizable-panels.development.node.esm.js +237 -49
- package/dist/react-resizable-panels.esm.js +189 -98
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +234 -46
- package/dist/react-resizable-panels.node.esm.js +234 -46
- package/package.json +1 -1
- package/src/Panel.ts +2 -0
- package/src/PanelGroup.ts +221 -97
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +15 -15
- package/src/utils/dom/getPanelElementsForGroup.ts +5 -0
package/src/PanelGroup.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { resetGlobalCursorStyle, setGlobalCursorStyle } from "./utils/cursor";
|
|
|
18
18
|
import debounce from "./utils/debounce";
|
|
19
19
|
import { determinePivotIndices } from "./utils/determinePivotIndices";
|
|
20
20
|
import { calculateAvailablePanelSizeInPixels } from "./utils/dom/calculateAvailablePanelSizeInPixels";
|
|
21
|
+
import { getPanelElementsForGroup } from "./utils/dom/getPanelElementsForGroup";
|
|
21
22
|
import { getPanelGroupElement } from "./utils/dom/getPanelGroupElement";
|
|
22
23
|
import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement";
|
|
23
24
|
import { isKeyDown, isMouseEvent, isTouchEvent } from "./utils/events";
|
|
@@ -70,7 +71,7 @@ const defaultStorage: PanelGroupStorage = {
|
|
|
70
71
|
};
|
|
71
72
|
|
|
72
73
|
export type PanelGroupProps = PropsWithChildren<{
|
|
73
|
-
autoSaveId?: string;
|
|
74
|
+
autoSaveId?: string | null;
|
|
74
75
|
className?: string;
|
|
75
76
|
dataAttributes?: DataAttributes;
|
|
76
77
|
direction: Direction;
|
|
@@ -88,7 +89,7 @@ const debounceMap: {
|
|
|
88
89
|
} = {};
|
|
89
90
|
|
|
90
91
|
function PanelGroupWithForwardedRef({
|
|
91
|
-
autoSaveId,
|
|
92
|
+
autoSaveId = null,
|
|
92
93
|
children,
|
|
93
94
|
className: classNameFromProps = "",
|
|
94
95
|
dataAttributes,
|
|
@@ -108,7 +109,6 @@ function PanelGroupWithForwardedRef({
|
|
|
108
109
|
|
|
109
110
|
const [dragState, setDragState] = useState<DragState | null>(null);
|
|
110
111
|
const [layout, setLayout] = useState<number[]>([]);
|
|
111
|
-
const [panelDataArray, setPanelDataArray] = useState<PanelData[]>([]);
|
|
112
112
|
|
|
113
113
|
const panelIdToLastNotifiedMixedSizesMapRef = useRef<
|
|
114
114
|
Record<string, MixedSizes>
|
|
@@ -117,6 +117,7 @@ function PanelGroupWithForwardedRef({
|
|
|
117
117
|
const prevDeltaRef = useRef<number>(0);
|
|
118
118
|
|
|
119
119
|
const committedValuesRef = useRef<{
|
|
120
|
+
autoSaveId: string | null;
|
|
120
121
|
direction: Direction;
|
|
121
122
|
dragState: DragState | null;
|
|
122
123
|
id: string;
|
|
@@ -125,7 +126,9 @@ function PanelGroupWithForwardedRef({
|
|
|
125
126
|
layout: number[];
|
|
126
127
|
onLayout: PanelGroupOnLayout | null;
|
|
127
128
|
panelDataArray: PanelData[];
|
|
129
|
+
storage: PanelGroupStorage;
|
|
128
130
|
}>({
|
|
131
|
+
autoSaveId,
|
|
129
132
|
direction,
|
|
130
133
|
dragState,
|
|
131
134
|
id: groupId,
|
|
@@ -133,7 +136,8 @@ function PanelGroupWithForwardedRef({
|
|
|
133
136
|
keyboardResizeByPixels,
|
|
134
137
|
layout,
|
|
135
138
|
onLayout,
|
|
136
|
-
panelDataArray,
|
|
139
|
+
panelDataArray: [],
|
|
140
|
+
storage,
|
|
137
141
|
});
|
|
138
142
|
|
|
139
143
|
const devWarningsRef = useRef<{
|
|
@@ -191,6 +195,8 @@ function PanelGroupWithForwardedRef({
|
|
|
191
195
|
if (!areEqual(prevLayout, safeLayout)) {
|
|
192
196
|
setLayout(safeLayout);
|
|
193
197
|
|
|
198
|
+
committedValuesRef.current.layout = safeLayout;
|
|
199
|
+
|
|
194
200
|
if (onLayout) {
|
|
195
201
|
onLayout(
|
|
196
202
|
safeLayout.map((sizePercentage) => ({
|
|
@@ -216,23 +222,28 @@ function PanelGroupWithForwardedRef({
|
|
|
216
222
|
);
|
|
217
223
|
|
|
218
224
|
useIsomorphicLayoutEffect(() => {
|
|
225
|
+
committedValuesRef.current.autoSaveId = autoSaveId;
|
|
219
226
|
committedValuesRef.current.direction = direction;
|
|
220
227
|
committedValuesRef.current.dragState = dragState;
|
|
221
228
|
committedValuesRef.current.id = groupId;
|
|
222
|
-
committedValuesRef.current.layout = layout;
|
|
223
229
|
committedValuesRef.current.onLayout = onLayout;
|
|
224
|
-
committedValuesRef.current.
|
|
230
|
+
committedValuesRef.current.storage = storage;
|
|
231
|
+
|
|
232
|
+
// panelDataArray and layout are updated in-sync with scheduled state updates.
|
|
233
|
+
// TODO [217] Move these values into a separate ref
|
|
225
234
|
});
|
|
226
235
|
|
|
227
236
|
useWindowSplitterPanelGroupBehavior({
|
|
228
237
|
committedValuesRef,
|
|
229
238
|
groupId,
|
|
230
239
|
layout,
|
|
231
|
-
panelDataArray,
|
|
240
|
+
panelDataArray: committedValuesRef.current.panelDataArray,
|
|
232
241
|
setLayout,
|
|
233
242
|
});
|
|
234
243
|
|
|
235
244
|
useEffect(() => {
|
|
245
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
246
|
+
|
|
236
247
|
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
237
248
|
if (autoSaveId) {
|
|
238
249
|
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
@@ -248,73 +259,11 @@ function PanelGroupWithForwardedRef({
|
|
|
248
259
|
}
|
|
249
260
|
debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
|
|
250
261
|
}
|
|
251
|
-
}, [autoSaveId, layout,
|
|
262
|
+
}, [autoSaveId, layout, storage]);
|
|
252
263
|
|
|
253
|
-
// Once all panels have registered themselves,
|
|
254
|
-
// Compute the initial sizes based on default weights.
|
|
255
|
-
// This assumes that panels register during initial mount (no conditional rendering)!
|
|
256
264
|
useIsomorphicLayoutEffect(() => {
|
|
257
|
-
const {
|
|
258
|
-
if (layout.length === panelDataArray.length) {
|
|
259
|
-
// Only compute (or restore) default layout once per panel configuration.
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// If this panel has been configured to persist sizing information,
|
|
264
|
-
// default size should be restored from local storage if possible.
|
|
265
|
-
let unsafeLayout: number[] | null = null;
|
|
266
|
-
if (autoSaveId) {
|
|
267
|
-
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
271
|
-
if (groupSizePixels <= 0) {
|
|
272
|
-
// Wait until the group has rendered a non-zero size before computing layout.
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (unsafeLayout == null) {
|
|
277
|
-
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
278
|
-
groupSizePixels,
|
|
279
|
-
panelDataArray,
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Validate even saved layouts in case something has changed since last render
|
|
284
|
-
// e.g. for pixel groups, this could be the size of the window
|
|
285
|
-
const validatedLayout = validatePanelGroupLayout({
|
|
286
|
-
groupSizePixels,
|
|
287
|
-
layout: unsafeLayout,
|
|
288
|
-
panelConstraints: panelDataArray.map(
|
|
289
|
-
(panelData) => panelData.constraints
|
|
290
|
-
),
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
if (!areEqual(layout, validatedLayout)) {
|
|
294
|
-
setLayout(validatedLayout);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (onLayout) {
|
|
298
|
-
onLayout(
|
|
299
|
-
validatedLayout.map((sizePercentage) => ({
|
|
300
|
-
sizePercentage,
|
|
301
|
-
sizePixels: convertPercentageToPixels(
|
|
302
|
-
sizePercentage,
|
|
303
|
-
groupSizePixels
|
|
304
|
-
),
|
|
305
|
-
}))
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
callPanelCallbacks(
|
|
310
|
-
groupId,
|
|
311
|
-
panelDataArray,
|
|
312
|
-
validatedLayout,
|
|
313
|
-
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
314
|
-
);
|
|
315
|
-
}, [autoSaveId, layout, panelDataArray, storage]);
|
|
265
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
316
266
|
|
|
317
|
-
useIsomorphicLayoutEffect(() => {
|
|
318
267
|
const constraints = panelDataArray.map(({ constraints }) => constraints);
|
|
319
268
|
if (!shouldMonitorPixelBasedConstraints(constraints)) {
|
|
320
269
|
// Avoid the overhead of ResizeObserver if no pixel constraints require monitoring
|
|
@@ -342,6 +291,8 @@ function PanelGroupWithForwardedRef({
|
|
|
342
291
|
if (!areEqual(prevLayout, nextLayout)) {
|
|
343
292
|
setLayout(nextLayout);
|
|
344
293
|
|
|
294
|
+
committedValuesRef.current.layout = nextLayout;
|
|
295
|
+
|
|
345
296
|
if (onLayout) {
|
|
346
297
|
onLayout(
|
|
347
298
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -369,11 +320,13 @@ function PanelGroupWithForwardedRef({
|
|
|
369
320
|
resizeObserver.disconnect();
|
|
370
321
|
};
|
|
371
322
|
}
|
|
372
|
-
}, [groupId
|
|
323
|
+
}, [groupId]);
|
|
373
324
|
|
|
374
325
|
// DEV warnings
|
|
375
326
|
useEffect(() => {
|
|
376
327
|
if (isDevelopment) {
|
|
328
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
329
|
+
|
|
377
330
|
const {
|
|
378
331
|
didLogIdAndOrderWarning,
|
|
379
332
|
didLogPanelConstraintsWarning,
|
|
@@ -381,8 +334,6 @@ function PanelGroupWithForwardedRef({
|
|
|
381
334
|
} = devWarningsRef.current;
|
|
382
335
|
|
|
383
336
|
if (!didLogIdAndOrderWarning) {
|
|
384
|
-
const { panelDataArray } = committedValuesRef.current;
|
|
385
|
-
|
|
386
337
|
const panelIds = panelDataArray.map(({ id }) => id);
|
|
387
338
|
|
|
388
339
|
devWarningsRef.current.prevPanelIds = panelIds;
|
|
@@ -480,6 +431,8 @@ function PanelGroupWithForwardedRef({
|
|
|
480
431
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
481
432
|
setLayout(nextLayout);
|
|
482
433
|
|
|
434
|
+
committedValuesRef.current.layout = nextLayout;
|
|
435
|
+
|
|
483
436
|
if (onLayout) {
|
|
484
437
|
onLayout(
|
|
485
438
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -555,6 +508,8 @@ function PanelGroupWithForwardedRef({
|
|
|
555
508
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
556
509
|
setLayout(nextLayout);
|
|
557
510
|
|
|
511
|
+
committedValuesRef.current.layout = nextLayout;
|
|
512
|
+
|
|
558
513
|
if (onLayout) {
|
|
559
514
|
onLayout(
|
|
560
515
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -603,6 +558,8 @@ function PanelGroupWithForwardedRef({
|
|
|
603
558
|
// This API should never read from committedValuesRef
|
|
604
559
|
const getPanelStyle = useCallback(
|
|
605
560
|
(panelData: PanelData) => {
|
|
561
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
562
|
+
|
|
606
563
|
const panelIndex = panelDataArray.indexOf(panelData);
|
|
607
564
|
|
|
608
565
|
return computePanelFlexBoxStyle({
|
|
@@ -612,7 +569,7 @@ function PanelGroupWithForwardedRef({
|
|
|
612
569
|
panelIndex,
|
|
613
570
|
});
|
|
614
571
|
},
|
|
615
|
-
[dragState, layout
|
|
572
|
+
[dragState, layout]
|
|
616
573
|
);
|
|
617
574
|
|
|
618
575
|
// External APIs are safe to memoize via committed values ref
|
|
@@ -644,22 +601,97 @@ function PanelGroupWithForwardedRef({
|
|
|
644
601
|
);
|
|
645
602
|
|
|
646
603
|
const registerPanel = useCallback((panelData: PanelData) => {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
604
|
+
const {
|
|
605
|
+
autoSaveId,
|
|
606
|
+
id: groupId,
|
|
607
|
+
layout: prevLayout,
|
|
608
|
+
onLayout,
|
|
609
|
+
panelDataArray,
|
|
610
|
+
storage,
|
|
611
|
+
} = committedValuesRef.current;
|
|
612
|
+
|
|
613
|
+
panelDataArray.push(panelData);
|
|
614
|
+
panelDataArray.sort((panelA, panelB) => {
|
|
615
|
+
const orderA = panelA.order;
|
|
616
|
+
const orderB = panelB.order;
|
|
617
|
+
if (orderA == null && orderB == null) {
|
|
618
|
+
return 0;
|
|
619
|
+
} else if (orderA == null) {
|
|
620
|
+
return -1;
|
|
621
|
+
} else if (orderB == null) {
|
|
622
|
+
return 1;
|
|
623
|
+
} else {
|
|
624
|
+
return orderA - orderB;
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
// Wait until all panels have registered before we try to compute layout;
|
|
629
|
+
// doing it earlier is both wasteful and may trigger misleading warnings in development mode.
|
|
630
|
+
const panelElements = getPanelElementsForGroup(groupId);
|
|
631
|
+
if (panelElements.length !== panelDataArray.length) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// If this panel has been configured to persist sizing information,
|
|
636
|
+
// default size should be restored from local storage if possible.
|
|
637
|
+
let unsafeLayout: number[] | null = null;
|
|
638
|
+
if (autoSaveId) {
|
|
639
|
+
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
643
|
+
if (groupSizePixels <= 0) {
|
|
644
|
+
if (
|
|
645
|
+
shouldMonitorPixelBasedConstraints(
|
|
646
|
+
panelDataArray.map(({ constraints }) => constraints)
|
|
647
|
+
)
|
|
648
|
+
) {
|
|
649
|
+
// Wait until the group has rendered a non-zero size before computing layout.
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (unsafeLayout == null) {
|
|
655
|
+
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
656
|
+
groupSizePixels,
|
|
657
|
+
panelDataArray,
|
|
661
658
|
});
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// Validate even saved layouts in case something has changed since last render
|
|
662
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
663
|
+
const nextLayout = validatePanelGroupLayout({
|
|
664
|
+
groupSizePixels,
|
|
665
|
+
layout: unsafeLayout,
|
|
666
|
+
panelConstraints: panelDataArray.map(
|
|
667
|
+
(panelData) => panelData.constraints
|
|
668
|
+
),
|
|
662
669
|
});
|
|
670
|
+
|
|
671
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
672
|
+
setLayout(nextLayout);
|
|
673
|
+
|
|
674
|
+
committedValuesRef.current.layout = nextLayout;
|
|
675
|
+
|
|
676
|
+
if (onLayout) {
|
|
677
|
+
onLayout(
|
|
678
|
+
nextLayout.map((sizePercentage) => ({
|
|
679
|
+
sizePercentage,
|
|
680
|
+
sizePixels: convertPercentageToPixels(
|
|
681
|
+
sizePercentage,
|
|
682
|
+
groupSizePixels
|
|
683
|
+
),
|
|
684
|
+
}))
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
callPanelCallbacks(
|
|
689
|
+
groupId,
|
|
690
|
+
panelDataArray,
|
|
691
|
+
nextLayout,
|
|
692
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
693
|
+
);
|
|
694
|
+
}
|
|
663
695
|
}, []);
|
|
664
696
|
|
|
665
697
|
const registerResizeHandle = useCallback((dragHandleId: string) => {
|
|
@@ -749,6 +781,8 @@ function PanelGroupWithForwardedRef({
|
|
|
749
781
|
if (layoutChanged) {
|
|
750
782
|
setLayout(nextLayout);
|
|
751
783
|
|
|
784
|
+
committedValuesRef.current.layout = nextLayout;
|
|
785
|
+
|
|
752
786
|
if (onLayout) {
|
|
753
787
|
onLayout(
|
|
754
788
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -810,6 +844,8 @@ function PanelGroupWithForwardedRef({
|
|
|
810
844
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
811
845
|
setLayout(nextLayout);
|
|
812
846
|
|
|
847
|
+
committedValuesRef.current.layout = nextLayout;
|
|
848
|
+
|
|
813
849
|
if (onLayout) {
|
|
814
850
|
onLayout(
|
|
815
851
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -859,18 +895,106 @@ function PanelGroupWithForwardedRef({
|
|
|
859
895
|
setDragState(null);
|
|
860
896
|
}, []);
|
|
861
897
|
|
|
898
|
+
const unregisterPanelRef = useRef<{
|
|
899
|
+
pendingPanelIds: Set<string>;
|
|
900
|
+
timeout: NodeJS.Timeout | null;
|
|
901
|
+
}>({
|
|
902
|
+
pendingPanelIds: new Set(),
|
|
903
|
+
timeout: null,
|
|
904
|
+
});
|
|
862
905
|
const unregisterPanel = useCallback((panelData: PanelData) => {
|
|
863
|
-
|
|
906
|
+
const {
|
|
907
|
+
id: groupId,
|
|
908
|
+
layout: prevLayout,
|
|
909
|
+
onLayout,
|
|
910
|
+
panelDataArray,
|
|
911
|
+
} = committedValuesRef.current;
|
|
912
|
+
|
|
913
|
+
const index = panelDataArray.indexOf(panelData);
|
|
914
|
+
if (index >= 0) {
|
|
915
|
+
panelDataArray.splice(index, 1);
|
|
916
|
+
unregisterPanelRef.current.pendingPanelIds.add(panelData.id);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
if (unregisterPanelRef.current.timeout != null) {
|
|
920
|
+
clearTimeout(unregisterPanelRef.current.timeout);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// Batch panel unmounts so that we only calculate layout once;
|
|
924
|
+
// This is more efficient and avoids misleading warnings in development mode.
|
|
925
|
+
// We can't check the DOM to detect this because Panel elements have not yet been removed.
|
|
926
|
+
unregisterPanelRef.current.timeout = setTimeout(() => {
|
|
927
|
+
const { pendingPanelIds } = unregisterPanelRef.current;
|
|
928
|
+
const map = panelIdToLastNotifiedMixedSizesMapRef.current;
|
|
929
|
+
|
|
930
|
+
// TRICKY
|
|
931
|
+
// Strict effects mode
|
|
932
|
+
let unmountDueToStrictMode = false;
|
|
933
|
+
pendingPanelIds.forEach((panelId) => {
|
|
934
|
+
pendingPanelIds.delete(panelId);
|
|
935
|
+
|
|
936
|
+
if (panelDataArray.find(({ id }) => id === panelId) == null) {
|
|
937
|
+
unmountDueToStrictMode = true;
|
|
938
|
+
|
|
939
|
+
// TRICKY
|
|
940
|
+
// When a panel is removed from the group, we should delete the most recent prev-size entry for it.
|
|
941
|
+
// If we don't do this, then a conditionally rendered panel might not call onResize when it's re-mounted.
|
|
942
|
+
// Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
|
|
943
|
+
delete panelIdToLastNotifiedMixedSizesMapRef.current[panelData.id];
|
|
944
|
+
}
|
|
945
|
+
});
|
|
864
946
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
if (index >= 0) {
|
|
868
|
-
panelDataArray = [...panelDataArray];
|
|
869
|
-
panelDataArray.splice(index, 1);
|
|
947
|
+
if (!unmountDueToStrictMode) {
|
|
948
|
+
return;
|
|
870
949
|
}
|
|
871
950
|
|
|
872
|
-
|
|
873
|
-
|
|
951
|
+
if (panelDataArray.length === 0) {
|
|
952
|
+
// The group is unmounting; skip layout calculation.
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
957
|
+
|
|
958
|
+
let unsafeLayout: number[] = calculateUnsafeDefaultLayout({
|
|
959
|
+
groupSizePixels,
|
|
960
|
+
panelDataArray,
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
// Validate even saved layouts in case something has changed since last render
|
|
964
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
965
|
+
const nextLayout = validatePanelGroupLayout({
|
|
966
|
+
groupSizePixels,
|
|
967
|
+
layout: unsafeLayout,
|
|
968
|
+
panelConstraints: panelDataArray.map(
|
|
969
|
+
(panelData) => panelData.constraints
|
|
970
|
+
),
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
974
|
+
setLayout(nextLayout);
|
|
975
|
+
|
|
976
|
+
committedValuesRef.current.layout = nextLayout;
|
|
977
|
+
|
|
978
|
+
if (onLayout) {
|
|
979
|
+
onLayout(
|
|
980
|
+
nextLayout.map((sizePercentage) => ({
|
|
981
|
+
sizePercentage,
|
|
982
|
+
sizePixels: convertPercentageToPixels(
|
|
983
|
+
sizePercentage,
|
|
984
|
+
groupSizePixels
|
|
985
|
+
),
|
|
986
|
+
}))
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
callPanelCallbacks(
|
|
991
|
+
groupId,
|
|
992
|
+
panelDataArray,
|
|
993
|
+
nextLayout,
|
|
994
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
}, 0);
|
|
874
998
|
}, []);
|
|
875
999
|
|
|
876
1000
|
const context = useMemo(
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { isDevelopment } from "#is-development";
|
|
2
2
|
import { PanelData } from "../Panel";
|
|
3
|
-
import { PRECISION } from "../constants";
|
|
4
3
|
import { Direction } from "../types";
|
|
5
4
|
import { adjustLayoutByDelta } from "../utils/adjustLayoutByDelta";
|
|
6
5
|
import { assert } from "../utils/assert";
|
|
@@ -12,6 +11,7 @@ import { getPanelGroupElement } from "../utils/dom/getPanelGroupElement";
|
|
|
12
11
|
import { getResizeHandleElementsForGroup } from "../utils/dom/getResizeHandleElementsForGroup";
|
|
13
12
|
import { getResizeHandlePanelIds } from "../utils/dom/getResizeHandlePanelIds";
|
|
14
13
|
import { getPercentageSizeFromMixedSizes } from "../utils/getPercentageSizeFromMixedSizes";
|
|
14
|
+
import { fuzzyNumbersEqual } from "../utils/numbers/fuzzyNumbersEqual";
|
|
15
15
|
import { RefObject, useEffect, useRef } from "../vendor/react";
|
|
16
16
|
import useIsomorphicLayoutEffect from "./useIsomorphicEffect";
|
|
17
17
|
|
|
@@ -95,13 +95,11 @@ export function useWindowSplitterPanelGroupBehavior({
|
|
|
95
95
|
}, [groupId, layout, panelDataArray]);
|
|
96
96
|
|
|
97
97
|
useEffect(() => {
|
|
98
|
-
const {
|
|
98
|
+
const { panelDataArray } = committedValuesRef.current!;
|
|
99
99
|
|
|
100
100
|
const groupElement = getPanelGroupElement(groupId);
|
|
101
101
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
102
102
|
|
|
103
|
-
const { height, width } = groupElement.getBoundingClientRect();
|
|
104
|
-
|
|
105
103
|
const handles = getResizeHandleElementsForGroup(groupId);
|
|
106
104
|
const cleanupFunctions = handles.map((handle) => {
|
|
107
105
|
const handleId = handle.getAttribute("data-panel-resize-handle-id")!;
|
|
@@ -130,9 +128,18 @@ export function useWindowSplitterPanelGroupBehavior({
|
|
|
130
128
|
if (index >= 0) {
|
|
131
129
|
const panelData = panelDataArray[index];
|
|
132
130
|
const size = layout[index];
|
|
133
|
-
if (size != null) {
|
|
131
|
+
if (size != null && panelData.constraints.collapsible) {
|
|
134
132
|
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
135
133
|
|
|
134
|
+
const collapsedSize =
|
|
135
|
+
getPercentageSizeFromMixedSizes(
|
|
136
|
+
{
|
|
137
|
+
sizePercentage:
|
|
138
|
+
panelData.constraints.collapsedSizePercentage,
|
|
139
|
+
sizePixels: panelData.constraints.collapsedSizePixels,
|
|
140
|
+
},
|
|
141
|
+
groupSizePixels
|
|
142
|
+
) ?? 0;
|
|
136
143
|
const minSize =
|
|
137
144
|
getPercentageSizeFromMixedSizes(
|
|
138
145
|
{
|
|
@@ -142,17 +149,10 @@ export function useWindowSplitterPanelGroupBehavior({
|
|
|
142
149
|
groupSizePixels
|
|
143
150
|
) ?? 0;
|
|
144
151
|
|
|
145
|
-
let delta = 0;
|
|
146
|
-
if (
|
|
147
|
-
size.toPrecision(PRECISION) <= minSize.toPrecision(PRECISION)
|
|
148
|
-
) {
|
|
149
|
-
delta = direction === "horizontal" ? width : height;
|
|
150
|
-
} else {
|
|
151
|
-
delta = -(direction === "horizontal" ? width : height);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
152
|
const nextLayout = adjustLayoutByDelta({
|
|
155
|
-
delta,
|
|
153
|
+
delta: fuzzyNumbersEqual(size, collapsedSize)
|
|
154
|
+
? minSize - collapsedSize
|
|
155
|
+
: collapsedSize - size,
|
|
156
156
|
groupSizePixels,
|
|
157
157
|
layout,
|
|
158
158
|
panelConstraints: panelDataArray.map(
|