react-resizable-panels 0.0.63 → 1.0.0-rc.2

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.
Files changed (74) hide show
  1. package/.eslintrc.cjs +1 -0
  2. package/CHANGELOG.md +5 -0
  3. package/dist/declarations/src/Panel.d.ts +19 -34
  4. package/dist/declarations/src/PanelGroup.d.ts +9 -13
  5. package/dist/declarations/src/PanelResizeHandle.d.ts +5 -7
  6. package/dist/declarations/src/index.d.ts +2 -2
  7. package/dist/declarations/src/types.d.ts +0 -7
  8. package/dist/declarations/src/utils/assert.d.ts +1 -0
  9. package/dist/declarations/src/vendor/react.d.ts +2 -2
  10. package/dist/react-resizable-panels.browser.cjs.js +253 -518
  11. package/dist/react-resizable-panels.browser.cjs.mjs +2 -1
  12. package/dist/react-resizable-panels.browser.development.cjs.js +279 -574
  13. package/dist/react-resizable-panels.browser.development.cjs.mjs +2 -1
  14. package/dist/react-resizable-panels.browser.development.esm.js +279 -575
  15. package/dist/react-resizable-panels.browser.esm.js +253 -519
  16. package/dist/react-resizable-panels.cjs.d.ts +88 -1
  17. package/dist/react-resizable-panels.cjs.d.ts.map +1 -1
  18. package/dist/react-resizable-panels.cjs.js +1481 -1983
  19. package/dist/react-resizable-panels.cjs.js.map +1 -1
  20. package/dist/react-resizable-panels.cjs.mjs +2 -1
  21. package/dist/react-resizable-panels.development.cjs.js +281 -576
  22. package/dist/react-resizable-panels.development.cjs.mjs +2 -1
  23. package/dist/react-resizable-panels.development.esm.js +281 -577
  24. package/dist/react-resizable-panels.development.node.cjs.js +267 -502
  25. package/dist/react-resizable-panels.development.node.cjs.mjs +2 -1
  26. package/dist/react-resizable-panels.development.node.esm.js +267 -503
  27. package/dist/react-resizable-panels.esm.js +1476 -1959
  28. package/dist/react-resizable-panels.esm.js.map +1 -1
  29. package/dist/react-resizable-panels.node.cjs.js +239 -444
  30. package/dist/react-resizable-panels.node.cjs.mjs +2 -1
  31. package/dist/react-resizable-panels.node.esm.js +239 -445
  32. package/package.json +1 -1
  33. package/src/Panel.test.tsx +74 -73
  34. package/src/Panel.ts +44 -68
  35. package/src/PanelGroup.test.tsx +43 -42
  36. package/src/PanelGroup.ts +221 -411
  37. package/src/PanelGroupContext.ts +2 -3
  38. package/src/PanelResizeHandle.test.tsx +68 -0
  39. package/src/PanelResizeHandle.ts +31 -22
  40. package/src/hooks/useWindowSplitterBehavior.ts +2 -1
  41. package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +22 -33
  42. package/src/index.ts +4 -3
  43. package/src/types.ts +0 -9
  44. package/src/utils/adjustLayoutByDelta.test.ts +206 -336
  45. package/src/utils/adjustLayoutByDelta.ts +59 -51
  46. package/src/utils/assert.ts +1 -1
  47. package/src/utils/calculateAriaValues.test.ts +6 -11
  48. package/src/utils/calculateAriaValues.ts +7 -29
  49. package/src/utils/calculateDeltaPercentage.ts +8 -15
  50. package/src/utils/calculateDragOffsetPercentage.ts +11 -5
  51. package/src/utils/calculateUnsafeDefaultLayout.test.ts +4 -9
  52. package/src/utils/calculateUnsafeDefaultLayout.ts +13 -18
  53. package/src/utils/callPanelCallbacks.ts +11 -46
  54. package/src/utils/getResizeEventCursorPosition.ts +2 -0
  55. package/src/utils/resizePanel.test.ts +6 -52
  56. package/src/utils/resizePanel.ts +24 -46
  57. package/src/utils/test-utils.ts +6 -7
  58. package/src/utils/validatePanelConstraints.test.ts +12 -65
  59. package/src/utils/validatePanelConstraints.ts +26 -67
  60. package/src/utils/validatePanelGroupLayout.test.ts +27 -142
  61. package/src/utils/validatePanelGroupLayout.ts +17 -13
  62. package/src/vendor/react.ts +2 -0
  63. package/src/utils/computePercentagePanelConstraints.test.ts +0 -98
  64. package/src/utils/computePercentagePanelConstraints.ts +0 -56
  65. package/src/utils/convertPercentageToPixels.test.ts +0 -9
  66. package/src/utils/convertPercentageToPixels.ts +0 -6
  67. package/src/utils/convertPixelConstraintsToPercentages.test.ts +0 -47
  68. package/src/utils/convertPixelConstraintsToPercentages.ts +0 -72
  69. package/src/utils/convertPixelsToPercentage.test.ts +0 -9
  70. package/src/utils/convertPixelsToPercentage.ts +0 -6
  71. package/src/utils/getPercentageSizeFromMixedSizes.test.ts +0 -47
  72. package/src/utils/getPercentageSizeFromMixedSizes.ts +0 -15
  73. package/src/utils/shouldMonitorPixelBasedConstraints.test.ts +0 -23
  74. package/src/utils/shouldMonitorPixelBasedConstraints.ts +0 -13
@@ -63,24 +63,20 @@ function useUniqueId(idFromParams = null) {
63
63
  function PanelWithForwardedRef({
64
64
  children,
65
65
  className: classNameFromProps = "",
66
- collapsedSizePercentage,
67
- collapsedSizePixels,
66
+ collapsedSize,
68
67
  collapsible,
69
- dataAttributes,
70
- defaultSizePercentage,
71
- defaultSizePixels,
68
+ defaultSize,
72
69
  forwardedRef,
73
70
  id: idFromProps,
74
- maxSizePercentage,
75
- maxSizePixels,
76
- minSizePercentage,
77
- minSizePixels,
71
+ maxSize,
72
+ minSize,
78
73
  onCollapse,
79
74
  onExpand,
80
75
  onResize,
81
76
  order,
82
77
  style: styleFromProps,
83
- tagName: Type = "div"
78
+ tagName: Type = "div",
79
+ ...rest
84
80
  }) {
85
81
  const context = useContext(PanelGroupContext);
86
82
  if (context === null) {
@@ -105,15 +101,11 @@ function PanelWithForwardedRef({
105
101
  onResize
106
102
  },
107
103
  constraints: {
108
- collapsedSizePercentage,
109
- collapsedSizePixels,
104
+ collapsedSize,
110
105
  collapsible,
111
- defaultSizePercentage,
112
- defaultSizePixels,
113
- maxSizePercentage,
114
- maxSizePixels,
115
- minSizePercentage,
116
- minSizePixels
106
+ defaultSize,
107
+ maxSize,
108
+ minSize
117
109
  },
118
110
  id: panelId,
119
111
  idIsFromProps: idFromProps !== undefined,
@@ -141,19 +133,19 @@ function PanelWithForwardedRef({
141
133
  isExpanded() {
142
134
  return !isPanelCollapsed(panelDataRef.current);
143
135
  },
144
- resize: mixedSizes => {
145
- resizePanel(panelDataRef.current, mixedSizes);
136
+ resize: size => {
137
+ resizePanel(panelDataRef.current, size);
146
138
  }
147
139
  }), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel]);
148
140
  const style = getPanelStyle(panelDataRef.current);
149
141
  return createElement(Type, {
142
+ ...rest,
150
143
  children,
151
144
  className: classNameFromProps,
152
145
  style: {
153
146
  ...style,
154
147
  ...styleFromProps
155
148
  },
156
- ...dataAttributes,
157
149
  // CSS selectors
158
150
  "data-panel": "",
159
151
  "data-panel-id": panelId,
@@ -170,81 +162,11 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
170
162
  PanelWithForwardedRef.displayName = "Panel";
171
163
  Panel.displayName = "forwardRef(Panel)";
172
164
 
173
- function convertPixelsToPercentage(pixels, groupSizePixels) {
174
- return pixels / groupSizePixels * 100;
175
- }
176
-
177
- function convertPixelConstraintsToPercentages(panelConstraints, groupSizePixels) {
178
- let {
179
- collapsedSizePercentage = 0,
180
- collapsedSizePixels,
181
- defaultSizePercentage,
182
- defaultSizePixels,
183
- maxSizePercentage = 100,
184
- maxSizePixels,
185
- minSizePercentage = 0,
186
- minSizePixels
187
- } = panelConstraints;
188
- const hasPixelConstraints = collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null;
189
- if (hasPixelConstraints && groupSizePixels <= 0) {
190
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
191
- return {
192
- collapsedSizePercentage: 0,
193
- defaultSizePercentage,
194
- maxSizePercentage: 0,
195
- minSizePercentage: 0
196
- };
197
- }
198
- if (collapsedSizePixels != null) {
199
- collapsedSizePercentage = convertPixelsToPercentage(collapsedSizePixels, groupSizePixels);
200
- }
201
- if (defaultSizePixels != null) {
202
- defaultSizePercentage = convertPixelsToPercentage(defaultSizePixels, groupSizePixels);
203
- }
204
- if (minSizePixels != null) {
205
- minSizePercentage = convertPixelsToPercentage(minSizePixels, groupSizePixels);
206
- }
207
- if (maxSizePixels != null) {
208
- maxSizePercentage = convertPixelsToPercentage(maxSizePixels, groupSizePixels);
209
- }
210
- return {
211
- collapsedSizePercentage,
212
- defaultSizePercentage,
213
- maxSizePercentage,
214
- minSizePercentage
215
- };
216
- }
217
-
218
- function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels) {
219
- // All panel constraints, excluding the current one
220
- let totalMinConstraints = 0;
221
- let totalMaxConstraints = 0;
222
- for (let index = 0; index < panelConstraintsArray.length; index++) {
223
- if (index !== panelIndex) {
224
- const {
225
- collapsible
226
- } = panelConstraintsArray[index];
227
- const {
228
- collapsedSizePercentage,
229
- maxSizePercentage,
230
- minSizePercentage
231
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[index], groupSizePixels);
232
- totalMaxConstraints += maxSizePercentage;
233
- totalMinConstraints += collapsible ? collapsedSizePercentage : minSizePercentage;
234
- }
165
+ function assert(expectedCondition, message = "Assertion failed!") {
166
+ if (!expectedCondition) {
167
+ console.error(message);
168
+ throw Error(message);
235
169
  }
236
- const {
237
- collapsedSizePercentage,
238
- defaultSizePercentage,
239
- maxSizePercentage,
240
- minSizePercentage
241
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[panelIndex], groupSizePixels);
242
- return {
243
- collapsedSizePercentage,
244
- defaultSizePercentage,
245
- maxSizePercentage: panelConstraintsArray.length > 1 ? Math.min(maxSizePercentage, 100 - totalMinConstraints) : maxSizePercentage,
246
- minSizePercentage: panelConstraintsArray.length > 1 ? Math.max(minSizePercentage, 100 - totalMaxConstraints) : minSizePercentage
247
- };
248
170
  }
249
171
 
250
172
  const PRECISION = 10;
@@ -266,56 +188,41 @@ function fuzzyNumbersEqual(actual, expected, fractionDigits) {
266
188
 
267
189
  // Panel size must be in percentages; pixel values should be pre-converted
268
190
  function resizePanel({
269
- groupSizePixels,
270
- panelConstraints,
191
+ panelConstraints: panelConstraintsArray,
271
192
  panelIndex,
272
193
  size
273
194
  }) {
274
- const hasPixelConstraints = panelConstraints.some(({
275
- collapsedSizePixels,
276
- defaultSizePixels,
277
- minSizePixels,
278
- maxSizePixels
279
- }) => collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null);
280
- if (hasPixelConstraints && groupSizePixels <= 0) {
281
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
282
- return 0;
283
- }
195
+ const panelConstraints = panelConstraintsArray[panelIndex];
196
+ assert(panelConstraints != null);
284
197
  let {
285
- collapsible
286
- } = panelConstraints[panelIndex];
287
- const {
288
- collapsedSizePercentage,
289
- maxSizePercentage,
290
- minSizePercentage
291
- } = computePercentagePanelConstraints(panelConstraints, panelIndex, groupSizePixels);
292
- if (minSizePercentage != null) {
293
- if (fuzzyCompareNumbers(size, minSizePercentage) < 0) {
294
- if (collapsible) {
295
- // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
296
- const halfwayPoint = (collapsedSizePercentage + minSizePercentage) / 2;
297
- if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
298
- size = collapsedSizePercentage;
299
- } else {
300
- size = minSizePercentage;
301
- }
198
+ collapsedSize = 0,
199
+ collapsible,
200
+ maxSize = 100,
201
+ minSize = 0
202
+ } = panelConstraints;
203
+ if (fuzzyCompareNumbers(size, minSize) < 0) {
204
+ if (collapsible) {
205
+ // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
206
+ const halfwayPoint = (collapsedSize + minSize) / 2;
207
+ if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
208
+ size = collapsedSize;
302
209
  } else {
303
- size = minSizePercentage;
210
+ size = minSize;
304
211
  }
212
+ } else {
213
+ size = minSize;
305
214
  }
306
215
  }
307
- if (maxSizePercentage != null) {
308
- size = Math.min(maxSizePercentage, size);
309
- }
216
+ size = Math.min(maxSize, size);
217
+ size = parseFloat(size.toFixed(PRECISION));
310
218
  return size;
311
219
  }
312
220
 
313
221
  // All units must be in percentages; pixel values should be pre-converted
314
222
  function adjustLayoutByDelta({
315
223
  delta,
316
- groupSizePixels,
317
224
  layout: prevLayout,
318
- panelConstraints,
225
+ panelConstraints: panelConstraintsArray,
319
226
  pivotIndices,
320
227
  trigger
321
228
  }) {
@@ -323,6 +230,9 @@ function adjustLayoutByDelta({
323
230
  return prevLayout;
324
231
  }
325
232
  const nextLayout = [...prevLayout];
233
+ const [firstPivotIndex, secondPivotIndex] = pivotIndices;
234
+ assert(firstPivotIndex != null);
235
+ assert(secondPivotIndex != null);
326
236
  let deltaApplied = 0;
327
237
 
328
238
  //const DEBUG = [];
@@ -346,18 +256,23 @@ function adjustLayoutByDelta({
346
256
  if (trigger === "keyboard") {
347
257
  {
348
258
  // Check if we should expand a collapsed panel
349
- const index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
350
- const constraints = panelConstraints[index];
259
+ const index = delta < 0 ? secondPivotIndex : firstPivotIndex;
260
+ const panelConstraints = panelConstraintsArray[index];
261
+ assert(panelConstraints);
262
+
351
263
  //DEBUG.push(`edge case check 1: ${index}`);
352
264
  //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
353
- if (constraints.collapsible) {
265
+ if (panelConstraints.collapsible) {
354
266
  const prevSize = prevLayout[index];
267
+ assert(prevSize != null);
268
+ const panelConstraints = panelConstraintsArray[index];
269
+ assert(panelConstraints);
355
270
  const {
356
- collapsedSizePercentage,
357
- minSizePercentage
358
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
359
- if (fuzzyNumbersEqual(prevSize, collapsedSizePercentage)) {
360
- const localDelta = minSizePercentage - prevSize;
271
+ collapsedSize = 0,
272
+ minSize = 0
273
+ } = panelConstraints;
274
+ if (fuzzyNumbersEqual(prevSize, collapsedSize)) {
275
+ const localDelta = minSize - prevSize;
361
276
  //DEBUG.push(` -> expand delta: ${localDelta}`);
362
277
 
363
278
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -370,18 +285,26 @@ function adjustLayoutByDelta({
370
285
 
371
286
  {
372
287
  // Check if we should collapse a panel at its minimum size
373
- const index = delta < 0 ? pivotIndices[0] : pivotIndices[1];
374
- const constraints = panelConstraints[index];
288
+ const index = delta < 0 ? firstPivotIndex : secondPivotIndex;
289
+ const panelConstraints = panelConstraintsArray[index];
290
+ assert(panelConstraints);
291
+ const {
292
+ collapsible
293
+ } = panelConstraints;
294
+
375
295
  //DEBUG.push(`edge case check 2: ${index}`);
376
- //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
377
- if (constraints.collapsible) {
296
+ //DEBUG.push(` -> collapsible? ${collapsible}`);
297
+ if (collapsible) {
378
298
  const prevSize = prevLayout[index];
299
+ assert(prevSize != null);
300
+ const panelConstraints = panelConstraintsArray[index];
301
+ assert(panelConstraints);
379
302
  const {
380
- collapsedSizePercentage,
381
- minSizePercentage
382
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
383
- if (fuzzyNumbersEqual(prevSize, minSizePercentage)) {
384
- const localDelta = prevSize - collapsedSizePercentage;
303
+ collapsedSize = 0,
304
+ minSize = 0
305
+ } = panelConstraints;
306
+ if (fuzzyNumbersEqual(prevSize, minSize)) {
307
+ const localDelta = prevSize - collapsedSize;
385
308
  //DEBUG.push(` -> expand delta: ${localDelta}`);
386
309
 
387
310
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -403,15 +326,15 @@ function adjustLayoutByDelta({
403
326
  // as an expanding panel might change from collapsed to min size.
404
327
 
405
328
  const increment = delta < 0 ? 1 : -1;
406
- let index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
329
+ let index = delta < 0 ? secondPivotIndex : firstPivotIndex;
407
330
  let maxAvailableDelta = 0;
408
331
 
409
332
  //DEBUG.push("pre calc...");
410
333
  while (true) {
411
334
  const prevSize = prevLayout[index];
335
+ assert(prevSize != null);
412
336
  const maxSafeSize = resizePanel({
413
- groupSizePixels,
414
- panelConstraints,
337
+ panelConstraints: panelConstraintsArray,
415
338
  panelIndex: index,
416
339
  size: 100
417
340
  });
@@ -420,7 +343,7 @@ function adjustLayoutByDelta({
420
343
 
421
344
  maxAvailableDelta += delta;
422
345
  index += increment;
423
- if (index < 0 || index >= panelConstraints.length) {
346
+ if (index < 0 || index >= panelConstraintsArray.length) {
424
347
  break;
425
348
  }
426
349
  }
@@ -435,15 +358,15 @@ function adjustLayoutByDelta({
435
358
  {
436
359
  // Delta added to a panel needs to be subtracted from other panels (within the constraints that those panels allow).
437
360
 
438
- const pivotIndex = delta < 0 ? pivotIndices[0] : pivotIndices[1];
361
+ const pivotIndex = delta < 0 ? firstPivotIndex : secondPivotIndex;
439
362
  let index = pivotIndex;
440
- while (index >= 0 && index < panelConstraints.length) {
363
+ while (index >= 0 && index < panelConstraintsArray.length) {
441
364
  const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
442
365
  const prevSize = prevLayout[index];
366
+ assert(prevSize != null);
443
367
  const unsafeSize = prevSize - deltaRemaining;
444
368
  const safeSize = resizePanel({
445
- groupSizePixels,
446
- panelConstraints,
369
+ panelConstraints: panelConstraintsArray,
447
370
  panelIndex: index,
448
371
  size: unsafeSize
449
372
  });
@@ -475,11 +398,12 @@ function adjustLayoutByDelta({
475
398
  }
476
399
  {
477
400
  // Now distribute the applied delta to the panels in the other direction
478
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
479
- const unsafeSize = prevLayout[pivotIndex] + deltaApplied;
401
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
402
+ const prevSize = prevLayout[pivotIndex];
403
+ assert(prevSize != null);
404
+ const unsafeSize = prevSize + deltaApplied;
480
405
  const safeSize = resizePanel({
481
- groupSizePixels,
482
- panelConstraints,
406
+ panelConstraints: panelConstraintsArray,
483
407
  panelIndex: pivotIndex,
484
408
  size: unsafeSize
485
409
  });
@@ -490,14 +414,14 @@ function adjustLayoutByDelta({
490
414
  // Edge case where expanding or contracting one panel caused another one to change collapsed state
491
415
  if (!fuzzyNumbersEqual(safeSize, unsafeSize)) {
492
416
  let deltaRemaining = unsafeSize - safeSize;
493
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
417
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
494
418
  let index = pivotIndex;
495
- while (index >= 0 && index < panelConstraints.length) {
419
+ while (index >= 0 && index < panelConstraintsArray.length) {
496
420
  const prevSize = nextLayout[index];
421
+ assert(prevSize != null);
497
422
  const unsafeSize = prevSize + deltaRemaining;
498
423
  const safeSize = resizePanel({
499
- groupSizePixels,
500
- panelConstraints,
424
+ panelConstraints: panelConstraintsArray,
501
425
  panelIndex: index,
502
426
  size: unsafeSize
503
427
  });
@@ -521,9 +445,7 @@ function adjustLayoutByDelta({
521
445
  //DEBUG.push("");
522
446
 
523
447
  const totalSize = nextLayout.reduce((total, size) => size + total, 0);
524
- deltaApplied = 100 - totalSize;
525
448
  //DEBUG.push(`total size: ${totalSize}`);
526
- //DEBUG.push(` deltaApplied: ${deltaApplied}`);
527
449
  //console.log(DEBUG.join("\n"));
528
450
 
529
451
  if (!fuzzyNumbersEqual(totalSize, 100)) {
@@ -532,25 +454,6 @@ function adjustLayoutByDelta({
532
454
  return nextLayout;
533
455
  }
534
456
 
535
- function assert(expectedCondition, message = "Assertion failed!") {
536
- if (!expectedCondition) {
537
- console.error(message);
538
- throw Error(message);
539
- }
540
- }
541
-
542
- function getPercentageSizeFromMixedSizes({
543
- sizePercentage,
544
- sizePixels
545
- }, groupSizePixels) {
546
- if (sizePercentage != null) {
547
- return sizePercentage;
548
- } else if (sizePixels != null) {
549
- return convertPixelsToPercentage(sizePixels, groupSizePixels);
550
- }
551
- return undefined;
552
- }
553
-
554
457
  function getResizeHandleElementsForGroup(groupId) {
555
458
  return Array.from(document.querySelectorAll(`[data-panel-resize-handle-id][data-panel-group-id="${groupId}"]`));
556
459
  }
@@ -574,42 +477,6 @@ function getPanelGroupElement(id) {
574
477
  return null;
575
478
  }
576
479
 
577
- function calculateAvailablePanelSizeInPixels(groupId) {
578
- const panelGroupElement = getPanelGroupElement(groupId);
579
- if (panelGroupElement == null) {
580
- return NaN;
581
- }
582
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
583
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
584
- if (direction === "horizontal") {
585
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
586
- return accumulated + handle.offsetWidth;
587
- }, 0);
588
- } else {
589
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
590
- return accumulated + handle.offsetHeight;
591
- }, 0);
592
- }
593
- }
594
-
595
- function getAvailableGroupSizePixels(groupId) {
596
- const panelGroupElement = getPanelGroupElement(groupId);
597
- if (panelGroupElement == null) {
598
- return NaN;
599
- }
600
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
601
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
602
- if (direction === "horizontal") {
603
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
604
- return accumulated + handle.offsetWidth;
605
- }, 0);
606
- } else {
607
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
608
- return accumulated + handle.offsetHeight;
609
- }, 0);
610
- }
611
- }
612
-
613
480
  function getResizeHandleElement(id) {
614
481
  const element = document.querySelector(`[data-panel-resize-handle-id="${id}"]`);
615
482
  if (element) {
@@ -642,14 +509,18 @@ function useWindowSplitterPanelGroupBehavior({
642
509
  didWarnAboutMissingResizeHandle: false
643
510
  });
644
511
  useEffect(() => {
512
+ const eagerValues = eagerValuesRef.current;
513
+ assert(eagerValues);
645
514
  const {
646
515
  panelDataArray
647
- } = eagerValuesRef.current;
516
+ } = eagerValues;
648
517
  const groupElement = getPanelGroupElement(groupId);
649
518
  assert(groupElement != null, `No group found for id "${groupId}"`);
650
519
  const handles = getResizeHandleElementsForGroup(groupId);
520
+ assert(handles);
651
521
  const cleanupFunctions = handles.map(handle => {
652
522
  const handleId = handle.getAttribute("data-panel-resize-handle-id");
523
+ assert(handleId);
653
524
  const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray);
654
525
  if (idBefore == null || idAfter == null) {
655
526
  return () => {};
@@ -665,21 +536,16 @@ function useWindowSplitterPanelGroupBehavior({
665
536
  const index = panelDataArray.findIndex(panelData => panelData.id === idBefore);
666
537
  if (index >= 0) {
667
538
  const panelData = panelDataArray[index];
539
+ assert(panelData);
668
540
  const size = layout[index];
669
- if (size != null && panelData.constraints.collapsible) {
670
- var _getPercentageSizeFro, _getPercentageSizeFro2;
671
- const groupSizePixels = getAvailableGroupSizePixels(groupId);
672
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
673
- sizePercentage: panelData.constraints.collapsedSizePercentage,
674
- sizePixels: panelData.constraints.collapsedSizePixels
675
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
676
- const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
677
- sizePercentage: panelData.constraints.minSizePercentage,
678
- sizePixels: panelData.constraints.minSizePixels
679
- }, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
541
+ const {
542
+ collapsedSize = 0,
543
+ collapsible,
544
+ minSize = 0
545
+ } = panelData.constraints;
546
+ if (size != null && collapsible) {
680
547
  const nextLayout = adjustLayoutByDelta({
681
548
  delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
682
- groupSizePixels,
683
549
  layout,
684
550
  panelConstraints: panelDataArray.map(panelData => panelData.constraints),
685
551
  pivotIndices: determinePivotIndices(groupId, handleId),
@@ -733,6 +599,7 @@ function getResizeEventCursorPosition(direction, event) {
733
599
  return isHorizontal ? event.clientX : event.clientY;
734
600
  } else if (isTouchEvent(event)) {
735
601
  const firstTouch = event.touches[0];
602
+ assert(firstTouch);
736
603
  return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
737
604
  } else {
738
605
  throw Error(`Unsupported event type "${event.type}"`);
@@ -742,12 +609,15 @@ function getResizeEventCursorPosition(direction, event) {
742
609
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState) {
743
610
  const isHorizontal = direction === "horizontal";
744
611
  const handleElement = getResizeHandleElement(dragHandleId);
612
+ assert(handleElement);
745
613
  const groupId = handleElement.getAttribute("data-panel-group-id");
614
+ assert(groupId);
746
615
  let {
747
616
  initialCursorPosition
748
617
  } = initialDragState;
749
618
  const cursorPosition = getResizeEventCursorPosition(direction, event);
750
619
  const groupElement = getPanelGroupElement(groupId);
620
+ assert(groupElement);
751
621
  const groupRect = groupElement.getBoundingClientRect();
752
622
  const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
753
623
  const offsetPixels = cursorPosition - initialCursorPosition;
@@ -756,19 +626,14 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
756
626
  }
757
627
 
758
628
  // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
759
- function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initialDragState, keyboardResizeByOptions) {
629
+ function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy) {
760
630
  if (isKeyDown(event)) {
761
631
  const isHorizontal = direction === "horizontal";
762
- const groupElement = getPanelGroupElement(groupId);
763
- const rect = groupElement.getBoundingClientRect();
764
- const groupSizeInPixels = isHorizontal ? rect.width : rect.height;
765
632
  let delta = 0;
766
633
  if (event.shiftKey) {
767
634
  delta = 100;
768
- } else if (keyboardResizeByOptions.percentage != null) {
769
- delta = keyboardResizeByOptions.percentage;
770
- } else if (keyboardResizeByOptions.pixels != null) {
771
- delta = keyboardResizeByOptions.pixels / groupSizeInPixels;
635
+ } else if (keyboardResizeBy != null) {
636
+ delta = keyboardResizeBy;
772
637
  } else {
773
638
  delta = 10;
774
639
  }
@@ -795,37 +660,43 @@ function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initi
795
660
  }
796
661
  return movement;
797
662
  } else {
663
+ if (initialDragState == null) {
664
+ return 0;
665
+ }
798
666
  return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState);
799
667
  }
800
668
  }
801
669
 
802
670
  function calculateUnsafeDefaultLayout({
803
- groupSizePixels,
804
671
  panelDataArray
805
672
  }) {
806
673
  const layout = Array(panelDataArray.length);
807
- const panelDataConstraints = panelDataArray.map(panelData => panelData.constraints);
674
+ const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
808
675
  let numPanelsWithSizes = 0;
809
676
  let remainingSize = 100;
810
677
 
811
678
  // Distribute default sizes first
812
679
  for (let index = 0; index < panelDataArray.length; index++) {
680
+ const panelConstraints = panelConstraintsArray[index];
681
+ assert(panelConstraints);
813
682
  const {
814
- defaultSizePercentage
815
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
816
- if (defaultSizePercentage != null) {
683
+ defaultSize
684
+ } = panelConstraints;
685
+ if (defaultSize != null) {
817
686
  numPanelsWithSizes++;
818
- layout[index] = defaultSizePercentage;
819
- remainingSize -= defaultSizePercentage;
687
+ layout[index] = defaultSize;
688
+ remainingSize -= defaultSize;
820
689
  }
821
690
  }
822
691
 
823
692
  // Remaining size should be distributed evenly between panels without default sizes
824
693
  for (let index = 0; index < panelDataArray.length; index++) {
694
+ const panelConstraints = panelConstraintsArray[index];
695
+ assert(panelConstraints);
825
696
  const {
826
- defaultSizePercentage
827
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
828
- if (defaultSizePercentage != null) {
697
+ defaultSize
698
+ } = panelConstraints;
699
+ if (defaultSize != null) {
829
700
  continue;
830
701
  }
831
702
  const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
@@ -837,54 +708,36 @@ function calculateUnsafeDefaultLayout({
837
708
  return layout;
838
709
  }
839
710
 
840
- function convertPercentageToPixels(percentage, groupSizePixels) {
841
- return percentage / 100 * groupSizePixels;
842
- }
843
-
844
711
  // Layout should be pre-converted into percentages
845
- function callPanelCallbacks(groupId, panelsArray, layout, panelIdToLastNotifiedMixedSizesMap) {
846
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
847
- layout.forEach((sizePercentage, index) => {
712
+ function callPanelCallbacks(panelsArray, layout, panelIdToLastNotifiedSizeMap) {
713
+ layout.forEach((size, index) => {
848
714
  const panelData = panelsArray[index];
849
- if (!panelData) {
850
- // Handle initial mount (when panels are registered too late to be in the panels array)
851
- // The subsequent render+effects will handle the resize notification
852
- return;
853
- }
715
+ assert(panelData);
854
716
  const {
855
717
  callbacks,
856
718
  constraints,
857
719
  id: panelId
858
720
  } = panelData;
859
721
  const {
722
+ collapsedSize = 0,
860
723
  collapsible
861
724
  } = constraints;
862
- const mixedSizes = {
863
- sizePercentage,
864
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
865
- };
866
- const lastNotifiedMixedSizes = panelIdToLastNotifiedMixedSizesMap[panelId];
867
- if (lastNotifiedMixedSizes == null || mixedSizes.sizePercentage !== lastNotifiedMixedSizes.sizePercentage || mixedSizes.sizePixels !== lastNotifiedMixedSizes.sizePixels) {
868
- panelIdToLastNotifiedMixedSizesMap[panelId] = mixedSizes;
725
+ const lastNotifiedSize = panelIdToLastNotifiedSizeMap[panelId];
726
+ if (lastNotifiedSize == null || size !== lastNotifiedSize) {
727
+ panelIdToLastNotifiedSizeMap[panelId] = size;
869
728
  const {
870
729
  onCollapse,
871
730
  onExpand,
872
731
  onResize
873
732
  } = callbacks;
874
733
  if (onResize) {
875
- onResize(mixedSizes, lastNotifiedMixedSizes);
734
+ onResize(size, lastNotifiedSize);
876
735
  }
877
736
  if (collapsible && (onCollapse || onExpand)) {
878
- var _getPercentageSizeFro;
879
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
880
- sizePercentage: constraints.collapsedSizePercentage,
881
- sizePixels: constraints.collapsedSizePixels
882
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
883
- const size = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
884
- if (onExpand && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage === collapsedSize) && size !== collapsedSize) {
737
+ if (onExpand && (lastNotifiedSize == null || lastNotifiedSize === collapsedSize) && size !== collapsedSize) {
885
738
  onExpand();
886
739
  }
887
- if (onCollapse && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage !== collapsedSize) && size === collapsedSize) {
740
+ if (onCollapse && (lastNotifiedSize == null || lastNotifiedSize !== collapsedSize) && size === collapsedSize) {
888
741
  onCollapse();
889
742
  }
890
743
  }
@@ -1067,31 +920,32 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1067
920
  }
1068
921
  }
1069
922
 
1070
- function shouldMonitorPixelBasedConstraints(constraints) {
1071
- return constraints.some(constraints => {
1072
- return constraints.collapsedSizePixels !== undefined || constraints.maxSizePixels !== undefined || constraints.minSizePixels !== undefined;
1073
- });
1074
- }
1075
-
1076
923
  // All units must be in percentages; pixel values should be pre-converted
1077
924
  function validatePanelGroupLayout({
1078
- groupSizePixels,
1079
925
  layout: prevLayout,
1080
926
  panelConstraints
1081
927
  }) {
1082
928
  const nextLayout = [...prevLayout];
929
+ const nextLayoutTotalSize = nextLayout.reduce((accumulated, current) => accumulated + current, 0);
1083
930
 
1084
931
  // Validate layout expectations
1085
932
  if (nextLayout.length !== panelConstraints.length) {
1086
933
  throw Error(`Invalid ${panelConstraints.length} panel layout: ${nextLayout.map(size => `${size}%`).join(", ")}`);
1087
- } else if (!fuzzyNumbersEqual(nextLayout.reduce((accumulated, current) => accumulated + current, 0), 100)) ;
934
+ } else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100)) {
935
+ for (let index = 0; index < panelConstraints.length; index++) {
936
+ const unsafeSize = nextLayout[index];
937
+ assert(unsafeSize != null);
938
+ const safeSize = 100 / nextLayoutTotalSize * unsafeSize;
939
+ nextLayout[index] = safeSize;
940
+ }
941
+ }
1088
942
  let remainingSize = 0;
1089
943
 
1090
944
  // First pass: Validate the proposed layout given each panel's constraints
1091
945
  for (let index = 0; index < panelConstraints.length; index++) {
1092
946
  const unsafeSize = nextLayout[index];
947
+ assert(unsafeSize != null);
1093
948
  const safeSize = resizePanel({
1094
- groupSizePixels,
1095
949
  panelConstraints,
1096
950
  panelIndex: index,
1097
951
  size: unsafeSize
@@ -1107,9 +961,9 @@ function validatePanelGroupLayout({
1107
961
  if (!fuzzyNumbersEqual(remainingSize, 0)) {
1108
962
  for (let index = 0; index < panelConstraints.length; index++) {
1109
963
  const prevSize = nextLayout[index];
964
+ assert(prevSize != null);
1110
965
  const unsafeSize = prevSize + remainingSize;
1111
966
  const safeSize = resizePanel({
1112
- groupSizePixels,
1113
967
  panelConstraints,
1114
968
  panelIndex: index,
1115
969
  size: unsafeSize
@@ -1144,21 +998,20 @@ function PanelGroupWithForwardedRef({
1144
998
  autoSaveId = null,
1145
999
  children,
1146
1000
  className: classNameFromProps = "",
1147
- dataAttributes,
1148
1001
  direction,
1149
1002
  forwardedRef,
1150
- id: idFromProps,
1003
+ id: idFromProps = null,
1151
1004
  onLayout = null,
1152
- keyboardResizeByPercentage = null,
1153
- keyboardResizeByPixels = null,
1005
+ keyboardResizeBy = null,
1154
1006
  storage = defaultStorage,
1155
1007
  style: styleFromProps,
1156
- tagName: Type = "div"
1008
+ tagName: Type = "div",
1009
+ ...rest
1157
1010
  }) {
1158
1011
  const groupId = useUniqueId(idFromProps);
1159
1012
  const [dragState, setDragState] = useState(null);
1160
1013
  const [layout, setLayout] = useState([]);
1161
- const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
1014
+ const panelIdToLastNotifiedSizeMapRef = useRef({});
1162
1015
  const panelSizeBeforeCollapseRef = useRef(new Map());
1163
1016
  const prevDeltaRef = useRef(0);
1164
1017
  const committedValuesRef = useRef({
@@ -1166,8 +1019,7 @@ function PanelGroupWithForwardedRef({
1166
1019
  direction,
1167
1020
  dragState,
1168
1021
  id: groupId,
1169
- keyboardResizeByPercentage,
1170
- keyboardResizeByPixels,
1022
+ keyboardResizeBy,
1171
1023
  onLayout,
1172
1024
  storage
1173
1025
  });
@@ -1183,33 +1035,20 @@ function PanelGroupWithForwardedRef({
1183
1035
  useImperativeHandle(forwardedRef, () => ({
1184
1036
  getId: () => committedValuesRef.current.id,
1185
1037
  getLayout: () => {
1186
- const {
1187
- id: groupId
1188
- } = committedValuesRef.current;
1189
1038
  const {
1190
1039
  layout
1191
1040
  } = eagerValuesRef.current;
1192
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1193
- return layout.map(sizePercentage => {
1194
- return {
1195
- sizePercentage,
1196
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1197
- };
1198
- });
1041
+ return layout;
1199
1042
  },
1200
- setLayout: mixedSizes => {
1043
+ setLayout: unsafeLayout => {
1201
1044
  const {
1202
- id: groupId,
1203
1045
  onLayout
1204
1046
  } = committedValuesRef.current;
1205
1047
  const {
1206
1048
  layout: prevLayout,
1207
1049
  panelDataArray
1208
1050
  } = eagerValuesRef.current;
1209
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1210
- const unsafeLayout = mixedSizes.map(mixedSize => getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels));
1211
1051
  const safeLayout = validatePanelGroupLayout({
1212
- groupSizePixels,
1213
1052
  layout: unsafeLayout,
1214
1053
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1215
1054
  });
@@ -1217,16 +1056,12 @@ function PanelGroupWithForwardedRef({
1217
1056
  setLayout(safeLayout);
1218
1057
  eagerValuesRef.current.layout = safeLayout;
1219
1058
  if (onLayout) {
1220
- onLayout(safeLayout.map(sizePercentage => ({
1221
- sizePercentage,
1222
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1223
- })));
1059
+ onLayout(safeLayout);
1224
1060
  }
1225
- callPanelCallbacks(groupId, panelDataArray, safeLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1061
+ callPanelCallbacks(panelDataArray, safeLayout, panelIdToLastNotifiedSizeMapRef.current);
1226
1062
  }
1227
1063
  }
1228
1064
  }), []);
1229
-
1230
1065
  useWindowSplitterPanelGroupBehavior({
1231
1066
  committedValuesRef,
1232
1067
  eagerValuesRef,
@@ -1245,12 +1080,14 @@ function PanelGroupWithForwardedRef({
1245
1080
  if (layout.length === 0 || layout.length !== panelDataArray.length) {
1246
1081
  return;
1247
1082
  }
1083
+ let debouncedSave = debounceMap[autoSaveId];
1248
1084
 
1249
1085
  // Limit the frequency of localStorage updates.
1250
- if (!debounceMap[autoSaveId]) {
1251
- debounceMap[autoSaveId] = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1086
+ if (debouncedSave == null) {
1087
+ debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1088
+ debounceMap[autoSaveId] = debouncedSave;
1252
1089
  }
1253
- debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
1090
+ debouncedSave(autoSaveId, panelDataArray, layout, storage);
1254
1091
  }
1255
1092
  }, [autoSaveId, layout, storage]);
1256
1093
 
@@ -1270,20 +1107,19 @@ function PanelGroupWithForwardedRef({
1270
1107
  if (panelData.constraints.collapsible) {
1271
1108
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1272
1109
  const {
1273
- collapsedSizePercentage,
1274
- panelSizePercentage,
1275
- pivotIndices,
1276
- groupSizePixels
1277
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1278
- if (panelSizePercentage !== collapsedSizePercentage) {
1110
+ collapsedSize = 0,
1111
+ panelSize,
1112
+ pivotIndices
1113
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1114
+ assert(panelSize != null);
1115
+ if (panelSize !== collapsedSize) {
1279
1116
  // Store size before collapse;
1280
1117
  // This is the size that gets restored if the expand() API is used.
1281
- panelSizeBeforeCollapseRef.current.set(panelData.id, panelSizePercentage);
1118
+ panelSizeBeforeCollapseRef.current.set(panelData.id, panelSize);
1282
1119
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1283
- const delta = isLastPanel ? panelSizePercentage - collapsedSizePercentage : collapsedSizePercentage - panelSizePercentage;
1120
+ const delta = isLastPanel ? panelSize - collapsedSize : collapsedSize - panelSize;
1284
1121
  const nextLayout = adjustLayoutByDelta({
1285
1122
  delta,
1286
- groupSizePixels,
1287
1123
  layout: prevLayout,
1288
1124
  panelConstraints: panelConstraintsArray,
1289
1125
  pivotIndices,
@@ -1293,16 +1129,13 @@ function PanelGroupWithForwardedRef({
1293
1129
  setLayout(nextLayout);
1294
1130
  eagerValuesRef.current.layout = nextLayout;
1295
1131
  if (onLayout) {
1296
- onLayout(nextLayout.map(sizePercentage => ({
1297
- sizePercentage,
1298
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1299
- })));
1132
+ onLayout(nextLayout);
1300
1133
  }
1301
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1134
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1302
1135
  }
1303
1136
  }
1304
1137
  }
1305
- }, [groupId]);
1138
+ }, []);
1306
1139
 
1307
1140
  // External APIs are safe to memoize via committed values ref
1308
1141
  const expandPanel = useCallback(panelData => {
@@ -1316,21 +1149,19 @@ function PanelGroupWithForwardedRef({
1316
1149
  if (panelData.constraints.collapsible) {
1317
1150
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1318
1151
  const {
1319
- collapsedSizePercentage,
1320
- panelSizePercentage,
1321
- minSizePercentage,
1322
- pivotIndices,
1323
- groupSizePixels
1324
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1325
- if (panelSizePercentage === collapsedSizePercentage) {
1152
+ collapsedSize = 0,
1153
+ panelSize,
1154
+ minSize = 0,
1155
+ pivotIndices
1156
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1157
+ if (panelSize === collapsedSize) {
1326
1158
  // Restore this panel to the size it was before it was collapsed, if possible.
1327
- const prevPanelSizePercentage = panelSizeBeforeCollapseRef.current.get(panelData.id);
1328
- const baseSizePercentage = prevPanelSizePercentage != null && prevPanelSizePercentage >= minSizePercentage ? prevPanelSizePercentage : minSizePercentage;
1159
+ const prevPanelSize = panelSizeBeforeCollapseRef.current.get(panelData.id);
1160
+ const baseSize = prevPanelSize != null && prevPanelSize >= minSize ? prevPanelSize : minSize;
1329
1161
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1330
- const delta = isLastPanel ? panelSizePercentage - baseSizePercentage : baseSizePercentage - panelSizePercentage;
1162
+ const delta = isLastPanel ? panelSize - baseSize : baseSize - panelSize;
1331
1163
  const nextLayout = adjustLayoutByDelta({
1332
1164
  delta,
1333
- groupSizePixels,
1334
1165
  layout: prevLayout,
1335
1166
  panelConstraints: panelConstraintsArray,
1336
1167
  pivotIndices,
@@ -1340,16 +1171,13 @@ function PanelGroupWithForwardedRef({
1340
1171
  setLayout(nextLayout);
1341
1172
  eagerValuesRef.current.layout = nextLayout;
1342
1173
  if (onLayout) {
1343
- onLayout(nextLayout.map(sizePercentage => ({
1344
- sizePercentage,
1345
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1346
- })));
1174
+ onLayout(nextLayout);
1347
1175
  }
1348
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1176
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1349
1177
  }
1350
1178
  }
1351
1179
  }
1352
- }, [groupId]);
1180
+ }, []);
1353
1181
 
1354
1182
  // External APIs are safe to memoize via committed values ref
1355
1183
  const getPanelSize = useCallback(panelData => {
@@ -1358,14 +1186,11 @@ function PanelGroupWithForwardedRef({
1358
1186
  panelDataArray
1359
1187
  } = eagerValuesRef.current;
1360
1188
  const {
1361
- panelSizePercentage,
1362
- panelSizePixels
1363
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1364
- return {
1365
- sizePercentage: panelSizePercentage,
1366
- sizePixels: panelSizePixels
1367
- };
1368
- }, [groupId]);
1189
+ panelSize
1190
+ } = panelDataHelper(panelDataArray, panelData, layout);
1191
+ assert(panelSize != null);
1192
+ return panelSize;
1193
+ }, []);
1369
1194
 
1370
1195
  // This API should never read from committedValuesRef
1371
1196
  const getPanelStyle = useCallback(panelData => {
@@ -1388,12 +1213,12 @@ function PanelGroupWithForwardedRef({
1388
1213
  panelDataArray
1389
1214
  } = eagerValuesRef.current;
1390
1215
  const {
1391
- collapsedSizePercentage,
1216
+ collapsedSize,
1392
1217
  collapsible,
1393
- panelSizePercentage
1394
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1395
- return collapsible === true && panelSizePercentage === collapsedSizePercentage;
1396
- }, [groupId]);
1218
+ panelSize
1219
+ } = panelDataHelper(panelDataArray, panelData, layout);
1220
+ return collapsible === true && panelSize === collapsedSize;
1221
+ }, []);
1397
1222
 
1398
1223
  // External APIs are safe to memoize via committed values ref
1399
1224
  const isPanelExpanded = useCallback(panelData => {
@@ -1402,12 +1227,13 @@ function PanelGroupWithForwardedRef({
1402
1227
  panelDataArray
1403
1228
  } = eagerValuesRef.current;
1404
1229
  const {
1405
- collapsedSizePercentage,
1230
+ collapsedSize = 0,
1406
1231
  collapsible,
1407
- panelSizePercentage
1408
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1409
- return !collapsible || panelSizePercentage > collapsedSizePercentage;
1410
- }, [groupId]);
1232
+ panelSize
1233
+ } = panelDataHelper(panelDataArray, panelData, layout);
1234
+ assert(panelSize != null);
1235
+ return !collapsible || panelSize > collapsedSize;
1236
+ }, []);
1411
1237
  const registerPanel = useCallback(panelData => {
1412
1238
  const {
1413
1239
  autoSaveId,
@@ -1447,18 +1273,8 @@ function PanelGroupWithForwardedRef({
1447
1273
  if (autoSaveId) {
1448
1274
  unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1449
1275
  }
1450
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1451
- if (groupSizePixels <= 0) {
1452
- if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
1453
- constraints
1454
- }) => constraints))) {
1455
- // Wait until the group has rendered a non-zero size before computing layout.
1456
- return;
1457
- }
1458
- }
1459
1276
  if (unsafeLayout == null) {
1460
1277
  unsafeLayout = calculateUnsafeDefaultLayout({
1461
- groupSizePixels,
1462
1278
  panelDataArray
1463
1279
  });
1464
1280
  }
@@ -1466,7 +1282,6 @@ function PanelGroupWithForwardedRef({
1466
1282
  // Validate even saved layouts in case something has changed since last render
1467
1283
  // e.g. for pixel groups, this could be the size of the window
1468
1284
  const nextLayout = validatePanelGroupLayout({
1469
- groupSizePixels,
1470
1285
  layout: unsafeLayout,
1471
1286
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1472
1287
  });
@@ -1478,12 +1293,9 @@ function PanelGroupWithForwardedRef({
1478
1293
  eagerValuesRef.current.layout = nextLayout;
1479
1294
  if (!areEqual(prevLayout, nextLayout)) {
1480
1295
  if (onLayout) {
1481
- onLayout(nextLayout.map(sizePercentage => ({
1482
- sizePercentage,
1483
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1484
- })));
1296
+ onLayout(nextLayout);
1485
1297
  }
1486
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1298
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1487
1299
  }
1488
1300
  }, []);
1489
1301
  const registerResizeHandle = useCallback(dragHandleId => {
@@ -1493,8 +1305,7 @@ function PanelGroupWithForwardedRef({
1493
1305
  direction,
1494
1306
  dragState,
1495
1307
  id: groupId,
1496
- keyboardResizeByPercentage,
1497
- keyboardResizeByPixels,
1308
+ keyboardResizeBy,
1498
1309
  onLayout
1499
1310
  } = committedValuesRef.current;
1500
1311
  const {
@@ -1505,10 +1316,7 @@ function PanelGroupWithForwardedRef({
1505
1316
  initialLayout
1506
1317
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1507
1318
  const pivotIndices = determinePivotIndices(groupId, dragHandleId);
1508
- let delta = calculateDeltaPercentage(event, groupId, dragHandleId, direction, dragState, {
1509
- percentage: keyboardResizeByPercentage,
1510
- pixels: keyboardResizeByPixels
1511
- });
1319
+ let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy);
1512
1320
  if (delta === 0) {
1513
1321
  return;
1514
1322
  }
@@ -1518,11 +1326,9 @@ function PanelGroupWithForwardedRef({
1518
1326
  if (document.dir === "rtl" && isHorizontal) {
1519
1327
  delta = -delta;
1520
1328
  }
1521
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1522
1329
  const panelConstraints = panelDataArray.map(panelData => panelData.constraints);
1523
1330
  const nextLayout = adjustLayoutByDelta({
1524
1331
  delta,
1525
- groupSizePixels,
1526
1332
  layout: initialLayout !== null && initialLayout !== void 0 ? initialLayout : prevLayout,
1527
1333
  panelConstraints,
1528
1334
  pivotIndices,
@@ -1558,18 +1364,15 @@ function PanelGroupWithForwardedRef({
1558
1364
  setLayout(nextLayout);
1559
1365
  eagerValuesRef.current.layout = nextLayout;
1560
1366
  if (onLayout) {
1561
- onLayout(nextLayout.map(sizePercentage => ({
1562
- sizePercentage,
1563
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1564
- })));
1367
+ onLayout(nextLayout);
1565
1368
  }
1566
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1369
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1567
1370
  }
1568
1371
  };
1569
1372
  }, []);
1570
1373
 
1571
1374
  // External APIs are safe to memoize via committed values ref
1572
- const resizePanel = useCallback((panelData, mixedSizes) => {
1375
+ const resizePanel = useCallback((panelData, unsafePanelSize) => {
1573
1376
  const {
1574
1377
  onLayout
1575
1378
  } = committedValuesRef.current;
@@ -1579,16 +1382,14 @@ function PanelGroupWithForwardedRef({
1579
1382
  } = eagerValuesRef.current;
1580
1383
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1581
1384
  const {
1582
- groupSizePixels,
1583
- panelSizePercentage,
1385
+ panelSize,
1584
1386
  pivotIndices
1585
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1586
- const sizePercentage = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
1387
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1388
+ assert(panelSize != null);
1587
1389
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1588
- const delta = isLastPanel ? panelSizePercentage - sizePercentage : sizePercentage - panelSizePercentage;
1390
+ const delta = isLastPanel ? panelSize - unsafePanelSize : unsafePanelSize - panelSize;
1589
1391
  const nextLayout = adjustLayoutByDelta({
1590
1392
  delta,
1591
- groupSizePixels,
1592
1393
  layout: prevLayout,
1593
1394
  panelConstraints: panelConstraintsArray,
1594
1395
  pivotIndices,
@@ -1598,14 +1399,11 @@ function PanelGroupWithForwardedRef({
1598
1399
  setLayout(nextLayout);
1599
1400
  eagerValuesRef.current.layout = nextLayout;
1600
1401
  if (onLayout) {
1601
- onLayout(nextLayout.map(sizePercentage => ({
1602
- sizePercentage,
1603
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1604
- })));
1402
+ onLayout(nextLayout);
1605
1403
  }
1606
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1404
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1607
1405
  }
1608
- }, [groupId]);
1406
+ }, []);
1609
1407
  const startDragging = useCallback((dragHandleId, event) => {
1610
1408
  const {
1611
1409
  direction
@@ -1614,6 +1412,7 @@ function PanelGroupWithForwardedRef({
1614
1412
  layout
1615
1413
  } = eagerValuesRef.current;
1616
1414
  const handleElement = getResizeHandleElement(dragHandleId);
1415
+ assert(handleElement);
1617
1416
  const initialCursorPosition = getResizeEventCursorPosition(direction, event);
1618
1417
  setDragState({
1619
1418
  dragHandleId,
@@ -1632,7 +1431,6 @@ function PanelGroupWithForwardedRef({
1632
1431
  });
1633
1432
  const unregisterPanel = useCallback(panelData => {
1634
1433
  const {
1635
- id: groupId,
1636
1434
  onLayout
1637
1435
  } = committedValuesRef.current;
1638
1436
  const {
@@ -1655,7 +1453,7 @@ function PanelGroupWithForwardedRef({
1655
1453
  const {
1656
1454
  pendingPanelIds
1657
1455
  } = unregisterPanelRef.current;
1658
- const map = panelIdToLastNotifiedMixedSizesMapRef.current;
1456
+ const map = panelIdToLastNotifiedSizeMapRef.current;
1659
1457
 
1660
1458
  // TRICKY
1661
1459
  // Strict effects mode
@@ -1664,7 +1462,7 @@ function PanelGroupWithForwardedRef({
1664
1462
  pendingPanelIds.delete(panelId);
1665
1463
  if (panelDataArray.find(({
1666
1464
  id
1667
- }) => id === panelId) == null) {
1465
+ }) => id === panelId) != null) {
1668
1466
  unmountDueToStrictMode = true;
1669
1467
 
1670
1468
  // TRICKY
@@ -1681,16 +1479,13 @@ function PanelGroupWithForwardedRef({
1681
1479
  // The group is unmounting; skip layout calculation.
1682
1480
  return;
1683
1481
  }
1684
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1685
1482
  let unsafeLayout = calculateUnsafeDefaultLayout({
1686
- groupSizePixels,
1687
1483
  panelDataArray
1688
1484
  });
1689
1485
 
1690
1486
  // Validate even saved layouts in case something has changed since last render
1691
1487
  // e.g. for pixel groups, this could be the size of the window
1692
1488
  const nextLayout = validatePanelGroupLayout({
1693
- groupSizePixels,
1694
1489
  layout: unsafeLayout,
1695
1490
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1696
1491
  });
@@ -1698,12 +1493,9 @@ function PanelGroupWithForwardedRef({
1698
1493
  setLayout(nextLayout);
1699
1494
  eagerValuesRef.current.layout = nextLayout;
1700
1495
  if (onLayout) {
1701
- onLayout(nextLayout.map(sizePercentage => ({
1702
- sizePercentage,
1703
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1704
- })));
1496
+ onLayout(nextLayout);
1705
1497
  }
1706
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1498
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1707
1499
  }
1708
1500
  }, 0);
1709
1501
  }, []);
@@ -1734,13 +1526,13 @@ function PanelGroupWithForwardedRef({
1734
1526
  return createElement(PanelGroupContext.Provider, {
1735
1527
  value: context
1736
1528
  }, createElement(Type, {
1529
+ ...rest,
1737
1530
  children,
1738
1531
  className: classNameFromProps,
1739
1532
  style: {
1740
1533
  ...style,
1741
1534
  ...styleFromProps
1742
1535
  },
1743
- ...dataAttributes,
1744
1536
  // CSS selectors
1745
1537
  "data-panel-group": "",
1746
1538
  "data-panel-group-direction": direction,
@@ -1753,22 +1545,16 @@ const PanelGroup = forwardRef((props, ref) => createElement(PanelGroupWithForwar
1753
1545
  }));
1754
1546
  PanelGroupWithForwardedRef.displayName = "PanelGroup";
1755
1547
  PanelGroup.displayName = "forwardRef(PanelGroup)";
1756
- function panelDataHelper(groupId, panelDataArray, panelData, layout) {
1548
+ function panelDataHelper(panelDataArray, panelData, layout) {
1757
1549
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1758
1550
  const panelIndex = panelDataArray.indexOf(panelData);
1759
1551
  const panelConstraints = panelConstraintsArray[panelIndex];
1760
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1761
- const percentagePanelConstraints = computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels);
1762
1552
  const isLastPanel = panelIndex === panelDataArray.length - 1;
1763
1553
  const pivotIndices = isLastPanel ? [panelIndex - 1, panelIndex] : [panelIndex, panelIndex + 1];
1764
- const panelSizePercentage = layout[panelIndex];
1765
- const panelSizePixels = convertPercentageToPixels(panelSizePercentage, groupSizePixels);
1554
+ const panelSize = layout[panelIndex];
1766
1555
  return {
1767
- ...percentagePanelConstraints,
1768
- collapsible: panelConstraints.collapsible,
1769
- panelSizePercentage,
1770
- panelSizePixels,
1771
- groupSizePixels,
1556
+ ...panelConstraints,
1557
+ panelSize,
1772
1558
  pivotIndices
1773
1559
  };
1774
1560
  }
@@ -1808,6 +1594,7 @@ function useWindowSplitterResizeHandlerBehavior({
1808
1594
  {
1809
1595
  event.preventDefault();
1810
1596
  const groupId = handleElement.getAttribute("data-panel-group-id");
1597
+ assert(groupId);
1811
1598
  const handles = getResizeHandleElementsForGroup(groupId);
1812
1599
  const index = getResizeHandleElementIndex(groupId, handleId);
1813
1600
  assert(index !== null);
@@ -1828,12 +1615,13 @@ function useWindowSplitterResizeHandlerBehavior({
1828
1615
  function PanelResizeHandle({
1829
1616
  children = null,
1830
1617
  className: classNameFromProps = "",
1831
- dataAttributes,
1832
1618
  disabled = false,
1833
- id: idFromProps = null,
1619
+ id: idFromProps,
1834
1620
  onDragging,
1835
1621
  style: styleFromProps = {},
1836
- tagName: Type = "div"
1622
+ tabIndex = 0,
1623
+ tagName: Type = "div",
1624
+ ...rest
1837
1625
  }) {
1838
1626
  const divElementRef = useRef(null);
1839
1627
 
@@ -1863,8 +1651,9 @@ function PanelResizeHandle({
1863
1651
  const stopDraggingAndBlur = useCallback(() => {
1864
1652
  // Clicking on the drag handle shouldn't leave it focused;
1865
1653
  // That would cause the PanelGroup to think it was still active.
1866
- const div = divElementRef.current;
1867
- div.blur();
1654
+ const divElement = divElementRef.current;
1655
+ assert(divElement);
1656
+ divElement.blur();
1868
1657
  stopDragging();
1869
1658
  const {
1870
1659
  onDragging
@@ -1892,6 +1681,7 @@ function PanelResizeHandle({
1892
1681
  resizeHandler(event);
1893
1682
  };
1894
1683
  const divElement = divElementRef.current;
1684
+ assert(divElement);
1895
1685
  const targetDocument = divElement.ownerDocument;
1896
1686
  targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
1897
1687
  targetDocument.body.addEventListener("mousemove", onMove);
@@ -1919,15 +1709,18 @@ function PanelResizeHandle({
1919
1709
  userSelect: "none"
1920
1710
  };
1921
1711
  return createElement(Type, {
1712
+ ...rest,
1922
1713
  children,
1923
1714
  className: classNameFromProps,
1924
1715
  onBlur: () => setIsFocused(false),
1925
1716
  onFocus: () => setIsFocused(true),
1926
1717
  onMouseDown: event => {
1927
1718
  startDragging(resizeHandleId, event.nativeEvent);
1719
+ const callbacks = callbacksRef.current;
1720
+ assert(callbacks);
1928
1721
  const {
1929
1722
  onDragging
1930
- } = callbacksRef.current;
1723
+ } = callbacks;
1931
1724
  if (onDragging) {
1932
1725
  onDragging(true);
1933
1726
  }
@@ -1937,9 +1730,11 @@ function PanelResizeHandle({
1937
1730
  onTouchEnd: stopDraggingAndBlur,
1938
1731
  onTouchStart: event => {
1939
1732
  startDragging(resizeHandleId, event.nativeEvent);
1733
+ const callbacks = callbacksRef.current;
1734
+ assert(callbacks);
1940
1735
  const {
1941
1736
  onDragging
1942
- } = callbacksRef.current;
1737
+ } = callbacks;
1943
1738
  if (onDragging) {
1944
1739
  onDragging(true);
1945
1740
  }
@@ -1950,8 +1745,7 @@ function PanelResizeHandle({
1950
1745
  ...style,
1951
1746
  ...styleFromProps
1952
1747
  },
1953
- tabIndex: 0,
1954
- ...dataAttributes,
1748
+ tabIndex,
1955
1749
  // CSS selectors
1956
1750
  "data-panel-group-direction": direction,
1957
1751
  "data-panel-group-id": groupId,
@@ -1966,3 +1760,4 @@ PanelResizeHandle.displayName = "PanelResizeHandle";
1966
1760
  exports.Panel = Panel;
1967
1761
  exports.PanelGroup = PanelGroup;
1968
1762
  exports.PanelResizeHandle = PanelResizeHandle;
1763
+ exports.assert = assert;