34 lines
1.2 KiB
Text
34 lines
1.2 KiB
Text
|
// @flow
|
||
|
import getScrollParent from './getScrollParent';
|
||
|
import getParentNode from './getParentNode';
|
||
|
import getWindow from './getWindow';
|
||
|
import type { Window, VisualViewport } from '../types';
|
||
|
import isScrollParent from './isScrollParent';
|
||
|
|
||
|
/*
|
||
|
given a DOM element, return the list of all scroll parents, up the list of ancesors
|
||
|
until we get to the top window object. This list is what we attach scroll listeners
|
||
|
to, because if any of these parent elements scroll, we'll need to re-calculate the
|
||
|
reference element's position.
|
||
|
*/
|
||
|
export default function listScrollParents(
|
||
|
element: Node,
|
||
|
list: Array<Element | Window> = []
|
||
|
): Array<Element | Window | VisualViewport> {
|
||
|
const scrollParent = getScrollParent(element);
|
||
|
const isBody = scrollParent === element.ownerDocument?.body;
|
||
|
const win = getWindow(scrollParent);
|
||
|
const target = isBody
|
||
|
? [win].concat(
|
||
|
win.visualViewport || [],
|
||
|
isScrollParent(scrollParent) ? scrollParent : []
|
||
|
)
|
||
|
: scrollParent;
|
||
|
const updatedList = list.concat(target);
|
||
|
|
||
|
return isBody
|
||
|
? updatedList
|
||
|
: // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
|
||
|
updatedList.concat(listScrollParents(getParentNode(target)));
|
||
|
}
|