react-resizable-panels 0.0.59 → 0.0.61
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 +10 -0
- package/dist/declarations/src/PanelGroup.d.ts +2 -2
- package/dist/react-resizable-panels.browser.cjs.js +226 -166
- package/dist/react-resizable-panels.browser.development.cjs.js +229 -169
- package/dist/react-resizable-panels.browser.development.esm.js +229 -169
- package/dist/react-resizable-panels.browser.esm.js +226 -166
- package/dist/react-resizable-panels.cjs.js +226 -166
- package/dist/react-resizable-panels.cjs.js.map +1 -1
- package/dist/react-resizable-panels.development.cjs.js +229 -169
- package/dist/react-resizable-panels.development.esm.js +229 -169
- package/dist/react-resizable-panels.development.node.cjs.js +273 -87
- package/dist/react-resizable-panels.development.node.esm.js +273 -87
- package/dist/react-resizable-panels.esm.js +226 -166
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +270 -84
- package/dist/react-resizable-panels.node.esm.js +270 -84
- package/package.json +1 -1
- package/src/Panel.ts +2 -0
- package/src/PanelGroup.ts +242 -208
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +12 -2
- package/src/utils/dom/getPanelElementsForGroup.ts +5 -0
|
@@ -67,6 +67,7 @@ function PanelWithForwardedRef({
|
|
|
67
67
|
expandPanel,
|
|
68
68
|
getPanelSize,
|
|
69
69
|
getPanelStyle,
|
|
70
|
+
groupId,
|
|
70
71
|
isPanelCollapsed,
|
|
71
72
|
registerPanel,
|
|
72
73
|
resizePanel,
|
|
@@ -132,6 +133,7 @@ function PanelWithForwardedRef({
|
|
|
132
133
|
// CSS selectors
|
|
133
134
|
"data-panel": "",
|
|
134
135
|
"data-panel-id": panelId,
|
|
136
|
+
"data-panel-group-id": groupId,
|
|
135
137
|
// e2e test attributes
|
|
136
138
|
"data-panel-collapsible": undefined,
|
|
137
139
|
"data-panel-size": undefined
|
|
@@ -606,6 +608,7 @@ function getResizeHandlePanelIds(groupId, handleId, panelsArray) {
|
|
|
606
608
|
|
|
607
609
|
function useWindowSplitterPanelGroupBehavior({
|
|
608
610
|
committedValuesRef,
|
|
611
|
+
eagerValuesRef,
|
|
609
612
|
groupId,
|
|
610
613
|
layout,
|
|
611
614
|
panelDataArray,
|
|
@@ -617,7 +620,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
617
620
|
useEffect(() => {
|
|
618
621
|
const {
|
|
619
622
|
panelDataArray
|
|
620
|
-
} =
|
|
623
|
+
} = eagerValuesRef.current;
|
|
621
624
|
const groupElement = getPanelGroupElement(groupId);
|
|
622
625
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
623
626
|
const handles = getResizeHandleElementsForGroup(groupId);
|
|
@@ -675,7 +678,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
675
678
|
return () => {
|
|
676
679
|
cleanupFunctions.forEach(cleanupFunction => cleanupFunction());
|
|
677
680
|
};
|
|
678
|
-
}, [committedValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
681
|
+
}, [committedValuesRef, eagerValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
679
682
|
}
|
|
680
683
|
|
|
681
684
|
function areEqual(arrayA, arrayB) {
|
|
@@ -772,6 +775,44 @@ function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initi
|
|
|
772
775
|
}
|
|
773
776
|
}
|
|
774
777
|
|
|
778
|
+
function calculateUnsafeDefaultLayout({
|
|
779
|
+
groupSizePixels,
|
|
780
|
+
panelDataArray
|
|
781
|
+
}) {
|
|
782
|
+
const layout = Array(panelDataArray.length);
|
|
783
|
+
const panelDataConstraints = panelDataArray.map(panelData => panelData.constraints);
|
|
784
|
+
let numPanelsWithSizes = 0;
|
|
785
|
+
let remainingSize = 100;
|
|
786
|
+
|
|
787
|
+
// Distribute default sizes first
|
|
788
|
+
for (let index = 0; index < panelDataArray.length; index++) {
|
|
789
|
+
const {
|
|
790
|
+
defaultSizePercentage
|
|
791
|
+
} = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
|
|
792
|
+
if (defaultSizePercentage != null) {
|
|
793
|
+
numPanelsWithSizes++;
|
|
794
|
+
layout[index] = defaultSizePercentage;
|
|
795
|
+
remainingSize -= defaultSizePercentage;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Remaining size should be distributed evenly between panels without default sizes
|
|
800
|
+
for (let index = 0; index < panelDataArray.length; index++) {
|
|
801
|
+
const {
|
|
802
|
+
defaultSizePercentage
|
|
803
|
+
} = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
|
|
804
|
+
if (defaultSizePercentage != null) {
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
|
|
808
|
+
const size = remainingSize / numRemainingPanels;
|
|
809
|
+
numPanelsWithSizes++;
|
|
810
|
+
layout[index] = size;
|
|
811
|
+
remainingSize -= size;
|
|
812
|
+
}
|
|
813
|
+
return layout;
|
|
814
|
+
}
|
|
815
|
+
|
|
775
816
|
function convertPercentageToPixels(percentage, groupSizePixels) {
|
|
776
817
|
return percentage / 100 * groupSizePixels;
|
|
777
818
|
}
|
|
@@ -922,6 +963,10 @@ function debounce(callback, durationMs = 10) {
|
|
|
922
963
|
return callable;
|
|
923
964
|
}
|
|
924
965
|
|
|
966
|
+
function getPanelElementsForGroup(groupId) {
|
|
967
|
+
return Array.from(document.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
968
|
+
}
|
|
969
|
+
|
|
925
970
|
// PanelGroup might be rendering in a server-side environment where localStorage is not available
|
|
926
971
|
// or on a browser with cookies/storage disabled.
|
|
927
972
|
// In either case, this function avoids accessing localStorage until needed,
|
|
@@ -977,6 +1022,15 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
|
977
1022
|
} catch (error) {}
|
|
978
1023
|
return null;
|
|
979
1024
|
}
|
|
1025
|
+
function loadPanelLayout(autoSaveId, panels, storage) {
|
|
1026
|
+
const state = loadSerializedPanelGroupState(autoSaveId, storage);
|
|
1027
|
+
if (state) {
|
|
1028
|
+
var _state$key;
|
|
1029
|
+
const key = getSerializationKey(panels);
|
|
1030
|
+
return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
|
|
1031
|
+
}
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
980
1034
|
function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
|
|
981
1035
|
const key = getSerializationKey(panels);
|
|
982
1036
|
const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
|
|
@@ -988,6 +1042,12 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
|
|
|
988
1042
|
}
|
|
989
1043
|
}
|
|
990
1044
|
|
|
1045
|
+
function shouldMonitorPixelBasedConstraints(constraints) {
|
|
1046
|
+
return constraints.some(constraints => {
|
|
1047
|
+
return constraints.collapsedSizePixels !== undefined || constraints.maxSizePixels !== undefined || constraints.minSizePixels !== undefined;
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
|
|
991
1051
|
// All units must be in percentages; pixel values should be pre-converted
|
|
992
1052
|
function validatePanelGroupLayout({
|
|
993
1053
|
groupSizePixels,
|
|
@@ -1056,7 +1116,7 @@ const defaultStorage = {
|
|
|
1056
1116
|
};
|
|
1057
1117
|
const debounceMap = {};
|
|
1058
1118
|
function PanelGroupWithForwardedRef({
|
|
1059
|
-
autoSaveId,
|
|
1119
|
+
autoSaveId = null,
|
|
1060
1120
|
children,
|
|
1061
1121
|
className: classNameFromProps = "",
|
|
1062
1122
|
dataAttributes,
|
|
@@ -1073,20 +1133,22 @@ function PanelGroupWithForwardedRef({
|
|
|
1073
1133
|
const groupId = useUniqueId(idFromProps);
|
|
1074
1134
|
const [dragState, setDragState] = useState(null);
|
|
1075
1135
|
const [layout, setLayout] = useState([]);
|
|
1076
|
-
const [panelDataArray, setPanelDataArray] = useState([]);
|
|
1077
1136
|
const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
|
|
1078
1137
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
1079
1138
|
const prevDeltaRef = useRef(0);
|
|
1080
|
-
const [imperativeApiQueue, setImperativeApiQueue] = useState([]);
|
|
1081
1139
|
const committedValuesRef = useRef({
|
|
1140
|
+
autoSaveId,
|
|
1082
1141
|
direction,
|
|
1083
1142
|
dragState,
|
|
1084
1143
|
id: groupId,
|
|
1085
1144
|
keyboardResizeByPercentage,
|
|
1086
1145
|
keyboardResizeByPixels,
|
|
1087
|
-
layout,
|
|
1088
1146
|
onLayout,
|
|
1089
|
-
|
|
1147
|
+
storage
|
|
1148
|
+
});
|
|
1149
|
+
const eagerValuesRef = useRef({
|
|
1150
|
+
layout,
|
|
1151
|
+
panelDataArray: []
|
|
1090
1152
|
});
|
|
1091
1153
|
useRef({
|
|
1092
1154
|
didLogIdAndOrderWarning: false,
|
|
@@ -1097,9 +1159,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1097
1159
|
getId: () => committedValuesRef.current.id,
|
|
1098
1160
|
getLayout: () => {
|
|
1099
1161
|
const {
|
|
1100
|
-
id: groupId
|
|
1101
|
-
layout
|
|
1162
|
+
id: groupId
|
|
1102
1163
|
} = committedValuesRef.current;
|
|
1164
|
+
const {
|
|
1165
|
+
layout
|
|
1166
|
+
} = eagerValuesRef.current;
|
|
1103
1167
|
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1104
1168
|
return layout.map(sizePercentage => {
|
|
1105
1169
|
return {
|
|
@@ -1111,10 +1175,12 @@ function PanelGroupWithForwardedRef({
|
|
|
1111
1175
|
setLayout: mixedSizes => {
|
|
1112
1176
|
const {
|
|
1113
1177
|
id: groupId,
|
|
1178
|
+
onLayout
|
|
1179
|
+
} = committedValuesRef.current;
|
|
1180
|
+
const {
|
|
1114
1181
|
layout: prevLayout,
|
|
1115
|
-
onLayout,
|
|
1116
1182
|
panelDataArray
|
|
1117
|
-
} =
|
|
1183
|
+
} = eagerValuesRef.current;
|
|
1118
1184
|
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1119
1185
|
const unsafeLayout = mixedSizes.map(mixedSize => getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels));
|
|
1120
1186
|
const safeLayout = validatePanelGroupLayout({
|
|
@@ -1124,6 +1190,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1124
1190
|
});
|
|
1125
1191
|
if (!areEqual(prevLayout, safeLayout)) {
|
|
1126
1192
|
setLayout(safeLayout);
|
|
1193
|
+
eagerValuesRef.current.layout = safeLayout;
|
|
1127
1194
|
if (onLayout) {
|
|
1128
1195
|
onLayout(safeLayout.map(sizePercentage => ({
|
|
1129
1196
|
sizePercentage,
|
|
@@ -1134,14 +1201,20 @@ function PanelGroupWithForwardedRef({
|
|
|
1134
1201
|
}
|
|
1135
1202
|
}
|
|
1136
1203
|
}), []);
|
|
1204
|
+
|
|
1137
1205
|
useWindowSplitterPanelGroupBehavior({
|
|
1138
1206
|
committedValuesRef,
|
|
1207
|
+
eagerValuesRef,
|
|
1139
1208
|
groupId,
|
|
1140
1209
|
layout,
|
|
1141
|
-
panelDataArray,
|
|
1210
|
+
panelDataArray: eagerValuesRef.current.panelDataArray,
|
|
1142
1211
|
setLayout
|
|
1143
1212
|
});
|
|
1144
1213
|
useEffect(() => {
|
|
1214
|
+
const {
|
|
1215
|
+
panelDataArray
|
|
1216
|
+
} = eagerValuesRef.current;
|
|
1217
|
+
|
|
1145
1218
|
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
1146
1219
|
if (autoSaveId) {
|
|
1147
1220
|
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
@@ -1154,7 +1227,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1154
1227
|
}
|
|
1155
1228
|
debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
|
|
1156
1229
|
}
|
|
1157
|
-
}, [autoSaveId, layout,
|
|
1230
|
+
}, [autoSaveId, layout, storage]);
|
|
1158
1231
|
|
|
1159
1232
|
// DEV warnings
|
|
1160
1233
|
useEffect(() => {
|
|
@@ -1162,22 +1235,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1162
1235
|
|
|
1163
1236
|
// External APIs are safe to memoize via committed values ref
|
|
1164
1237
|
const collapsePanel = useCallback(panelData => {
|
|
1238
|
+
const {
|
|
1239
|
+
onLayout
|
|
1240
|
+
} = committedValuesRef.current;
|
|
1165
1241
|
const {
|
|
1166
1242
|
layout: prevLayout,
|
|
1167
|
-
onLayout,
|
|
1168
1243
|
panelDataArray
|
|
1169
|
-
} =
|
|
1170
|
-
|
|
1171
|
-
// See issues/211
|
|
1172
|
-
if (panelDataArray.find(({
|
|
1173
|
-
id
|
|
1174
|
-
}) => id === panelData.id) == null) {
|
|
1175
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1176
|
-
panelData,
|
|
1177
|
-
type: "collapse"
|
|
1178
|
-
}]);
|
|
1179
|
-
return;
|
|
1180
|
-
}
|
|
1244
|
+
} = eagerValuesRef.current;
|
|
1181
1245
|
if (panelData.constraints.collapsible) {
|
|
1182
1246
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1183
1247
|
const {
|
|
@@ -1202,6 +1266,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1202
1266
|
});
|
|
1203
1267
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1204
1268
|
setLayout(nextLayout);
|
|
1269
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1205
1270
|
if (onLayout) {
|
|
1206
1271
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1207
1272
|
sizePercentage,
|
|
@@ -1216,22 +1281,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1216
1281
|
|
|
1217
1282
|
// External APIs are safe to memoize via committed values ref
|
|
1218
1283
|
const expandPanel = useCallback(panelData => {
|
|
1284
|
+
const {
|
|
1285
|
+
onLayout
|
|
1286
|
+
} = committedValuesRef.current;
|
|
1219
1287
|
const {
|
|
1220
1288
|
layout: prevLayout,
|
|
1221
|
-
onLayout,
|
|
1222
1289
|
panelDataArray
|
|
1223
|
-
} =
|
|
1224
|
-
|
|
1225
|
-
// See issues/211
|
|
1226
|
-
if (panelDataArray.find(({
|
|
1227
|
-
id
|
|
1228
|
-
}) => id === panelData.id) == null) {
|
|
1229
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1230
|
-
panelData,
|
|
1231
|
-
type: "expand"
|
|
1232
|
-
}]);
|
|
1233
|
-
return;
|
|
1234
|
-
}
|
|
1290
|
+
} = eagerValuesRef.current;
|
|
1235
1291
|
if (panelData.constraints.collapsible) {
|
|
1236
1292
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1237
1293
|
const {
|
|
@@ -1257,6 +1313,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1257
1313
|
});
|
|
1258
1314
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1259
1315
|
setLayout(nextLayout);
|
|
1316
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1260
1317
|
if (onLayout) {
|
|
1261
1318
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1262
1319
|
sizePercentage,
|
|
@@ -1274,7 +1331,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1274
1331
|
const {
|
|
1275
1332
|
layout,
|
|
1276
1333
|
panelDataArray
|
|
1277
|
-
} =
|
|
1334
|
+
} = eagerValuesRef.current;
|
|
1278
1335
|
const {
|
|
1279
1336
|
panelSizePercentage,
|
|
1280
1337
|
panelSizePixels
|
|
@@ -1287,6 +1344,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1287
1344
|
|
|
1288
1345
|
// This API should never read from committedValuesRef
|
|
1289
1346
|
const getPanelStyle = useCallback(panelData => {
|
|
1347
|
+
const {
|
|
1348
|
+
panelDataArray
|
|
1349
|
+
} = eagerValuesRef.current;
|
|
1290
1350
|
const panelIndex = panelDataArray.indexOf(panelData);
|
|
1291
1351
|
return computePanelFlexBoxStyle({
|
|
1292
1352
|
dragState,
|
|
@@ -1294,14 +1354,14 @@ function PanelGroupWithForwardedRef({
|
|
|
1294
1354
|
panelData: panelDataArray,
|
|
1295
1355
|
panelIndex
|
|
1296
1356
|
});
|
|
1297
|
-
}, [dragState, layout
|
|
1357
|
+
}, [dragState, layout]);
|
|
1298
1358
|
|
|
1299
1359
|
// External APIs are safe to memoize via committed values ref
|
|
1300
1360
|
const isPanelCollapsed = useCallback(panelData => {
|
|
1301
1361
|
const {
|
|
1302
1362
|
layout,
|
|
1303
1363
|
panelDataArray
|
|
1304
|
-
} =
|
|
1364
|
+
} = eagerValuesRef.current;
|
|
1305
1365
|
const {
|
|
1306
1366
|
collapsedSizePercentage,
|
|
1307
1367
|
collapsible,
|
|
@@ -1315,7 +1375,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1315
1375
|
const {
|
|
1316
1376
|
layout,
|
|
1317
1377
|
panelDataArray
|
|
1318
|
-
} =
|
|
1378
|
+
} = eagerValuesRef.current;
|
|
1319
1379
|
const {
|
|
1320
1380
|
collapsedSizePercentage,
|
|
1321
1381
|
collapsible,
|
|
@@ -1324,22 +1384,82 @@ function PanelGroupWithForwardedRef({
|
|
|
1324
1384
|
return !collapsible || panelSizePercentage > collapsedSizePercentage;
|
|
1325
1385
|
}, [groupId]);
|
|
1326
1386
|
const registerPanel = useCallback(panelData => {
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1387
|
+
const {
|
|
1388
|
+
autoSaveId,
|
|
1389
|
+
id: groupId,
|
|
1390
|
+
onLayout,
|
|
1391
|
+
storage
|
|
1392
|
+
} = committedValuesRef.current;
|
|
1393
|
+
const {
|
|
1394
|
+
layout: prevLayout,
|
|
1395
|
+
panelDataArray
|
|
1396
|
+
} = eagerValuesRef.current;
|
|
1397
|
+
panelDataArray.push(panelData);
|
|
1398
|
+
panelDataArray.sort((panelA, panelB) => {
|
|
1399
|
+
const orderA = panelA.order;
|
|
1400
|
+
const orderB = panelB.order;
|
|
1401
|
+
if (orderA == null && orderB == null) {
|
|
1402
|
+
return 0;
|
|
1403
|
+
} else if (orderA == null) {
|
|
1404
|
+
return -1;
|
|
1405
|
+
} else if (orderB == null) {
|
|
1406
|
+
return 1;
|
|
1407
|
+
} else {
|
|
1408
|
+
return orderA - orderB;
|
|
1409
|
+
}
|
|
1410
|
+
});
|
|
1411
|
+
|
|
1412
|
+
// Wait until all panels have registered before we try to compute layout;
|
|
1413
|
+
// doing it earlier is both wasteful and may trigger misleading warnings in development mode.
|
|
1414
|
+
const panelElements = getPanelElementsForGroup(groupId);
|
|
1415
|
+
if (panelElements.length !== panelDataArray.length) {
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
// If this panel has been configured to persist sizing information,
|
|
1420
|
+
// default size should be restored from local storage if possible.
|
|
1421
|
+
let unsafeLayout = null;
|
|
1422
|
+
if (autoSaveId) {
|
|
1423
|
+
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
1424
|
+
}
|
|
1425
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1426
|
+
if (groupSizePixels <= 0) {
|
|
1427
|
+
if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
|
|
1428
|
+
constraints
|
|
1429
|
+
}) => constraints))) {
|
|
1430
|
+
// Wait until the group has rendered a non-zero size before computing layout.
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
if (unsafeLayout == null) {
|
|
1435
|
+
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1436
|
+
groupSizePixels,
|
|
1437
|
+
panelDataArray
|
|
1341
1438
|
});
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
// Validate even saved layouts in case something has changed since last render
|
|
1442
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1443
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1444
|
+
groupSizePixels,
|
|
1445
|
+
layout: unsafeLayout,
|
|
1446
|
+
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1342
1447
|
});
|
|
1448
|
+
|
|
1449
|
+
// Offscreen mode makes this a bit weird;
|
|
1450
|
+
// Panels unregister when hidden and re-register when shown again,
|
|
1451
|
+
// but the overall layout doesn't change between these two cases.
|
|
1452
|
+
setLayout(nextLayout);
|
|
1453
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1454
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1455
|
+
if (onLayout) {
|
|
1456
|
+
onLayout(nextLayout.map(sizePercentage => ({
|
|
1457
|
+
sizePercentage,
|
|
1458
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1459
|
+
})));
|
|
1460
|
+
}
|
|
1461
|
+
callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1462
|
+
}
|
|
1343
1463
|
}, []);
|
|
1344
1464
|
const registerResizeHandle = useCallback(dragHandleId => {
|
|
1345
1465
|
return function resizeHandler(event) {
|
|
@@ -1350,10 +1470,12 @@ function PanelGroupWithForwardedRef({
|
|
|
1350
1470
|
id: groupId,
|
|
1351
1471
|
keyboardResizeByPercentage,
|
|
1352
1472
|
keyboardResizeByPixels,
|
|
1353
|
-
onLayout
|
|
1354
|
-
panelDataArray,
|
|
1355
|
-
layout: prevLayout
|
|
1473
|
+
onLayout
|
|
1356
1474
|
} = committedValuesRef.current;
|
|
1475
|
+
const {
|
|
1476
|
+
layout: prevLayout,
|
|
1477
|
+
panelDataArray
|
|
1478
|
+
} = eagerValuesRef.current;
|
|
1357
1479
|
const {
|
|
1358
1480
|
initialLayout
|
|
1359
1481
|
} = dragState !== null && dragState !== void 0 ? dragState : {};
|
|
@@ -1409,6 +1531,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1409
1531
|
}
|
|
1410
1532
|
if (layoutChanged) {
|
|
1411
1533
|
setLayout(nextLayout);
|
|
1534
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1412
1535
|
if (onLayout) {
|
|
1413
1536
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1414
1537
|
sizePercentage,
|
|
@@ -1422,23 +1545,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1422
1545
|
|
|
1423
1546
|
// External APIs are safe to memoize via committed values ref
|
|
1424
1547
|
const resizePanel = useCallback((panelData, mixedSizes) => {
|
|
1548
|
+
const {
|
|
1549
|
+
onLayout
|
|
1550
|
+
} = committedValuesRef.current;
|
|
1425
1551
|
const {
|
|
1426
1552
|
layout: prevLayout,
|
|
1427
|
-
onLayout,
|
|
1428
1553
|
panelDataArray
|
|
1429
|
-
} =
|
|
1430
|
-
|
|
1431
|
-
// See issues/211
|
|
1432
|
-
if (panelDataArray.find(({
|
|
1433
|
-
id
|
|
1434
|
-
}) => id === panelData.id) == null) {
|
|
1435
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1436
|
-
panelData,
|
|
1437
|
-
mixedSizes,
|
|
1438
|
-
type: "resize"
|
|
1439
|
-
}]);
|
|
1440
|
-
return;
|
|
1441
|
-
}
|
|
1554
|
+
} = eagerValuesRef.current;
|
|
1442
1555
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1443
1556
|
const {
|
|
1444
1557
|
groupSizePixels,
|
|
@@ -1458,6 +1571,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1458
1571
|
});
|
|
1459
1572
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1460
1573
|
setLayout(nextLayout);
|
|
1574
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1461
1575
|
if (onLayout) {
|
|
1462
1576
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1463
1577
|
sizePercentage,
|
|
@@ -1469,9 +1583,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1469
1583
|
}, [groupId]);
|
|
1470
1584
|
const startDragging = useCallback((dragHandleId, event) => {
|
|
1471
1585
|
const {
|
|
1472
|
-
direction
|
|
1473
|
-
layout
|
|
1586
|
+
direction
|
|
1474
1587
|
} = committedValuesRef.current;
|
|
1588
|
+
const {
|
|
1589
|
+
layout
|
|
1590
|
+
} = eagerValuesRef.current;
|
|
1475
1591
|
const handleElement = getResizeHandleElement(dragHandleId);
|
|
1476
1592
|
const initialCursorPosition = getResizeEventCursorPosition(direction, event);
|
|
1477
1593
|
setDragState({
|
|
@@ -1485,16 +1601,86 @@ function PanelGroupWithForwardedRef({
|
|
|
1485
1601
|
resetGlobalCursorStyle();
|
|
1486
1602
|
setDragState(null);
|
|
1487
1603
|
}, []);
|
|
1604
|
+
const unregisterPanelRef = useRef({
|
|
1605
|
+
pendingPanelIds: new Set(),
|
|
1606
|
+
timeout: null
|
|
1607
|
+
});
|
|
1488
1608
|
const unregisterPanel = useCallback(panelData => {
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1609
|
+
const {
|
|
1610
|
+
id: groupId,
|
|
1611
|
+
onLayout
|
|
1612
|
+
} = committedValuesRef.current;
|
|
1613
|
+
const {
|
|
1614
|
+
layout: prevLayout,
|
|
1615
|
+
panelDataArray
|
|
1616
|
+
} = eagerValuesRef.current;
|
|
1617
|
+
const index = panelDataArray.indexOf(panelData);
|
|
1618
|
+
if (index >= 0) {
|
|
1619
|
+
panelDataArray.splice(index, 1);
|
|
1620
|
+
unregisterPanelRef.current.pendingPanelIds.add(panelData.id);
|
|
1621
|
+
}
|
|
1622
|
+
if (unregisterPanelRef.current.timeout != null) {
|
|
1623
|
+
clearTimeout(unregisterPanelRef.current.timeout);
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
// Batch panel unmounts so that we only calculate layout once;
|
|
1627
|
+
// This is more efficient and avoids misleading warnings in development mode.
|
|
1628
|
+
// We can't check the DOM to detect this because Panel elements have not yet been removed.
|
|
1629
|
+
unregisterPanelRef.current.timeout = setTimeout(() => {
|
|
1630
|
+
const {
|
|
1631
|
+
pendingPanelIds
|
|
1632
|
+
} = unregisterPanelRef.current;
|
|
1633
|
+
const map = panelIdToLastNotifiedMixedSizesMapRef.current;
|
|
1634
|
+
|
|
1635
|
+
// TRICKY
|
|
1636
|
+
// Strict effects mode
|
|
1637
|
+
let unmountDueToStrictMode = false;
|
|
1638
|
+
pendingPanelIds.forEach(panelId => {
|
|
1639
|
+
pendingPanelIds.delete(panelId);
|
|
1640
|
+
if (panelDataArray.find(({
|
|
1641
|
+
id
|
|
1642
|
+
}) => id === panelId) == null) {
|
|
1643
|
+
unmountDueToStrictMode = true;
|
|
1644
|
+
|
|
1645
|
+
// TRICKY
|
|
1646
|
+
// When a panel is removed from the group, we should delete the most recent prev-size entry for it.
|
|
1647
|
+
// If we don't do this, then a conditionally rendered panel might not call onResize when it's re-mounted.
|
|
1648
|
+
// Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
|
|
1649
|
+
delete map[panelData.id];
|
|
1650
|
+
}
|
|
1651
|
+
});
|
|
1652
|
+
if (!unmountDueToStrictMode) {
|
|
1653
|
+
return;
|
|
1495
1654
|
}
|
|
1496
|
-
|
|
1497
|
-
|
|
1655
|
+
if (panelDataArray.length === 0) {
|
|
1656
|
+
// The group is unmounting; skip layout calculation.
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1660
|
+
let unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1661
|
+
groupSizePixels,
|
|
1662
|
+
panelDataArray
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1665
|
+
// Validate even saved layouts in case something has changed since last render
|
|
1666
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1667
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1668
|
+
groupSizePixels,
|
|
1669
|
+
layout: unsafeLayout,
|
|
1670
|
+
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1671
|
+
});
|
|
1672
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1673
|
+
setLayout(nextLayout);
|
|
1674
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1675
|
+
if (onLayout) {
|
|
1676
|
+
onLayout(nextLayout.map(sizePercentage => ({
|
|
1677
|
+
sizePercentage,
|
|
1678
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1679
|
+
})));
|
|
1680
|
+
}
|
|
1681
|
+
callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1682
|
+
}
|
|
1683
|
+
}, 0);
|
|
1498
1684
|
}, []);
|
|
1499
1685
|
const context = useMemo(() => ({
|
|
1500
1686
|
collapsePanel,
|
package/package.json
CHANGED
package/src/Panel.ts
CHANGED
|
@@ -115,6 +115,7 @@ export function PanelWithForwardedRef({
|
|
|
115
115
|
expandPanel,
|
|
116
116
|
getPanelSize,
|
|
117
117
|
getPanelStyle,
|
|
118
|
+
groupId,
|
|
118
119
|
isPanelCollapsed,
|
|
119
120
|
registerPanel,
|
|
120
121
|
resizePanel,
|
|
@@ -250,6 +251,7 @@ export function PanelWithForwardedRef({
|
|
|
250
251
|
// CSS selectors
|
|
251
252
|
"data-panel": "",
|
|
252
253
|
"data-panel-id": panelId,
|
|
254
|
+
"data-panel-group-id": groupId,
|
|
253
255
|
|
|
254
256
|
// e2e test attributes
|
|
255
257
|
"data-panel-collapsible": isDevelopment
|