All files / components/Tooltip position.js

100% Statements 21/21
100% Branches 12/12
100% Functions 3/3
100% Lines 21/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 693x 3x 3x   3x 10x           10x           3x 6x 1x     5x 5x 5x 5x   5x   5x                                   3x 5x 5x         5x   5x       5x                
const OFFSET = 12; // modified from reach-ui/tooltip OFFSET value
const TRIANGLE_SCALE_X = 6;
const TRIANGLE_SCALE_Y = 8;
 
const isDirectionUp = (triggerRect, tooltipRect) => {
  const collisions = {
    top: triggerRect.top - tooltipRect.height < 0,
    bottom:
      window.innerHeight < triggerRect.bottom + tooltipRect.height + OFFSET,
  };
 
  return !collisions.top || collisions.bottom;
};
 
// modified from @reach/tooltip default positioning function
// positions Tooltip relative to trigger
// https://github.com/reach/reach-ui/blob/master/packages/tooltip/src/index.tsx#L532
const positionTip = (triggerRect, tooltipRect) => {
  if (!triggerRect || !tooltipRect) {
    return {};
  }
 
  const triggerCenter = triggerRect.left + triggerRect.width / 2;
  const left = triggerCenter - tooltipRect.width / 2;
  const maxLeft = window.innerWidth - tooltipRect.width - 2;
  const centerLeft = Math.min(Math.max(2, left), maxLeft) + window.pageXOffset;
 
  const directionUp = isDirectionUp(triggerRect, tooltipRect);
 
  return {
    left: `${centerLeft}px`,
    top: directionUp
      ? `${
          triggerRect.top - OFFSET - tooltipRect.height + window.pageYOffset
        }px`
      : `${
          triggerRect.top + OFFSET + triggerRect.height + window.pageYOffset
        }px`,
  };
};
 
export default positionTip;
 
// position triangle relative to tooltip position
// TODO: figure out a better way to render these updates from within react
// rendering. This method causes an additional repaint after the Tooltip
// has been rendered. may require changes to @reach/tooltip.
export const positionTriangle = (triggerRect, tooltipRect) => {
  const directionUp = isDirectionUp(triggerRect, tooltipRect);
  const triangleTop = directionUp
    ? triggerRect.top + window.pageYOffset - OFFSET
    : triggerRect.bottom + window.pageYOffset + OFFSET - TRIANGLE_SCALE_Y;
 
  const triangleLeft =
    triggerRect.left - TRIANGLE_SCALE_X + triggerRect.width / 2;
 
  const triangleBorder = directionUp
    ? `border-top: ${TRIANGLE_SCALE_Y}px solid;`
    : `border-bottom: ${TRIANGLE_SCALE_Y}px solid;`;
 
  return `
        border-left: ${TRIANGLE_SCALE_X}px solid transparent;
        border-right: ${TRIANGLE_SCALE_X}px solid transparent;
        left: ${triangleLeft}px;
        top: ${triangleTop}px;
        ${triangleBorder}
    `;
};