react-resizable-panels 0.0.55 → 0.0.57
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/.eslintrc.cjs +26 -0
- package/CHANGELOG.md +238 -90
- package/README.md +55 -49
- package/dist/declarations/src/Panel.d.ts +75 -20
- package/dist/declarations/src/PanelGroup.d.ts +29 -25
- package/dist/declarations/src/PanelResizeHandle.d.ts +1 -1
- package/dist/declarations/src/index.d.ts +5 -6
- package/dist/declarations/src/types.d.ts +3 -26
- package/dist/declarations/src/vendor/react.d.ts +4 -4
- package/dist/react-resizable-panels.browser.cjs.js +1276 -1043
- package/dist/react-resizable-panels.browser.cjs.mjs +1 -2
- package/dist/react-resizable-panels.browser.development.cjs.js +1410 -1097
- package/dist/react-resizable-panels.browser.development.cjs.mjs +1 -2
- package/dist/react-resizable-panels.browser.development.esm.js +1411 -1097
- package/dist/react-resizable-panels.browser.esm.js +1277 -1043
- package/dist/react-resizable-panels.cjs.js +1276 -1043
- package/dist/react-resizable-panels.cjs.js.map +1 -1
- package/dist/react-resizable-panels.cjs.mjs +1 -2
- package/dist/react-resizable-panels.development.cjs.js +1415 -1102
- package/dist/react-resizable-panels.development.cjs.mjs +1 -2
- package/dist/react-resizable-panels.development.esm.js +1416 -1102
- package/dist/react-resizable-panels.development.node.cjs.js +1179 -947
- package/dist/react-resizable-panels.development.node.cjs.mjs +1 -2
- package/dist/react-resizable-panels.development.node.esm.js +1180 -947
- package/dist/react-resizable-panels.esm.js +1277 -1043
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +1068 -910
- package/dist/react-resizable-panels.node.cjs.mjs +1 -2
- package/dist/react-resizable-panels.node.esm.js +1069 -910
- package/jest.config.js +10 -0
- package/package.json +5 -1
- package/src/Panel.test.tsx +308 -0
- package/src/Panel.ts +175 -123
- package/src/PanelGroup.test.tsx +210 -0
- package/src/PanelGroup.ts +730 -667
- package/src/PanelGroupContext.ts +33 -0
- package/src/PanelResizeHandle.ts +21 -17
- package/src/hooks/useUniqueId.ts +1 -1
- package/src/hooks/useWindowSplitterBehavior.ts +9 -164
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +185 -0
- package/src/index.ts +19 -14
- package/src/types.ts +3 -30
- package/src/utils/adjustLayoutByDelta.test.ts +1808 -0
- package/src/utils/adjustLayoutByDelta.ts +211 -0
- package/src/utils/calculateAriaValues.test.ts +111 -0
- package/src/utils/calculateAriaValues.ts +67 -0
- package/src/utils/calculateDeltaPercentage.ts +68 -0
- package/src/utils/calculateDragOffsetPercentage.ts +30 -0
- package/src/utils/calculateUnsafeDefaultLayout.test.ts +92 -0
- package/src/utils/calculateUnsafeDefaultLayout.ts +55 -0
- package/src/utils/callPanelCallbacks.ts +81 -0
- package/src/utils/compareLayouts.test.ts +9 -0
- package/src/utils/compareLayouts.ts +12 -0
- package/src/utils/computePanelFlexBoxStyle.ts +44 -0
- package/src/utils/computePercentagePanelConstraints.test.ts +98 -0
- package/src/utils/computePercentagePanelConstraints.ts +56 -0
- package/src/utils/convertPercentageToPixels.test.ts +9 -0
- package/src/utils/convertPercentageToPixels.ts +6 -0
- package/src/utils/convertPixelConstraintsToPercentages.test.ts +47 -0
- package/src/utils/convertPixelConstraintsToPercentages.ts +72 -0
- package/src/utils/convertPixelsToPercentage.test.ts +9 -0
- package/src/utils/convertPixelsToPercentage.ts +6 -0
- package/src/utils/determinePivotIndices.ts +10 -0
- package/src/utils/dom/calculateAvailablePanelSizeInPixels.ts +29 -0
- package/src/utils/dom/getAvailableGroupSizePixels.ts +29 -0
- package/src/utils/dom/getPanelElement.ts +7 -0
- package/src/utils/dom/getPanelGroupElement.ts +9 -0
- package/src/utils/dom/getResizeHandleElement.ts +9 -0
- package/src/utils/dom/getResizeHandleElementIndex.ts +12 -0
- package/src/utils/dom/getResizeHandleElementsForGroup.ts +9 -0
- package/src/utils/dom/getResizeHandlePanelIds.ts +18 -0
- package/src/utils/events.ts +13 -0
- package/src/utils/getPercentageSizeFromMixedSizes.test.ts +47 -0
- package/src/utils/getPercentageSizeFromMixedSizes.ts +15 -0
- package/src/utils/getResizeEventCursorPosition.ts +19 -0
- package/src/utils/initializeDefaultStorage.ts +26 -0
- package/src/utils/numbers/fuzzyCompareNumbers.test.ts +16 -0
- package/src/utils/numbers/fuzzyCompareNumbers.ts +17 -0
- package/src/utils/numbers/fuzzyNumbersEqual.ts +9 -0
- package/src/utils/resizePanel.test.ts +45 -0
- package/src/utils/resizePanel.ts +60 -0
- package/src/utils/serialization.ts +9 -4
- package/src/utils/shouldMonitorPixelBasedConstraints.test.ts +23 -0
- package/src/utils/shouldMonitorPixelBasedConstraints.ts +13 -0
- package/src/utils/test-utils.ts +136 -0
- package/src/utils/validatePanelConstraints.test.ts +151 -0
- package/src/utils/validatePanelConstraints.ts +103 -0
- package/src/utils/validatePanelGroupLayout.test.ts +233 -0
- package/src/utils/validatePanelGroupLayout.ts +88 -0
- package/src/vendor/react.ts +4 -0
- package/.eslintrc.json +0 -22
- package/dist/declarations/src/utils/group.d.ts +0 -29
- package/src/PanelContexts.ts +0 -22
- package/src/utils/coordinates.ts +0 -149
- package/src/utils/group.ts +0 -614
package/src/PanelGroup.ts
CHANGED
|
@@ -1,12 +1,40 @@
|
|
|
1
|
-
import { isBrowser } from "#is-browser";
|
|
2
1
|
import { isDevelopment } from "#is-development";
|
|
2
|
+
import { PanelData } from "./Panel";
|
|
3
|
+
import { DragState, PanelGroupContext, ResizeEvent } from "./PanelGroupContext";
|
|
4
|
+
import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
|
|
5
|
+
import useUniqueId from "./hooks/useUniqueId";
|
|
6
|
+
import { useWindowSplitterPanelGroupBehavior } from "./hooks/useWindowSplitterPanelGroupBehavior";
|
|
7
|
+
import { Direction, MixedSizes } from "./types";
|
|
8
|
+
import { adjustLayoutByDelta } from "./utils/adjustLayoutByDelta";
|
|
9
|
+
import { areEqual } from "./utils/arrays";
|
|
10
|
+
import { calculateDeltaPercentage } from "./utils/calculateDeltaPercentage";
|
|
11
|
+
import { calculateUnsafeDefaultLayout } from "./utils/calculateUnsafeDefaultLayout";
|
|
12
|
+
import { callPanelCallbacks } from "./utils/callPanelCallbacks";
|
|
13
|
+
import { compareLayouts } from "./utils/compareLayouts";
|
|
14
|
+
import { computePanelFlexBoxStyle } from "./utils/computePanelFlexBoxStyle";
|
|
15
|
+
import { computePercentagePanelConstraints } from "./utils/computePercentagePanelConstraints";
|
|
16
|
+
import { convertPercentageToPixels } from "./utils/convertPercentageToPixels";
|
|
17
|
+
import { resetGlobalCursorStyle, setGlobalCursorStyle } from "./utils/cursor";
|
|
18
|
+
import debounce from "./utils/debounce";
|
|
19
|
+
import { determinePivotIndices } from "./utils/determinePivotIndices";
|
|
20
|
+
import { calculateAvailablePanelSizeInPixels } from "./utils/dom/calculateAvailablePanelSizeInPixels";
|
|
21
|
+
import { getPanelGroupElement } from "./utils/dom/getPanelGroupElement";
|
|
22
|
+
import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement";
|
|
23
|
+
import { isKeyDown, isMouseEvent, isTouchEvent } from "./utils/events";
|
|
24
|
+
import { getPercentageSizeFromMixedSizes } from "./utils/getPercentageSizeFromMixedSizes";
|
|
25
|
+
import { getResizeEventCursorPosition } from "./utils/getResizeEventCursorPosition";
|
|
26
|
+
import { initializeDefaultStorage } from "./utils/initializeDefaultStorage";
|
|
27
|
+
import { loadPanelLayout, savePanelGroupLayout } from "./utils/serialization";
|
|
28
|
+
import { shouldMonitorPixelBasedConstraints } from "./utils/shouldMonitorPixelBasedConstraints";
|
|
29
|
+
import { validatePanelConstraints } from "./utils/validatePanelConstraints";
|
|
30
|
+
import { validatePanelGroupLayout } from "./utils/validatePanelGroupLayout";
|
|
3
31
|
import {
|
|
4
|
-
createElement,
|
|
5
32
|
CSSProperties,
|
|
6
33
|
ElementType,
|
|
7
34
|
ForwardedRef,
|
|
35
|
+
PropsWithChildren,
|
|
36
|
+
createElement,
|
|
8
37
|
forwardRef,
|
|
9
|
-
ReactNode,
|
|
10
38
|
useCallback,
|
|
11
39
|
useEffect,
|
|
12
40
|
useImperativeHandle,
|
|
@@ -15,76 +43,20 @@ import {
|
|
|
15
43
|
useState,
|
|
16
44
|
} from "./vendor/react";
|
|
17
45
|
|
|
18
|
-
|
|
19
|
-
import useUniqueId from "./hooks/useUniqueId";
|
|
20
|
-
import { useWindowSplitterPanelGroupBehavior } from "./hooks/useWindowSplitterBehavior";
|
|
21
|
-
import { PanelGroupContext } from "./PanelContexts";
|
|
22
|
-
import {
|
|
23
|
-
Direction,
|
|
24
|
-
PanelData,
|
|
25
|
-
PanelGroupOnLayout,
|
|
26
|
-
PanelGroupStorage,
|
|
27
|
-
ResizeEvent,
|
|
28
|
-
Units,
|
|
29
|
-
} from "./types";
|
|
30
|
-
import { areEqual } from "./utils/arrays";
|
|
31
|
-
import {
|
|
32
|
-
getDragOffset,
|
|
33
|
-
getMovement,
|
|
34
|
-
isMouseEvent,
|
|
35
|
-
isTouchEvent,
|
|
36
|
-
} from "./utils/coordinates";
|
|
37
|
-
import { resetGlobalCursorStyle, setGlobalCursorStyle } from "./utils/cursor";
|
|
38
|
-
import debounce from "./utils/debounce";
|
|
39
|
-
import {
|
|
40
|
-
adjustByDelta,
|
|
41
|
-
calculateDefaultLayout,
|
|
42
|
-
callPanelCallbacks,
|
|
43
|
-
getAvailableGroupSizePixels,
|
|
44
|
-
getBeforeAndAfterIds,
|
|
45
|
-
getFlexGrow,
|
|
46
|
-
getPanelGroup,
|
|
47
|
-
getResizeHandle,
|
|
48
|
-
getResizeHandlePanelIds,
|
|
49
|
-
panelsMapToSortedArray,
|
|
50
|
-
validatePanelGroupLayout,
|
|
51
|
-
validatePanelProps,
|
|
52
|
-
} from "./utils/group";
|
|
53
|
-
import { loadPanelLayout, savePanelGroupLayout } from "./utils/serialization";
|
|
46
|
+
const LOCAL_STORAGE_DEBOUNCE_INTERVAL = 100;
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
storage: PanelGroupStorage
|
|
61
|
-
) => void;
|
|
62
|
-
} = {};
|
|
48
|
+
export type ImperativePanelGroupHandle = {
|
|
49
|
+
getId: () => string;
|
|
50
|
+
getLayout: () => MixedSizes[];
|
|
51
|
+
setLayout: (layout: Partial<MixedSizes>[]) => void;
|
|
52
|
+
};
|
|
63
53
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
function initializeDefaultStorage(storageObject: PanelGroupStorage) {
|
|
69
|
-
try {
|
|
70
|
-
if (typeof localStorage !== "undefined") {
|
|
71
|
-
// Bypass this check for future calls
|
|
72
|
-
storageObject.getItem = (name: string) => {
|
|
73
|
-
return localStorage.getItem(name);
|
|
74
|
-
};
|
|
75
|
-
storageObject.setItem = (name: string, value: string) => {
|
|
76
|
-
localStorage.setItem(name, value);
|
|
77
|
-
};
|
|
78
|
-
} else {
|
|
79
|
-
throw new Error("localStorage not supported in this environment");
|
|
80
|
-
}
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error(error);
|
|
54
|
+
export type PanelGroupStorage = {
|
|
55
|
+
getItem(name: string): string | null;
|
|
56
|
+
setItem(name: string, value: string): void;
|
|
57
|
+
};
|
|
83
58
|
|
|
84
|
-
|
|
85
|
-
storageObject.setItem = () => {};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
59
|
+
export type PanelGroupOnLayout = (layout: MixedSizes[]) => void;
|
|
88
60
|
|
|
89
61
|
const defaultStorage: PanelGroupStorage = {
|
|
90
62
|
getItem: (name: string) => {
|
|
@@ -97,271 +69,319 @@ const defaultStorage: PanelGroupStorage = {
|
|
|
97
69
|
},
|
|
98
70
|
};
|
|
99
71
|
|
|
100
|
-
export type
|
|
101
|
-
direction: Direction;
|
|
102
|
-
id: string;
|
|
103
|
-
panels: Map<string, PanelData>;
|
|
104
|
-
sizes: number[];
|
|
105
|
-
units: Units;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
export type PanelDataMap = Map<string, PanelData>;
|
|
109
|
-
|
|
110
|
-
// Initial drag state serves a few purposes:
|
|
111
|
-
// * dragOffset:
|
|
112
|
-
// Resize is calculated by the distance between the current pointer event and the resize handle being "dragged"
|
|
113
|
-
// This value accounts for the initial offset when the touch/click starts, so the handle doesn't appear to "jump"
|
|
114
|
-
// * dragHandleRect, sizes:
|
|
115
|
-
// When resizing is done via mouse/touch event– some initial state is stored
|
|
116
|
-
// so that any panels that contract will also expand if drag direction is reversed.
|
|
117
|
-
export type InitialDragState = {
|
|
118
|
-
dragHandleRect: DOMRect;
|
|
119
|
-
dragOffset: number;
|
|
120
|
-
sizes: number[];
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
export type PanelGroupProps = {
|
|
72
|
+
export type PanelGroupProps = PropsWithChildren<{
|
|
124
73
|
autoSaveId?: string;
|
|
125
|
-
children?: ReactNode;
|
|
126
74
|
className?: string;
|
|
127
75
|
direction: Direction;
|
|
128
|
-
disablePointerEventsDuringResize?: boolean;
|
|
129
76
|
id?: string | null;
|
|
130
|
-
|
|
77
|
+
keyboardResizeByPercentage?: number | null;
|
|
78
|
+
keyboardResizeByPixels?: number | null;
|
|
79
|
+
onLayout?: PanelGroupOnLayout | null;
|
|
131
80
|
storage?: PanelGroupStorage;
|
|
132
81
|
style?: CSSProperties;
|
|
133
82
|
tagName?: ElementType;
|
|
134
|
-
|
|
135
|
-
};
|
|
83
|
+
}>;
|
|
136
84
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
setLayout: (panelSizes: number[], units?: Units) => void;
|
|
141
|
-
};
|
|
85
|
+
const debounceMap: {
|
|
86
|
+
[key: string]: typeof savePanelGroupLayout;
|
|
87
|
+
} = {};
|
|
142
88
|
|
|
143
89
|
function PanelGroupWithForwardedRef({
|
|
144
90
|
autoSaveId,
|
|
145
|
-
children
|
|
91
|
+
children,
|
|
146
92
|
className: classNameFromProps = "",
|
|
147
93
|
direction,
|
|
148
|
-
disablePointerEventsDuringResize = false,
|
|
149
94
|
forwardedRef,
|
|
150
|
-
id: idFromProps
|
|
151
|
-
onLayout,
|
|
95
|
+
id: idFromProps,
|
|
96
|
+
onLayout = null,
|
|
97
|
+
keyboardResizeByPercentage = null,
|
|
98
|
+
keyboardResizeByPixels = null,
|
|
152
99
|
storage = defaultStorage,
|
|
153
|
-
style: styleFromProps
|
|
100
|
+
style: styleFromProps,
|
|
154
101
|
tagName: Type = "div",
|
|
155
|
-
units = "percentages",
|
|
156
102
|
}: PanelGroupProps & {
|
|
157
103
|
forwardedRef: ForwardedRef<ImperativePanelGroupHandle>;
|
|
158
104
|
}) {
|
|
159
105
|
const groupId = useUniqueId(idFromProps);
|
|
160
106
|
|
|
161
|
-
const [
|
|
162
|
-
const [
|
|
107
|
+
const [dragState, setDragState] = useState<DragState | null>(null);
|
|
108
|
+
const [layout, setLayout] = useState<number[]>([]);
|
|
109
|
+
const [panelDataArray, setPanelDataArray] = useState<PanelData[]>([]);
|
|
163
110
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const
|
|
111
|
+
const panelIdToLastNotifiedMixedSizesMapRef = useRef<
|
|
112
|
+
Record<string, MixedSizes>
|
|
113
|
+
>({});
|
|
114
|
+
const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
|
|
115
|
+
const prevDeltaRef = useRef<number>(0);
|
|
116
|
+
|
|
117
|
+
const committedValuesRef = useRef<{
|
|
118
|
+
direction: Direction;
|
|
119
|
+
dragState: DragState | null;
|
|
120
|
+
id: string;
|
|
121
|
+
keyboardResizeByPercentage: number | null;
|
|
122
|
+
keyboardResizeByPixels: number | null;
|
|
123
|
+
layout: number[];
|
|
124
|
+
onLayout: PanelGroupOnLayout | null;
|
|
125
|
+
panelDataArray: PanelData[];
|
|
126
|
+
}>({
|
|
127
|
+
direction,
|
|
128
|
+
dragState,
|
|
129
|
+
id: groupId,
|
|
130
|
+
keyboardResizeByPercentage,
|
|
131
|
+
keyboardResizeByPixels,
|
|
132
|
+
layout,
|
|
133
|
+
onLayout,
|
|
134
|
+
panelDataArray,
|
|
135
|
+
});
|
|
168
136
|
|
|
169
137
|
const devWarningsRef = useRef<{
|
|
170
|
-
didLogDefaultSizeWarning: boolean;
|
|
171
138
|
didLogIdAndOrderWarning: boolean;
|
|
172
|
-
|
|
139
|
+
didLogPanelConstraintsWarning: boolean;
|
|
173
140
|
prevPanelIds: string[];
|
|
174
141
|
}>({
|
|
175
|
-
didLogDefaultSizeWarning: false,
|
|
176
142
|
didLogIdAndOrderWarning: false,
|
|
177
|
-
|
|
143
|
+
didLogPanelConstraintsWarning: false,
|
|
178
144
|
prevPanelIds: [],
|
|
179
145
|
});
|
|
180
146
|
|
|
181
|
-
// Use a ref to guard against users passing inline props
|
|
182
|
-
const callbacksRef = useRef<{
|
|
183
|
-
onLayout: PanelGroupOnLayout | undefined;
|
|
184
|
-
}>({ onLayout });
|
|
185
|
-
useEffect(() => {
|
|
186
|
-
callbacksRef.current.onLayout = onLayout;
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
const panelIdToLastNotifiedSizeMapRef = useRef<Record<string, number>>({});
|
|
190
|
-
|
|
191
|
-
// 0-1 values representing the relative size of each panel.
|
|
192
|
-
const [sizes, setSizes] = useState<number[]>([]);
|
|
193
|
-
|
|
194
|
-
// Used to support imperative collapse/expand API.
|
|
195
|
-
const panelSizeBeforeCollapse = useRef<Map<string, number>>(new Map());
|
|
196
|
-
|
|
197
|
-
const prevDeltaRef = useRef<number>(0);
|
|
198
|
-
|
|
199
|
-
// Store committed values to avoid unnecessarily re-running memoization/effects functions.
|
|
200
|
-
const committedValuesRef = useRef<CommittedValues>({
|
|
201
|
-
direction,
|
|
202
|
-
id: groupId,
|
|
203
|
-
panels,
|
|
204
|
-
sizes,
|
|
205
|
-
units,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
147
|
useImperativeHandle(
|
|
209
148
|
forwardedRef,
|
|
210
149
|
() => ({
|
|
211
|
-
getId: () =>
|
|
212
|
-
getLayout: (
|
|
213
|
-
const {
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
150
|
+
getId: () => committedValuesRef.current.id,
|
|
151
|
+
getLayout: () => {
|
|
152
|
+
const { id: groupId, layout } = committedValuesRef.current;
|
|
153
|
+
|
|
154
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
155
|
+
|
|
156
|
+
return layout.map((sizePercentage) => {
|
|
157
|
+
return {
|
|
158
|
+
sizePercentage,
|
|
159
|
+
sizePixels: convertPercentageToPixels(
|
|
160
|
+
sizePercentage,
|
|
161
|
+
groupSizePixels
|
|
162
|
+
),
|
|
163
|
+
};
|
|
164
|
+
});
|
|
222
165
|
},
|
|
223
|
-
setLayout: (
|
|
166
|
+
setLayout: (mixedSizes: Partial<MixedSizes>[]) => {
|
|
224
167
|
const {
|
|
225
168
|
id: groupId,
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
169
|
+
layout: prevLayout,
|
|
170
|
+
onLayout,
|
|
171
|
+
panelDataArray,
|
|
229
172
|
} = committedValuesRef.current;
|
|
230
173
|
|
|
231
|
-
|
|
232
|
-
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
233
|
-
sizes = sizes.map((size) => (size / groupSizePixels) * 100);
|
|
234
|
-
}
|
|
174
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
235
175
|
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
176
|
+
const unsafeLayout = mixedSizes.map(
|
|
177
|
+
(mixedSize) =>
|
|
178
|
+
getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels)!
|
|
179
|
+
);
|
|
239
180
|
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
181
|
+
const safeLayout = validatePanelGroupLayout({
|
|
182
|
+
groupSizePixels,
|
|
183
|
+
layout: unsafeLayout,
|
|
184
|
+
panelConstraints: panelDataArray.map(
|
|
185
|
+
(panelData) => panelData.constraints
|
|
186
|
+
),
|
|
246
187
|
});
|
|
247
|
-
|
|
248
|
-
|
|
188
|
+
|
|
189
|
+
if (!areEqual(prevLayout, safeLayout)) {
|
|
190
|
+
setLayout(safeLayout);
|
|
191
|
+
|
|
192
|
+
if (onLayout) {
|
|
193
|
+
onLayout(
|
|
194
|
+
safeLayout.map((sizePercentage) => ({
|
|
195
|
+
sizePercentage,
|
|
196
|
+
sizePixels: convertPercentageToPixels(
|
|
197
|
+
sizePercentage,
|
|
198
|
+
groupSizePixels
|
|
199
|
+
),
|
|
200
|
+
}))
|
|
201
|
+
);
|
|
202
|
+
}
|
|
249
203
|
|
|
250
204
|
callPanelCallbacks(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
205
|
+
groupId,
|
|
206
|
+
panelDataArray,
|
|
207
|
+
safeLayout,
|
|
208
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
254
209
|
);
|
|
255
210
|
}
|
|
256
211
|
},
|
|
257
212
|
}),
|
|
258
|
-
[
|
|
213
|
+
[]
|
|
259
214
|
);
|
|
260
215
|
|
|
261
216
|
useIsomorphicLayoutEffect(() => {
|
|
262
217
|
committedValuesRef.current.direction = direction;
|
|
218
|
+
committedValuesRef.current.dragState = dragState;
|
|
263
219
|
committedValuesRef.current.id = groupId;
|
|
264
|
-
committedValuesRef.current.
|
|
265
|
-
committedValuesRef.current.
|
|
266
|
-
committedValuesRef.current.
|
|
220
|
+
committedValuesRef.current.layout = layout;
|
|
221
|
+
committedValuesRef.current.onLayout = onLayout;
|
|
222
|
+
committedValuesRef.current.panelDataArray = panelDataArray;
|
|
267
223
|
});
|
|
268
224
|
|
|
269
225
|
useWindowSplitterPanelGroupBehavior({
|
|
270
226
|
committedValuesRef,
|
|
271
227
|
groupId,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
panelSizeBeforeCollapse,
|
|
228
|
+
layout,
|
|
229
|
+
panelDataArray,
|
|
230
|
+
setLayout,
|
|
276
231
|
});
|
|
277
232
|
|
|
278
|
-
// Notify external code when sizes have changed.
|
|
279
233
|
useEffect(() => {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (sizes.length > 0) {
|
|
285
|
-
if (onLayout) {
|
|
286
|
-
onLayout(sizes);
|
|
234
|
+
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
235
|
+
if (autoSaveId) {
|
|
236
|
+
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
237
|
+
return;
|
|
287
238
|
}
|
|
288
239
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const panelsArray = panelsMapToSortedArray(panels);
|
|
298
|
-
callPanelCallbacks(panelsArray, sizes, panelIdToLastNotifiedSizeMap);
|
|
240
|
+
// Limit the frequency of localStorage updates.
|
|
241
|
+
if (!debounceMap[autoSaveId]) {
|
|
242
|
+
debounceMap[autoSaveId] = debounce(
|
|
243
|
+
savePanelGroupLayout,
|
|
244
|
+
LOCAL_STORAGE_DEBOUNCE_INTERVAL
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
|
|
299
248
|
}
|
|
300
|
-
}, [
|
|
249
|
+
}, [autoSaveId, layout, panelDataArray, storage]);
|
|
301
250
|
|
|
302
251
|
// Once all panels have registered themselves,
|
|
303
252
|
// Compute the initial sizes based on default weights.
|
|
304
253
|
// This assumes that panels register during initial mount (no conditional rendering)!
|
|
305
254
|
useIsomorphicLayoutEffect(() => {
|
|
306
|
-
const { id: groupId,
|
|
307
|
-
if (
|
|
308
|
-
// Only compute (or restore) default
|
|
255
|
+
const { id: groupId, layout, onLayout } = committedValuesRef.current;
|
|
256
|
+
if (layout.length === panelDataArray.length) {
|
|
257
|
+
// Only compute (or restore) default layout once per panel configuration.
|
|
309
258
|
return;
|
|
310
259
|
}
|
|
311
260
|
|
|
312
261
|
// If this panel has been configured to persist sizing information,
|
|
313
262
|
// default size should be restored from local storage if possible.
|
|
314
|
-
let
|
|
263
|
+
let unsafeLayout: number[] | null = null;
|
|
315
264
|
if (autoSaveId) {
|
|
316
|
-
|
|
317
|
-
defaultSizes = loadPanelLayout(autoSaveId, panelsArray, storage);
|
|
265
|
+
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
318
266
|
}
|
|
319
267
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
panels,
|
|
326
|
-
nextSizes: defaultSizes,
|
|
327
|
-
prevSizes: defaultSizes,
|
|
328
|
-
units,
|
|
329
|
-
});
|
|
268
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
269
|
+
if (groupSizePixels <= 0) {
|
|
270
|
+
// Wait until the group has rendered a non-zero size before computing layout.
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
330
273
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
panels,
|
|
336
|
-
units,
|
|
274
|
+
if (unsafeLayout == null) {
|
|
275
|
+
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
276
|
+
groupSizePixels,
|
|
277
|
+
panelDataArray,
|
|
337
278
|
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Validate even saved layouts in case something has changed since last render
|
|
282
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
283
|
+
const validatedLayout = validatePanelGroupLayout({
|
|
284
|
+
groupSizePixels,
|
|
285
|
+
layout: unsafeLayout,
|
|
286
|
+
panelConstraints: panelDataArray.map(
|
|
287
|
+
(panelData) => panelData.constraints
|
|
288
|
+
),
|
|
289
|
+
});
|
|
338
290
|
|
|
339
|
-
|
|
291
|
+
if (!areEqual(layout, validatedLayout)) {
|
|
292
|
+
setLayout(validatedLayout);
|
|
340
293
|
}
|
|
341
|
-
}, [autoSaveId, panels, storage]);
|
|
342
294
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
295
|
+
if (onLayout) {
|
|
296
|
+
onLayout(
|
|
297
|
+
validatedLayout.map((sizePercentage) => ({
|
|
298
|
+
sizePercentage,
|
|
299
|
+
sizePixels: convertPercentageToPixels(
|
|
300
|
+
sizePercentage,
|
|
301
|
+
groupSizePixels
|
|
302
|
+
),
|
|
303
|
+
}))
|
|
304
|
+
);
|
|
305
|
+
}
|
|
349
306
|
|
|
350
|
-
|
|
307
|
+
callPanelCallbacks(
|
|
308
|
+
groupId,
|
|
309
|
+
panelDataArray,
|
|
310
|
+
validatedLayout,
|
|
311
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
312
|
+
);
|
|
313
|
+
}, [autoSaveId, layout, panelDataArray, storage]);
|
|
351
314
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
315
|
+
useIsomorphicLayoutEffect(() => {
|
|
316
|
+
const constraints = panelDataArray.map(({ constraints }) => constraints);
|
|
317
|
+
if (!shouldMonitorPixelBasedConstraints(constraints)) {
|
|
318
|
+
// Avoid the overhead of ResizeObserver if no pixel constraints require monitoring
|
|
319
|
+
return;
|
|
357
320
|
}
|
|
358
321
|
|
|
322
|
+
if (typeof ResizeObserver === "undefined") {
|
|
323
|
+
console.warn(
|
|
324
|
+
`WARNING: Pixel based constraints require ResizeObserver but it is not supported by the current browser.`
|
|
325
|
+
);
|
|
326
|
+
} else {
|
|
327
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
328
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
329
|
+
|
|
330
|
+
const { layout: prevLayout, onLayout } = committedValuesRef.current;
|
|
331
|
+
|
|
332
|
+
const nextLayout = validatePanelGroupLayout({
|
|
333
|
+
groupSizePixels,
|
|
334
|
+
layout: prevLayout,
|
|
335
|
+
panelConstraints: panelDataArray.map(
|
|
336
|
+
(panelData) => panelData.constraints
|
|
337
|
+
),
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
341
|
+
setLayout(nextLayout);
|
|
342
|
+
|
|
343
|
+
if (onLayout) {
|
|
344
|
+
onLayout(
|
|
345
|
+
nextLayout.map((sizePercentage) => ({
|
|
346
|
+
sizePercentage,
|
|
347
|
+
sizePixels: convertPercentageToPixels(
|
|
348
|
+
sizePercentage,
|
|
349
|
+
groupSizePixels
|
|
350
|
+
),
|
|
351
|
+
}))
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
callPanelCallbacks(
|
|
356
|
+
groupId,
|
|
357
|
+
panelDataArray,
|
|
358
|
+
nextLayout,
|
|
359
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
resizeObserver.observe(getPanelGroupElement(groupId)!);
|
|
365
|
+
|
|
366
|
+
return () => {
|
|
367
|
+
resizeObserver.disconnect();
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
}, [groupId, panelDataArray]);
|
|
371
|
+
|
|
372
|
+
// DEV warnings
|
|
373
|
+
useEffect(() => {
|
|
359
374
|
if (isDevelopment) {
|
|
360
|
-
const {
|
|
375
|
+
const {
|
|
376
|
+
didLogIdAndOrderWarning,
|
|
377
|
+
didLogPanelConstraintsWarning,
|
|
378
|
+
prevPanelIds,
|
|
379
|
+
} = devWarningsRef.current;
|
|
380
|
+
|
|
361
381
|
if (!didLogIdAndOrderWarning) {
|
|
362
|
-
const {
|
|
382
|
+
const { panelDataArray } = committedValuesRef.current;
|
|
363
383
|
|
|
364
|
-
const panelIds =
|
|
384
|
+
const panelIds = panelDataArray.map(({ id }) => id);
|
|
365
385
|
|
|
366
386
|
devWarningsRef.current.prevPanelIds = panelIds;
|
|
367
387
|
|
|
@@ -369,9 +389,8 @@ function PanelGroupWithForwardedRef({
|
|
|
369
389
|
prevPanelIds.length > 0 && !areEqual(prevPanelIds, panelIds);
|
|
370
390
|
if (panelsHaveChanged) {
|
|
371
391
|
if (
|
|
372
|
-
|
|
373
|
-
(
|
|
374
|
-
panel.current.idWasAutoGenerated || panel.current.order == null
|
|
392
|
+
panelDataArray.find(
|
|
393
|
+
({ idIsFromProps, order }) => !idIsFromProps || order == null
|
|
375
394
|
)
|
|
376
395
|
) {
|
|
377
396
|
devWarningsRef.current.didLogIdAndOrderWarning = true;
|
|
@@ -382,512 +401,509 @@ function PanelGroupWithForwardedRef({
|
|
|
382
401
|
}
|
|
383
402
|
}
|
|
384
403
|
}
|
|
385
|
-
}
|
|
386
|
-
}, [autoSaveId, panels, sizes, storage]);
|
|
387
404
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const resizeObserver = new ResizeObserver(() => {
|
|
393
|
-
const { panels, sizes: prevSizes } = committedValuesRef.current;
|
|
405
|
+
if (!didLogPanelConstraintsWarning) {
|
|
406
|
+
const panelConstraints = panelDataArray.map(
|
|
407
|
+
(panelData) => panelData.constraints
|
|
408
|
+
);
|
|
394
409
|
|
|
395
|
-
const
|
|
396
|
-
groupId,
|
|
397
|
-
panels,
|
|
398
|
-
nextSizes: prevSizes,
|
|
399
|
-
prevSizes,
|
|
400
|
-
units,
|
|
401
|
-
});
|
|
402
|
-
if (!areEqual(prevSizes, nextSizes)) {
|
|
403
|
-
setSizes(nextSizes);
|
|
404
|
-
}
|
|
405
|
-
});
|
|
410
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
406
411
|
|
|
407
|
-
|
|
412
|
+
for (
|
|
413
|
+
let panelIndex = 0;
|
|
414
|
+
panelIndex < panelConstraints.length;
|
|
415
|
+
panelIndex++
|
|
416
|
+
) {
|
|
417
|
+
const isValid = validatePanelConstraints({
|
|
418
|
+
groupSizePixels,
|
|
419
|
+
panelConstraints,
|
|
420
|
+
panelId: panelDataArray[panelIndex].id,
|
|
421
|
+
panelIndex,
|
|
422
|
+
});
|
|
408
423
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
}, [groupId, units]);
|
|
424
|
+
if (!isValid) {
|
|
425
|
+
devWarningsRef.current.didLogPanelConstraintsWarning = true;
|
|
414
426
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
});
|
|
418
433
|
|
|
419
|
-
|
|
434
|
+
// External APIs are safe to memoize via committed values ref
|
|
435
|
+
const collapsePanel = useCallback(
|
|
436
|
+
(panelData: PanelData) => {
|
|
437
|
+
const {
|
|
438
|
+
layout: prevLayout,
|
|
439
|
+
onLayout,
|
|
440
|
+
panelDataArray,
|
|
441
|
+
} = committedValuesRef.current;
|
|
420
442
|
|
|
421
|
-
|
|
422
|
-
|
|
443
|
+
if (panelData.constraints.collapsible) {
|
|
444
|
+
const panelConstraintsArray = panelDataArray.map(
|
|
445
|
+
(panelData) => panelData.constraints
|
|
446
|
+
);
|
|
423
447
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
448
|
+
const {
|
|
449
|
+
collapsedSizePercentage,
|
|
450
|
+
panelSizePercentage,
|
|
451
|
+
pivotIndices,
|
|
452
|
+
groupSizePixels,
|
|
453
|
+
} = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
|
|
454
|
+
|
|
455
|
+
if (panelSizePercentage !== collapsedSizePercentage) {
|
|
456
|
+
// Store size before collapse;
|
|
457
|
+
// This is the size that gets restored if the expand() API is used.
|
|
458
|
+
panelSizeBeforeCollapseRef.current.set(
|
|
459
|
+
panelData.id,
|
|
460
|
+
panelSizePercentage
|
|
461
|
+
);
|
|
434
462
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
463
|
+
const isLastPanel =
|
|
464
|
+
panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
|
|
465
|
+
const delta = isLastPanel
|
|
466
|
+
? panelSizePercentage - collapsedSizePercentage
|
|
467
|
+
: collapsedSizePercentage - panelSizePercentage;
|
|
468
|
+
|
|
469
|
+
const nextLayout = adjustLayoutByDelta({
|
|
470
|
+
delta,
|
|
471
|
+
groupSizePixels,
|
|
472
|
+
layout: prevLayout,
|
|
473
|
+
panelConstraints: panelConstraintsArray,
|
|
474
|
+
pivotIndices,
|
|
475
|
+
trigger: "imperative-api",
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
479
|
+
setLayout(nextLayout);
|
|
480
|
+
|
|
481
|
+
if (onLayout) {
|
|
482
|
+
onLayout(
|
|
483
|
+
nextLayout.map((sizePercentage) => ({
|
|
484
|
+
sizePercentage,
|
|
485
|
+
sizePixels: convertPercentageToPixels(
|
|
486
|
+
sizePercentage,
|
|
487
|
+
groupSizePixels
|
|
488
|
+
),
|
|
489
|
+
}))
|
|
449
490
|
);
|
|
450
491
|
}
|
|
492
|
+
|
|
493
|
+
callPanelCallbacks(
|
|
494
|
+
groupId,
|
|
495
|
+
panelDataArray,
|
|
496
|
+
nextLayout,
|
|
497
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
498
|
+
);
|
|
451
499
|
}
|
|
452
500
|
}
|
|
453
|
-
|
|
454
|
-
return {
|
|
455
|
-
flexBasis: 0,
|
|
456
|
-
flexGrow: defaultSize != null ? defaultSize : undefined,
|
|
457
|
-
flexShrink: 1,
|
|
458
|
-
|
|
459
|
-
// Without this, Panel sizes may be unintentionally overridden by their content.
|
|
460
|
-
overflow: "hidden",
|
|
461
|
-
};
|
|
462
501
|
}
|
|
463
|
-
|
|
464
|
-
const flexGrow = getFlexGrow(panels, id, sizes);
|
|
465
|
-
|
|
466
|
-
return {
|
|
467
|
-
flexBasis: 0,
|
|
468
|
-
flexGrow,
|
|
469
|
-
flexShrink: 1,
|
|
470
|
-
|
|
471
|
-
// Without this, Panel sizes may be unintentionally overridden by their content.
|
|
472
|
-
overflow: "hidden",
|
|
473
|
-
|
|
474
|
-
// Disable pointer events inside of a panel during resize.
|
|
475
|
-
// This avoid edge cases like nested iframes.
|
|
476
|
-
pointerEvents:
|
|
477
|
-
disablePointerEventsDuringResize && activeHandleId !== null
|
|
478
|
-
? "none"
|
|
479
|
-
: undefined,
|
|
480
|
-
};
|
|
481
502
|
},
|
|
482
|
-
[
|
|
503
|
+
[groupId]
|
|
483
504
|
);
|
|
484
505
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
const nextPanels = new Map(prevPanels);
|
|
496
|
-
nextPanels.set(id, panelRef);
|
|
497
|
-
|
|
498
|
-
return nextPanels;
|
|
499
|
-
});
|
|
500
|
-
}, []);
|
|
501
|
-
|
|
502
|
-
const registerResizeHandle = useCallback(
|
|
503
|
-
(handleId: string) => {
|
|
504
|
-
const resizeHandler = (event: ResizeEvent) => {
|
|
505
|
-
event.preventDefault();
|
|
506
|
-
|
|
507
|
-
const {
|
|
508
|
-
direction,
|
|
509
|
-
panels,
|
|
510
|
-
sizes: prevSizes,
|
|
511
|
-
} = committedValuesRef.current;
|
|
512
|
-
|
|
513
|
-
const panelsArray = panelsMapToSortedArray(panels);
|
|
514
|
-
|
|
515
|
-
const [idBefore, idAfter] = getResizeHandlePanelIds(
|
|
516
|
-
groupId,
|
|
517
|
-
handleId,
|
|
518
|
-
panelsArray
|
|
519
|
-
);
|
|
520
|
-
if (idBefore == null || idAfter == null) {
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
let movement = getMovement(
|
|
525
|
-
event,
|
|
526
|
-
groupId,
|
|
527
|
-
handleId,
|
|
528
|
-
panelsArray,
|
|
529
|
-
direction,
|
|
530
|
-
prevSizes,
|
|
531
|
-
initialDragStateRef.current
|
|
532
|
-
);
|
|
533
|
-
if (movement === 0) {
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const groupElement = getPanelGroup(groupId)!;
|
|
538
|
-
const rect = groupElement.getBoundingClientRect();
|
|
539
|
-
const isHorizontal = direction === "horizontal";
|
|
540
|
-
|
|
541
|
-
// Support RTL layouts
|
|
542
|
-
if (document.dir === "rtl" && isHorizontal) {
|
|
543
|
-
movement = -movement;
|
|
544
|
-
}
|
|
506
|
+
// External APIs are safe to memoize via committed values ref
|
|
507
|
+
const expandPanel = useCallback(
|
|
508
|
+
(panelData: PanelData) => {
|
|
509
|
+
const {
|
|
510
|
+
layout: prevLayout,
|
|
511
|
+
onLayout,
|
|
512
|
+
panelDataArray,
|
|
513
|
+
} = committedValuesRef.current;
|
|
545
514
|
|
|
546
|
-
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
// If a validateLayout method has been provided
|
|
550
|
-
// it's important to use it before updating the mouse cursor
|
|
551
|
-
const nextSizes = adjustByDelta(
|
|
552
|
-
event,
|
|
553
|
-
committedValuesRef.current,
|
|
554
|
-
idBefore,
|
|
555
|
-
idAfter,
|
|
556
|
-
delta,
|
|
557
|
-
prevSizes,
|
|
558
|
-
panelSizeBeforeCollapse.current,
|
|
559
|
-
initialDragStateRef.current
|
|
515
|
+
if (panelData.constraints.collapsible) {
|
|
516
|
+
const panelConstraintsArray = panelDataArray.map(
|
|
517
|
+
(panelData) => panelData.constraints
|
|
560
518
|
);
|
|
561
519
|
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
520
|
+
const {
|
|
521
|
+
collapsedSizePercentage,
|
|
522
|
+
panelSizePercentage,
|
|
523
|
+
minSizePercentage,
|
|
524
|
+
pivotIndices,
|
|
525
|
+
groupSizePixels,
|
|
526
|
+
} = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
|
|
527
|
+
|
|
528
|
+
if (panelSizePercentage === collapsedSizePercentage) {
|
|
529
|
+
// Restore this panel to the size it was before it was collapsed, if possible.
|
|
530
|
+
const prevPanelSizePercentage =
|
|
531
|
+
panelSizeBeforeCollapseRef.current.get(panelData.id);
|
|
532
|
+
|
|
533
|
+
const baseSizePercentage =
|
|
534
|
+
prevPanelSizePercentage != null
|
|
535
|
+
? prevPanelSizePercentage
|
|
536
|
+
: minSizePercentage;
|
|
537
|
+
|
|
538
|
+
const isLastPanel =
|
|
539
|
+
panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
|
|
540
|
+
const delta = isLastPanel
|
|
541
|
+
? panelSizePercentage - baseSizePercentage
|
|
542
|
+
: baseSizePercentage - panelSizePercentage;
|
|
543
|
+
|
|
544
|
+
const nextLayout = adjustLayoutByDelta({
|
|
545
|
+
delta,
|
|
546
|
+
groupSizePixels,
|
|
547
|
+
layout: prevLayout,
|
|
548
|
+
panelConstraints: panelConstraintsArray,
|
|
549
|
+
pivotIndices,
|
|
550
|
+
trigger: "imperative-api",
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
554
|
+
setLayout(nextLayout);
|
|
555
|
+
|
|
556
|
+
if (onLayout) {
|
|
557
|
+
onLayout(
|
|
558
|
+
nextLayout.map((sizePercentage) => ({
|
|
559
|
+
sizePercentage,
|
|
560
|
+
sizePixels: convertPercentageToPixels(
|
|
561
|
+
sizePercentage,
|
|
562
|
+
groupSizePixels
|
|
563
|
+
),
|
|
564
|
+
}))
|
|
565
|
+
);
|
|
587
566
|
}
|
|
567
|
+
|
|
568
|
+
callPanelCallbacks(
|
|
569
|
+
groupId,
|
|
570
|
+
panelDataArray,
|
|
571
|
+
nextLayout,
|
|
572
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
573
|
+
);
|
|
588
574
|
}
|
|
589
575
|
}
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
[groupId]
|
|
579
|
+
);
|
|
590
580
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
// It's okay to bypass in this case because we already validated above
|
|
596
|
-
setSizes(nextSizes);
|
|
581
|
+
// External APIs are safe to memoize via committed values ref
|
|
582
|
+
const getPanelSize = useCallback(
|
|
583
|
+
(panelData: PanelData) => {
|
|
584
|
+
const { layout, panelDataArray } = committedValuesRef.current;
|
|
597
585
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
);
|
|
605
|
-
}
|
|
586
|
+
const { panelSizePercentage, panelSizePixels } = panelDataHelper(
|
|
587
|
+
groupId,
|
|
588
|
+
panelDataArray,
|
|
589
|
+
panelData,
|
|
590
|
+
layout
|
|
591
|
+
);
|
|
606
592
|
|
|
607
|
-
|
|
593
|
+
return {
|
|
594
|
+
sizePercentage: panelSizePercentage,
|
|
595
|
+
sizePixels: panelSizePixels,
|
|
608
596
|
};
|
|
609
|
-
|
|
610
|
-
return resizeHandler;
|
|
611
597
|
},
|
|
612
598
|
[groupId]
|
|
613
599
|
);
|
|
614
600
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
const { panels, sizes: prevSizes } = committedValuesRef.current;
|
|
630
|
-
|
|
631
|
-
const panel = panels.get(id);
|
|
632
|
-
if (panel == null) {
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
const { collapsedSize, collapsible } = panel.current;
|
|
637
|
-
if (!collapsible) {
|
|
638
|
-
return;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
const panelsArray = panelsMapToSortedArray(panels);
|
|
601
|
+
// This API should never read from committedValuesRef
|
|
602
|
+
const getPanelStyle = useCallback(
|
|
603
|
+
(panelData: PanelData) => {
|
|
604
|
+
const panelIndex = panelDataArray.indexOf(panelData);
|
|
605
|
+
|
|
606
|
+
return computePanelFlexBoxStyle({
|
|
607
|
+
dragState,
|
|
608
|
+
layout,
|
|
609
|
+
panelData: panelDataArray,
|
|
610
|
+
panelIndex,
|
|
611
|
+
});
|
|
612
|
+
},
|
|
613
|
+
[dragState, layout, panelDataArray]
|
|
614
|
+
);
|
|
642
615
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
616
|
+
// External APIs are safe to memoize via committed values ref
|
|
617
|
+
const isPanelCollapsed = useCallback(
|
|
618
|
+
(panelData: PanelData) => {
|
|
619
|
+
const { layout, panelDataArray } = committedValuesRef.current;
|
|
647
620
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
// Panel is already collapsed.
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
621
|
+
const { collapsedSizePercentage, collapsible, panelSizePercentage } =
|
|
622
|
+
panelDataHelper(groupId, panelDataArray, panelData, layout);
|
|
653
623
|
|
|
654
|
-
|
|
624
|
+
return (
|
|
625
|
+
collapsible === true && panelSizePercentage === collapsedSizePercentage
|
|
626
|
+
);
|
|
627
|
+
},
|
|
628
|
+
[groupId]
|
|
629
|
+
);
|
|
655
630
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
631
|
+
// External APIs are safe to memoize via committed values ref
|
|
632
|
+
const isPanelExpanded = useCallback(
|
|
633
|
+
(panelData: PanelData) => {
|
|
634
|
+
const { layout, panelDataArray } = committedValuesRef.current;
|
|
660
635
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
const nextSizes = adjustByDelta(
|
|
665
|
-
null,
|
|
666
|
-
committedValuesRef.current,
|
|
667
|
-
idBefore,
|
|
668
|
-
idAfter,
|
|
669
|
-
delta,
|
|
670
|
-
prevSizes,
|
|
671
|
-
panelSizeBeforeCollapse.current,
|
|
672
|
-
null
|
|
673
|
-
);
|
|
674
|
-
if (prevSizes !== nextSizes) {
|
|
675
|
-
const panelIdToLastNotifiedSizeMap =
|
|
676
|
-
panelIdToLastNotifiedSizeMapRef.current;
|
|
636
|
+
const { collapsedSizePercentage, collapsible, panelSizePercentage } =
|
|
637
|
+
panelDataHelper(groupId, panelDataArray, panelData, layout);
|
|
677
638
|
|
|
678
|
-
|
|
639
|
+
return !collapsible || panelSizePercentage > collapsedSizePercentage;
|
|
640
|
+
},
|
|
641
|
+
[groupId]
|
|
642
|
+
);
|
|
679
643
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
644
|
+
const registerPanel = useCallback((panelData: PanelData) => {
|
|
645
|
+
setPanelDataArray((prevPanelDataArray) => {
|
|
646
|
+
const nextPanelDataArray = [...prevPanelDataArray, panelData];
|
|
647
|
+
return nextPanelDataArray.sort((panelA, panelB) => {
|
|
648
|
+
const orderA = panelA.order;
|
|
649
|
+
const orderB = panelB.order;
|
|
650
|
+
if (orderA == null && orderB == null) {
|
|
651
|
+
return 0;
|
|
652
|
+
} else if (orderA == null) {
|
|
653
|
+
return -1;
|
|
654
|
+
} else if (orderB == null) {
|
|
655
|
+
return 1;
|
|
656
|
+
} else {
|
|
657
|
+
return orderA - orderB;
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
});
|
|
684
661
|
}, []);
|
|
685
662
|
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
const panel = panels.get(id);
|
|
690
|
-
if (panel == null) {
|
|
691
|
-
return;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
const { collapsedSize, minSize } = panel.current;
|
|
695
|
-
|
|
696
|
-
const sizeBeforeCollapse =
|
|
697
|
-
panelSizeBeforeCollapse.current.get(id) || minSize;
|
|
698
|
-
if (!sizeBeforeCollapse) {
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
const panelsArray = panelsMapToSortedArray(panels);
|
|
703
|
-
|
|
704
|
-
const index = panelsArray.indexOf(panel);
|
|
705
|
-
if (index < 0) {
|
|
706
|
-
return;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
const currentSize = prevSizes[index];
|
|
710
|
-
if (currentSize !== collapsedSize) {
|
|
711
|
-
// Panel is already expanded.
|
|
712
|
-
return;
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
716
|
-
if (idBefore == null || idAfter == null) {
|
|
717
|
-
return;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
const isLastPanel = index === panelsArray.length - 1;
|
|
721
|
-
const delta = isLastPanel
|
|
722
|
-
? collapsedSize - sizeBeforeCollapse
|
|
723
|
-
: sizeBeforeCollapse;
|
|
724
|
-
|
|
725
|
-
const nextSizes = adjustByDelta(
|
|
726
|
-
null,
|
|
727
|
-
committedValuesRef.current,
|
|
728
|
-
idBefore,
|
|
729
|
-
idAfter,
|
|
730
|
-
delta,
|
|
731
|
-
prevSizes,
|
|
732
|
-
panelSizeBeforeCollapse.current,
|
|
733
|
-
null
|
|
734
|
-
);
|
|
735
|
-
if (prevSizes !== nextSizes) {
|
|
736
|
-
const panelIdToLastNotifiedSizeMap =
|
|
737
|
-
panelIdToLastNotifiedSizeMapRef.current;
|
|
738
|
-
|
|
739
|
-
setSizes(nextSizes);
|
|
740
|
-
|
|
741
|
-
// If resize change handlers have been declared, this is the time to call them.
|
|
742
|
-
// Trigger user callbacks after updating state, so that user code can override the sizes.
|
|
743
|
-
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
744
|
-
}
|
|
745
|
-
}, []);
|
|
663
|
+
const registerResizeHandle = useCallback((dragHandleId: string) => {
|
|
664
|
+
return function resizeHandler(event: ResizeEvent) {
|
|
665
|
+
event.preventDefault();
|
|
746
666
|
|
|
747
|
-
const resizePanel = useCallback(
|
|
748
|
-
(id: string, nextSize: number, unitsFromParams?: Units) => {
|
|
749
667
|
const {
|
|
668
|
+
direction,
|
|
669
|
+
dragState,
|
|
750
670
|
id: groupId,
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
671
|
+
keyboardResizeByPercentage,
|
|
672
|
+
keyboardResizeByPixels,
|
|
673
|
+
onLayout,
|
|
674
|
+
panelDataArray,
|
|
675
|
+
layout: prevLayout,
|
|
754
676
|
} = committedValuesRef.current;
|
|
755
677
|
|
|
756
|
-
|
|
757
|
-
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
758
|
-
nextSize = (nextSize / groupSizePixels) * 100;
|
|
759
|
-
}
|
|
678
|
+
const { initialLayout } = dragState ?? {};
|
|
760
679
|
|
|
761
|
-
const
|
|
762
|
-
if (panel == null) {
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
let { collapsedSize, collapsible, maxSize, minSize } = panel.current;
|
|
680
|
+
const pivotIndices = determinePivotIndices(groupId, dragHandleId);
|
|
767
681
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
682
|
+
let delta = calculateDeltaPercentage(
|
|
683
|
+
event,
|
|
684
|
+
groupId,
|
|
685
|
+
dragHandleId,
|
|
686
|
+
direction,
|
|
687
|
+
dragState!,
|
|
688
|
+
{
|
|
689
|
+
percentage: keyboardResizeByPercentage,
|
|
690
|
+
pixels: keyboardResizeByPixels,
|
|
773
691
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
const panelsArray = panelsMapToSortedArray(panels);
|
|
777
|
-
|
|
778
|
-
const index = panelsArray.indexOf(panel);
|
|
779
|
-
if (index < 0) {
|
|
692
|
+
);
|
|
693
|
+
if (delta === 0) {
|
|
780
694
|
return;
|
|
781
695
|
}
|
|
782
696
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
697
|
+
// Support RTL layouts
|
|
698
|
+
const isHorizontal = direction === "horizontal";
|
|
699
|
+
if (document.dir === "rtl" && isHorizontal) {
|
|
700
|
+
delta = -delta;
|
|
786
701
|
}
|
|
787
702
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
703
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
704
|
+
const panelConstraints = panelDataArray.map(
|
|
705
|
+
(panelData) => panelData.constraints
|
|
706
|
+
);
|
|
792
707
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
708
|
+
const nextLayout = adjustLayoutByDelta({
|
|
709
|
+
delta,
|
|
710
|
+
groupSizePixels,
|
|
711
|
+
layout: initialLayout ?? prevLayout,
|
|
712
|
+
panelConstraints,
|
|
713
|
+
pivotIndices,
|
|
714
|
+
trigger: isKeyDown(event) ? "keyboard" : "mouse-or-touch",
|
|
715
|
+
});
|
|
797
716
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
717
|
+
const layoutChanged = !compareLayouts(prevLayout, nextLayout);
|
|
718
|
+
|
|
719
|
+
// Only update the cursor for layout changes triggered by touch/mouse events (not keyboard)
|
|
720
|
+
// Update the cursor even if the layout hasn't changed (we may need to show an invalid cursor state)
|
|
721
|
+
if (isMouseEvent(event) || isTouchEvent(event)) {
|
|
722
|
+
// Watch for multiple subsequent deltas; this might occur for tiny cursor movements.
|
|
723
|
+
// In this case, Panel sizes might not change–
|
|
724
|
+
// but updating cursor in this scenario would cause a flicker.
|
|
725
|
+
if (prevDeltaRef.current != delta) {
|
|
726
|
+
prevDeltaRef.current = delta;
|
|
727
|
+
|
|
728
|
+
if (!layoutChanged) {
|
|
729
|
+
// If the pointer has moved too far to resize the panel any further,
|
|
730
|
+
// update the cursor style for a visual clue.
|
|
731
|
+
// This mimics VS Code behavior.
|
|
732
|
+
|
|
733
|
+
if (isHorizontal) {
|
|
734
|
+
setGlobalCursorStyle(
|
|
735
|
+
delta < 0 ? "horizontal-min" : "horizontal-max"
|
|
736
|
+
);
|
|
737
|
+
} else {
|
|
738
|
+
setGlobalCursorStyle(delta < 0 ? "vertical-min" : "vertical-max");
|
|
739
|
+
}
|
|
740
|
+
} else {
|
|
741
|
+
// Reset the cursor style to the the normal resize cursor.
|
|
742
|
+
setGlobalCursorStyle(isHorizontal ? "horizontal" : "vertical");
|
|
803
743
|
}
|
|
804
744
|
}
|
|
805
745
|
}
|
|
806
746
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
747
|
+
if (layoutChanged) {
|
|
748
|
+
setLayout(nextLayout);
|
|
749
|
+
|
|
750
|
+
if (onLayout) {
|
|
751
|
+
onLayout(
|
|
752
|
+
nextLayout.map((sizePercentage) => ({
|
|
753
|
+
sizePercentage,
|
|
754
|
+
sizePixels: convertPercentageToPixels(
|
|
755
|
+
sizePercentage,
|
|
756
|
+
groupSizePixels
|
|
757
|
+
),
|
|
758
|
+
}))
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
callPanelCallbacks(
|
|
763
|
+
groupId,
|
|
764
|
+
panelDataArray,
|
|
765
|
+
nextLayout,
|
|
766
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
767
|
+
);
|
|
810
768
|
}
|
|
769
|
+
};
|
|
770
|
+
}, []);
|
|
811
771
|
|
|
812
|
-
|
|
772
|
+
// External APIs are safe to memoize via committed values ref
|
|
773
|
+
const resizePanel = useCallback(
|
|
774
|
+
(panelData: PanelData, mixedSizes: Partial<MixedSizes>) => {
|
|
775
|
+
const {
|
|
776
|
+
layout: prevLayout,
|
|
777
|
+
onLayout,
|
|
778
|
+
panelDataArray,
|
|
779
|
+
} = committedValuesRef.current;
|
|
780
|
+
|
|
781
|
+
const panelConstraintsArray = panelDataArray.map(
|
|
782
|
+
(panelData) => panelData.constraints
|
|
783
|
+
);
|
|
784
|
+
|
|
785
|
+
const { groupSizePixels, panelSizePercentage, pivotIndices } =
|
|
786
|
+
panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
|
|
787
|
+
|
|
788
|
+
const sizePercentage = getPercentageSizeFromMixedSizes(
|
|
789
|
+
mixedSizes,
|
|
790
|
+
groupSizePixels
|
|
791
|
+
)!;
|
|
792
|
+
|
|
793
|
+
const isLastPanel =
|
|
794
|
+
panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
|
|
813
795
|
const delta = isLastPanel
|
|
814
|
-
?
|
|
815
|
-
:
|
|
816
|
-
|
|
817
|
-
const
|
|
818
|
-
null,
|
|
819
|
-
committedValuesRef.current,
|
|
820
|
-
idBefore,
|
|
821
|
-
idAfter,
|
|
796
|
+
? panelSizePercentage - sizePercentage
|
|
797
|
+
: sizePercentage - panelSizePercentage;
|
|
798
|
+
|
|
799
|
+
const nextLayout = adjustLayoutByDelta({
|
|
822
800
|
delta,
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
panelIdToLastNotifiedSizeMapRef.current;
|
|
801
|
+
groupSizePixels,
|
|
802
|
+
layout: prevLayout,
|
|
803
|
+
panelConstraints: panelConstraintsArray,
|
|
804
|
+
pivotIndices,
|
|
805
|
+
trigger: "imperative-api",
|
|
806
|
+
});
|
|
830
807
|
|
|
831
|
-
|
|
808
|
+
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
809
|
+
setLayout(nextLayout);
|
|
810
|
+
|
|
811
|
+
if (onLayout) {
|
|
812
|
+
onLayout(
|
|
813
|
+
nextLayout.map((sizePercentage) => ({
|
|
814
|
+
sizePercentage,
|
|
815
|
+
sizePixels: convertPercentageToPixels(
|
|
816
|
+
sizePercentage,
|
|
817
|
+
groupSizePixels
|
|
818
|
+
),
|
|
819
|
+
}))
|
|
820
|
+
);
|
|
821
|
+
}
|
|
832
822
|
|
|
833
|
-
// If resize change handlers have been declared, this is the time to call them.
|
|
834
|
-
// Trigger user callbacks after updating state, so that user code can override the sizes.
|
|
835
823
|
callPanelCallbacks(
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
824
|
+
groupId,
|
|
825
|
+
panelDataArray,
|
|
826
|
+
nextLayout,
|
|
827
|
+
panelIdToLastNotifiedMixedSizesMapRef.current
|
|
839
828
|
);
|
|
840
829
|
}
|
|
841
830
|
},
|
|
831
|
+
[groupId]
|
|
832
|
+
);
|
|
833
|
+
|
|
834
|
+
const startDragging = useCallback(
|
|
835
|
+
(dragHandleId: string, event: ResizeEvent) => {
|
|
836
|
+
const { direction, layout } = committedValuesRef.current;
|
|
837
|
+
|
|
838
|
+
const handleElement = getResizeHandleElement(dragHandleId)!;
|
|
839
|
+
|
|
840
|
+
const initialCursorPosition = getResizeEventCursorPosition(
|
|
841
|
+
direction,
|
|
842
|
+
event
|
|
843
|
+
);
|
|
844
|
+
|
|
845
|
+
setDragState({
|
|
846
|
+
dragHandleId,
|
|
847
|
+
dragHandleRect: handleElement.getBoundingClientRect(),
|
|
848
|
+
initialCursorPosition,
|
|
849
|
+
initialLayout: layout,
|
|
850
|
+
});
|
|
851
|
+
},
|
|
842
852
|
[]
|
|
843
853
|
);
|
|
844
854
|
|
|
855
|
+
const stopDragging = useCallback(() => {
|
|
856
|
+
resetGlobalCursorStyle();
|
|
857
|
+
setDragState(null);
|
|
858
|
+
}, []);
|
|
859
|
+
|
|
860
|
+
const unregisterPanel = useCallback((panelData: PanelData) => {
|
|
861
|
+
delete panelIdToLastNotifiedMixedSizesMapRef.current[panelData.id];
|
|
862
|
+
|
|
863
|
+
setPanelDataArray((panelDataArray) => {
|
|
864
|
+
const index = panelDataArray.indexOf(panelData);
|
|
865
|
+
if (index >= 0) {
|
|
866
|
+
panelDataArray = [...panelDataArray];
|
|
867
|
+
panelDataArray.splice(index, 1);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
return panelDataArray;
|
|
871
|
+
});
|
|
872
|
+
}, []);
|
|
873
|
+
|
|
845
874
|
const context = useMemo(
|
|
846
875
|
() => ({
|
|
847
|
-
activeHandleId,
|
|
848
876
|
collapsePanel,
|
|
849
877
|
direction,
|
|
878
|
+
dragState,
|
|
850
879
|
expandPanel,
|
|
851
880
|
getPanelSize,
|
|
852
881
|
getPanelStyle,
|
|
853
882
|
groupId,
|
|
883
|
+
isPanelCollapsed,
|
|
884
|
+
isPanelExpanded,
|
|
854
885
|
registerPanel,
|
|
855
886
|
registerResizeHandle,
|
|
856
887
|
resizePanel,
|
|
857
|
-
startDragging
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
if (isMouseEvent(event) || isTouchEvent(event)) {
|
|
861
|
-
const handleElement = getResizeHandle(id)!;
|
|
862
|
-
|
|
863
|
-
initialDragStateRef.current = {
|
|
864
|
-
dragHandleRect: handleElement.getBoundingClientRect(),
|
|
865
|
-
dragOffset: getDragOffset(event, id, direction),
|
|
866
|
-
sizes: committedValuesRef.current.sizes,
|
|
867
|
-
};
|
|
868
|
-
}
|
|
869
|
-
},
|
|
870
|
-
stopDragging: () => {
|
|
871
|
-
resetGlobalCursorStyle();
|
|
872
|
-
setActiveHandleId(null);
|
|
873
|
-
|
|
874
|
-
initialDragStateRef.current = null;
|
|
875
|
-
},
|
|
876
|
-
units,
|
|
888
|
+
startDragging,
|
|
889
|
+
stopDragging,
|
|
877
890
|
unregisterPanel,
|
|
878
891
|
}),
|
|
879
892
|
[
|
|
880
|
-
activeHandleId,
|
|
881
893
|
collapsePanel,
|
|
894
|
+
dragState,
|
|
882
895
|
direction,
|
|
883
896
|
expandPanel,
|
|
884
897
|
getPanelSize,
|
|
885
898
|
getPanelStyle,
|
|
886
899
|
groupId,
|
|
900
|
+
isPanelCollapsed,
|
|
901
|
+
isPanelExpanded,
|
|
887
902
|
registerPanel,
|
|
888
903
|
registerResizeHandle,
|
|
889
904
|
resizePanel,
|
|
890
|
-
|
|
905
|
+
startDragging,
|
|
906
|
+
stopDragging,
|
|
891
907
|
unregisterPanel,
|
|
892
908
|
]
|
|
893
909
|
);
|
|
@@ -900,18 +916,23 @@ function PanelGroupWithForwardedRef({
|
|
|
900
916
|
width: "100%",
|
|
901
917
|
};
|
|
902
918
|
|
|
903
|
-
return createElement(
|
|
904
|
-
|
|
919
|
+
return createElement(
|
|
920
|
+
PanelGroupContext.Provider,
|
|
921
|
+
{ value: context },
|
|
922
|
+
createElement(Type, {
|
|
905
923
|
children,
|
|
906
924
|
className: classNameFromProps,
|
|
925
|
+
style: {
|
|
926
|
+
...style,
|
|
927
|
+
...styleFromProps,
|
|
928
|
+
},
|
|
929
|
+
|
|
930
|
+
// CSS selectors
|
|
907
931
|
"data-panel-group": "",
|
|
908
932
|
"data-panel-group-direction": direction,
|
|
909
933
|
"data-panel-group-id": groupId,
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
}),
|
|
913
|
-
value: context,
|
|
914
|
-
});
|
|
934
|
+
})
|
|
935
|
+
);
|
|
915
936
|
}
|
|
916
937
|
|
|
917
938
|
export const PanelGroup = forwardRef<
|
|
@@ -923,3 +944,45 @@ export const PanelGroup = forwardRef<
|
|
|
923
944
|
|
|
924
945
|
PanelGroupWithForwardedRef.displayName = "PanelGroup";
|
|
925
946
|
PanelGroup.displayName = "forwardRef(PanelGroup)";
|
|
947
|
+
|
|
948
|
+
function panelDataHelper(
|
|
949
|
+
groupId: string,
|
|
950
|
+
panelDataArray: PanelData[],
|
|
951
|
+
panelData: PanelData,
|
|
952
|
+
layout: number[]
|
|
953
|
+
) {
|
|
954
|
+
const panelConstraintsArray = panelDataArray.map(
|
|
955
|
+
(panelData) => panelData.constraints
|
|
956
|
+
);
|
|
957
|
+
|
|
958
|
+
const panelIndex = panelDataArray.indexOf(panelData);
|
|
959
|
+
const panelConstraints = panelConstraintsArray[panelIndex];
|
|
960
|
+
|
|
961
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
962
|
+
|
|
963
|
+
const percentagePanelConstraints = computePercentagePanelConstraints(
|
|
964
|
+
panelConstraintsArray,
|
|
965
|
+
panelIndex,
|
|
966
|
+
groupSizePixels
|
|
967
|
+
);
|
|
968
|
+
|
|
969
|
+
const isLastPanel = panelIndex === panelDataArray.length - 1;
|
|
970
|
+
const pivotIndices = isLastPanel
|
|
971
|
+
? [panelIndex - 1, panelIndex]
|
|
972
|
+
: [panelIndex, panelIndex + 1];
|
|
973
|
+
|
|
974
|
+
const panelSizePercentage = layout[panelIndex];
|
|
975
|
+
const panelSizePixels = convertPercentageToPixels(
|
|
976
|
+
panelSizePercentage,
|
|
977
|
+
groupSizePixels
|
|
978
|
+
);
|
|
979
|
+
|
|
980
|
+
return {
|
|
981
|
+
...percentagePanelConstraints,
|
|
982
|
+
collapsible: panelConstraints.collapsible,
|
|
983
|
+
panelSizePercentage,
|
|
984
|
+
panelSizePixels,
|
|
985
|
+
groupSizePixels,
|
|
986
|
+
pivotIndices,
|
|
987
|
+
};
|
|
988
|
+
}
|