react-resizable-panels 0.0.58 → 0.0.59

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.
@@ -168,8 +168,6 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
168
168
  PanelWithForwardedRef.displayName = "Panel";
169
169
  Panel.displayName = "forwardRef(Panel)";
170
170
 
171
- const PRECISION = 10;
172
-
173
171
  function convertPixelsToPercentage(pixels, groupSizePixels) {
174
172
  return pixels / groupSizePixels * 100;
175
173
  }
@@ -247,6 +245,8 @@ function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, gr
247
245
  };
248
246
  }
249
247
 
248
+ const PRECISION = 10;
249
+
250
250
  function fuzzyCompareNumbers(actual, expected, fractionDigits = PRECISION) {
251
251
  actual = parseFloat(actual.toFixed(fractionDigits));
252
252
  expected = parseFloat(expected.toFixed(fractionDigits));
@@ -640,15 +640,10 @@ function useWindowSplitterPanelGroupBehavior({
640
640
  });
641
641
  useEffect(() => {
642
642
  const {
643
- direction,
644
643
  panelDataArray
645
644
  } = committedValuesRef.current;
646
645
  const groupElement = getPanelGroupElement(groupId);
647
646
  assert(groupElement != null, `No group found for id "${groupId}"`);
648
- const {
649
- height,
650
- width
651
- } = groupElement.getBoundingClientRect();
652
647
  const handles = getResizeHandleElementsForGroup(groupId);
653
648
  const cleanupFunctions = handles.map(handle => {
654
649
  const handleId = handle.getAttribute("data-panel-resize-handle-id");
@@ -668,21 +663,19 @@ function useWindowSplitterPanelGroupBehavior({
668
663
  if (index >= 0) {
669
664
  const panelData = panelDataArray[index];
670
665
  const size = layout[index];
671
- if (size != null) {
672
- var _getPercentageSizeFro;
666
+ if (size != null && panelData.constraints.collapsible) {
667
+ var _getPercentageSizeFro, _getPercentageSizeFro2;
673
668
  const groupSizePixels = getAvailableGroupSizePixels(groupId);
674
- const minSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
669
+ const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
670
+ sizePercentage: panelData.constraints.collapsedSizePercentage,
671
+ sizePixels: panelData.constraints.collapsedSizePixels
672
+ }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
673
+ const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
675
674
  sizePercentage: panelData.constraints.minSizePercentage,
676
675
  sizePixels: panelData.constraints.minSizePixels
677
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
678
- let delta = 0;
679
- if (size.toPrecision(PRECISION) <= minSize.toPrecision(PRECISION)) {
680
- delta = direction === "horizontal" ? width : height;
681
- } else {
682
- delta = -(direction === "horizontal" ? width : height);
683
- }
676
+ }, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
684
677
  const nextLayout = adjustLayoutByDelta({
685
- delta,
678
+ delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
686
679
  groupSizePixels,
687
680
  layout,
688
681
  panelConstraints: panelDataArray.map(panelData => panelData.constraints),
@@ -1108,6 +1101,7 @@ function PanelGroupWithForwardedRef({
1108
1101
  const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
1109
1102
  const panelSizeBeforeCollapseRef = useRef(new Map());
1110
1103
  const prevDeltaRef = useRef(0);
1104
+ const [imperativeApiQueue, setImperativeApiQueue] = useState([]);
1111
1105
  const committedValuesRef = useRef({
1112
1106
  direction,
1113
1107
  dragState,
@@ -1197,6 +1191,17 @@ function PanelGroupWithForwardedRef({
1197
1191
  onLayout,
1198
1192
  panelDataArray
1199
1193
  } = committedValuesRef.current;
1194
+
1195
+ // See issues/211
1196
+ if (panelDataArray.find(({
1197
+ id
1198
+ }) => id === panelData.id) == null) {
1199
+ setImperativeApiQueue(prev => [...prev, {
1200
+ panelData,
1201
+ type: "collapse"
1202
+ }]);
1203
+ return;
1204
+ }
1200
1205
  if (panelData.constraints.collapsible) {
1201
1206
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1202
1207
  const {
@@ -1240,6 +1245,17 @@ function PanelGroupWithForwardedRef({
1240
1245
  onLayout,
1241
1246
  panelDataArray
1242
1247
  } = committedValuesRef.current;
1248
+
1249
+ // See issues/211
1250
+ if (panelDataArray.find(({
1251
+ id
1252
+ }) => id === panelData.id) == null) {
1253
+ setImperativeApiQueue(prev => [...prev, {
1254
+ panelData,
1255
+ type: "expand"
1256
+ }]);
1257
+ return;
1258
+ }
1243
1259
  if (panelData.constraints.collapsible) {
1244
1260
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1245
1261
  const {
@@ -1435,6 +1451,18 @@ function PanelGroupWithForwardedRef({
1435
1451
  onLayout,
1436
1452
  panelDataArray
1437
1453
  } = committedValuesRef.current;
1454
+
1455
+ // See issues/211
1456
+ if (panelDataArray.find(({
1457
+ id
1458
+ }) => id === panelData.id) == null) {
1459
+ setImperativeApiQueue(prev => [...prev, {
1460
+ panelData,
1461
+ mixedSizes,
1462
+ type: "resize"
1463
+ }]);
1464
+ return;
1465
+ }
1438
1466
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1439
1467
  const {
1440
1468
  groupSizePixels,
@@ -144,8 +144,6 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
144
144
  PanelWithForwardedRef.displayName = "Panel";
145
145
  Panel.displayName = "forwardRef(Panel)";
146
146
 
147
- const PRECISION = 10;
148
-
149
147
  function convertPixelsToPercentage(pixels, groupSizePixels) {
150
148
  return pixels / groupSizePixels * 100;
151
149
  }
@@ -223,6 +221,8 @@ function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, gr
223
221
  };
224
222
  }
225
223
 
224
+ const PRECISION = 10;
225
+
226
226
  function fuzzyCompareNumbers(actual, expected, fractionDigits = PRECISION) {
227
227
  actual = parseFloat(actual.toFixed(fractionDigits));
228
228
  expected = parseFloat(expected.toFixed(fractionDigits));
@@ -616,15 +616,10 @@ function useWindowSplitterPanelGroupBehavior({
616
616
  });
617
617
  useEffect(() => {
618
618
  const {
619
- direction,
620
619
  panelDataArray
621
620
  } = committedValuesRef.current;
622
621
  const groupElement = getPanelGroupElement(groupId);
623
622
  assert(groupElement != null, `No group found for id "${groupId}"`);
624
- const {
625
- height,
626
- width
627
- } = groupElement.getBoundingClientRect();
628
623
  const handles = getResizeHandleElementsForGroup(groupId);
629
624
  const cleanupFunctions = handles.map(handle => {
630
625
  const handleId = handle.getAttribute("data-panel-resize-handle-id");
@@ -644,21 +639,19 @@ function useWindowSplitterPanelGroupBehavior({
644
639
  if (index >= 0) {
645
640
  const panelData = panelDataArray[index];
646
641
  const size = layout[index];
647
- if (size != null) {
648
- var _getPercentageSizeFro;
642
+ if (size != null && panelData.constraints.collapsible) {
643
+ var _getPercentageSizeFro, _getPercentageSizeFro2;
649
644
  const groupSizePixels = getAvailableGroupSizePixels(groupId);
650
- const minSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
645
+ const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
646
+ sizePercentage: panelData.constraints.collapsedSizePercentage,
647
+ sizePixels: panelData.constraints.collapsedSizePixels
648
+ }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
649
+ const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
651
650
  sizePercentage: panelData.constraints.minSizePercentage,
652
651
  sizePixels: panelData.constraints.minSizePixels
653
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
654
- let delta = 0;
655
- if (size.toPrecision(PRECISION) <= minSize.toPrecision(PRECISION)) {
656
- delta = direction === "horizontal" ? width : height;
657
- } else {
658
- delta = -(direction === "horizontal" ? width : height);
659
- }
652
+ }, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
660
653
  const nextLayout = adjustLayoutByDelta({
661
- delta,
654
+ delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
662
655
  groupSizePixels,
663
656
  layout,
664
657
  panelConstraints: panelDataArray.map(panelData => panelData.constraints),
@@ -1084,6 +1077,7 @@ function PanelGroupWithForwardedRef({
1084
1077
  const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
1085
1078
  const panelSizeBeforeCollapseRef = useRef(new Map());
1086
1079
  const prevDeltaRef = useRef(0);
1080
+ const [imperativeApiQueue, setImperativeApiQueue] = useState([]);
1087
1081
  const committedValuesRef = useRef({
1088
1082
  direction,
1089
1083
  dragState,
@@ -1173,6 +1167,17 @@ function PanelGroupWithForwardedRef({
1173
1167
  onLayout,
1174
1168
  panelDataArray
1175
1169
  } = committedValuesRef.current;
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
+ }
1176
1181
  if (panelData.constraints.collapsible) {
1177
1182
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1178
1183
  const {
@@ -1216,6 +1221,17 @@ function PanelGroupWithForwardedRef({
1216
1221
  onLayout,
1217
1222
  panelDataArray
1218
1223
  } = committedValuesRef.current;
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
+ }
1219
1235
  if (panelData.constraints.collapsible) {
1220
1236
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1221
1237
  const {
@@ -1411,6 +1427,18 @@ function PanelGroupWithForwardedRef({
1411
1427
  onLayout,
1412
1428
  panelDataArray
1413
1429
  } = committedValuesRef.current;
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
+ }
1414
1442
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1415
1443
  const {
1416
1444
  groupSizePixels,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-resizable-panels",
3
- "version": "0.0.58",
3
+ "version": "0.0.59",
4
4
  "description": "React components for resizable panel groups/layouts",
5
5
  "author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
6
6
  "license": "MIT",
package/src/PanelGroup.ts CHANGED
@@ -83,6 +83,12 @@ export type PanelGroupProps = PropsWithChildren<{
83
83
  tagName?: ElementType;
84
84
  }>;
85
85
 
86
+ type ImperativeApiQueue = {
87
+ type: "collapse" | "expand" | "resize";
88
+ mixedSizes?: Partial<MixedSizes>;
89
+ panelData: PanelData;
90
+ };
91
+
86
92
  const debounceMap: {
87
93
  [key: string]: typeof savePanelGroupLayout;
88
94
  } = {};
@@ -116,6 +122,10 @@ function PanelGroupWithForwardedRef({
116
122
  const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
117
123
  const prevDeltaRef = useRef<number>(0);
118
124
 
125
+ const [imperativeApiQueue, setImperativeApiQueue] = useState<
126
+ ImperativeApiQueue[]
127
+ >([]);
128
+
119
129
  const committedValuesRef = useRef<{
120
130
  direction: Direction;
121
131
  dragState: DragState | null;
@@ -269,8 +279,14 @@ function PanelGroupWithForwardedRef({
269
279
 
270
280
  const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
271
281
  if (groupSizePixels <= 0) {
272
- // Wait until the group has rendered a non-zero size before computing layout.
273
- return;
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
+ }
274
290
  }
275
291
 
276
292
  if (unsafeLayout == null) {
@@ -442,6 +458,18 @@ function PanelGroupWithForwardedRef({
442
458
  panelDataArray,
443
459
  } = committedValuesRef.current;
444
460
 
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
+
445
473
  if (panelData.constraints.collapsible) {
446
474
  const panelConstraintsArray = panelDataArray.map(
447
475
  (panelData) => panelData.constraints
@@ -514,6 +542,18 @@ function PanelGroupWithForwardedRef({
514
542
  panelDataArray,
515
543
  } = committedValuesRef.current;
516
544
 
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
+
517
557
  if (panelData.constraints.collapsible) {
518
558
  const panelConstraintsArray = panelDataArray.map(
519
559
  (panelData) => panelData.constraints
@@ -780,6 +820,19 @@ function PanelGroupWithForwardedRef({
780
820
  panelDataArray,
781
821
  } = committedValuesRef.current;
782
822
 
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
+
783
836
  const panelConstraintsArray = panelDataArray.map(
784
837
  (panelData) => panelData.constraints
785
838
  );
@@ -873,6 +926,35 @@ function PanelGroupWithForwardedRef({
873
926
  });
874
927
  }, []);
875
928
 
929
+ // Handle imperative API calls that were made before panels were registered
930
+ useIsomorphicLayoutEffect(() => {
931
+ const queue = imperativeApiQueue;
932
+ while (queue.length > 0) {
933
+ const current = queue.shift()!;
934
+ switch (current.type) {
935
+ case "collapse": {
936
+ collapsePanel(current.panelData);
937
+ break;
938
+ }
939
+ case "expand": {
940
+ expandPanel(current.panelData);
941
+ break;
942
+ }
943
+ case "resize": {
944
+ resizePanel(current.panelData, current.mixedSizes!);
945
+ break;
946
+ }
947
+ }
948
+ }
949
+ }, [
950
+ collapsePanel,
951
+ expandPanel,
952
+ imperativeApiQueue,
953
+ layout,
954
+ panelDataArray,
955
+ resizePanel,
956
+ ]);
957
+
876
958
  const context = useMemo(
877
959
  () => ({
878
960
  collapsePanel,
@@ -1,6 +1,5 @@
1
1
  import { isDevelopment } from "#is-development";
2
2
  import { PanelData } from "../Panel";
3
- import { PRECISION } from "../constants";
4
3
  import { Direction } from "../types";
5
4
  import { adjustLayoutByDelta } from "../utils/adjustLayoutByDelta";
6
5
  import { assert } from "../utils/assert";
@@ -12,6 +11,7 @@ import { getPanelGroupElement } from "../utils/dom/getPanelGroupElement";
12
11
  import { getResizeHandleElementsForGroup } from "../utils/dom/getResizeHandleElementsForGroup";
13
12
  import { getResizeHandlePanelIds } from "../utils/dom/getResizeHandlePanelIds";
14
13
  import { getPercentageSizeFromMixedSizes } from "../utils/getPercentageSizeFromMixedSizes";
14
+ import { fuzzyNumbersEqual } from "../utils/numbers/fuzzyNumbersEqual";
15
15
  import { RefObject, useEffect, useRef } from "../vendor/react";
16
16
  import useIsomorphicLayoutEffect from "./useIsomorphicEffect";
17
17
 
@@ -95,13 +95,11 @@ export function useWindowSplitterPanelGroupBehavior({
95
95
  }, [groupId, layout, panelDataArray]);
96
96
 
97
97
  useEffect(() => {
98
- const { direction, panelDataArray } = committedValuesRef.current!;
98
+ const { panelDataArray } = committedValuesRef.current!;
99
99
 
100
100
  const groupElement = getPanelGroupElement(groupId);
101
101
  assert(groupElement != null, `No group found for id "${groupId}"`);
102
102
 
103
- const { height, width } = groupElement.getBoundingClientRect();
104
-
105
103
  const handles = getResizeHandleElementsForGroup(groupId);
106
104
  const cleanupFunctions = handles.map((handle) => {
107
105
  const handleId = handle.getAttribute("data-panel-resize-handle-id")!;
@@ -130,9 +128,18 @@ export function useWindowSplitterPanelGroupBehavior({
130
128
  if (index >= 0) {
131
129
  const panelData = panelDataArray[index];
132
130
  const size = layout[index];
133
- if (size != null) {
131
+ if (size != null && panelData.constraints.collapsible) {
134
132
  const groupSizePixels = getAvailableGroupSizePixels(groupId);
135
133
 
134
+ const collapsedSize =
135
+ getPercentageSizeFromMixedSizes(
136
+ {
137
+ sizePercentage:
138
+ panelData.constraints.collapsedSizePercentage,
139
+ sizePixels: panelData.constraints.collapsedSizePixels,
140
+ },
141
+ groupSizePixels
142
+ ) ?? 0;
136
143
  const minSize =
137
144
  getPercentageSizeFromMixedSizes(
138
145
  {
@@ -142,17 +149,10 @@ export function useWindowSplitterPanelGroupBehavior({
142
149
  groupSizePixels
143
150
  ) ?? 0;
144
151
 
145
- let delta = 0;
146
- if (
147
- size.toPrecision(PRECISION) <= minSize.toPrecision(PRECISION)
148
- ) {
149
- delta = direction === "horizontal" ? width : height;
150
- } else {
151
- delta = -(direction === "horizontal" ? width : height);
152
- }
153
-
154
152
  const nextLayout = adjustLayoutByDelta({
155
- delta,
153
+ delta: fuzzyNumbersEqual(size, collapsedSize)
154
+ ? minSize - collapsedSize
155
+ : collapsedSize - size,
156
156
  groupSizePixels,
157
157
  layout,
158
158
  panelConstraints: panelDataArray.map(