Skip to content

Commit ff4875c

Browse files
committed
fix: restore smallest-area fallback and exclude decorative overlays from index
The bugbot-driven change from smallest-area to first-valid (topmost) in the fallback path reintroduced the original "stuck on decorative overlay" bug. Decorative overlay divs (positioned, empty, transparent) are topmost in elementsFromPoint results, so taking the first valid element returns the overlay instead of the content underneath. Fallback path: restored smallest-area selection. elementsFromPoint returns in z-order; smallest-area naturally skips large overlays in favor of specific content elements. Handles modals correctly because modal content elements are smaller than background content at the same point. Prehit path: exclude positioned elements with no children and no text from the R-tree. These are decorative hover-effect divs that should never be selection targets. The stacking-order sort then operates only on meaningful content elements.
1 parent de5ffe6 commit ff4875c

File tree

2 files changed

+14
-4
lines changed

2 files changed

+14
-4
lines changed

packages/react-grab/src/utils/element-at-point-index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,13 @@ export const buildElementAtPointIndex = (): void => {
4747
const boundingRect = entry.boundingClientRect;
4848
if (boundingRect.width === 0 || boundingRect.height === 0) continue;
4949
if (!isValidGrabbableElement(targetElement)) continue;
50-
if (getComputedStyle(targetElement).position === "fixed") continue;
50+
const computedPosition = getComputedStyle(targetElement).position;
51+
if (computedPosition === "fixed") continue;
52+
if (
53+
(computedPosition === "absolute" || computedPosition === "sticky") &&
54+
targetElement.childElementCount === 0 &&
55+
(targetElement.textContent?.trim().length ?? 0) === 0
56+
) continue;
5157

5258
accumulatedElements.push({
5359
element: targetElement,

packages/react-grab/src/utils/get-element-at-position.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,16 @@ export const getElementAtPosition = (clientX: number, clientY: number): Element
8686

8787
const elementsAtPoint = document.elementsFromPoint(clientX, clientY);
8888
let result: Element | null = null;
89+
let smallestArea = Infinity;
8990

9091
for (const candidateElement of elementsAtPoint) {
9192
if (!isValidGrabbableElement(candidateElement)) continue;
92-
if (getElementArea(candidateElement) === 0) continue;
93-
result = candidateElement;
94-
break;
93+
const area = getElementArea(candidateElement);
94+
if (area === 0) continue;
95+
if (area < smallestArea) {
96+
smallestArea = area;
97+
result = candidateElement;
98+
}
9599
}
96100

97101
scheduleResume();

0 commit comments

Comments
 (0)