[Flare] Ensure getAbsoluteBoundingClientRect aligns with offsetParent (#15720)
Dominic Gannaway committed
May 23, 2019 at 13:51 UTC
025b07b61038300486b44c71f796a74cbdcd5d9f
2 files changed
+24
-13
packages/react-events/src/Press.js
+23
-13
@@ -426,6 +426,18 @@ function calculateDelayMS(delay: ?number, min = 0, fallback = 0) {
426
return Math.max(min, maybeNumber != null ? maybeNumber : fallback);
427
}
428
429
+function isNodeFixedPositioned(node: Node | null | void): boolean {
430
+ return (
431
+ node != null &&
432
+ (node: any).offsetParent === null &&
433
+ !isNodeDocumentNode(node.parentNode)
434
+ );
435
+}
436
+
437
+function isNodeDocumentNode(node: Node | null | void): boolean {
438
+ return node != null && node.nodeType === Node.DOCUMENT_NODE;
439
+}
440
+
441
function getAbsoluteBoundingClientRect(
442
target: Element,
443
): {left: number, right: number, bottom: number, top: number} {
@@ -440,25 +452,23 @@ function getAbsoluteBoundingClientRect(
452
const parent = node.parentNode;
453
const scrollTop = (node: any).scrollTop;
454
const scrollLeft = (node: any).scrollLeft;
443
- const isParentDocumentNode =
444
- parent != null && parent.nodeType === Node.DOCUMENT_NODE;
445
-
446
- // Check if the current node is fixed position, by using
447
- // offsetParent node for a fast-path. Then we need to
448
- // check if it's a scrollable container by checking if
449
- // either scrollLeft or scrollTop are not 0. If it is
450
- // a scrollable container and the parent node is not
451
- // the document, then we can stop traversing the tree.
455
+
456
+ // We first need to check if it's a scrollable container by
457
+ // checking if either scrollLeft or scrollTop are not 0.
458
+ // Then we check if either the current node or its parent
459
+ // are fixed position, using offsetParent node for a fast-path.
460
+ // We need to check both as offsetParent accounts for both
461
+ // itself and the parent; so we need to align with that API.
462
+ // If these all pass, we can stop traversing the tree.
463
if (
453
- !isParentDocumentNode &&
454
- (node: any).offsetParent === null &&
455
- (scrollLeft !== 0 || scrollTop !== 0)
464
+ (scrollLeft !== 0 || scrollTop !== 0) &&
465
+ (isNodeFixedPositioned(parent) || isNodeFixedPositioned(node))
466
) {
467
break;
468
}
469
offsetX += scrollLeft;
470
offsetY += scrollTop;
461
- if (isParentDocumentNode) {
471
+ if (isNodeDocumentNode(parent)) {
472
break;
473
}
474
node = parent;
packages/react-events/src/__tests__/Press-test.internal.js
+1
@@ -1167,6 +1167,7 @@ describe('Event responder: Press', () => {
1167
1168
// The fixed container is not scrolled
1169
fixedDiv.scrollTop = 0;
1170
+ fixedDiv.scrollLeft = 0;
1171
ref.current.getBoundingClientRect = getBoundingClientRectMock;
1172
// Emulate the <html> element being offset with scroll
1173
document.firstElementChild.scrollTop = 1000;