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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { compare } from 'stacking-order';
|
|
2
3
|
|
|
3
4
|
const isBrowser = typeof window !== "undefined";
|
|
4
5
|
|
|
@@ -23,11 +24,12 @@ const {
|
|
|
23
24
|
|
|
24
25
|
// `toString()` prevents bundlers from trying to `import { useId } from 'react'`
|
|
25
26
|
const useId = React["useId".toString()];
|
|
27
|
+
const useLayoutEffect_do_not_use_directly = useLayoutEffect;
|
|
26
28
|
|
|
27
29
|
const PanelGroupContext = createContext(null);
|
|
28
30
|
PanelGroupContext.displayName = "PanelGroupContext";
|
|
29
31
|
|
|
30
|
-
const useIsomorphicLayoutEffect = isBrowser ?
|
|
32
|
+
const useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect_do_not_use_directly : () => {};
|
|
31
33
|
|
|
32
34
|
const wrappedUseId = typeof useId === "function" ? useId : () => null;
|
|
33
35
|
let counter = 0;
|
|
@@ -283,6 +285,14 @@ function getInputType() {
|
|
|
283
285
|
}
|
|
284
286
|
}
|
|
285
287
|
|
|
288
|
+
function intersects(rectOne, rectTwo, strict) {
|
|
289
|
+
if (strict) {
|
|
290
|
+
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;
|
|
291
|
+
} else {
|
|
292
|
+
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;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
286
296
|
const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
287
297
|
const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
288
298
|
const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
@@ -321,12 +331,16 @@ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins
|
|
|
321
331
|
};
|
|
322
332
|
}
|
|
323
333
|
function handlePointerDown(event) {
|
|
334
|
+
const {
|
|
335
|
+
target
|
|
336
|
+
} = event;
|
|
324
337
|
const {
|
|
325
338
|
x,
|
|
326
339
|
y
|
|
327
340
|
} = getResizeEventCoordinates(event);
|
|
328
341
|
isPointerDown = true;
|
|
329
342
|
recalculateIntersectingHandles({
|
|
343
|
+
target,
|
|
330
344
|
x,
|
|
331
345
|
y
|
|
332
346
|
});
|
|
@@ -342,10 +356,15 @@ function handlePointerMove(event) {
|
|
|
342
356
|
y
|
|
343
357
|
} = getResizeEventCoordinates(event);
|
|
344
358
|
if (!isPointerDown) {
|
|
359
|
+
const {
|
|
360
|
+
target
|
|
361
|
+
} = event;
|
|
362
|
+
|
|
345
363
|
// Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
|
|
346
364
|
// at that point, the handles may not move with the pointer (depending on constraints)
|
|
347
365
|
// but the same set of active handles should be locked until the pointer is released
|
|
348
366
|
recalculateIntersectingHandles({
|
|
367
|
+
target,
|
|
349
368
|
x,
|
|
350
369
|
y
|
|
351
370
|
});
|
|
@@ -359,6 +378,9 @@ function handlePointerMove(event) {
|
|
|
359
378
|
}
|
|
360
379
|
}
|
|
361
380
|
function handlePointerUp(event) {
|
|
381
|
+
const {
|
|
382
|
+
target
|
|
383
|
+
} = event;
|
|
362
384
|
const {
|
|
363
385
|
x,
|
|
364
386
|
y
|
|
@@ -368,33 +390,72 @@ function handlePointerUp(event) {
|
|
|
368
390
|
if (intersectingHandles.length > 0) {
|
|
369
391
|
event.preventDefault();
|
|
370
392
|
}
|
|
393
|
+
updateResizeHandlerStates("up", event);
|
|
371
394
|
recalculateIntersectingHandles({
|
|
395
|
+
target,
|
|
372
396
|
x,
|
|
373
397
|
y
|
|
374
398
|
});
|
|
375
|
-
updateResizeHandlerStates("up", event);
|
|
376
399
|
updateCursor();
|
|
377
400
|
updateListeners();
|
|
378
401
|
}
|
|
379
402
|
function recalculateIntersectingHandles({
|
|
403
|
+
target,
|
|
380
404
|
x,
|
|
381
405
|
y
|
|
382
406
|
}) {
|
|
383
407
|
intersectingHandles.splice(0);
|
|
408
|
+
let targetElement = null;
|
|
409
|
+
if (target instanceof HTMLElement) {
|
|
410
|
+
targetElement = target;
|
|
411
|
+
}
|
|
384
412
|
registeredResizeHandlers.forEach(data => {
|
|
385
413
|
const {
|
|
386
|
-
element,
|
|
414
|
+
element: dragHandleElement,
|
|
387
415
|
hitAreaMargins
|
|
388
416
|
} = data;
|
|
417
|
+
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
389
418
|
const {
|
|
390
419
|
bottom,
|
|
391
420
|
left,
|
|
392
421
|
right,
|
|
393
422
|
top
|
|
394
|
-
} =
|
|
423
|
+
} = dragHandleRect;
|
|
395
424
|
const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
425
|
+
const eventIntersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
|
|
426
|
+
if (eventIntersects) {
|
|
427
|
+
// TRICKY
|
|
428
|
+
// We listen for pointers events at the root in order to support hit area margins
|
|
429
|
+
// (determining when the pointer is close enough to an element to be considered a "hit")
|
|
430
|
+
// Clicking on an element "above" a handle (e.g. a modal) should prevent a hit though
|
|
431
|
+
// so at this point we need to compare stacking order of a potentially intersecting drag handle,
|
|
432
|
+
// and the element that was actually clicked/touched
|
|
433
|
+
if (targetElement !== null && dragHandleElement !== targetElement && !dragHandleElement.contains(targetElement) && !targetElement.contains(dragHandleElement) &&
|
|
434
|
+
// Calculating stacking order has a cost, so we should avoid it if possible
|
|
435
|
+
// That is why we only check potentially intersecting handles,
|
|
436
|
+
// and why we skip if the event target is within the handle's DOM
|
|
437
|
+
compare(targetElement, dragHandleElement) > 0) {
|
|
438
|
+
// If the target is above the drag handle, then we also need to confirm they overlap
|
|
439
|
+
// If they are beside each other (e.g. a panel and its drag handle) then the handle is still interactive
|
|
440
|
+
//
|
|
441
|
+
// It's not enough to compare only the target
|
|
442
|
+
// The target might be a small element inside of a larger container
|
|
443
|
+
// (For example, a SPAN or a DIV inside of a larger modal dialog)
|
|
444
|
+
let currentElement = targetElement;
|
|
445
|
+
let didIntersect = false;
|
|
446
|
+
while (currentElement) {
|
|
447
|
+
if (currentElement.contains(dragHandleElement)) {
|
|
448
|
+
break;
|
|
449
|
+
} else if (intersects(currentElement.getBoundingClientRect(), dragHandleRect, true)) {
|
|
450
|
+
didIntersect = true;
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
currentElement = currentElement.parentElement;
|
|
454
|
+
}
|
|
455
|
+
if (didIntersect) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
398
459
|
intersectingHandles.push(data);
|
|
399
460
|
}
|
|
400
461
|
});
|
|
@@ -2127,7 +2188,7 @@ function PanelResizeHandle({
|
|
|
2127
2188
|
const committedValuesRef = useRef({
|
|
2128
2189
|
state
|
|
2129
2190
|
});
|
|
2130
|
-
|
|
2191
|
+
useIsomorphicLayoutEffect(() => {
|
|
2131
2192
|
committedValuesRef.current.state = state;
|
|
2132
2193
|
});
|
|
2133
2194
|
useEffect(() => {
|
|
@@ -2242,4 +2303,21 @@ function getPanelElementsForGroup(groupId, scope = document) {
|
|
|
2242
2303
|
return Array.from(scope.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
2243
2304
|
}
|
|
2244
2305
|
|
|
2245
|
-
|
|
2306
|
+
function getIntersectingRectangle(rectOne, rectTwo, strict) {
|
|
2307
|
+
if (!intersects(rectOne, rectTwo, strict)) {
|
|
2308
|
+
return {
|
|
2309
|
+
x: 0,
|
|
2310
|
+
y: 0,
|
|
2311
|
+
width: 0,
|
|
2312
|
+
height: 0
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
return {
|
|
2316
|
+
x: Math.max(rectOne.x, rectTwo.x),
|
|
2317
|
+
y: Math.max(rectOne.y, rectTwo.y),
|
|
2318
|
+
width: Math.min(rectOne.x + rectOne.width, rectTwo.x + rectTwo.width) - Math.max(rectOne.x, rectTwo.x),
|
|
2319
|
+
height: Math.min(rectOne.y + rectOne.height, rectTwo.y + rectTwo.height) - Math.max(rectOne.y, rectTwo.y)
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
export { Panel, PanelGroup, PanelResizeHandle, assert, getIntersectingRectangle, getPanelElement, getPanelElementsForGroup, getPanelGroupElement, getResizeHandleElement, getResizeHandleElementIndex, getResizeHandleElementsForGroup, getResizeHandlePanelIds, intersects };
|
|
@@ -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;
|
|
@@ -270,6 +271,14 @@ function getInputType() {
|
|
|
270
271
|
}
|
|
271
272
|
}
|
|
272
273
|
|
|
274
|
+
function intersects(rectOne, rectTwo, strict) {
|
|
275
|
+
if (strict) {
|
|
276
|
+
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;
|
|
277
|
+
} else {
|
|
278
|
+
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;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
273
282
|
const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
274
283
|
const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
275
284
|
const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
@@ -308,12 +317,16 @@ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins
|
|
|
308
317
|
};
|
|
309
318
|
}
|
|
310
319
|
function handlePointerDown(event) {
|
|
320
|
+
const {
|
|
321
|
+
target
|
|
322
|
+
} = event;
|
|
311
323
|
const {
|
|
312
324
|
x,
|
|
313
325
|
y
|
|
314
326
|
} = getResizeEventCoordinates(event);
|
|
315
327
|
isPointerDown = true;
|
|
316
328
|
recalculateIntersectingHandles({
|
|
329
|
+
target,
|
|
317
330
|
x,
|
|
318
331
|
y
|
|
319
332
|
});
|
|
@@ -329,10 +342,15 @@ function handlePointerMove(event) {
|
|
|
329
342
|
y
|
|
330
343
|
} = getResizeEventCoordinates(event);
|
|
331
344
|
if (!isPointerDown) {
|
|
345
|
+
const {
|
|
346
|
+
target
|
|
347
|
+
} = event;
|
|
348
|
+
|
|
332
349
|
// Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
|
|
333
350
|
// at that point, the handles may not move with the pointer (depending on constraints)
|
|
334
351
|
// but the same set of active handles should be locked until the pointer is released
|
|
335
352
|
recalculateIntersectingHandles({
|
|
353
|
+
target,
|
|
336
354
|
x,
|
|
337
355
|
y
|
|
338
356
|
});
|
|
@@ -346,6 +364,9 @@ function handlePointerMove(event) {
|
|
|
346
364
|
}
|
|
347
365
|
}
|
|
348
366
|
function handlePointerUp(event) {
|
|
367
|
+
const {
|
|
368
|
+
target
|
|
369
|
+
} = event;
|
|
349
370
|
const {
|
|
350
371
|
x,
|
|
351
372
|
y
|
|
@@ -355,33 +376,72 @@ function handlePointerUp(event) {
|
|
|
355
376
|
if (intersectingHandles.length > 0) {
|
|
356
377
|
event.preventDefault();
|
|
357
378
|
}
|
|
379
|
+
updateResizeHandlerStates("up", event);
|
|
358
380
|
recalculateIntersectingHandles({
|
|
381
|
+
target,
|
|
359
382
|
x,
|
|
360
383
|
y
|
|
361
384
|
});
|
|
362
|
-
updateResizeHandlerStates("up", event);
|
|
363
385
|
updateCursor();
|
|
364
386
|
updateListeners();
|
|
365
387
|
}
|
|
366
388
|
function recalculateIntersectingHandles({
|
|
389
|
+
target,
|
|
367
390
|
x,
|
|
368
391
|
y
|
|
369
392
|
}) {
|
|
370
393
|
intersectingHandles.splice(0);
|
|
394
|
+
let targetElement = null;
|
|
395
|
+
if (target instanceof HTMLElement) {
|
|
396
|
+
targetElement = target;
|
|
397
|
+
}
|
|
371
398
|
registeredResizeHandlers.forEach(data => {
|
|
372
399
|
const {
|
|
373
|
-
element,
|
|
400
|
+
element: dragHandleElement,
|
|
374
401
|
hitAreaMargins
|
|
375
402
|
} = data;
|
|
403
|
+
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
376
404
|
const {
|
|
377
405
|
bottom,
|
|
378
406
|
left,
|
|
379
407
|
right,
|
|
380
408
|
top
|
|
381
|
-
} =
|
|
409
|
+
} = dragHandleRect;
|
|
382
410
|
const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
|
|
383
|
-
const
|
|
384
|
-
if (
|
|
411
|
+
const eventIntersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
|
|
412
|
+
if (eventIntersects) {
|
|
413
|
+
// TRICKY
|
|
414
|
+
// We listen for pointers events at the root in order to support hit area margins
|
|
415
|
+
// (determining when the pointer is close enough to an element to be considered a "hit")
|
|
416
|
+
// Clicking on an element "above" a handle (e.g. a modal) should prevent a hit though
|
|
417
|
+
// so at this point we need to compare stacking order of a potentially intersecting drag handle,
|
|
418
|
+
// and the element that was actually clicked/touched
|
|
419
|
+
if (targetElement !== null && dragHandleElement !== targetElement && !dragHandleElement.contains(targetElement) && !targetElement.contains(dragHandleElement) &&
|
|
420
|
+
// Calculating stacking order has a cost, so we should avoid it if possible
|
|
421
|
+
// That is why we only check potentially intersecting handles,
|
|
422
|
+
// and why we skip if the event target is within the handle's DOM
|
|
423
|
+
stackingOrder.compare(targetElement, dragHandleElement) > 0) {
|
|
424
|
+
// If the target is above the drag handle, then we also need to confirm they overlap
|
|
425
|
+
// If they are beside each other (e.g. a panel and its drag handle) then the handle is still interactive
|
|
426
|
+
//
|
|
427
|
+
// It's not enough to compare only the target
|
|
428
|
+
// The target might be a small element inside of a larger container
|
|
429
|
+
// (For example, a SPAN or a DIV inside of a larger modal dialog)
|
|
430
|
+
let currentElement = targetElement;
|
|
431
|
+
let didIntersect = false;
|
|
432
|
+
while (currentElement) {
|
|
433
|
+
if (currentElement.contains(dragHandleElement)) {
|
|
434
|
+
break;
|
|
435
|
+
} else if (intersects(currentElement.getBoundingClientRect(), dragHandleRect, true)) {
|
|
436
|
+
didIntersect = true;
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
currentElement = currentElement.parentElement;
|
|
440
|
+
}
|
|
441
|
+
if (didIntersect) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
385
445
|
intersectingHandles.push(data);
|
|
386
446
|
}
|
|
387
447
|
});
|
|
@@ -1920,9 +1980,6 @@ function PanelResizeHandle({
|
|
|
1920
1980
|
const committedValuesRef = useRef({
|
|
1921
1981
|
state
|
|
1922
1982
|
});
|
|
1923
|
-
useLayoutEffect(() => {
|
|
1924
|
-
committedValuesRef.current.state = state;
|
|
1925
|
-
});
|
|
1926
1983
|
useEffect(() => {
|
|
1927
1984
|
if (disabled) {
|
|
1928
1985
|
setResizeHandler(null);
|
|
@@ -2035,10 +2092,28 @@ function getPanelElementsForGroup(groupId, scope = document) {
|
|
|
2035
2092
|
return Array.from(scope.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
2036
2093
|
}
|
|
2037
2094
|
|
|
2095
|
+
function getIntersectingRectangle(rectOne, rectTwo, strict) {
|
|
2096
|
+
if (!intersects(rectOne, rectTwo, strict)) {
|
|
2097
|
+
return {
|
|
2098
|
+
x: 0,
|
|
2099
|
+
y: 0,
|
|
2100
|
+
width: 0,
|
|
2101
|
+
height: 0
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
return {
|
|
2105
|
+
x: Math.max(rectOne.x, rectTwo.x),
|
|
2106
|
+
y: Math.max(rectOne.y, rectTwo.y),
|
|
2107
|
+
width: Math.min(rectOne.x + rectOne.width, rectTwo.x + rectTwo.width) - Math.max(rectOne.x, rectTwo.x),
|
|
2108
|
+
height: Math.min(rectOne.y + rectOne.height, rectTwo.y + rectTwo.height) - Math.max(rectOne.y, rectTwo.y)
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2038
2112
|
exports.Panel = Panel;
|
|
2039
2113
|
exports.PanelGroup = PanelGroup;
|
|
2040
2114
|
exports.PanelResizeHandle = PanelResizeHandle;
|
|
2041
2115
|
exports.assert = assert;
|
|
2116
|
+
exports.getIntersectingRectangle = getIntersectingRectangle;
|
|
2042
2117
|
exports.getPanelElement = getPanelElement;
|
|
2043
2118
|
exports.getPanelElementsForGroup = getPanelElementsForGroup;
|
|
2044
2119
|
exports.getPanelGroupElement = getPanelGroupElement;
|
|
@@ -2046,3 +2121,4 @@ exports.getResizeHandleElement = getResizeHandleElement;
|
|
|
2046
2121
|
exports.getResizeHandleElementIndex = getResizeHandleElementIndex;
|
|
2047
2122
|
exports.getResizeHandleElementsForGroup = getResizeHandleElementsForGroup;
|
|
2048
2123
|
exports.getResizeHandlePanelIds = getResizeHandlePanelIds;
|
|
2124
|
+
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.development.node.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
|
|
|
@@ -246,6 +247,14 @@ function getInputType() {
|
|
|
246
247
|
}
|
|
247
248
|
}
|
|
248
249
|
|
|
250
|
+
function intersects(rectOne, rectTwo, strict) {
|
|
251
|
+
if (strict) {
|
|
252
|
+
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;
|
|
253
|
+
} else {
|
|
254
|
+
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;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
249
258
|
const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
250
259
|
const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
251
260
|
const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
@@ -284,12 +293,16 @@ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins
|
|
|
284
293
|
};
|
|
285
294
|
}
|
|
286
295
|
function handlePointerDown(event) {
|
|
296
|
+
const {
|
|
297
|
+
target
|
|
298
|
+
} = event;
|
|
287
299
|
const {
|
|
288
300
|
x,
|
|
289
301
|
y
|
|
290
302
|
} = getResizeEventCoordinates(event);
|
|
291
303
|
isPointerDown = true;
|
|
292
304
|
recalculateIntersectingHandles({
|
|
305
|
+
target,
|
|
293
306
|
x,
|
|
294
307
|
y
|
|
295
308
|
});
|
|
@@ -305,10 +318,15 @@ function handlePointerMove(event) {
|
|
|
305
318
|
y
|
|
306
319
|
} = getResizeEventCoordinates(event);
|
|
307
320
|
if (!isPointerDown) {
|
|
321
|
+
const {
|
|
322
|
+
target
|
|
323
|
+
} = event;
|
|
324
|
+
|
|
308
325
|
// Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
|
|
309
326
|
// at that point, the handles may not move with the pointer (depending on constraints)
|
|
310
327
|
// but the same set of active handles should be locked until the pointer is released
|
|
311
328
|
recalculateIntersectingHandles({
|
|
329
|
+
target,
|
|
312
330
|
x,
|
|
313
331
|
y
|
|
314
332
|
});
|
|
@@ -322,6 +340,9 @@ function handlePointerMove(event) {
|
|
|
322
340
|
}
|
|
323
341
|
}
|
|
324
342
|
function handlePointerUp(event) {
|
|
343
|
+
const {
|
|
344
|
+
target
|
|
345
|
+
} = event;
|
|
325
346
|
const {
|
|
326
347
|
x,
|
|
327
348
|
y
|
|
@@ -331,33 +352,72 @@ function handlePointerUp(event) {
|
|
|
331
352
|
if (intersectingHandles.length > 0) {
|
|
332
353
|
event.preventDefault();
|
|
333
354
|
}
|
|
355
|
+
updateResizeHandlerStates("up", event);
|
|
334
356
|
recalculateIntersectingHandles({
|
|
357
|
+
target,
|
|
335
358
|
x,
|
|
336
359
|
y
|
|
337
360
|
});
|
|
338
|
-
updateResizeHandlerStates("up", event);
|
|
339
361
|
updateCursor();
|
|
340
362
|
updateListeners();
|
|
341
363
|
}
|
|
342
364
|
function recalculateIntersectingHandles({
|
|
365
|
+
target,
|
|
343
366
|
x,
|
|
344
367
|
y
|
|
345
368
|
}) {
|
|
346
369
|
intersectingHandles.splice(0);
|
|
370
|
+
let targetElement = null;
|
|
371
|
+
if (target instanceof HTMLElement) {
|
|
372
|
+
targetElement = target;
|
|
373
|
+
}
|
|
347
374
|
registeredResizeHandlers.forEach(data => {
|
|
348
375
|
const {
|
|
349
|
-
element,
|
|
376
|
+
element: dragHandleElement,
|
|
350
377
|
hitAreaMargins
|
|
351
378
|
} = data;
|
|
379
|
+
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
352
380
|
const {
|
|
353
381
|
bottom,
|
|
354
382
|
left,
|
|
355
383
|
right,
|
|
356
384
|
top
|
|
357
|
-
} =
|
|
385
|
+
} = dragHandleRect;
|
|
358
386
|
const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
|
|
359
|
-
const
|
|
360
|
-
if (
|
|
387
|
+
const eventIntersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
|
|
388
|
+
if (eventIntersects) {
|
|
389
|
+
// TRICKY
|
|
390
|
+
// We listen for pointers events at the root in order to support hit area margins
|
|
391
|
+
// (determining when the pointer is close enough to an element to be considered a "hit")
|
|
392
|
+
// Clicking on an element "above" a handle (e.g. a modal) should prevent a hit though
|
|
393
|
+
// so at this point we need to compare stacking order of a potentially intersecting drag handle,
|
|
394
|
+
// and the element that was actually clicked/touched
|
|
395
|
+
if (targetElement !== null && dragHandleElement !== targetElement && !dragHandleElement.contains(targetElement) && !targetElement.contains(dragHandleElement) &&
|
|
396
|
+
// Calculating stacking order has a cost, so we should avoid it if possible
|
|
397
|
+
// That is why we only check potentially intersecting handles,
|
|
398
|
+
// and why we skip if the event target is within the handle's DOM
|
|
399
|
+
compare(targetElement, dragHandleElement) > 0) {
|
|
400
|
+
// If the target is above the drag handle, then we also need to confirm they overlap
|
|
401
|
+
// If they are beside each other (e.g. a panel and its drag handle) then the handle is still interactive
|
|
402
|
+
//
|
|
403
|
+
// It's not enough to compare only the target
|
|
404
|
+
// The target might be a small element inside of a larger container
|
|
405
|
+
// (For example, a SPAN or a DIV inside of a larger modal dialog)
|
|
406
|
+
let currentElement = targetElement;
|
|
407
|
+
let didIntersect = false;
|
|
408
|
+
while (currentElement) {
|
|
409
|
+
if (currentElement.contains(dragHandleElement)) {
|
|
410
|
+
break;
|
|
411
|
+
} else if (intersects(currentElement.getBoundingClientRect(), dragHandleRect, true)) {
|
|
412
|
+
didIntersect = true;
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
currentElement = currentElement.parentElement;
|
|
416
|
+
}
|
|
417
|
+
if (didIntersect) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
361
421
|
intersectingHandles.push(data);
|
|
362
422
|
}
|
|
363
423
|
});
|
|
@@ -1896,9 +1956,6 @@ function PanelResizeHandle({
|
|
|
1896
1956
|
const committedValuesRef = useRef({
|
|
1897
1957
|
state
|
|
1898
1958
|
});
|
|
1899
|
-
useLayoutEffect(() => {
|
|
1900
|
-
committedValuesRef.current.state = state;
|
|
1901
|
-
});
|
|
1902
1959
|
useEffect(() => {
|
|
1903
1960
|
if (disabled) {
|
|
1904
1961
|
setResizeHandler(null);
|
|
@@ -2011,4 +2068,21 @@ function getPanelElementsForGroup(groupId, scope = document) {
|
|
|
2011
2068
|
return Array.from(scope.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
2012
2069
|
}
|
|
2013
2070
|
|
|
2014
|
-
|
|
2071
|
+
function getIntersectingRectangle(rectOne, rectTwo, strict) {
|
|
2072
|
+
if (!intersects(rectOne, rectTwo, strict)) {
|
|
2073
|
+
return {
|
|
2074
|
+
x: 0,
|
|
2075
|
+
y: 0,
|
|
2076
|
+
width: 0,
|
|
2077
|
+
height: 0
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
return {
|
|
2081
|
+
x: Math.max(rectOne.x, rectTwo.x),
|
|
2082
|
+
y: Math.max(rectOne.y, rectTwo.y),
|
|
2083
|
+
width: Math.min(rectOne.x + rectOne.width, rectTwo.x + rectTwo.width) - Math.max(rectOne.x, rectTwo.x),
|
|
2084
|
+
height: Math.min(rectOne.y + rectOne.height, rectTwo.y + rectTwo.height) - Math.max(rectOne.y, rectTwo.y)
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
export { Panel, PanelGroup, PanelResizeHandle, assert, getIntersectingRectangle, getPanelElement, getPanelElementsForGroup, getPanelGroupElement, getResizeHandleElement, getResizeHandleElementIndex, getResizeHandleElementsForGroup, getResizeHandlePanelIds, intersects };
|