react-resizable-panels 0.0.54 → 0.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/declarations/src/Panel.d.ts +5 -4
- package/dist/declarations/src/PanelGroup.d.ts +7 -3
- package/dist/declarations/src/index.d.ts +3 -2
- package/dist/declarations/src/types.d.ts +2 -1
- package/dist/declarations/src/utils/group.d.ts +29 -0
- package/dist/react-resizable-panels.browser.cjs.js +385 -108
- package/dist/react-resizable-panels.browser.cjs.mjs +2 -1
- package/dist/react-resizable-panels.browser.development.cjs.js +417 -108
- package/dist/react-resizable-panels.browser.development.cjs.mjs +2 -1
- package/dist/react-resizable-panels.browser.development.esm.js +417 -109
- package/dist/react-resizable-panels.browser.esm.js +385 -109
- package/dist/react-resizable-panels.cjs.js +385 -108
- package/dist/react-resizable-panels.cjs.js.map +1 -0
- package/dist/react-resizable-panels.cjs.mjs +2 -1
- package/dist/react-resizable-panels.development.cjs.js +417 -108
- package/dist/react-resizable-panels.development.cjs.mjs +2 -1
- package/dist/react-resizable-panels.development.esm.js +417 -109
- package/dist/react-resizable-panels.development.node.cjs.js +282 -76
- package/dist/react-resizable-panels.development.node.cjs.mjs +2 -1
- package/dist/react-resizable-panels.development.node.esm.js +282 -77
- package/dist/react-resizable-panels.esm.js +385 -109
- package/dist/react-resizable-panels.esm.js.map +1 -0
- package/dist/react-resizable-panels.node.cjs.js +254 -76
- package/dist/react-resizable-panels.node.cjs.mjs +2 -1
- package/dist/react-resizable-panels.node.esm.js +254 -77
- package/package.json +1 -1
- package/src/Panel.ts +32 -32
- package/src/PanelContexts.ts +4 -2
- package/src/PanelGroup.ts +221 -111
- package/src/hooks/useWindowSplitterBehavior.ts +14 -11
- package/src/index.ts +11 -3
- package/src/types.ts +2 -1
- package/src/utils/group.ts +327 -28
|
@@ -43,8 +43,8 @@ function PanelWithForwardedRef({
|
|
|
43
43
|
defaultSize = null,
|
|
44
44
|
forwardedRef,
|
|
45
45
|
id: idFromProps = null,
|
|
46
|
-
maxSize =
|
|
47
|
-
minSize
|
|
46
|
+
maxSize = null,
|
|
47
|
+
minSize,
|
|
48
48
|
onCollapse = null,
|
|
49
49
|
onResize = null,
|
|
50
50
|
order = null,
|
|
@@ -59,11 +59,22 @@ function PanelWithForwardedRef({
|
|
|
59
59
|
const {
|
|
60
60
|
collapsePanel,
|
|
61
61
|
expandPanel,
|
|
62
|
+
getPanelSize,
|
|
62
63
|
getPanelStyle,
|
|
63
64
|
registerPanel,
|
|
64
65
|
resizePanel,
|
|
66
|
+
units,
|
|
65
67
|
unregisterPanel
|
|
66
68
|
} = context;
|
|
69
|
+
if (minSize == null) {
|
|
70
|
+
if (units === "percentages") {
|
|
71
|
+
// Mimics legacy default value for percentage based panel groups
|
|
72
|
+
minSize = 10;
|
|
73
|
+
} else {
|
|
74
|
+
// There is no meaningful minimum pixel default we can provide
|
|
75
|
+
minSize = 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
67
78
|
|
|
68
79
|
// Use a ref to guard against users passing inline props
|
|
69
80
|
const callbacksRef = useRef({
|
|
@@ -74,22 +85,6 @@ function PanelWithForwardedRef({
|
|
|
74
85
|
callbacksRef.current.onCollapse = onCollapse;
|
|
75
86
|
callbacksRef.current.onResize = onResize;
|
|
76
87
|
});
|
|
77
|
-
|
|
78
|
-
// Basic props validation
|
|
79
|
-
if (minSize < 0 || minSize > 100) {
|
|
80
|
-
throw Error(`Panel minSize must be between 0 and 100, but was ${minSize}`);
|
|
81
|
-
} else if (maxSize < 0 || maxSize > 100) {
|
|
82
|
-
throw Error(`Panel maxSize must be between 0 and 100, but was ${maxSize}`);
|
|
83
|
-
} else {
|
|
84
|
-
if (defaultSize !== null) {
|
|
85
|
-
if (defaultSize < 0 || defaultSize > 100) {
|
|
86
|
-
throw Error(`Panel defaultSize must be between 0 and 100, but was ${defaultSize}`);
|
|
87
|
-
} else if (minSize > defaultSize && !collapsible) {
|
|
88
|
-
console.error(`Panel minSize ${minSize} cannot be greater than defaultSize ${defaultSize}`);
|
|
89
|
-
defaultSize = minSize;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
88
|
const style = getPanelStyle(panelId, defaultSize);
|
|
94
89
|
const committedValuesRef = useRef({
|
|
95
90
|
size: parseSizeFromStyle(style)
|
|
@@ -111,11 +106,14 @@ function PanelWithForwardedRef({
|
|
|
111
106
|
getCollapsed() {
|
|
112
107
|
return committedValuesRef.current.size === 0;
|
|
113
108
|
},
|
|
114
|
-
|
|
115
|
-
return
|
|
109
|
+
getId() {
|
|
110
|
+
return panelId;
|
|
111
|
+
},
|
|
112
|
+
getSize(units) {
|
|
113
|
+
return getPanelSize(panelId, units);
|
|
116
114
|
},
|
|
117
|
-
resize: percentage => resizePanel(panelId, percentage)
|
|
118
|
-
}), [collapsePanel, expandPanel, panelId, resizePanel]);
|
|
115
|
+
resize: (percentage, units) => resizePanel(panelId, percentage, units)
|
|
116
|
+
}), [collapsePanel, expandPanel, getPanelSize, panelId, resizePanel]);
|
|
119
117
|
return createElement(Type, {
|
|
120
118
|
children,
|
|
121
119
|
className: classNameFromProps,
|
|
@@ -151,7 +149,13 @@ function parseSizeFromStyle(style) {
|
|
|
151
149
|
|
|
152
150
|
const PRECISION = 10;
|
|
153
151
|
|
|
154
|
-
function adjustByDelta(event,
|
|
152
|
+
function adjustByDelta(event, committedValues, idBefore, idAfter, deltaPixels, prevSizes, panelSizeBeforeCollapse, initialDragState) {
|
|
153
|
+
const {
|
|
154
|
+
id: groupId,
|
|
155
|
+
panels,
|
|
156
|
+
units
|
|
157
|
+
} = committedValues;
|
|
158
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
155
159
|
const {
|
|
156
160
|
sizes: initialSizes
|
|
157
161
|
} = initialDragState || {};
|
|
@@ -159,9 +163,6 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
159
163
|
// If we're resizing by mouse or touch, use the initial sizes as a base.
|
|
160
164
|
// This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
|
|
161
165
|
const baseSizes = initialSizes || prevSizes;
|
|
162
|
-
if (delta === 0) {
|
|
163
|
-
return baseSizes;
|
|
164
|
-
}
|
|
165
166
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
166
167
|
const nextSizes = baseSizes.concat();
|
|
167
168
|
let deltaApplied = 0;
|
|
@@ -176,11 +177,11 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
176
177
|
|
|
177
178
|
// Max-bounds check the panel being expanded first.
|
|
178
179
|
{
|
|
179
|
-
const pivotId =
|
|
180
|
+
const pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
180
181
|
const index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
181
182
|
const panel = panelsArray[index];
|
|
182
183
|
const baseSize = baseSizes[index];
|
|
183
|
-
const nextSize = safeResizePanel(panel, Math.abs(
|
|
184
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize + Math.abs(deltaPixels), event);
|
|
184
185
|
if (baseSize === nextSize) {
|
|
185
186
|
// If there's no room for the pivot panel to grow, we can ignore this drag update.
|
|
186
187
|
return baseSizes;
|
|
@@ -188,29 +189,29 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
188
189
|
if (nextSize === 0 && baseSize > 0) {
|
|
189
190
|
panelSizeBeforeCollapse.set(pivotId, baseSize);
|
|
190
191
|
}
|
|
191
|
-
|
|
192
|
+
deltaPixels = deltaPixels < 0 ? baseSize - nextSize : nextSize - baseSize;
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
|
-
let pivotId =
|
|
195
|
+
let pivotId = deltaPixels < 0 ? idBefore : idAfter;
|
|
195
196
|
let index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
196
197
|
while (true) {
|
|
197
198
|
const panel = panelsArray[index];
|
|
198
199
|
const baseSize = baseSizes[index];
|
|
199
|
-
const deltaRemaining = Math.abs(
|
|
200
|
-
const nextSize = safeResizePanel(panel,
|
|
200
|
+
const deltaRemaining = Math.abs(deltaPixels) - Math.abs(deltaApplied);
|
|
201
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize - deltaRemaining, event);
|
|
201
202
|
if (baseSize !== nextSize) {
|
|
202
203
|
if (nextSize === 0 && baseSize > 0) {
|
|
203
204
|
panelSizeBeforeCollapse.set(panel.current.id, baseSize);
|
|
204
205
|
}
|
|
205
206
|
deltaApplied += baseSize - nextSize;
|
|
206
207
|
nextSizes[index] = nextSize;
|
|
207
|
-
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(
|
|
208
|
+
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(deltaPixels).toPrecision(PRECISION), undefined, {
|
|
208
209
|
numeric: true
|
|
209
210
|
}) >= 0) {
|
|
210
211
|
break;
|
|
211
212
|
}
|
|
212
213
|
}
|
|
213
|
-
if (
|
|
214
|
+
if (deltaPixels < 0) {
|
|
214
215
|
if (--index < 0) {
|
|
215
216
|
break;
|
|
216
217
|
}
|
|
@@ -228,7 +229,7 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
// Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
|
|
231
|
-
pivotId =
|
|
232
|
+
pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
232
233
|
index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
233
234
|
nextSizes[index] = baseSizes[index] + deltaApplied;
|
|
234
235
|
return nextSizes;
|
|
@@ -280,6 +281,23 @@ function getBeforeAndAfterIds(id, panelsArray) {
|
|
|
280
281
|
const idAfter = isLastPanel ? id : panelsArray[index + 1].current.id;
|
|
281
282
|
return [idBefore, idAfter];
|
|
282
283
|
}
|
|
284
|
+
function getAvailableGroupSizePixels(groupId) {
|
|
285
|
+
const panelGroupElement = getPanelGroup(groupId);
|
|
286
|
+
if (panelGroupElement == null) {
|
|
287
|
+
return NaN;
|
|
288
|
+
}
|
|
289
|
+
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
290
|
+
const resizeHandles = getResizeHandlesForGroup(groupId);
|
|
291
|
+
if (direction === "horizontal") {
|
|
292
|
+
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
293
|
+
return accumulated + handle.offsetWidth;
|
|
294
|
+
}, 0);
|
|
295
|
+
} else {
|
|
296
|
+
return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
|
|
297
|
+
return accumulated + handle.offsetHeight;
|
|
298
|
+
}, 0);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
283
301
|
|
|
284
302
|
// This method returns a number between 1 and 100 representing
|
|
285
303
|
// the % of the group's overall space this panel should occupy.
|
|
@@ -350,18 +368,24 @@ function panelsMapToSortedArray(panels) {
|
|
|
350
368
|
}
|
|
351
369
|
});
|
|
352
370
|
}
|
|
353
|
-
function safeResizePanel(
|
|
354
|
-
|
|
355
|
-
const {
|
|
371
|
+
function safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize, event = null) {
|
|
372
|
+
let {
|
|
356
373
|
collapsedSize,
|
|
357
374
|
collapsible,
|
|
358
375
|
maxSize,
|
|
359
376
|
minSize
|
|
360
377
|
} = panel.current;
|
|
378
|
+
if (units === "pixels") {
|
|
379
|
+
collapsedSize = collapsedSize / groupSizePixels * 100;
|
|
380
|
+
if (maxSize != null) {
|
|
381
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
382
|
+
}
|
|
383
|
+
minSize = minSize / groupSizePixels * 100;
|
|
384
|
+
}
|
|
361
385
|
if (collapsible) {
|
|
362
386
|
if (prevSize > collapsedSize) {
|
|
363
387
|
// Mimic VS COde behavior; collapse a panel if it's smaller than half of its min-size
|
|
364
|
-
if (
|
|
388
|
+
if (nextSize <= minSize / 2 + collapsedSize) {
|
|
365
389
|
return collapsedSize;
|
|
366
390
|
}
|
|
367
391
|
} else {
|
|
@@ -370,14 +394,119 @@ function safeResizePanel(panel, delta, prevSize, event) {
|
|
|
370
394
|
// Keyboard events should expand a collapsed panel to the min size,
|
|
371
395
|
// but mouse events should wait until the panel has reached its min size
|
|
372
396
|
// to avoid a visual flickering when dragging between collapsed and min size.
|
|
373
|
-
if (
|
|
397
|
+
if (nextSize < minSize) {
|
|
374
398
|
return collapsedSize;
|
|
375
399
|
}
|
|
376
400
|
}
|
|
377
401
|
}
|
|
378
402
|
}
|
|
379
|
-
|
|
380
|
-
|
|
403
|
+
return Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
404
|
+
}
|
|
405
|
+
function validatePanelProps(units, panelData) {
|
|
406
|
+
const {
|
|
407
|
+
collapsible,
|
|
408
|
+
defaultSize,
|
|
409
|
+
maxSize,
|
|
410
|
+
minSize
|
|
411
|
+
} = panelData.current;
|
|
412
|
+
|
|
413
|
+
// Basic props validation
|
|
414
|
+
if (minSize < 0 || units === "percentages" && minSize > 100) {
|
|
415
|
+
{
|
|
416
|
+
console.error(`Invalid Panel minSize provided, ${minSize}`);
|
|
417
|
+
}
|
|
418
|
+
panelData.current.minSize = 0;
|
|
419
|
+
}
|
|
420
|
+
if (maxSize != null) {
|
|
421
|
+
if (maxSize < 0 || units === "percentages" && maxSize > 100) {
|
|
422
|
+
{
|
|
423
|
+
console.error(`Invalid Panel maxSize provided, ${maxSize}`);
|
|
424
|
+
}
|
|
425
|
+
panelData.current.maxSize = null;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (defaultSize !== null) {
|
|
429
|
+
if (defaultSize < 0 || units === "percentages" && defaultSize > 100) {
|
|
430
|
+
{
|
|
431
|
+
console.error(`Invalid Panel defaultSize provided, ${defaultSize}`);
|
|
432
|
+
}
|
|
433
|
+
panelData.current.defaultSize = null;
|
|
434
|
+
} else if (defaultSize < minSize && !collapsible) {
|
|
435
|
+
{
|
|
436
|
+
console.error(`Panel minSize (${minSize}) cannot be greater than defaultSize (${defaultSize})`);
|
|
437
|
+
}
|
|
438
|
+
panelData.current.defaultSize = minSize;
|
|
439
|
+
} else if (maxSize != null && defaultSize > maxSize) {
|
|
440
|
+
{
|
|
441
|
+
console.error(`Panel maxSize (${maxSize}) cannot be less than defaultSize (${defaultSize})`);
|
|
442
|
+
}
|
|
443
|
+
panelData.current.defaultSize = maxSize;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function validatePanelGroupLayout({
|
|
448
|
+
groupId,
|
|
449
|
+
panels,
|
|
450
|
+
nextSizes,
|
|
451
|
+
prevSizes,
|
|
452
|
+
units
|
|
453
|
+
}) {
|
|
454
|
+
// Clone because this method modifies
|
|
455
|
+
nextSizes = [...nextSizes];
|
|
456
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
457
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
458
|
+
let remainingSize = 0;
|
|
459
|
+
|
|
460
|
+
// First, check all of the proposed sizes against the min/max constraints
|
|
461
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
462
|
+
const panel = panelsArray[index];
|
|
463
|
+
const prevSize = prevSizes[index];
|
|
464
|
+
const nextSize = nextSizes[index];
|
|
465
|
+
const safeNextSize = safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize);
|
|
466
|
+
if (nextSize != safeNextSize) {
|
|
467
|
+
remainingSize += nextSize - safeNextSize;
|
|
468
|
+
nextSizes[index] = safeNextSize;
|
|
469
|
+
{
|
|
470
|
+
console.error(`Invalid size (${nextSize}) specified for Panel "${panel.current.id}" given the panel's min/max size constraints`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// If there is additional, left over space, assign it to any panel(s) that permits it
|
|
476
|
+
// (It's not worth taking multiple additional passes to evenly distribute)
|
|
477
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
478
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
479
|
+
const panel = panelsArray[index];
|
|
480
|
+
let {
|
|
481
|
+
maxSize,
|
|
482
|
+
minSize
|
|
483
|
+
} = panel.current;
|
|
484
|
+
if (units === "pixels") {
|
|
485
|
+
minSize = minSize / groupSizePixels * 100;
|
|
486
|
+
if (maxSize != null) {
|
|
487
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSizes[index] + remainingSize));
|
|
491
|
+
if (size !== nextSizes[index]) {
|
|
492
|
+
remainingSize -= size - nextSizes[index];
|
|
493
|
+
nextSizes[index] = size;
|
|
494
|
+
|
|
495
|
+
// Fuzzy comparison to account for imprecise floating point math
|
|
496
|
+
if (Math.abs(remainingSize).toFixed(3) === "0.000") {
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// If we still have remainder, the requested layout wasn't valid and we should warn about it
|
|
504
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
505
|
+
{
|
|
506
|
+
console.error(`"Invalid panel group configuration; default panel sizes should total 100% but was ${100 - remainingSize}%`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return nextSizes;
|
|
381
510
|
}
|
|
382
511
|
|
|
383
512
|
function assert(expectedCondition, message = "Assertion failed!") {
|
|
@@ -403,6 +532,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
403
532
|
panels
|
|
404
533
|
} = committedValuesRef.current;
|
|
405
534
|
const groupElement = getPanelGroup(groupId);
|
|
535
|
+
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
406
536
|
const {
|
|
407
537
|
height,
|
|
408
538
|
width
|
|
@@ -415,23 +545,28 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
415
545
|
if (idBefore == null || idAfter == null) {
|
|
416
546
|
return () => {};
|
|
417
547
|
}
|
|
418
|
-
let
|
|
419
|
-
let
|
|
548
|
+
let currentMinSize = 0;
|
|
549
|
+
let currentMaxSize = 100;
|
|
420
550
|
let totalMinSize = 0;
|
|
421
551
|
let totalMaxSize = 0;
|
|
422
552
|
|
|
423
553
|
// A panel's effective min/max sizes also need to account for other panel's sizes.
|
|
424
554
|
panelsArray.forEach(panelData => {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
555
|
+
const {
|
|
556
|
+
id,
|
|
557
|
+
maxSize,
|
|
558
|
+
minSize
|
|
559
|
+
} = panelData.current;
|
|
560
|
+
if (id === idBefore) {
|
|
561
|
+
currentMinSize = minSize;
|
|
562
|
+
currentMaxSize = maxSize != null ? maxSize : 100;
|
|
428
563
|
} else {
|
|
429
|
-
totalMinSize +=
|
|
430
|
-
totalMaxSize +=
|
|
564
|
+
totalMinSize += minSize;
|
|
565
|
+
totalMaxSize += maxSize != null ? maxSize : 100;
|
|
431
566
|
}
|
|
432
567
|
});
|
|
433
|
-
const ariaValueMax = Math.min(
|
|
434
|
-
const ariaValueMin = Math.max(
|
|
568
|
+
const ariaValueMax = Math.min(currentMaxSize, 100 - totalMinSize);
|
|
569
|
+
const ariaValueMin = Math.max(currentMinSize, (panelsArray.length - 1) * 100 - totalMaxSize);
|
|
435
570
|
const flexGrow = getFlexGrow(panels, idBefore, sizes);
|
|
436
571
|
handle.setAttribute("aria-valuemax", "" + Math.round(ariaValueMax));
|
|
437
572
|
handle.setAttribute("aria-valuemin", "" + Math.round(ariaValueMin));
|
|
@@ -455,7 +590,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
455
590
|
} else {
|
|
456
591
|
delta = -(direction === "horizontal" ? width : height);
|
|
457
592
|
}
|
|
458
|
-
const nextSizes = adjustByDelta(event,
|
|
593
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, sizes, panelSizeBeforeCollapse.current, null);
|
|
459
594
|
if (sizes !== nextSizes) {
|
|
460
595
|
setSizes(nextSizes);
|
|
461
596
|
}
|
|
@@ -762,9 +897,6 @@ const defaultStorage = {
|
|
|
762
897
|
// * dragHandleRect, sizes:
|
|
763
898
|
// When resizing is done via mouse/touch event– some initial state is stored
|
|
764
899
|
// so that any panels that contract will also expand if drag direction is reversed.
|
|
765
|
-
// TODO
|
|
766
|
-
// Within an active drag, remember original positions to refine more easily on expand.
|
|
767
|
-
// Look at what the Chrome devtools Sources does.
|
|
768
900
|
function PanelGroupWithForwardedRef({
|
|
769
901
|
autoSaveId,
|
|
770
902
|
children = null,
|
|
@@ -776,7 +908,8 @@ function PanelGroupWithForwardedRef({
|
|
|
776
908
|
onLayout,
|
|
777
909
|
storage = defaultStorage,
|
|
778
910
|
style: styleFromProps = {},
|
|
779
|
-
tagName: Type = "div"
|
|
911
|
+
tagName: Type = "div",
|
|
912
|
+
units = "percentages"
|
|
780
913
|
}) {
|
|
781
914
|
const groupId = useUniqueId(idFromProps);
|
|
782
915
|
const [activeHandleId, setActiveHandleId] = useState(null);
|
|
@@ -789,6 +922,7 @@ function PanelGroupWithForwardedRef({
|
|
|
789
922
|
const devWarningsRef = useRef({
|
|
790
923
|
didLogDefaultSizeWarning: false,
|
|
791
924
|
didLogIdAndOrderWarning: false,
|
|
925
|
+
didLogInvalidLayoutWarning: false,
|
|
792
926
|
prevPanelIds: []
|
|
793
927
|
});
|
|
794
928
|
|
|
@@ -811,28 +945,52 @@ function PanelGroupWithForwardedRef({
|
|
|
811
945
|
// Store committed values to avoid unnecessarily re-running memoization/effects functions.
|
|
812
946
|
const committedValuesRef = useRef({
|
|
813
947
|
direction,
|
|
948
|
+
id: groupId,
|
|
814
949
|
panels,
|
|
815
|
-
sizes
|
|
950
|
+
sizes,
|
|
951
|
+
units
|
|
816
952
|
});
|
|
817
953
|
useImperativeHandle(forwardedRef, () => ({
|
|
818
|
-
|
|
954
|
+
getId: () => groupId,
|
|
955
|
+
getLayout: unitsFromParams => {
|
|
819
956
|
const {
|
|
820
|
-
sizes
|
|
957
|
+
sizes,
|
|
958
|
+
units: unitsFromProps
|
|
821
959
|
} = committedValuesRef.current;
|
|
822
|
-
|
|
960
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
961
|
+
if (units === "pixels") {
|
|
962
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
963
|
+
return sizes.map(size => size / 100 * groupSizePixels);
|
|
964
|
+
} else {
|
|
965
|
+
return sizes;
|
|
966
|
+
}
|
|
823
967
|
},
|
|
824
|
-
setLayout: sizes => {
|
|
825
|
-
const total = sizes.reduce((accumulated, current) => accumulated + current, 0);
|
|
826
|
-
assert(total === 100, "Panel sizes must add up to 100%");
|
|
968
|
+
setLayout: (sizes, unitsFromParams) => {
|
|
827
969
|
const {
|
|
828
|
-
|
|
970
|
+
id: groupId,
|
|
971
|
+
panels,
|
|
972
|
+
sizes: prevSizes,
|
|
973
|
+
units
|
|
829
974
|
} = committedValuesRef.current;
|
|
975
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
976
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
977
|
+
sizes = sizes.map(size => size / groupSizePixels * 100);
|
|
978
|
+
}
|
|
830
979
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
831
980
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
832
|
-
|
|
833
|
-
|
|
981
|
+
const nextSizes = validatePanelGroupLayout({
|
|
982
|
+
groupId,
|
|
983
|
+
panels,
|
|
984
|
+
nextSizes: sizes,
|
|
985
|
+
prevSizes,
|
|
986
|
+
units
|
|
987
|
+
});
|
|
988
|
+
if (!areEqual(prevSizes, nextSizes)) {
|
|
989
|
+
setSizes(nextSizes);
|
|
990
|
+
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
991
|
+
}
|
|
834
992
|
}
|
|
835
|
-
}), []);
|
|
993
|
+
}), [groupId]);
|
|
836
994
|
useWindowSplitterPanelGroupBehavior({
|
|
837
995
|
committedValuesRef,
|
|
838
996
|
groupId,
|
|
@@ -903,6 +1061,22 @@ function PanelGroupWithForwardedRef({
|
|
|
903
1061
|
}
|
|
904
1062
|
}
|
|
905
1063
|
}, [autoSaveId, panels, sizes, storage]);
|
|
1064
|
+
const getPanelSize = useCallback((id, unitsFromParams) => {
|
|
1065
|
+
const {
|
|
1066
|
+
panels,
|
|
1067
|
+
units: unitsFromProps
|
|
1068
|
+
} = committedValuesRef.current;
|
|
1069
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
1070
|
+
const index = panelsArray.findIndex(panel => panel.current.id === id);
|
|
1071
|
+
const size = sizes[index];
|
|
1072
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
1073
|
+
if (units === "pixels") {
|
|
1074
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1075
|
+
return size / 100 * groupSizePixels;
|
|
1076
|
+
} else {
|
|
1077
|
+
return size;
|
|
1078
|
+
}
|
|
1079
|
+
}, [groupId, sizes]);
|
|
906
1080
|
const getPanelStyle = useCallback((id, defaultSize) => {
|
|
907
1081
|
const {
|
|
908
1082
|
panels
|
|
@@ -941,6 +1115,10 @@ function PanelGroupWithForwardedRef({
|
|
|
941
1115
|
};
|
|
942
1116
|
}, [activeHandleId, disablePointerEventsDuringResize, sizes]);
|
|
943
1117
|
const registerPanel = useCallback((id, panelRef) => {
|
|
1118
|
+
const {
|
|
1119
|
+
units
|
|
1120
|
+
} = committedValuesRef.current;
|
|
1121
|
+
validatePanelProps(units, panelRef);
|
|
944
1122
|
setPanels(prevPanels => {
|
|
945
1123
|
if (prevPanels.has(id)) {
|
|
946
1124
|
return prevPanels;
|
|
@@ -977,7 +1155,10 @@ function PanelGroupWithForwardedRef({
|
|
|
977
1155
|
}
|
|
978
1156
|
const size = isHorizontal ? rect.width : rect.height;
|
|
979
1157
|
const delta = movement / size * 100;
|
|
980
|
-
|
|
1158
|
+
|
|
1159
|
+
// If a validateLayout method has been provided
|
|
1160
|
+
// it's important to use it before updating the mouse cursor
|
|
1161
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, initialDragStateRef.current);
|
|
981
1162
|
const sizesChanged = !areEqual(prevSizes, nextSizes);
|
|
982
1163
|
|
|
983
1164
|
// Don't update cursor for resizes triggered by keyboard interactions.
|
|
@@ -1004,6 +1185,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1004
1185
|
}
|
|
1005
1186
|
if (sizesChanged) {
|
|
1006
1187
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1188
|
+
|
|
1189
|
+
// It's okay to bypass in this case because we already validated above
|
|
1007
1190
|
setSizes(nextSizes);
|
|
1008
1191
|
|
|
1009
1192
|
// If resize change handlers have been declared, this is the time to call them.
|
|
@@ -1057,7 +1240,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1057
1240
|
}
|
|
1058
1241
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1059
1242
|
const delta = isLastPanel ? currentSize : collapsedSize - currentSize;
|
|
1060
|
-
const nextSizes = adjustByDelta(null,
|
|
1243
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1061
1244
|
if (prevSizes !== nextSizes) {
|
|
1062
1245
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1063
1246
|
setSizes(nextSizes);
|
|
@@ -1100,7 +1283,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1100
1283
|
}
|
|
1101
1284
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1102
1285
|
const delta = isLastPanel ? collapsedSize - sizeBeforeCollapse : sizeBeforeCollapse;
|
|
1103
|
-
const nextSizes = adjustByDelta(null,
|
|
1286
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1104
1287
|
if (prevSizes !== nextSizes) {
|
|
1105
1288
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1106
1289
|
setSizes(nextSizes);
|
|
@@ -1110,21 +1293,34 @@ function PanelGroupWithForwardedRef({
|
|
|
1110
1293
|
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1111
1294
|
}
|
|
1112
1295
|
}, []);
|
|
1113
|
-
const resizePanel = useCallback((id, nextSize) => {
|
|
1296
|
+
const resizePanel = useCallback((id, nextSize, unitsFromParams) => {
|
|
1114
1297
|
const {
|
|
1298
|
+
id: groupId,
|
|
1115
1299
|
panels,
|
|
1116
|
-
sizes: prevSizes
|
|
1300
|
+
sizes: prevSizes,
|
|
1301
|
+
units
|
|
1117
1302
|
} = committedValuesRef.current;
|
|
1303
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1304
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1305
|
+
nextSize = nextSize / groupSizePixels * 100;
|
|
1306
|
+
}
|
|
1118
1307
|
const panel = panels.get(id);
|
|
1119
1308
|
if (panel == null) {
|
|
1120
1309
|
return;
|
|
1121
1310
|
}
|
|
1122
|
-
|
|
1311
|
+
let {
|
|
1123
1312
|
collapsedSize,
|
|
1124
1313
|
collapsible,
|
|
1125
1314
|
maxSize,
|
|
1126
1315
|
minSize
|
|
1127
1316
|
} = panel.current;
|
|
1317
|
+
if (units === "pixels") {
|
|
1318
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1319
|
+
minSize = minSize / groupSizePixels * 100;
|
|
1320
|
+
if (maxSize != null) {
|
|
1321
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1128
1324
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
1129
1325
|
const index = panelsArray.indexOf(panel);
|
|
1130
1326
|
if (index < 0) {
|
|
@@ -1135,7 +1331,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1135
1331
|
return;
|
|
1136
1332
|
}
|
|
1137
1333
|
if (collapsible && nextSize === collapsedSize) ; else {
|
|
1138
|
-
|
|
1334
|
+
const unsafeNextSize = nextSize;
|
|
1335
|
+
nextSize = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
1336
|
+
{
|
|
1337
|
+
if (unsafeNextSize !== nextSize) {
|
|
1338
|
+
console.error(`Invalid size (${unsafeNextSize}) specified for Panel "${panel.current.id}" given the panel's min/max size constraints`);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1139
1341
|
}
|
|
1140
1342
|
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
1141
1343
|
if (idBefore == null || idAfter == null) {
|
|
@@ -1143,7 +1345,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1143
1345
|
}
|
|
1144
1346
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1145
1347
|
const delta = isLastPanel ? currentSize - nextSize : nextSize - currentSize;
|
|
1146
|
-
const nextSizes = adjustByDelta(null,
|
|
1348
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1147
1349
|
if (prevSizes !== nextSizes) {
|
|
1148
1350
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1149
1351
|
setSizes(nextSizes);
|
|
@@ -1158,6 +1360,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1158
1360
|
collapsePanel,
|
|
1159
1361
|
direction,
|
|
1160
1362
|
expandPanel,
|
|
1363
|
+
getPanelSize,
|
|
1161
1364
|
getPanelStyle,
|
|
1162
1365
|
groupId,
|
|
1163
1366
|
registerPanel,
|
|
@@ -1179,8 +1382,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1179
1382
|
setActiveHandleId(null);
|
|
1180
1383
|
initialDragStateRef.current = null;
|
|
1181
1384
|
},
|
|
1385
|
+
units,
|
|
1182
1386
|
unregisterPanel
|
|
1183
|
-
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, unregisterPanel]);
|
|
1387
|
+
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelSize, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, units, unregisterPanel]);
|
|
1184
1388
|
const style = {
|
|
1185
1389
|
display: "flex",
|
|
1186
1390
|
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
@@ -1195,6 +1399,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1195
1399
|
"data-panel-group": "",
|
|
1196
1400
|
"data-panel-group-direction": direction,
|
|
1197
1401
|
"data-panel-group-id": groupId,
|
|
1402
|
+
"data-panel-group-units": units,
|
|
1198
1403
|
style: {
|
|
1199
1404
|
...style,
|
|
1200
1405
|
...styleFromProps
|
|
@@ -1344,4 +1549,4 @@ function PanelResizeHandle({
|
|
|
1344
1549
|
}
|
|
1345
1550
|
PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
1346
1551
|
|
|
1347
|
-
export { Panel, PanelGroup, PanelResizeHandle };
|
|
1552
|
+
export { Panel, PanelGroup, PanelResizeHandle, getAvailableGroupSizePixels };
|