react-resizable-panels 0.0.62 → 1.0.0-rc.1

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 (73) hide show
  1. package/.eslintrc.cjs +1 -0
  2. package/CHANGELOG.md +9 -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 +255 -519
  11. package/dist/react-resizable-panels.browser.cjs.mjs +2 -1
  12. package/dist/react-resizable-panels.browser.development.cjs.js +281 -575
  13. package/dist/react-resizable-panels.browser.development.cjs.mjs +2 -1
  14. package/dist/react-resizable-panels.browser.development.esm.js +281 -576
  15. package/dist/react-resizable-panels.browser.esm.js +255 -520
  16. package/dist/react-resizable-panels.cjs.js +255 -519
  17. package/dist/react-resizable-panels.cjs.js.map +1 -0
  18. package/dist/react-resizable-panels.cjs.mjs +2 -1
  19. package/dist/react-resizable-panels.development.cjs.js +283 -577
  20. package/dist/react-resizable-panels.development.cjs.mjs +2 -1
  21. package/dist/react-resizable-panels.development.esm.js +283 -578
  22. package/dist/react-resizable-panels.development.node.cjs.js +269 -503
  23. package/dist/react-resizable-panels.development.node.cjs.mjs +2 -1
  24. package/dist/react-resizable-panels.development.node.esm.js +269 -504
  25. package/dist/react-resizable-panels.esm.js +255 -520
  26. package/dist/react-resizable-panels.esm.js.map +1 -0
  27. package/dist/react-resizable-panels.node.cjs.js +241 -445
  28. package/dist/react-resizable-panels.node.cjs.mjs +2 -1
  29. package/dist/react-resizable-panels.node.esm.js +241 -446
  30. package/package.json +1 -1
  31. package/src/Panel.test.tsx +74 -73
  32. package/src/Panel.ts +44 -68
  33. package/src/PanelGroup.test.tsx +43 -42
  34. package/src/PanelGroup.ts +189 -403
  35. package/src/PanelGroupContext.ts +2 -3
  36. package/src/PanelResizeHandle.test.tsx +68 -0
  37. package/src/PanelResizeHandle.ts +31 -22
  38. package/src/hooks/useWindowSplitterBehavior.ts +2 -1
  39. package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +22 -33
  40. package/src/index.ts +4 -3
  41. package/src/types.ts +0 -9
  42. package/src/utils/adjustLayoutByDelta.test.ts +206 -336
  43. package/src/utils/adjustLayoutByDelta.ts +59 -51
  44. package/src/utils/assert.ts +1 -1
  45. package/src/utils/calculateAriaValues.test.ts +6 -11
  46. package/src/utils/calculateAriaValues.ts +7 -29
  47. package/src/utils/calculateDeltaPercentage.ts +8 -15
  48. package/src/utils/calculateDragOffsetPercentage.ts +11 -5
  49. package/src/utils/calculateUnsafeDefaultLayout.test.ts +4 -9
  50. package/src/utils/calculateUnsafeDefaultLayout.ts +13 -18
  51. package/src/utils/callPanelCallbacks.ts +11 -46
  52. package/src/utils/computePanelFlexBoxStyle.ts +3 -2
  53. package/src/utils/getResizeEventCursorPosition.ts +2 -0
  54. package/src/utils/resizePanel.test.ts +6 -52
  55. package/src/utils/resizePanel.ts +24 -46
  56. package/src/utils/test-utils.ts +6 -7
  57. package/src/utils/validatePanelConstraints.test.ts +12 -65
  58. package/src/utils/validatePanelConstraints.ts +26 -67
  59. package/src/utils/validatePanelGroupLayout.test.ts +27 -142
  60. package/src/utils/validatePanelGroupLayout.ts +17 -13
  61. package/src/vendor/react.ts +2 -0
  62. package/src/utils/computePercentagePanelConstraints.test.ts +0 -98
  63. package/src/utils/computePercentagePanelConstraints.ts +0 -56
  64. package/src/utils/convertPercentageToPixels.test.ts +0 -9
  65. package/src/utils/convertPercentageToPixels.ts +0 -6
  66. package/src/utils/convertPixelConstraintsToPercentages.test.ts +0 -47
  67. package/src/utils/convertPixelConstraintsToPercentages.ts +0 -72
  68. package/src/utils/convertPixelsToPercentage.test.ts +0 -9
  69. package/src/utils/convertPixelsToPercentage.ts +0 -6
  70. package/src/utils/getPercentageSizeFromMixedSizes.test.ts +0 -47
  71. package/src/utils/getPercentageSizeFromMixedSizes.ts +0 -15
  72. package/src/utils/shouldMonitorPixelBasedConstraints.test.ts +0 -23
  73. package/src/utils/shouldMonitorPixelBasedConstraints.ts +0 -13
@@ -39,24 +39,20 @@ function useUniqueId(idFromParams = null) {
39
39
  function PanelWithForwardedRef({
40
40
  children,
41
41
  className: classNameFromProps = "",
42
- collapsedSizePercentage,
43
- collapsedSizePixels,
42
+ collapsedSize,
44
43
  collapsible,
45
- dataAttributes,
46
- defaultSizePercentage,
47
- defaultSizePixels,
44
+ defaultSize,
48
45
  forwardedRef,
49
46
  id: idFromProps,
50
- maxSizePercentage,
51
- maxSizePixels,
52
- minSizePercentage,
53
- minSizePixels,
47
+ maxSize,
48
+ minSize,
54
49
  onCollapse,
55
50
  onExpand,
56
51
  onResize,
57
52
  order,
58
53
  style: styleFromProps,
59
- tagName: Type = "div"
54
+ tagName: Type = "div",
55
+ ...rest
60
56
  }) {
61
57
  const context = useContext(PanelGroupContext);
62
58
  if (context === null) {
@@ -81,15 +77,11 @@ function PanelWithForwardedRef({
81
77
  onResize
82
78
  },
83
79
  constraints: {
84
- collapsedSizePercentage,
85
- collapsedSizePixels,
80
+ collapsedSize,
86
81
  collapsible,
87
- defaultSizePercentage,
88
- defaultSizePixels,
89
- maxSizePercentage,
90
- maxSizePixels,
91
- minSizePercentage,
92
- minSizePixels
82
+ defaultSize,
83
+ maxSize,
84
+ minSize
93
85
  },
94
86
  id: panelId,
95
87
  idIsFromProps: idFromProps !== undefined,
@@ -117,19 +109,19 @@ function PanelWithForwardedRef({
117
109
  isExpanded() {
118
110
  return !isPanelCollapsed(panelDataRef.current);
119
111
  },
120
- resize: mixedSizes => {
121
- resizePanel(panelDataRef.current, mixedSizes);
112
+ resize: size => {
113
+ resizePanel(panelDataRef.current, size);
122
114
  }
123
115
  }), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel]);
124
116
  const style = getPanelStyle(panelDataRef.current);
125
117
  return createElement(Type, {
118
+ ...rest,
126
119
  children,
127
120
  className: classNameFromProps,
128
121
  style: {
129
122
  ...style,
130
123
  ...styleFromProps
131
124
  },
132
- ...dataAttributes,
133
125
  // CSS selectors
134
126
  "data-panel": "",
135
127
  "data-panel-id": panelId,
@@ -146,81 +138,11 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
146
138
  PanelWithForwardedRef.displayName = "Panel";
147
139
  Panel.displayName = "forwardRef(Panel)";
148
140
 
149
- function convertPixelsToPercentage(pixels, groupSizePixels) {
150
- return pixels / groupSizePixels * 100;
151
- }
152
-
153
- function convertPixelConstraintsToPercentages(panelConstraints, groupSizePixels) {
154
- let {
155
- collapsedSizePercentage = 0,
156
- collapsedSizePixels,
157
- defaultSizePercentage,
158
- defaultSizePixels,
159
- maxSizePercentage = 100,
160
- maxSizePixels,
161
- minSizePercentage = 0,
162
- minSizePixels
163
- } = panelConstraints;
164
- const hasPixelConstraints = collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null;
165
- if (hasPixelConstraints && groupSizePixels <= 0) {
166
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
167
- return {
168
- collapsedSizePercentage: 0,
169
- defaultSizePercentage,
170
- maxSizePercentage: 0,
171
- minSizePercentage: 0
172
- };
173
- }
174
- if (collapsedSizePixels != null) {
175
- collapsedSizePercentage = convertPixelsToPercentage(collapsedSizePixels, groupSizePixels);
176
- }
177
- if (defaultSizePixels != null) {
178
- defaultSizePercentage = convertPixelsToPercentage(defaultSizePixels, groupSizePixels);
179
- }
180
- if (minSizePixels != null) {
181
- minSizePercentage = convertPixelsToPercentage(minSizePixels, groupSizePixels);
182
- }
183
- if (maxSizePixels != null) {
184
- maxSizePercentage = convertPixelsToPercentage(maxSizePixels, groupSizePixels);
185
- }
186
- return {
187
- collapsedSizePercentage,
188
- defaultSizePercentage,
189
- maxSizePercentage,
190
- minSizePercentage
191
- };
192
- }
193
-
194
- function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels) {
195
- // All panel constraints, excluding the current one
196
- let totalMinConstraints = 0;
197
- let totalMaxConstraints = 0;
198
- for (let index = 0; index < panelConstraintsArray.length; index++) {
199
- if (index !== panelIndex) {
200
- const {
201
- collapsible
202
- } = panelConstraintsArray[index];
203
- const {
204
- collapsedSizePercentage,
205
- maxSizePercentage,
206
- minSizePercentage
207
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[index], groupSizePixels);
208
- totalMaxConstraints += maxSizePercentage;
209
- totalMinConstraints += collapsible ? collapsedSizePercentage : minSizePercentage;
210
- }
141
+ function assert(expectedCondition, message = "Assertion failed!") {
142
+ if (!expectedCondition) {
143
+ console.error(message);
144
+ throw Error(message);
211
145
  }
212
- const {
213
- collapsedSizePercentage,
214
- defaultSizePercentage,
215
- maxSizePercentage,
216
- minSizePercentage
217
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[panelIndex], groupSizePixels);
218
- return {
219
- collapsedSizePercentage,
220
- defaultSizePercentage,
221
- maxSizePercentage: panelConstraintsArray.length > 1 ? Math.min(maxSizePercentage, 100 - totalMinConstraints) : maxSizePercentage,
222
- minSizePercentage: panelConstraintsArray.length > 1 ? Math.max(minSizePercentage, 100 - totalMaxConstraints) : minSizePercentage
223
- };
224
146
  }
225
147
 
226
148
  const PRECISION = 10;
@@ -242,56 +164,41 @@ function fuzzyNumbersEqual(actual, expected, fractionDigits) {
242
164
 
243
165
  // Panel size must be in percentages; pixel values should be pre-converted
244
166
  function resizePanel({
245
- groupSizePixels,
246
- panelConstraints,
167
+ panelConstraints: panelConstraintsArray,
247
168
  panelIndex,
248
169
  size
249
170
  }) {
250
- const hasPixelConstraints = panelConstraints.some(({
251
- collapsedSizePixels,
252
- defaultSizePixels,
253
- minSizePixels,
254
- maxSizePixels
255
- }) => collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null);
256
- if (hasPixelConstraints && groupSizePixels <= 0) {
257
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
258
- return 0;
259
- }
171
+ const panelConstraints = panelConstraintsArray[panelIndex];
172
+ assert(panelConstraints != null);
260
173
  let {
261
- collapsible
262
- } = panelConstraints[panelIndex];
263
- const {
264
- collapsedSizePercentage,
265
- maxSizePercentage,
266
- minSizePercentage
267
- } = computePercentagePanelConstraints(panelConstraints, panelIndex, groupSizePixels);
268
- if (minSizePercentage != null) {
269
- if (fuzzyCompareNumbers(size, minSizePercentage) < 0) {
270
- if (collapsible) {
271
- // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
272
- const halfwayPoint = (collapsedSizePercentage + minSizePercentage) / 2;
273
- if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
274
- size = collapsedSizePercentage;
275
- } else {
276
- size = minSizePercentage;
277
- }
174
+ collapsedSize = 0,
175
+ collapsible,
176
+ maxSize = 100,
177
+ minSize = 0
178
+ } = panelConstraints;
179
+ if (fuzzyCompareNumbers(size, minSize) < 0) {
180
+ if (collapsible) {
181
+ // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
182
+ const halfwayPoint = (collapsedSize + minSize) / 2;
183
+ if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
184
+ size = collapsedSize;
278
185
  } else {
279
- size = minSizePercentage;
186
+ size = minSize;
280
187
  }
188
+ } else {
189
+ size = minSize;
281
190
  }
282
191
  }
283
- if (maxSizePercentage != null) {
284
- size = Math.min(maxSizePercentage, size);
285
- }
192
+ size = Math.min(maxSize, size);
193
+ size = parseFloat(size.toFixed(PRECISION));
286
194
  return size;
287
195
  }
288
196
 
289
197
  // All units must be in percentages; pixel values should be pre-converted
290
198
  function adjustLayoutByDelta({
291
199
  delta,
292
- groupSizePixels,
293
200
  layout: prevLayout,
294
- panelConstraints,
201
+ panelConstraints: panelConstraintsArray,
295
202
  pivotIndices,
296
203
  trigger
297
204
  }) {
@@ -299,6 +206,9 @@ function adjustLayoutByDelta({
299
206
  return prevLayout;
300
207
  }
301
208
  const nextLayout = [...prevLayout];
209
+ const [firstPivotIndex, secondPivotIndex] = pivotIndices;
210
+ assert(firstPivotIndex != null);
211
+ assert(secondPivotIndex != null);
302
212
  let deltaApplied = 0;
303
213
 
304
214
  //const DEBUG = [];
@@ -322,18 +232,23 @@ function adjustLayoutByDelta({
322
232
  if (trigger === "keyboard") {
323
233
  {
324
234
  // Check if we should expand a collapsed panel
325
- const index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
326
- const constraints = panelConstraints[index];
235
+ const index = delta < 0 ? secondPivotIndex : firstPivotIndex;
236
+ const panelConstraints = panelConstraintsArray[index];
237
+ assert(panelConstraints);
238
+
327
239
  //DEBUG.push(`edge case check 1: ${index}`);
328
240
  //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
329
- if (constraints.collapsible) {
241
+ if (panelConstraints.collapsible) {
330
242
  const prevSize = prevLayout[index];
243
+ assert(prevSize != null);
244
+ const panelConstraints = panelConstraintsArray[index];
245
+ assert(panelConstraints);
331
246
  const {
332
- collapsedSizePercentage,
333
- minSizePercentage
334
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
335
- if (fuzzyNumbersEqual(prevSize, collapsedSizePercentage)) {
336
- const localDelta = minSizePercentage - prevSize;
247
+ collapsedSize = 0,
248
+ minSize = 0
249
+ } = panelConstraints;
250
+ if (fuzzyNumbersEqual(prevSize, collapsedSize)) {
251
+ const localDelta = minSize - prevSize;
337
252
  //DEBUG.push(` -> expand delta: ${localDelta}`);
338
253
 
339
254
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -346,18 +261,26 @@ function adjustLayoutByDelta({
346
261
 
347
262
  {
348
263
  // Check if we should collapse a panel at its minimum size
349
- const index = delta < 0 ? pivotIndices[0] : pivotIndices[1];
350
- const constraints = panelConstraints[index];
264
+ const index = delta < 0 ? firstPivotIndex : secondPivotIndex;
265
+ const panelConstraints = panelConstraintsArray[index];
266
+ assert(panelConstraints);
267
+ const {
268
+ collapsible
269
+ } = panelConstraints;
270
+
351
271
  //DEBUG.push(`edge case check 2: ${index}`);
352
- //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
353
- if (constraints.collapsible) {
272
+ //DEBUG.push(` -> collapsible? ${collapsible}`);
273
+ if (collapsible) {
354
274
  const prevSize = prevLayout[index];
275
+ assert(prevSize != null);
276
+ const panelConstraints = panelConstraintsArray[index];
277
+ assert(panelConstraints);
355
278
  const {
356
- collapsedSizePercentage,
357
- minSizePercentage
358
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
359
- if (fuzzyNumbersEqual(prevSize, minSizePercentage)) {
360
- const localDelta = prevSize - collapsedSizePercentage;
279
+ collapsedSize = 0,
280
+ minSize = 0
281
+ } = panelConstraints;
282
+ if (fuzzyNumbersEqual(prevSize, minSize)) {
283
+ const localDelta = prevSize - collapsedSize;
361
284
  //DEBUG.push(` -> expand delta: ${localDelta}`);
362
285
 
363
286
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -379,15 +302,15 @@ function adjustLayoutByDelta({
379
302
  // as an expanding panel might change from collapsed to min size.
380
303
 
381
304
  const increment = delta < 0 ? 1 : -1;
382
- let index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
305
+ let index = delta < 0 ? secondPivotIndex : firstPivotIndex;
383
306
  let maxAvailableDelta = 0;
384
307
 
385
308
  //DEBUG.push("pre calc...");
386
309
  while (true) {
387
310
  const prevSize = prevLayout[index];
311
+ assert(prevSize != null);
388
312
  const maxSafeSize = resizePanel({
389
- groupSizePixels,
390
- panelConstraints,
313
+ panelConstraints: panelConstraintsArray,
391
314
  panelIndex: index,
392
315
  size: 100
393
316
  });
@@ -396,7 +319,7 @@ function adjustLayoutByDelta({
396
319
 
397
320
  maxAvailableDelta += delta;
398
321
  index += increment;
399
- if (index < 0 || index >= panelConstraints.length) {
322
+ if (index < 0 || index >= panelConstraintsArray.length) {
400
323
  break;
401
324
  }
402
325
  }
@@ -411,15 +334,15 @@ function adjustLayoutByDelta({
411
334
  {
412
335
  // Delta added to a panel needs to be subtracted from other panels (within the constraints that those panels allow).
413
336
 
414
- const pivotIndex = delta < 0 ? pivotIndices[0] : pivotIndices[1];
337
+ const pivotIndex = delta < 0 ? firstPivotIndex : secondPivotIndex;
415
338
  let index = pivotIndex;
416
- while (index >= 0 && index < panelConstraints.length) {
339
+ while (index >= 0 && index < panelConstraintsArray.length) {
417
340
  const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
418
341
  const prevSize = prevLayout[index];
342
+ assert(prevSize != null);
419
343
  const unsafeSize = prevSize - deltaRemaining;
420
344
  const safeSize = resizePanel({
421
- groupSizePixels,
422
- panelConstraints,
345
+ panelConstraints: panelConstraintsArray,
423
346
  panelIndex: index,
424
347
  size: unsafeSize
425
348
  });
@@ -451,11 +374,12 @@ function adjustLayoutByDelta({
451
374
  }
452
375
  {
453
376
  // Now distribute the applied delta to the panels in the other direction
454
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
455
- const unsafeSize = prevLayout[pivotIndex] + deltaApplied;
377
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
378
+ const prevSize = prevLayout[pivotIndex];
379
+ assert(prevSize != null);
380
+ const unsafeSize = prevSize + deltaApplied;
456
381
  const safeSize = resizePanel({
457
- groupSizePixels,
458
- panelConstraints,
382
+ panelConstraints: panelConstraintsArray,
459
383
  panelIndex: pivotIndex,
460
384
  size: unsafeSize
461
385
  });
@@ -466,14 +390,14 @@ function adjustLayoutByDelta({
466
390
  // Edge case where expanding or contracting one panel caused another one to change collapsed state
467
391
  if (!fuzzyNumbersEqual(safeSize, unsafeSize)) {
468
392
  let deltaRemaining = unsafeSize - safeSize;
469
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
393
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
470
394
  let index = pivotIndex;
471
- while (index >= 0 && index < panelConstraints.length) {
395
+ while (index >= 0 && index < panelConstraintsArray.length) {
472
396
  const prevSize = nextLayout[index];
397
+ assert(prevSize != null);
473
398
  const unsafeSize = prevSize + deltaRemaining;
474
399
  const safeSize = resizePanel({
475
- groupSizePixels,
476
- panelConstraints,
400
+ panelConstraints: panelConstraintsArray,
477
401
  panelIndex: index,
478
402
  size: unsafeSize
479
403
  });
@@ -497,9 +421,7 @@ function adjustLayoutByDelta({
497
421
  //DEBUG.push("");
498
422
 
499
423
  const totalSize = nextLayout.reduce((total, size) => size + total, 0);
500
- deltaApplied = 100 - totalSize;
501
424
  //DEBUG.push(`total size: ${totalSize}`);
502
- //DEBUG.push(` deltaApplied: ${deltaApplied}`);
503
425
  //console.log(DEBUG.join("\n"));
504
426
 
505
427
  if (!fuzzyNumbersEqual(totalSize, 100)) {
@@ -508,25 +430,6 @@ function adjustLayoutByDelta({
508
430
  return nextLayout;
509
431
  }
510
432
 
511
- function assert(expectedCondition, message = "Assertion failed!") {
512
- if (!expectedCondition) {
513
- console.error(message);
514
- throw Error(message);
515
- }
516
- }
517
-
518
- function getPercentageSizeFromMixedSizes({
519
- sizePercentage,
520
- sizePixels
521
- }, groupSizePixels) {
522
- if (sizePercentage != null) {
523
- return sizePercentage;
524
- } else if (sizePixels != null) {
525
- return convertPixelsToPercentage(sizePixels, groupSizePixels);
526
- }
527
- return undefined;
528
- }
529
-
530
433
  function getResizeHandleElementsForGroup(groupId) {
531
434
  return Array.from(document.querySelectorAll(`[data-panel-resize-handle-id][data-panel-group-id="${groupId}"]`));
532
435
  }
@@ -550,42 +453,6 @@ function getPanelGroupElement(id) {
550
453
  return null;
551
454
  }
552
455
 
553
- function calculateAvailablePanelSizeInPixels(groupId) {
554
- const panelGroupElement = getPanelGroupElement(groupId);
555
- if (panelGroupElement == null) {
556
- return NaN;
557
- }
558
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
559
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
560
- if (direction === "horizontal") {
561
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
562
- return accumulated + handle.offsetWidth;
563
- }, 0);
564
- } else {
565
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
566
- return accumulated + handle.offsetHeight;
567
- }, 0);
568
- }
569
- }
570
-
571
- function getAvailableGroupSizePixels(groupId) {
572
- const panelGroupElement = getPanelGroupElement(groupId);
573
- if (panelGroupElement == null) {
574
- return NaN;
575
- }
576
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
577
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
578
- if (direction === "horizontal") {
579
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
580
- return accumulated + handle.offsetWidth;
581
- }, 0);
582
- } else {
583
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
584
- return accumulated + handle.offsetHeight;
585
- }, 0);
586
- }
587
- }
588
-
589
456
  function getResizeHandleElement(id) {
590
457
  const element = document.querySelector(`[data-panel-resize-handle-id="${id}"]`);
591
458
  if (element) {
@@ -618,14 +485,18 @@ function useWindowSplitterPanelGroupBehavior({
618
485
  didWarnAboutMissingResizeHandle: false
619
486
  });
620
487
  useEffect(() => {
488
+ const eagerValues = eagerValuesRef.current;
489
+ assert(eagerValues);
621
490
  const {
622
491
  panelDataArray
623
- } = eagerValuesRef.current;
492
+ } = eagerValues;
624
493
  const groupElement = getPanelGroupElement(groupId);
625
494
  assert(groupElement != null, `No group found for id "${groupId}"`);
626
495
  const handles = getResizeHandleElementsForGroup(groupId);
496
+ assert(handles);
627
497
  const cleanupFunctions = handles.map(handle => {
628
498
  const handleId = handle.getAttribute("data-panel-resize-handle-id");
499
+ assert(handleId);
629
500
  const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray);
630
501
  if (idBefore == null || idAfter == null) {
631
502
  return () => {};
@@ -641,21 +512,16 @@ function useWindowSplitterPanelGroupBehavior({
641
512
  const index = panelDataArray.findIndex(panelData => panelData.id === idBefore);
642
513
  if (index >= 0) {
643
514
  const panelData = panelDataArray[index];
515
+ assert(panelData);
644
516
  const size = layout[index];
645
- if (size != null && panelData.constraints.collapsible) {
646
- var _getPercentageSizeFro, _getPercentageSizeFro2;
647
- const groupSizePixels = getAvailableGroupSizePixels(groupId);
648
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
649
- sizePercentage: panelData.constraints.collapsedSizePercentage,
650
- sizePixels: panelData.constraints.collapsedSizePixels
651
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
652
- const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
653
- sizePercentage: panelData.constraints.minSizePercentage,
654
- sizePixels: panelData.constraints.minSizePixels
655
- }, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
517
+ const {
518
+ collapsedSize = 0,
519
+ collapsible,
520
+ minSize = 0
521
+ } = panelData.constraints;
522
+ if (size != null && collapsible) {
656
523
  const nextLayout = adjustLayoutByDelta({
657
524
  delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
658
- groupSizePixels,
659
525
  layout,
660
526
  panelConstraints: panelDataArray.map(panelData => panelData.constraints),
661
527
  pivotIndices: determinePivotIndices(groupId, handleId),
@@ -709,6 +575,7 @@ function getResizeEventCursorPosition(direction, event) {
709
575
  return isHorizontal ? event.clientX : event.clientY;
710
576
  } else if (isTouchEvent(event)) {
711
577
  const firstTouch = event.touches[0];
578
+ assert(firstTouch);
712
579
  return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
713
580
  } else {
714
581
  throw Error(`Unsupported event type "${event.type}"`);
@@ -718,12 +585,15 @@ function getResizeEventCursorPosition(direction, event) {
718
585
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState) {
719
586
  const isHorizontal = direction === "horizontal";
720
587
  const handleElement = getResizeHandleElement(dragHandleId);
588
+ assert(handleElement);
721
589
  const groupId = handleElement.getAttribute("data-panel-group-id");
590
+ assert(groupId);
722
591
  let {
723
592
  initialCursorPosition
724
593
  } = initialDragState;
725
594
  const cursorPosition = getResizeEventCursorPosition(direction, event);
726
595
  const groupElement = getPanelGroupElement(groupId);
596
+ assert(groupElement);
727
597
  const groupRect = groupElement.getBoundingClientRect();
728
598
  const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
729
599
  const offsetPixels = cursorPosition - initialCursorPosition;
@@ -732,19 +602,14 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
732
602
  }
733
603
 
734
604
  // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
735
- function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initialDragState, keyboardResizeByOptions) {
605
+ function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy) {
736
606
  if (isKeyDown(event)) {
737
607
  const isHorizontal = direction === "horizontal";
738
- const groupElement = getPanelGroupElement(groupId);
739
- const rect = groupElement.getBoundingClientRect();
740
- const groupSizeInPixels = isHorizontal ? rect.width : rect.height;
741
608
  let delta = 0;
742
609
  if (event.shiftKey) {
743
610
  delta = 100;
744
- } else if (keyboardResizeByOptions.percentage != null) {
745
- delta = keyboardResizeByOptions.percentage;
746
- } else if (keyboardResizeByOptions.pixels != null) {
747
- delta = keyboardResizeByOptions.pixels / groupSizeInPixels;
611
+ } else if (keyboardResizeBy != null) {
612
+ delta = keyboardResizeBy;
748
613
  } else {
749
614
  delta = 10;
750
615
  }
@@ -771,37 +636,43 @@ function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initi
771
636
  }
772
637
  return movement;
773
638
  } else {
639
+ if (initialDragState == null) {
640
+ return 0;
641
+ }
774
642
  return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState);
775
643
  }
776
644
  }
777
645
 
778
646
  function calculateUnsafeDefaultLayout({
779
- groupSizePixels,
780
647
  panelDataArray
781
648
  }) {
782
649
  const layout = Array(panelDataArray.length);
783
- const panelDataConstraints = panelDataArray.map(panelData => panelData.constraints);
650
+ const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
784
651
  let numPanelsWithSizes = 0;
785
652
  let remainingSize = 100;
786
653
 
787
654
  // Distribute default sizes first
788
655
  for (let index = 0; index < panelDataArray.length; index++) {
656
+ const panelConstraints = panelConstraintsArray[index];
657
+ assert(panelConstraints);
789
658
  const {
790
- defaultSizePercentage
791
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
792
- if (defaultSizePercentage != null) {
659
+ defaultSize
660
+ } = panelConstraints;
661
+ if (defaultSize != null) {
793
662
  numPanelsWithSizes++;
794
- layout[index] = defaultSizePercentage;
795
- remainingSize -= defaultSizePercentage;
663
+ layout[index] = defaultSize;
664
+ remainingSize -= defaultSize;
796
665
  }
797
666
  }
798
667
 
799
668
  // Remaining size should be distributed evenly between panels without default sizes
800
669
  for (let index = 0; index < panelDataArray.length; index++) {
670
+ const panelConstraints = panelConstraintsArray[index];
671
+ assert(panelConstraints);
801
672
  const {
802
- defaultSizePercentage
803
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
804
- if (defaultSizePercentage != null) {
673
+ defaultSize
674
+ } = panelConstraints;
675
+ if (defaultSize != null) {
805
676
  continue;
806
677
  }
807
678
  const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
@@ -813,54 +684,36 @@ function calculateUnsafeDefaultLayout({
813
684
  return layout;
814
685
  }
815
686
 
816
- function convertPercentageToPixels(percentage, groupSizePixels) {
817
- return percentage / 100 * groupSizePixels;
818
- }
819
-
820
687
  // Layout should be pre-converted into percentages
821
- function callPanelCallbacks(groupId, panelsArray, layout, panelIdToLastNotifiedMixedSizesMap) {
822
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
823
- layout.forEach((sizePercentage, index) => {
688
+ function callPanelCallbacks(panelsArray, layout, panelIdToLastNotifiedSizeMap) {
689
+ layout.forEach((size, index) => {
824
690
  const panelData = panelsArray[index];
825
- if (!panelData) {
826
- // Handle initial mount (when panels are registered too late to be in the panels array)
827
- // The subsequent render+effects will handle the resize notification
828
- return;
829
- }
691
+ assert(panelData);
830
692
  const {
831
693
  callbacks,
832
694
  constraints,
833
695
  id: panelId
834
696
  } = panelData;
835
697
  const {
698
+ collapsedSize = 0,
836
699
  collapsible
837
700
  } = constraints;
838
- const mixedSizes = {
839
- sizePercentage,
840
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
841
- };
842
- const lastNotifiedMixedSizes = panelIdToLastNotifiedMixedSizesMap[panelId];
843
- if (lastNotifiedMixedSizes == null || mixedSizes.sizePercentage !== lastNotifiedMixedSizes.sizePercentage || mixedSizes.sizePixels !== lastNotifiedMixedSizes.sizePixels) {
844
- panelIdToLastNotifiedMixedSizesMap[panelId] = mixedSizes;
701
+ const lastNotifiedSize = panelIdToLastNotifiedSizeMap[panelId];
702
+ if (lastNotifiedSize == null || size !== lastNotifiedSize) {
703
+ panelIdToLastNotifiedSizeMap[panelId] = size;
845
704
  const {
846
705
  onCollapse,
847
706
  onExpand,
848
707
  onResize
849
708
  } = callbacks;
850
709
  if (onResize) {
851
- onResize(mixedSizes, lastNotifiedMixedSizes);
710
+ onResize(size, lastNotifiedSize);
852
711
  }
853
712
  if (collapsible && (onCollapse || onExpand)) {
854
- var _getPercentageSizeFro;
855
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
856
- sizePercentage: constraints.collapsedSizePercentage,
857
- sizePixels: constraints.collapsedSizePixels
858
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
859
- const size = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
860
- if (onExpand && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage === collapsedSize) && size !== collapsedSize) {
713
+ if (onExpand && (lastNotifiedSize == null || lastNotifiedSize === collapsedSize) && size !== collapsedSize) {
861
714
  onExpand();
862
715
  }
863
- if (onCollapse && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage !== collapsedSize) && size === collapsedSize) {
716
+ if (onCollapse && (lastNotifiedSize == null || lastNotifiedSize !== collapsedSize) && size === collapsedSize) {
864
717
  onCollapse();
865
718
  }
866
719
  }
@@ -894,9 +747,10 @@ function computePanelFlexBoxStyle({
894
747
  const size = layout[panelIndex];
895
748
  let flexGrow;
896
749
  if (panelData.length === 1) {
897
- flexGrow = "100";
750
+ flexGrow = "1";
898
751
  } else if (size == null) {
899
- flexGrow = "0";
752
+ // Initial render (before panels have registered themselves)
753
+ flexGrow = "1";
900
754
  } else {
901
755
  flexGrow = size.toPrecision(precision);
902
756
  }
@@ -1042,31 +896,32 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1042
896
  }
1043
897
  }
1044
898
 
1045
- function shouldMonitorPixelBasedConstraints(constraints) {
1046
- return constraints.some(constraints => {
1047
- return constraints.collapsedSizePixels !== undefined || constraints.maxSizePixels !== undefined || constraints.minSizePixels !== undefined;
1048
- });
1049
- }
1050
-
1051
899
  // All units must be in percentages; pixel values should be pre-converted
1052
900
  function validatePanelGroupLayout({
1053
- groupSizePixels,
1054
901
  layout: prevLayout,
1055
902
  panelConstraints
1056
903
  }) {
1057
904
  const nextLayout = [...prevLayout];
905
+ const nextLayoutTotalSize = nextLayout.reduce((accumulated, current) => accumulated + current, 0);
1058
906
 
1059
907
  // Validate layout expectations
1060
908
  if (nextLayout.length !== panelConstraints.length) {
1061
909
  throw Error(`Invalid ${panelConstraints.length} panel layout: ${nextLayout.map(size => `${size}%`).join(", ")}`);
1062
- } else if (!fuzzyNumbersEqual(nextLayout.reduce((accumulated, current) => accumulated + current, 0), 100)) ;
910
+ } else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100)) {
911
+ for (let index = 0; index < panelConstraints.length; index++) {
912
+ const unsafeSize = nextLayout[index];
913
+ assert(unsafeSize != null);
914
+ const safeSize = 100 / nextLayoutTotalSize * unsafeSize;
915
+ nextLayout[index] = safeSize;
916
+ }
917
+ }
1063
918
  let remainingSize = 0;
1064
919
 
1065
920
  // First pass: Validate the proposed layout given each panel's constraints
1066
921
  for (let index = 0; index < panelConstraints.length; index++) {
1067
922
  const unsafeSize = nextLayout[index];
923
+ assert(unsafeSize != null);
1068
924
  const safeSize = resizePanel({
1069
- groupSizePixels,
1070
925
  panelConstraints,
1071
926
  panelIndex: index,
1072
927
  size: unsafeSize
@@ -1082,9 +937,9 @@ function validatePanelGroupLayout({
1082
937
  if (!fuzzyNumbersEqual(remainingSize, 0)) {
1083
938
  for (let index = 0; index < panelConstraints.length; index++) {
1084
939
  const prevSize = nextLayout[index];
940
+ assert(prevSize != null);
1085
941
  const unsafeSize = prevSize + remainingSize;
1086
942
  const safeSize = resizePanel({
1087
- groupSizePixels,
1088
943
  panelConstraints,
1089
944
  panelIndex: index,
1090
945
  size: unsafeSize
@@ -1119,21 +974,20 @@ function PanelGroupWithForwardedRef({
1119
974
  autoSaveId = null,
1120
975
  children,
1121
976
  className: classNameFromProps = "",
1122
- dataAttributes,
1123
977
  direction,
1124
978
  forwardedRef,
1125
- id: idFromProps,
979
+ id: idFromProps = null,
1126
980
  onLayout = null,
1127
- keyboardResizeByPercentage = null,
1128
- keyboardResizeByPixels = null,
981
+ keyboardResizeBy = null,
1129
982
  storage = defaultStorage,
1130
983
  style: styleFromProps,
1131
- tagName: Type = "div"
984
+ tagName: Type = "div",
985
+ ...rest
1132
986
  }) {
1133
987
  const groupId = useUniqueId(idFromProps);
1134
988
  const [dragState, setDragState] = useState(null);
1135
989
  const [layout, setLayout] = useState([]);
1136
- const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
990
+ const panelIdToLastNotifiedSizeMapRef = useRef({});
1137
991
  const panelSizeBeforeCollapseRef = useRef(new Map());
1138
992
  const prevDeltaRef = useRef(0);
1139
993
  const committedValuesRef = useRef({
@@ -1141,8 +995,7 @@ function PanelGroupWithForwardedRef({
1141
995
  direction,
1142
996
  dragState,
1143
997
  id: groupId,
1144
- keyboardResizeByPercentage,
1145
- keyboardResizeByPixels,
998
+ keyboardResizeBy,
1146
999
  onLayout,
1147
1000
  storage
1148
1001
  });
@@ -1158,33 +1011,20 @@ function PanelGroupWithForwardedRef({
1158
1011
  useImperativeHandle(forwardedRef, () => ({
1159
1012
  getId: () => committedValuesRef.current.id,
1160
1013
  getLayout: () => {
1161
- const {
1162
- id: groupId
1163
- } = committedValuesRef.current;
1164
1014
  const {
1165
1015
  layout
1166
1016
  } = eagerValuesRef.current;
1167
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1168
- return layout.map(sizePercentage => {
1169
- return {
1170
- sizePercentage,
1171
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1172
- };
1173
- });
1017
+ return layout;
1174
1018
  },
1175
- setLayout: mixedSizes => {
1019
+ setLayout: unsafeLayout => {
1176
1020
  const {
1177
- id: groupId,
1178
1021
  onLayout
1179
1022
  } = committedValuesRef.current;
1180
1023
  const {
1181
1024
  layout: prevLayout,
1182
1025
  panelDataArray
1183
1026
  } = eagerValuesRef.current;
1184
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1185
- const unsafeLayout = mixedSizes.map(mixedSize => getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels));
1186
1027
  const safeLayout = validatePanelGroupLayout({
1187
- groupSizePixels,
1188
1028
  layout: unsafeLayout,
1189
1029
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1190
1030
  });
@@ -1192,16 +1032,12 @@ function PanelGroupWithForwardedRef({
1192
1032
  setLayout(safeLayout);
1193
1033
  eagerValuesRef.current.layout = safeLayout;
1194
1034
  if (onLayout) {
1195
- onLayout(safeLayout.map(sizePercentage => ({
1196
- sizePercentage,
1197
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1198
- })));
1035
+ onLayout(safeLayout);
1199
1036
  }
1200
- callPanelCallbacks(groupId, panelDataArray, safeLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1037
+ callPanelCallbacks(panelDataArray, safeLayout, panelIdToLastNotifiedSizeMapRef.current);
1201
1038
  }
1202
1039
  }
1203
1040
  }), []);
1204
-
1205
1041
  useWindowSplitterPanelGroupBehavior({
1206
1042
  committedValuesRef,
1207
1043
  eagerValuesRef,
@@ -1220,12 +1056,14 @@ function PanelGroupWithForwardedRef({
1220
1056
  if (layout.length === 0 || layout.length !== panelDataArray.length) {
1221
1057
  return;
1222
1058
  }
1059
+ let debouncedSave = debounceMap[autoSaveId];
1223
1060
 
1224
1061
  // Limit the frequency of localStorage updates.
1225
- if (!debounceMap[autoSaveId]) {
1226
- debounceMap[autoSaveId] = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1062
+ if (debouncedSave == null) {
1063
+ debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1064
+ debounceMap[autoSaveId] = debouncedSave;
1227
1065
  }
1228
- debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
1066
+ debouncedSave(autoSaveId, panelDataArray, layout, storage);
1229
1067
  }
1230
1068
  }, [autoSaveId, layout, storage]);
1231
1069
 
@@ -1245,20 +1083,19 @@ function PanelGroupWithForwardedRef({
1245
1083
  if (panelData.constraints.collapsible) {
1246
1084
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1247
1085
  const {
1248
- collapsedSizePercentage,
1249
- panelSizePercentage,
1250
- pivotIndices,
1251
- groupSizePixels
1252
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1253
- if (panelSizePercentage !== collapsedSizePercentage) {
1086
+ collapsedSize = 0,
1087
+ panelSize,
1088
+ pivotIndices
1089
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1090
+ assert(panelSize != null);
1091
+ if (panelSize !== collapsedSize) {
1254
1092
  // Store size before collapse;
1255
1093
  // This is the size that gets restored if the expand() API is used.
1256
- panelSizeBeforeCollapseRef.current.set(panelData.id, panelSizePercentage);
1094
+ panelSizeBeforeCollapseRef.current.set(panelData.id, panelSize);
1257
1095
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1258
- const delta = isLastPanel ? panelSizePercentage - collapsedSizePercentage : collapsedSizePercentage - panelSizePercentage;
1096
+ const delta = isLastPanel ? panelSize - collapsedSize : collapsedSize - panelSize;
1259
1097
  const nextLayout = adjustLayoutByDelta({
1260
1098
  delta,
1261
- groupSizePixels,
1262
1099
  layout: prevLayout,
1263
1100
  panelConstraints: panelConstraintsArray,
1264
1101
  pivotIndices,
@@ -1268,16 +1105,13 @@ function PanelGroupWithForwardedRef({
1268
1105
  setLayout(nextLayout);
1269
1106
  eagerValuesRef.current.layout = nextLayout;
1270
1107
  if (onLayout) {
1271
- onLayout(nextLayout.map(sizePercentage => ({
1272
- sizePercentage,
1273
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1274
- })));
1108
+ onLayout(nextLayout);
1275
1109
  }
1276
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1110
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1277
1111
  }
1278
1112
  }
1279
1113
  }
1280
- }, [groupId]);
1114
+ }, []);
1281
1115
 
1282
1116
  // External APIs are safe to memoize via committed values ref
1283
1117
  const expandPanel = useCallback(panelData => {
@@ -1291,21 +1125,19 @@ function PanelGroupWithForwardedRef({
1291
1125
  if (panelData.constraints.collapsible) {
1292
1126
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1293
1127
  const {
1294
- collapsedSizePercentage,
1295
- panelSizePercentage,
1296
- minSizePercentage,
1297
- pivotIndices,
1298
- groupSizePixels
1299
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1300
- if (panelSizePercentage === collapsedSizePercentage) {
1128
+ collapsedSize = 0,
1129
+ panelSize,
1130
+ minSize = 0,
1131
+ pivotIndices
1132
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1133
+ if (panelSize === collapsedSize) {
1301
1134
  // Restore this panel to the size it was before it was collapsed, if possible.
1302
- const prevPanelSizePercentage = panelSizeBeforeCollapseRef.current.get(panelData.id);
1303
- const baseSizePercentage = prevPanelSizePercentage != null && prevPanelSizePercentage >= minSizePercentage ? prevPanelSizePercentage : minSizePercentage;
1135
+ const prevPanelSize = panelSizeBeforeCollapseRef.current.get(panelData.id);
1136
+ const baseSize = prevPanelSize != null && prevPanelSize >= minSize ? prevPanelSize : minSize;
1304
1137
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1305
- const delta = isLastPanel ? panelSizePercentage - baseSizePercentage : baseSizePercentage - panelSizePercentage;
1138
+ const delta = isLastPanel ? panelSize - baseSize : baseSize - panelSize;
1306
1139
  const nextLayout = adjustLayoutByDelta({
1307
1140
  delta,
1308
- groupSizePixels,
1309
1141
  layout: prevLayout,
1310
1142
  panelConstraints: panelConstraintsArray,
1311
1143
  pivotIndices,
@@ -1315,16 +1147,13 @@ function PanelGroupWithForwardedRef({
1315
1147
  setLayout(nextLayout);
1316
1148
  eagerValuesRef.current.layout = nextLayout;
1317
1149
  if (onLayout) {
1318
- onLayout(nextLayout.map(sizePercentage => ({
1319
- sizePercentage,
1320
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1321
- })));
1150
+ onLayout(nextLayout);
1322
1151
  }
1323
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1152
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1324
1153
  }
1325
1154
  }
1326
1155
  }
1327
- }, [groupId]);
1156
+ }, []);
1328
1157
 
1329
1158
  // External APIs are safe to memoize via committed values ref
1330
1159
  const getPanelSize = useCallback(panelData => {
@@ -1333,14 +1162,11 @@ function PanelGroupWithForwardedRef({
1333
1162
  panelDataArray
1334
1163
  } = eagerValuesRef.current;
1335
1164
  const {
1336
- panelSizePercentage,
1337
- panelSizePixels
1338
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1339
- return {
1340
- sizePercentage: panelSizePercentage,
1341
- sizePixels: panelSizePixels
1342
- };
1343
- }, [groupId]);
1165
+ panelSize
1166
+ } = panelDataHelper(panelDataArray, panelData, layout);
1167
+ assert(panelSize != null);
1168
+ return panelSize;
1169
+ }, []);
1344
1170
 
1345
1171
  // This API should never read from committedValuesRef
1346
1172
  const getPanelStyle = useCallback(panelData => {
@@ -1363,12 +1189,12 @@ function PanelGroupWithForwardedRef({
1363
1189
  panelDataArray
1364
1190
  } = eagerValuesRef.current;
1365
1191
  const {
1366
- collapsedSizePercentage,
1192
+ collapsedSize,
1367
1193
  collapsible,
1368
- panelSizePercentage
1369
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1370
- return collapsible === true && panelSizePercentage === collapsedSizePercentage;
1371
- }, [groupId]);
1194
+ panelSize
1195
+ } = panelDataHelper(panelDataArray, panelData, layout);
1196
+ return collapsible === true && panelSize === collapsedSize;
1197
+ }, []);
1372
1198
 
1373
1199
  // External APIs are safe to memoize via committed values ref
1374
1200
  const isPanelExpanded = useCallback(panelData => {
@@ -1377,12 +1203,13 @@ function PanelGroupWithForwardedRef({
1377
1203
  panelDataArray
1378
1204
  } = eagerValuesRef.current;
1379
1205
  const {
1380
- collapsedSizePercentage,
1206
+ collapsedSize = 0,
1381
1207
  collapsible,
1382
- panelSizePercentage
1383
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1384
- return !collapsible || panelSizePercentage > collapsedSizePercentage;
1385
- }, [groupId]);
1208
+ panelSize
1209
+ } = panelDataHelper(panelDataArray, panelData, layout);
1210
+ assert(panelSize != null);
1211
+ return !collapsible || panelSize > collapsedSize;
1212
+ }, []);
1386
1213
  const registerPanel = useCallback(panelData => {
1387
1214
  const {
1388
1215
  autoSaveId,
@@ -1422,18 +1249,8 @@ function PanelGroupWithForwardedRef({
1422
1249
  if (autoSaveId) {
1423
1250
  unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1424
1251
  }
1425
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1426
- if (groupSizePixels <= 0) {
1427
- if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
1428
- constraints
1429
- }) => constraints))) {
1430
- // Wait until the group has rendered a non-zero size before computing layout.
1431
- return;
1432
- }
1433
- }
1434
1252
  if (unsafeLayout == null) {
1435
1253
  unsafeLayout = calculateUnsafeDefaultLayout({
1436
- groupSizePixels,
1437
1254
  panelDataArray
1438
1255
  });
1439
1256
  }
@@ -1441,7 +1258,6 @@ function PanelGroupWithForwardedRef({
1441
1258
  // Validate even saved layouts in case something has changed since last render
1442
1259
  // e.g. for pixel groups, this could be the size of the window
1443
1260
  const nextLayout = validatePanelGroupLayout({
1444
- groupSizePixels,
1445
1261
  layout: unsafeLayout,
1446
1262
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1447
1263
  });
@@ -1453,12 +1269,9 @@ function PanelGroupWithForwardedRef({
1453
1269
  eagerValuesRef.current.layout = nextLayout;
1454
1270
  if (!areEqual(prevLayout, nextLayout)) {
1455
1271
  if (onLayout) {
1456
- onLayout(nextLayout.map(sizePercentage => ({
1457
- sizePercentage,
1458
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1459
- })));
1272
+ onLayout(nextLayout);
1460
1273
  }
1461
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1274
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1462
1275
  }
1463
1276
  }, []);
1464
1277
  const registerResizeHandle = useCallback(dragHandleId => {
@@ -1468,8 +1281,7 @@ function PanelGroupWithForwardedRef({
1468
1281
  direction,
1469
1282
  dragState,
1470
1283
  id: groupId,
1471
- keyboardResizeByPercentage,
1472
- keyboardResizeByPixels,
1284
+ keyboardResizeBy,
1473
1285
  onLayout
1474
1286
  } = committedValuesRef.current;
1475
1287
  const {
@@ -1480,10 +1292,7 @@ function PanelGroupWithForwardedRef({
1480
1292
  initialLayout
1481
1293
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1482
1294
  const pivotIndices = determinePivotIndices(groupId, dragHandleId);
1483
- let delta = calculateDeltaPercentage(event, groupId, dragHandleId, direction, dragState, {
1484
- percentage: keyboardResizeByPercentage,
1485
- pixels: keyboardResizeByPixels
1486
- });
1295
+ let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy);
1487
1296
  if (delta === 0) {
1488
1297
  return;
1489
1298
  }
@@ -1493,11 +1302,9 @@ function PanelGroupWithForwardedRef({
1493
1302
  if (document.dir === "rtl" && isHorizontal) {
1494
1303
  delta = -delta;
1495
1304
  }
1496
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1497
1305
  const panelConstraints = panelDataArray.map(panelData => panelData.constraints);
1498
1306
  const nextLayout = adjustLayoutByDelta({
1499
1307
  delta,
1500
- groupSizePixels,
1501
1308
  layout: initialLayout !== null && initialLayout !== void 0 ? initialLayout : prevLayout,
1502
1309
  panelConstraints,
1503
1310
  pivotIndices,
@@ -1533,18 +1340,15 @@ function PanelGroupWithForwardedRef({
1533
1340
  setLayout(nextLayout);
1534
1341
  eagerValuesRef.current.layout = nextLayout;
1535
1342
  if (onLayout) {
1536
- onLayout(nextLayout.map(sizePercentage => ({
1537
- sizePercentage,
1538
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1539
- })));
1343
+ onLayout(nextLayout);
1540
1344
  }
1541
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1345
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1542
1346
  }
1543
1347
  };
1544
1348
  }, []);
1545
1349
 
1546
1350
  // External APIs are safe to memoize via committed values ref
1547
- const resizePanel = useCallback((panelData, mixedSizes) => {
1351
+ const resizePanel = useCallback((panelData, unsafePanelSize) => {
1548
1352
  const {
1549
1353
  onLayout
1550
1354
  } = committedValuesRef.current;
@@ -1554,16 +1358,14 @@ function PanelGroupWithForwardedRef({
1554
1358
  } = eagerValuesRef.current;
1555
1359
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1556
1360
  const {
1557
- groupSizePixels,
1558
- panelSizePercentage,
1361
+ panelSize,
1559
1362
  pivotIndices
1560
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1561
- const sizePercentage = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
1363
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1364
+ assert(panelSize != null);
1562
1365
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1563
- const delta = isLastPanel ? panelSizePercentage - sizePercentage : sizePercentage - panelSizePercentage;
1366
+ const delta = isLastPanel ? panelSize - unsafePanelSize : unsafePanelSize - panelSize;
1564
1367
  const nextLayout = adjustLayoutByDelta({
1565
1368
  delta,
1566
- groupSizePixels,
1567
1369
  layout: prevLayout,
1568
1370
  panelConstraints: panelConstraintsArray,
1569
1371
  pivotIndices,
@@ -1573,14 +1375,11 @@ function PanelGroupWithForwardedRef({
1573
1375
  setLayout(nextLayout);
1574
1376
  eagerValuesRef.current.layout = nextLayout;
1575
1377
  if (onLayout) {
1576
- onLayout(nextLayout.map(sizePercentage => ({
1577
- sizePercentage,
1578
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1579
- })));
1378
+ onLayout(nextLayout);
1580
1379
  }
1581
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1380
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1582
1381
  }
1583
- }, [groupId]);
1382
+ }, []);
1584
1383
  const startDragging = useCallback((dragHandleId, event) => {
1585
1384
  const {
1586
1385
  direction
@@ -1589,6 +1388,7 @@ function PanelGroupWithForwardedRef({
1589
1388
  layout
1590
1389
  } = eagerValuesRef.current;
1591
1390
  const handleElement = getResizeHandleElement(dragHandleId);
1391
+ assert(handleElement);
1592
1392
  const initialCursorPosition = getResizeEventCursorPosition(direction, event);
1593
1393
  setDragState({
1594
1394
  dragHandleId,
@@ -1607,7 +1407,6 @@ function PanelGroupWithForwardedRef({
1607
1407
  });
1608
1408
  const unregisterPanel = useCallback(panelData => {
1609
1409
  const {
1610
- id: groupId,
1611
1410
  onLayout
1612
1411
  } = committedValuesRef.current;
1613
1412
  const {
@@ -1630,7 +1429,7 @@ function PanelGroupWithForwardedRef({
1630
1429
  const {
1631
1430
  pendingPanelIds
1632
1431
  } = unregisterPanelRef.current;
1633
- const map = panelIdToLastNotifiedMixedSizesMapRef.current;
1432
+ const map = panelIdToLastNotifiedSizeMapRef.current;
1634
1433
 
1635
1434
  // TRICKY
1636
1435
  // Strict effects mode
@@ -1656,16 +1455,13 @@ function PanelGroupWithForwardedRef({
1656
1455
  // The group is unmounting; skip layout calculation.
1657
1456
  return;
1658
1457
  }
1659
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1660
1458
  let unsafeLayout = calculateUnsafeDefaultLayout({
1661
- groupSizePixels,
1662
1459
  panelDataArray
1663
1460
  });
1664
1461
 
1665
1462
  // Validate even saved layouts in case something has changed since last render
1666
1463
  // e.g. for pixel groups, this could be the size of the window
1667
1464
  const nextLayout = validatePanelGroupLayout({
1668
- groupSizePixels,
1669
1465
  layout: unsafeLayout,
1670
1466
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1671
1467
  });
@@ -1673,12 +1469,9 @@ function PanelGroupWithForwardedRef({
1673
1469
  setLayout(nextLayout);
1674
1470
  eagerValuesRef.current.layout = nextLayout;
1675
1471
  if (onLayout) {
1676
- onLayout(nextLayout.map(sizePercentage => ({
1677
- sizePercentage,
1678
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1679
- })));
1472
+ onLayout(nextLayout);
1680
1473
  }
1681
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1474
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1682
1475
  }
1683
1476
  }, 0);
1684
1477
  }, []);
@@ -1709,13 +1502,13 @@ function PanelGroupWithForwardedRef({
1709
1502
  return createElement(PanelGroupContext.Provider, {
1710
1503
  value: context
1711
1504
  }, createElement(Type, {
1505
+ ...rest,
1712
1506
  children,
1713
1507
  className: classNameFromProps,
1714
1508
  style: {
1715
1509
  ...style,
1716
1510
  ...styleFromProps
1717
1511
  },
1718
- ...dataAttributes,
1719
1512
  // CSS selectors
1720
1513
  "data-panel-group": "",
1721
1514
  "data-panel-group-direction": direction,
@@ -1728,22 +1521,16 @@ const PanelGroup = forwardRef((props, ref) => createElement(PanelGroupWithForwar
1728
1521
  }));
1729
1522
  PanelGroupWithForwardedRef.displayName = "PanelGroup";
1730
1523
  PanelGroup.displayName = "forwardRef(PanelGroup)";
1731
- function panelDataHelper(groupId, panelDataArray, panelData, layout) {
1524
+ function panelDataHelper(panelDataArray, panelData, layout) {
1732
1525
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1733
1526
  const panelIndex = panelDataArray.indexOf(panelData);
1734
1527
  const panelConstraints = panelConstraintsArray[panelIndex];
1735
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1736
- const percentagePanelConstraints = computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels);
1737
1528
  const isLastPanel = panelIndex === panelDataArray.length - 1;
1738
1529
  const pivotIndices = isLastPanel ? [panelIndex - 1, panelIndex] : [panelIndex, panelIndex + 1];
1739
- const panelSizePercentage = layout[panelIndex];
1740
- const panelSizePixels = convertPercentageToPixels(panelSizePercentage, groupSizePixels);
1530
+ const panelSize = layout[panelIndex];
1741
1531
  return {
1742
- ...percentagePanelConstraints,
1743
- collapsible: panelConstraints.collapsible,
1744
- panelSizePercentage,
1745
- panelSizePixels,
1746
- groupSizePixels,
1532
+ ...panelConstraints,
1533
+ panelSize,
1747
1534
  pivotIndices
1748
1535
  };
1749
1536
  }
@@ -1783,6 +1570,7 @@ function useWindowSplitterResizeHandlerBehavior({
1783
1570
  {
1784
1571
  event.preventDefault();
1785
1572
  const groupId = handleElement.getAttribute("data-panel-group-id");
1573
+ assert(groupId);
1786
1574
  const handles = getResizeHandleElementsForGroup(groupId);
1787
1575
  const index = getResizeHandleElementIndex(groupId, handleId);
1788
1576
  assert(index !== null);
@@ -1803,12 +1591,13 @@ function useWindowSplitterResizeHandlerBehavior({
1803
1591
  function PanelResizeHandle({
1804
1592
  children = null,
1805
1593
  className: classNameFromProps = "",
1806
- dataAttributes,
1807
1594
  disabled = false,
1808
- id: idFromProps = null,
1595
+ id: idFromProps,
1809
1596
  onDragging,
1810
1597
  style: styleFromProps = {},
1811
- tagName: Type = "div"
1598
+ tabIndex = 0,
1599
+ tagName: Type = "div",
1600
+ ...rest
1812
1601
  }) {
1813
1602
  const divElementRef = useRef(null);
1814
1603
 
@@ -1838,8 +1627,9 @@ function PanelResizeHandle({
1838
1627
  const stopDraggingAndBlur = useCallback(() => {
1839
1628
  // Clicking on the drag handle shouldn't leave it focused;
1840
1629
  // That would cause the PanelGroup to think it was still active.
1841
- const div = divElementRef.current;
1842
- div.blur();
1630
+ const divElement = divElementRef.current;
1631
+ assert(divElement);
1632
+ divElement.blur();
1843
1633
  stopDragging();
1844
1634
  const {
1845
1635
  onDragging
@@ -1867,6 +1657,7 @@ function PanelResizeHandle({
1867
1657
  resizeHandler(event);
1868
1658
  };
1869
1659
  const divElement = divElementRef.current;
1660
+ assert(divElement);
1870
1661
  const targetDocument = divElement.ownerDocument;
1871
1662
  targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
1872
1663
  targetDocument.body.addEventListener("mousemove", onMove);
@@ -1894,15 +1685,18 @@ function PanelResizeHandle({
1894
1685
  userSelect: "none"
1895
1686
  };
1896
1687
  return createElement(Type, {
1688
+ ...rest,
1897
1689
  children,
1898
1690
  className: classNameFromProps,
1899
1691
  onBlur: () => setIsFocused(false),
1900
1692
  onFocus: () => setIsFocused(true),
1901
1693
  onMouseDown: event => {
1902
1694
  startDragging(resizeHandleId, event.nativeEvent);
1695
+ const callbacks = callbacksRef.current;
1696
+ assert(callbacks);
1903
1697
  const {
1904
1698
  onDragging
1905
- } = callbacksRef.current;
1699
+ } = callbacks;
1906
1700
  if (onDragging) {
1907
1701
  onDragging(true);
1908
1702
  }
@@ -1912,9 +1706,11 @@ function PanelResizeHandle({
1912
1706
  onTouchEnd: stopDraggingAndBlur,
1913
1707
  onTouchStart: event => {
1914
1708
  startDragging(resizeHandleId, event.nativeEvent);
1709
+ const callbacks = callbacksRef.current;
1710
+ assert(callbacks);
1915
1711
  const {
1916
1712
  onDragging
1917
- } = callbacksRef.current;
1713
+ } = callbacks;
1918
1714
  if (onDragging) {
1919
1715
  onDragging(true);
1920
1716
  }
@@ -1925,8 +1721,7 @@ function PanelResizeHandle({
1925
1721
  ...style,
1926
1722
  ...styleFromProps
1927
1723
  },
1928
- tabIndex: 0,
1929
- ...dataAttributes,
1724
+ tabIndex,
1930
1725
  // CSS selectors
1931
1726
  "data-panel-group-direction": direction,
1932
1727
  "data-panel-group-id": groupId,
@@ -1938,4 +1733,4 @@ function PanelResizeHandle({
1938
1733
  }
1939
1734
  PanelResizeHandle.displayName = "PanelResizeHandle";
1940
1735
 
1941
- export { Panel, PanelGroup, PanelResizeHandle };
1736
+ export { Panel, PanelGroup, PanelResizeHandle, assert };