UNPKG

@popperjs/core

Version:

Tooltip and Popover Positioning Engine

56 lines (48 loc) 2.94 kB
import { viewport } from "../enums.js"; import getViewportRect from "./getViewportRect.js"; import getDocumentRect from "./getDocumentRect.js"; import listScrollParents from "./listScrollParents.js"; import getOffsetParent from "./getOffsetParent.js"; import getDocumentElement from "./getDocumentElement.js"; import getComputedStyle from "./getComputedStyle.js"; import { isElement, isHTMLElement } from "./instanceOf.js"; import getBoundingClientRect from "./getBoundingClientRect.js"; import getDecorations from "./getDecorations.js"; import contains from "./contains.js"; import rectToClientRect from "../utils/rectToClientRect.js"; function getClientRectFromMixedType(element, clippingParent) { return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element))); } // A "clipping parent" is an overflowable container with the characteristic of // clipping (or hiding) overflowing elements with a position different from // `initial` function getClippingParents(element) { var clippingParents = listScrollParents(element); var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0; var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element; if (!isElement(clipperElement)) { return []; } // $FlowFixMe: https://github.com/facebook/flow/issues/1414 return clippingParents.filter(function (clippingParent) { return isElement(clippingParent) && contains(clippingParent, clipperElement); }); } // Gets the maximum area that the element is visible in due to any number of // clipping parents export default function getClippingRect(element, boundary, rootBoundary) { var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary); var clippingParents = [].concat(mainClippingParents, [rootBoundary]); var firstClippingParent = clippingParents[0]; var clippingRect = clippingParents.reduce(function (accRect, clippingParent) { var rect = getClientRectFromMixedType(element, clippingParent); var decorations = getDecorations(isHTMLElement(clippingParent) ? clippingParent : getDocumentElement(element)); accRect.top = Math.max(rect.top + decorations.top, accRect.top); accRect.right = Math.min(rect.right - decorations.right, accRect.right); accRect.bottom = Math.min(rect.bottom - decorations.bottom, accRect.bottom); accRect.left = Math.max(rect.left + decorations.left, accRect.left); return accRect; }, getClientRectFromMixedType(element, firstClippingParent)); clippingRect.width = clippingRect.right - clippingRect.left; clippingRect.height = clippingRect.bottom - clippingRect.top; clippingRect.x = clippingRect.left; clippingRect.y = clippingRect.top; return clippingRect; }