react-resizable-panels 2.1.6 → 2.1.8
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/README.md +4 -0
- package/dist/declarations/src/Panel.d.ts +1 -1
- package/dist/declarations/src/PanelGroup.d.ts +1 -1
- package/dist/declarations/src/PanelResizeHandle.d.ts +6 -3
- package/dist/react-resizable-panels.browser.cjs.js +90 -94
- package/dist/react-resizable-panels.browser.development.cjs.js +90 -94
- package/dist/react-resizable-panels.browser.development.esm.js +38 -41
- package/dist/react-resizable-panels.browser.esm.js +38 -41
- package/dist/react-resizable-panels.cjs.js +90 -94
- package/dist/react-resizable-panels.development.cjs.js +90 -94
- package/dist/react-resizable-panels.development.esm.js +38 -41
- package/dist/react-resizable-panels.development.node.cjs.js +89 -92
- package/dist/react-resizable-panels.development.node.esm.js +37 -39
- package/dist/react-resizable-panels.esm.js +38 -41
- package/dist/react-resizable-panels.node.cjs.js +89 -92
- package/dist/react-resizable-panels.node.esm.js +37 -39
- package/package.json +7 -2
- package/.eslintrc.cjs +0 -27
- package/CHANGELOG.md +0 -574
- package/dist/declarations/src/vendor/react.d.ts +0 -7
- package/jest.config.js +0 -10
- package/src/Panel.test.tsx +0 -1084
- package/src/Panel.ts +0 -259
- package/src/PanelGroup.test.tsx +0 -443
- package/src/PanelGroup.ts +0 -999
- package/src/PanelGroupContext.ts +0 -42
- package/src/PanelResizeHandle.test.tsx +0 -367
- package/src/PanelResizeHandle.ts +0 -246
- package/src/PanelResizeHandleRegistry.ts +0 -336
- package/src/constants.ts +0 -1
- package/src/env-conditions/browser.ts +0 -1
- package/src/env-conditions/development.ts +0 -1
- package/src/env-conditions/node.ts +0 -1
- package/src/env-conditions/production.ts +0 -1
- package/src/env-conditions/unknown.ts +0 -1
- package/src/hooks/useForceUpdate.ts +0 -7
- package/src/hooks/useIsomorphicEffect.ts +0 -8
- package/src/hooks/useUniqueId.ts +0 -19
- package/src/hooks/useWindowSplitterBehavior.ts +0 -90
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +0 -201
- package/src/index.ts +0 -77
- package/src/types.ts +0 -5
- package/src/utils/adjustLayoutByDelta.test.ts +0 -2061
- package/src/utils/adjustLayoutByDelta.ts +0 -308
- package/src/utils/arrays.ts +0 -13
- package/src/utils/assert.ts +0 -10
- package/src/utils/calculateAriaValues.test.ts +0 -106
- package/src/utils/calculateAriaValues.ts +0 -45
- package/src/utils/calculateDeltaPercentage.ts +0 -63
- package/src/utils/calculateDragOffsetPercentage.ts +0 -40
- package/src/utils/calculateUnsafeDefaultLayout.test.ts +0 -87
- package/src/utils/calculateUnsafeDefaultLayout.ts +0 -50
- package/src/utils/callPanelCallbacks.ts +0 -49
- package/src/utils/compareLayouts.test.ts +0 -9
- package/src/utils/compareLayouts.ts +0 -12
- package/src/utils/computePanelFlexBoxStyle.test.ts +0 -123
- package/src/utils/computePanelFlexBoxStyle.ts +0 -50
- package/src/utils/csp.ts +0 -9
- package/src/utils/cursor.ts +0 -103
- package/src/utils/debounce.ts +0 -18
- package/src/utils/determinePivotIndices.ts +0 -15
- package/src/utils/dom/getPanelElement.ts +0 -10
- package/src/utils/dom/getPanelElementsForGroup.ts +0 -8
- package/src/utils/dom/getPanelGroupElement.ts +0 -21
- package/src/utils/dom/getResizeHandleElement.ts +0 -10
- package/src/utils/dom/getResizeHandleElementIndex.ts +0 -13
- package/src/utils/dom/getResizeHandleElementsForGroup.ts +0 -10
- package/src/utils/dom/getResizeHandlePanelIds.ts +0 -19
- package/src/utils/events/getResizeEventCoordinates.ts +0 -23
- package/src/utils/events/getResizeEventCursorPosition.ts +0 -14
- package/src/utils/events/index.ts +0 -13
- package/src/utils/getInputType.ts +0 -5
- package/src/utils/initializeDefaultStorage.ts +0 -26
- package/src/utils/numbers/fuzzyCompareNumbers.test.ts +0 -16
- package/src/utils/numbers/fuzzyCompareNumbers.ts +0 -21
- package/src/utils/numbers/fuzzyLayoutsEqual.ts +0 -22
- package/src/utils/numbers/fuzzyNumbersEqual.ts +0 -9
- package/src/utils/rects/getIntersectingRectangle.test.ts +0 -198
- package/src/utils/rects/getIntersectingRectangle.ts +0 -28
- package/src/utils/rects/intersects.test.ts +0 -197
- package/src/utils/rects/intersects.ts +0 -23
- package/src/utils/rects/types.ts +0 -6
- package/src/utils/resizePanel.test.ts +0 -59
- package/src/utils/resizePanel.ts +0 -47
- package/src/utils/serialization.ts +0 -87
- package/src/utils/test-utils.ts +0 -205
- package/src/utils/validatePanelConstraints.test.ts +0 -143
- package/src/utils/validatePanelConstraints.ts +0 -69
- package/src/utils/validatePanelGroupLayout.test.ts +0 -148
- package/src/utils/validatePanelGroupLayout.ts +0 -95
- package/src/vendor/react.ts +0 -73
- package/src/vendor/stacking-order.ts +0 -139
package/src/PanelGroup.ts
DELETED
|
@@ -1,999 +0,0 @@
|
|
|
1
|
-
import { isDevelopment } from "#is-development";
|
|
2
|
-
import { PanelConstraints, PanelData } from "./Panel";
|
|
3
|
-
import {
|
|
4
|
-
DragState,
|
|
5
|
-
PanelGroupContext,
|
|
6
|
-
ResizeEvent,
|
|
7
|
-
TPanelGroupContext,
|
|
8
|
-
} from "./PanelGroupContext";
|
|
9
|
-
import {
|
|
10
|
-
EXCEEDED_HORIZONTAL_MAX,
|
|
11
|
-
EXCEEDED_HORIZONTAL_MIN,
|
|
12
|
-
EXCEEDED_VERTICAL_MAX,
|
|
13
|
-
EXCEEDED_VERTICAL_MIN,
|
|
14
|
-
reportConstraintsViolation,
|
|
15
|
-
} from "./PanelResizeHandleRegistry";
|
|
16
|
-
import { useForceUpdate } from "./hooks/useForceUpdate";
|
|
17
|
-
import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
|
|
18
|
-
import useUniqueId from "./hooks/useUniqueId";
|
|
19
|
-
import { useWindowSplitterPanelGroupBehavior } from "./hooks/useWindowSplitterPanelGroupBehavior";
|
|
20
|
-
import { Direction } from "./types";
|
|
21
|
-
import { adjustLayoutByDelta } from "./utils/adjustLayoutByDelta";
|
|
22
|
-
import { areEqual } from "./utils/arrays";
|
|
23
|
-
import { assert } from "./utils/assert";
|
|
24
|
-
import { calculateDeltaPercentage } from "./utils/calculateDeltaPercentage";
|
|
25
|
-
import { calculateUnsafeDefaultLayout } from "./utils/calculateUnsafeDefaultLayout";
|
|
26
|
-
import { callPanelCallbacks } from "./utils/callPanelCallbacks";
|
|
27
|
-
import { compareLayouts } from "./utils/compareLayouts";
|
|
28
|
-
import { computePanelFlexBoxStyle } from "./utils/computePanelFlexBoxStyle";
|
|
29
|
-
import debounce from "./utils/debounce";
|
|
30
|
-
import { determinePivotIndices } from "./utils/determinePivotIndices";
|
|
31
|
-
import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement";
|
|
32
|
-
import { isKeyDown, isMouseEvent, isPointerEvent } from "./utils/events";
|
|
33
|
-
import { getResizeEventCursorPosition } from "./utils/events/getResizeEventCursorPosition";
|
|
34
|
-
import { initializeDefaultStorage } from "./utils/initializeDefaultStorage";
|
|
35
|
-
import {
|
|
36
|
-
fuzzyCompareNumbers,
|
|
37
|
-
fuzzyNumbersEqual,
|
|
38
|
-
} from "./utils/numbers/fuzzyCompareNumbers";
|
|
39
|
-
import {
|
|
40
|
-
loadPanelGroupState,
|
|
41
|
-
savePanelGroupState,
|
|
42
|
-
} from "./utils/serialization";
|
|
43
|
-
import { validatePanelConstraints } from "./utils/validatePanelConstraints";
|
|
44
|
-
import { validatePanelGroupLayout } from "./utils/validatePanelGroupLayout";
|
|
45
|
-
import {
|
|
46
|
-
CSSProperties,
|
|
47
|
-
ForwardedRef,
|
|
48
|
-
HTMLAttributes,
|
|
49
|
-
PropsWithChildren,
|
|
50
|
-
ReactElement,
|
|
51
|
-
createElement,
|
|
52
|
-
forwardRef,
|
|
53
|
-
useCallback,
|
|
54
|
-
useEffect,
|
|
55
|
-
useImperativeHandle,
|
|
56
|
-
useMemo,
|
|
57
|
-
useRef,
|
|
58
|
-
useState,
|
|
59
|
-
} from "./vendor/react";
|
|
60
|
-
|
|
61
|
-
const LOCAL_STORAGE_DEBOUNCE_INTERVAL = 100;
|
|
62
|
-
|
|
63
|
-
export type ImperativePanelGroupHandle = {
|
|
64
|
-
getId: () => string;
|
|
65
|
-
getLayout: () => number[];
|
|
66
|
-
setLayout: (layout: number[]) => void;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export type PanelGroupStorage = {
|
|
70
|
-
getItem(name: string): string | null;
|
|
71
|
-
setItem(name: string, value: string): void;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export type PanelGroupOnLayout = (layout: number[]) => void;
|
|
75
|
-
|
|
76
|
-
const defaultStorage: PanelGroupStorage = {
|
|
77
|
-
getItem: (name: string) => {
|
|
78
|
-
initializeDefaultStorage(defaultStorage);
|
|
79
|
-
return defaultStorage.getItem(name);
|
|
80
|
-
},
|
|
81
|
-
setItem: (name: string, value: string) => {
|
|
82
|
-
initializeDefaultStorage(defaultStorage);
|
|
83
|
-
defaultStorage.setItem(name, value);
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export type PanelGroupProps = Omit<
|
|
88
|
-
HTMLAttributes<keyof HTMLElementTagNameMap>,
|
|
89
|
-
"id"
|
|
90
|
-
> &
|
|
91
|
-
PropsWithChildren<{
|
|
92
|
-
autoSaveId?: string | null;
|
|
93
|
-
className?: string;
|
|
94
|
-
direction: Direction;
|
|
95
|
-
id?: string | null;
|
|
96
|
-
keyboardResizeBy?: number | null;
|
|
97
|
-
onLayout?: PanelGroupOnLayout | null;
|
|
98
|
-
storage?: PanelGroupStorage;
|
|
99
|
-
style?: CSSProperties;
|
|
100
|
-
tagName?: keyof HTMLElementTagNameMap;
|
|
101
|
-
|
|
102
|
-
// Better TypeScript hinting
|
|
103
|
-
dir?: "auto" | "ltr" | "rtl" | undefined;
|
|
104
|
-
}>;
|
|
105
|
-
|
|
106
|
-
const debounceMap: {
|
|
107
|
-
[key: string]: typeof savePanelGroupState;
|
|
108
|
-
} = {};
|
|
109
|
-
|
|
110
|
-
function PanelGroupWithForwardedRef({
|
|
111
|
-
autoSaveId = null,
|
|
112
|
-
children,
|
|
113
|
-
className: classNameFromProps = "",
|
|
114
|
-
direction,
|
|
115
|
-
forwardedRef,
|
|
116
|
-
id: idFromProps = null,
|
|
117
|
-
onLayout = null,
|
|
118
|
-
keyboardResizeBy = null,
|
|
119
|
-
storage = defaultStorage,
|
|
120
|
-
style: styleFromProps,
|
|
121
|
-
tagName: Type = "div",
|
|
122
|
-
...rest
|
|
123
|
-
}: PanelGroupProps & {
|
|
124
|
-
forwardedRef: ForwardedRef<ImperativePanelGroupHandle>;
|
|
125
|
-
}): ReactElement {
|
|
126
|
-
const groupId = useUniqueId(idFromProps);
|
|
127
|
-
const panelGroupElementRef = useRef<HTMLDivElement | null>(null);
|
|
128
|
-
const [dragState, setDragState] = useState<DragState | null>(null);
|
|
129
|
-
const [layout, setLayout] = useState<number[]>([]);
|
|
130
|
-
const forceUpdate = useForceUpdate();
|
|
131
|
-
|
|
132
|
-
const panelIdToLastNotifiedSizeMapRef = useRef<Record<string, number>>({});
|
|
133
|
-
const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
|
|
134
|
-
const prevDeltaRef = useRef<number>(0);
|
|
135
|
-
|
|
136
|
-
const committedValuesRef = useRef<{
|
|
137
|
-
autoSaveId: string | null;
|
|
138
|
-
direction: Direction;
|
|
139
|
-
dragState: DragState | null;
|
|
140
|
-
id: string;
|
|
141
|
-
keyboardResizeBy: number | null;
|
|
142
|
-
onLayout: PanelGroupOnLayout | null;
|
|
143
|
-
storage: PanelGroupStorage;
|
|
144
|
-
}>({
|
|
145
|
-
autoSaveId,
|
|
146
|
-
direction,
|
|
147
|
-
dragState,
|
|
148
|
-
id: groupId,
|
|
149
|
-
keyboardResizeBy,
|
|
150
|
-
onLayout,
|
|
151
|
-
storage,
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
const eagerValuesRef = useRef<{
|
|
155
|
-
layout: number[];
|
|
156
|
-
panelDataArray: PanelData[];
|
|
157
|
-
panelDataArrayChanged: boolean;
|
|
158
|
-
}>({
|
|
159
|
-
layout,
|
|
160
|
-
panelDataArray: [],
|
|
161
|
-
panelDataArrayChanged: false,
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
const devWarningsRef = useRef<{
|
|
165
|
-
didLogIdAndOrderWarning: boolean;
|
|
166
|
-
didLogPanelConstraintsWarning: boolean;
|
|
167
|
-
prevPanelIds: string[];
|
|
168
|
-
}>({
|
|
169
|
-
didLogIdAndOrderWarning: false,
|
|
170
|
-
didLogPanelConstraintsWarning: false,
|
|
171
|
-
prevPanelIds: [],
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
useImperativeHandle(
|
|
175
|
-
forwardedRef,
|
|
176
|
-
() => ({
|
|
177
|
-
getId: () => committedValuesRef.current.id,
|
|
178
|
-
getLayout: () => {
|
|
179
|
-
const { layout } = eagerValuesRef.current;
|
|
180
|
-
|
|
181
|
-
return layout;
|
|
182
|
-
},
|
|
183
|
-
setLayout: (unsafeLayout: number[]) => {
|
|
184
|
-
const { onLayout } = committedValuesRef.current;
|
|
185
|
-
const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
|
|
186
|
-
|
|
187
|
-
const safeLayout = validatePanelGroupLayout({
|
|
188
|
-
layout: unsafeLayout,
|
|
189
|
-
panelConstraints: panelDataArray.map(
|
|
190
|
-
(panelData) => panelData.constraints
|
|
191
|
-
),
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
if (!areEqual(prevLayout, safeLayout)) {
|
|
195
|
-
setLayout(safeLayout);
|
|
196
|
-
|
|
197
|
-
eagerValuesRef.current.layout = safeLayout;
|
|
198
|
-
|
|
199
|
-
if (onLayout) {
|
|
200
|
-
onLayout(safeLayout);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
callPanelCallbacks(
|
|
204
|
-
panelDataArray,
|
|
205
|
-
safeLayout,
|
|
206
|
-
panelIdToLastNotifiedSizeMapRef.current
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
}),
|
|
211
|
-
[]
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
useIsomorphicLayoutEffect(() => {
|
|
215
|
-
committedValuesRef.current.autoSaveId = autoSaveId;
|
|
216
|
-
committedValuesRef.current.direction = direction;
|
|
217
|
-
committedValuesRef.current.dragState = dragState;
|
|
218
|
-
committedValuesRef.current.id = groupId;
|
|
219
|
-
committedValuesRef.current.onLayout = onLayout;
|
|
220
|
-
committedValuesRef.current.storage = storage;
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
useWindowSplitterPanelGroupBehavior({
|
|
224
|
-
committedValuesRef,
|
|
225
|
-
eagerValuesRef,
|
|
226
|
-
groupId,
|
|
227
|
-
layout,
|
|
228
|
-
panelDataArray: eagerValuesRef.current.panelDataArray,
|
|
229
|
-
setLayout,
|
|
230
|
-
panelGroupElement: panelGroupElementRef.current,
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
useEffect(() => {
|
|
234
|
-
const { panelDataArray } = eagerValuesRef.current;
|
|
235
|
-
|
|
236
|
-
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
237
|
-
if (autoSaveId) {
|
|
238
|
-
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
let debouncedSave = debounceMap[autoSaveId];
|
|
243
|
-
|
|
244
|
-
// Limit the frequency of localStorage updates.
|
|
245
|
-
if (debouncedSave == null) {
|
|
246
|
-
debouncedSave = debounce(
|
|
247
|
-
savePanelGroupState,
|
|
248
|
-
LOCAL_STORAGE_DEBOUNCE_INTERVAL
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
debounceMap[autoSaveId] = debouncedSave;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Clone mutable data before passing to the debounced function,
|
|
255
|
-
// else we run the risk of saving an incorrect combination of mutable and immutable values to state.
|
|
256
|
-
const clonedPanelDataArray = [...panelDataArray];
|
|
257
|
-
const clonedPanelSizesBeforeCollapse = new Map(
|
|
258
|
-
panelSizeBeforeCollapseRef.current
|
|
259
|
-
);
|
|
260
|
-
debouncedSave(
|
|
261
|
-
autoSaveId,
|
|
262
|
-
clonedPanelDataArray,
|
|
263
|
-
clonedPanelSizesBeforeCollapse,
|
|
264
|
-
layout,
|
|
265
|
-
storage
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
}, [autoSaveId, layout, storage]);
|
|
269
|
-
|
|
270
|
-
// DEV warnings
|
|
271
|
-
useEffect(() => {
|
|
272
|
-
if (isDevelopment) {
|
|
273
|
-
const { panelDataArray } = eagerValuesRef.current;
|
|
274
|
-
|
|
275
|
-
const {
|
|
276
|
-
didLogIdAndOrderWarning,
|
|
277
|
-
didLogPanelConstraintsWarning,
|
|
278
|
-
prevPanelIds,
|
|
279
|
-
} = devWarningsRef.current;
|
|
280
|
-
|
|
281
|
-
if (!didLogIdAndOrderWarning) {
|
|
282
|
-
const panelIds = panelDataArray.map(({ id }) => id);
|
|
283
|
-
|
|
284
|
-
devWarningsRef.current.prevPanelIds = panelIds;
|
|
285
|
-
|
|
286
|
-
const panelsHaveChanged =
|
|
287
|
-
prevPanelIds.length > 0 && !areEqual(prevPanelIds, panelIds);
|
|
288
|
-
if (panelsHaveChanged) {
|
|
289
|
-
if (
|
|
290
|
-
panelDataArray.find(
|
|
291
|
-
({ idIsFromProps, order }) => !idIsFromProps || order == null
|
|
292
|
-
)
|
|
293
|
-
) {
|
|
294
|
-
devWarningsRef.current.didLogIdAndOrderWarning = true;
|
|
295
|
-
|
|
296
|
-
console.warn(
|
|
297
|
-
`WARNING: Panel id and order props recommended when panels are dynamically rendered`
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (!didLogPanelConstraintsWarning) {
|
|
304
|
-
const panelConstraints = panelDataArray.map(
|
|
305
|
-
(panelData) => panelData.constraints
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
for (
|
|
309
|
-
let panelIndex = 0;
|
|
310
|
-
panelIndex < panelConstraints.length;
|
|
311
|
-
panelIndex++
|
|
312
|
-
) {
|
|
313
|
-
const panelData = panelDataArray[panelIndex];
|
|
314
|
-
assert(panelData, `Panel data not found for index ${panelIndex}`);
|
|
315
|
-
|
|
316
|
-
const isValid = validatePanelConstraints({
|
|
317
|
-
panelConstraints,
|
|
318
|
-
panelId: panelData.id,
|
|
319
|
-
panelIndex,
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
if (!isValid) {
|
|
323
|
-
devWarningsRef.current.didLogPanelConstraintsWarning = true;
|
|
324
|
-
|
|
325
|
-
break;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
// External APIs are safe to memoize via committed values ref
|
|
333
|
-
const collapsePanel = useCallback((panelData: PanelData) => {
|
|
334
|
-
const { onLayout } = committedValuesRef.current;
|
|
335
|
-
const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
|
|
336
|
-
|
|
337
|
-
if (panelData.constraints.collapsible) {
|
|
338
|
-
const panelConstraintsArray = panelDataArray.map(
|
|
339
|
-
(panelData) => panelData.constraints
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
const {
|
|
343
|
-
collapsedSize = 0,
|
|
344
|
-
panelSize,
|
|
345
|
-
pivotIndices,
|
|
346
|
-
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
347
|
-
|
|
348
|
-
assert(
|
|
349
|
-
panelSize != null,
|
|
350
|
-
`Panel size not found for panel "${panelData.id}"`
|
|
351
|
-
);
|
|
352
|
-
|
|
353
|
-
if (!fuzzyNumbersEqual(panelSize, collapsedSize)) {
|
|
354
|
-
// Store size before collapse;
|
|
355
|
-
// This is the size that gets restored if the expand() API is used.
|
|
356
|
-
panelSizeBeforeCollapseRef.current.set(panelData.id, panelSize);
|
|
357
|
-
|
|
358
|
-
const isLastPanel =
|
|
359
|
-
findPanelDataIndex(panelDataArray, panelData) ===
|
|
360
|
-
panelDataArray.length - 1;
|
|
361
|
-
const delta = isLastPanel
|
|
362
|
-
? panelSize - collapsedSize
|
|
363
|
-
: collapsedSize - panelSize;
|
|
364
|
-
|
|
365
|
-
const nextLayout = adjustLayoutByDelta({
|
|
366
|
-
delta,
|
|
367
|
-
initialLayout: prevLayout,
|
|
368
|
-
panelConstraints: panelConstraintsArray,
|
|
369
|
-
pivotIndices,
|
|
370
|
-
prevLayout,
|
|
371
|
-
trigger: "imperative-api",
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
375
|
-
setLayout(nextLayout);
|
|
376
|
-
|
|
377
|
-
eagerValuesRef.current.layout = nextLayout;
|
|
378
|
-
|
|
379
|
-
if (onLayout) {
|
|
380
|
-
onLayout(nextLayout);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
callPanelCallbacks(
|
|
384
|
-
panelDataArray,
|
|
385
|
-
nextLayout,
|
|
386
|
-
panelIdToLastNotifiedSizeMapRef.current
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}, []);
|
|
392
|
-
|
|
393
|
-
// External APIs are safe to memoize via committed values ref
|
|
394
|
-
const expandPanel = useCallback(
|
|
395
|
-
(panelData: PanelData, minSizeOverride?: number) => {
|
|
396
|
-
const { onLayout } = committedValuesRef.current;
|
|
397
|
-
const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
|
|
398
|
-
|
|
399
|
-
if (panelData.constraints.collapsible) {
|
|
400
|
-
const panelConstraintsArray = panelDataArray.map(
|
|
401
|
-
(panelData) => panelData.constraints
|
|
402
|
-
);
|
|
403
|
-
|
|
404
|
-
const {
|
|
405
|
-
collapsedSize = 0,
|
|
406
|
-
panelSize = 0,
|
|
407
|
-
minSize: minSizeFromProps = 0,
|
|
408
|
-
pivotIndices,
|
|
409
|
-
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
410
|
-
|
|
411
|
-
const minSize = minSizeOverride ?? minSizeFromProps;
|
|
412
|
-
|
|
413
|
-
if (fuzzyNumbersEqual(panelSize, collapsedSize)) {
|
|
414
|
-
// Restore this panel to the size it was before it was collapsed, if possible.
|
|
415
|
-
const prevPanelSize = panelSizeBeforeCollapseRef.current.get(
|
|
416
|
-
panelData.id
|
|
417
|
-
);
|
|
418
|
-
|
|
419
|
-
const baseSize =
|
|
420
|
-
prevPanelSize != null && prevPanelSize >= minSize
|
|
421
|
-
? prevPanelSize
|
|
422
|
-
: minSize;
|
|
423
|
-
|
|
424
|
-
const isLastPanel =
|
|
425
|
-
findPanelDataIndex(panelDataArray, panelData) ===
|
|
426
|
-
panelDataArray.length - 1;
|
|
427
|
-
const delta = isLastPanel
|
|
428
|
-
? panelSize - baseSize
|
|
429
|
-
: baseSize - panelSize;
|
|
430
|
-
|
|
431
|
-
const nextLayout = adjustLayoutByDelta({
|
|
432
|
-
delta,
|
|
433
|
-
initialLayout: prevLayout,
|
|
434
|
-
panelConstraints: panelConstraintsArray,
|
|
435
|
-
pivotIndices,
|
|
436
|
-
prevLayout,
|
|
437
|
-
trigger: "imperative-api",
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
441
|
-
setLayout(nextLayout);
|
|
442
|
-
|
|
443
|
-
eagerValuesRef.current.layout = nextLayout;
|
|
444
|
-
|
|
445
|
-
if (onLayout) {
|
|
446
|
-
onLayout(nextLayout);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
callPanelCallbacks(
|
|
450
|
-
panelDataArray,
|
|
451
|
-
nextLayout,
|
|
452
|
-
panelIdToLastNotifiedSizeMapRef.current
|
|
453
|
-
);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
},
|
|
458
|
-
[]
|
|
459
|
-
);
|
|
460
|
-
|
|
461
|
-
// External APIs are safe to memoize via committed values ref
|
|
462
|
-
const getPanelSize = useCallback((panelData: PanelData) => {
|
|
463
|
-
const { layout, panelDataArray } = eagerValuesRef.current;
|
|
464
|
-
|
|
465
|
-
const { panelSize } = panelDataHelper(panelDataArray, panelData, layout);
|
|
466
|
-
|
|
467
|
-
assert(
|
|
468
|
-
panelSize != null,
|
|
469
|
-
`Panel size not found for panel "${panelData.id}"`
|
|
470
|
-
);
|
|
471
|
-
|
|
472
|
-
return panelSize;
|
|
473
|
-
}, []);
|
|
474
|
-
|
|
475
|
-
// This API should never read from committedValuesRef
|
|
476
|
-
const getPanelStyle = useCallback(
|
|
477
|
-
(panelData: PanelData, defaultSize: number | undefined) => {
|
|
478
|
-
const { panelDataArray } = eagerValuesRef.current;
|
|
479
|
-
|
|
480
|
-
const panelIndex = findPanelDataIndex(panelDataArray, panelData);
|
|
481
|
-
|
|
482
|
-
return computePanelFlexBoxStyle({
|
|
483
|
-
defaultSize,
|
|
484
|
-
dragState,
|
|
485
|
-
layout,
|
|
486
|
-
panelData: panelDataArray,
|
|
487
|
-
panelIndex,
|
|
488
|
-
});
|
|
489
|
-
},
|
|
490
|
-
[dragState, layout]
|
|
491
|
-
);
|
|
492
|
-
|
|
493
|
-
// External APIs are safe to memoize via committed values ref
|
|
494
|
-
const isPanelCollapsed = useCallback((panelData: PanelData) => {
|
|
495
|
-
const { layout, panelDataArray } = eagerValuesRef.current;
|
|
496
|
-
|
|
497
|
-
const {
|
|
498
|
-
collapsedSize = 0,
|
|
499
|
-
collapsible,
|
|
500
|
-
panelSize,
|
|
501
|
-
} = panelDataHelper(panelDataArray, panelData, layout);
|
|
502
|
-
|
|
503
|
-
assert(
|
|
504
|
-
panelSize != null,
|
|
505
|
-
`Panel size not found for panel "${panelData.id}"`
|
|
506
|
-
);
|
|
507
|
-
|
|
508
|
-
return collapsible === true && fuzzyNumbersEqual(panelSize, collapsedSize);
|
|
509
|
-
}, []);
|
|
510
|
-
|
|
511
|
-
// External APIs are safe to memoize via committed values ref
|
|
512
|
-
const isPanelExpanded = useCallback((panelData: PanelData) => {
|
|
513
|
-
const { layout, panelDataArray } = eagerValuesRef.current;
|
|
514
|
-
|
|
515
|
-
const {
|
|
516
|
-
collapsedSize = 0,
|
|
517
|
-
collapsible,
|
|
518
|
-
panelSize,
|
|
519
|
-
} = panelDataHelper(panelDataArray, panelData, layout);
|
|
520
|
-
|
|
521
|
-
assert(
|
|
522
|
-
panelSize != null,
|
|
523
|
-
`Panel size not found for panel "${panelData.id}"`
|
|
524
|
-
);
|
|
525
|
-
|
|
526
|
-
return !collapsible || fuzzyCompareNumbers(panelSize, collapsedSize) > 0;
|
|
527
|
-
}, []);
|
|
528
|
-
|
|
529
|
-
const registerPanel = useCallback(
|
|
530
|
-
(panelData: PanelData) => {
|
|
531
|
-
const { panelDataArray } = eagerValuesRef.current;
|
|
532
|
-
|
|
533
|
-
panelDataArray.push(panelData);
|
|
534
|
-
panelDataArray.sort((panelA, panelB) => {
|
|
535
|
-
const orderA = panelA.order;
|
|
536
|
-
const orderB = panelB.order;
|
|
537
|
-
if (orderA == null && orderB == null) {
|
|
538
|
-
return 0;
|
|
539
|
-
} else if (orderA == null) {
|
|
540
|
-
return -1;
|
|
541
|
-
} else if (orderB == null) {
|
|
542
|
-
return 1;
|
|
543
|
-
} else {
|
|
544
|
-
return orderA - orderB;
|
|
545
|
-
}
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
eagerValuesRef.current.panelDataArrayChanged = true;
|
|
549
|
-
|
|
550
|
-
forceUpdate();
|
|
551
|
-
},
|
|
552
|
-
[forceUpdate]
|
|
553
|
-
);
|
|
554
|
-
|
|
555
|
-
// (Re)calculate group layout whenever panels are registered or unregistered.
|
|
556
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
557
|
-
useIsomorphicLayoutEffect(() => {
|
|
558
|
-
if (eagerValuesRef.current.panelDataArrayChanged) {
|
|
559
|
-
eagerValuesRef.current.panelDataArrayChanged = false;
|
|
560
|
-
|
|
561
|
-
const { autoSaveId, onLayout, storage } = committedValuesRef.current;
|
|
562
|
-
const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
|
|
563
|
-
|
|
564
|
-
// If this panel has been configured to persist sizing information,
|
|
565
|
-
// default size should be restored from local storage if possible.
|
|
566
|
-
let unsafeLayout: number[] | null = null;
|
|
567
|
-
if (autoSaveId) {
|
|
568
|
-
const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
|
|
569
|
-
if (state) {
|
|
570
|
-
panelSizeBeforeCollapseRef.current = new Map(
|
|
571
|
-
Object.entries(state.expandToSizes)
|
|
572
|
-
);
|
|
573
|
-
unsafeLayout = state.layout;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
if (unsafeLayout == null) {
|
|
578
|
-
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
579
|
-
panelDataArray,
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// Validate even saved layouts in case something has changed since last render
|
|
584
|
-
// e.g. for pixel groups, this could be the size of the window
|
|
585
|
-
const nextLayout = validatePanelGroupLayout({
|
|
586
|
-
layout: unsafeLayout,
|
|
587
|
-
panelConstraints: panelDataArray.map(
|
|
588
|
-
(panelData) => panelData.constraints
|
|
589
|
-
),
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
if (!areEqual(prevLayout, nextLayout)) {
|
|
593
|
-
setLayout(nextLayout);
|
|
594
|
-
|
|
595
|
-
eagerValuesRef.current.layout = nextLayout;
|
|
596
|
-
|
|
597
|
-
if (onLayout) {
|
|
598
|
-
onLayout(nextLayout);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
callPanelCallbacks(
|
|
602
|
-
panelDataArray,
|
|
603
|
-
nextLayout,
|
|
604
|
-
panelIdToLastNotifiedSizeMapRef.current
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
// Reset the cached layout if hidden by the Activity/Offscreen API
|
|
611
|
-
useIsomorphicLayoutEffect(() => {
|
|
612
|
-
const eagerValues = eagerValuesRef.current;
|
|
613
|
-
return () => {
|
|
614
|
-
eagerValues.layout = [];
|
|
615
|
-
};
|
|
616
|
-
}, []);
|
|
617
|
-
|
|
618
|
-
const registerResizeHandle = useCallback((dragHandleId: string) => {
|
|
619
|
-
let isRTL = false;
|
|
620
|
-
|
|
621
|
-
const panelGroupElement = panelGroupElementRef.current;
|
|
622
|
-
if (panelGroupElement) {
|
|
623
|
-
const style = window.getComputedStyle(panelGroupElement, null);
|
|
624
|
-
if (style.getPropertyValue("direction") === "rtl") {
|
|
625
|
-
isRTL = true;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
return function resizeHandler(event: ResizeEvent) {
|
|
630
|
-
event.preventDefault();
|
|
631
|
-
|
|
632
|
-
const panelGroupElement = panelGroupElementRef.current;
|
|
633
|
-
if (!panelGroupElement) {
|
|
634
|
-
return () => null;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
const {
|
|
638
|
-
direction,
|
|
639
|
-
dragState,
|
|
640
|
-
id: groupId,
|
|
641
|
-
keyboardResizeBy,
|
|
642
|
-
onLayout,
|
|
643
|
-
} = committedValuesRef.current;
|
|
644
|
-
const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
|
|
645
|
-
|
|
646
|
-
const { initialLayout } = dragState ?? {};
|
|
647
|
-
|
|
648
|
-
const pivotIndices = determinePivotIndices(
|
|
649
|
-
groupId,
|
|
650
|
-
dragHandleId,
|
|
651
|
-
panelGroupElement
|
|
652
|
-
);
|
|
653
|
-
|
|
654
|
-
let delta = calculateDeltaPercentage(
|
|
655
|
-
event,
|
|
656
|
-
dragHandleId,
|
|
657
|
-
direction,
|
|
658
|
-
dragState,
|
|
659
|
-
keyboardResizeBy,
|
|
660
|
-
panelGroupElement
|
|
661
|
-
);
|
|
662
|
-
|
|
663
|
-
const isHorizontal = direction === "horizontal";
|
|
664
|
-
|
|
665
|
-
if (isHorizontal && isRTL) {
|
|
666
|
-
delta = -delta;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
const panelConstraints = panelDataArray.map(
|
|
670
|
-
(panelData) => panelData.constraints
|
|
671
|
-
);
|
|
672
|
-
|
|
673
|
-
const nextLayout = adjustLayoutByDelta({
|
|
674
|
-
delta,
|
|
675
|
-
initialLayout: initialLayout ?? prevLayout,
|
|
676
|
-
panelConstraints,
|
|
677
|
-
pivotIndices,
|
|
678
|
-
prevLayout,
|
|
679
|
-
trigger: isKeyDown(event) ? "keyboard" : "mouse-or-touch",
|
|
680
|
-
});
|
|
681
|
-
|
|
682
|
-
const layoutChanged = !compareLayouts(prevLayout, nextLayout);
|
|
683
|
-
|
|
684
|
-
// Only update the cursor for layout changes triggered by touch/mouse events (not keyboard)
|
|
685
|
-
// Update the cursor even if the layout hasn't changed (we may need to show an invalid cursor state)
|
|
686
|
-
if (isPointerEvent(event) || isMouseEvent(event)) {
|
|
687
|
-
// Watch for multiple subsequent deltas; this might occur for tiny cursor movements.
|
|
688
|
-
// In this case, Panel sizes might not change–
|
|
689
|
-
// but updating cursor in this scenario would cause a flicker.
|
|
690
|
-
if (prevDeltaRef.current != delta) {
|
|
691
|
-
prevDeltaRef.current = delta;
|
|
692
|
-
|
|
693
|
-
if (!layoutChanged && delta !== 0) {
|
|
694
|
-
// If the pointer has moved too far to resize the panel any further, note this so we can update the cursor.
|
|
695
|
-
// This mimics VS Code behavior.
|
|
696
|
-
if (isHorizontal) {
|
|
697
|
-
reportConstraintsViolation(
|
|
698
|
-
dragHandleId,
|
|
699
|
-
delta < 0 ? EXCEEDED_HORIZONTAL_MIN : EXCEEDED_HORIZONTAL_MAX
|
|
700
|
-
);
|
|
701
|
-
} else {
|
|
702
|
-
reportConstraintsViolation(
|
|
703
|
-
dragHandleId,
|
|
704
|
-
delta < 0 ? EXCEEDED_VERTICAL_MIN : EXCEEDED_VERTICAL_MAX
|
|
705
|
-
);
|
|
706
|
-
}
|
|
707
|
-
} else {
|
|
708
|
-
reportConstraintsViolation(dragHandleId, 0);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
if (layoutChanged) {
|
|
714
|
-
setLayout(nextLayout);
|
|
715
|
-
|
|
716
|
-
eagerValuesRef.current.layout = nextLayout;
|
|
717
|
-
|
|
718
|
-
if (onLayout) {
|
|
719
|
-
onLayout(nextLayout);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
callPanelCallbacks(
|
|
723
|
-
panelDataArray,
|
|
724
|
-
nextLayout,
|
|
725
|
-
panelIdToLastNotifiedSizeMapRef.current
|
|
726
|
-
);
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
}, []);
|
|
730
|
-
|
|
731
|
-
// External APIs are safe to memoize via committed values ref
|
|
732
|
-
const resizePanel = useCallback(
|
|
733
|
-
(panelData: PanelData, unsafePanelSize: number) => {
|
|
734
|
-
const { onLayout } = committedValuesRef.current;
|
|
735
|
-
|
|
736
|
-
const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
|
|
737
|
-
|
|
738
|
-
const panelConstraintsArray = panelDataArray.map(
|
|
739
|
-
(panelData) => panelData.constraints
|
|
740
|
-
);
|
|
741
|
-
|
|
742
|
-
const { panelSize, pivotIndices } = panelDataHelper(
|
|
743
|
-
panelDataArray,
|
|
744
|
-
panelData,
|
|
745
|
-
prevLayout
|
|
746
|
-
);
|
|
747
|
-
|
|
748
|
-
assert(
|
|
749
|
-
panelSize != null,
|
|
750
|
-
`Panel size not found for panel "${panelData.id}"`
|
|
751
|
-
);
|
|
752
|
-
|
|
753
|
-
const isLastPanel =
|
|
754
|
-
findPanelDataIndex(panelDataArray, panelData) ===
|
|
755
|
-
panelDataArray.length - 1;
|
|
756
|
-
const delta = isLastPanel
|
|
757
|
-
? panelSize - unsafePanelSize
|
|
758
|
-
: unsafePanelSize - panelSize;
|
|
759
|
-
|
|
760
|
-
const nextLayout = adjustLayoutByDelta({
|
|
761
|
-
delta,
|
|
762
|
-
initialLayout: prevLayout,
|
|
763
|
-
panelConstraints: panelConstraintsArray,
|
|
764
|
-
pivotIndices,
|
|
765
|
-
prevLayout,
|
|
766
|
-
trigger: "imperative-api",
|
|
767
|
-
});
|
|
768
|
-
|
|
769
|
-
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
770
|
-
setLayout(nextLayout);
|
|
771
|
-
|
|
772
|
-
eagerValuesRef.current.layout = nextLayout;
|
|
773
|
-
|
|
774
|
-
if (onLayout) {
|
|
775
|
-
onLayout(nextLayout);
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
callPanelCallbacks(
|
|
779
|
-
panelDataArray,
|
|
780
|
-
nextLayout,
|
|
781
|
-
panelIdToLastNotifiedSizeMapRef.current
|
|
782
|
-
);
|
|
783
|
-
}
|
|
784
|
-
},
|
|
785
|
-
[]
|
|
786
|
-
);
|
|
787
|
-
|
|
788
|
-
const reevaluatePanelConstraints = useCallback(
|
|
789
|
-
(panelData: PanelData, prevConstraints: PanelConstraints) => {
|
|
790
|
-
const { layout, panelDataArray } = eagerValuesRef.current;
|
|
791
|
-
|
|
792
|
-
const {
|
|
793
|
-
collapsedSize: prevCollapsedSize = 0,
|
|
794
|
-
collapsible: prevCollapsible,
|
|
795
|
-
} = prevConstraints;
|
|
796
|
-
|
|
797
|
-
const {
|
|
798
|
-
collapsedSize: nextCollapsedSize = 0,
|
|
799
|
-
collapsible: nextCollapsible,
|
|
800
|
-
maxSize: nextMaxSize = 100,
|
|
801
|
-
minSize: nextMinSize = 0,
|
|
802
|
-
} = panelData.constraints;
|
|
803
|
-
|
|
804
|
-
const { panelSize: prevPanelSize } = panelDataHelper(
|
|
805
|
-
panelDataArray,
|
|
806
|
-
panelData,
|
|
807
|
-
layout
|
|
808
|
-
);
|
|
809
|
-
if (prevPanelSize == null) {
|
|
810
|
-
// It's possible that the panels in this group have changed since the last render
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
if (
|
|
815
|
-
prevCollapsible &&
|
|
816
|
-
nextCollapsible &&
|
|
817
|
-
fuzzyNumbersEqual(prevPanelSize, prevCollapsedSize)
|
|
818
|
-
) {
|
|
819
|
-
if (!fuzzyNumbersEqual(prevCollapsedSize, nextCollapsedSize)) {
|
|
820
|
-
resizePanel(panelData, nextCollapsedSize);
|
|
821
|
-
} else {
|
|
822
|
-
// Stay collapsed
|
|
823
|
-
}
|
|
824
|
-
} else if (prevPanelSize < nextMinSize) {
|
|
825
|
-
resizePanel(panelData, nextMinSize);
|
|
826
|
-
} else if (prevPanelSize > nextMaxSize) {
|
|
827
|
-
resizePanel(panelData, nextMaxSize);
|
|
828
|
-
}
|
|
829
|
-
},
|
|
830
|
-
[resizePanel]
|
|
831
|
-
);
|
|
832
|
-
|
|
833
|
-
// TODO Multiple drag handles can be active at the same time so this API is a bit awkward now
|
|
834
|
-
const startDragging = useCallback(
|
|
835
|
-
(dragHandleId: string, event: ResizeEvent) => {
|
|
836
|
-
const { direction } = committedValuesRef.current;
|
|
837
|
-
const { layout } = eagerValuesRef.current;
|
|
838
|
-
if (!panelGroupElementRef.current) {
|
|
839
|
-
return;
|
|
840
|
-
}
|
|
841
|
-
const handleElement = getResizeHandleElement(
|
|
842
|
-
dragHandleId,
|
|
843
|
-
panelGroupElementRef.current
|
|
844
|
-
);
|
|
845
|
-
assert(
|
|
846
|
-
handleElement,
|
|
847
|
-
`Drag handle element not found for id "${dragHandleId}"`
|
|
848
|
-
);
|
|
849
|
-
|
|
850
|
-
const initialCursorPosition = getResizeEventCursorPosition(
|
|
851
|
-
direction,
|
|
852
|
-
event
|
|
853
|
-
);
|
|
854
|
-
|
|
855
|
-
setDragState({
|
|
856
|
-
dragHandleId,
|
|
857
|
-
dragHandleRect: handleElement.getBoundingClientRect(),
|
|
858
|
-
initialCursorPosition,
|
|
859
|
-
initialLayout: layout,
|
|
860
|
-
});
|
|
861
|
-
},
|
|
862
|
-
[]
|
|
863
|
-
);
|
|
864
|
-
|
|
865
|
-
const stopDragging = useCallback(() => {
|
|
866
|
-
setDragState(null);
|
|
867
|
-
}, []);
|
|
868
|
-
|
|
869
|
-
const unregisterPanel = useCallback(
|
|
870
|
-
(panelData: PanelData) => {
|
|
871
|
-
const { panelDataArray } = eagerValuesRef.current;
|
|
872
|
-
|
|
873
|
-
const index = findPanelDataIndex(panelDataArray, panelData);
|
|
874
|
-
if (index >= 0) {
|
|
875
|
-
panelDataArray.splice(index, 1);
|
|
876
|
-
|
|
877
|
-
// TRICKY
|
|
878
|
-
// When a panel is removed from the group, we should delete the most recent prev-size entry for it.
|
|
879
|
-
// If we don't do this, then a conditionally rendered panel might not call onResize when it's re-mounted.
|
|
880
|
-
// Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
|
|
881
|
-
delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
|
|
882
|
-
|
|
883
|
-
eagerValuesRef.current.panelDataArrayChanged = true;
|
|
884
|
-
|
|
885
|
-
forceUpdate();
|
|
886
|
-
}
|
|
887
|
-
},
|
|
888
|
-
[forceUpdate]
|
|
889
|
-
);
|
|
890
|
-
|
|
891
|
-
const context = useMemo(
|
|
892
|
-
() =>
|
|
893
|
-
({
|
|
894
|
-
collapsePanel,
|
|
895
|
-
direction,
|
|
896
|
-
dragState,
|
|
897
|
-
expandPanel,
|
|
898
|
-
getPanelSize,
|
|
899
|
-
getPanelStyle,
|
|
900
|
-
groupId,
|
|
901
|
-
isPanelCollapsed,
|
|
902
|
-
isPanelExpanded,
|
|
903
|
-
reevaluatePanelConstraints,
|
|
904
|
-
registerPanel,
|
|
905
|
-
registerResizeHandle,
|
|
906
|
-
resizePanel,
|
|
907
|
-
startDragging,
|
|
908
|
-
stopDragging,
|
|
909
|
-
unregisterPanel,
|
|
910
|
-
panelGroupElement: panelGroupElementRef.current,
|
|
911
|
-
}) satisfies TPanelGroupContext,
|
|
912
|
-
[
|
|
913
|
-
collapsePanel,
|
|
914
|
-
dragState,
|
|
915
|
-
direction,
|
|
916
|
-
expandPanel,
|
|
917
|
-
getPanelSize,
|
|
918
|
-
getPanelStyle,
|
|
919
|
-
groupId,
|
|
920
|
-
isPanelCollapsed,
|
|
921
|
-
isPanelExpanded,
|
|
922
|
-
reevaluatePanelConstraints,
|
|
923
|
-
registerPanel,
|
|
924
|
-
registerResizeHandle,
|
|
925
|
-
resizePanel,
|
|
926
|
-
startDragging,
|
|
927
|
-
stopDragging,
|
|
928
|
-
unregisterPanel,
|
|
929
|
-
]
|
|
930
|
-
);
|
|
931
|
-
|
|
932
|
-
const style: CSSProperties = {
|
|
933
|
-
display: "flex",
|
|
934
|
-
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
935
|
-
height: "100%",
|
|
936
|
-
overflow: "hidden",
|
|
937
|
-
width: "100%",
|
|
938
|
-
};
|
|
939
|
-
|
|
940
|
-
return createElement(
|
|
941
|
-
PanelGroupContext.Provider,
|
|
942
|
-
{ value: context },
|
|
943
|
-
createElement(Type, {
|
|
944
|
-
...rest,
|
|
945
|
-
|
|
946
|
-
children,
|
|
947
|
-
className: classNameFromProps,
|
|
948
|
-
id: idFromProps,
|
|
949
|
-
ref: panelGroupElementRef,
|
|
950
|
-
style: {
|
|
951
|
-
...style,
|
|
952
|
-
...styleFromProps,
|
|
953
|
-
},
|
|
954
|
-
|
|
955
|
-
// CSS selectors
|
|
956
|
-
"data-panel-group": "",
|
|
957
|
-
"data-panel-group-direction": direction,
|
|
958
|
-
"data-panel-group-id": groupId,
|
|
959
|
-
})
|
|
960
|
-
);
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
export const PanelGroup = forwardRef<
|
|
964
|
-
ImperativePanelGroupHandle,
|
|
965
|
-
PanelGroupProps
|
|
966
|
-
>((props: PanelGroupProps, ref: ForwardedRef<ImperativePanelGroupHandle>) =>
|
|
967
|
-
createElement(PanelGroupWithForwardedRef, { ...props, forwardedRef: ref })
|
|
968
|
-
);
|
|
969
|
-
|
|
970
|
-
PanelGroupWithForwardedRef.displayName = "PanelGroup";
|
|
971
|
-
PanelGroup.displayName = "forwardRef(PanelGroup)";
|
|
972
|
-
|
|
973
|
-
function findPanelDataIndex(panelDataArray: PanelData[], panelData: PanelData) {
|
|
974
|
-
return panelDataArray.findIndex(
|
|
975
|
-
(prevPanelData) =>
|
|
976
|
-
prevPanelData === panelData || prevPanelData.id === panelData.id
|
|
977
|
-
);
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
function panelDataHelper(
|
|
981
|
-
panelDataArray: PanelData[],
|
|
982
|
-
panelData: PanelData,
|
|
983
|
-
layout: number[]
|
|
984
|
-
) {
|
|
985
|
-
const panelIndex = findPanelDataIndex(panelDataArray, panelData);
|
|
986
|
-
|
|
987
|
-
const isLastPanel = panelIndex === panelDataArray.length - 1;
|
|
988
|
-
const pivotIndices = isLastPanel
|
|
989
|
-
? [panelIndex - 1, panelIndex]
|
|
990
|
-
: [panelIndex, panelIndex + 1];
|
|
991
|
-
|
|
992
|
-
const panelSize = layout[panelIndex];
|
|
993
|
-
|
|
994
|
-
return {
|
|
995
|
-
...panelData.constraints,
|
|
996
|
-
panelSize,
|
|
997
|
-
pivotIndices,
|
|
998
|
-
};
|
|
999
|
-
}
|