react-resizable-panels 0.0.57 → 0.0.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/declarations/src/Panel.d.ts +7 -3
- package/dist/declarations/src/PanelGroup.d.ts +3 -1
- package/dist/declarations/src/PanelResizeHandle.d.ts +3 -1
- package/dist/declarations/src/types.d.ts +3 -0
- package/dist/react-resizable-panels.browser.cjs.js +206 -77
- package/dist/react-resizable-panels.browser.development.cjs.js +206 -77
- package/dist/react-resizable-panels.browser.development.esm.js +206 -77
- package/dist/react-resizable-panels.browser.esm.js +206 -77
- package/dist/react-resizable-panels.cjs.js +206 -77
- package/dist/react-resizable-panels.cjs.js.map +1 -1
- package/dist/react-resizable-panels.development.cjs.js +206 -77
- package/dist/react-resizable-panels.development.esm.js +206 -77
- package/dist/react-resizable-panels.development.node.cjs.js +175 -75
- package/dist/react-resizable-panels.development.node.esm.js +175 -75
- package/dist/react-resizable-panels.esm.js +206 -77
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +175 -75
- package/dist/react-resizable-panels.node.esm.js +175 -75
- package/package.json +1 -1
- package/src/Panel.ts +8 -2
- package/src/PanelGroup.ts +89 -3
- package/src/PanelResizeHandle.ts +5 -0
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +15 -15
- package/src/types.ts +4 -0
- package/src/utils/adjustLayoutByDelta.test.ts +238 -8
- package/src/utils/adjustLayoutByDelta.ts +122 -72
- package/src/utils/resizePanel.test.ts +61 -1
- package/src/utils/resizePanel.ts +7 -1
- package/src/utils/validatePanelGroupLayout.test.ts +36 -6
|
@@ -42,6 +42,7 @@ function PanelWithForwardedRef({
|
|
|
42
42
|
collapsedSizePercentage,
|
|
43
43
|
collapsedSizePixels,
|
|
44
44
|
collapsible,
|
|
45
|
+
dataAttributes,
|
|
45
46
|
defaultSizePercentage,
|
|
46
47
|
defaultSizePixels,
|
|
47
48
|
forwardedRef,
|
|
@@ -127,6 +128,7 @@ function PanelWithForwardedRef({
|
|
|
127
128
|
...style,
|
|
128
129
|
...styleFromProps
|
|
129
130
|
},
|
|
131
|
+
...dataAttributes,
|
|
130
132
|
// CSS selectors
|
|
131
133
|
"data-panel": "",
|
|
132
134
|
"data-panel-id": panelId,
|
|
@@ -142,8 +144,6 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
|
|
|
142
144
|
PanelWithForwardedRef.displayName = "Panel";
|
|
143
145
|
Panel.displayName = "forwardRef(Panel)";
|
|
144
146
|
|
|
145
|
-
const PRECISION = 10;
|
|
146
|
-
|
|
147
147
|
function convertPixelsToPercentage(pixels, groupSizePixels) {
|
|
148
148
|
return pixels / groupSizePixels * 100;
|
|
149
149
|
}
|
|
@@ -221,6 +221,8 @@ function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, gr
|
|
|
221
221
|
};
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
const PRECISION = 10;
|
|
225
|
+
|
|
224
226
|
function fuzzyCompareNumbers(actual, expected, fractionDigits = PRECISION) {
|
|
225
227
|
actual = parseFloat(actual.toFixed(fractionDigits));
|
|
226
228
|
expected = parseFloat(expected.toFixed(fractionDigits));
|
|
@@ -264,7 +266,13 @@ function resizePanel({
|
|
|
264
266
|
if (minSizePercentage != null) {
|
|
265
267
|
if (fuzzyCompareNumbers(size, minSizePercentage) < 0) {
|
|
266
268
|
if (collapsible) {
|
|
267
|
-
|
|
269
|
+
// Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
|
|
270
|
+
const halfwayPoint = (collapsedSizePercentage + minSizePercentage) / 2;
|
|
271
|
+
if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
|
|
272
|
+
size = collapsedSizePercentage;
|
|
273
|
+
} else {
|
|
274
|
+
size = minSizePercentage;
|
|
275
|
+
}
|
|
268
276
|
} else {
|
|
269
277
|
size = minSizePercentage;
|
|
270
278
|
}
|
|
@@ -291,60 +299,123 @@ function adjustLayoutByDelta({
|
|
|
291
299
|
const nextLayout = [...prevLayout];
|
|
292
300
|
let deltaApplied = 0;
|
|
293
301
|
|
|
302
|
+
//const DEBUG = [];
|
|
303
|
+
//DEBUG.push(`adjustLayoutByDelta() ${prevLayout.join(", ")}`);
|
|
304
|
+
//DEBUG.push(` delta: ${delta}`);
|
|
305
|
+
//DEBUG.push(` pivotIndices: ${pivotIndices.join(", ")}`);
|
|
306
|
+
//DEBUG.push(` trigger: ${trigger}`);
|
|
307
|
+
//DEBUG.push("");
|
|
308
|
+
|
|
294
309
|
// A resizing panel affects the panels before or after it.
|
|
295
310
|
//
|
|
296
|
-
// A negative delta means the panel immediately after the
|
|
311
|
+
// A negative delta means the panel(s) immediately after the resize handle should grow/expand by decreasing its offset.
|
|
297
312
|
// Other panels may also need to shrink/contract (and shift) to make room, depending on the min weights.
|
|
298
313
|
//
|
|
299
|
-
// A positive delta means the panel immediately before the
|
|
300
|
-
// This is accomplished by shrinking/contracting (and shifting) one or more of the panels after the
|
|
314
|
+
// A positive delta means the panel(s) immediately before the resize handle should "expand".
|
|
315
|
+
// This is accomplished by shrinking/contracting (and shifting) one or more of the panels after the resize handle.
|
|
301
316
|
|
|
302
|
-
// First, check the panel we're pivoting around;
|
|
303
|
-
// We should only expand or contract by as much as its constraints allow
|
|
304
317
|
{
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
318
|
+
// If this is a resize triggered by a keyboard event, our logic for expanding/collapsing is different.
|
|
319
|
+
// We no longer check the halfway threshold because this may prevent the panel from expanding at all.
|
|
320
|
+
if (trigger === "keyboard") {
|
|
321
|
+
{
|
|
322
|
+
// Check if we should expand a collapsed panel
|
|
323
|
+
const index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
|
|
324
|
+
const constraints = panelConstraints[index];
|
|
325
|
+
//DEBUG.push(`edge case check 1: ${index}`);
|
|
326
|
+
//DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
|
|
327
|
+
if (constraints.collapsible) {
|
|
328
|
+
const prevSize = prevLayout[index];
|
|
329
|
+
const {
|
|
330
|
+
collapsedSizePercentage,
|
|
331
|
+
minSizePercentage
|
|
332
|
+
} = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
|
|
333
|
+
if (fuzzyNumbersEqual(prevSize, collapsedSizePercentage)) {
|
|
334
|
+
const localDelta = minSizePercentage - prevSize;
|
|
335
|
+
//DEBUG.push(` -> expand delta: ${localDelta}`);
|
|
336
|
+
|
|
337
|
+
if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
|
|
338
|
+
delta = delta < 0 ? 0 - localDelta : localDelta;
|
|
339
|
+
//DEBUG.push(` -> delta: ${delta}`);
|
|
340
|
+
}
|
|
321
341
|
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
{
|
|
346
|
+
// Check if we should collapse a panel at its minimum size
|
|
347
|
+
const index = delta < 0 ? pivotIndices[0] : pivotIndices[1];
|
|
348
|
+
const constraints = panelConstraints[index];
|
|
349
|
+
//DEBUG.push(`edge case check 2: ${index}`);
|
|
350
|
+
//DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
|
|
351
|
+
if (constraints.collapsible) {
|
|
352
|
+
const prevSize = prevLayout[index];
|
|
353
|
+
const {
|
|
354
|
+
collapsedSizePercentage,
|
|
355
|
+
minSizePercentage
|
|
356
|
+
} = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
|
|
357
|
+
if (fuzzyNumbersEqual(prevSize, minSizePercentage)) {
|
|
358
|
+
const localDelta = prevSize - collapsedSizePercentage;
|
|
359
|
+
//DEBUG.push(` -> expand delta: ${localDelta}`);
|
|
360
|
+
|
|
361
|
+
if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
|
|
362
|
+
delta = delta < 0 ? 0 - localDelta : localDelta;
|
|
363
|
+
//DEBUG.push(` -> delta: ${delta}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
322
367
|
}
|
|
323
368
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
369
|
+
//DEBUG.push("");
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
{
|
|
373
|
+
// Pre-calculate max available delta in the opposite direction of our pivot.
|
|
374
|
+
// This will be the maximum amount we're allowed to expand/contract the panels in the primary direction.
|
|
375
|
+
// If this amount is less than the requested delta, adjust the requested delta.
|
|
376
|
+
// If this amount is greater than the requested delta, that's useful information too–
|
|
377
|
+
// as an expanding panel might change from collapsed to min size.
|
|
378
|
+
|
|
379
|
+
const increment = delta < 0 ? 1 : -1;
|
|
380
|
+
let index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
|
|
381
|
+
let maxAvailableDelta = 0;
|
|
382
|
+
|
|
383
|
+
//DEBUG.push("pre calc...");
|
|
384
|
+
while (true) {
|
|
385
|
+
const prevSize = prevLayout[index];
|
|
386
|
+
const maxSafeSize = resizePanel({
|
|
387
|
+
groupSizePixels,
|
|
388
|
+
panelConstraints,
|
|
389
|
+
panelIndex: index,
|
|
390
|
+
size: 100
|
|
391
|
+
});
|
|
392
|
+
const delta = maxSafeSize - prevSize;
|
|
393
|
+
//DEBUG.push(` ${index}: ${prevSize} -> ${maxSafeSize}`);
|
|
394
|
+
|
|
395
|
+
maxAvailableDelta += delta;
|
|
396
|
+
index += increment;
|
|
397
|
+
if (index < 0 || index >= panelConstraints.length) {
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
335
400
|
}
|
|
401
|
+
|
|
402
|
+
//DEBUG.push(` -> max available delta: ${maxAvailableDelta}`);
|
|
403
|
+
const minAbsDelta = Math.min(Math.abs(delta), Math.abs(maxAvailableDelta));
|
|
404
|
+
delta = delta < 0 ? 0 - minAbsDelta : minAbsDelta;
|
|
405
|
+
//DEBUG.push(` -> adjusted delta: ${delta}`);
|
|
406
|
+
//DEBUG.push("");
|
|
336
407
|
}
|
|
337
408
|
|
|
338
|
-
// Delta added to a panel needs to be subtracted from other panels
|
|
339
|
-
// within the constraints that those panels allow
|
|
340
409
|
{
|
|
410
|
+
// Delta added to a panel needs to be subtracted from other panels (within the constraints that those panels allow).
|
|
411
|
+
|
|
341
412
|
const pivotIndex = delta < 0 ? pivotIndices[0] : pivotIndices[1];
|
|
342
413
|
let index = pivotIndex;
|
|
343
414
|
while (index >= 0 && index < panelConstraints.length) {
|
|
344
415
|
const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
|
|
345
416
|
const prevSize = prevLayout[index];
|
|
346
417
|
const unsafeSize = prevSize - deltaRemaining;
|
|
347
|
-
|
|
418
|
+
const safeSize = resizePanel({
|
|
348
419
|
groupSizePixels,
|
|
349
420
|
panelConstraints,
|
|
350
421
|
panelIndex: index,
|
|
@@ -366,13 +437,18 @@ function adjustLayoutByDelta({
|
|
|
366
437
|
}
|
|
367
438
|
}
|
|
368
439
|
}
|
|
440
|
+
//DEBUG.push(`after 1: ${nextLayout.join(", ")}`);
|
|
441
|
+
//DEBUG.push(` deltaApplied: ${deltaApplied}`);
|
|
442
|
+
//DEBUG.push("");
|
|
369
443
|
|
|
370
444
|
// If we were unable to resize any of the panels panels, return the previous state.
|
|
371
445
|
// This will essentially bailout and ignore e.g. drags past a panel's boundaries
|
|
372
446
|
if (fuzzyNumbersEqual(deltaApplied, 0)) {
|
|
447
|
+
//console.log(DEBUG.join("\n"));
|
|
373
448
|
return prevLayout;
|
|
374
449
|
}
|
|
375
450
|
{
|
|
451
|
+
// Now distribute the applied delta to the panels in the other direction
|
|
376
452
|
const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
|
|
377
453
|
const unsafeSize = prevLayout[pivotIndex] + deltaApplied;
|
|
378
454
|
const safeSize = resizePanel({
|
|
@@ -412,29 +488,21 @@ function adjustLayoutByDelta({
|
|
|
412
488
|
index++;
|
|
413
489
|
}
|
|
414
490
|
}
|
|
415
|
-
|
|
416
|
-
// If we can't redistribute, this layout is invalid;
|
|
417
|
-
// There may be an incremental layout that is valid though
|
|
418
|
-
if (!fuzzyNumbersEqual(deltaRemaining, 0)) {
|
|
419
|
-
try {
|
|
420
|
-
return adjustLayoutByDelta({
|
|
421
|
-
delta: delta < 0 ? delta + 1 : delta - 1,
|
|
422
|
-
groupSizePixels,
|
|
423
|
-
layout: prevLayout,
|
|
424
|
-
panelConstraints,
|
|
425
|
-
pivotIndices,
|
|
426
|
-
trigger
|
|
427
|
-
});
|
|
428
|
-
} catch (error) {
|
|
429
|
-
if (error instanceof RangeError) {
|
|
430
|
-
console.error(`Could not apply delta ${delta} to layout`);
|
|
431
|
-
return prevLayout;
|
|
432
|
-
}
|
|
433
|
-
} finally {
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
491
|
}
|
|
437
492
|
}
|
|
493
|
+
//DEBUG.push(`after 2: ${nextLayout.join(", ")}`);
|
|
494
|
+
//DEBUG.push(` deltaApplied: ${deltaApplied}`);
|
|
495
|
+
//DEBUG.push("");
|
|
496
|
+
|
|
497
|
+
const totalSize = nextLayout.reduce((total, size) => size + total, 0);
|
|
498
|
+
deltaApplied = 100 - totalSize;
|
|
499
|
+
//DEBUG.push(`total size: ${totalSize}`);
|
|
500
|
+
//DEBUG.push(` deltaApplied: ${deltaApplied}`);
|
|
501
|
+
//console.log(DEBUG.join("\n"));
|
|
502
|
+
|
|
503
|
+
if (!fuzzyNumbersEqual(totalSize, 100)) {
|
|
504
|
+
return prevLayout;
|
|
505
|
+
}
|
|
438
506
|
return nextLayout;
|
|
439
507
|
}
|
|
440
508
|
|
|
@@ -548,15 +616,10 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
548
616
|
});
|
|
549
617
|
useEffect(() => {
|
|
550
618
|
const {
|
|
551
|
-
direction,
|
|
552
619
|
panelDataArray
|
|
553
620
|
} = committedValuesRef.current;
|
|
554
621
|
const groupElement = getPanelGroupElement(groupId);
|
|
555
622
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
556
|
-
const {
|
|
557
|
-
height,
|
|
558
|
-
width
|
|
559
|
-
} = groupElement.getBoundingClientRect();
|
|
560
623
|
const handles = getResizeHandleElementsForGroup(groupId);
|
|
561
624
|
const cleanupFunctions = handles.map(handle => {
|
|
562
625
|
const handleId = handle.getAttribute("data-panel-resize-handle-id");
|
|
@@ -576,21 +639,19 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
576
639
|
if (index >= 0) {
|
|
577
640
|
const panelData = panelDataArray[index];
|
|
578
641
|
const size = layout[index];
|
|
579
|
-
if (size != null) {
|
|
580
|
-
var _getPercentageSizeFro;
|
|
642
|
+
if (size != null && panelData.constraints.collapsible) {
|
|
643
|
+
var _getPercentageSizeFro, _getPercentageSizeFro2;
|
|
581
644
|
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
582
|
-
const
|
|
645
|
+
const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
|
|
646
|
+
sizePercentage: panelData.constraints.collapsedSizePercentage,
|
|
647
|
+
sizePixels: panelData.constraints.collapsedSizePixels
|
|
648
|
+
}, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
|
|
649
|
+
const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
|
|
583
650
|
sizePercentage: panelData.constraints.minSizePercentage,
|
|
584
651
|
sizePixels: panelData.constraints.minSizePixels
|
|
585
|
-
}, groupSizePixels)) !== null &&
|
|
586
|
-
let delta = 0;
|
|
587
|
-
if (size.toPrecision(PRECISION) <= minSize.toPrecision(PRECISION)) {
|
|
588
|
-
delta = direction === "horizontal" ? width : height;
|
|
589
|
-
} else {
|
|
590
|
-
delta = -(direction === "horizontal" ? width : height);
|
|
591
|
-
}
|
|
652
|
+
}, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
|
|
592
653
|
const nextLayout = adjustLayoutByDelta({
|
|
593
|
-
delta,
|
|
654
|
+
delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
|
|
594
655
|
groupSizePixels,
|
|
595
656
|
layout,
|
|
596
657
|
panelConstraints: panelDataArray.map(panelData => panelData.constraints),
|
|
@@ -998,6 +1059,7 @@ function PanelGroupWithForwardedRef({
|
|
|
998
1059
|
autoSaveId,
|
|
999
1060
|
children,
|
|
1000
1061
|
className: classNameFromProps = "",
|
|
1062
|
+
dataAttributes,
|
|
1001
1063
|
direction,
|
|
1002
1064
|
forwardedRef,
|
|
1003
1065
|
id: idFromProps,
|
|
@@ -1015,6 +1077,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1015
1077
|
const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
|
|
1016
1078
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
1017
1079
|
const prevDeltaRef = useRef(0);
|
|
1080
|
+
const [imperativeApiQueue, setImperativeApiQueue] = useState([]);
|
|
1018
1081
|
const committedValuesRef = useRef({
|
|
1019
1082
|
direction,
|
|
1020
1083
|
dragState,
|
|
@@ -1104,6 +1167,17 @@ function PanelGroupWithForwardedRef({
|
|
|
1104
1167
|
onLayout,
|
|
1105
1168
|
panelDataArray
|
|
1106
1169
|
} = committedValuesRef.current;
|
|
1170
|
+
|
|
1171
|
+
// See issues/211
|
|
1172
|
+
if (panelDataArray.find(({
|
|
1173
|
+
id
|
|
1174
|
+
}) => id === panelData.id) == null) {
|
|
1175
|
+
setImperativeApiQueue(prev => [...prev, {
|
|
1176
|
+
panelData,
|
|
1177
|
+
type: "collapse"
|
|
1178
|
+
}]);
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1107
1181
|
if (panelData.constraints.collapsible) {
|
|
1108
1182
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1109
1183
|
const {
|
|
@@ -1147,6 +1221,17 @@ function PanelGroupWithForwardedRef({
|
|
|
1147
1221
|
onLayout,
|
|
1148
1222
|
panelDataArray
|
|
1149
1223
|
} = committedValuesRef.current;
|
|
1224
|
+
|
|
1225
|
+
// See issues/211
|
|
1226
|
+
if (panelDataArray.find(({
|
|
1227
|
+
id
|
|
1228
|
+
}) => id === panelData.id) == null) {
|
|
1229
|
+
setImperativeApiQueue(prev => [...prev, {
|
|
1230
|
+
panelData,
|
|
1231
|
+
type: "expand"
|
|
1232
|
+
}]);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1150
1235
|
if (panelData.constraints.collapsible) {
|
|
1151
1236
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1152
1237
|
const {
|
|
@@ -1342,6 +1427,18 @@ function PanelGroupWithForwardedRef({
|
|
|
1342
1427
|
onLayout,
|
|
1343
1428
|
panelDataArray
|
|
1344
1429
|
} = committedValuesRef.current;
|
|
1430
|
+
|
|
1431
|
+
// See issues/211
|
|
1432
|
+
if (panelDataArray.find(({
|
|
1433
|
+
id
|
|
1434
|
+
}) => id === panelData.id) == null) {
|
|
1435
|
+
setImperativeApiQueue(prev => [...prev, {
|
|
1436
|
+
panelData,
|
|
1437
|
+
mixedSizes,
|
|
1438
|
+
type: "resize"
|
|
1439
|
+
}]);
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1345
1442
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1346
1443
|
const {
|
|
1347
1444
|
groupSizePixels,
|
|
@@ -1432,6 +1529,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1432
1529
|
...style,
|
|
1433
1530
|
...styleFromProps
|
|
1434
1531
|
},
|
|
1532
|
+
...dataAttributes,
|
|
1435
1533
|
// CSS selectors
|
|
1436
1534
|
"data-panel-group": "",
|
|
1437
1535
|
"data-panel-group-direction": direction,
|
|
@@ -1519,6 +1617,7 @@ function useWindowSplitterResizeHandlerBehavior({
|
|
|
1519
1617
|
function PanelResizeHandle({
|
|
1520
1618
|
children = null,
|
|
1521
1619
|
className: classNameFromProps = "",
|
|
1620
|
+
dataAttributes,
|
|
1522
1621
|
disabled = false,
|
|
1523
1622
|
id: idFromProps = null,
|
|
1524
1623
|
onDragging,
|
|
@@ -1641,6 +1740,7 @@ function PanelResizeHandle({
|
|
|
1641
1740
|
...styleFromProps
|
|
1642
1741
|
},
|
|
1643
1742
|
tabIndex: 0,
|
|
1743
|
+
...dataAttributes,
|
|
1644
1744
|
// CSS selectors
|
|
1645
1745
|
"data-panel-group-direction": direction,
|
|
1646
1746
|
"data-panel-group-id": groupId,
|
package/package.json
CHANGED
package/src/Panel.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { isDevelopment } from "#is-development";
|
|
|
3
3
|
import { PanelGroupContext } from "./PanelGroupContext";
|
|
4
4
|
import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
|
|
5
5
|
import useUniqueId from "./hooks/useUniqueId";
|
|
6
|
-
import { MixedSizes } from "./types";
|
|
6
|
+
import { DataAttributes, MixedSizes } from "./types";
|
|
7
7
|
import {
|
|
8
8
|
ElementType,
|
|
9
9
|
ForwardedRef,
|
|
@@ -19,7 +19,7 @@ export type PanelOnCollapse = () => void;
|
|
|
19
19
|
export type PanelOnExpand = () => void;
|
|
20
20
|
export type PanelOnResize = (
|
|
21
21
|
mixedSizes: MixedSizes,
|
|
22
|
-
prevMixedSizes: MixedSizes
|
|
22
|
+
prevMixedSizes: MixedSizes | undefined
|
|
23
23
|
) => void;
|
|
24
24
|
|
|
25
25
|
export type PanelCallbacks = {
|
|
@@ -53,6 +53,8 @@ export type ImperativePanelHandle = {
|
|
|
53
53
|
expand: () => void;
|
|
54
54
|
getId(): string;
|
|
55
55
|
getSize(): MixedSizes;
|
|
56
|
+
isCollapsed: () => boolean;
|
|
57
|
+
isExpanded: () => boolean;
|
|
56
58
|
resize: (size: Partial<MixedSizes>) => void;
|
|
57
59
|
};
|
|
58
60
|
|
|
@@ -61,6 +63,7 @@ export type PanelProps = PropsWithChildren<{
|
|
|
61
63
|
collapsedSizePercentage?: number | undefined;
|
|
62
64
|
collapsedSizePixels?: number | undefined;
|
|
63
65
|
collapsible?: boolean | undefined;
|
|
66
|
+
dataAttributes?: DataAttributes;
|
|
64
67
|
defaultSizePercentage?: number | undefined;
|
|
65
68
|
defaultSizePixels?: number | undefined;
|
|
66
69
|
id?: string;
|
|
@@ -82,6 +85,7 @@ export function PanelWithForwardedRef({
|
|
|
82
85
|
collapsedSizePercentage,
|
|
83
86
|
collapsedSizePixels,
|
|
84
87
|
collapsible,
|
|
88
|
+
dataAttributes,
|
|
85
89
|
defaultSizePercentage,
|
|
86
90
|
defaultSizePixels,
|
|
87
91
|
forwardedRef,
|
|
@@ -241,6 +245,8 @@ export function PanelWithForwardedRef({
|
|
|
241
245
|
...styleFromProps,
|
|
242
246
|
},
|
|
243
247
|
|
|
248
|
+
...dataAttributes,
|
|
249
|
+
|
|
244
250
|
// CSS selectors
|
|
245
251
|
"data-panel": "",
|
|
246
252
|
"data-panel-id": panelId,
|
package/src/PanelGroup.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { DragState, PanelGroupContext, ResizeEvent } from "./PanelGroupContext";
|
|
|
4
4
|
import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
|
|
5
5
|
import useUniqueId from "./hooks/useUniqueId";
|
|
6
6
|
import { useWindowSplitterPanelGroupBehavior } from "./hooks/useWindowSplitterPanelGroupBehavior";
|
|
7
|
-
import { Direction, MixedSizes } from "./types";
|
|
7
|
+
import { DataAttributes, Direction, MixedSizes } from "./types";
|
|
8
8
|
import { adjustLayoutByDelta } from "./utils/adjustLayoutByDelta";
|
|
9
9
|
import { areEqual } from "./utils/arrays";
|
|
10
10
|
import { calculateDeltaPercentage } from "./utils/calculateDeltaPercentage";
|
|
@@ -72,6 +72,7 @@ const defaultStorage: PanelGroupStorage = {
|
|
|
72
72
|
export type PanelGroupProps = PropsWithChildren<{
|
|
73
73
|
autoSaveId?: string;
|
|
74
74
|
className?: string;
|
|
75
|
+
dataAttributes?: DataAttributes;
|
|
75
76
|
direction: Direction;
|
|
76
77
|
id?: string | null;
|
|
77
78
|
keyboardResizeByPercentage?: number | null;
|
|
@@ -82,6 +83,12 @@ export type PanelGroupProps = PropsWithChildren<{
|
|
|
82
83
|
tagName?: ElementType;
|
|
83
84
|
}>;
|
|
84
85
|
|
|
86
|
+
type ImperativeApiQueue = {
|
|
87
|
+
type: "collapse" | "expand" | "resize";
|
|
88
|
+
mixedSizes?: Partial<MixedSizes>;
|
|
89
|
+
panelData: PanelData;
|
|
90
|
+
};
|
|
91
|
+
|
|
85
92
|
const debounceMap: {
|
|
86
93
|
[key: string]: typeof savePanelGroupLayout;
|
|
87
94
|
} = {};
|
|
@@ -90,6 +97,7 @@ function PanelGroupWithForwardedRef({
|
|
|
90
97
|
autoSaveId,
|
|
91
98
|
children,
|
|
92
99
|
className: classNameFromProps = "",
|
|
100
|
+
dataAttributes,
|
|
93
101
|
direction,
|
|
94
102
|
forwardedRef,
|
|
95
103
|
id: idFromProps,
|
|
@@ -114,6 +122,10 @@ function PanelGroupWithForwardedRef({
|
|
|
114
122
|
const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
|
|
115
123
|
const prevDeltaRef = useRef<number>(0);
|
|
116
124
|
|
|
125
|
+
const [imperativeApiQueue, setImperativeApiQueue] = useState<
|
|
126
|
+
ImperativeApiQueue[]
|
|
127
|
+
>([]);
|
|
128
|
+
|
|
117
129
|
const committedValuesRef = useRef<{
|
|
118
130
|
direction: Direction;
|
|
119
131
|
dragState: DragState | null;
|
|
@@ -267,8 +279,14 @@ function PanelGroupWithForwardedRef({
|
|
|
267
279
|
|
|
268
280
|
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
269
281
|
if (groupSizePixels <= 0) {
|
|
270
|
-
|
|
271
|
-
|
|
282
|
+
if (
|
|
283
|
+
shouldMonitorPixelBasedConstraints(
|
|
284
|
+
panelDataArray.map(({ constraints }) => constraints)
|
|
285
|
+
)
|
|
286
|
+
) {
|
|
287
|
+
// Wait until the group has rendered a non-zero size before computing layout.
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
272
290
|
}
|
|
273
291
|
|
|
274
292
|
if (unsafeLayout == null) {
|
|
@@ -440,6 +458,18 @@ function PanelGroupWithForwardedRef({
|
|
|
440
458
|
panelDataArray,
|
|
441
459
|
} = committedValuesRef.current;
|
|
442
460
|
|
|
461
|
+
// See issues/211
|
|
462
|
+
if (panelDataArray.find(({ id }) => id === panelData.id) == null) {
|
|
463
|
+
setImperativeApiQueue((prev) => [
|
|
464
|
+
...prev,
|
|
465
|
+
{
|
|
466
|
+
panelData,
|
|
467
|
+
type: "collapse",
|
|
468
|
+
},
|
|
469
|
+
]);
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
443
473
|
if (panelData.constraints.collapsible) {
|
|
444
474
|
const panelConstraintsArray = panelDataArray.map(
|
|
445
475
|
(panelData) => panelData.constraints
|
|
@@ -512,6 +542,18 @@ function PanelGroupWithForwardedRef({
|
|
|
512
542
|
panelDataArray,
|
|
513
543
|
} = committedValuesRef.current;
|
|
514
544
|
|
|
545
|
+
// See issues/211
|
|
546
|
+
if (panelDataArray.find(({ id }) => id === panelData.id) == null) {
|
|
547
|
+
setImperativeApiQueue((prev) => [
|
|
548
|
+
...prev,
|
|
549
|
+
{
|
|
550
|
+
panelData,
|
|
551
|
+
type: "expand",
|
|
552
|
+
},
|
|
553
|
+
]);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
515
557
|
if (panelData.constraints.collapsible) {
|
|
516
558
|
const panelConstraintsArray = panelDataArray.map(
|
|
517
559
|
(panelData) => panelData.constraints
|
|
@@ -778,6 +820,19 @@ function PanelGroupWithForwardedRef({
|
|
|
778
820
|
panelDataArray,
|
|
779
821
|
} = committedValuesRef.current;
|
|
780
822
|
|
|
823
|
+
// See issues/211
|
|
824
|
+
if (panelDataArray.find(({ id }) => id === panelData.id) == null) {
|
|
825
|
+
setImperativeApiQueue((prev) => [
|
|
826
|
+
...prev,
|
|
827
|
+
{
|
|
828
|
+
panelData,
|
|
829
|
+
mixedSizes,
|
|
830
|
+
type: "resize",
|
|
831
|
+
},
|
|
832
|
+
]);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
|
|
781
836
|
const panelConstraintsArray = panelDataArray.map(
|
|
782
837
|
(panelData) => panelData.constraints
|
|
783
838
|
);
|
|
@@ -871,6 +926,35 @@ function PanelGroupWithForwardedRef({
|
|
|
871
926
|
});
|
|
872
927
|
}, []);
|
|
873
928
|
|
|
929
|
+
// Handle imperative API calls that were made before panels were registered
|
|
930
|
+
useIsomorphicLayoutEffect(() => {
|
|
931
|
+
const queue = imperativeApiQueue;
|
|
932
|
+
while (queue.length > 0) {
|
|
933
|
+
const current = queue.shift()!;
|
|
934
|
+
switch (current.type) {
|
|
935
|
+
case "collapse": {
|
|
936
|
+
collapsePanel(current.panelData);
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
939
|
+
case "expand": {
|
|
940
|
+
expandPanel(current.panelData);
|
|
941
|
+
break;
|
|
942
|
+
}
|
|
943
|
+
case "resize": {
|
|
944
|
+
resizePanel(current.panelData, current.mixedSizes!);
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}, [
|
|
950
|
+
collapsePanel,
|
|
951
|
+
expandPanel,
|
|
952
|
+
imperativeApiQueue,
|
|
953
|
+
layout,
|
|
954
|
+
panelDataArray,
|
|
955
|
+
resizePanel,
|
|
956
|
+
]);
|
|
957
|
+
|
|
874
958
|
const context = useMemo(
|
|
875
959
|
() => ({
|
|
876
960
|
collapsePanel,
|
|
@@ -927,6 +1011,8 @@ function PanelGroupWithForwardedRef({
|
|
|
927
1011
|
...styleFromProps,
|
|
928
1012
|
},
|
|
929
1013
|
|
|
1014
|
+
...dataAttributes,
|
|
1015
|
+
|
|
930
1016
|
// CSS selectors
|
|
931
1017
|
"data-panel-group": "",
|
|
932
1018
|
"data-panel-group-direction": direction,
|
package/src/PanelResizeHandle.ts
CHANGED
|
@@ -20,12 +20,14 @@ import {
|
|
|
20
20
|
ResizeHandler,
|
|
21
21
|
} from "./PanelGroupContext";
|
|
22
22
|
import { getCursorStyle } from "./utils/cursor";
|
|
23
|
+
import { DataAttributes } from "./types";
|
|
23
24
|
|
|
24
25
|
export type PanelResizeHandleOnDragging = (isDragging: boolean) => void;
|
|
25
26
|
|
|
26
27
|
export type PanelResizeHandleProps = {
|
|
27
28
|
children?: ReactNode;
|
|
28
29
|
className?: string;
|
|
30
|
+
dataAttributes?: DataAttributes;
|
|
29
31
|
disabled?: boolean;
|
|
30
32
|
id?: string | null;
|
|
31
33
|
onDragging?: PanelResizeHandleOnDragging;
|
|
@@ -36,6 +38,7 @@ export type PanelResizeHandleProps = {
|
|
|
36
38
|
export function PanelResizeHandle({
|
|
37
39
|
children = null,
|
|
38
40
|
className: classNameFromProps = "",
|
|
41
|
+
dataAttributes,
|
|
39
42
|
disabled = false,
|
|
40
43
|
id: idFromProps = null,
|
|
41
44
|
onDragging,
|
|
@@ -180,6 +183,8 @@ export function PanelResizeHandle({
|
|
|
180
183
|
},
|
|
181
184
|
tabIndex: 0,
|
|
182
185
|
|
|
186
|
+
...dataAttributes,
|
|
187
|
+
|
|
183
188
|
// CSS selectors
|
|
184
189
|
"data-panel-group-direction": direction,
|
|
185
190
|
"data-panel-group-id": groupId,
|