129 lines
4.9 KiB
JavaScript
129 lines
4.9 KiB
JavaScript
|
function getNodeName(node) {
|
||
|
if (isNode(node)) {
|
||
|
return (node.nodeName || '').toLowerCase();
|
||
|
}
|
||
|
// Mocked nodes in testing environments may not be instances of Node. By
|
||
|
// returning `#document` an infinite loop won't occur.
|
||
|
// https://github.com/floating-ui/floating-ui/issues/2317
|
||
|
return '#document';
|
||
|
}
|
||
|
function getWindow(node) {
|
||
|
var _node$ownerDocument;
|
||
|
return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
|
||
|
}
|
||
|
function getDocumentElement(node) {
|
||
|
var _ref;
|
||
|
return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
|
||
|
}
|
||
|
function isNode(value) {
|
||
|
return value instanceof Node || value instanceof getWindow(value).Node;
|
||
|
}
|
||
|
function isElement(value) {
|
||
|
return value instanceof Element || value instanceof getWindow(value).Element;
|
||
|
}
|
||
|
function isHTMLElement(value) {
|
||
|
return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
|
||
|
}
|
||
|
function isShadowRoot(value) {
|
||
|
// Browsers without `ShadowRoot` support.
|
||
|
if (typeof ShadowRoot === 'undefined') {
|
||
|
return false;
|
||
|
}
|
||
|
return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
|
||
|
}
|
||
|
function isOverflowElement(element) {
|
||
|
const {
|
||
|
overflow,
|
||
|
overflowX,
|
||
|
overflowY,
|
||
|
display
|
||
|
} = getComputedStyle(element);
|
||
|
return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !['inline', 'contents'].includes(display);
|
||
|
}
|
||
|
function isTableElement(element) {
|
||
|
return ['table', 'td', 'th'].includes(getNodeName(element));
|
||
|
}
|
||
|
function isContainingBlock(element) {
|
||
|
const webkit = isWebKit();
|
||
|
const css = getComputedStyle(element);
|
||
|
|
||
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
|
||
|
return css.transform !== 'none' || css.perspective !== 'none' || (css.containerType ? css.containerType !== 'normal' : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== 'none' : false) || !webkit && (css.filter ? css.filter !== 'none' : false) || ['transform', 'perspective', 'filter'].some(value => (css.willChange || '').includes(value)) || ['paint', 'layout', 'strict', 'content'].some(value => (css.contain || '').includes(value));
|
||
|
}
|
||
|
function getContainingBlock(element) {
|
||
|
let currentNode = getParentNode(element);
|
||
|
while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
|
||
|
if (isContainingBlock(currentNode)) {
|
||
|
return currentNode;
|
||
|
} else {
|
||
|
currentNode = getParentNode(currentNode);
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
function isWebKit() {
|
||
|
if (typeof CSS === 'undefined' || !CSS.supports) return false;
|
||
|
return CSS.supports('-webkit-backdrop-filter', 'none');
|
||
|
}
|
||
|
function isLastTraversableNode(node) {
|
||
|
return ['html', 'body', '#document'].includes(getNodeName(node));
|
||
|
}
|
||
|
function getComputedStyle(element) {
|
||
|
return getWindow(element).getComputedStyle(element);
|
||
|
}
|
||
|
function getNodeScroll(element) {
|
||
|
if (isElement(element)) {
|
||
|
return {
|
||
|
scrollLeft: element.scrollLeft,
|
||
|
scrollTop: element.scrollTop
|
||
|
};
|
||
|
}
|
||
|
return {
|
||
|
scrollLeft: element.pageXOffset,
|
||
|
scrollTop: element.pageYOffset
|
||
|
};
|
||
|
}
|
||
|
function getParentNode(node) {
|
||
|
if (getNodeName(node) === 'html') {
|
||
|
return node;
|
||
|
}
|
||
|
const result =
|
||
|
// Step into the shadow DOM of the parent of a slotted node.
|
||
|
node.assignedSlot ||
|
||
|
// DOM Element detected.
|
||
|
node.parentNode ||
|
||
|
// ShadowRoot detected.
|
||
|
isShadowRoot(node) && node.host ||
|
||
|
// Fallback.
|
||
|
getDocumentElement(node);
|
||
|
return isShadowRoot(result) ? result.host : result;
|
||
|
}
|
||
|
function getNearestOverflowAncestor(node) {
|
||
|
const parentNode = getParentNode(node);
|
||
|
if (isLastTraversableNode(parentNode)) {
|
||
|
return node.ownerDocument ? node.ownerDocument.body : node.body;
|
||
|
}
|
||
|
if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
|
||
|
return parentNode;
|
||
|
}
|
||
|
return getNearestOverflowAncestor(parentNode);
|
||
|
}
|
||
|
function getOverflowAncestors(node, list, traverseIframes) {
|
||
|
var _node$ownerDocument2;
|
||
|
if (list === void 0) {
|
||
|
list = [];
|
||
|
}
|
||
|
if (traverseIframes === void 0) {
|
||
|
traverseIframes = true;
|
||
|
}
|
||
|
const scrollableAncestor = getNearestOverflowAncestor(node);
|
||
|
const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
|
||
|
const win = getWindow(scrollableAncestor);
|
||
|
if (isBody) {
|
||
|
return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], win.frameElement && traverseIframes ? getOverflowAncestors(win.frameElement) : []);
|
||
|
}
|
||
|
return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
|
||
|
}
|
||
|
|
||
|
export { getComputedStyle, getContainingBlock, getDocumentElement, getNearestOverflowAncestor, getNodeName, getNodeScroll, getOverflowAncestors, getParentNode, getWindow, isContainingBlock, isElement, isHTMLElement, isLastTraversableNode, isNode, isOverflowElement, isShadowRoot, isTableElement, isWebKit };
|