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
|
@@ -67,8 +67,8 @@ function PanelWithForwardedRef({
|
|
|
67
67
|
defaultSize = null,
|
|
68
68
|
forwardedRef,
|
|
69
69
|
id: idFromProps = null,
|
|
70
|
-
maxSize =
|
|
71
|
-
minSize
|
|
70
|
+
maxSize = null,
|
|
71
|
+
minSize,
|
|
72
72
|
onCollapse = null,
|
|
73
73
|
onResize = null,
|
|
74
74
|
order = null,
|
|
@@ -83,11 +83,22 @@ function PanelWithForwardedRef({
|
|
|
83
83
|
const {
|
|
84
84
|
collapsePanel,
|
|
85
85
|
expandPanel,
|
|
86
|
+
getPanelSize,
|
|
86
87
|
getPanelStyle,
|
|
87
88
|
registerPanel,
|
|
88
89
|
resizePanel,
|
|
90
|
+
units,
|
|
89
91
|
unregisterPanel
|
|
90
92
|
} = context;
|
|
93
|
+
if (minSize == null) {
|
|
94
|
+
if (units === "percentages") {
|
|
95
|
+
// Mimics legacy default value for percentage based panel groups
|
|
96
|
+
minSize = 10;
|
|
97
|
+
} else {
|
|
98
|
+
// There is no meaningful minimum pixel default we can provide
|
|
99
|
+
minSize = 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
91
102
|
|
|
92
103
|
// Use a ref to guard against users passing inline props
|
|
93
104
|
const callbacksRef = useRef({
|
|
@@ -98,22 +109,6 @@ function PanelWithForwardedRef({
|
|
|
98
109
|
callbacksRef.current.onCollapse = onCollapse;
|
|
99
110
|
callbacksRef.current.onResize = onResize;
|
|
100
111
|
});
|
|
101
|
-
|
|
102
|
-
// Basic props validation
|
|
103
|
-
if (minSize < 0 || minSize > 100) {
|
|
104
|
-
throw Error(`Panel minSize must be between 0 and 100, but was ${minSize}`);
|
|
105
|
-
} else if (maxSize < 0 || maxSize > 100) {
|
|
106
|
-
throw Error(`Panel maxSize must be between 0 and 100, but was ${maxSize}`);
|
|
107
|
-
} else {
|
|
108
|
-
if (defaultSize !== null) {
|
|
109
|
-
if (defaultSize < 0 || defaultSize > 100) {
|
|
110
|
-
throw Error(`Panel defaultSize must be between 0 and 100, but was ${defaultSize}`);
|
|
111
|
-
} else if (minSize > defaultSize && !collapsible) {
|
|
112
|
-
console.error(`Panel minSize ${minSize} cannot be greater than defaultSize ${defaultSize}`);
|
|
113
|
-
defaultSize = minSize;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
112
|
const style = getPanelStyle(panelId, defaultSize);
|
|
118
113
|
const committedValuesRef = useRef({
|
|
119
114
|
size: parseSizeFromStyle(style)
|
|
@@ -135,11 +130,14 @@ function PanelWithForwardedRef({
|
|
|
135
130
|
getCollapsed() {
|
|
136
131
|
return committedValuesRef.current.size === 0;
|
|
137
132
|
},
|
|
138
|
-
|
|
139
|
-
return
|
|
133
|
+
getId() {
|
|
134
|
+
return panelId;
|
|
135
|
+
},
|
|
136
|
+
getSize(units) {
|
|
137
|
+
return getPanelSize(panelId, units);
|
|
140
138
|
},
|
|
141
|
-
resize: percentage => resizePanel(panelId, percentage)
|
|
142
|
-
}), [collapsePanel, expandPanel, panelId, resizePanel]);
|
|
139
|
+
resize: (percentage, units) => resizePanel(panelId, percentage, units)
|
|
140
|
+
}), [collapsePanel, expandPanel, getPanelSize, panelId, resizePanel]);
|
|
143
141
|
return createElement(Type, {
|
|
144
142
|
children,
|
|
145
143
|
className: classNameFromProps,
|
|
@@ -175,7 +173,13 @@ function parseSizeFromStyle(style) {
|
|
|
175
173
|
|
|
176
174
|
const PRECISION = 10;
|
|
177
175
|
|
|
178
|
-
function adjustByDelta(event,
|
|
176
|
+
function adjustByDelta(event, committedValues, idBefore, idAfter, deltaPixels, prevSizes, panelSizeBeforeCollapse, initialDragState) {
|
|
177
|
+
const {
|
|
178
|
+
id: groupId,
|
|
179
|
+
panels,
|
|
180
|
+
units
|
|
181
|
+
} = committedValues;
|
|
182
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
179
183
|
const {
|
|
180
184
|
sizes: initialSizes
|
|
181
185
|
} = initialDragState || {};
|
|
@@ -183,9 +187,6 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
183
187
|
// If we're resizing by mouse or touch, use the initial sizes as a base.
|
|
184
188
|
// This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
|
|
185
189
|
const baseSizes = initialSizes || prevSizes;
|
|
186
|
-
if (delta === 0) {
|
|
187
|
-
return baseSizes;
|
|
188
|
-
}
|
|
189
190
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
190
191
|
const nextSizes = baseSizes.concat();
|
|
191
192
|
let deltaApplied = 0;
|
|
@@ -200,11 +201,11 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
200
201
|
|
|
201
202
|
// Max-bounds check the panel being expanded first.
|
|
202
203
|
{
|
|
203
|
-
const pivotId =
|
|
204
|
+
const pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
204
205
|
const index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
205
206
|
const panel = panelsArray[index];
|
|
206
207
|
const baseSize = baseSizes[index];
|
|
207
|
-
const nextSize = safeResizePanel(panel, Math.abs(
|
|
208
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize + Math.abs(deltaPixels), event);
|
|
208
209
|
if (baseSize === nextSize) {
|
|
209
210
|
// If there's no room for the pivot panel to grow, we can ignore this drag update.
|
|
210
211
|
return baseSizes;
|
|
@@ -212,29 +213,29 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
212
213
|
if (nextSize === 0 && baseSize > 0) {
|
|
213
214
|
panelSizeBeforeCollapse.set(pivotId, baseSize);
|
|
214
215
|
}
|
|
215
|
-
|
|
216
|
+
deltaPixels = deltaPixels < 0 ? baseSize - nextSize : nextSize - baseSize;
|
|
216
217
|
}
|
|
217
218
|
}
|
|
218
|
-
let pivotId =
|
|
219
|
+
let pivotId = deltaPixels < 0 ? idBefore : idAfter;
|
|
219
220
|
let index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
220
221
|
while (true) {
|
|
221
222
|
const panel = panelsArray[index];
|
|
222
223
|
const baseSize = baseSizes[index];
|
|
223
|
-
const deltaRemaining = Math.abs(
|
|
224
|
-
const nextSize = safeResizePanel(panel,
|
|
224
|
+
const deltaRemaining = Math.abs(deltaPixels) - Math.abs(deltaApplied);
|
|
225
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize - deltaRemaining, event);
|
|
225
226
|
if (baseSize !== nextSize) {
|
|
226
227
|
if (nextSize === 0 && baseSize > 0) {
|
|
227
228
|
panelSizeBeforeCollapse.set(panel.current.id, baseSize);
|
|
228
229
|
}
|
|
229
230
|
deltaApplied += baseSize - nextSize;
|
|
230
231
|
nextSizes[index] = nextSize;
|
|
231
|
-
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(
|
|
232
|
+
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(deltaPixels).toPrecision(PRECISION), undefined, {
|
|
232
233
|
numeric: true
|
|
233
234
|
}) >= 0) {
|
|
234
235
|
break;
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
|
-
if (
|
|
238
|
+
if (deltaPixels < 0) {
|
|
238
239
|
if (--index < 0) {
|
|
239
240
|
break;
|
|
240
241
|
}
|
|
@@ -252,7 +253,7 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
// Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
|
|
255
|
-
pivotId =
|
|
256
|
+
pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
256
257
|
index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
257
258
|
nextSizes[index] = baseSizes[index] + deltaApplied;
|
|
258
259
|
return nextSizes;
|
|
@@ -304,6 +305,23 @@ function getBeforeAndAfterIds(id, panelsArray) {
|
|
|
304
305
|
const idAfter = isLastPanel ? id : panelsArray[index + 1].current.id;
|
|
305
306
|
return [idBefore, idAfter];
|
|
306
307
|
}
|
|
308
|
+
function getAvailableGroupSizePixels(groupId) {
|
|
309
|
+
const panelGroupElement = getPanelGroup(groupId);
|
|
310
|
+
if (panelGroupElement == null) {
|
|
311
|
+
return NaN;
|
|
312
|
+
}
|
|
313
|
+
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
314
|
+
const resizeHandles = getResizeHandlesForGroup(groupId);
|
|
315
|
+
if (direction === "horizontal") {
|
|
316
|
+
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
317
|
+
return accumulated + handle.offsetWidth;
|
|
318
|
+
}, 0);
|
|
319
|
+
} else {
|
|
320
|
+
return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
|
|
321
|
+
return accumulated + handle.offsetHeight;
|
|
322
|
+
}, 0);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
307
325
|
|
|
308
326
|
// This method returns a number between 1 and 100 representing
|
|
309
327
|
// the % of the group's overall space this panel should occupy.
|
|
@@ -374,18 +392,24 @@ function panelsMapToSortedArray(panels) {
|
|
|
374
392
|
}
|
|
375
393
|
});
|
|
376
394
|
}
|
|
377
|
-
function safeResizePanel(
|
|
378
|
-
|
|
379
|
-
const {
|
|
395
|
+
function safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize, event = null) {
|
|
396
|
+
let {
|
|
380
397
|
collapsedSize,
|
|
381
398
|
collapsible,
|
|
382
399
|
maxSize,
|
|
383
400
|
minSize
|
|
384
401
|
} = panel.current;
|
|
402
|
+
if (units === "pixels") {
|
|
403
|
+
collapsedSize = collapsedSize / groupSizePixels * 100;
|
|
404
|
+
if (maxSize != null) {
|
|
405
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
406
|
+
}
|
|
407
|
+
minSize = minSize / groupSizePixels * 100;
|
|
408
|
+
}
|
|
385
409
|
if (collapsible) {
|
|
386
410
|
if (prevSize > collapsedSize) {
|
|
387
411
|
// Mimic VS COde behavior; collapse a panel if it's smaller than half of its min-size
|
|
388
|
-
if (
|
|
412
|
+
if (nextSize <= minSize / 2 + collapsedSize) {
|
|
389
413
|
return collapsedSize;
|
|
390
414
|
}
|
|
391
415
|
} else {
|
|
@@ -394,14 +418,119 @@ function safeResizePanel(panel, delta, prevSize, event) {
|
|
|
394
418
|
// Keyboard events should expand a collapsed panel to the min size,
|
|
395
419
|
// but mouse events should wait until the panel has reached its min size
|
|
396
420
|
// to avoid a visual flickering when dragging between collapsed and min size.
|
|
397
|
-
if (
|
|
421
|
+
if (nextSize < minSize) {
|
|
398
422
|
return collapsedSize;
|
|
399
423
|
}
|
|
400
424
|
}
|
|
401
425
|
}
|
|
402
426
|
}
|
|
403
|
-
|
|
404
|
-
|
|
427
|
+
return Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
428
|
+
}
|
|
429
|
+
function validatePanelProps(units, panelData) {
|
|
430
|
+
const {
|
|
431
|
+
collapsible,
|
|
432
|
+
defaultSize,
|
|
433
|
+
maxSize,
|
|
434
|
+
minSize
|
|
435
|
+
} = panelData.current;
|
|
436
|
+
|
|
437
|
+
// Basic props validation
|
|
438
|
+
if (minSize < 0 || units === "percentages" && minSize > 100) {
|
|
439
|
+
{
|
|
440
|
+
console.error(`Invalid Panel minSize provided, ${minSize}`);
|
|
441
|
+
}
|
|
442
|
+
panelData.current.minSize = 0;
|
|
443
|
+
}
|
|
444
|
+
if (maxSize != null) {
|
|
445
|
+
if (maxSize < 0 || units === "percentages" && maxSize > 100) {
|
|
446
|
+
{
|
|
447
|
+
console.error(`Invalid Panel maxSize provided, ${maxSize}`);
|
|
448
|
+
}
|
|
449
|
+
panelData.current.maxSize = null;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (defaultSize !== null) {
|
|
453
|
+
if (defaultSize < 0 || units === "percentages" && defaultSize > 100) {
|
|
454
|
+
{
|
|
455
|
+
console.error(`Invalid Panel defaultSize provided, ${defaultSize}`);
|
|
456
|
+
}
|
|
457
|
+
panelData.current.defaultSize = null;
|
|
458
|
+
} else if (defaultSize < minSize && !collapsible) {
|
|
459
|
+
{
|
|
460
|
+
console.error(`Panel minSize (${minSize}) cannot be greater than defaultSize (${defaultSize})`);
|
|
461
|
+
}
|
|
462
|
+
panelData.current.defaultSize = minSize;
|
|
463
|
+
} else if (maxSize != null && defaultSize > maxSize) {
|
|
464
|
+
{
|
|
465
|
+
console.error(`Panel maxSize (${maxSize}) cannot be less than defaultSize (${defaultSize})`);
|
|
466
|
+
}
|
|
467
|
+
panelData.current.defaultSize = maxSize;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function validatePanelGroupLayout({
|
|
472
|
+
groupId,
|
|
473
|
+
panels,
|
|
474
|
+
nextSizes,
|
|
475
|
+
prevSizes,
|
|
476
|
+
units
|
|
477
|
+
}) {
|
|
478
|
+
// Clone because this method modifies
|
|
479
|
+
nextSizes = [...nextSizes];
|
|
480
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
481
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
482
|
+
let remainingSize = 0;
|
|
483
|
+
|
|
484
|
+
// First, check all of the proposed sizes against the min/max constraints
|
|
485
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
486
|
+
const panel = panelsArray[index];
|
|
487
|
+
const prevSize = prevSizes[index];
|
|
488
|
+
const nextSize = nextSizes[index];
|
|
489
|
+
const safeNextSize = safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize);
|
|
490
|
+
if (nextSize != safeNextSize) {
|
|
491
|
+
remainingSize += nextSize - safeNextSize;
|
|
492
|
+
nextSizes[index] = safeNextSize;
|
|
493
|
+
{
|
|
494
|
+
console.error(`Invalid size (${nextSize}) specified for Panel "${panel.current.id}" given the panel's min/max size constraints`);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// If there is additional, left over space, assign it to any panel(s) that permits it
|
|
500
|
+
// (It's not worth taking multiple additional passes to evenly distribute)
|
|
501
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
502
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
503
|
+
const panel = panelsArray[index];
|
|
504
|
+
let {
|
|
505
|
+
maxSize,
|
|
506
|
+
minSize
|
|
507
|
+
} = panel.current;
|
|
508
|
+
if (units === "pixels") {
|
|
509
|
+
minSize = minSize / groupSizePixels * 100;
|
|
510
|
+
if (maxSize != null) {
|
|
511
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSizes[index] + remainingSize));
|
|
515
|
+
if (size !== nextSizes[index]) {
|
|
516
|
+
remainingSize -= size - nextSizes[index];
|
|
517
|
+
nextSizes[index] = size;
|
|
518
|
+
|
|
519
|
+
// Fuzzy comparison to account for imprecise floating point math
|
|
520
|
+
if (Math.abs(remainingSize).toFixed(3) === "0.000") {
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// If we still have remainder, the requested layout wasn't valid and we should warn about it
|
|
528
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
529
|
+
{
|
|
530
|
+
console.error(`"Invalid panel group configuration; default panel sizes should total 100% but was ${100 - remainingSize}%`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return nextSizes;
|
|
405
534
|
}
|
|
406
535
|
|
|
407
536
|
function assert(expectedCondition, message = "Assertion failed!") {
|
|
@@ -427,6 +556,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
427
556
|
panels
|
|
428
557
|
} = committedValuesRef.current;
|
|
429
558
|
const groupElement = getPanelGroup(groupId);
|
|
559
|
+
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
430
560
|
const {
|
|
431
561
|
height,
|
|
432
562
|
width
|
|
@@ -439,23 +569,28 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
439
569
|
if (idBefore == null || idAfter == null) {
|
|
440
570
|
return () => {};
|
|
441
571
|
}
|
|
442
|
-
let
|
|
443
|
-
let
|
|
572
|
+
let currentMinSize = 0;
|
|
573
|
+
let currentMaxSize = 100;
|
|
444
574
|
let totalMinSize = 0;
|
|
445
575
|
let totalMaxSize = 0;
|
|
446
576
|
|
|
447
577
|
// A panel's effective min/max sizes also need to account for other panel's sizes.
|
|
448
578
|
panelsArray.forEach(panelData => {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
579
|
+
const {
|
|
580
|
+
id,
|
|
581
|
+
maxSize,
|
|
582
|
+
minSize
|
|
583
|
+
} = panelData.current;
|
|
584
|
+
if (id === idBefore) {
|
|
585
|
+
currentMinSize = minSize;
|
|
586
|
+
currentMaxSize = maxSize != null ? maxSize : 100;
|
|
452
587
|
} else {
|
|
453
|
-
totalMinSize +=
|
|
454
|
-
totalMaxSize +=
|
|
588
|
+
totalMinSize += minSize;
|
|
589
|
+
totalMaxSize += maxSize != null ? maxSize : 100;
|
|
455
590
|
}
|
|
456
591
|
});
|
|
457
|
-
const ariaValueMax = Math.min(
|
|
458
|
-
const ariaValueMin = Math.max(
|
|
592
|
+
const ariaValueMax = Math.min(currentMaxSize, 100 - totalMinSize);
|
|
593
|
+
const ariaValueMin = Math.max(currentMinSize, (panelsArray.length - 1) * 100 - totalMaxSize);
|
|
459
594
|
const flexGrow = getFlexGrow(panels, idBefore, sizes);
|
|
460
595
|
handle.setAttribute("aria-valuemax", "" + Math.round(ariaValueMax));
|
|
461
596
|
handle.setAttribute("aria-valuemin", "" + Math.round(ariaValueMin));
|
|
@@ -479,7 +614,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
479
614
|
} else {
|
|
480
615
|
delta = -(direction === "horizontal" ? width : height);
|
|
481
616
|
}
|
|
482
|
-
const nextSizes = adjustByDelta(event,
|
|
617
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, sizes, panelSizeBeforeCollapse.current, null);
|
|
483
618
|
if (sizes !== nextSizes) {
|
|
484
619
|
setSizes(nextSizes);
|
|
485
620
|
}
|
|
@@ -786,9 +921,6 @@ const defaultStorage = {
|
|
|
786
921
|
// * dragHandleRect, sizes:
|
|
787
922
|
// When resizing is done via mouse/touch event– some initial state is stored
|
|
788
923
|
// so that any panels that contract will also expand if drag direction is reversed.
|
|
789
|
-
// TODO
|
|
790
|
-
// Within an active drag, remember original positions to refine more easily on expand.
|
|
791
|
-
// Look at what the Chrome devtools Sources does.
|
|
792
924
|
function PanelGroupWithForwardedRef({
|
|
793
925
|
autoSaveId,
|
|
794
926
|
children = null,
|
|
@@ -800,7 +932,8 @@ function PanelGroupWithForwardedRef({
|
|
|
800
932
|
onLayout,
|
|
801
933
|
storage = defaultStorage,
|
|
802
934
|
style: styleFromProps = {},
|
|
803
|
-
tagName: Type = "div"
|
|
935
|
+
tagName: Type = "div",
|
|
936
|
+
units = "percentages"
|
|
804
937
|
}) {
|
|
805
938
|
const groupId = useUniqueId(idFromProps);
|
|
806
939
|
const [activeHandleId, setActiveHandleId] = useState(null);
|
|
@@ -813,6 +946,7 @@ function PanelGroupWithForwardedRef({
|
|
|
813
946
|
const devWarningsRef = useRef({
|
|
814
947
|
didLogDefaultSizeWarning: false,
|
|
815
948
|
didLogIdAndOrderWarning: false,
|
|
949
|
+
didLogInvalidLayoutWarning: false,
|
|
816
950
|
prevPanelIds: []
|
|
817
951
|
});
|
|
818
952
|
|
|
@@ -835,28 +969,52 @@ function PanelGroupWithForwardedRef({
|
|
|
835
969
|
// Store committed values to avoid unnecessarily re-running memoization/effects functions.
|
|
836
970
|
const committedValuesRef = useRef({
|
|
837
971
|
direction,
|
|
972
|
+
id: groupId,
|
|
838
973
|
panels,
|
|
839
|
-
sizes
|
|
974
|
+
sizes,
|
|
975
|
+
units
|
|
840
976
|
});
|
|
841
977
|
useImperativeHandle(forwardedRef, () => ({
|
|
842
|
-
|
|
978
|
+
getId: () => groupId,
|
|
979
|
+
getLayout: unitsFromParams => {
|
|
843
980
|
const {
|
|
844
|
-
sizes
|
|
981
|
+
sizes,
|
|
982
|
+
units: unitsFromProps
|
|
845
983
|
} = committedValuesRef.current;
|
|
846
|
-
|
|
984
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
985
|
+
if (units === "pixels") {
|
|
986
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
987
|
+
return sizes.map(size => size / 100 * groupSizePixels);
|
|
988
|
+
} else {
|
|
989
|
+
return sizes;
|
|
990
|
+
}
|
|
847
991
|
},
|
|
848
|
-
setLayout: sizes => {
|
|
849
|
-
const total = sizes.reduce((accumulated, current) => accumulated + current, 0);
|
|
850
|
-
assert(total === 100, "Panel sizes must add up to 100%");
|
|
992
|
+
setLayout: (sizes, unitsFromParams) => {
|
|
851
993
|
const {
|
|
852
|
-
|
|
994
|
+
id: groupId,
|
|
995
|
+
panels,
|
|
996
|
+
sizes: prevSizes,
|
|
997
|
+
units
|
|
853
998
|
} = committedValuesRef.current;
|
|
999
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1000
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1001
|
+
sizes = sizes.map(size => size / groupSizePixels * 100);
|
|
1002
|
+
}
|
|
854
1003
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
855
1004
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
856
|
-
|
|
857
|
-
|
|
1005
|
+
const nextSizes = validatePanelGroupLayout({
|
|
1006
|
+
groupId,
|
|
1007
|
+
panels,
|
|
1008
|
+
nextSizes: sizes,
|
|
1009
|
+
prevSizes,
|
|
1010
|
+
units
|
|
1011
|
+
});
|
|
1012
|
+
if (!areEqual(prevSizes, nextSizes)) {
|
|
1013
|
+
setSizes(nextSizes);
|
|
1014
|
+
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1015
|
+
}
|
|
858
1016
|
}
|
|
859
|
-
}), []);
|
|
1017
|
+
}), [groupId]);
|
|
860
1018
|
useWindowSplitterPanelGroupBehavior({
|
|
861
1019
|
committedValuesRef,
|
|
862
1020
|
groupId,
|
|
@@ -927,6 +1085,22 @@ function PanelGroupWithForwardedRef({
|
|
|
927
1085
|
}
|
|
928
1086
|
}
|
|
929
1087
|
}, [autoSaveId, panels, sizes, storage]);
|
|
1088
|
+
const getPanelSize = useCallback((id, unitsFromParams) => {
|
|
1089
|
+
const {
|
|
1090
|
+
panels,
|
|
1091
|
+
units: unitsFromProps
|
|
1092
|
+
} = committedValuesRef.current;
|
|
1093
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
1094
|
+
const index = panelsArray.findIndex(panel => panel.current.id === id);
|
|
1095
|
+
const size = sizes[index];
|
|
1096
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
1097
|
+
if (units === "pixels") {
|
|
1098
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1099
|
+
return size / 100 * groupSizePixels;
|
|
1100
|
+
} else {
|
|
1101
|
+
return size;
|
|
1102
|
+
}
|
|
1103
|
+
}, [groupId, sizes]);
|
|
930
1104
|
const getPanelStyle = useCallback((id, defaultSize) => {
|
|
931
1105
|
const {
|
|
932
1106
|
panels
|
|
@@ -965,6 +1139,10 @@ function PanelGroupWithForwardedRef({
|
|
|
965
1139
|
};
|
|
966
1140
|
}, [activeHandleId, disablePointerEventsDuringResize, sizes]);
|
|
967
1141
|
const registerPanel = useCallback((id, panelRef) => {
|
|
1142
|
+
const {
|
|
1143
|
+
units
|
|
1144
|
+
} = committedValuesRef.current;
|
|
1145
|
+
validatePanelProps(units, panelRef);
|
|
968
1146
|
setPanels(prevPanels => {
|
|
969
1147
|
if (prevPanels.has(id)) {
|
|
970
1148
|
return prevPanels;
|
|
@@ -1001,7 +1179,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1001
1179
|
}
|
|
1002
1180
|
const size = isHorizontal ? rect.width : rect.height;
|
|
1003
1181
|
const delta = movement / size * 100;
|
|
1004
|
-
|
|
1182
|
+
|
|
1183
|
+
// If a validateLayout method has been provided
|
|
1184
|
+
// it's important to use it before updating the mouse cursor
|
|
1185
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, initialDragStateRef.current);
|
|
1005
1186
|
const sizesChanged = !areEqual(prevSizes, nextSizes);
|
|
1006
1187
|
|
|
1007
1188
|
// Don't update cursor for resizes triggered by keyboard interactions.
|
|
@@ -1028,6 +1209,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1028
1209
|
}
|
|
1029
1210
|
if (sizesChanged) {
|
|
1030
1211
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1212
|
+
|
|
1213
|
+
// It's okay to bypass in this case because we already validated above
|
|
1031
1214
|
setSizes(nextSizes);
|
|
1032
1215
|
|
|
1033
1216
|
// If resize change handlers have been declared, this is the time to call them.
|
|
@@ -1081,7 +1264,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1081
1264
|
}
|
|
1082
1265
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1083
1266
|
const delta = isLastPanel ? currentSize : collapsedSize - currentSize;
|
|
1084
|
-
const nextSizes = adjustByDelta(null,
|
|
1267
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1085
1268
|
if (prevSizes !== nextSizes) {
|
|
1086
1269
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1087
1270
|
setSizes(nextSizes);
|
|
@@ -1124,7 +1307,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1124
1307
|
}
|
|
1125
1308
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1126
1309
|
const delta = isLastPanel ? collapsedSize - sizeBeforeCollapse : sizeBeforeCollapse;
|
|
1127
|
-
const nextSizes = adjustByDelta(null,
|
|
1310
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1128
1311
|
if (prevSizes !== nextSizes) {
|
|
1129
1312
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1130
1313
|
setSizes(nextSizes);
|
|
@@ -1134,21 +1317,34 @@ function PanelGroupWithForwardedRef({
|
|
|
1134
1317
|
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1135
1318
|
}
|
|
1136
1319
|
}, []);
|
|
1137
|
-
const resizePanel = useCallback((id, nextSize) => {
|
|
1320
|
+
const resizePanel = useCallback((id, nextSize, unitsFromParams) => {
|
|
1138
1321
|
const {
|
|
1322
|
+
id: groupId,
|
|
1139
1323
|
panels,
|
|
1140
|
-
sizes: prevSizes
|
|
1324
|
+
sizes: prevSizes,
|
|
1325
|
+
units
|
|
1141
1326
|
} = committedValuesRef.current;
|
|
1327
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1328
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1329
|
+
nextSize = nextSize / groupSizePixels * 100;
|
|
1330
|
+
}
|
|
1142
1331
|
const panel = panels.get(id);
|
|
1143
1332
|
if (panel == null) {
|
|
1144
1333
|
return;
|
|
1145
1334
|
}
|
|
1146
|
-
|
|
1335
|
+
let {
|
|
1147
1336
|
collapsedSize,
|
|
1148
1337
|
collapsible,
|
|
1149
1338
|
maxSize,
|
|
1150
1339
|
minSize
|
|
1151
1340
|
} = panel.current;
|
|
1341
|
+
if (units === "pixels") {
|
|
1342
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1343
|
+
minSize = minSize / groupSizePixels * 100;
|
|
1344
|
+
if (maxSize != null) {
|
|
1345
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1152
1348
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
1153
1349
|
const index = panelsArray.indexOf(panel);
|
|
1154
1350
|
if (index < 0) {
|
|
@@ -1159,7 +1355,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1159
1355
|
return;
|
|
1160
1356
|
}
|
|
1161
1357
|
if (collapsible && nextSize === collapsedSize) ; else {
|
|
1162
|
-
|
|
1358
|
+
const unsafeNextSize = nextSize;
|
|
1359
|
+
nextSize = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
1360
|
+
{
|
|
1361
|
+
if (unsafeNextSize !== nextSize) {
|
|
1362
|
+
console.error(`Invalid size (${unsafeNextSize}) specified for Panel "${panel.current.id}" given the panel's min/max size constraints`);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1163
1365
|
}
|
|
1164
1366
|
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
1165
1367
|
if (idBefore == null || idAfter == null) {
|
|
@@ -1167,7 +1369,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1167
1369
|
}
|
|
1168
1370
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1169
1371
|
const delta = isLastPanel ? currentSize - nextSize : nextSize - currentSize;
|
|
1170
|
-
const nextSizes = adjustByDelta(null,
|
|
1372
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1171
1373
|
if (prevSizes !== nextSizes) {
|
|
1172
1374
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1173
1375
|
setSizes(nextSizes);
|
|
@@ -1182,6 +1384,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1182
1384
|
collapsePanel,
|
|
1183
1385
|
direction,
|
|
1184
1386
|
expandPanel,
|
|
1387
|
+
getPanelSize,
|
|
1185
1388
|
getPanelStyle,
|
|
1186
1389
|
groupId,
|
|
1187
1390
|
registerPanel,
|
|
@@ -1203,8 +1406,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1203
1406
|
setActiveHandleId(null);
|
|
1204
1407
|
initialDragStateRef.current = null;
|
|
1205
1408
|
},
|
|
1409
|
+
units,
|
|
1206
1410
|
unregisterPanel
|
|
1207
|
-
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, unregisterPanel]);
|
|
1411
|
+
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelSize, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, units, unregisterPanel]);
|
|
1208
1412
|
const style = {
|
|
1209
1413
|
display: "flex",
|
|
1210
1414
|
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
@@ -1219,6 +1423,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1219
1423
|
"data-panel-group": "",
|
|
1220
1424
|
"data-panel-group-direction": direction,
|
|
1221
1425
|
"data-panel-group-id": groupId,
|
|
1426
|
+
"data-panel-group-units": units,
|
|
1222
1427
|
style: {
|
|
1223
1428
|
...style,
|
|
1224
1429
|
...styleFromProps
|
|
@@ -1371,3 +1576,4 @@ PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
|
1371
1576
|
exports.Panel = Panel;
|
|
1372
1577
|
exports.PanelGroup = PanelGroup;
|
|
1373
1578
|
exports.PanelResizeHandle = PanelResizeHandle;
|
|
1579
|
+
exports.getAvailableGroupSizePixels = getAvailableGroupSizePixels;
|