@uiw/react-overlay-trigger
Version:
OverlayTrigger component
78 lines (67 loc) • 2.52 kB
text/typescript
import { getScroll } from '@uiw/utils';
import getStyleComputedProperty from './getStyleComputedProperty';
import getBordersSize from './getBordersSize';
import getWindowSizes, { WindowSize } from './getWindowSizes';
import getClientRect from './getClientRect';
import isIE from './isIE';
export interface IBoundingClientRect extends DOMRect {
left: number;
right: number;
top: number;
bottom: number;
width: number;
height: number;
offsetLeft?: number;
offsetTop?: number;
}
/**
* Get bounding client rect of given element
* @method
* @memberof Popper.Utils
* @param {HTMLElement} element
* @return {Object} client rect
*/
export default function getBoundingClientRect(element: HTMLElement) {
let rect = {} as IBoundingClientRect;
// IE10 10 FIX: Please, don't ask, the element isn't
// considered in DOM in some circumstances...
// This isn't reproducible in IE10 compatibility mode of IE11
try {
if (isIE(10)) {
rect = element.getBoundingClientRect();
const scrollTop = getScroll(element, true);
const scrollLeft = getScroll(element);
rect.top += scrollTop;
rect.left += scrollLeft;
rect.bottom += scrollTop;
rect.right += scrollLeft;
} else {
rect = element.getBoundingClientRect();
}
// eslint-disable-next-line
} catch (e) {}
const result = {
left: rect.left,
top: rect.top,
width: rect.right - rect.left,
height: rect.bottom - rect.top,
} as IBoundingClientRect;
// subtract scrollbar size from sizes
const sizes: WindowSize = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument!) : {};
const width = sizes.width || element.clientWidth || result.right - result.left;
const height = sizes.height || element.clientHeight || result.bottom - result.top;
let horizScrollbar = element.offsetWidth - width;
let vertScrollbar = element.offsetHeight - height;
result.offsetLeft = element.offsetLeft || element.scrollLeft || 0;
result.offsetTop = element.offsetTop || element.offsetTop || 0;
// if an hypothetical scrollbar is detected, we must be sure it's not a `border`
// we make this check conditional for performance reasons
if (horizScrollbar || vertScrollbar) {
const styles = getStyleComputedProperty(element);
horizScrollbar -= getBordersSize(styles, 'x');
vertScrollbar -= getBordersSize(styles, 'y');
result.width -= horizScrollbar;
result.height -= vertScrollbar;
}
return getClientRect(result) as IBoundingClientRect;
}