Skip to content

Commit

Permalink
Merge pull request Expensify#20240 from bernhardoj/fix/improve-toolti…
Browse files Browse the repository at this point in the history
…p-overlap-check

Show tooltip below as soon as another element overlap the top edge
  • Loading branch information
pecanoro authored Jun 27, 2023
2 parents c122266 + e52bb39 commit 27d657e
Showing 1 changed file with 9 additions and 15 deletions.
24 changes: 9 additions & 15 deletions src/styles/getTooltipStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ function computeHorizontalShift(windowWidth, xOffset, componentWidth, tooltipWid
}

/**
* Determines if there is an overlapping element at the top of both given coordinates.
* Determines if there is an overlapping element at the top of a given coordinate.
* (targetCenterX, y)
* |
* v
* _ _ _ _ _
* | |
* | |
* (x, targetCenterY) -> | |
* | |
* | |
* |_ _ _ _ _|
*
Expand All @@ -67,37 +67,31 @@ function computeHorizontalShift(windowWidth, xOffset, componentWidth, tooltipWid
* and the top edge of the wrapped component.
* @param {Element} [tooltip] - The reference to the tooltip's root element
* @param {Number} tooltipTargetWidth - The width of the tooltip's target
* @param {Number} tooltipTargetHeight - The height of the tooltip's target
* @returns {Boolean}
*/
function isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetWidth, tooltipTargetHeight) {
function isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetWidth) {
if (typeof document.elementFromPoint !== 'function') {
return false;
}

// Use the x and y center position of the target to prevent wrong element
// returned by elementFromPoint in case the target has a border radius or is a multiline text.
// Use the x center position of the target to prevent wrong element returned by elementFromPoint
// in case the target has a border radius or is a multiline text.
const targetCenterX = xOffset + tooltipTargetWidth / 2;
const targetCenterY = yOffset + tooltipTargetHeight / 2;
const elementAtTargetCenterX = document.elementFromPoint(targetCenterX, yOffset);
const elementAtTargetCenterY = document.elementFromPoint(xOffset, targetCenterY);
const tooltipRef = (tooltip && tooltip.current) || tooltip;

// Ensure it's not the already rendered element of this very tooltip, so the tooltip doesn't try to "avoid" itself
if (!elementAtTargetCenterX || !elementAtTargetCenterY || (tooltipRef && (tooltipRef.contains(elementAtTargetCenterX) || tooltipRef.contains(elementAtTargetCenterY)))) {
if (!elementAtTargetCenterX || (tooltipRef && tooltipRef.contains(elementAtTargetCenterX))) {
return false;
}

const rectAtTargetCenterX = elementAtTargetCenterX.getBoundingClientRect();
const rectAtTargetCenterY = elementAtTargetCenterY.getBoundingClientRect();

// Ensure it's not overlapping with another element by checking if the yOffset is greater than the top of the element
// and less than the bottom of the element
const isOverlappingAtTargetCenterX = yOffset > rectAtTargetCenterX.top && yOffset < rectAtTargetCenterX.bottom;
const isOverlappingAtTargetCenterY = yOffset > rectAtTargetCenterY.top && yOffset < rectAtTargetCenterY.bottom;

// Return true only if both elementAtTargetCenterX and elementAtTargetCenterY overlap with another element
return isOverlappingAtTargetCenterX && isOverlappingAtTargetCenterY;
return isOverlappingAtTargetCenterX;
}

/**
Expand Down Expand Up @@ -160,9 +154,9 @@ export default function getTooltipStyles(
if (isTooltipSizeReady) {
// Determine if the tooltip should display below the wrapped component.
// If either a tooltip will try to render within GUTTER_WIDTH logical pixels of the top of the screen,
// Or the wrapped component is overlapping at top-left with another element
// Or the wrapped component is overlapping at top-center with another element
// we'll display it beneath its wrapped component rather than above it as usual.
shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetWidth, tooltipTargetHeight);
shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetWidth);

// When the tooltip size is ready, we can start animating the scale.
scale = currentSize;
Expand Down

0 comments on commit 27d657e

Please sign in to comment.