-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
Copy pathgetScrollParent.ts
59 lines (52 loc) · 1.88 KB
/
getScrollParent.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* Returns the parent node or the host of the node argument.
* @param node - DOM node.
* @returns - parent DOM node.
*/
export const getParentNode = (node: HTMLElement): HTMLElement => {
if (node.nodeName === 'HTML') {
return node;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return node.parentNode || (node as any).host;
};
/**
* Returns CSS styles of the given node.
* @param node - DOM node.
* @returns - CSS styles.
*/
const getStyleComputedProperty = (node: HTMLElement): Partial<CSSStyleDeclaration> => {
if (node.nodeType !== 1) {
return {};
}
const window = node.ownerDocument?.defaultView;
return window!.getComputedStyle(node, null);
};
/**
* Returns the first scrollable parent of the given element.
* @param node - DOM node.
* @returns - the first scrollable parent.
*/
export const getScrollParent = (node: Document | HTMLElement | null): HTMLElement => {
// Return body, `getScroll` will take care to get the correct `scrollTop` from it
const parentNode = node && getParentNode(node as HTMLElement);
// eslint-disable-next-line
if (!parentNode) return document.body;
switch (parentNode.nodeName) {
case 'HTML':
case 'BODY':
return parentNode.ownerDocument!.body;
case '#document':
return ((parentNode as unknown) as Document).body;
}
// If any of the overflow props is defined for the node then we return it as the parent
const { overflow, overflowX, overflowY } = getStyleComputedProperty(parentNode);
if (/(auto|scroll|overlay)/.test(overflow! + overflowY! + overflowX)) {
return parentNode;
}
return getScrollParent(parentNode);
};
export const hasScrollParent = (node: Document | HTMLElement | null): boolean => {
const scrollParentElement: HTMLElement = getScrollParent(node);
return scrollParentElement ? scrollParentElement !== scrollParentElement.ownerDocument?.body : false;
};