react-resizable-panels 2.1.5 → 2.1.7
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/dist/declarations/src/PanelGroup.d.ts +2 -0
- package/dist/react-resizable-panels.browser.cjs.js +16 -10
- package/dist/react-resizable-panels.browser.development.cjs.js +16 -10
- package/dist/react-resizable-panels.browser.development.esm.js +16 -10
- package/dist/react-resizable-panels.browser.esm.js +16 -10
- package/dist/react-resizable-panels.cjs.js +16 -10
- package/dist/react-resizable-panels.development.cjs.js +16 -10
- package/dist/react-resizable-panels.development.esm.js +16 -10
- package/dist/react-resizable-panels.development.node.cjs.js +16 -10
- package/dist/react-resizable-panels.development.node.esm.js +16 -10
- package/dist/react-resizable-panels.esm.js +16 -10
- package/dist/react-resizable-panels.node.cjs.js +16 -10
- package/dist/react-resizable-panels.node.esm.js +16 -10
- package/package.json +7 -1
- package/.eslintrc.cjs +0 -27
- package/CHANGELOG.md +0 -569
- package/jest.config.js +0 -10
- package/react-resizable-panels-2.1.5.tgz +0 -0
- 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 -985
- 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
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
import { Direction, ResizeEvent } from "./types";
|
|
2
|
-
import { resetGlobalCursorStyle, setGlobalCursorStyle } from "./utils/cursor";
|
|
3
|
-
import { getResizeEventCoordinates } from "./utils/events/getResizeEventCoordinates";
|
|
4
|
-
import { getInputType } from "./utils/getInputType";
|
|
5
|
-
import { intersects } from "./utils/rects/intersects";
|
|
6
|
-
import { compare } from "./vendor/stacking-order";
|
|
7
|
-
|
|
8
|
-
export type ResizeHandlerAction = "down" | "move" | "up";
|
|
9
|
-
export type SetResizeHandlerState = (
|
|
10
|
-
action: ResizeHandlerAction,
|
|
11
|
-
isActive: boolean,
|
|
12
|
-
event: ResizeEvent | null
|
|
13
|
-
) => void;
|
|
14
|
-
|
|
15
|
-
export type PointerHitAreaMargins = {
|
|
16
|
-
coarse: number;
|
|
17
|
-
fine: number;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export type ResizeHandlerData = {
|
|
21
|
-
direction: Direction;
|
|
22
|
-
element: HTMLElement;
|
|
23
|
-
hitAreaMargins: PointerHitAreaMargins;
|
|
24
|
-
setResizeHandlerState: SetResizeHandlerState;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
28
|
-
export const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
29
|
-
export const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
30
|
-
export const EXCEEDED_VERTICAL_MAX = 0b1000;
|
|
31
|
-
|
|
32
|
-
const isCoarsePointer = getInputType() === "coarse";
|
|
33
|
-
|
|
34
|
-
let intersectingHandles: ResizeHandlerData[] = [];
|
|
35
|
-
let isPointerDown = false;
|
|
36
|
-
let ownerDocumentCounts: Map<Document, number> = new Map();
|
|
37
|
-
let panelConstraintFlags: Map<string, number> = new Map();
|
|
38
|
-
|
|
39
|
-
const registeredResizeHandlers = new Set<ResizeHandlerData>();
|
|
40
|
-
|
|
41
|
-
export function registerResizeHandle(
|
|
42
|
-
resizeHandleId: string,
|
|
43
|
-
element: HTMLElement,
|
|
44
|
-
direction: Direction,
|
|
45
|
-
hitAreaMargins: PointerHitAreaMargins,
|
|
46
|
-
setResizeHandlerState: SetResizeHandlerState
|
|
47
|
-
) {
|
|
48
|
-
const { ownerDocument } = element;
|
|
49
|
-
|
|
50
|
-
const data: ResizeHandlerData = {
|
|
51
|
-
direction,
|
|
52
|
-
element,
|
|
53
|
-
hitAreaMargins,
|
|
54
|
-
setResizeHandlerState,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const count = ownerDocumentCounts.get(ownerDocument) ?? 0;
|
|
58
|
-
ownerDocumentCounts.set(ownerDocument, count + 1);
|
|
59
|
-
|
|
60
|
-
registeredResizeHandlers.add(data);
|
|
61
|
-
|
|
62
|
-
updateListeners();
|
|
63
|
-
|
|
64
|
-
return function unregisterResizeHandle() {
|
|
65
|
-
panelConstraintFlags.delete(resizeHandleId);
|
|
66
|
-
registeredResizeHandlers.delete(data);
|
|
67
|
-
|
|
68
|
-
const count = ownerDocumentCounts.get(ownerDocument) ?? 1;
|
|
69
|
-
ownerDocumentCounts.set(ownerDocument, count - 1);
|
|
70
|
-
|
|
71
|
-
updateListeners();
|
|
72
|
-
|
|
73
|
-
if (count === 1) {
|
|
74
|
-
ownerDocumentCounts.delete(ownerDocument);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// If the resize handle that is currently unmounting is intersecting with the pointer,
|
|
78
|
-
// update the global pointer to account for the change
|
|
79
|
-
if (intersectingHandles.includes(data)) {
|
|
80
|
-
const index = intersectingHandles.indexOf(data);
|
|
81
|
-
if (index >= 0) {
|
|
82
|
-
intersectingHandles.splice(index, 1);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
updateCursor();
|
|
86
|
-
|
|
87
|
-
// Also instruct the handle to stop dragging; this prevents the parent group from being left in an inconsistent state
|
|
88
|
-
// See github.com/bvaughn/react-resizable-panels/issues/402
|
|
89
|
-
setResizeHandlerState("up", true, null);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function handlePointerDown(event: PointerEvent) {
|
|
95
|
-
const { target } = event;
|
|
96
|
-
const { x, y } = getResizeEventCoordinates(event);
|
|
97
|
-
|
|
98
|
-
isPointerDown = true;
|
|
99
|
-
|
|
100
|
-
recalculateIntersectingHandles({ target, x, y });
|
|
101
|
-
updateListeners();
|
|
102
|
-
|
|
103
|
-
if (intersectingHandles.length > 0) {
|
|
104
|
-
updateResizeHandlerStates("down", event);
|
|
105
|
-
|
|
106
|
-
event.preventDefault();
|
|
107
|
-
event.stopPropagation();
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function handlePointerMove(event: PointerEvent) {
|
|
112
|
-
const { x, y } = getResizeEventCoordinates(event);
|
|
113
|
-
|
|
114
|
-
// Edge case (see #340)
|
|
115
|
-
// Detect when the pointer has been released outside an iframe on a different domain
|
|
116
|
-
if (isPointerDown && event.buttons === 0) {
|
|
117
|
-
isPointerDown = false;
|
|
118
|
-
|
|
119
|
-
updateResizeHandlerStates("up", event);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (!isPointerDown) {
|
|
123
|
-
const { target } = event;
|
|
124
|
-
|
|
125
|
-
// Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
|
|
126
|
-
// at that point, the handles may not move with the pointer (depending on constraints)
|
|
127
|
-
// but the same set of active handles should be locked until the pointer is released
|
|
128
|
-
recalculateIntersectingHandles({ target, x, y });
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
updateResizeHandlerStates("move", event);
|
|
132
|
-
|
|
133
|
-
// Update cursor based on return value(s) from active handles
|
|
134
|
-
updateCursor();
|
|
135
|
-
|
|
136
|
-
if (intersectingHandles.length > 0) {
|
|
137
|
-
event.preventDefault();
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function handlePointerUp(event: ResizeEvent) {
|
|
142
|
-
const { target } = event;
|
|
143
|
-
const { x, y } = getResizeEventCoordinates(event);
|
|
144
|
-
|
|
145
|
-
panelConstraintFlags.clear();
|
|
146
|
-
isPointerDown = false;
|
|
147
|
-
|
|
148
|
-
if (intersectingHandles.length > 0) {
|
|
149
|
-
event.preventDefault();
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
updateResizeHandlerStates("up", event);
|
|
153
|
-
recalculateIntersectingHandles({ target, x, y });
|
|
154
|
-
updateCursor();
|
|
155
|
-
|
|
156
|
-
updateListeners();
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function recalculateIntersectingHandles({
|
|
160
|
-
target,
|
|
161
|
-
x,
|
|
162
|
-
y,
|
|
163
|
-
}: {
|
|
164
|
-
target: EventTarget | null;
|
|
165
|
-
x: number;
|
|
166
|
-
y: number;
|
|
167
|
-
}) {
|
|
168
|
-
intersectingHandles.splice(0);
|
|
169
|
-
|
|
170
|
-
let targetElement: HTMLElement | null = null;
|
|
171
|
-
if (target instanceof HTMLElement) {
|
|
172
|
-
targetElement = target;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
registeredResizeHandlers.forEach((data) => {
|
|
176
|
-
const { element: dragHandleElement, hitAreaMargins } = data;
|
|
177
|
-
|
|
178
|
-
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
179
|
-
const { bottom, left, right, top } = dragHandleRect;
|
|
180
|
-
|
|
181
|
-
const margin = isCoarsePointer
|
|
182
|
-
? hitAreaMargins.coarse
|
|
183
|
-
: hitAreaMargins.fine;
|
|
184
|
-
|
|
185
|
-
const eventIntersects =
|
|
186
|
-
x >= left - margin &&
|
|
187
|
-
x <= right + margin &&
|
|
188
|
-
y >= top - margin &&
|
|
189
|
-
y <= bottom + margin;
|
|
190
|
-
|
|
191
|
-
if (eventIntersects) {
|
|
192
|
-
// TRICKY
|
|
193
|
-
// We listen for pointers events at the root in order to support hit area margins
|
|
194
|
-
// (determining when the pointer is close enough to an element to be considered a "hit")
|
|
195
|
-
// Clicking on an element "above" a handle (e.g. a modal) should prevent a hit though
|
|
196
|
-
// so at this point we need to compare stacking order of a potentially intersecting drag handle,
|
|
197
|
-
// and the element that was actually clicked/touched
|
|
198
|
-
if (
|
|
199
|
-
targetElement !== null &&
|
|
200
|
-
document.contains(targetElement) &&
|
|
201
|
-
dragHandleElement !== targetElement &&
|
|
202
|
-
!dragHandleElement.contains(targetElement) &&
|
|
203
|
-
!targetElement.contains(dragHandleElement) &&
|
|
204
|
-
// Calculating stacking order has a cost, so we should avoid it if possible
|
|
205
|
-
// That is why we only check potentially intersecting handles,
|
|
206
|
-
// and why we skip if the event target is within the handle's DOM
|
|
207
|
-
compare(targetElement, dragHandleElement) > 0
|
|
208
|
-
) {
|
|
209
|
-
// If the target is above the drag handle, then we also need to confirm they overlap
|
|
210
|
-
// If they are beside each other (e.g. a panel and its drag handle) then the handle is still interactive
|
|
211
|
-
//
|
|
212
|
-
// It's not enough to compare only the target
|
|
213
|
-
// The target might be a small element inside of a larger container
|
|
214
|
-
// (For example, a SPAN or a DIV inside of a larger modal dialog)
|
|
215
|
-
let currentElement: HTMLElement | null = targetElement;
|
|
216
|
-
let didIntersect = false;
|
|
217
|
-
while (currentElement) {
|
|
218
|
-
if (currentElement.contains(dragHandleElement)) {
|
|
219
|
-
break;
|
|
220
|
-
} else if (
|
|
221
|
-
intersects(
|
|
222
|
-
currentElement.getBoundingClientRect(),
|
|
223
|
-
dragHandleRect,
|
|
224
|
-
true
|
|
225
|
-
)
|
|
226
|
-
) {
|
|
227
|
-
didIntersect = true;
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
currentElement = currentElement.parentElement;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (didIntersect) {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
intersectingHandles.push(data);
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export function reportConstraintsViolation(
|
|
245
|
-
resizeHandleId: string,
|
|
246
|
-
flag: number
|
|
247
|
-
) {
|
|
248
|
-
panelConstraintFlags.set(resizeHandleId, flag);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function updateCursor() {
|
|
252
|
-
let intersectsHorizontal = false;
|
|
253
|
-
let intersectsVertical = false;
|
|
254
|
-
|
|
255
|
-
intersectingHandles.forEach((data) => {
|
|
256
|
-
const { direction } = data;
|
|
257
|
-
|
|
258
|
-
if (direction === "horizontal") {
|
|
259
|
-
intersectsHorizontal = true;
|
|
260
|
-
} else {
|
|
261
|
-
intersectsVertical = true;
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
let constraintFlags = 0;
|
|
266
|
-
panelConstraintFlags.forEach((flag) => {
|
|
267
|
-
constraintFlags |= flag;
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
if (intersectsHorizontal && intersectsVertical) {
|
|
271
|
-
setGlobalCursorStyle("intersection", constraintFlags);
|
|
272
|
-
} else if (intersectsHorizontal) {
|
|
273
|
-
setGlobalCursorStyle("horizontal", constraintFlags);
|
|
274
|
-
} else if (intersectsVertical) {
|
|
275
|
-
setGlobalCursorStyle("vertical", constraintFlags);
|
|
276
|
-
} else {
|
|
277
|
-
resetGlobalCursorStyle();
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function updateListeners() {
|
|
282
|
-
ownerDocumentCounts.forEach((_, ownerDocument) => {
|
|
283
|
-
const { body } = ownerDocument;
|
|
284
|
-
|
|
285
|
-
body.removeEventListener("contextmenu", handlePointerUp);
|
|
286
|
-
body.removeEventListener("pointerdown", handlePointerDown);
|
|
287
|
-
body.removeEventListener("pointerleave", handlePointerMove);
|
|
288
|
-
body.removeEventListener("pointermove", handlePointerMove);
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
window.removeEventListener("pointerup", handlePointerUp);
|
|
292
|
-
window.removeEventListener("pointercancel", handlePointerUp);
|
|
293
|
-
|
|
294
|
-
if (registeredResizeHandlers.size > 0) {
|
|
295
|
-
if (isPointerDown) {
|
|
296
|
-
if (intersectingHandles.length > 0) {
|
|
297
|
-
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
298
|
-
const { body } = ownerDocument;
|
|
299
|
-
|
|
300
|
-
if (count > 0) {
|
|
301
|
-
body.addEventListener("contextmenu", handlePointerUp);
|
|
302
|
-
body.addEventListener("pointerleave", handlePointerMove);
|
|
303
|
-
body.addEventListener("pointermove", handlePointerMove);
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
window.addEventListener("pointerup", handlePointerUp);
|
|
309
|
-
window.addEventListener("pointercancel", handlePointerUp);
|
|
310
|
-
} else {
|
|
311
|
-
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
312
|
-
const { body } = ownerDocument;
|
|
313
|
-
|
|
314
|
-
if (count > 0) {
|
|
315
|
-
body.addEventListener("pointerdown", handlePointerDown, {
|
|
316
|
-
capture: true,
|
|
317
|
-
});
|
|
318
|
-
body.addEventListener("pointermove", handlePointerMove);
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
function updateResizeHandlerStates(
|
|
326
|
-
action: ResizeHandlerAction,
|
|
327
|
-
event: ResizeEvent
|
|
328
|
-
) {
|
|
329
|
-
registeredResizeHandlers.forEach((data) => {
|
|
330
|
-
const { setResizeHandlerState } = data;
|
|
331
|
-
|
|
332
|
-
const isActive = intersectingHandles.includes(data);
|
|
333
|
-
|
|
334
|
-
setResizeHandlerState(action, isActive, event);
|
|
335
|
-
});
|
|
336
|
-
}
|
package/src/constants.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const PRECISION = 10;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const isBrowser = true;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const isDevelopment = true;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const isBrowser = false;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const isDevelopment = false;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const isBrowser = typeof window !== "undefined";
|
package/src/hooks/useUniqueId.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { useId, useRef } from "../vendor/react";
|
|
2
|
-
|
|
3
|
-
const wrappedUseId: () => string | null =
|
|
4
|
-
typeof useId === "function" ? useId : (): null => null;
|
|
5
|
-
|
|
6
|
-
let counter = 0;
|
|
7
|
-
|
|
8
|
-
export default function useUniqueId(
|
|
9
|
-
idFromParams: string | null = null
|
|
10
|
-
): string {
|
|
11
|
-
const idFromUseId = wrappedUseId();
|
|
12
|
-
|
|
13
|
-
const idRef = useRef<string | null>(idFromParams || idFromUseId || null);
|
|
14
|
-
if (idRef.current === null) {
|
|
15
|
-
idRef.current = "" + counter++;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return idFromParams ?? idRef.current;
|
|
19
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { ResizeHandler } from "../types";
|
|
2
|
-
import { assert } from "../utils/assert";
|
|
3
|
-
import { getResizeHandleElement } from "../utils/dom/getResizeHandleElement";
|
|
4
|
-
import { getResizeHandleElementIndex } from "../utils/dom/getResizeHandleElementIndex";
|
|
5
|
-
import { getResizeHandleElementsForGroup } from "../utils/dom/getResizeHandleElementsForGroup";
|
|
6
|
-
import { useEffect } from "../vendor/react";
|
|
7
|
-
|
|
8
|
-
// https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/
|
|
9
|
-
|
|
10
|
-
export function useWindowSplitterResizeHandlerBehavior({
|
|
11
|
-
disabled,
|
|
12
|
-
handleId,
|
|
13
|
-
resizeHandler,
|
|
14
|
-
panelGroupElement,
|
|
15
|
-
}: {
|
|
16
|
-
disabled: boolean;
|
|
17
|
-
handleId: string;
|
|
18
|
-
resizeHandler: ResizeHandler | null;
|
|
19
|
-
panelGroupElement: ParentNode | null;
|
|
20
|
-
}): void {
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
if (disabled || resizeHandler == null || panelGroupElement == null) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const handleElement = getResizeHandleElement(handleId, panelGroupElement);
|
|
27
|
-
if (handleElement == null) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const onKeyDown = (event: KeyboardEvent) => {
|
|
32
|
-
if (event.defaultPrevented) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
switch (event.key) {
|
|
37
|
-
case "ArrowDown":
|
|
38
|
-
case "ArrowLeft":
|
|
39
|
-
case "ArrowRight":
|
|
40
|
-
case "ArrowUp":
|
|
41
|
-
case "End":
|
|
42
|
-
case "Home": {
|
|
43
|
-
event.preventDefault();
|
|
44
|
-
|
|
45
|
-
resizeHandler(event);
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
case "F6": {
|
|
49
|
-
event.preventDefault();
|
|
50
|
-
|
|
51
|
-
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
52
|
-
assert(groupId, `No group element found for id "${groupId}"`);
|
|
53
|
-
|
|
54
|
-
const handles = getResizeHandleElementsForGroup(
|
|
55
|
-
groupId,
|
|
56
|
-
panelGroupElement
|
|
57
|
-
);
|
|
58
|
-
const index = getResizeHandleElementIndex(
|
|
59
|
-
groupId,
|
|
60
|
-
handleId,
|
|
61
|
-
panelGroupElement
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
assert(
|
|
65
|
-
index !== null,
|
|
66
|
-
`No resize element found for id "${handleId}"`
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
const nextIndex = event.shiftKey
|
|
70
|
-
? index > 0
|
|
71
|
-
? index - 1
|
|
72
|
-
: handles.length - 1
|
|
73
|
-
: index + 1 < handles.length
|
|
74
|
-
? index + 1
|
|
75
|
-
: 0;
|
|
76
|
-
|
|
77
|
-
const nextHandle = handles[nextIndex] as HTMLElement;
|
|
78
|
-
nextHandle.focus();
|
|
79
|
-
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
handleElement.addEventListener("keydown", onKeyDown);
|
|
86
|
-
return () => {
|
|
87
|
-
handleElement.removeEventListener("keydown", onKeyDown);
|
|
88
|
-
};
|
|
89
|
-
}, [panelGroupElement, disabled, handleId, resizeHandler]);
|
|
90
|
-
}
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { isDevelopment } from "#is-development";
|
|
2
|
-
import { PanelData } from "../Panel";
|
|
3
|
-
import { Direction } from "../types";
|
|
4
|
-
import { adjustLayoutByDelta } from "../utils/adjustLayoutByDelta";
|
|
5
|
-
import { assert } from "../utils/assert";
|
|
6
|
-
import { calculateAriaValues } from "../utils/calculateAriaValues";
|
|
7
|
-
import { determinePivotIndices } from "../utils/determinePivotIndices";
|
|
8
|
-
import { getPanelGroupElement } from "../utils/dom/getPanelGroupElement";
|
|
9
|
-
import { getResizeHandleElementsForGroup } from "../utils/dom/getResizeHandleElementsForGroup";
|
|
10
|
-
import { getResizeHandlePanelIds } from "../utils/dom/getResizeHandlePanelIds";
|
|
11
|
-
import { fuzzyNumbersEqual } from "../utils/numbers/fuzzyNumbersEqual";
|
|
12
|
-
import { RefObject, useEffect, useRef } from "../vendor/react";
|
|
13
|
-
import useIsomorphicLayoutEffect from "./useIsomorphicEffect";
|
|
14
|
-
|
|
15
|
-
// https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/
|
|
16
|
-
|
|
17
|
-
export function useWindowSplitterPanelGroupBehavior({
|
|
18
|
-
committedValuesRef,
|
|
19
|
-
eagerValuesRef,
|
|
20
|
-
groupId,
|
|
21
|
-
layout,
|
|
22
|
-
panelDataArray,
|
|
23
|
-
panelGroupElement,
|
|
24
|
-
setLayout,
|
|
25
|
-
}: {
|
|
26
|
-
committedValuesRef: RefObject<{
|
|
27
|
-
direction: Direction;
|
|
28
|
-
}>;
|
|
29
|
-
eagerValuesRef: RefObject<{
|
|
30
|
-
panelDataArray: PanelData[];
|
|
31
|
-
}>;
|
|
32
|
-
groupId: string;
|
|
33
|
-
layout: number[];
|
|
34
|
-
panelDataArray: PanelData[];
|
|
35
|
-
panelGroupElement: ParentNode | null;
|
|
36
|
-
setLayout: (sizes: number[]) => void;
|
|
37
|
-
}): void {
|
|
38
|
-
const devWarningsRef = useRef<{
|
|
39
|
-
didWarnAboutMissingResizeHandle: boolean;
|
|
40
|
-
}>({
|
|
41
|
-
didWarnAboutMissingResizeHandle: false,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
useIsomorphicLayoutEffect(() => {
|
|
45
|
-
if (!panelGroupElement) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
const resizeHandleElements = getResizeHandleElementsForGroup(
|
|
49
|
-
groupId,
|
|
50
|
-
panelGroupElement
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
for (let index = 0; index < panelDataArray.length - 1; index++) {
|
|
54
|
-
const { valueMax, valueMin, valueNow } = calculateAriaValues({
|
|
55
|
-
layout,
|
|
56
|
-
panelsArray: panelDataArray,
|
|
57
|
-
pivotIndices: [index, index + 1],
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const resizeHandleElement = resizeHandleElements[index];
|
|
61
|
-
if (resizeHandleElement == null) {
|
|
62
|
-
if (isDevelopment) {
|
|
63
|
-
const { didWarnAboutMissingResizeHandle } = devWarningsRef.current;
|
|
64
|
-
|
|
65
|
-
if (!didWarnAboutMissingResizeHandle) {
|
|
66
|
-
devWarningsRef.current.didWarnAboutMissingResizeHandle = true;
|
|
67
|
-
|
|
68
|
-
console.warn(
|
|
69
|
-
`WARNING: Missing resize handle for PanelGroup "${groupId}"`
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
const panelData = panelDataArray[index];
|
|
75
|
-
assert(panelData, `No panel data found for index "${index}"`);
|
|
76
|
-
|
|
77
|
-
resizeHandleElement.setAttribute("aria-controls", panelData.id);
|
|
78
|
-
resizeHandleElement.setAttribute(
|
|
79
|
-
"aria-valuemax",
|
|
80
|
-
"" + Math.round(valueMax)
|
|
81
|
-
);
|
|
82
|
-
resizeHandleElement.setAttribute(
|
|
83
|
-
"aria-valuemin",
|
|
84
|
-
"" + Math.round(valueMin)
|
|
85
|
-
);
|
|
86
|
-
resizeHandleElement.setAttribute(
|
|
87
|
-
"aria-valuenow",
|
|
88
|
-
valueNow != null ? "" + Math.round(valueNow) : ""
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return () => {
|
|
94
|
-
resizeHandleElements.forEach((resizeHandleElement, index) => {
|
|
95
|
-
resizeHandleElement.removeAttribute("aria-controls");
|
|
96
|
-
resizeHandleElement.removeAttribute("aria-valuemax");
|
|
97
|
-
resizeHandleElement.removeAttribute("aria-valuemin");
|
|
98
|
-
resizeHandleElement.removeAttribute("aria-valuenow");
|
|
99
|
-
});
|
|
100
|
-
};
|
|
101
|
-
}, [groupId, layout, panelDataArray, panelGroupElement]);
|
|
102
|
-
|
|
103
|
-
useEffect(() => {
|
|
104
|
-
if (!panelGroupElement) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
const eagerValues = eagerValuesRef.current;
|
|
108
|
-
assert(eagerValues, `Eager values not found`);
|
|
109
|
-
|
|
110
|
-
const { panelDataArray } = eagerValues;
|
|
111
|
-
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
112
|
-
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
113
|
-
|
|
114
|
-
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
115
|
-
assert(handles, `No resize handles found for group id "${groupId}"`);
|
|
116
|
-
|
|
117
|
-
const cleanupFunctions = handles.map((handle) => {
|
|
118
|
-
const handleId = handle.getAttribute("data-panel-resize-handle-id");
|
|
119
|
-
assert(handleId, `Resize handle element has no handle id attribute`);
|
|
120
|
-
|
|
121
|
-
const [idBefore, idAfter] = getResizeHandlePanelIds(
|
|
122
|
-
groupId,
|
|
123
|
-
handleId,
|
|
124
|
-
panelDataArray,
|
|
125
|
-
panelGroupElement
|
|
126
|
-
);
|
|
127
|
-
if (idBefore == null || idAfter == null) {
|
|
128
|
-
return () => {};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const onKeyDown = (event: KeyboardEvent) => {
|
|
132
|
-
if (event.defaultPrevented) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
switch (event.key) {
|
|
137
|
-
case "Enter": {
|
|
138
|
-
event.preventDefault();
|
|
139
|
-
|
|
140
|
-
const index = panelDataArray.findIndex(
|
|
141
|
-
(panelData) => panelData.id === idBefore
|
|
142
|
-
);
|
|
143
|
-
if (index >= 0) {
|
|
144
|
-
const panelData = panelDataArray[index];
|
|
145
|
-
assert(panelData, `No panel data found for index ${index}`);
|
|
146
|
-
|
|
147
|
-
const size = layout[index];
|
|
148
|
-
|
|
149
|
-
const {
|
|
150
|
-
collapsedSize = 0,
|
|
151
|
-
collapsible,
|
|
152
|
-
minSize = 0,
|
|
153
|
-
} = panelData.constraints;
|
|
154
|
-
|
|
155
|
-
if (size != null && collapsible) {
|
|
156
|
-
const nextLayout = adjustLayoutByDelta({
|
|
157
|
-
delta: fuzzyNumbersEqual(size, collapsedSize)
|
|
158
|
-
? minSize - collapsedSize
|
|
159
|
-
: collapsedSize - size,
|
|
160
|
-
initialLayout: layout,
|
|
161
|
-
panelConstraints: panelDataArray.map(
|
|
162
|
-
(panelData) => panelData.constraints
|
|
163
|
-
),
|
|
164
|
-
pivotIndices: determinePivotIndices(
|
|
165
|
-
groupId,
|
|
166
|
-
handleId,
|
|
167
|
-
panelGroupElement
|
|
168
|
-
),
|
|
169
|
-
prevLayout: layout,
|
|
170
|
-
trigger: "keyboard",
|
|
171
|
-
});
|
|
172
|
-
if (layout !== nextLayout) {
|
|
173
|
-
setLayout(nextLayout);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
handle.addEventListener("keydown", onKeyDown);
|
|
183
|
-
|
|
184
|
-
return () => {
|
|
185
|
-
handle.removeEventListener("keydown", onKeyDown);
|
|
186
|
-
};
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
return () => {
|
|
190
|
-
cleanupFunctions.forEach((cleanupFunction) => cleanupFunction());
|
|
191
|
-
};
|
|
192
|
-
}, [
|
|
193
|
-
panelGroupElement,
|
|
194
|
-
committedValuesRef,
|
|
195
|
-
eagerValuesRef,
|
|
196
|
-
groupId,
|
|
197
|
-
layout,
|
|
198
|
-
panelDataArray,
|
|
199
|
-
setLayout,
|
|
200
|
-
]);
|
|
201
|
-
}
|