1 | import getWindow from "./getWindow.js";
|
---|
2 | import getNodeName from "./getNodeName.js";
|
---|
3 | import getComputedStyle from "./getComputedStyle.js";
|
---|
4 | import { isHTMLElement, isShadowRoot } from "./instanceOf.js";
|
---|
5 | import isTableElement from "./isTableElement.js";
|
---|
6 | import getParentNode from "./getParentNode.js";
|
---|
7 | import getUAString from "../utils/userAgent.js";
|
---|
8 |
|
---|
9 | function getTrueOffsetParent(element) {
|
---|
10 | if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
|
---|
11 | getComputedStyle(element).position === 'fixed') {
|
---|
12 | return null;
|
---|
13 | }
|
---|
14 |
|
---|
15 | return element.offsetParent;
|
---|
16 | } // `.offsetParent` reports `null` for fixed elements, while absolute elements
|
---|
17 | // return the containing block
|
---|
18 |
|
---|
19 |
|
---|
20 | function getContainingBlock(element) {
|
---|
21 | var isFirefox = /firefox/i.test(getUAString());
|
---|
22 | var isIE = /Trident/i.test(getUAString());
|
---|
23 |
|
---|
24 | if (isIE && isHTMLElement(element)) {
|
---|
25 | // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport
|
---|
26 | var elementCss = getComputedStyle(element);
|
---|
27 |
|
---|
28 | if (elementCss.position === 'fixed') {
|
---|
29 | return null;
|
---|
30 | }
|
---|
31 | }
|
---|
32 |
|
---|
33 | var currentNode = getParentNode(element);
|
---|
34 |
|
---|
35 | if (isShadowRoot(currentNode)) {
|
---|
36 | currentNode = currentNode.host;
|
---|
37 | }
|
---|
38 |
|
---|
39 | while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {
|
---|
40 | var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that
|
---|
41 | // create a containing block.
|
---|
42 | // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
|
---|
43 |
|
---|
44 | if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {
|
---|
45 | return currentNode;
|
---|
46 | } else {
|
---|
47 | currentNode = currentNode.parentNode;
|
---|
48 | }
|
---|
49 | }
|
---|
50 |
|
---|
51 | return null;
|
---|
52 | } // Gets the closest ancestor positioned element. Handles some edge cases,
|
---|
53 | // such as table ancestors and cross browser bugs.
|
---|
54 |
|
---|
55 |
|
---|
56 | export default function getOffsetParent(element) {
|
---|
57 | var window = getWindow(element);
|
---|
58 | var offsetParent = getTrueOffsetParent(element);
|
---|
59 |
|
---|
60 | while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {
|
---|
61 | offsetParent = getTrueOffsetParent(offsetParent);
|
---|
62 | }
|
---|
63 |
|
---|
64 | if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {
|
---|
65 | return window;
|
---|
66 | }
|
---|
67 |
|
---|
68 | return offsetParent || getContainingBlock(element) || window;
|
---|
69 | } |
---|