| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 | // @flowimport type { ClientRectObject, PositioningStrategy } from '../types';import type { Boundary, RootBoundary } from '../enums';import { viewport } from '../enums';import getViewportRect from './getViewportRect';import getDocumentRect from './getDocumentRect';import listScrollParents from './listScrollParents';import getOffsetParent from './getOffsetParent';import getDocumentElement from './getDocumentElement';import getComputedStyle from './getComputedStyle';import { isElement, isHTMLElement } from './instanceOf';import getBoundingClientRect from './getBoundingClientRect';import getParentNode from './getParentNode';import contains from './contains';import getNodeName from './getNodeName';import rectToClientRect from '../utils/rectToClientRect';import { max, min } from '../utils/math';function getInnerBoundingClientRect(  element: Element,  strategy: PositioningStrategy) {  const rect = getBoundingClientRect(element, false, strategy === 'fixed');  rect.top = rect.top + element.clientTop;  rect.left = rect.left + element.clientLeft;  rect.bottom = rect.top + element.clientHeight;  rect.right = rect.left + element.clientWidth;  rect.width = element.clientWidth;  rect.height = element.clientHeight;  rect.x = rect.left;  rect.y = rect.top;  return rect;}function getClientRectFromMixedType(  element: Element,  clippingParent: Element | RootBoundary,  strategy: PositioningStrategy): ClientRectObject {  return clippingParent === viewport    ? rectToClientRect(getViewportRect(element, strategy))    : isElement(clippingParent)    ? getInnerBoundingClientRect(clippingParent, strategy)    : 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: Element): Array<Element> {  const clippingParents = listScrollParents(getParentNode(element));  const canEscapeClipping =    ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;  const clipperElement =    canEscapeClipping && isHTMLElement(element)      ? getOffsetParent(element)      : element;  if (!isElement(clipperElement)) {    return [];  }  // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414  return clippingParents.filter(    (clippingParent) =>      isElement(clippingParent) &&      contains(clippingParent, clipperElement) &&      getNodeName(clippingParent) !== 'body'  );}// Gets the maximum area that the element is visible in due to any number of// clipping parentsexport default function getClippingRect(  element: Element,  boundary: Boundary,  rootBoundary: RootBoundary,  strategy: PositioningStrategy): ClientRectObject {  const mainClippingParents =    boundary === 'clippingParents'      ? getClippingParents(element)      : [].concat(boundary);  const clippingParents = [...mainClippingParents, rootBoundary];  const firstClippingParent = clippingParents[0];  const clippingRect = clippingParents.reduce((accRect, clippingParent) => {    const rect = getClientRectFromMixedType(element, clippingParent, strategy);    accRect.top = max(rect.top, accRect.top);    accRect.right = min(rect.right, accRect.right);    accRect.bottom = min(rect.bottom, accRect.bottom);    accRect.left = max(rect.left, accRect.left);    return accRect;  }, getClientRectFromMixedType(element, firstClippingParent, strategy));  clippingRect.width = clippingRect.right - clippingRect.left;  clippingRect.height = clippingRect.bottom - clippingRect.top;  clippingRect.x = clippingRect.left;  clippingRect.y = clippingRect.top;  return clippingRect;}
 |