react-resizable-panels 2.0.4 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/declarations/src/index.d.ts +3 -1
- package/dist/declarations/src/utils/rects/getIntersectingRectangle.d.ts +2 -0
- package/dist/declarations/src/utils/rects/intersects.d.ts +2 -0
- package/dist/declarations/src/utils/rects/types.d.ts +6 -0
- package/dist/declarations/src/vendor/react.d.ts +3 -2
- package/dist/react-resizable-panels.browser.cjs.js +87 -7
- package/dist/react-resizable-panels.browser.cjs.mjs +3 -1
- package/dist/react-resizable-panels.browser.development.cjs.js +87 -7
- package/dist/react-resizable-panels.browser.development.cjs.mjs +3 -1
- package/dist/react-resizable-panels.browser.development.esm.js +86 -8
- package/dist/react-resizable-panels.browser.esm.js +86 -8
- package/dist/react-resizable-panels.cjs.js +87 -7
- package/dist/react-resizable-panels.cjs.mjs +3 -1
- package/dist/react-resizable-panels.development.cjs.js +87 -7
- package/dist/react-resizable-panels.development.cjs.mjs +3 -1
- package/dist/react-resizable-panels.development.esm.js +86 -8
- package/dist/react-resizable-panels.development.node.cjs.js +84 -8
- package/dist/react-resizable-panels.development.node.cjs.mjs +3 -1
- package/dist/react-resizable-panels.development.node.esm.js +83 -9
- package/dist/react-resizable-panels.esm.js +86 -8
- package/dist/react-resizable-panels.node.cjs.js +84 -8
- package/dist/react-resizable-panels.node.cjs.mjs +3 -1
- package/dist/react-resizable-panels.node.esm.js +83 -9
- package/package.json +4 -1
- package/src/PanelResizeHandle.ts +2 -2
- package/src/PanelResizeHandleRegistry.ts +75 -8
- package/src/hooks/useIsomorphicEffect.ts +4 -2
- package/src/index.ts +4 -0
- package/src/utils/rects/getIntersectingRectangle.test.ts +198 -0
- package/src/utils/rects/getIntersectingRectangle.ts +28 -0
- package/src/utils/rects/intersects.test.ts +197 -0
- package/src/utils/rects/intersects.ts +23 -0
- package/src/utils/rects/types.ts +6 -0
- package/src/vendor/react.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.6
|
|
4
|
+
|
|
5
|
+
- Replace `useLayoutEffect` usage with SSR-safe wrapper hook (#294)
|
|
6
|
+
|
|
7
|
+
## 2.0.5
|
|
8
|
+
|
|
9
|
+
- Resize handle hit detection considers [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context) when determining hit detection (#291)
|
|
10
|
+
|
|
3
11
|
## 2.0.4
|
|
4
12
|
|
|
5
13
|
- Fixed `PanelResizeHandle` `onDragging` prop to only be called for the handle being dragged (#289)
|
|
@@ -9,7 +9,9 @@ import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement.js";
|
|
|
9
9
|
import { getResizeHandleElementIndex } from "./utils/dom/getResizeHandleElementIndex.js";
|
|
10
10
|
import { getResizeHandleElementsForGroup } from "./utils/dom/getResizeHandleElementsForGroup.js";
|
|
11
11
|
import { getResizeHandlePanelIds } from "./utils/dom/getResizeHandlePanelIds.js";
|
|
12
|
+
import { getIntersectingRectangle } from "./utils/rects/getIntersectingRectangle.js";
|
|
13
|
+
import { intersects } from "./utils/rects/intersects.js";
|
|
12
14
|
import type { ImperativePanelHandle, PanelOnCollapse, PanelOnExpand, PanelOnResize, PanelProps } from "./Panel.js";
|
|
13
15
|
import type { ImperativePanelGroupHandle, PanelGroupOnLayout, PanelGroupProps, PanelGroupStorage } from "./PanelGroup.js";
|
|
14
16
|
import type { PanelResizeHandleOnDragging, PanelResizeHandleProps } from "./PanelResizeHandle.js";
|
|
15
|
-
export { ImperativePanelGroupHandle, ImperativePanelHandle, PanelGroupOnLayout, PanelGroupProps, PanelGroupStorage, PanelOnCollapse, PanelOnExpand, PanelOnResize, PanelProps, PanelResizeHandleOnDragging, PanelResizeHandleProps, Panel, PanelGroup, PanelResizeHandle, assert, getPanelElement, getPanelElementsForGroup, getPanelGroupElement, getResizeHandleElement, getResizeHandleElementIndex, getResizeHandleElementsForGroup, getResizeHandlePanelIds, };
|
|
17
|
+
export { ImperativePanelGroupHandle, ImperativePanelHandle, PanelGroupOnLayout, PanelGroupProps, PanelGroupStorage, PanelOnCollapse, PanelOnExpand, PanelOnResize, PanelProps, PanelResizeHandleOnDragging, PanelResizeHandleProps, Panel, PanelGroup, PanelResizeHandle, assert, getIntersectingRectangle, intersects, getPanelElement, getPanelElementsForGroup, getPanelGroupElement, getResizeHandleElement, getResizeHandleElementIndex, getResizeHandleElementsForGroup, getResizeHandlePanelIds, };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { CSSProperties, ElementType, ForwardedRef, HTMLAttributes, MouseEvent, PropsWithChildren, ReactElement, ReactNode, RefObject, TouchEvent } from "react";
|
|
3
|
-
declare const createElement: typeof React.createElement, createContext: typeof React.createContext, createRef: typeof React.createRef, forwardRef: typeof React.forwardRef, useCallback: typeof React.useCallback, useContext: typeof React.useContext, useEffect: typeof React.useEffect, useImperativeHandle: typeof React.useImperativeHandle,
|
|
3
|
+
declare const createElement: typeof React.createElement, createContext: typeof React.createContext, createRef: typeof React.createRef, forwardRef: typeof React.forwardRef, useCallback: typeof React.useCallback, useContext: typeof React.useContext, useEffect: typeof React.useEffect, useImperativeHandle: typeof React.useImperativeHandle, useMemo: typeof React.useMemo, useRef: typeof React.useRef, useState: typeof React.useState;
|
|
4
4
|
declare const useId: () => string;
|
|
5
|
-
|
|
5
|
+
declare const useLayoutEffect_do_not_use_directly: typeof React.useLayoutEffect;
|
|
6
|
+
export { createElement, createContext, createRef, forwardRef, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect_do_not_use_directly, useMemo, useRef, useState, };
|
|
6
7
|
export type { CSSProperties, ElementType, ForwardedRef, HTMLAttributes, MouseEvent, PropsWithChildren, ReactElement, ReactNode, RefObject, TouchEvent, };
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var stackingOrder = require('stacking-order');
|
|
6
7
|
|
|
7
8
|
function _interopNamespace(e) {
|
|
8
9
|
if (e && e.__esModule) return e;
|
|
@@ -45,11 +46,12 @@ const {
|
|
|
45
46
|
|
|
46
47
|
// `toString()` prevents bundlers from trying to `import { useId } from 'react'`
|
|
47
48
|
const useId = React__namespace["useId".toString()];
|
|
49
|
+
const useLayoutEffect_do_not_use_directly = useLayoutEffect;
|
|
48
50
|
|
|
49
51
|
const PanelGroupContext = createContext(null);
|
|
50
52
|
PanelGroupContext.displayName = "PanelGroupContext";
|
|
51
53
|
|
|
52
|
-
const useIsomorphicLayoutEffect =
|
|
54
|
+
const useIsomorphicLayoutEffect = useLayoutEffect_do_not_use_directly ;
|
|
53
55
|
|
|
54
56
|
const wrappedUseId = typeof useId === "function" ? useId : () => null;
|
|
55
57
|
let counter = 0;
|
|
@@ -294,6 +296,14 @@ function getInputType() {
|
|
|
294
296
|
}
|
|
295
297
|
}
|
|
296
298
|
|
|
299
|
+
function intersects(rectOne, rectTwo, strict) {
|
|
300
|
+
if (strict) {
|
|
301
|
+
return rectOne.x < rectTwo.x + rectTwo.width && rectOne.x + rectOne.width > rectTwo.x && rectOne.y < rectTwo.y + rectTwo.height && rectOne.y + rectOne.height > rectTwo.y;
|
|
302
|
+
} else {
|
|
303
|
+
return rectOne.x <= rectTwo.x + rectTwo.width && rectOne.x + rectOne.width >= rectTwo.x && rectOne.y <= rectTwo.y + rectTwo.height && rectOne.y + rectOne.height >= rectTwo.y;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
297
307
|
const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
298
308
|
const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
299
309
|
const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
@@ -332,12 +342,16 @@ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins
|
|
|
332
342
|
};
|
|
333
343
|
}
|
|
334
344
|
function handlePointerDown(event) {
|
|
345
|
+
const {
|
|
346
|
+
target
|
|
347
|
+
} = event;
|
|
335
348
|
const {
|
|
336
349
|
x,
|
|
337
350
|
y
|
|
338
351
|
} = getResizeEventCoordinates(event);
|
|
339
352
|
isPointerDown = true;
|
|
340
353
|
recalculateIntersectingHandles({
|
|
354
|
+
target,
|
|
341
355
|
x,
|
|
342
356
|
y
|
|
343
357
|
});
|
|
@@ -353,10 +367,15 @@ function handlePointerMove(event) {
|
|
|
353
367
|
y
|
|
354
368
|
} = getResizeEventCoordinates(event);
|
|
355
369
|
if (!isPointerDown) {
|
|
370
|
+
const {
|
|
371
|
+
target
|
|
372
|
+
} = event;
|
|
373
|
+
|
|
356
374
|
// Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
|
|
357
375
|
// at that point, the handles may not move with the pointer (depending on constraints)
|
|
358
376
|
// but the same set of active handles should be locked until the pointer is released
|
|
359
377
|
recalculateIntersectingHandles({
|
|
378
|
+
target,
|
|
360
379
|
x,
|
|
361
380
|
y
|
|
362
381
|
});
|
|
@@ -370,6 +389,9 @@ function handlePointerMove(event) {
|
|
|
370
389
|
}
|
|
371
390
|
}
|
|
372
391
|
function handlePointerUp(event) {
|
|
392
|
+
const {
|
|
393
|
+
target
|
|
394
|
+
} = event;
|
|
373
395
|
const {
|
|
374
396
|
x,
|
|
375
397
|
y
|
|
@@ -379,33 +401,72 @@ function handlePointerUp(event) {
|
|
|
379
401
|
if (intersectingHandles.length > 0) {
|
|
380
402
|
event.preventDefault();
|
|
381
403
|
}
|
|
404
|
+
updateResizeHandlerStates("up", event);
|
|
382
405
|
recalculateIntersectingHandles({
|
|
406
|
+
target,
|
|
383
407
|
x,
|
|
384
408
|
y
|
|
385
409
|
});
|
|
386
|
-
updateResizeHandlerStates("up", event);
|
|
387
410
|
updateCursor();
|
|
388
411
|
updateListeners();
|
|
389
412
|
}
|
|
390
413
|
function recalculateIntersectingHandles({
|
|
414
|
+
target,
|
|
391
415
|
x,
|
|
392
416
|
y
|
|
393
417
|
}) {
|
|
394
418
|
intersectingHandles.splice(0);
|
|
419
|
+
let targetElement = null;
|
|
420
|
+
if (target instanceof HTMLElement) {
|
|
421
|
+
targetElement = target;
|
|
422
|
+
}
|
|
395
423
|
registeredResizeHandlers.forEach(data => {
|
|
396
424
|
const {
|
|
397
|
-
element,
|
|
425
|
+
element: dragHandleElement,
|
|
398
426
|
hitAreaMargins
|
|
399
427
|
} = data;
|
|
428
|
+
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
400
429
|
const {
|
|
401
430
|
bottom,
|
|
402
431
|
left,
|
|
403
432
|
right,
|
|
404
433
|
top
|
|
405
|
-
} =
|
|
434
|
+
} = dragHandleRect;
|
|
406
435
|
const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
|
|
407
|
-
const
|
|
408
|
-
if (
|
|
436
|
+
const eventIntersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
|
|
437
|
+
if (eventIntersects) {
|
|
438
|
+
// TRICKY
|
|
439
|
+
// We listen for pointers events at the root in order to support hit area margins
|
|
440
|
+
// (determining when the pointer is close enough to an element to be considered a "hit")
|
|
441
|
+
// Clicking on an element "above" a handle (e.g. a modal) should prevent a hit though
|
|
442
|
+
// so at this point we need to compare stacking order of a potentially intersecting drag handle,
|
|
443
|
+
// and the element that was actually clicked/touched
|
|
444
|
+
if (targetElement !== null && dragHandleElement !== targetElement && !dragHandleElement.contains(targetElement) && !targetElement.contains(dragHandleElement) &&
|
|
445
|
+
// Calculating stacking order has a cost, so we should avoid it if possible
|
|
446
|
+
// That is why we only check potentially intersecting handles,
|
|
447
|
+
// and why we skip if the event target is within the handle's DOM
|
|
448
|
+
stackingOrder.compare(targetElement, dragHandleElement) > 0) {
|
|
449
|
+
// If the target is above the drag handle, then we also need to confirm they overlap
|
|
450
|
+
// If they are beside each other (e.g. a panel and its drag handle) then the handle is still interactive
|
|
451
|
+
//
|
|
452
|
+
// It's not enough to compare only the target
|
|
453
|
+
// The target might be a small element inside of a larger container
|
|
454
|
+
// (For example, a SPAN or a DIV inside of a larger modal dialog)
|
|
455
|
+
let currentElement = targetElement;
|
|
456
|
+
let didIntersect = false;
|
|
457
|
+
while (currentElement) {
|
|
458
|
+
if (currentElement.contains(dragHandleElement)) {
|
|
459
|
+
break;
|
|
460
|
+
} else if (intersects(currentElement.getBoundingClientRect(), dragHandleRect, true)) {
|
|
461
|
+
didIntersect = true;
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
currentElement = currentElement.parentElement;
|
|
465
|
+
}
|
|
466
|
+
if (didIntersect) {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
409
470
|
intersectingHandles.push(data);
|
|
410
471
|
}
|
|
411
472
|
});
|
|
@@ -2038,7 +2099,7 @@ function PanelResizeHandle({
|
|
|
2038
2099
|
const committedValuesRef = useRef({
|
|
2039
2100
|
state
|
|
2040
2101
|
});
|
|
2041
|
-
|
|
2102
|
+
useIsomorphicLayoutEffect(() => {
|
|
2042
2103
|
committedValuesRef.current.state = state;
|
|
2043
2104
|
});
|
|
2044
2105
|
useEffect(() => {
|
|
@@ -2153,10 +2214,28 @@ function getPanelElementsForGroup(groupId, scope = document) {
|
|
|
2153
2214
|
return Array.from(scope.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
2154
2215
|
}
|
|
2155
2216
|
|
|
2217
|
+
function getIntersectingRectangle(rectOne, rectTwo, strict) {
|
|
2218
|
+
if (!intersects(rectOne, rectTwo, strict)) {
|
|
2219
|
+
return {
|
|
2220
|
+
x: 0,
|
|
2221
|
+
y: 0,
|
|
2222
|
+
width: 0,
|
|
2223
|
+
height: 0
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
return {
|
|
2227
|
+
x: Math.max(rectOne.x, rectTwo.x),
|
|
2228
|
+
y: Math.max(rectOne.y, rectTwo.y),
|
|
2229
|
+
width: Math.min(rectOne.x + rectOne.width, rectTwo.x + rectTwo.width) - Math.max(rectOne.x, rectTwo.x),
|
|
2230
|
+
height: Math.min(rectOne.y + rectOne.height, rectTwo.y + rectTwo.height) - Math.max(rectOne.y, rectTwo.y)
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2156
2234
|
exports.Panel = Panel;
|
|
2157
2235
|
exports.PanelGroup = PanelGroup;
|
|
2158
2236
|
exports.PanelResizeHandle = PanelResizeHandle;
|
|
2159
2237
|
exports.assert = assert;
|
|
2238
|
+
exports.getIntersectingRectangle = getIntersectingRectangle;
|
|
2160
2239
|
exports.getPanelElement = getPanelElement;
|
|
2161
2240
|
exports.getPanelElementsForGroup = getPanelElementsForGroup;
|
|
2162
2241
|
exports.getPanelGroupElement = getPanelGroupElement;
|
|
@@ -2164,3 +2243,4 @@ exports.getResizeHandleElement = getResizeHandleElement;
|
|
|
2164
2243
|
exports.getResizeHandleElementIndex = getResizeHandleElementIndex;
|
|
2165
2244
|
exports.getResizeHandleElementsForGroup = getResizeHandleElementsForGroup;
|
|
2166
2245
|
exports.getResizeHandlePanelIds = getResizeHandlePanelIds;
|
|
2246
|
+
exports.intersects = intersects;
|
|
@@ -3,11 +3,13 @@ export {
|
|
|
3
3
|
PanelGroup,
|
|
4
4
|
PanelResizeHandle,
|
|
5
5
|
assert,
|
|
6
|
+
getIntersectingRectangle,
|
|
6
7
|
getPanelElement,
|
|
7
8
|
getPanelElementsForGroup,
|
|
8
9
|
getPanelGroupElement,
|
|
9
10
|
getResizeHandleElement,
|
|
10
11
|
getResizeHandleElementIndex,
|
|
11
12
|
getResizeHandleElementsForGroup,
|
|
12
|
-
getResizeHandlePanelIds
|
|
13
|
+
getResizeHandlePanelIds,
|
|
14
|
+
intersects
|
|
13
15
|
} from "./react-resizable-panels.browser.cjs.js";
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var stackingOrder = require('stacking-order');
|
|
6
7
|
|
|
7
8
|
function _interopNamespace(e) {
|
|
8
9
|
if (e && e.__esModule) return e;
|
|
@@ -45,11 +46,12 @@ const {
|
|
|
45
46
|
|
|
46
47
|
// `toString()` prevents bundlers from trying to `import { useId } from 'react'`
|
|
47
48
|
const useId = React__namespace["useId".toString()];
|
|
49
|
+
const useLayoutEffect_do_not_use_directly = useLayoutEffect;
|
|
48
50
|
|
|
49
51
|
const PanelGroupContext = createContext(null);
|
|
50
52
|
PanelGroupContext.displayName = "PanelGroupContext";
|
|
51
53
|
|
|
52
|
-
const useIsomorphicLayoutEffect =
|
|
54
|
+
const useIsomorphicLayoutEffect = useLayoutEffect_do_not_use_directly ;
|
|
53
55
|
|
|
54
56
|
const wrappedUseId = typeof useId === "function" ? useId : () => null;
|
|
55
57
|
let counter = 0;
|
|
@@ -300,6 +302,14 @@ function getInputType() {
|
|
|
300
302
|
}
|
|
301
303
|
}
|
|
302
304
|
|
|
305
|
+
function intersects(rectOne, rectTwo, strict) {
|
|
306
|
+
if (strict) {
|
|
307
|
+
return rectOne.x < rectTwo.x + rectTwo.width && rectOne.x + rectOne.width > rectTwo.x && rectOne.y < rectTwo.y + rectTwo.height && rectOne.y + rectOne.height > rectTwo.y;
|
|
308
|
+
} else {
|
|
309
|
+
return rectOne.x <= rectTwo.x + rectTwo.width && rectOne.x + rectOne.width >= rectTwo.x && rectOne.y <= rectTwo.y + rectTwo.height && rectOne.y + rectOne.height >= rectTwo.y;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
303
313
|
const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
304
314
|
const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
305
315
|
const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
@@ -338,12 +348,16 @@ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins
|
|
|
338
348
|
};
|
|
339
349
|
}
|
|
340
350
|
function handlePointerDown(event) {
|
|
351
|
+
const {
|
|
352
|
+
target
|
|
353
|
+
} = event;
|
|
341
354
|
const {
|
|
342
355
|
x,
|
|
343
356
|
y
|
|
344
357
|
} = getResizeEventCoordinates(event);
|
|
345
358
|
isPointerDown = true;
|
|
346
359
|
recalculateIntersectingHandles({
|
|
360
|
+
target,
|
|
347
361
|
x,
|
|
348
362
|
y
|
|
349
363
|
});
|
|
@@ -359,10 +373,15 @@ function handlePointerMove(event) {
|
|
|
359
373
|
y
|
|
360
374
|
} = getResizeEventCoordinates(event);
|
|
361
375
|
if (!isPointerDown) {
|
|
376
|
+
const {
|
|
377
|
+
target
|
|
378
|
+
} = event;
|
|
379
|
+
|
|
362
380
|
// Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
|
|
363
381
|
// at that point, the handles may not move with the pointer (depending on constraints)
|
|
364
382
|
// but the same set of active handles should be locked until the pointer is released
|
|
365
383
|
recalculateIntersectingHandles({
|
|
384
|
+
target,
|
|
366
385
|
x,
|
|
367
386
|
y
|
|
368
387
|
});
|
|
@@ -376,6 +395,9 @@ function handlePointerMove(event) {
|
|
|
376
395
|
}
|
|
377
396
|
}
|
|
378
397
|
function handlePointerUp(event) {
|
|
398
|
+
const {
|
|
399
|
+
target
|
|
400
|
+
} = event;
|
|
379
401
|
const {
|
|
380
402
|
x,
|
|
381
403
|
y
|
|
@@ -385,33 +407,72 @@ function handlePointerUp(event) {
|
|
|
385
407
|
if (intersectingHandles.length > 0) {
|
|
386
408
|
event.preventDefault();
|
|
387
409
|
}
|
|
410
|
+
updateResizeHandlerStates("up", event);
|
|
388
411
|
recalculateIntersectingHandles({
|
|
412
|
+
target,
|
|
389
413
|
x,
|
|
390
414
|
y
|
|
391
415
|
});
|
|
392
|
-
updateResizeHandlerStates("up", event);
|
|
393
416
|
updateCursor();
|
|
394
417
|
updateListeners();
|
|
395
418
|
}
|
|
396
419
|
function recalculateIntersectingHandles({
|
|
420
|
+
target,
|
|
397
421
|
x,
|
|
398
422
|
y
|
|
399
423
|
}) {
|
|
400
424
|
intersectingHandles.splice(0);
|
|
425
|
+
let targetElement = null;
|
|
426
|
+
if (target instanceof HTMLElement) {
|
|
427
|
+
targetElement = target;
|
|
428
|
+
}
|
|
401
429
|
registeredResizeHandlers.forEach(data => {
|
|
402
430
|
const {
|
|
403
|
-
element,
|
|
431
|
+
element: dragHandleElement,
|
|
404
432
|
hitAreaMargins
|
|
405
433
|
} = data;
|
|
434
|
+
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
406
435
|
const {
|
|
407
436
|
bottom,
|
|
408
437
|
left,
|
|
409
438
|
right,
|
|
410
439
|
top
|
|
411
|
-
} =
|
|
440
|
+
} = dragHandleRect;
|
|
412
441
|
const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
|
|
413
|
-
const
|
|
414
|
-
if (
|
|
442
|
+
const eventIntersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
|
|
443
|
+
if (eventIntersects) {
|
|
444
|
+
// TRICKY
|
|
445
|
+
// We listen for pointers events at the root in order to support hit area margins
|
|
446
|
+
// (determining when the pointer is close enough to an element to be considered a "hit")
|
|
447
|
+
// Clicking on an element "above" a handle (e.g. a modal) should prevent a hit though
|
|
448
|
+
// so at this point we need to compare stacking order of a potentially intersecting drag handle,
|
|
449
|
+
// and the element that was actually clicked/touched
|
|
450
|
+
if (targetElement !== null && dragHandleElement !== targetElement && !dragHandleElement.contains(targetElement) && !targetElement.contains(dragHandleElement) &&
|
|
451
|
+
// Calculating stacking order has a cost, so we should avoid it if possible
|
|
452
|
+
// That is why we only check potentially intersecting handles,
|
|
453
|
+
// and why we skip if the event target is within the handle's DOM
|
|
454
|
+
stackingOrder.compare(targetElement, dragHandleElement) > 0) {
|
|
455
|
+
// If the target is above the drag handle, then we also need to confirm they overlap
|
|
456
|
+
// If they are beside each other (e.g. a panel and its drag handle) then the handle is still interactive
|
|
457
|
+
//
|
|
458
|
+
// It's not enough to compare only the target
|
|
459
|
+
// The target might be a small element inside of a larger container
|
|
460
|
+
// (For example, a SPAN or a DIV inside of a larger modal dialog)
|
|
461
|
+
let currentElement = targetElement;
|
|
462
|
+
let didIntersect = false;
|
|
463
|
+
while (currentElement) {
|
|
464
|
+
if (currentElement.contains(dragHandleElement)) {
|
|
465
|
+
break;
|
|
466
|
+
} else if (intersects(currentElement.getBoundingClientRect(), dragHandleRect, true)) {
|
|
467
|
+
didIntersect = true;
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
currentElement = currentElement.parentElement;
|
|
471
|
+
}
|
|
472
|
+
if (didIntersect) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
415
476
|
intersectingHandles.push(data);
|
|
416
477
|
}
|
|
417
478
|
});
|
|
@@ -2144,7 +2205,7 @@ function PanelResizeHandle({
|
|
|
2144
2205
|
const committedValuesRef = useRef({
|
|
2145
2206
|
state
|
|
2146
2207
|
});
|
|
2147
|
-
|
|
2208
|
+
useIsomorphicLayoutEffect(() => {
|
|
2148
2209
|
committedValuesRef.current.state = state;
|
|
2149
2210
|
});
|
|
2150
2211
|
useEffect(() => {
|
|
@@ -2259,10 +2320,28 @@ function getPanelElementsForGroup(groupId, scope = document) {
|
|
|
2259
2320
|
return Array.from(scope.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
2260
2321
|
}
|
|
2261
2322
|
|
|
2323
|
+
function getIntersectingRectangle(rectOne, rectTwo, strict) {
|
|
2324
|
+
if (!intersects(rectOne, rectTwo, strict)) {
|
|
2325
|
+
return {
|
|
2326
|
+
x: 0,
|
|
2327
|
+
y: 0,
|
|
2328
|
+
width: 0,
|
|
2329
|
+
height: 0
|
|
2330
|
+
};
|
|
2331
|
+
}
|
|
2332
|
+
return {
|
|
2333
|
+
x: Math.max(rectOne.x, rectTwo.x),
|
|
2334
|
+
y: Math.max(rectOne.y, rectTwo.y),
|
|
2335
|
+
width: Math.min(rectOne.x + rectOne.width, rectTwo.x + rectTwo.width) - Math.max(rectOne.x, rectTwo.x),
|
|
2336
|
+
height: Math.min(rectOne.y + rectOne.height, rectTwo.y + rectTwo.height) - Math.max(rectOne.y, rectTwo.y)
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2262
2340
|
exports.Panel = Panel;
|
|
2263
2341
|
exports.PanelGroup = PanelGroup;
|
|
2264
2342
|
exports.PanelResizeHandle = PanelResizeHandle;
|
|
2265
2343
|
exports.assert = assert;
|
|
2344
|
+
exports.getIntersectingRectangle = getIntersectingRectangle;
|
|
2266
2345
|
exports.getPanelElement = getPanelElement;
|
|
2267
2346
|
exports.getPanelElementsForGroup = getPanelElementsForGroup;
|
|
2268
2347
|
exports.getPanelGroupElement = getPanelGroupElement;
|
|
@@ -2270,3 +2349,4 @@ exports.getResizeHandleElement = getResizeHandleElement;
|
|
|
2270
2349
|
exports.getResizeHandleElementIndex = getResizeHandleElementIndex;
|
|
2271
2350
|
exports.getResizeHandleElementsForGroup = getResizeHandleElementsForGroup;
|
|
2272
2351
|
exports.getResizeHandlePanelIds = getResizeHandlePanelIds;
|
|
2352
|
+
exports.intersects = intersects;
|
|
@@ -3,11 +3,13 @@ export {
|
|
|
3
3
|
PanelGroup,
|
|
4
4
|
PanelResizeHandle,
|
|
5
5
|
assert,
|
|
6
|
+
getIntersectingRectangle,
|
|
6
7
|
getPanelElement,
|
|
7
8
|
getPanelElementsForGroup,
|
|
8
9
|
getPanelGroupElement,
|
|
9
10
|
getResizeHandleElement,
|
|
10
11
|
getResizeHandleElementIndex,
|
|
11
12
|
getResizeHandleElementsForGroup,
|
|
12
|
-
getResizeHandlePanelIds
|
|
13
|
+
getResizeHandlePanelIds,
|
|
14
|
+
intersects
|
|
13
15
|
} from "./react-resizable-panels.browser.development.cjs.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { compare } from 'stacking-order';
|
|
2
3
|
|
|
3
4
|
// This module exists to work around Webpack issue https://github.com/webpack/webpack/issues/14814
|
|
4
5
|
|
|
@@ -21,11 +22,12 @@ const {
|
|
|
21
22
|
|
|
22
23
|
// `toString()` prevents bundlers from trying to `import { useId } from 'react'`
|
|
23
24
|
const useId = React["useId".toString()];
|
|
25
|
+
const useLayoutEffect_do_not_use_directly = useLayoutEffect;
|
|
24
26
|
|
|
25
27
|
const PanelGroupContext = createContext(null);
|
|
26
28
|
PanelGroupContext.displayName = "PanelGroupContext";
|
|
27
29
|
|
|
28
|
-
const useIsomorphicLayoutEffect =
|
|
30
|
+
const useIsomorphicLayoutEffect = useLayoutEffect_do_not_use_directly ;
|
|
29
31
|
|
|
30
32
|
const wrappedUseId = typeof useId === "function" ? useId : () => null;
|
|
31
33
|
let counter = 0;
|
|
@@ -276,6 +278,14 @@ function getInputType() {
|
|
|
276
278
|
}
|
|
277
279
|
}
|
|
278
280
|
|
|
281
|
+
function intersects(rectOne, rectTwo, strict) {
|
|
282
|
+
if (strict) {
|
|
283
|
+
return rectOne.x < rectTwo.x + rectTwo.width && rectOne.x + rectOne.width > rectTwo.x && rectOne.y < rectTwo.y + rectTwo.height && rectOne.y + rectOne.height > rectTwo.y;
|
|
284
|
+
} else {
|
|
285
|
+
return rectOne.x <= rectTwo.x + rectTwo.width && rectOne.x + rectOne.width >= rectTwo.x && rectOne.y <= rectTwo.y + rectTwo.height && rectOne.y + rectOne.height >= rectTwo.y;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
279
289
|
const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
280
290
|
const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
281
291
|
const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
@@ -314,12 +324,16 @@ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins
|
|
|
314
324
|
};
|
|
315
325
|
}
|
|
316
326
|
function handlePointerDown(event) {
|
|
327
|
+
const {
|
|
328
|
+
target
|
|
329
|
+
} = event;
|
|
317
330
|
const {
|
|
318
331
|
x,
|
|
319
332
|
y
|
|
320
333
|
} = getResizeEventCoordinates(event);
|
|
321
334
|
isPointerDown = true;
|
|
322
335
|
recalculateIntersectingHandles({
|
|
336
|
+
target,
|
|
323
337
|
x,
|
|
324
338
|
y
|
|
325
339
|
});
|
|
@@ -335,10 +349,15 @@ function handlePointerMove(event) {
|
|
|
335
349
|
y
|
|
336
350
|
} = getResizeEventCoordinates(event);
|
|
337
351
|
if (!isPointerDown) {
|
|
352
|
+
const {
|
|
353
|
+
target
|
|
354
|
+
} = event;
|
|
355
|
+
|
|
338
356
|
// Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
|
|
339
357
|
// at that point, the handles may not move with the pointer (depending on constraints)
|
|
340
358
|
// but the same set of active handles should be locked until the pointer is released
|
|
341
359
|
recalculateIntersectingHandles({
|
|
360
|
+
target,
|
|
342
361
|
x,
|
|
343
362
|
y
|
|
344
363
|
});
|
|
@@ -352,6 +371,9 @@ function handlePointerMove(event) {
|
|
|
352
371
|
}
|
|
353
372
|
}
|
|
354
373
|
function handlePointerUp(event) {
|
|
374
|
+
const {
|
|
375
|
+
target
|
|
376
|
+
} = event;
|
|
355
377
|
const {
|
|
356
378
|
x,
|
|
357
379
|
y
|
|
@@ -361,33 +383,72 @@ function handlePointerUp(event) {
|
|
|
361
383
|
if (intersectingHandles.length > 0) {
|
|
362
384
|
event.preventDefault();
|
|
363
385
|
}
|
|
386
|
+
updateResizeHandlerStates("up", event);
|
|
364
387
|
recalculateIntersectingHandles({
|
|
388
|
+
target,
|
|
365
389
|
x,
|
|
366
390
|
y
|
|
367
391
|
});
|
|
368
|
-
updateResizeHandlerStates("up", event);
|
|
369
392
|
updateCursor();
|
|
370
393
|
updateListeners();
|
|
371
394
|
}
|
|
372
395
|
function recalculateIntersectingHandles({
|
|
396
|
+
target,
|
|
373
397
|
x,
|
|
374
398
|
y
|
|
375
399
|
}) {
|
|
376
400
|
intersectingHandles.splice(0);
|
|
401
|
+
let targetElement = null;
|
|
402
|
+
if (target instanceof HTMLElement) {
|
|
403
|
+
targetElement = target;
|
|
404
|
+
}
|
|
377
405
|
registeredResizeHandlers.forEach(data => {
|
|
378
406
|
const {
|
|
379
|
-
element,
|
|
407
|
+
element: dragHandleElement,
|
|
380
408
|
hitAreaMargins
|
|
381
409
|
} = data;
|
|
410
|
+
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
382
411
|
const {
|
|
383
412
|
bottom,
|
|
384
413
|
left,
|
|
385
414
|
right,
|
|
386
415
|
top
|
|
387
|
-
} =
|
|
416
|
+
} = dragHandleRect;
|
|
388
417
|
const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
|
|
389
|
-
const
|
|
390
|
-
if (
|
|
418
|
+
const eventIntersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
|
|
419
|
+
if (eventIntersects) {
|
|
420
|
+
// TRICKY
|
|
421
|
+
// We listen for pointers events at the root in order to support hit area margins
|
|
422
|
+
// (determining when the pointer is close enough to an element to be considered a "hit")
|
|
423
|
+
// Clicking on an element "above" a handle (e.g. a modal) should prevent a hit though
|
|
424
|
+
// so at this point we need to compare stacking order of a potentially intersecting drag handle,
|
|
425
|
+
// and the element that was actually clicked/touched
|
|
426
|
+
if (targetElement !== null && dragHandleElement !== targetElement && !dragHandleElement.contains(targetElement) && !targetElement.contains(dragHandleElement) &&
|
|
427
|
+
// Calculating stacking order has a cost, so we should avoid it if possible
|
|
428
|
+
// That is why we only check potentially intersecting handles,
|
|
429
|
+
// and why we skip if the event target is within the handle's DOM
|
|
430
|
+
compare(targetElement, dragHandleElement) > 0) {
|
|
431
|
+
// If the target is above the drag handle, then we also need to confirm they overlap
|
|
432
|
+
// If they are beside each other (e.g. a panel and its drag handle) then the handle is still interactive
|
|
433
|
+
//
|
|
434
|
+
// It's not enough to compare only the target
|
|
435
|
+
// The target might be a small element inside of a larger container
|
|
436
|
+
// (For example, a SPAN or a DIV inside of a larger modal dialog)
|
|
437
|
+
let currentElement = targetElement;
|
|
438
|
+
let didIntersect = false;
|
|
439
|
+
while (currentElement) {
|
|
440
|
+
if (currentElement.contains(dragHandleElement)) {
|
|
441
|
+
break;
|
|
442
|
+
} else if (intersects(currentElement.getBoundingClientRect(), dragHandleRect, true)) {
|
|
443
|
+
didIntersect = true;
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
currentElement = currentElement.parentElement;
|
|
447
|
+
}
|
|
448
|
+
if (didIntersect) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
391
452
|
intersectingHandles.push(data);
|
|
392
453
|
}
|
|
393
454
|
});
|
|
@@ -2120,7 +2181,7 @@ function PanelResizeHandle({
|
|
|
2120
2181
|
const committedValuesRef = useRef({
|
|
2121
2182
|
state
|
|
2122
2183
|
});
|
|
2123
|
-
|
|
2184
|
+
useIsomorphicLayoutEffect(() => {
|
|
2124
2185
|
committedValuesRef.current.state = state;
|
|
2125
2186
|
});
|
|
2126
2187
|
useEffect(() => {
|
|
@@ -2235,4 +2296,21 @@ function getPanelElementsForGroup(groupId, scope = document) {
|
|
|
2235
2296
|
return Array.from(scope.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
2236
2297
|
}
|
|
2237
2298
|
|
|
2238
|
-
|
|
2299
|
+
function getIntersectingRectangle(rectOne, rectTwo, strict) {
|
|
2300
|
+
if (!intersects(rectOne, rectTwo, strict)) {
|
|
2301
|
+
return {
|
|
2302
|
+
x: 0,
|
|
2303
|
+
y: 0,
|
|
2304
|
+
width: 0,
|
|
2305
|
+
height: 0
|
|
2306
|
+
};
|
|
2307
|
+
}
|
|
2308
|
+
return {
|
|
2309
|
+
x: Math.max(rectOne.x, rectTwo.x),
|
|
2310
|
+
y: Math.max(rectOne.y, rectTwo.y),
|
|
2311
|
+
width: Math.min(rectOne.x + rectOne.width, rectTwo.x + rectTwo.width) - Math.max(rectOne.x, rectTwo.x),
|
|
2312
|
+
height: Math.min(rectOne.y + rectOne.height, rectTwo.y + rectTwo.height) - Math.max(rectOne.y, rectTwo.y)
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
export { Panel, PanelGroup, PanelResizeHandle, assert, getIntersectingRectangle, getPanelElement, getPanelElementsForGroup, getPanelGroupElement, getResizeHandleElement, getResizeHandleElementIndex, getResizeHandleElementsForGroup, getResizeHandlePanelIds, intersects };
|