react-resizable-panels 1.0.2 → 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 +5 -1
- package/dist/react-resizable-panels.browser.cjs.js +33 -21
- package/dist/react-resizable-panels.browser.development.cjs.js +33 -21
- package/dist/react-resizable-panels.browser.development.esm.js +33 -21
- package/dist/react-resizable-panels.browser.esm.js +33 -21
- package/dist/react-resizable-panels.cjs.js +33 -21
- package/dist/react-resizable-panels.development.cjs.js +33 -21
- package/dist/react-resizable-panels.development.esm.js +33 -21
- package/dist/react-resizable-panels.development.node.cjs.js +23 -12
- package/dist/react-resizable-panels.development.node.esm.js +23 -12
- package/dist/react-resizable-panels.esm.js +33 -21
- package/dist/react-resizable-panels.node.cjs.js +23 -12
- package/dist/react-resizable-panels.node.esm.js +23 -12
- package/package.json +1 -1
- package/src/PanelGroup.ts +26 -8
- package/src/utils/serialization.ts +33 -18
|
@@ -960,11 +960,15 @@ function initializeDefaultStorage(storageObject) {
|
|
|
960
960
|
}
|
|
961
961
|
}
|
|
962
962
|
|
|
963
|
+
function getPanelGroupKey(autoSaveId) {
|
|
964
|
+
return `react-resizable-panels:${autoSaveId}`;
|
|
965
|
+
}
|
|
966
|
+
|
|
963
967
|
// Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
|
|
964
968
|
// so they should not be used as part of the serialization key.
|
|
965
969
|
// Using the min/max size attributes should work well enough as a backup.
|
|
966
970
|
// Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
|
|
967
|
-
function
|
|
971
|
+
function getPanelKey(panels) {
|
|
968
972
|
return panels.map(panel => {
|
|
969
973
|
const {
|
|
970
974
|
constraints,
|
|
@@ -981,7 +985,8 @@ function getSerializationKey(panels) {
|
|
|
981
985
|
}
|
|
982
986
|
function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
983
987
|
try {
|
|
984
|
-
const
|
|
988
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
989
|
+
const serialized = storage.getItem(panelGroupKey);
|
|
985
990
|
if (serialized) {
|
|
986
991
|
const parsed = JSON.parse(serialized);
|
|
987
992
|
if (typeof parsed === "object" && parsed != null) {
|
|
@@ -991,21 +996,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
|
991
996
|
} catch (error) {}
|
|
992
997
|
return null;
|
|
993
998
|
}
|
|
994
|
-
function
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
|
|
1000
|
-
}
|
|
1001
|
-
return null;
|
|
999
|
+
function loadPanelGroupState(autoSaveId, panels, storage) {
|
|
1000
|
+
var _loadSerializedPanelG, _state$panelKey;
|
|
1001
|
+
const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
|
|
1002
|
+
const panelKey = getPanelKey(panels);
|
|
1003
|
+
return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
|
|
1002
1004
|
}
|
|
1003
|
-
function
|
|
1004
|
-
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1005
|
+
function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
|
|
1006
|
+
var _loadSerializedPanelG2;
|
|
1007
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
1008
|
+
const panelKey = getPanelKey(panels);
|
|
1009
|
+
const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
|
|
1010
|
+
state[panelKey] = {
|
|
1011
|
+
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
|
|
1012
|
+
layout: sizes
|
|
1013
|
+
};
|
|
1007
1014
|
try {
|
|
1008
|
-
storage.setItem(
|
|
1015
|
+
storage.setItem(panelGroupKey, JSON.stringify(state));
|
|
1009
1016
|
} catch (error) {
|
|
1010
1017
|
console.error(error);
|
|
1011
1018
|
}
|
|
@@ -1149,7 +1156,6 @@ function PanelGroupWithForwardedRef({
|
|
|
1149
1156
|
const groupId = useUniqueId(idFromProps);
|
|
1150
1157
|
const [dragState, setDragState] = useState(null);
|
|
1151
1158
|
const [layout, setLayout] = useState([]);
|
|
1152
|
-
useState([]);
|
|
1153
1159
|
const panelIdToLastNotifiedSizeMapRef = useRef({});
|
|
1154
1160
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
1155
1161
|
const prevDeltaRef = useRef(0);
|
|
@@ -1232,13 +1238,15 @@ function PanelGroupWithForwardedRef({
|
|
|
1232
1238
|
|
|
1233
1239
|
// Limit the frequency of localStorage updates.
|
|
1234
1240
|
if (debouncedSave == null) {
|
|
1235
|
-
debouncedSave = debounce(
|
|
1241
|
+
debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
|
|
1236
1242
|
debounceMap[autoSaveId] = debouncedSave;
|
|
1237
1243
|
}
|
|
1238
1244
|
|
|
1239
|
-
// Clone
|
|
1240
|
-
//
|
|
1241
|
-
|
|
1245
|
+
// Clone mutable data before passing to the debounced function,
|
|
1246
|
+
// else we run the risk of saving an incorrect combination of mutable and immutable values to state.
|
|
1247
|
+
const clonedPanelDataArray = [...panelDataArray];
|
|
1248
|
+
const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
|
|
1249
|
+
debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
|
|
1242
1250
|
}
|
|
1243
1251
|
}, [autoSaveId, layout, storage]);
|
|
1244
1252
|
|
|
@@ -1467,7 +1475,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1467
1475
|
// default size should be restored from local storage if possible.
|
|
1468
1476
|
let unsafeLayout = null;
|
|
1469
1477
|
if (autoSaveId) {
|
|
1470
|
-
|
|
1478
|
+
const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
|
|
1479
|
+
if (state) {
|
|
1480
|
+
panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
|
|
1481
|
+
unsafeLayout = state.layout;
|
|
1482
|
+
}
|
|
1471
1483
|
}
|
|
1472
1484
|
if (unsafeLayout == null) {
|
|
1473
1485
|
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
@@ -835,11 +835,15 @@ function initializeDefaultStorage(storageObject) {
|
|
|
835
835
|
}
|
|
836
836
|
}
|
|
837
837
|
|
|
838
|
+
function getPanelGroupKey(autoSaveId) {
|
|
839
|
+
return `react-resizable-panels:${autoSaveId}`;
|
|
840
|
+
}
|
|
841
|
+
|
|
838
842
|
// Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
|
|
839
843
|
// so they should not be used as part of the serialization key.
|
|
840
844
|
// Using the min/max size attributes should work well enough as a backup.
|
|
841
845
|
// Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
|
|
842
|
-
function
|
|
846
|
+
function getPanelKey(panels) {
|
|
843
847
|
return panels.map(panel => {
|
|
844
848
|
const {
|
|
845
849
|
constraints,
|
|
@@ -856,7 +860,8 @@ function getSerializationKey(panels) {
|
|
|
856
860
|
}
|
|
857
861
|
function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
858
862
|
try {
|
|
859
|
-
const
|
|
863
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
864
|
+
const serialized = storage.getItem(panelGroupKey);
|
|
860
865
|
if (serialized) {
|
|
861
866
|
const parsed = JSON.parse(serialized);
|
|
862
867
|
if (typeof parsed === "object" && parsed != null) {
|
|
@@ -866,12 +871,17 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
|
866
871
|
} catch (error) {}
|
|
867
872
|
return null;
|
|
868
873
|
}
|
|
869
|
-
function
|
|
870
|
-
|
|
871
|
-
const
|
|
872
|
-
|
|
874
|
+
function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
|
|
875
|
+
var _loadSerializedPanelG2;
|
|
876
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
877
|
+
const panelKey = getPanelKey(panels);
|
|
878
|
+
const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
|
|
879
|
+
state[panelKey] = {
|
|
880
|
+
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
|
|
881
|
+
layout: sizes
|
|
882
|
+
};
|
|
873
883
|
try {
|
|
874
|
-
storage.setItem(
|
|
884
|
+
storage.setItem(panelGroupKey, JSON.stringify(state));
|
|
875
885
|
} catch (error) {
|
|
876
886
|
console.error(error);
|
|
877
887
|
}
|
|
@@ -1015,7 +1025,6 @@ function PanelGroupWithForwardedRef({
|
|
|
1015
1025
|
const groupId = useUniqueId(idFromProps);
|
|
1016
1026
|
const [dragState, setDragState] = useState(null);
|
|
1017
1027
|
const [layout, setLayout] = useState([]);
|
|
1018
|
-
useState([]);
|
|
1019
1028
|
const panelIdToLastNotifiedSizeMapRef = useRef({});
|
|
1020
1029
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
1021
1030
|
const prevDeltaRef = useRef(0);
|
|
@@ -1090,13 +1099,15 @@ function PanelGroupWithForwardedRef({
|
|
|
1090
1099
|
|
|
1091
1100
|
// Limit the frequency of localStorage updates.
|
|
1092
1101
|
if (debouncedSave == null) {
|
|
1093
|
-
debouncedSave = debounce(
|
|
1102
|
+
debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
|
|
1094
1103
|
debounceMap[autoSaveId] = debouncedSave;
|
|
1095
1104
|
}
|
|
1096
1105
|
|
|
1097
|
-
// Clone
|
|
1098
|
-
//
|
|
1099
|
-
|
|
1106
|
+
// Clone mutable data before passing to the debounced function,
|
|
1107
|
+
// else we run the risk of saving an incorrect combination of mutable and immutable values to state.
|
|
1108
|
+
const clonedPanelDataArray = [...panelDataArray];
|
|
1109
|
+
const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
|
|
1110
|
+
debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
|
|
1100
1111
|
}
|
|
1101
1112
|
}, [autoSaveId, layout, storage]);
|
|
1102
1113
|
|
|
@@ -811,11 +811,15 @@ function initializeDefaultStorage(storageObject) {
|
|
|
811
811
|
}
|
|
812
812
|
}
|
|
813
813
|
|
|
814
|
+
function getPanelGroupKey(autoSaveId) {
|
|
815
|
+
return `react-resizable-panels:${autoSaveId}`;
|
|
816
|
+
}
|
|
817
|
+
|
|
814
818
|
// Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
|
|
815
819
|
// so they should not be used as part of the serialization key.
|
|
816
820
|
// Using the min/max size attributes should work well enough as a backup.
|
|
817
821
|
// Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
|
|
818
|
-
function
|
|
822
|
+
function getPanelKey(panels) {
|
|
819
823
|
return panels.map(panel => {
|
|
820
824
|
const {
|
|
821
825
|
constraints,
|
|
@@ -832,7 +836,8 @@ function getSerializationKey(panels) {
|
|
|
832
836
|
}
|
|
833
837
|
function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
834
838
|
try {
|
|
835
|
-
const
|
|
839
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
840
|
+
const serialized = storage.getItem(panelGroupKey);
|
|
836
841
|
if (serialized) {
|
|
837
842
|
const parsed = JSON.parse(serialized);
|
|
838
843
|
if (typeof parsed === "object" && parsed != null) {
|
|
@@ -842,12 +847,17 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
|
842
847
|
} catch (error) {}
|
|
843
848
|
return null;
|
|
844
849
|
}
|
|
845
|
-
function
|
|
846
|
-
|
|
847
|
-
const
|
|
848
|
-
|
|
850
|
+
function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
|
|
851
|
+
var _loadSerializedPanelG2;
|
|
852
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
853
|
+
const panelKey = getPanelKey(panels);
|
|
854
|
+
const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
|
|
855
|
+
state[panelKey] = {
|
|
856
|
+
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
|
|
857
|
+
layout: sizes
|
|
858
|
+
};
|
|
849
859
|
try {
|
|
850
|
-
storage.setItem(
|
|
860
|
+
storage.setItem(panelGroupKey, JSON.stringify(state));
|
|
851
861
|
} catch (error) {
|
|
852
862
|
console.error(error);
|
|
853
863
|
}
|
|
@@ -991,7 +1001,6 @@ function PanelGroupWithForwardedRef({
|
|
|
991
1001
|
const groupId = useUniqueId(idFromProps);
|
|
992
1002
|
const [dragState, setDragState] = useState(null);
|
|
993
1003
|
const [layout, setLayout] = useState([]);
|
|
994
|
-
useState([]);
|
|
995
1004
|
const panelIdToLastNotifiedSizeMapRef = useRef({});
|
|
996
1005
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
997
1006
|
const prevDeltaRef = useRef(0);
|
|
@@ -1066,13 +1075,15 @@ function PanelGroupWithForwardedRef({
|
|
|
1066
1075
|
|
|
1067
1076
|
// Limit the frequency of localStorage updates.
|
|
1068
1077
|
if (debouncedSave == null) {
|
|
1069
|
-
debouncedSave = debounce(
|
|
1078
|
+
debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
|
|
1070
1079
|
debounceMap[autoSaveId] = debouncedSave;
|
|
1071
1080
|
}
|
|
1072
1081
|
|
|
1073
|
-
// Clone
|
|
1074
|
-
//
|
|
1075
|
-
|
|
1082
|
+
// Clone mutable data before passing to the debounced function,
|
|
1083
|
+
// else we run the risk of saving an incorrect combination of mutable and immutable values to state.
|
|
1084
|
+
const clonedPanelDataArray = [...panelDataArray];
|
|
1085
|
+
const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
|
|
1086
|
+
debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
|
|
1076
1087
|
}
|
|
1077
1088
|
}, [autoSaveId, layout, storage]);
|
|
1078
1089
|
|
|
@@ -939,11 +939,15 @@ function initializeDefaultStorage(storageObject) {
|
|
|
939
939
|
}
|
|
940
940
|
}
|
|
941
941
|
|
|
942
|
+
function getPanelGroupKey(autoSaveId) {
|
|
943
|
+
return `react-resizable-panels:${autoSaveId}`;
|
|
944
|
+
}
|
|
945
|
+
|
|
942
946
|
// Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
|
|
943
947
|
// so they should not be used as part of the serialization key.
|
|
944
948
|
// Using the min/max size attributes should work well enough as a backup.
|
|
945
949
|
// Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
|
|
946
|
-
function
|
|
950
|
+
function getPanelKey(panels) {
|
|
947
951
|
return panels.map(panel => {
|
|
948
952
|
const {
|
|
949
953
|
constraints,
|
|
@@ -960,7 +964,8 @@ function getSerializationKey(panels) {
|
|
|
960
964
|
}
|
|
961
965
|
function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
962
966
|
try {
|
|
963
|
-
const
|
|
967
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
968
|
+
const serialized = storage.getItem(panelGroupKey);
|
|
964
969
|
if (serialized) {
|
|
965
970
|
const parsed = JSON.parse(serialized);
|
|
966
971
|
if (typeof parsed === "object" && parsed != null) {
|
|
@@ -970,21 +975,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
|
970
975
|
} catch (error) {}
|
|
971
976
|
return null;
|
|
972
977
|
}
|
|
973
|
-
function
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
|
|
979
|
-
}
|
|
980
|
-
return null;
|
|
978
|
+
function loadPanelGroupState(autoSaveId, panels, storage) {
|
|
979
|
+
var _loadSerializedPanelG, _state$panelKey;
|
|
980
|
+
const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
|
|
981
|
+
const panelKey = getPanelKey(panels);
|
|
982
|
+
return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
|
|
981
983
|
}
|
|
982
|
-
function
|
|
983
|
-
|
|
984
|
-
const
|
|
985
|
-
|
|
984
|
+
function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
|
|
985
|
+
var _loadSerializedPanelG2;
|
|
986
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
987
|
+
const panelKey = getPanelKey(panels);
|
|
988
|
+
const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
|
|
989
|
+
state[panelKey] = {
|
|
990
|
+
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
|
|
991
|
+
layout: sizes
|
|
992
|
+
};
|
|
986
993
|
try {
|
|
987
|
-
storage.setItem(
|
|
994
|
+
storage.setItem(panelGroupKey, JSON.stringify(state));
|
|
988
995
|
} catch (error) {
|
|
989
996
|
console.error(error);
|
|
990
997
|
}
|
|
@@ -1081,7 +1088,6 @@ function PanelGroupWithForwardedRef({
|
|
|
1081
1088
|
const groupId = useUniqueId(idFromProps);
|
|
1082
1089
|
const [dragState, setDragState] = useState(null);
|
|
1083
1090
|
const [layout, setLayout] = useState([]);
|
|
1084
|
-
useState([]);
|
|
1085
1091
|
const panelIdToLastNotifiedSizeMapRef = useRef({});
|
|
1086
1092
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
1087
1093
|
const prevDeltaRef = useRef(0);
|
|
@@ -1164,13 +1170,15 @@ function PanelGroupWithForwardedRef({
|
|
|
1164
1170
|
|
|
1165
1171
|
// Limit the frequency of localStorage updates.
|
|
1166
1172
|
if (debouncedSave == null) {
|
|
1167
|
-
debouncedSave = debounce(
|
|
1173
|
+
debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
|
|
1168
1174
|
debounceMap[autoSaveId] = debouncedSave;
|
|
1169
1175
|
}
|
|
1170
1176
|
|
|
1171
|
-
// Clone
|
|
1172
|
-
//
|
|
1173
|
-
|
|
1177
|
+
// Clone mutable data before passing to the debounced function,
|
|
1178
|
+
// else we run the risk of saving an incorrect combination of mutable and immutable values to state.
|
|
1179
|
+
const clonedPanelDataArray = [...panelDataArray];
|
|
1180
|
+
const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
|
|
1181
|
+
debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
|
|
1174
1182
|
}
|
|
1175
1183
|
}, [autoSaveId, layout, storage]);
|
|
1176
1184
|
|
|
@@ -1357,7 +1365,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1357
1365
|
// default size should be restored from local storage if possible.
|
|
1358
1366
|
let unsafeLayout = null;
|
|
1359
1367
|
if (autoSaveId) {
|
|
1360
|
-
|
|
1368
|
+
const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
|
|
1369
|
+
if (state) {
|
|
1370
|
+
panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
|
|
1371
|
+
unsafeLayout = state.layout;
|
|
1372
|
+
}
|
|
1361
1373
|
}
|
|
1362
1374
|
if (unsafeLayout == null) {
|
|
1363
1375
|
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
@@ -824,11 +824,15 @@ function initializeDefaultStorage(storageObject) {
|
|
|
824
824
|
}
|
|
825
825
|
}
|
|
826
826
|
|
|
827
|
+
function getPanelGroupKey(autoSaveId) {
|
|
828
|
+
return `react-resizable-panels:${autoSaveId}`;
|
|
829
|
+
}
|
|
830
|
+
|
|
827
831
|
// Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
|
|
828
832
|
// so they should not be used as part of the serialization key.
|
|
829
833
|
// Using the min/max size attributes should work well enough as a backup.
|
|
830
834
|
// Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
|
|
831
|
-
function
|
|
835
|
+
function getPanelKey(panels) {
|
|
832
836
|
return panels.map(panel => {
|
|
833
837
|
const {
|
|
834
838
|
constraints,
|
|
@@ -845,7 +849,8 @@ function getSerializationKey(panels) {
|
|
|
845
849
|
}
|
|
846
850
|
function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
847
851
|
try {
|
|
848
|
-
const
|
|
852
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
853
|
+
const serialized = storage.getItem(panelGroupKey);
|
|
849
854
|
if (serialized) {
|
|
850
855
|
const parsed = JSON.parse(serialized);
|
|
851
856
|
if (typeof parsed === "object" && parsed != null) {
|
|
@@ -855,12 +860,17 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
|
855
860
|
} catch (error) {}
|
|
856
861
|
return null;
|
|
857
862
|
}
|
|
858
|
-
function
|
|
859
|
-
|
|
860
|
-
const
|
|
861
|
-
|
|
863
|
+
function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
|
|
864
|
+
var _loadSerializedPanelG2;
|
|
865
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
866
|
+
const panelKey = getPanelKey(panels);
|
|
867
|
+
const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
|
|
868
|
+
state[panelKey] = {
|
|
869
|
+
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
|
|
870
|
+
layout: sizes
|
|
871
|
+
};
|
|
862
872
|
try {
|
|
863
|
-
storage.setItem(
|
|
873
|
+
storage.setItem(panelGroupKey, JSON.stringify(state));
|
|
864
874
|
} catch (error) {
|
|
865
875
|
console.error(error);
|
|
866
876
|
}
|
|
@@ -957,7 +967,6 @@ function PanelGroupWithForwardedRef({
|
|
|
957
967
|
const groupId = useUniqueId(idFromProps);
|
|
958
968
|
const [dragState, setDragState] = useState(null);
|
|
959
969
|
const [layout, setLayout] = useState([]);
|
|
960
|
-
useState([]);
|
|
961
970
|
const panelIdToLastNotifiedSizeMapRef = useRef({});
|
|
962
971
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
963
972
|
const prevDeltaRef = useRef(0);
|
|
@@ -1032,13 +1041,15 @@ function PanelGroupWithForwardedRef({
|
|
|
1032
1041
|
|
|
1033
1042
|
// Limit the frequency of localStorage updates.
|
|
1034
1043
|
if (debouncedSave == null) {
|
|
1035
|
-
debouncedSave = debounce(
|
|
1044
|
+
debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
|
|
1036
1045
|
debounceMap[autoSaveId] = debouncedSave;
|
|
1037
1046
|
}
|
|
1038
1047
|
|
|
1039
|
-
// Clone
|
|
1040
|
-
//
|
|
1041
|
-
|
|
1048
|
+
// Clone mutable data before passing to the debounced function,
|
|
1049
|
+
// else we run the risk of saving an incorrect combination of mutable and immutable values to state.
|
|
1050
|
+
const clonedPanelDataArray = [...panelDataArray];
|
|
1051
|
+
const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
|
|
1052
|
+
debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
|
|
1042
1053
|
}
|
|
1043
1054
|
}, [autoSaveId, layout, storage]);
|
|
1044
1055
|
|
|
@@ -800,11 +800,15 @@ function initializeDefaultStorage(storageObject) {
|
|
|
800
800
|
}
|
|
801
801
|
}
|
|
802
802
|
|
|
803
|
+
function getPanelGroupKey(autoSaveId) {
|
|
804
|
+
return `react-resizable-panels:${autoSaveId}`;
|
|
805
|
+
}
|
|
806
|
+
|
|
803
807
|
// Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
|
|
804
808
|
// so they should not be used as part of the serialization key.
|
|
805
809
|
// Using the min/max size attributes should work well enough as a backup.
|
|
806
810
|
// Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
|
|
807
|
-
function
|
|
811
|
+
function getPanelKey(panels) {
|
|
808
812
|
return panels.map(panel => {
|
|
809
813
|
const {
|
|
810
814
|
constraints,
|
|
@@ -821,7 +825,8 @@ function getSerializationKey(panels) {
|
|
|
821
825
|
}
|
|
822
826
|
function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
823
827
|
try {
|
|
824
|
-
const
|
|
828
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
829
|
+
const serialized = storage.getItem(panelGroupKey);
|
|
825
830
|
if (serialized) {
|
|
826
831
|
const parsed = JSON.parse(serialized);
|
|
827
832
|
if (typeof parsed === "object" && parsed != null) {
|
|
@@ -831,12 +836,17 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
|
831
836
|
} catch (error) {}
|
|
832
837
|
return null;
|
|
833
838
|
}
|
|
834
|
-
function
|
|
835
|
-
|
|
836
|
-
const
|
|
837
|
-
|
|
839
|
+
function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
|
|
840
|
+
var _loadSerializedPanelG2;
|
|
841
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
842
|
+
const panelKey = getPanelKey(panels);
|
|
843
|
+
const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
|
|
844
|
+
state[panelKey] = {
|
|
845
|
+
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
|
|
846
|
+
layout: sizes
|
|
847
|
+
};
|
|
838
848
|
try {
|
|
839
|
-
storage.setItem(
|
|
849
|
+
storage.setItem(panelGroupKey, JSON.stringify(state));
|
|
840
850
|
} catch (error) {
|
|
841
851
|
console.error(error);
|
|
842
852
|
}
|
|
@@ -933,7 +943,6 @@ function PanelGroupWithForwardedRef({
|
|
|
933
943
|
const groupId = useUniqueId(idFromProps);
|
|
934
944
|
const [dragState, setDragState] = useState(null);
|
|
935
945
|
const [layout, setLayout] = useState([]);
|
|
936
|
-
useState([]);
|
|
937
946
|
const panelIdToLastNotifiedSizeMapRef = useRef({});
|
|
938
947
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
939
948
|
const prevDeltaRef = useRef(0);
|
|
@@ -1008,13 +1017,15 @@ function PanelGroupWithForwardedRef({
|
|
|
1008
1017
|
|
|
1009
1018
|
// Limit the frequency of localStorage updates.
|
|
1010
1019
|
if (debouncedSave == null) {
|
|
1011
|
-
debouncedSave = debounce(
|
|
1020
|
+
debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
|
|
1012
1021
|
debounceMap[autoSaveId] = debouncedSave;
|
|
1013
1022
|
}
|
|
1014
1023
|
|
|
1015
|
-
// Clone
|
|
1016
|
-
//
|
|
1017
|
-
|
|
1024
|
+
// Clone mutable data before passing to the debounced function,
|
|
1025
|
+
// else we run the risk of saving an incorrect combination of mutable and immutable values to state.
|
|
1026
|
+
const clonedPanelDataArray = [...panelDataArray];
|
|
1027
|
+
const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
|
|
1028
|
+
debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
|
|
1018
1029
|
}
|
|
1019
1030
|
}, [autoSaveId, layout, storage]);
|
|
1020
1031
|
|
package/package.json
CHANGED
package/src/PanelGroup.ts
CHANGED
|
@@ -20,7 +20,10 @@ import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement";
|
|
|
20
20
|
import { isKeyDown, isMouseEvent, isTouchEvent } from "./utils/events";
|
|
21
21
|
import { getResizeEventCursorPosition } from "./utils/getResizeEventCursorPosition";
|
|
22
22
|
import { initializeDefaultStorage } from "./utils/initializeDefaultStorage";
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
loadPanelGroupState,
|
|
25
|
+
savePanelGroupState,
|
|
26
|
+
} from "./utils/serialization";
|
|
24
27
|
import { validatePanelConstraints } from "./utils/validatePanelConstraints";
|
|
25
28
|
import { validatePanelGroupLayout } from "./utils/validatePanelGroupLayout";
|
|
26
29
|
import {
|
|
@@ -79,7 +82,7 @@ export type PanelGroupProps = Omit<HTMLAttributes<ElementType>, "id"> &
|
|
|
79
82
|
}>;
|
|
80
83
|
|
|
81
84
|
const debounceMap: {
|
|
82
|
-
[key: string]: typeof
|
|
85
|
+
[key: string]: typeof savePanelGroupState;
|
|
83
86
|
} = {};
|
|
84
87
|
|
|
85
88
|
function PanelGroupWithForwardedRef({
|
|
@@ -102,7 +105,6 @@ function PanelGroupWithForwardedRef({
|
|
|
102
105
|
|
|
103
106
|
const [dragState, setDragState] = useState<DragState | null>(null);
|
|
104
107
|
const [layout, setLayout] = useState<number[]>([]);
|
|
105
|
-
const [panelDataArray, setPanelDataArray] = useState<PanelData[]>([]);
|
|
106
108
|
|
|
107
109
|
const panelIdToLastNotifiedSizeMapRef = useRef<Record<string, number>>({});
|
|
108
110
|
const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
|
|
@@ -218,16 +220,26 @@ function PanelGroupWithForwardedRef({
|
|
|
218
220
|
// Limit the frequency of localStorage updates.
|
|
219
221
|
if (debouncedSave == null) {
|
|
220
222
|
debouncedSave = debounce(
|
|
221
|
-
|
|
223
|
+
savePanelGroupState,
|
|
222
224
|
LOCAL_STORAGE_DEBOUNCE_INTERVAL
|
|
223
225
|
);
|
|
224
226
|
|
|
225
227
|
debounceMap[autoSaveId] = debouncedSave;
|
|
226
228
|
}
|
|
227
229
|
|
|
228
|
-
// Clone
|
|
229
|
-
//
|
|
230
|
-
|
|
230
|
+
// Clone mutable data before passing to the debounced function,
|
|
231
|
+
// else we run the risk of saving an incorrect combination of mutable and immutable values to state.
|
|
232
|
+
const clonedPanelDataArray = [...panelDataArray];
|
|
233
|
+
const clonedPanelSizesBeforeCollapse = new Map(
|
|
234
|
+
panelSizeBeforeCollapseRef.current
|
|
235
|
+
);
|
|
236
|
+
debouncedSave(
|
|
237
|
+
autoSaveId,
|
|
238
|
+
clonedPanelDataArray,
|
|
239
|
+
clonedPanelSizesBeforeCollapse,
|
|
240
|
+
layout,
|
|
241
|
+
storage
|
|
242
|
+
);
|
|
231
243
|
}
|
|
232
244
|
}, [autoSaveId, layout, storage]);
|
|
233
245
|
|
|
@@ -500,7 +512,13 @@ function PanelGroupWithForwardedRef({
|
|
|
500
512
|
// default size should be restored from local storage if possible.
|
|
501
513
|
let unsafeLayout: number[] | null = null;
|
|
502
514
|
if (autoSaveId) {
|
|
503
|
-
|
|
515
|
+
const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
|
|
516
|
+
if (state) {
|
|
517
|
+
panelSizeBeforeCollapseRef.current = new Map(
|
|
518
|
+
Object.entries(state.expandToSizes)
|
|
519
|
+
);
|
|
520
|
+
unsafeLayout = state.layout;
|
|
521
|
+
}
|
|
504
522
|
}
|
|
505
523
|
|
|
506
524
|
if (unsafeLayout == null) {
|