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,7 +1,9 @@
|
|
|
1
|
+
import { compare } from "stacking-order";
|
|
1
2
|
import { Direction, ResizeEvent } from "./types";
|
|
2
3
|
import { resetGlobalCursorStyle, setGlobalCursorStyle } from "./utils/cursor";
|
|
3
4
|
import { getResizeEventCoordinates } from "./utils/events/getResizeEventCoordinates";
|
|
4
5
|
import { getInputType } from "./utils/getInputType";
|
|
6
|
+
import { intersects } from "./utils/rects/intersects";
|
|
5
7
|
|
|
6
8
|
export type ResizeHandlerAction = "down" | "move" | "up";
|
|
7
9
|
export type SetResizeHandlerState = (
|
|
@@ -75,11 +77,12 @@ export function registerResizeHandle(
|
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
function handlePointerDown(event: ResizeEvent) {
|
|
80
|
+
const { target } = event;
|
|
78
81
|
const { x, y } = getResizeEventCoordinates(event);
|
|
79
82
|
|
|
80
83
|
isPointerDown = true;
|
|
81
84
|
|
|
82
|
-
recalculateIntersectingHandles({ x, y });
|
|
85
|
+
recalculateIntersectingHandles({ target, x, y });
|
|
83
86
|
updateListeners();
|
|
84
87
|
|
|
85
88
|
if (intersectingHandles.length > 0) {
|
|
@@ -93,10 +96,12 @@ function handlePointerMove(event: ResizeEvent) {
|
|
|
93
96
|
const { x, y } = getResizeEventCoordinates(event);
|
|
94
97
|
|
|
95
98
|
if (!isPointerDown) {
|
|
99
|
+
const { target } = event;
|
|
100
|
+
|
|
96
101
|
// Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
|
|
97
102
|
// at that point, the handles may not move with the pointer (depending on constraints)
|
|
98
103
|
// but the same set of active handles should be locked until the pointer is released
|
|
99
|
-
recalculateIntersectingHandles({ x, y });
|
|
104
|
+
recalculateIntersectingHandles({ target, x, y });
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
updateResizeHandlerStates("move", event);
|
|
@@ -110,6 +115,7 @@ function handlePointerMove(event: ResizeEvent) {
|
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
function handlePointerUp(event: ResizeEvent) {
|
|
118
|
+
const { target } = event;
|
|
113
119
|
const { x, y } = getResizeEventCoordinates(event);
|
|
114
120
|
|
|
115
121
|
panelConstraintFlags.clear();
|
|
@@ -119,31 +125,92 @@ function handlePointerUp(event: ResizeEvent) {
|
|
|
119
125
|
event.preventDefault();
|
|
120
126
|
}
|
|
121
127
|
|
|
122
|
-
recalculateIntersectingHandles({ x, y });
|
|
123
128
|
updateResizeHandlerStates("up", event);
|
|
129
|
+
recalculateIntersectingHandles({ target, x, y });
|
|
124
130
|
updateCursor();
|
|
125
131
|
|
|
126
132
|
updateListeners();
|
|
127
133
|
}
|
|
128
134
|
|
|
129
|
-
function recalculateIntersectingHandles({
|
|
135
|
+
function recalculateIntersectingHandles({
|
|
136
|
+
target,
|
|
137
|
+
x,
|
|
138
|
+
y,
|
|
139
|
+
}: {
|
|
140
|
+
target: EventTarget | null;
|
|
141
|
+
x: number;
|
|
142
|
+
y: number;
|
|
143
|
+
}) {
|
|
130
144
|
intersectingHandles.splice(0);
|
|
131
145
|
|
|
146
|
+
let targetElement: HTMLElement | null = null;
|
|
147
|
+
if (target instanceof HTMLElement) {
|
|
148
|
+
targetElement = target;
|
|
149
|
+
}
|
|
150
|
+
|
|
132
151
|
registeredResizeHandlers.forEach((data) => {
|
|
133
|
-
const { element, hitAreaMargins } = data;
|
|
134
|
-
|
|
152
|
+
const { element: dragHandleElement, hitAreaMargins } = data;
|
|
153
|
+
|
|
154
|
+
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
155
|
+
const { bottom, left, right, top } = dragHandleRect;
|
|
135
156
|
|
|
136
157
|
const margin = isCoarsePointer
|
|
137
158
|
? hitAreaMargins.coarse
|
|
138
159
|
: hitAreaMargins.fine;
|
|
139
160
|
|
|
140
|
-
const
|
|
161
|
+
const eventIntersects =
|
|
141
162
|
x >= left - margin &&
|
|
142
163
|
x <= right + margin &&
|
|
143
164
|
y >= top - margin &&
|
|
144
165
|
y <= bottom + margin;
|
|
145
166
|
|
|
146
|
-
if (
|
|
167
|
+
if (eventIntersects) {
|
|
168
|
+
// TRICKY
|
|
169
|
+
// We listen for pointers events at the root in order to support hit area margins
|
|
170
|
+
// (determining when the pointer is close enough to an element to be considered a "hit")
|
|
171
|
+
// Clicking on an element "above" a handle (e.g. a modal) should prevent a hit though
|
|
172
|
+
// so at this point we need to compare stacking order of a potentially intersecting drag handle,
|
|
173
|
+
// and the element that was actually clicked/touched
|
|
174
|
+
if (
|
|
175
|
+
targetElement !== null &&
|
|
176
|
+
dragHandleElement !== targetElement &&
|
|
177
|
+
!dragHandleElement.contains(targetElement) &&
|
|
178
|
+
!targetElement.contains(dragHandleElement) &&
|
|
179
|
+
// Calculating stacking order has a cost, so we should avoid it if possible
|
|
180
|
+
// That is why we only check potentially intersecting handles,
|
|
181
|
+
// and why we skip if the event target is within the handle's DOM
|
|
182
|
+
compare(targetElement, dragHandleElement) > 0
|
|
183
|
+
) {
|
|
184
|
+
// If the target is above the drag handle, then we also need to confirm they overlap
|
|
185
|
+
// If they are beside each other (e.g. a panel and its drag handle) then the handle is still interactive
|
|
186
|
+
//
|
|
187
|
+
// It's not enough to compare only the target
|
|
188
|
+
// The target might be a small element inside of a larger container
|
|
189
|
+
// (For example, a SPAN or a DIV inside of a larger modal dialog)
|
|
190
|
+
let currentElement: HTMLElement | null = targetElement;
|
|
191
|
+
let didIntersect = false;
|
|
192
|
+
while (currentElement) {
|
|
193
|
+
if (currentElement.contains(dragHandleElement)) {
|
|
194
|
+
break;
|
|
195
|
+
} else if (
|
|
196
|
+
intersects(
|
|
197
|
+
currentElement.getBoundingClientRect(),
|
|
198
|
+
dragHandleRect,
|
|
199
|
+
true
|
|
200
|
+
)
|
|
201
|
+
) {
|
|
202
|
+
didIntersect = true;
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
currentElement = currentElement.parentElement;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (didIntersect) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
147
214
|
intersectingHandles.push(data);
|
|
148
215
|
}
|
|
149
216
|
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { isBrowser } from "#is-browser";
|
|
2
|
-
import {
|
|
2
|
+
import { useLayoutEffect_do_not_use_directly } from "../vendor/react";
|
|
3
3
|
|
|
4
|
-
const useIsomorphicLayoutEffect = isBrowser
|
|
4
|
+
const useIsomorphicLayoutEffect = isBrowser
|
|
5
|
+
? useLayoutEffect_do_not_use_directly
|
|
6
|
+
: () => {};
|
|
5
7
|
|
|
6
8
|
export default useIsomorphicLayoutEffect;
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,8 @@ import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement";
|
|
|
9
9
|
import { getResizeHandleElementIndex } from "./utils/dom/getResizeHandleElementIndex";
|
|
10
10
|
import { getResizeHandleElementsForGroup } from "./utils/dom/getResizeHandleElementsForGroup";
|
|
11
11
|
import { getResizeHandlePanelIds } from "./utils/dom/getResizeHandlePanelIds";
|
|
12
|
+
import { getIntersectingRectangle } from "./utils/rects/getIntersectingRectangle";
|
|
13
|
+
import { intersects } from "./utils/rects/intersects";
|
|
12
14
|
|
|
13
15
|
import type {
|
|
14
16
|
ImperativePanelHandle,
|
|
@@ -49,6 +51,8 @@ export {
|
|
|
49
51
|
|
|
50
52
|
// Utility methods
|
|
51
53
|
assert,
|
|
54
|
+
getIntersectingRectangle,
|
|
55
|
+
intersects,
|
|
52
56
|
|
|
53
57
|
// DOM helpers
|
|
54
58
|
getPanelElement,
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { getIntersectingRectangle } from "./getIntersectingRectangle";
|
|
2
|
+
import { Rectangle } from "./types";
|
|
3
|
+
|
|
4
|
+
const emptyRect = { x: 0, y: 0, width: 0, height: 0 };
|
|
5
|
+
const rect = { x: 25, y: 25, width: 50, height: 50 };
|
|
6
|
+
|
|
7
|
+
function forkRect(partial: Partial<Rectangle>, baseRect: Rectangle = rect) {
|
|
8
|
+
return { ...rect, ...partial };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe("getIntersectingRectangle", () => {
|
|
12
|
+
let strict: boolean = false;
|
|
13
|
+
|
|
14
|
+
function verify(rectOne: Rectangle, rectTwo: Rectangle, expected: Rectangle) {
|
|
15
|
+
const actual = getIntersectingRectangle(rectOne, rectTwo, strict);
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
expect(actual).toEqual(expected);
|
|
19
|
+
} catch (thrown) {
|
|
20
|
+
console.log(
|
|
21
|
+
"Expect",
|
|
22
|
+
strict ? "strict mode" : "loose mode",
|
|
23
|
+
"\n",
|
|
24
|
+
rectOne,
|
|
25
|
+
"\n",
|
|
26
|
+
rectTwo,
|
|
27
|
+
"\n\nto intersect as:\n",
|
|
28
|
+
expected,
|
|
29
|
+
"\n\nbut got:\n",
|
|
30
|
+
actual
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
throw thrown;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe("loose", () => {
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
strict = false;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should support empty rects", () => {
|
|
43
|
+
verify(emptyRect, emptyRect, emptyRect);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should support fully overlapping rects", () => {
|
|
47
|
+
verify(rect, forkRect({ x: 35, width: 30 }), {
|
|
48
|
+
x: 35,
|
|
49
|
+
y: 25,
|
|
50
|
+
width: 30,
|
|
51
|
+
height: 50,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
verify(rect, forkRect({ y: 35, height: 30 }), {
|
|
55
|
+
x: 25,
|
|
56
|
+
y: 35,
|
|
57
|
+
width: 50,
|
|
58
|
+
height: 30,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
verify(
|
|
62
|
+
rect,
|
|
63
|
+
forkRect({
|
|
64
|
+
x: 35,
|
|
65
|
+
y: 35,
|
|
66
|
+
width: 30,
|
|
67
|
+
height: 30,
|
|
68
|
+
}),
|
|
69
|
+
|
|
70
|
+
{
|
|
71
|
+
x: 35,
|
|
72
|
+
y: 35,
|
|
73
|
+
width: 30,
|
|
74
|
+
height: 30,
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should support partially overlapping rects", () => {
|
|
80
|
+
verify(rect, forkRect({ x: 10, y: 10 }), {
|
|
81
|
+
x: 25,
|
|
82
|
+
y: 25,
|
|
83
|
+
width: 35,
|
|
84
|
+
height: 35,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
verify(rect, forkRect({ x: 45, y: 30 }), {
|
|
88
|
+
x: 45,
|
|
89
|
+
y: 30,
|
|
90
|
+
width: 30,
|
|
91
|
+
height: 45,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should support non-overlapping rects", () => {
|
|
96
|
+
verify(rect, forkRect({ x: 100, y: 100 }), emptyRect);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should support all negative coordinates", () => {
|
|
100
|
+
verify(
|
|
101
|
+
{
|
|
102
|
+
x: -100,
|
|
103
|
+
y: -100,
|
|
104
|
+
width: 50,
|
|
105
|
+
height: 50,
|
|
106
|
+
},
|
|
107
|
+
{ x: -80, y: -80, width: 50, height: 50 },
|
|
108
|
+
{
|
|
109
|
+
x: -80,
|
|
110
|
+
y: -80,
|
|
111
|
+
width: 30,
|
|
112
|
+
height: 30,
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe("strict", () => {
|
|
119
|
+
beforeEach(() => {
|
|
120
|
+
strict = true;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should support empty rects", () => {
|
|
124
|
+
verify(emptyRect, emptyRect, emptyRect);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should support fully overlapping rects", () => {
|
|
128
|
+
verify(rect, forkRect({ x: 35, width: 30 }), {
|
|
129
|
+
x: 35,
|
|
130
|
+
y: 25,
|
|
131
|
+
width: 30,
|
|
132
|
+
height: 50,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
verify(rect, forkRect({ y: 35, height: 30 }), {
|
|
136
|
+
x: 25,
|
|
137
|
+
y: 35,
|
|
138
|
+
width: 50,
|
|
139
|
+
height: 30,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
verify(
|
|
143
|
+
rect,
|
|
144
|
+
forkRect({
|
|
145
|
+
x: 35,
|
|
146
|
+
y: 35,
|
|
147
|
+
width: 30,
|
|
148
|
+
height: 30,
|
|
149
|
+
}),
|
|
150
|
+
|
|
151
|
+
{
|
|
152
|
+
x: 35,
|
|
153
|
+
y: 35,
|
|
154
|
+
width: 30,
|
|
155
|
+
height: 30,
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should support partially overlapping rects", () => {
|
|
161
|
+
verify(rect, forkRect({ x: 10, y: 10 }), {
|
|
162
|
+
x: 25,
|
|
163
|
+
y: 25,
|
|
164
|
+
width: 35,
|
|
165
|
+
height: 35,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
verify(rect, forkRect({ x: 45, y: 30 }), {
|
|
169
|
+
x: 45,
|
|
170
|
+
y: 30,
|
|
171
|
+
width: 30,
|
|
172
|
+
height: 45,
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("should support non-overlapping rects", () => {
|
|
177
|
+
verify(rect, forkRect({ x: 100, y: 100 }), emptyRect);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should support all negative coordinates", () => {
|
|
181
|
+
verify(
|
|
182
|
+
{
|
|
183
|
+
x: -100,
|
|
184
|
+
y: -100,
|
|
185
|
+
width: 50,
|
|
186
|
+
height: 50,
|
|
187
|
+
},
|
|
188
|
+
{ x: -80, y: -80, width: 50, height: 50 },
|
|
189
|
+
{
|
|
190
|
+
x: -80,
|
|
191
|
+
y: -80,
|
|
192
|
+
width: 30,
|
|
193
|
+
height: 30,
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { intersects } from "./intersects";
|
|
2
|
+
import { Rectangle } from "./types";
|
|
3
|
+
|
|
4
|
+
export function getIntersectingRectangle(
|
|
5
|
+
rectOne: Rectangle,
|
|
6
|
+
rectTwo: Rectangle,
|
|
7
|
+
strict: boolean
|
|
8
|
+
): Rectangle {
|
|
9
|
+
if (!intersects(rectOne, rectTwo, strict)) {
|
|
10
|
+
return {
|
|
11
|
+
x: 0,
|
|
12
|
+
y: 0,
|
|
13
|
+
width: 0,
|
|
14
|
+
height: 0,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
x: Math.max(rectOne.x, rectTwo.x),
|
|
20
|
+
y: Math.max(rectOne.y, rectTwo.y),
|
|
21
|
+
width:
|
|
22
|
+
Math.min(rectOne.x + rectOne.width, rectTwo.x + rectTwo.width) -
|
|
23
|
+
Math.max(rectOne.x, rectTwo.x),
|
|
24
|
+
height:
|
|
25
|
+
Math.min(rectOne.y + rectOne.height, rectTwo.y + rectTwo.height) -
|
|
26
|
+
Math.max(rectOne.y, rectTwo.y),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { intersects } from "./intersects";
|
|
2
|
+
import { Rectangle } from "./types";
|
|
3
|
+
|
|
4
|
+
const emptyRect = { x: 0, y: 0, width: 0, height: 0 };
|
|
5
|
+
const rect = { x: 25, y: 25, width: 50, height: 50 };
|
|
6
|
+
|
|
7
|
+
function forkRect(partial: Partial<Rectangle>, baseRect: Rectangle = rect) {
|
|
8
|
+
return { ...rect, ...partial };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe("intersects", () => {
|
|
12
|
+
let strict: boolean = false;
|
|
13
|
+
|
|
14
|
+
function verify(rectOne: Rectangle, rectTwo: Rectangle, expected: boolean) {
|
|
15
|
+
const actual = intersects(rectOne, rectTwo, strict);
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
expect(actual).toBe(expected);
|
|
19
|
+
} catch (thrown) {
|
|
20
|
+
console.log(
|
|
21
|
+
"Expected",
|
|
22
|
+
rectOne,
|
|
23
|
+
"to",
|
|
24
|
+
expected ? "intersect" : "not intersect",
|
|
25
|
+
rectTwo,
|
|
26
|
+
strict ? "in strict mode" : "in loose mode"
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
throw thrown;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe("loose", () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
strict = false;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should handle empty rects", () => {
|
|
39
|
+
verify(emptyRect, emptyRect, true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should support fully overlapping rects", () => {
|
|
43
|
+
verify(rect, rect, true);
|
|
44
|
+
|
|
45
|
+
verify(rect, forkRect({ x: 35, width: 30 }), true);
|
|
46
|
+
verify(rect, forkRect({ y: 35, height: 30 }), true);
|
|
47
|
+
verify(
|
|
48
|
+
rect,
|
|
49
|
+
forkRect({
|
|
50
|
+
x: 35,
|
|
51
|
+
y: 35,
|
|
52
|
+
width: 30,
|
|
53
|
+
height: 30,
|
|
54
|
+
}),
|
|
55
|
+
true
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
verify(rect, forkRect({ x: 10, width: 100 }), true);
|
|
59
|
+
verify(rect, forkRect({ y: 10, height: 100 }), true);
|
|
60
|
+
verify(
|
|
61
|
+
rect,
|
|
62
|
+
forkRect({
|
|
63
|
+
x: 10,
|
|
64
|
+
y: 10,
|
|
65
|
+
width: 100,
|
|
66
|
+
height: 100,
|
|
67
|
+
}),
|
|
68
|
+
true
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should support partially overlapping rects", () => {
|
|
73
|
+
const cases: Partial<Rectangle>[] = [
|
|
74
|
+
{ x: 0 },
|
|
75
|
+
{ y: 0 },
|
|
76
|
+
|
|
77
|
+
// Loose mode only
|
|
78
|
+
{ x: -25 },
|
|
79
|
+
{ x: 75 },
|
|
80
|
+
{ y: -25 },
|
|
81
|
+
{ y: 75 },
|
|
82
|
+
{ x: -25, y: -25 },
|
|
83
|
+
{ x: 75, y: 75 },
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
cases.forEach((partial) => {
|
|
87
|
+
verify(forkRect(partial), rect, true);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should support non-overlapping rects", () => {
|
|
92
|
+
const cases: Partial<Rectangle>[] = [
|
|
93
|
+
{ x: 100 },
|
|
94
|
+
{ x: -100 },
|
|
95
|
+
{ y: 100 },
|
|
96
|
+
{ y: -100 },
|
|
97
|
+
{ x: -100, y: -100 },
|
|
98
|
+
{ x: 100, y: 100 },
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
cases.forEach((partial) => {
|
|
102
|
+
verify(forkRect(partial), rect, false);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should support all negative coordinates", () => {
|
|
107
|
+
expect(
|
|
108
|
+
intersects(
|
|
109
|
+
{ x: -100, y: -100, width: 50, height: 50 },
|
|
110
|
+
{ x: -110, y: -90, width: 50, height: 50 },
|
|
111
|
+
false
|
|
112
|
+
)
|
|
113
|
+
).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("strict", () => {
|
|
118
|
+
beforeEach(() => {
|
|
119
|
+
strict = true;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should handle empty rects", () => {
|
|
123
|
+
verify(emptyRect, emptyRect, false);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should support fully overlapping rects", () => {
|
|
127
|
+
verify(rect, rect, true);
|
|
128
|
+
|
|
129
|
+
verify(rect, forkRect({ x: 35, width: 30 }), true);
|
|
130
|
+
verify(rect, forkRect({ y: 35, height: 30 }), true);
|
|
131
|
+
verify(
|
|
132
|
+
rect,
|
|
133
|
+
forkRect({
|
|
134
|
+
x: 35,
|
|
135
|
+
y: 35,
|
|
136
|
+
width: 30,
|
|
137
|
+
height: 30,
|
|
138
|
+
}),
|
|
139
|
+
true
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
verify(rect, forkRect({ x: 10, width: 100 }), true);
|
|
143
|
+
verify(rect, forkRect({ y: 10, height: 100 }), true);
|
|
144
|
+
verify(
|
|
145
|
+
rect,
|
|
146
|
+
forkRect({
|
|
147
|
+
x: 10,
|
|
148
|
+
y: 10,
|
|
149
|
+
width: 100,
|
|
150
|
+
height: 100,
|
|
151
|
+
}),
|
|
152
|
+
true
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("should support partially overlapping rects", () => {
|
|
157
|
+
const cases: Partial<Rectangle>[] = [{ x: 0 }, { y: 0 }];
|
|
158
|
+
|
|
159
|
+
cases.forEach((partial) => {
|
|
160
|
+
verify(forkRect(partial), rect, true);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("should support non-overlapping rects", () => {
|
|
165
|
+
const cases: Partial<Rectangle>[] = [
|
|
166
|
+
{ x: 100 },
|
|
167
|
+
{ x: -100 },
|
|
168
|
+
{ y: 100 },
|
|
169
|
+
{ y: -100 },
|
|
170
|
+
{ x: -100, y: -100 },
|
|
171
|
+
{ x: 100, y: 100 },
|
|
172
|
+
|
|
173
|
+
// Strict mode only
|
|
174
|
+
{ x: -25 },
|
|
175
|
+
{ x: 75 },
|
|
176
|
+
{ y: -25 },
|
|
177
|
+
{ y: 75 },
|
|
178
|
+
{ x: -25, y: -25 },
|
|
179
|
+
{ x: 75, y: 75 },
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
cases.forEach((partial) => {
|
|
183
|
+
verify(forkRect(partial), rect, false);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("should support all negative coordinates", () => {
|
|
188
|
+
expect(
|
|
189
|
+
intersects(
|
|
190
|
+
{ x: -100, y: -100, width: 50, height: 50 },
|
|
191
|
+
{ x: -110, y: -90, width: 50, height: 50 },
|
|
192
|
+
true
|
|
193
|
+
)
|
|
194
|
+
).toBe(true);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Rectangle } from "./types";
|
|
2
|
+
|
|
3
|
+
export function intersects(
|
|
4
|
+
rectOne: Rectangle,
|
|
5
|
+
rectTwo: Rectangle,
|
|
6
|
+
strict: boolean
|
|
7
|
+
): boolean {
|
|
8
|
+
if (strict) {
|
|
9
|
+
return (
|
|
10
|
+
rectOne.x < rectTwo.x + rectTwo.width &&
|
|
11
|
+
rectOne.x + rectOne.width > rectTwo.x &&
|
|
12
|
+
rectOne.y < rectTwo.y + rectTwo.height &&
|
|
13
|
+
rectOne.y + rectOne.height > rectTwo.y
|
|
14
|
+
);
|
|
15
|
+
} else {
|
|
16
|
+
return (
|
|
17
|
+
rectOne.x <= rectTwo.x + rectTwo.width &&
|
|
18
|
+
rectOne.x + rectOne.width >= rectTwo.x &&
|
|
19
|
+
rectOne.y <= rectTwo.y + rectTwo.height &&
|
|
20
|
+
rectOne.y + rectOne.height >= rectTwo.y
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/vendor/react.ts
CHANGED
|
@@ -39,6 +39,8 @@ const {
|
|
|
39
39
|
// `toString()` prevents bundlers from trying to `import { useId } from 'react'`
|
|
40
40
|
const useId = (React as any)["useId".toString()] as () => string;
|
|
41
41
|
|
|
42
|
+
const useLayoutEffect_do_not_use_directly = useLayoutEffect;
|
|
43
|
+
|
|
42
44
|
export {
|
|
43
45
|
createElement,
|
|
44
46
|
createContext,
|
|
@@ -49,7 +51,7 @@ export {
|
|
|
49
51
|
useEffect,
|
|
50
52
|
useId,
|
|
51
53
|
useImperativeHandle,
|
|
52
|
-
|
|
54
|
+
useLayoutEffect_do_not_use_directly,
|
|
53
55
|
useMemo,
|
|
54
56
|
useRef,
|
|
55
57
|
useState,
|