react-resizable-panels 0.0.59 → 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 +6 -0
- package/dist/declarations/src/PanelGroup.d.ts +2 -2
- package/dist/react-resizable-panels.browser.cjs.js +177 -143
- package/dist/react-resizable-panels.browser.development.cjs.js +180 -146
- package/dist/react-resizable-panels.browser.development.esm.js +180 -146
- package/dist/react-resizable-panels.browser.esm.js +177 -143
- package/dist/react-resizable-panels.cjs.js +177 -143
- package/dist/react-resizable-panels.cjs.js.map +1 -1
- package/dist/react-resizable-panels.development.cjs.js +180 -146
- package/dist/react-resizable-panels.development.esm.js +180 -146
- package/dist/react-resizable-panels.development.node.cjs.js +226 -66
- package/dist/react-resizable-panels.development.node.esm.js +226 -66
- package/dist/react-resizable-panels.esm.js +177 -143
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +223 -63
- package/dist/react-resizable-panels.node.esm.js +223 -63
- package/package.json +1 -1
- package/src/Panel.ts +2 -0
- package/src/PanelGroup.ts +219 -177
- 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;
|
|
@@ -83,18 +84,12 @@ export type PanelGroupProps = PropsWithChildren<{
|
|
|
83
84
|
tagName?: ElementType;
|
|
84
85
|
}>;
|
|
85
86
|
|
|
86
|
-
type ImperativeApiQueue = {
|
|
87
|
-
type: "collapse" | "expand" | "resize";
|
|
88
|
-
mixedSizes?: Partial<MixedSizes>;
|
|
89
|
-
panelData: PanelData;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
87
|
const debounceMap: {
|
|
93
88
|
[key: string]: typeof savePanelGroupLayout;
|
|
94
89
|
} = {};
|
|
95
90
|
|
|
96
91
|
function PanelGroupWithForwardedRef({
|
|
97
|
-
autoSaveId,
|
|
92
|
+
autoSaveId = null,
|
|
98
93
|
children,
|
|
99
94
|
className: classNameFromProps = "",
|
|
100
95
|
dataAttributes,
|
|
@@ -114,7 +109,6 @@ function PanelGroupWithForwardedRef({
|
|
|
114
109
|
|
|
115
110
|
const [dragState, setDragState] = useState<DragState | null>(null);
|
|
116
111
|
const [layout, setLayout] = useState<number[]>([]);
|
|
117
|
-
const [panelDataArray, setPanelDataArray] = useState<PanelData[]>([]);
|
|
118
112
|
|
|
119
113
|
const panelIdToLastNotifiedMixedSizesMapRef = useRef<
|
|
120
114
|
Record<string, MixedSizes>
|
|
@@ -122,11 +116,8 @@ function PanelGroupWithForwardedRef({
|
|
|
122
116
|
const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
|
|
123
117
|
const prevDeltaRef = useRef<number>(0);
|
|
124
118
|
|
|
125
|
-
const [imperativeApiQueue, setImperativeApiQueue] = useState<
|
|
126
|
-
ImperativeApiQueue[]
|
|
127
|
-
>([]);
|
|
128
|
-
|
|
129
119
|
const committedValuesRef = useRef<{
|
|
120
|
+
autoSaveId: string | null;
|
|
130
121
|
direction: Direction;
|
|
131
122
|
dragState: DragState | null;
|
|
132
123
|
id: string;
|
|
@@ -135,7 +126,9 @@ function PanelGroupWithForwardedRef({
|
|
|
135
126
|
layout: number[];
|
|
136
127
|
onLayout: PanelGroupOnLayout | null;
|
|
137
128
|
panelDataArray: PanelData[];
|
|
129
|
+
storage: PanelGroupStorage;
|
|
138
130
|
}>({
|
|
131
|
+
autoSaveId,
|
|
139
132
|
direction,
|
|
140
133
|
dragState,
|
|
141
134
|
id: groupId,
|
|
@@ -143,7 +136,8 @@ function PanelGroupWithForwardedRef({
|
|
|
143
136
|
keyboardResizeByPixels,
|
|
144
137
|
layout,
|
|
145
138
|
onLayout,
|
|
146
|
-
panelDataArray,
|
|
139
|
+
panelDataArray: [],
|
|
140
|
+
storage,
|
|
147
141
|
});
|
|
148
142
|
|
|
149
143
|
const devWarningsRef = useRef<{
|
|
@@ -201,6 +195,8 @@ function PanelGroupWithForwardedRef({
|
|
|
201
195
|
if (!areEqual(prevLayout, safeLayout)) {
|
|
202
196
|
setLayout(safeLayout);
|
|
203
197
|
|
|
198
|
+
committedValuesRef.current.layout = safeLayout;
|
|
199
|
+
|
|
204
200
|
if (onLayout) {
|
|
205
201
|
onLayout(
|
|
206
202
|
safeLayout.map((sizePercentage) => ({
|
|
@@ -226,23 +222,28 @@ function PanelGroupWithForwardedRef({
|
|
|
226
222
|
);
|
|
227
223
|
|
|
228
224
|
useIsomorphicLayoutEffect(() => {
|
|
225
|
+
committedValuesRef.current.autoSaveId = autoSaveId;
|
|
229
226
|
committedValuesRef.current.direction = direction;
|
|
230
227
|
committedValuesRef.current.dragState = dragState;
|
|
231
228
|
committedValuesRef.current.id = groupId;
|
|
232
|
-
committedValuesRef.current.layout = layout;
|
|
233
229
|
committedValuesRef.current.onLayout = onLayout;
|
|
234
|
-
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
|
|
235
234
|
});
|
|
236
235
|
|
|
237
236
|
useWindowSplitterPanelGroupBehavior({
|
|
238
237
|
committedValuesRef,
|
|
239
238
|
groupId,
|
|
240
239
|
layout,
|
|
241
|
-
panelDataArray,
|
|
240
|
+
panelDataArray: committedValuesRef.current.panelDataArray,
|
|
242
241
|
setLayout,
|
|
243
242
|
});
|
|
244
243
|
|
|
245
244
|
useEffect(() => {
|
|
245
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
246
|
+
|
|
246
247
|
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
247
248
|
if (autoSaveId) {
|
|
248
249
|
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
@@ -258,79 +259,11 @@ function PanelGroupWithForwardedRef({
|
|
|
258
259
|
}
|
|
259
260
|
debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
|
|
260
261
|
}
|
|
261
|
-
}, [autoSaveId, layout,
|
|
262
|
+
}, [autoSaveId, layout, storage]);
|
|
262
263
|
|
|
263
|
-
// Once all panels have registered themselves,
|
|
264
|
-
// Compute the initial sizes based on default weights.
|
|
265
|
-
// This assumes that panels register during initial mount (no conditional rendering)!
|
|
266
264
|
useIsomorphicLayoutEffect(() => {
|
|
267
|
-
const {
|
|
268
|
-
if (layout.length === panelDataArray.length) {
|
|
269
|
-
// Only compute (or restore) default layout once per panel configuration.
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// If this panel has been configured to persist sizing information,
|
|
274
|
-
// default size should be restored from local storage if possible.
|
|
275
|
-
let unsafeLayout: number[] | null = null;
|
|
276
|
-
if (autoSaveId) {
|
|
277
|
-
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
281
|
-
if (groupSizePixels <= 0) {
|
|
282
|
-
if (
|
|
283
|
-
shouldMonitorPixelBasedConstraints(
|
|
284
|
-
panelDataArray.map(({ constraints }) => constraints)
|
|
285
|
-
)
|
|
286
|
-
) {
|
|
287
|
-
// Wait until the group has rendered a non-zero size before computing layout.
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (unsafeLayout == null) {
|
|
293
|
-
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
294
|
-
groupSizePixels,
|
|
295
|
-
panelDataArray,
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Validate even saved layouts in case something has changed since last render
|
|
300
|
-
// e.g. for pixel groups, this could be the size of the window
|
|
301
|
-
const validatedLayout = validatePanelGroupLayout({
|
|
302
|
-
groupSizePixels,
|
|
303
|
-
layout: unsafeLayout,
|
|
304
|
-
panelConstraints: panelDataArray.map(
|
|
305
|
-
(panelData) => panelData.constraints
|
|
306
|
-
),
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
if (!areEqual(layout, validatedLayout)) {
|
|
310
|
-
setLayout(validatedLayout);
|
|
311
|
-
}
|
|
265
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
312
266
|
|
|
313
|
-
if (onLayout) {
|
|
314
|
-
onLayout(
|
|
315
|
-
validatedLayout.map((sizePercentage) => ({
|
|
316
|
-
sizePercentage,
|
|
317
|
-
sizePixels: convertPercentageToPixels(
|
|
318
|
-
sizePercentage,
|
|
319
|
-
groupSizePixels
|
|
320
|
-
),
|
|
321
|
-
}))
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
callPanelCallbacks(
|
|
326
|
-
groupId,
|
|
327
|
-
panelDataArray,
|
|
328
|
-
validatedLayout,
|
|
329
|
-
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
330
|
-
);
|
|
331
|
-
}, [autoSaveId, layout, panelDataArray, storage]);
|
|
332
|
-
|
|
333
|
-
useIsomorphicLayoutEffect(() => {
|
|
334
267
|
const constraints = panelDataArray.map(({ constraints }) => constraints);
|
|
335
268
|
if (!shouldMonitorPixelBasedConstraints(constraints)) {
|
|
336
269
|
// Avoid the overhead of ResizeObserver if no pixel constraints require monitoring
|
|
@@ -358,6 +291,8 @@ function PanelGroupWithForwardedRef({
|
|
|
358
291
|
if (!areEqual(prevLayout, nextLayout)) {
|
|
359
292
|
setLayout(nextLayout);
|
|
360
293
|
|
|
294
|
+
committedValuesRef.current.layout = nextLayout;
|
|
295
|
+
|
|
361
296
|
if (onLayout) {
|
|
362
297
|
onLayout(
|
|
363
298
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -385,11 +320,13 @@ function PanelGroupWithForwardedRef({
|
|
|
385
320
|
resizeObserver.disconnect();
|
|
386
321
|
};
|
|
387
322
|
}
|
|
388
|
-
}, [groupId
|
|
323
|
+
}, [groupId]);
|
|
389
324
|
|
|
390
325
|
// DEV warnings
|
|
391
326
|
useEffect(() => {
|
|
392
327
|
if (isDevelopment) {
|
|
328
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
329
|
+
|
|
393
330
|
const {
|
|
394
331
|
didLogIdAndOrderWarning,
|
|
395
332
|
didLogPanelConstraintsWarning,
|
|
@@ -397,8 +334,6 @@ function PanelGroupWithForwardedRef({
|
|
|
397
334
|
} = devWarningsRef.current;
|
|
398
335
|
|
|
399
336
|
if (!didLogIdAndOrderWarning) {
|
|
400
|
-
const { panelDataArray } = committedValuesRef.current;
|
|
401
|
-
|
|
402
337
|
const panelIds = panelDataArray.map(({ id }) => id);
|
|
403
338
|
|
|
404
339
|
devWarningsRef.current.prevPanelIds = panelIds;
|
|
@@ -458,18 +393,6 @@ function PanelGroupWithForwardedRef({
|
|
|
458
393
|
panelDataArray,
|
|
459
394
|
} = committedValuesRef.current;
|
|
460
395
|
|
|
461
|
-
// See issues/211
|
|
462
|
-
if (panelDataArray.find(({ id }) => id === panelData.id) == null) {
|
|
463
|
-
setImperativeApiQueue((prev) => [
|
|
464
|
-
...prev,
|
|
465
|
-
{
|
|
466
|
-
panelData,
|
|
467
|
-
type: "collapse",
|
|
468
|
-
},
|
|
469
|
-
]);
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
396
|
if (panelData.constraints.collapsible) {
|
|
474
397
|
const panelConstraintsArray = panelDataArray.map(
|
|
475
398
|
(panelData) => panelData.constraints
|
|
@@ -508,6 +431,8 @@ function PanelGroupWithForwardedRef({
|
|
|
508
431
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
509
432
|
setLayout(nextLayout);
|
|
510
433
|
|
|
434
|
+
committedValuesRef.current.layout = nextLayout;
|
|
435
|
+
|
|
511
436
|
if (onLayout) {
|
|
512
437
|
onLayout(
|
|
513
438
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -542,18 +467,6 @@ function PanelGroupWithForwardedRef({
|
|
|
542
467
|
panelDataArray,
|
|
543
468
|
} = committedValuesRef.current;
|
|
544
469
|
|
|
545
|
-
// See issues/211
|
|
546
|
-
if (panelDataArray.find(({ id }) => id === panelData.id) == null) {
|
|
547
|
-
setImperativeApiQueue((prev) => [
|
|
548
|
-
...prev,
|
|
549
|
-
{
|
|
550
|
-
panelData,
|
|
551
|
-
type: "expand",
|
|
552
|
-
},
|
|
553
|
-
]);
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
470
|
if (panelData.constraints.collapsible) {
|
|
558
471
|
const panelConstraintsArray = panelDataArray.map(
|
|
559
472
|
(panelData) => panelData.constraints
|
|
@@ -595,6 +508,8 @@ function PanelGroupWithForwardedRef({
|
|
|
595
508
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
596
509
|
setLayout(nextLayout);
|
|
597
510
|
|
|
511
|
+
committedValuesRef.current.layout = nextLayout;
|
|
512
|
+
|
|
598
513
|
if (onLayout) {
|
|
599
514
|
onLayout(
|
|
600
515
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -643,6 +558,8 @@ function PanelGroupWithForwardedRef({
|
|
|
643
558
|
// This API should never read from committedValuesRef
|
|
644
559
|
const getPanelStyle = useCallback(
|
|
645
560
|
(panelData: PanelData) => {
|
|
561
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
562
|
+
|
|
646
563
|
const panelIndex = panelDataArray.indexOf(panelData);
|
|
647
564
|
|
|
648
565
|
return computePanelFlexBoxStyle({
|
|
@@ -652,7 +569,7 @@ function PanelGroupWithForwardedRef({
|
|
|
652
569
|
panelIndex,
|
|
653
570
|
});
|
|
654
571
|
},
|
|
655
|
-
[dragState, layout
|
|
572
|
+
[dragState, layout]
|
|
656
573
|
);
|
|
657
574
|
|
|
658
575
|
// External APIs are safe to memoize via committed values ref
|
|
@@ -684,22 +601,97 @@ function PanelGroupWithForwardedRef({
|
|
|
684
601
|
);
|
|
685
602
|
|
|
686
603
|
const registerPanel = useCallback((panelData: PanelData) => {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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,
|
|
701
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
|
+
),
|
|
702
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
|
+
}
|
|
703
695
|
}, []);
|
|
704
696
|
|
|
705
697
|
const registerResizeHandle = useCallback((dragHandleId: string) => {
|
|
@@ -789,6 +781,8 @@ function PanelGroupWithForwardedRef({
|
|
|
789
781
|
if (layoutChanged) {
|
|
790
782
|
setLayout(nextLayout);
|
|
791
783
|
|
|
784
|
+
committedValuesRef.current.layout = nextLayout;
|
|
785
|
+
|
|
792
786
|
if (onLayout) {
|
|
793
787
|
onLayout(
|
|
794
788
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -820,19 +814,6 @@ function PanelGroupWithForwardedRef({
|
|
|
820
814
|
panelDataArray,
|
|
821
815
|
} = committedValuesRef.current;
|
|
822
816
|
|
|
823
|
-
// See issues/211
|
|
824
|
-
if (panelDataArray.find(({ id }) => id === panelData.id) == null) {
|
|
825
|
-
setImperativeApiQueue((prev) => [
|
|
826
|
-
...prev,
|
|
827
|
-
{
|
|
828
|
-
panelData,
|
|
829
|
-
mixedSizes,
|
|
830
|
-
type: "resize",
|
|
831
|
-
},
|
|
832
|
-
]);
|
|
833
|
-
return;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
817
|
const panelConstraintsArray = panelDataArray.map(
|
|
837
818
|
(panelData) => panelData.constraints
|
|
838
819
|
);
|
|
@@ -863,6 +844,8 @@ function PanelGroupWithForwardedRef({
|
|
|
863
844
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
864
845
|
setLayout(nextLayout);
|
|
865
846
|
|
|
847
|
+
committedValuesRef.current.layout = nextLayout;
|
|
848
|
+
|
|
866
849
|
if (onLayout) {
|
|
867
850
|
onLayout(
|
|
868
851
|
nextLayout.map((sizePercentage) => ({
|
|
@@ -912,48 +895,107 @@ function PanelGroupWithForwardedRef({
|
|
|
912
895
|
setDragState(null);
|
|
913
896
|
}, []);
|
|
914
897
|
|
|
898
|
+
const unregisterPanelRef = useRef<{
|
|
899
|
+
pendingPanelIds: Set<string>;
|
|
900
|
+
timeout: NodeJS.Timeout | null;
|
|
901
|
+
}>({
|
|
902
|
+
pendingPanelIds: new Set(),
|
|
903
|
+
timeout: null,
|
|
904
|
+
});
|
|
915
905
|
const unregisterPanel = useCallback((panelData: PanelData) => {
|
|
916
|
-
|
|
906
|
+
const {
|
|
907
|
+
id: groupId,
|
|
908
|
+
layout: prevLayout,
|
|
909
|
+
onLayout,
|
|
910
|
+
panelDataArray,
|
|
911
|
+
} = committedValuesRef.current;
|
|
917
912
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
}
|
|
913
|
+
const index = panelDataArray.indexOf(panelData);
|
|
914
|
+
if (index >= 0) {
|
|
915
|
+
panelDataArray.splice(index, 1);
|
|
916
|
+
unregisterPanelRef.current.pendingPanelIds.add(panelData.id);
|
|
917
|
+
}
|
|
924
918
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
919
|
+
if (unregisterPanelRef.current.timeout != null) {
|
|
920
|
+
clearTimeout(unregisterPanelRef.current.timeout);
|
|
921
|
+
}
|
|
928
922
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
const
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
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];
|
|
942
944
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
if (!unmountDueToStrictMode) {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
|
|
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
|
+
);
|
|
946
988
|
}
|
|
989
|
+
|
|
990
|
+
callPanelCallbacks(
|
|
991
|
+
groupId,
|
|
992
|
+
panelDataArray,
|
|
993
|
+
nextLayout,
|
|
994
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
995
|
+
);
|
|
947
996
|
}
|
|
948
|
-
}
|
|
949
|
-
}, [
|
|
950
|
-
collapsePanel,
|
|
951
|
-
expandPanel,
|
|
952
|
-
imperativeApiQueue,
|
|
953
|
-
layout,
|
|
954
|
-
panelDataArray,
|
|
955
|
-
resizePanel,
|
|
956
|
-
]);
|
|
997
|
+
}, 0);
|
|
998
|
+
}, []);
|
|
957
999
|
|
|
958
1000
|
const context = useMemo(
|
|
959
1001
|
() => ({
|