react-resizable-panels 1.0.1 → 1.0.3

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.3
4
+
5
+ - Remember most recently expanded panel size in local storage (#234)
6
+
7
+ ## 1.0.2
8
+
9
+ - Change local storage key for persisted sizes to avoid restoring pixel-based sizes (#233)
10
+
3
11
  ## 1.0.1
4
12
 
5
13
  - Small bug fix to guard against saving an incorrect panel layout to local storage
@@ -961,11 +961,15 @@ function initializeDefaultStorage(storageObject) {
961
961
  }
962
962
  }
963
963
 
964
+ function getPanelGroupKey(autoSaveId) {
965
+ return `react-resizable-panels:${autoSaveId}`;
966
+ }
967
+
964
968
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
965
969
  // so they should not be used as part of the serialization key.
966
970
  // Using the min/max size attributes should work well enough as a backup.
967
971
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
968
- function getSerializationKey(panels) {
972
+ function getPanelKey(panels) {
969
973
  return panels.map(panel => {
970
974
  const {
971
975
  constraints,
@@ -976,13 +980,14 @@ function getSerializationKey(panels) {
976
980
  if (idIsFromProps) {
977
981
  return id;
978
982
  } else {
979
- return `${order}:${JSON.stringify(constraints)}`;
983
+ return order ? `${order}:${JSON.stringify(constraints)}` : JSON.stringify(constraints);
980
984
  }
981
985
  }).sort((a, b) => a.localeCompare(b)).join(",");
982
986
  }
983
987
  function loadSerializedPanelGroupState(autoSaveId, storage) {
984
988
  try {
985
- const serialized = storage.getItem(`PanelGroup:sizes:${autoSaveId}`);
989
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
990
+ const serialized = storage.getItem(panelGroupKey);
986
991
  if (serialized) {
987
992
  const parsed = JSON.parse(serialized);
988
993
  if (typeof parsed === "object" && parsed != null) {
@@ -992,21 +997,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
992
997
  } catch (error) {}
993
998
  return null;
994
999
  }
995
- function loadPanelLayout(autoSaveId, panels, storage) {
996
- const state = loadSerializedPanelGroupState(autoSaveId, storage);
997
- if (state) {
998
- var _state$key;
999
- const key = getSerializationKey(panels);
1000
- return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
1001
- }
1002
- return null;
1000
+ function loadPanelGroupState(autoSaveId, panels, storage) {
1001
+ var _loadSerializedPanelG, _state$panelKey;
1002
+ const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
1003
+ const panelKey = getPanelKey(panels);
1004
+ return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
1003
1005
  }
1004
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1005
- const key = getSerializationKey(panels);
1006
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
1007
- state[key] = sizes;
1006
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
1007
+ var _loadSerializedPanelG2;
1008
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
1009
+ const panelKey = getPanelKey(panels);
1010
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
1011
+ state[panelKey] = {
1012
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
1013
+ layout: sizes
1014
+ };
1008
1015
  try {
1009
- storage.setItem(`PanelGroup:sizes:${autoSaveId}`, JSON.stringify(state));
1016
+ storage.setItem(panelGroupKey, JSON.stringify(state));
1010
1017
  } catch (error) {
1011
1018
  console.error(error);
1012
1019
  }
@@ -1103,7 +1110,6 @@ function PanelGroupWithForwardedRef({
1103
1110
  const groupId = useUniqueId(idFromProps);
1104
1111
  const [dragState, setDragState] = useState(null);
1105
1112
  const [layout, setLayout] = useState([]);
1106
- useState([]);
1107
1113
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1108
1114
  const panelSizeBeforeCollapseRef = useRef(new Map());
1109
1115
  const prevDeltaRef = useRef(0);
@@ -1186,13 +1192,15 @@ function PanelGroupWithForwardedRef({
1186
1192
 
1187
1193
  // Limit the frequency of localStorage updates.
1188
1194
  if (debouncedSave == null) {
1189
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1195
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1190
1196
  debounceMap[autoSaveId] = debouncedSave;
1191
1197
  }
1192
1198
 
1193
- // Clone panel data array before saving since this array is mutated.
1194
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1195
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1199
+ // Clone mutable data before passing to the debounced function,
1200
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1201
+ const clonedPanelDataArray = [...panelDataArray];
1202
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1203
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1196
1204
  }
1197
1205
  }, [autoSaveId, layout, storage]);
1198
1206
 
@@ -1379,7 +1387,11 @@ function PanelGroupWithForwardedRef({
1379
1387
  // default size should be restored from local storage if possible.
1380
1388
  let unsafeLayout = null;
1381
1389
  if (autoSaveId) {
1382
- unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1390
+ const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
1391
+ if (state) {
1392
+ panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
1393
+ unsafeLayout = state.layout;
1394
+ }
1383
1395
  }
1384
1396
  if (unsafeLayout == null) {
1385
1397
  unsafeLayout = calculateUnsafeDefaultLayout({
@@ -977,11 +977,15 @@ function initializeDefaultStorage(storageObject) {
977
977
  }
978
978
  }
979
979
 
980
+ function getPanelGroupKey(autoSaveId) {
981
+ return `react-resizable-panels:${autoSaveId}`;
982
+ }
983
+
980
984
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
981
985
  // so they should not be used as part of the serialization key.
982
986
  // Using the min/max size attributes should work well enough as a backup.
983
987
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
984
- function getSerializationKey(panels) {
988
+ function getPanelKey(panels) {
985
989
  return panels.map(panel => {
986
990
  const {
987
991
  constraints,
@@ -992,13 +996,14 @@ function getSerializationKey(panels) {
992
996
  if (idIsFromProps) {
993
997
  return id;
994
998
  } else {
995
- return `${order}:${JSON.stringify(constraints)}`;
999
+ return order ? `${order}:${JSON.stringify(constraints)}` : JSON.stringify(constraints);
996
1000
  }
997
1001
  }).sort((a, b) => a.localeCompare(b)).join(",");
998
1002
  }
999
1003
  function loadSerializedPanelGroupState(autoSaveId, storage) {
1000
1004
  try {
1001
- const serialized = storage.getItem(`PanelGroup:sizes:${autoSaveId}`);
1005
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
1006
+ const serialized = storage.getItem(panelGroupKey);
1002
1007
  if (serialized) {
1003
1008
  const parsed = JSON.parse(serialized);
1004
1009
  if (typeof parsed === "object" && parsed != null) {
@@ -1008,21 +1013,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
1008
1013
  } catch (error) {}
1009
1014
  return null;
1010
1015
  }
1011
- function loadPanelLayout(autoSaveId, panels, storage) {
1012
- const state = loadSerializedPanelGroupState(autoSaveId, storage);
1013
- if (state) {
1014
- var _state$key;
1015
- const key = getSerializationKey(panels);
1016
- return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
1017
- }
1018
- return null;
1016
+ function loadPanelGroupState(autoSaveId, panels, storage) {
1017
+ var _loadSerializedPanelG, _state$panelKey;
1018
+ const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
1019
+ const panelKey = getPanelKey(panels);
1020
+ return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
1019
1021
  }
1020
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1021
- const key = getSerializationKey(panels);
1022
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
1023
- state[key] = sizes;
1022
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
1023
+ var _loadSerializedPanelG2;
1024
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
1025
+ const panelKey = getPanelKey(panels);
1026
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
1027
+ state[panelKey] = {
1028
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
1029
+ layout: sizes
1030
+ };
1024
1031
  try {
1025
- storage.setItem(`PanelGroup:sizes:${autoSaveId}`, JSON.stringify(state));
1032
+ storage.setItem(panelGroupKey, JSON.stringify(state));
1026
1033
  } catch (error) {
1027
1034
  console.error(error);
1028
1035
  }
@@ -1166,7 +1173,6 @@ function PanelGroupWithForwardedRef({
1166
1173
  const groupId = useUniqueId(idFromProps);
1167
1174
  const [dragState, setDragState] = useState(null);
1168
1175
  const [layout, setLayout] = useState([]);
1169
- useState([]);
1170
1176
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1171
1177
  const panelSizeBeforeCollapseRef = useRef(new Map());
1172
1178
  const prevDeltaRef = useRef(0);
@@ -1249,13 +1255,15 @@ function PanelGroupWithForwardedRef({
1249
1255
 
1250
1256
  // Limit the frequency of localStorage updates.
1251
1257
  if (debouncedSave == null) {
1252
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1258
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1253
1259
  debounceMap[autoSaveId] = debouncedSave;
1254
1260
  }
1255
1261
 
1256
- // Clone panel data array before saving since this array is mutated.
1257
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1258
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1262
+ // Clone mutable data before passing to the debounced function,
1263
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1264
+ const clonedPanelDataArray = [...panelDataArray];
1265
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1266
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1259
1267
  }
1260
1268
  }, [autoSaveId, layout, storage]);
1261
1269
 
@@ -1484,7 +1492,11 @@ function PanelGroupWithForwardedRef({
1484
1492
  // default size should be restored from local storage if possible.
1485
1493
  let unsafeLayout = null;
1486
1494
  if (autoSaveId) {
1487
- unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1495
+ const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
1496
+ if (state) {
1497
+ panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
1498
+ unsafeLayout = state.layout;
1499
+ }
1488
1500
  }
1489
1501
  if (unsafeLayout == null) {
1490
1502
  unsafeLayout = calculateUnsafeDefaultLayout({
@@ -953,11 +953,15 @@ function initializeDefaultStorage(storageObject) {
953
953
  }
954
954
  }
955
955
 
956
+ function getPanelGroupKey(autoSaveId) {
957
+ return `react-resizable-panels:${autoSaveId}`;
958
+ }
959
+
956
960
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
957
961
  // so they should not be used as part of the serialization key.
958
962
  // Using the min/max size attributes should work well enough as a backup.
959
963
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
960
- function getSerializationKey(panels) {
964
+ function getPanelKey(panels) {
961
965
  return panels.map(panel => {
962
966
  const {
963
967
  constraints,
@@ -968,13 +972,14 @@ function getSerializationKey(panels) {
968
972
  if (idIsFromProps) {
969
973
  return id;
970
974
  } else {
971
- return `${order}:${JSON.stringify(constraints)}`;
975
+ return order ? `${order}:${JSON.stringify(constraints)}` : JSON.stringify(constraints);
972
976
  }
973
977
  }).sort((a, b) => a.localeCompare(b)).join(",");
974
978
  }
975
979
  function loadSerializedPanelGroupState(autoSaveId, storage) {
976
980
  try {
977
- const serialized = storage.getItem(`PanelGroup:sizes:${autoSaveId}`);
981
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
982
+ const serialized = storage.getItem(panelGroupKey);
978
983
  if (serialized) {
979
984
  const parsed = JSON.parse(serialized);
980
985
  if (typeof parsed === "object" && parsed != null) {
@@ -984,21 +989,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
984
989
  } catch (error) {}
985
990
  return null;
986
991
  }
987
- function loadPanelLayout(autoSaveId, panels, storage) {
988
- const state = loadSerializedPanelGroupState(autoSaveId, storage);
989
- if (state) {
990
- var _state$key;
991
- const key = getSerializationKey(panels);
992
- return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
993
- }
994
- return null;
992
+ function loadPanelGroupState(autoSaveId, panels, storage) {
993
+ var _loadSerializedPanelG, _state$panelKey;
994
+ const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
995
+ const panelKey = getPanelKey(panels);
996
+ return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
995
997
  }
996
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
997
- const key = getSerializationKey(panels);
998
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
999
- state[key] = sizes;
998
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
999
+ var _loadSerializedPanelG2;
1000
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
1001
+ const panelKey = getPanelKey(panels);
1002
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
1003
+ state[panelKey] = {
1004
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
1005
+ layout: sizes
1006
+ };
1000
1007
  try {
1001
- storage.setItem(`PanelGroup:sizes:${autoSaveId}`, JSON.stringify(state));
1008
+ storage.setItem(panelGroupKey, JSON.stringify(state));
1002
1009
  } catch (error) {
1003
1010
  console.error(error);
1004
1011
  }
@@ -1142,7 +1149,6 @@ function PanelGroupWithForwardedRef({
1142
1149
  const groupId = useUniqueId(idFromProps);
1143
1150
  const [dragState, setDragState] = useState(null);
1144
1151
  const [layout, setLayout] = useState([]);
1145
- useState([]);
1146
1152
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1147
1153
  const panelSizeBeforeCollapseRef = useRef(new Map());
1148
1154
  const prevDeltaRef = useRef(0);
@@ -1225,13 +1231,15 @@ function PanelGroupWithForwardedRef({
1225
1231
 
1226
1232
  // Limit the frequency of localStorage updates.
1227
1233
  if (debouncedSave == null) {
1228
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1234
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1229
1235
  debounceMap[autoSaveId] = debouncedSave;
1230
1236
  }
1231
1237
 
1232
- // Clone panel data array before saving since this array is mutated.
1233
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1234
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1238
+ // Clone mutable data before passing to the debounced function,
1239
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1240
+ const clonedPanelDataArray = [...panelDataArray];
1241
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1242
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1235
1243
  }
1236
1244
  }, [autoSaveId, layout, storage]);
1237
1245
 
@@ -1460,7 +1468,11 @@ function PanelGroupWithForwardedRef({
1460
1468
  // default size should be restored from local storage if possible.
1461
1469
  let unsafeLayout = null;
1462
1470
  if (autoSaveId) {
1463
- unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1471
+ const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
1472
+ if (state) {
1473
+ panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
1474
+ unsafeLayout = state.layout;
1475
+ }
1464
1476
  }
1465
1477
  if (unsafeLayout == null) {
1466
1478
  unsafeLayout = calculateUnsafeDefaultLayout({
@@ -937,11 +937,15 @@ function initializeDefaultStorage(storageObject) {
937
937
  }
938
938
  }
939
939
 
940
+ function getPanelGroupKey(autoSaveId) {
941
+ return `react-resizable-panels:${autoSaveId}`;
942
+ }
943
+
940
944
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
941
945
  // so they should not be used as part of the serialization key.
942
946
  // Using the min/max size attributes should work well enough as a backup.
943
947
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
944
- function getSerializationKey(panels) {
948
+ function getPanelKey(panels) {
945
949
  return panels.map(panel => {
946
950
  const {
947
951
  constraints,
@@ -952,13 +956,14 @@ function getSerializationKey(panels) {
952
956
  if (idIsFromProps) {
953
957
  return id;
954
958
  } else {
955
- return `${order}:${JSON.stringify(constraints)}`;
959
+ return order ? `${order}:${JSON.stringify(constraints)}` : JSON.stringify(constraints);
956
960
  }
957
961
  }).sort((a, b) => a.localeCompare(b)).join(",");
958
962
  }
959
963
  function loadSerializedPanelGroupState(autoSaveId, storage) {
960
964
  try {
961
- const serialized = storage.getItem(`PanelGroup:sizes:${autoSaveId}`);
965
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
966
+ const serialized = storage.getItem(panelGroupKey);
962
967
  if (serialized) {
963
968
  const parsed = JSON.parse(serialized);
964
969
  if (typeof parsed === "object" && parsed != null) {
@@ -968,21 +973,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
968
973
  } catch (error) {}
969
974
  return null;
970
975
  }
971
- function loadPanelLayout(autoSaveId, panels, storage) {
972
- const state = loadSerializedPanelGroupState(autoSaveId, storage);
973
- if (state) {
974
- var _state$key;
975
- const key = getSerializationKey(panels);
976
- return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
977
- }
978
- return null;
976
+ function loadPanelGroupState(autoSaveId, panels, storage) {
977
+ var _loadSerializedPanelG, _state$panelKey;
978
+ const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
979
+ const panelKey = getPanelKey(panels);
980
+ return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
979
981
  }
980
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
981
- const key = getSerializationKey(panels);
982
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
983
- state[key] = sizes;
982
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
983
+ var _loadSerializedPanelG2;
984
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
985
+ const panelKey = getPanelKey(panels);
986
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
987
+ state[panelKey] = {
988
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
989
+ layout: sizes
990
+ };
984
991
  try {
985
- storage.setItem(`PanelGroup:sizes:${autoSaveId}`, JSON.stringify(state));
992
+ storage.setItem(panelGroupKey, JSON.stringify(state));
986
993
  } catch (error) {
987
994
  console.error(error);
988
995
  }
@@ -1079,7 +1086,6 @@ function PanelGroupWithForwardedRef({
1079
1086
  const groupId = useUniqueId(idFromProps);
1080
1087
  const [dragState, setDragState] = useState(null);
1081
1088
  const [layout, setLayout] = useState([]);
1082
- useState([]);
1083
1089
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1084
1090
  const panelSizeBeforeCollapseRef = useRef(new Map());
1085
1091
  const prevDeltaRef = useRef(0);
@@ -1162,13 +1168,15 @@ function PanelGroupWithForwardedRef({
1162
1168
 
1163
1169
  // Limit the frequency of localStorage updates.
1164
1170
  if (debouncedSave == null) {
1165
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1171
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1166
1172
  debounceMap[autoSaveId] = debouncedSave;
1167
1173
  }
1168
1174
 
1169
- // Clone panel data array before saving since this array is mutated.
1170
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1171
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1175
+ // Clone mutable data before passing to the debounced function,
1176
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1177
+ const clonedPanelDataArray = [...panelDataArray];
1178
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1179
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1172
1180
  }
1173
1181
  }, [autoSaveId, layout, storage]);
1174
1182
 
@@ -1355,7 +1363,11 @@ function PanelGroupWithForwardedRef({
1355
1363
  // default size should be restored from local storage if possible.
1356
1364
  let unsafeLayout = null;
1357
1365
  if (autoSaveId) {
1358
- unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1366
+ const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
1367
+ if (state) {
1368
+ panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
1369
+ unsafeLayout = state.layout;
1370
+ }
1359
1371
  }
1360
1372
  if (unsafeLayout == null) {
1361
1373
  unsafeLayout = calculateUnsafeDefaultLayout({
@@ -963,11 +963,15 @@ function initializeDefaultStorage(storageObject) {
963
963
  }
964
964
  }
965
965
 
966
+ function getPanelGroupKey(autoSaveId) {
967
+ return `react-resizable-panels:${autoSaveId}`;
968
+ }
969
+
966
970
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
967
971
  // so they should not be used as part of the serialization key.
968
972
  // Using the min/max size attributes should work well enough as a backup.
969
973
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
970
- function getSerializationKey(panels) {
974
+ function getPanelKey(panels) {
971
975
  return panels.map(panel => {
972
976
  const {
973
977
  constraints,
@@ -978,13 +982,14 @@ function getSerializationKey(panels) {
978
982
  if (idIsFromProps) {
979
983
  return id;
980
984
  } else {
981
- return `${order}:${JSON.stringify(constraints)}`;
985
+ return order ? `${order}:${JSON.stringify(constraints)}` : JSON.stringify(constraints);
982
986
  }
983
987
  }).sort((a, b) => a.localeCompare(b)).join(",");
984
988
  }
985
989
  function loadSerializedPanelGroupState(autoSaveId, storage) {
986
990
  try {
987
- const serialized = storage.getItem(`PanelGroup:sizes:${autoSaveId}`);
991
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
992
+ const serialized = storage.getItem(panelGroupKey);
988
993
  if (serialized) {
989
994
  const parsed = JSON.parse(serialized);
990
995
  if (typeof parsed === "object" && parsed != null) {
@@ -994,21 +999,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
994
999
  } catch (error) {}
995
1000
  return null;
996
1001
  }
997
- function loadPanelLayout(autoSaveId, panels, storage) {
998
- const state = loadSerializedPanelGroupState(autoSaveId, storage);
999
- if (state) {
1000
- var _state$key;
1001
- const key = getSerializationKey(panels);
1002
- return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
1003
- }
1004
- return null;
1002
+ function loadPanelGroupState(autoSaveId, panels, storage) {
1003
+ var _loadSerializedPanelG, _state$panelKey;
1004
+ const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
1005
+ const panelKey = getPanelKey(panels);
1006
+ return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
1005
1007
  }
1006
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1007
- const key = getSerializationKey(panels);
1008
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
1009
- state[key] = sizes;
1008
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
1009
+ var _loadSerializedPanelG2;
1010
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
1011
+ const panelKey = getPanelKey(panels);
1012
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
1013
+ state[panelKey] = {
1014
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
1015
+ layout: sizes
1016
+ };
1010
1017
  try {
1011
- storage.setItem(`PanelGroup:sizes:${autoSaveId}`, JSON.stringify(state));
1018
+ storage.setItem(panelGroupKey, JSON.stringify(state));
1012
1019
  } catch (error) {
1013
1020
  console.error(error);
1014
1021
  }
@@ -1105,7 +1112,6 @@ function PanelGroupWithForwardedRef({
1105
1112
  const groupId = useUniqueId(idFromProps);
1106
1113
  const [dragState, setDragState] = useState(null);
1107
1114
  const [layout, setLayout] = useState([]);
1108
- useState([]);
1109
1115
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1110
1116
  const panelSizeBeforeCollapseRef = useRef(new Map());
1111
1117
  const prevDeltaRef = useRef(0);
@@ -1188,13 +1194,15 @@ function PanelGroupWithForwardedRef({
1188
1194
 
1189
1195
  // Limit the frequency of localStorage updates.
1190
1196
  if (debouncedSave == null) {
1191
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1197
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1192
1198
  debounceMap[autoSaveId] = debouncedSave;
1193
1199
  }
1194
1200
 
1195
- // Clone panel data array before saving since this array is mutated.
1196
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1197
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1201
+ // Clone mutable data before passing to the debounced function,
1202
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1203
+ const clonedPanelDataArray = [...panelDataArray];
1204
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1205
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1198
1206
  }
1199
1207
  }, [autoSaveId, layout, storage]);
1200
1208
 
@@ -1381,7 +1389,11 @@ function PanelGroupWithForwardedRef({
1381
1389
  // default size should be restored from local storage if possible.
1382
1390
  let unsafeLayout = null;
1383
1391
  if (autoSaveId) {
1384
- unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1392
+ const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
1393
+ if (state) {
1394
+ panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
1395
+ unsafeLayout = state.layout;
1396
+ }
1385
1397
  }
1386
1398
  if (unsafeLayout == null) {
1387
1399
  unsafeLayout = calculateUnsafeDefaultLayout({