react-resizable-panels 0.0.53 → 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 +33 -0
- package/dist/declarations/src/Panel.d.ts +6 -5
- package/dist/declarations/src/PanelGroup.d.ts +8 -4
- package/dist/declarations/src/PanelResizeHandle.d.ts +5 -2
- package/dist/declarations/src/index.d.ts +9 -8
- package/dist/declarations/src/types.d.ts +4 -2
- package/dist/declarations/src/utils/group.d.ts +29 -0
- package/dist/react-resizable-panels.browser.cjs.js +1709 -0
- package/dist/react-resizable-panels.browser.cjs.mjs +6 -0
- package/dist/react-resizable-panels.browser.development.cjs.js +1764 -0
- package/dist/react-resizable-panels.browser.development.cjs.mjs +6 -0
- package/dist/react-resizable-panels.browser.development.esm.js +1737 -0
- package/dist/react-resizable-panels.browser.esm.js +1682 -0
- package/dist/react-resizable-panels.cjs.js +395 -126
- 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 +452 -135
- package/dist/react-resizable-panels.development.cjs.mjs +6 -0
- package/dist/react-resizable-panels.development.esm.js +452 -136
- package/dist/react-resizable-panels.development.node.cjs.js +1579 -0
- package/dist/react-resizable-panels.development.node.cjs.mjs +6 -0
- package/dist/react-resizable-panels.development.node.esm.js +1552 -0
- package/dist/react-resizable-panels.esm.js +395 -127
- package/dist/react-resizable-panels.esm.js.map +1 -0
- package/dist/react-resizable-panels.node.cjs.js +1523 -0
- package/dist/react-resizable-panels.node.cjs.mjs +6 -0
- package/dist/react-resizable-panels.node.esm.js +1496 -0
- package/package.json +26 -1
- package/src/Panel.ts +37 -37
- package/src/PanelContexts.ts +5 -6
- package/src/PanelGroup.ts +269 -121
- package/src/PanelResizeHandle.ts +1 -4
- package/src/env-conditions/browser.ts +1 -0
- package/src/env-conditions/node.ts +1 -0
- package/src/env-conditions/unknown.ts +1 -0
- package/src/hooks/useIsomorphicEffect.ts +2 -9
- package/src/hooks/useWindowSplitterBehavior.ts +14 -11
- package/src/index.ts +11 -3
- package/src/types.ts +3 -1
- package/src/utils/group.ts +327 -28
- package/src/utils/ssr.ts +0 -7
|
@@ -24,6 +24,8 @@ function _interopNamespace(e) {
|
|
|
24
24
|
|
|
25
25
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
26
26
|
|
|
27
|
+
const isBrowser = typeof window !== "undefined";
|
|
28
|
+
|
|
27
29
|
// This module exists to work around Webpack issue https://github.com/webpack/webpack/issues/14814
|
|
28
30
|
|
|
29
31
|
// eslint-disable-next-line no-restricted-imports
|
|
@@ -45,8 +47,7 @@ const {
|
|
|
45
47
|
// `toString()` prevents bundlers from trying to `import { useId } from 'react'`
|
|
46
48
|
const useId = React__namespace["useId".toString()];
|
|
47
49
|
|
|
48
|
-
const
|
|
49
|
-
const useIsomorphicLayoutEffect = canUseEffectHooks ? useLayoutEffect : () => {};
|
|
50
|
+
const useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : () => {};
|
|
50
51
|
|
|
51
52
|
const wrappedUseId = typeof useId === "function" ? useId : () => null;
|
|
52
53
|
let counter = 0;
|
|
@@ -60,10 +61,6 @@ function useUniqueId(idFromParams = null) {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
const PanelGroupContext = createContext(null);
|
|
63
|
-
|
|
64
|
-
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
65
|
-
// Casting to :any is required to avoid corrupting the generated TypeScript types.
|
|
66
|
-
// See github.com/parcel-bundler/parcel/issues/8724
|
|
67
64
|
PanelGroupContext.displayName = "PanelGroupContext";
|
|
68
65
|
|
|
69
66
|
function PanelWithForwardedRef({
|
|
@@ -74,8 +71,8 @@ function PanelWithForwardedRef({
|
|
|
74
71
|
defaultSize = null,
|
|
75
72
|
forwardedRef,
|
|
76
73
|
id: idFromProps = null,
|
|
77
|
-
maxSize =
|
|
78
|
-
minSize
|
|
74
|
+
maxSize = null,
|
|
75
|
+
minSize,
|
|
79
76
|
onCollapse = null,
|
|
80
77
|
onResize = null,
|
|
81
78
|
order = null,
|
|
@@ -90,11 +87,22 @@ function PanelWithForwardedRef({
|
|
|
90
87
|
const {
|
|
91
88
|
collapsePanel,
|
|
92
89
|
expandPanel,
|
|
90
|
+
getPanelSize,
|
|
93
91
|
getPanelStyle,
|
|
94
92
|
registerPanel,
|
|
95
93
|
resizePanel,
|
|
94
|
+
units,
|
|
96
95
|
unregisterPanel
|
|
97
96
|
} = context;
|
|
97
|
+
if (minSize == null) {
|
|
98
|
+
if (units === "percentages") {
|
|
99
|
+
// Mimics legacy default value for percentage based panel groups
|
|
100
|
+
minSize = 10;
|
|
101
|
+
} else {
|
|
102
|
+
// There is no meaningful minimum pixel default we can provide
|
|
103
|
+
minSize = 0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
98
106
|
|
|
99
107
|
// Use a ref to guard against users passing inline props
|
|
100
108
|
const callbacksRef = useRef({
|
|
@@ -105,22 +113,6 @@ function PanelWithForwardedRef({
|
|
|
105
113
|
callbacksRef.current.onCollapse = onCollapse;
|
|
106
114
|
callbacksRef.current.onResize = onResize;
|
|
107
115
|
});
|
|
108
|
-
|
|
109
|
-
// Basic props validation
|
|
110
|
-
if (minSize < 0 || minSize > 100) {
|
|
111
|
-
throw Error(`Panel minSize must be between 0 and 100, but was ${minSize}`);
|
|
112
|
-
} else if (maxSize < 0 || maxSize > 100) {
|
|
113
|
-
throw Error(`Panel maxSize must be between 0 and 100, but was ${maxSize}`);
|
|
114
|
-
} else {
|
|
115
|
-
if (defaultSize !== null) {
|
|
116
|
-
if (defaultSize < 0 || defaultSize > 100) {
|
|
117
|
-
throw Error(`Panel defaultSize must be between 0 and 100, but was ${defaultSize}`);
|
|
118
|
-
} else if (minSize > defaultSize && !collapsible) {
|
|
119
|
-
console.error(`Panel minSize ${minSize} cannot be greater than defaultSize ${defaultSize}`);
|
|
120
|
-
defaultSize = minSize;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
116
|
const style = getPanelStyle(panelId, defaultSize);
|
|
125
117
|
const committedValuesRef = useRef({
|
|
126
118
|
size: parseSizeFromStyle(style)
|
|
@@ -131,6 +123,7 @@ function PanelWithForwardedRef({
|
|
|
131
123
|
collapsible,
|
|
132
124
|
defaultSize,
|
|
133
125
|
id: panelId,
|
|
126
|
+
idWasAutoGenerated: idFromProps == null,
|
|
134
127
|
maxSize,
|
|
135
128
|
minSize,
|
|
136
129
|
order
|
|
@@ -142,6 +135,7 @@ function PanelWithForwardedRef({
|
|
|
142
135
|
panelDataRef.current.collapsible = collapsible;
|
|
143
136
|
panelDataRef.current.defaultSize = defaultSize;
|
|
144
137
|
panelDataRef.current.id = panelId;
|
|
138
|
+
panelDataRef.current.idWasAutoGenerated = idFromProps == null;
|
|
145
139
|
panelDataRef.current.maxSize = maxSize;
|
|
146
140
|
panelDataRef.current.minSize = minSize;
|
|
147
141
|
panelDataRef.current.order = order;
|
|
@@ -158,11 +152,14 @@ function PanelWithForwardedRef({
|
|
|
158
152
|
getCollapsed() {
|
|
159
153
|
return committedValuesRef.current.size === 0;
|
|
160
154
|
},
|
|
161
|
-
|
|
162
|
-
return
|
|
155
|
+
getId() {
|
|
156
|
+
return panelId;
|
|
163
157
|
},
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
getSize(units) {
|
|
159
|
+
return getPanelSize(panelId, units);
|
|
160
|
+
},
|
|
161
|
+
resize: (percentage, units) => resizePanel(panelId, percentage, units)
|
|
162
|
+
}), [collapsePanel, expandPanel, getPanelSize, panelId, resizePanel]);
|
|
166
163
|
return createElement(Type, {
|
|
167
164
|
children,
|
|
168
165
|
className: classNameFromProps,
|
|
@@ -181,10 +178,6 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
|
|
|
181
178
|
...props,
|
|
182
179
|
forwardedRef: ref
|
|
183
180
|
}));
|
|
184
|
-
|
|
185
|
-
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
186
|
-
// Casting to :any is required to avoid corrupting the generated TypeScript types.
|
|
187
|
-
// See github.com/parcel-bundler/parcel/issues/8724
|
|
188
181
|
PanelWithForwardedRef.displayName = "Panel";
|
|
189
182
|
Panel.displayName = "forwardRef(Panel)";
|
|
190
183
|
|
|
@@ -202,7 +195,13 @@ function parseSizeFromStyle(style) {
|
|
|
202
195
|
|
|
203
196
|
const PRECISION = 10;
|
|
204
197
|
|
|
205
|
-
function adjustByDelta(event,
|
|
198
|
+
function adjustByDelta(event, committedValues, idBefore, idAfter, deltaPixels, prevSizes, panelSizeBeforeCollapse, initialDragState) {
|
|
199
|
+
const {
|
|
200
|
+
id: groupId,
|
|
201
|
+
panels,
|
|
202
|
+
units
|
|
203
|
+
} = committedValues;
|
|
204
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
206
205
|
const {
|
|
207
206
|
sizes: initialSizes
|
|
208
207
|
} = initialDragState || {};
|
|
@@ -210,9 +209,6 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
210
209
|
// If we're resizing by mouse or touch, use the initial sizes as a base.
|
|
211
210
|
// This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
|
|
212
211
|
const baseSizes = initialSizes || prevSizes;
|
|
213
|
-
if (delta === 0) {
|
|
214
|
-
return baseSizes;
|
|
215
|
-
}
|
|
216
212
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
217
213
|
const nextSizes = baseSizes.concat();
|
|
218
214
|
let deltaApplied = 0;
|
|
@@ -227,11 +223,11 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
227
223
|
|
|
228
224
|
// Max-bounds check the panel being expanded first.
|
|
229
225
|
{
|
|
230
|
-
const pivotId =
|
|
226
|
+
const pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
231
227
|
const index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
232
228
|
const panel = panelsArray[index];
|
|
233
229
|
const baseSize = baseSizes[index];
|
|
234
|
-
const nextSize = safeResizePanel(panel, Math.abs(
|
|
230
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize + Math.abs(deltaPixels), event);
|
|
235
231
|
if (baseSize === nextSize) {
|
|
236
232
|
// If there's no room for the pivot panel to grow, we can ignore this drag update.
|
|
237
233
|
return baseSizes;
|
|
@@ -239,29 +235,29 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
239
235
|
if (nextSize === 0 && baseSize > 0) {
|
|
240
236
|
panelSizeBeforeCollapse.set(pivotId, baseSize);
|
|
241
237
|
}
|
|
242
|
-
|
|
238
|
+
deltaPixels = deltaPixels < 0 ? baseSize - nextSize : nextSize - baseSize;
|
|
243
239
|
}
|
|
244
240
|
}
|
|
245
|
-
let pivotId =
|
|
241
|
+
let pivotId = deltaPixels < 0 ? idBefore : idAfter;
|
|
246
242
|
let index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
247
243
|
while (true) {
|
|
248
244
|
const panel = panelsArray[index];
|
|
249
245
|
const baseSize = baseSizes[index];
|
|
250
|
-
const deltaRemaining = Math.abs(
|
|
251
|
-
const nextSize = safeResizePanel(panel,
|
|
246
|
+
const deltaRemaining = Math.abs(deltaPixels) - Math.abs(deltaApplied);
|
|
247
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize - deltaRemaining, event);
|
|
252
248
|
if (baseSize !== nextSize) {
|
|
253
249
|
if (nextSize === 0 && baseSize > 0) {
|
|
254
250
|
panelSizeBeforeCollapse.set(panel.current.id, baseSize);
|
|
255
251
|
}
|
|
256
252
|
deltaApplied += baseSize - nextSize;
|
|
257
253
|
nextSizes[index] = nextSize;
|
|
258
|
-
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(
|
|
254
|
+
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(deltaPixels).toPrecision(PRECISION), undefined, {
|
|
259
255
|
numeric: true
|
|
260
256
|
}) >= 0) {
|
|
261
257
|
break;
|
|
262
258
|
}
|
|
263
259
|
}
|
|
264
|
-
if (
|
|
260
|
+
if (deltaPixels < 0) {
|
|
265
261
|
if (--index < 0) {
|
|
266
262
|
break;
|
|
267
263
|
}
|
|
@@ -279,7 +275,7 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
279
275
|
}
|
|
280
276
|
|
|
281
277
|
// Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
|
|
282
|
-
pivotId =
|
|
278
|
+
pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
283
279
|
index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
284
280
|
nextSizes[index] = baseSizes[index] + deltaApplied;
|
|
285
281
|
return nextSizes;
|
|
@@ -318,6 +314,93 @@ function callPanelCallbacks(panelsArray, sizes, panelIdToLastNotifiedSizeMap) {
|
|
|
318
314
|
}
|
|
319
315
|
});
|
|
320
316
|
}
|
|
317
|
+
function calculateDefaultLayout({
|
|
318
|
+
groupId,
|
|
319
|
+
panels,
|
|
320
|
+
units
|
|
321
|
+
}) {
|
|
322
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
323
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
324
|
+
const sizes = Array(panelsArray.length);
|
|
325
|
+
let numPanelsWithSizes = 0;
|
|
326
|
+
let remainingSize = 100;
|
|
327
|
+
|
|
328
|
+
// Assigning default sizes requires a couple of passes:
|
|
329
|
+
// First, all panels with defaultSize should be set as-is
|
|
330
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
331
|
+
const panel = panelsArray[index];
|
|
332
|
+
const {
|
|
333
|
+
defaultSize
|
|
334
|
+
} = panel.current;
|
|
335
|
+
if (defaultSize != null) {
|
|
336
|
+
numPanelsWithSizes++;
|
|
337
|
+
sizes[index] = units === "pixels" ? defaultSize / groupSizePixels * 100 : defaultSize;
|
|
338
|
+
remainingSize -= sizes[index];
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Remaining total size should be distributed evenly between panels
|
|
343
|
+
// This may require two passes, depending on min/max constraints
|
|
344
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
345
|
+
const panel = panelsArray[index];
|
|
346
|
+
let {
|
|
347
|
+
defaultSize,
|
|
348
|
+
id,
|
|
349
|
+
maxSize,
|
|
350
|
+
minSize
|
|
351
|
+
} = panel.current;
|
|
352
|
+
if (defaultSize != null) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (units === "pixels") {
|
|
356
|
+
minSize = minSize / groupSizePixels * 100;
|
|
357
|
+
if (maxSize != null) {
|
|
358
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const remainingPanels = panelsArray.length - numPanelsWithSizes;
|
|
362
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, remainingSize / remainingPanels));
|
|
363
|
+
sizes[index] = size;
|
|
364
|
+
numPanelsWithSizes++;
|
|
365
|
+
remainingSize -= size;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// If there is additional, left over space, assign it to any panel(s) that permits it
|
|
369
|
+
// (It's not worth taking multiple additional passes to evenly distribute)
|
|
370
|
+
if (remainingSize !== 0) {
|
|
371
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
372
|
+
const panel = panelsArray[index];
|
|
373
|
+
let {
|
|
374
|
+
maxSize,
|
|
375
|
+
minSize
|
|
376
|
+
} = panel.current;
|
|
377
|
+
if (units === "pixels") {
|
|
378
|
+
minSize = minSize / groupSizePixels * 100;
|
|
379
|
+
if (maxSize != null) {
|
|
380
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, sizes[index] + remainingSize));
|
|
384
|
+
if (size !== sizes[index]) {
|
|
385
|
+
remainingSize -= size - sizes[index];
|
|
386
|
+
sizes[index] = size;
|
|
387
|
+
|
|
388
|
+
// Fuzzy comparison to account for imprecise floating point math
|
|
389
|
+
if (Math.abs(remainingSize).toFixed(3) === "0.000") {
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Finally, if there is still left-over size, log an error
|
|
397
|
+
if (Math.abs(remainingSize).toFixed(3) !== "0.000") {
|
|
398
|
+
{
|
|
399
|
+
console.error(`Invalid panel group configuration; default panel sizes should total 100% but was ${(100 - remainingSize).toFixed(1)}%. This can cause the cursor to become misaligned while dragging.`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return sizes;
|
|
403
|
+
}
|
|
321
404
|
function getBeforeAndAfterIds(id, panelsArray) {
|
|
322
405
|
if (panelsArray.length < 2) {
|
|
323
406
|
return [null, null];
|
|
@@ -331,6 +414,23 @@ function getBeforeAndAfterIds(id, panelsArray) {
|
|
|
331
414
|
const idAfter = isLastPanel ? id : panelsArray[index + 1].current.id;
|
|
332
415
|
return [idBefore, idAfter];
|
|
333
416
|
}
|
|
417
|
+
function getAvailableGroupSizePixels(groupId) {
|
|
418
|
+
const panelGroupElement = getPanelGroup(groupId);
|
|
419
|
+
if (panelGroupElement == null) {
|
|
420
|
+
return NaN;
|
|
421
|
+
}
|
|
422
|
+
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
423
|
+
const resizeHandles = getResizeHandlesForGroup(groupId);
|
|
424
|
+
if (direction === "horizontal") {
|
|
425
|
+
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
426
|
+
return accumulated + handle.offsetWidth;
|
|
427
|
+
}, 0);
|
|
428
|
+
} else {
|
|
429
|
+
return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
|
|
430
|
+
return accumulated + handle.offsetHeight;
|
|
431
|
+
}, 0);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
334
434
|
|
|
335
435
|
// This method returns a number between 1 and 100 representing
|
|
336
436
|
// the % of the group's overall space this panel should occupy.
|
|
@@ -401,18 +501,24 @@ function panelsMapToSortedArray(panels) {
|
|
|
401
501
|
}
|
|
402
502
|
});
|
|
403
503
|
}
|
|
404
|
-
function safeResizePanel(
|
|
405
|
-
|
|
406
|
-
const {
|
|
504
|
+
function safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize, event = null) {
|
|
505
|
+
let {
|
|
407
506
|
collapsedSize,
|
|
408
507
|
collapsible,
|
|
409
508
|
maxSize,
|
|
410
509
|
minSize
|
|
411
510
|
} = panel.current;
|
|
511
|
+
if (units === "pixels") {
|
|
512
|
+
collapsedSize = collapsedSize / groupSizePixels * 100;
|
|
513
|
+
if (maxSize != null) {
|
|
514
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
515
|
+
}
|
|
516
|
+
minSize = minSize / groupSizePixels * 100;
|
|
517
|
+
}
|
|
412
518
|
if (collapsible) {
|
|
413
519
|
if (prevSize > collapsedSize) {
|
|
414
520
|
// Mimic VS COde behavior; collapse a panel if it's smaller than half of its min-size
|
|
415
|
-
if (
|
|
521
|
+
if (nextSize <= minSize / 2 + collapsedSize) {
|
|
416
522
|
return collapsedSize;
|
|
417
523
|
}
|
|
418
524
|
} else {
|
|
@@ -421,14 +527,119 @@ function safeResizePanel(panel, delta, prevSize, event) {
|
|
|
421
527
|
// Keyboard events should expand a collapsed panel to the min size,
|
|
422
528
|
// but mouse events should wait until the panel has reached its min size
|
|
423
529
|
// to avoid a visual flickering when dragging between collapsed and min size.
|
|
424
|
-
if (
|
|
530
|
+
if (nextSize < minSize) {
|
|
425
531
|
return collapsedSize;
|
|
426
532
|
}
|
|
427
533
|
}
|
|
428
534
|
}
|
|
429
535
|
}
|
|
430
|
-
|
|
431
|
-
|
|
536
|
+
return Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
537
|
+
}
|
|
538
|
+
function validatePanelProps(units, panelData) {
|
|
539
|
+
const {
|
|
540
|
+
collapsible,
|
|
541
|
+
defaultSize,
|
|
542
|
+
maxSize,
|
|
543
|
+
minSize
|
|
544
|
+
} = panelData.current;
|
|
545
|
+
|
|
546
|
+
// Basic props validation
|
|
547
|
+
if (minSize < 0 || units === "percentages" && minSize > 100) {
|
|
548
|
+
{
|
|
549
|
+
console.error(`Invalid Panel minSize provided, ${minSize}`);
|
|
550
|
+
}
|
|
551
|
+
panelData.current.minSize = 0;
|
|
552
|
+
}
|
|
553
|
+
if (maxSize != null) {
|
|
554
|
+
if (maxSize < 0 || units === "percentages" && maxSize > 100) {
|
|
555
|
+
{
|
|
556
|
+
console.error(`Invalid Panel maxSize provided, ${maxSize}`);
|
|
557
|
+
}
|
|
558
|
+
panelData.current.maxSize = null;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (defaultSize !== null) {
|
|
562
|
+
if (defaultSize < 0 || units === "percentages" && defaultSize > 100) {
|
|
563
|
+
{
|
|
564
|
+
console.error(`Invalid Panel defaultSize provided, ${defaultSize}`);
|
|
565
|
+
}
|
|
566
|
+
panelData.current.defaultSize = null;
|
|
567
|
+
} else if (defaultSize < minSize && !collapsible) {
|
|
568
|
+
{
|
|
569
|
+
console.error(`Panel minSize (${minSize}) cannot be greater than defaultSize (${defaultSize})`);
|
|
570
|
+
}
|
|
571
|
+
panelData.current.defaultSize = minSize;
|
|
572
|
+
} else if (maxSize != null && defaultSize > maxSize) {
|
|
573
|
+
{
|
|
574
|
+
console.error(`Panel maxSize (${maxSize}) cannot be less than defaultSize (${defaultSize})`);
|
|
575
|
+
}
|
|
576
|
+
panelData.current.defaultSize = maxSize;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
function validatePanelGroupLayout({
|
|
581
|
+
groupId,
|
|
582
|
+
panels,
|
|
583
|
+
nextSizes,
|
|
584
|
+
prevSizes,
|
|
585
|
+
units
|
|
586
|
+
}) {
|
|
587
|
+
// Clone because this method modifies
|
|
588
|
+
nextSizes = [...nextSizes];
|
|
589
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
590
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
591
|
+
let remainingSize = 0;
|
|
592
|
+
|
|
593
|
+
// First, check all of the proposed sizes against the min/max constraints
|
|
594
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
595
|
+
const panel = panelsArray[index];
|
|
596
|
+
const prevSize = prevSizes[index];
|
|
597
|
+
const nextSize = nextSizes[index];
|
|
598
|
+
const safeNextSize = safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize);
|
|
599
|
+
if (nextSize != safeNextSize) {
|
|
600
|
+
remainingSize += nextSize - safeNextSize;
|
|
601
|
+
nextSizes[index] = safeNextSize;
|
|
602
|
+
{
|
|
603
|
+
console.error(`Invalid size (${nextSize}) specified for Panel "${panel.current.id}" given the panel's min/max size constraints`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// If there is additional, left over space, assign it to any panel(s) that permits it
|
|
609
|
+
// (It's not worth taking multiple additional passes to evenly distribute)
|
|
610
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
611
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
612
|
+
const panel = panelsArray[index];
|
|
613
|
+
let {
|
|
614
|
+
maxSize,
|
|
615
|
+
minSize
|
|
616
|
+
} = panel.current;
|
|
617
|
+
if (units === "pixels") {
|
|
618
|
+
minSize = minSize / groupSizePixels * 100;
|
|
619
|
+
if (maxSize != null) {
|
|
620
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSizes[index] + remainingSize));
|
|
624
|
+
if (size !== nextSizes[index]) {
|
|
625
|
+
remainingSize -= size - nextSizes[index];
|
|
626
|
+
nextSizes[index] = size;
|
|
627
|
+
|
|
628
|
+
// Fuzzy comparison to account for imprecise floating point math
|
|
629
|
+
if (Math.abs(remainingSize).toFixed(3) === "0.000") {
|
|
630
|
+
break;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// If we still have remainder, the requested layout wasn't valid and we should warn about it
|
|
637
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
638
|
+
{
|
|
639
|
+
console.error(`"Invalid panel group configuration; default panel sizes should total 100% but was ${100 - remainingSize}%`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return nextSizes;
|
|
432
643
|
}
|
|
433
644
|
|
|
434
645
|
function assert(expectedCondition, message = "Assertion failed!") {
|
|
@@ -454,6 +665,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
454
665
|
panels
|
|
455
666
|
} = committedValuesRef.current;
|
|
456
667
|
const groupElement = getPanelGroup(groupId);
|
|
668
|
+
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
457
669
|
const {
|
|
458
670
|
height,
|
|
459
671
|
width
|
|
@@ -466,23 +678,28 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
466
678
|
if (idBefore == null || idAfter == null) {
|
|
467
679
|
return () => {};
|
|
468
680
|
}
|
|
469
|
-
let
|
|
470
|
-
let
|
|
681
|
+
let currentMinSize = 0;
|
|
682
|
+
let currentMaxSize = 100;
|
|
471
683
|
let totalMinSize = 0;
|
|
472
684
|
let totalMaxSize = 0;
|
|
473
685
|
|
|
474
686
|
// A panel's effective min/max sizes also need to account for other panel's sizes.
|
|
475
687
|
panelsArray.forEach(panelData => {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
688
|
+
const {
|
|
689
|
+
id,
|
|
690
|
+
maxSize,
|
|
691
|
+
minSize
|
|
692
|
+
} = panelData.current;
|
|
693
|
+
if (id === idBefore) {
|
|
694
|
+
currentMinSize = minSize;
|
|
695
|
+
currentMaxSize = maxSize != null ? maxSize : 100;
|
|
479
696
|
} else {
|
|
480
|
-
totalMinSize +=
|
|
481
|
-
totalMaxSize +=
|
|
697
|
+
totalMinSize += minSize;
|
|
698
|
+
totalMaxSize += maxSize != null ? maxSize : 100;
|
|
482
699
|
}
|
|
483
700
|
});
|
|
484
|
-
const ariaValueMax = Math.min(
|
|
485
|
-
const ariaValueMin = Math.max(
|
|
701
|
+
const ariaValueMax = Math.min(currentMaxSize, 100 - totalMinSize);
|
|
702
|
+
const ariaValueMin = Math.max(currentMinSize, (panelsArray.length - 1) * 100 - totalMaxSize);
|
|
486
703
|
const flexGrow = getFlexGrow(panels, idBefore, sizes);
|
|
487
704
|
handle.setAttribute("aria-valuemax", "" + Math.round(ariaValueMax));
|
|
488
705
|
handle.setAttribute("aria-valuemin", "" + Math.round(ariaValueMin));
|
|
@@ -506,7 +723,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
506
723
|
} else {
|
|
507
724
|
delta = -(direction === "horizontal" ? width : height);
|
|
508
725
|
}
|
|
509
|
-
const nextSizes = adjustByDelta(event,
|
|
726
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, sizes, panelSizeBeforeCollapse.current, null);
|
|
510
727
|
if (sizes !== nextSizes) {
|
|
511
728
|
setSizes(nextSizes);
|
|
512
729
|
}
|
|
@@ -778,13 +995,6 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
|
|
|
778
995
|
}
|
|
779
996
|
}
|
|
780
997
|
|
|
781
|
-
function isServerRendering() {
|
|
782
|
-
try {
|
|
783
|
-
return typeof window === undefined;
|
|
784
|
-
} catch (error) {}
|
|
785
|
-
return true;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
998
|
const debounceMap = {};
|
|
789
999
|
|
|
790
1000
|
// PanelGroup might be rendering in a server-side environment where localStorage is not available
|
|
@@ -828,9 +1038,6 @@ const defaultStorage = {
|
|
|
828
1038
|
// * dragHandleRect, sizes:
|
|
829
1039
|
// When resizing is done via mouse/touch event– some initial state is stored
|
|
830
1040
|
// so that any panels that contract will also expand if drag direction is reversed.
|
|
831
|
-
// TODO
|
|
832
|
-
// Within an active drag, remember original positions to refine more easily on expand.
|
|
833
|
-
// Look at what the Chrome devtools Sources does.
|
|
834
1041
|
function PanelGroupWithForwardedRef({
|
|
835
1042
|
autoSaveId,
|
|
836
1043
|
children = null,
|
|
@@ -842,7 +1049,8 @@ function PanelGroupWithForwardedRef({
|
|
|
842
1049
|
onLayout,
|
|
843
1050
|
storage = defaultStorage,
|
|
844
1051
|
style: styleFromProps = {},
|
|
845
|
-
tagName: Type = "div"
|
|
1052
|
+
tagName: Type = "div",
|
|
1053
|
+
units = "percentages"
|
|
846
1054
|
}) {
|
|
847
1055
|
const groupId = useUniqueId(idFromProps);
|
|
848
1056
|
const [activeHandleId, setActiveHandleId] = useState(null);
|
|
@@ -852,6 +1060,12 @@ function PanelGroupWithForwardedRef({
|
|
|
852
1060
|
// We store the initial Panel sizes in this ref, and apply move deltas to them instead of to the current sizes.
|
|
853
1061
|
// This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
|
|
854
1062
|
const initialDragStateRef = useRef(null);
|
|
1063
|
+
const devWarningsRef = useRef({
|
|
1064
|
+
didLogDefaultSizeWarning: false,
|
|
1065
|
+
didLogIdAndOrderWarning: false,
|
|
1066
|
+
didLogInvalidLayoutWarning: false,
|
|
1067
|
+
prevPanelIds: []
|
|
1068
|
+
});
|
|
855
1069
|
|
|
856
1070
|
// Use a ref to guard against users passing inline props
|
|
857
1071
|
const callbacksRef = useRef({
|
|
@@ -872,32 +1086,58 @@ function PanelGroupWithForwardedRef({
|
|
|
872
1086
|
// Store committed values to avoid unnecessarily re-running memoization/effects functions.
|
|
873
1087
|
const committedValuesRef = useRef({
|
|
874
1088
|
direction,
|
|
1089
|
+
id: groupId,
|
|
875
1090
|
panels,
|
|
876
|
-
sizes
|
|
1091
|
+
sizes,
|
|
1092
|
+
units
|
|
877
1093
|
});
|
|
878
1094
|
useImperativeHandle(forwardedRef, () => ({
|
|
879
|
-
|
|
1095
|
+
getId: () => groupId,
|
|
1096
|
+
getLayout: unitsFromParams => {
|
|
880
1097
|
const {
|
|
881
|
-
sizes
|
|
1098
|
+
sizes,
|
|
1099
|
+
units: unitsFromProps
|
|
882
1100
|
} = committedValuesRef.current;
|
|
883
|
-
|
|
1101
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
1102
|
+
if (units === "pixels") {
|
|
1103
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1104
|
+
return sizes.map(size => size / 100 * groupSizePixels);
|
|
1105
|
+
} else {
|
|
1106
|
+
return sizes;
|
|
1107
|
+
}
|
|
884
1108
|
},
|
|
885
|
-
setLayout: sizes => {
|
|
886
|
-
const total = sizes.reduce((accumulated, current) => accumulated + current, 0);
|
|
887
|
-
assert(total === 100, "Panel sizes must add up to 100%");
|
|
1109
|
+
setLayout: (sizes, unitsFromParams) => {
|
|
888
1110
|
const {
|
|
889
|
-
|
|
1111
|
+
id: groupId,
|
|
1112
|
+
panels,
|
|
1113
|
+
sizes: prevSizes,
|
|
1114
|
+
units
|
|
890
1115
|
} = committedValuesRef.current;
|
|
1116
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1117
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1118
|
+
sizes = sizes.map(size => size / groupSizePixels * 100);
|
|
1119
|
+
}
|
|
891
1120
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
892
1121
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
893
|
-
|
|
894
|
-
|
|
1122
|
+
const nextSizes = validatePanelGroupLayout({
|
|
1123
|
+
groupId,
|
|
1124
|
+
panels,
|
|
1125
|
+
nextSizes: sizes,
|
|
1126
|
+
prevSizes,
|
|
1127
|
+
units
|
|
1128
|
+
});
|
|
1129
|
+
if (!areEqual(prevSizes, nextSizes)) {
|
|
1130
|
+
setSizes(nextSizes);
|
|
1131
|
+
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1132
|
+
}
|
|
895
1133
|
}
|
|
896
|
-
}), []);
|
|
1134
|
+
}), [groupId]);
|
|
897
1135
|
useIsomorphicLayoutEffect(() => {
|
|
898
1136
|
committedValuesRef.current.direction = direction;
|
|
1137
|
+
committedValuesRef.current.id = groupId;
|
|
899
1138
|
committedValuesRef.current.panels = panels;
|
|
900
1139
|
committedValuesRef.current.sizes = sizes;
|
|
1140
|
+
committedValuesRef.current.units = units;
|
|
901
1141
|
});
|
|
902
1142
|
useWindowSplitterPanelGroupBehavior({
|
|
903
1143
|
committedValuesRef,
|
|
@@ -939,7 +1179,11 @@ function PanelGroupWithForwardedRef({
|
|
|
939
1179
|
// Compute the initial sizes based on default weights.
|
|
940
1180
|
// This assumes that panels register during initial mount (no conditional rendering)!
|
|
941
1181
|
useIsomorphicLayoutEffect(() => {
|
|
942
|
-
const
|
|
1182
|
+
const {
|
|
1183
|
+
id: groupId,
|
|
1184
|
+
sizes,
|
|
1185
|
+
units
|
|
1186
|
+
} = committedValuesRef.current;
|
|
943
1187
|
if (sizes.length === panels.size) {
|
|
944
1188
|
// Only compute (or restore) default sizes once per panel configuration.
|
|
945
1189
|
return;
|
|
@@ -953,39 +1197,23 @@ function PanelGroupWithForwardedRef({
|
|
|
953
1197
|
defaultSizes = loadPanelLayout(autoSaveId, panelsArray, storage);
|
|
954
1198
|
}
|
|
955
1199
|
if (defaultSizes != null) {
|
|
956
|
-
|
|
1200
|
+
// Validate saved sizes in case something has changed since last render
|
|
1201
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1202
|
+
const validatedSizes = validatePanelGroupLayout({
|
|
1203
|
+
groupId,
|
|
1204
|
+
panels,
|
|
1205
|
+
nextSizes: defaultSizes,
|
|
1206
|
+
prevSizes: defaultSizes,
|
|
1207
|
+
units
|
|
1208
|
+
});
|
|
1209
|
+
setSizes(validatedSizes);
|
|
957
1210
|
} else {
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
// TODO
|
|
964
|
-
// Implicit default size calculations below do not account for inferred min/max size values.
|
|
965
|
-
// e.g. if Panel A has a maxSize of 40 then Panels A and B can't both have an implicit default size of 50.
|
|
966
|
-
// For now, these logic edge cases are left to the user to handle via props.
|
|
967
|
-
|
|
968
|
-
panelsArray.forEach(panel => {
|
|
969
|
-
totalMinSize += panel.current.minSize;
|
|
970
|
-
if (panel.current.defaultSize === null) {
|
|
971
|
-
panelsWithNullDefaultSize++;
|
|
972
|
-
} else {
|
|
973
|
-
totalDefaultSize += panel.current.defaultSize;
|
|
974
|
-
}
|
|
1211
|
+
const sizes = calculateDefaultLayout({
|
|
1212
|
+
groupId,
|
|
1213
|
+
panels,
|
|
1214
|
+
units
|
|
975
1215
|
});
|
|
976
|
-
|
|
977
|
-
throw new Error(`Default panel sizes cannot exceed 100%`);
|
|
978
|
-
} else if (panelsArray.length > 1 && panelsWithNullDefaultSize === 0 && totalDefaultSize !== 100) {
|
|
979
|
-
throw new Error(`Invalid default sizes specified for panels`);
|
|
980
|
-
} else if (totalMinSize > 100) {
|
|
981
|
-
throw new Error(`Minimum panel sizes cannot exceed 100%`);
|
|
982
|
-
}
|
|
983
|
-
setSizes(panelsArray.map(panel => {
|
|
984
|
-
if (panel.current.defaultSize === null) {
|
|
985
|
-
return (100 - totalDefaultSize) / panelsWithNullDefaultSize;
|
|
986
|
-
}
|
|
987
|
-
return panel.current.defaultSize;
|
|
988
|
-
}));
|
|
1216
|
+
setSizes(sizes);
|
|
989
1217
|
}
|
|
990
1218
|
}, [autoSaveId, panels, storage]);
|
|
991
1219
|
useEffect(() => {
|
|
@@ -1002,7 +1230,69 @@ function PanelGroupWithForwardedRef({
|
|
|
1002
1230
|
}
|
|
1003
1231
|
debounceMap[autoSaveId](autoSaveId, panelsArray, sizes, storage);
|
|
1004
1232
|
}
|
|
1233
|
+
{
|
|
1234
|
+
const {
|
|
1235
|
+
didLogIdAndOrderWarning,
|
|
1236
|
+
prevPanelIds
|
|
1237
|
+
} = devWarningsRef.current;
|
|
1238
|
+
if (!didLogIdAndOrderWarning) {
|
|
1239
|
+
const {
|
|
1240
|
+
panels
|
|
1241
|
+
} = committedValuesRef.current;
|
|
1242
|
+
const panelIds = Array.from(panels.keys());
|
|
1243
|
+
devWarningsRef.current.prevPanelIds = panelIds;
|
|
1244
|
+
const panelsHaveChanged = prevPanelIds.length > 0 && !areEqual(prevPanelIds, panelIds);
|
|
1245
|
+
if (panelsHaveChanged) {
|
|
1246
|
+
if (Array.from(panels.values()).find(panel => panel.current.idWasAutoGenerated || panel.current.order == null)) {
|
|
1247
|
+
devWarningsRef.current.didLogIdAndOrderWarning = true;
|
|
1248
|
+
console.warn(`WARNING: Panel id and order props recommended when panels are dynamically rendered`);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1005
1253
|
}, [autoSaveId, panels, sizes, storage]);
|
|
1254
|
+
useIsomorphicLayoutEffect(() => {
|
|
1255
|
+
// Pixel panel constraints need to be reassessed after a group resize
|
|
1256
|
+
// We can avoid the ResizeObserver overhead for relative layouts
|
|
1257
|
+
if (units === "pixels") {
|
|
1258
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1259
|
+
const {
|
|
1260
|
+
panels,
|
|
1261
|
+
sizes: prevSizes
|
|
1262
|
+
} = committedValuesRef.current;
|
|
1263
|
+
const nextSizes = validatePanelGroupLayout({
|
|
1264
|
+
groupId,
|
|
1265
|
+
panels,
|
|
1266
|
+
nextSizes: prevSizes,
|
|
1267
|
+
prevSizes,
|
|
1268
|
+
units
|
|
1269
|
+
});
|
|
1270
|
+
if (!areEqual(prevSizes, nextSizes)) {
|
|
1271
|
+
setSizes(nextSizes);
|
|
1272
|
+
}
|
|
1273
|
+
});
|
|
1274
|
+
resizeObserver.observe(getPanelGroup(groupId));
|
|
1275
|
+
return () => {
|
|
1276
|
+
resizeObserver.disconnect();
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
}, [groupId, units]);
|
|
1280
|
+
const getPanelSize = useCallback((id, unitsFromParams) => {
|
|
1281
|
+
const {
|
|
1282
|
+
panels,
|
|
1283
|
+
units: unitsFromProps
|
|
1284
|
+
} = committedValuesRef.current;
|
|
1285
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
1286
|
+
const index = panelsArray.findIndex(panel => panel.current.id === id);
|
|
1287
|
+
const size = sizes[index];
|
|
1288
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
1289
|
+
if (units === "pixels") {
|
|
1290
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1291
|
+
return size / 100 * groupSizePixels;
|
|
1292
|
+
} else {
|
|
1293
|
+
return size;
|
|
1294
|
+
}
|
|
1295
|
+
}, [groupId, sizes]);
|
|
1006
1296
|
const getPanelStyle = useCallback((id, defaultSize) => {
|
|
1007
1297
|
const {
|
|
1008
1298
|
panels
|
|
@@ -1013,8 +1303,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1013
1303
|
// At this point the best we can do is render everything with the same size.
|
|
1014
1304
|
if (panels.size === 0) {
|
|
1015
1305
|
{
|
|
1016
|
-
if (
|
|
1017
|
-
|
|
1306
|
+
if (!devWarningsRef.current.didLogDefaultSizeWarning) {
|
|
1307
|
+
if (!isBrowser && defaultSize == null) {
|
|
1308
|
+
devWarningsRef.current.didLogDefaultSizeWarning = true;
|
|
1309
|
+
console.warn(`WARNING: Panel defaultSize prop recommended to avoid layout shift after server rendering`);
|
|
1310
|
+
}
|
|
1018
1311
|
}
|
|
1019
1312
|
}
|
|
1020
1313
|
return {
|
|
@@ -1038,6 +1331,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1038
1331
|
};
|
|
1039
1332
|
}, [activeHandleId, disablePointerEventsDuringResize, sizes]);
|
|
1040
1333
|
const registerPanel = useCallback((id, panelRef) => {
|
|
1334
|
+
const {
|
|
1335
|
+
units
|
|
1336
|
+
} = committedValuesRef.current;
|
|
1337
|
+
validatePanelProps(units, panelRef);
|
|
1041
1338
|
setPanels(prevPanels => {
|
|
1042
1339
|
if (prevPanels.has(id)) {
|
|
1043
1340
|
return prevPanels;
|
|
@@ -1074,7 +1371,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1074
1371
|
}
|
|
1075
1372
|
const size = isHorizontal ? rect.width : rect.height;
|
|
1076
1373
|
const delta = movement / size * 100;
|
|
1077
|
-
|
|
1374
|
+
|
|
1375
|
+
// If a validateLayout method has been provided
|
|
1376
|
+
// it's important to use it before updating the mouse cursor
|
|
1377
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, initialDragStateRef.current);
|
|
1078
1378
|
const sizesChanged = !areEqual(prevSizes, nextSizes);
|
|
1079
1379
|
|
|
1080
1380
|
// Don't update cursor for resizes triggered by keyboard interactions.
|
|
@@ -1101,6 +1401,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1101
1401
|
}
|
|
1102
1402
|
if (sizesChanged) {
|
|
1103
1403
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1404
|
+
|
|
1405
|
+
// It's okay to bypass in this case because we already validated above
|
|
1104
1406
|
setSizes(nextSizes);
|
|
1105
1407
|
|
|
1106
1408
|
// If resize change handlers have been declared, this is the time to call them.
|
|
@@ -1154,7 +1456,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1154
1456
|
}
|
|
1155
1457
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1156
1458
|
const delta = isLastPanel ? currentSize : collapsedSize - currentSize;
|
|
1157
|
-
const nextSizes = adjustByDelta(null,
|
|
1459
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1158
1460
|
if (prevSizes !== nextSizes) {
|
|
1159
1461
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1160
1462
|
setSizes(nextSizes);
|
|
@@ -1197,7 +1499,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1197
1499
|
}
|
|
1198
1500
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1199
1501
|
const delta = isLastPanel ? collapsedSize - sizeBeforeCollapse : sizeBeforeCollapse;
|
|
1200
|
-
const nextSizes = adjustByDelta(null,
|
|
1502
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1201
1503
|
if (prevSizes !== nextSizes) {
|
|
1202
1504
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1203
1505
|
setSizes(nextSizes);
|
|
@@ -1207,21 +1509,34 @@ function PanelGroupWithForwardedRef({
|
|
|
1207
1509
|
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1208
1510
|
}
|
|
1209
1511
|
}, []);
|
|
1210
|
-
const resizePanel = useCallback((id, nextSize) => {
|
|
1512
|
+
const resizePanel = useCallback((id, nextSize, unitsFromParams) => {
|
|
1211
1513
|
const {
|
|
1514
|
+
id: groupId,
|
|
1212
1515
|
panels,
|
|
1213
|
-
sizes: prevSizes
|
|
1516
|
+
sizes: prevSizes,
|
|
1517
|
+
units
|
|
1214
1518
|
} = committedValuesRef.current;
|
|
1519
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1520
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1521
|
+
nextSize = nextSize / groupSizePixels * 100;
|
|
1522
|
+
}
|
|
1215
1523
|
const panel = panels.get(id);
|
|
1216
1524
|
if (panel == null) {
|
|
1217
1525
|
return;
|
|
1218
1526
|
}
|
|
1219
|
-
|
|
1527
|
+
let {
|
|
1220
1528
|
collapsedSize,
|
|
1221
1529
|
collapsible,
|
|
1222
1530
|
maxSize,
|
|
1223
1531
|
minSize
|
|
1224
1532
|
} = panel.current;
|
|
1533
|
+
if (units === "pixels") {
|
|
1534
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1535
|
+
minSize = minSize / groupSizePixels * 100;
|
|
1536
|
+
if (maxSize != null) {
|
|
1537
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1225
1540
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
1226
1541
|
const index = panelsArray.indexOf(panel);
|
|
1227
1542
|
if (index < 0) {
|
|
@@ -1232,7 +1547,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1232
1547
|
return;
|
|
1233
1548
|
}
|
|
1234
1549
|
if (collapsible && nextSize === collapsedSize) ; else {
|
|
1235
|
-
|
|
1550
|
+
const unsafeNextSize = nextSize;
|
|
1551
|
+
nextSize = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
1552
|
+
{
|
|
1553
|
+
if (unsafeNextSize !== nextSize) {
|
|
1554
|
+
console.error(`Invalid size (${unsafeNextSize}) specified for Panel "${panel.current.id}" given the panel's min/max size constraints`);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1236
1557
|
}
|
|
1237
1558
|
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
1238
1559
|
if (idBefore == null || idAfter == null) {
|
|
@@ -1240,7 +1561,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1240
1561
|
}
|
|
1241
1562
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1242
1563
|
const delta = isLastPanel ? currentSize - nextSize : nextSize - currentSize;
|
|
1243
|
-
const nextSizes = adjustByDelta(null,
|
|
1564
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1244
1565
|
if (prevSizes !== nextSizes) {
|
|
1245
1566
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1246
1567
|
setSizes(nextSizes);
|
|
@@ -1255,6 +1576,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1255
1576
|
collapsePanel,
|
|
1256
1577
|
direction,
|
|
1257
1578
|
expandPanel,
|
|
1579
|
+
getPanelSize,
|
|
1258
1580
|
getPanelStyle,
|
|
1259
1581
|
groupId,
|
|
1260
1582
|
registerPanel,
|
|
@@ -1276,8 +1598,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1276
1598
|
setActiveHandleId(null);
|
|
1277
1599
|
initialDragStateRef.current = null;
|
|
1278
1600
|
},
|
|
1601
|
+
units,
|
|
1279
1602
|
unregisterPanel
|
|
1280
|
-
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, unregisterPanel]);
|
|
1603
|
+
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelSize, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, units, unregisterPanel]);
|
|
1281
1604
|
const style = {
|
|
1282
1605
|
display: "flex",
|
|
1283
1606
|
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
@@ -1292,6 +1615,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1292
1615
|
"data-panel-group": "",
|
|
1293
1616
|
"data-panel-group-direction": direction,
|
|
1294
1617
|
"data-panel-group-id": groupId,
|
|
1618
|
+
"data-panel-group-units": units,
|
|
1295
1619
|
style: {
|
|
1296
1620
|
...style,
|
|
1297
1621
|
...styleFromProps
|
|
@@ -1304,10 +1628,6 @@ const PanelGroup = forwardRef((props, ref) => createElement(PanelGroupWithForwar
|
|
|
1304
1628
|
...props,
|
|
1305
1629
|
forwardedRef: ref
|
|
1306
1630
|
}));
|
|
1307
|
-
|
|
1308
|
-
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
1309
|
-
// Casting to :any is required to avoid corrupting the generated TypeScript types.
|
|
1310
|
-
// See github.com/parcel-bundler/parcel/issues/8724
|
|
1311
1631
|
PanelGroupWithForwardedRef.displayName = "PanelGroup";
|
|
1312
1632
|
PanelGroup.displayName = "forwardRef(PanelGroup)";
|
|
1313
1633
|
|
|
@@ -1443,12 +1763,9 @@ function PanelResizeHandle({
|
|
|
1443
1763
|
tabIndex: 0
|
|
1444
1764
|
});
|
|
1445
1765
|
}
|
|
1446
|
-
|
|
1447
|
-
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
1448
|
-
// Casting to :any is required to avoid corrupting the generated TypeScript types.
|
|
1449
|
-
// See github.com/parcel-bundler/parcel/issues/8724
|
|
1450
1766
|
PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
1451
1767
|
|
|
1452
1768
|
exports.Panel = Panel;
|
|
1453
1769
|
exports.PanelGroup = PanelGroup;
|
|
1454
1770
|
exports.PanelResizeHandle = PanelResizeHandle;
|
|
1771
|
+
exports.getAvailableGroupSizePixels = getAvailableGroupSizePixels;
|