You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

69 lines
3.2 KiB

  1. import { viewport } from "../enums.js";
  2. import getViewportRect from "./getViewportRect.js";
  3. import getDocumentRect from "./getDocumentRect.js";
  4. import listScrollParents from "./listScrollParents.js";
  5. import getOffsetParent from "./getOffsetParent.js";
  6. import getDocumentElement from "./getDocumentElement.js";
  7. import getComputedStyle from "./getComputedStyle.js";
  8. import { isElement, isHTMLElement } from "./instanceOf.js";
  9. import getBoundingClientRect from "./getBoundingClientRect.js";
  10. import getParentNode from "./getParentNode.js";
  11. import contains from "./contains.js";
  12. import getNodeName from "./getNodeName.js";
  13. import rectToClientRect from "../utils/rectToClientRect.js";
  14. import { max, min } from "../utils/math.js";
  15. function getInnerBoundingClientRect(element) {
  16. var rect = getBoundingClientRect(element);
  17. rect.top = rect.top + element.clientTop;
  18. rect.left = rect.left + element.clientLeft;
  19. rect.bottom = rect.top + element.clientHeight;
  20. rect.right = rect.left + element.clientWidth;
  21. rect.width = element.clientWidth;
  22. rect.height = element.clientHeight;
  23. rect.x = rect.left;
  24. rect.y = rect.top;
  25. return rect;
  26. }
  27. function getClientRectFromMixedType(element, clippingParent) {
  28. return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
  29. } // A "clipping parent" is an overflowable container with the characteristic of
  30. // clipping (or hiding) overflowing elements with a position different from
  31. // `initial`
  32. function getClippingParents(element) {
  33. var clippingParents = listScrollParents(getParentNode(element));
  34. var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;
  35. var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
  36. if (!isElement(clipperElement)) {
  37. return [];
  38. } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414
  39. return clippingParents.filter(function (clippingParent) {
  40. return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';
  41. });
  42. } // Gets the maximum area that the element is visible in due to any number of
  43. // clipping parents
  44. export default function getClippingRect(element, boundary, rootBoundary) {
  45. var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);
  46. var clippingParents = [].concat(mainClippingParents, [rootBoundary]);
  47. var firstClippingParent = clippingParents[0];
  48. var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {
  49. var rect = getClientRectFromMixedType(element, clippingParent);
  50. accRect.top = max(rect.top, accRect.top);
  51. accRect.right = min(rect.right, accRect.right);
  52. accRect.bottom = min(rect.bottom, accRect.bottom);
  53. accRect.left = max(rect.left, accRect.left);
  54. return accRect;
  55. }, getClientRectFromMixedType(element, firstClippingParent));
  56. clippingRect.width = clippingRect.right - clippingRect.left;
  57. clippingRect.height = clippingRect.bottom - clippingRect.top;
  58. clippingRect.x = clippingRect.left;
  59. clippingRect.y = clippingRect.top;
  60. return clippingRect;
  61. }