@base-ui/react
Version:
Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.
51 lines • 2.19 kB
JavaScript
import { getComputedStyle, getParentNode, isHTMLElement, isLastTraversableNode } from '@floating-ui/utils/dom';
export function isScrollableY(element, allowOverflowIntent = false) {
const {
overflowY
} = getComputedStyle(element);
if (overflowY !== 'auto' && overflowY !== 'scroll') {
return false;
}
// When `allowOverflowIntent` is true, a container that overflows only once extra space is
// added (e.g. drawer keyboard scroll slack) still counts, as long as it has layout size on
// the axis.
return allowOverflowIntent ? element.clientHeight > 0 : element.scrollHeight > element.clientHeight;
}
export function isScrollableX(element, allowOverflowIntent = false) {
const {
overflowX
} = getComputedStyle(element);
if (overflowX !== 'auto' && overflowX !== 'scroll') {
return false;
}
return allowOverflowIntent ? element.clientWidth > 0 : element.scrollWidth > element.clientWidth;
}
export function isScrollable(element, axis, allowOverflowIntent = false) {
return axis === 'vertical' ? isScrollableY(element, allowOverflowIntent) : isScrollableX(element, allowOverflowIntent);
}
export function hasScrollableAncestor(target, root, axes) {
// `getParentNode` crosses shadow boundaries (and slots), so a target inside a shadow root
// still walks up to scrollable ancestors in the light DOM.
let node = target;
while (isHTMLElement(node) && node !== root && !isLastTraversableNode(node)) {
for (const axis of axes) {
if (isScrollable(node, axis)) {
return true;
}
}
node = getParentNode(node);
}
return false;
}
export function findScrollableTouchTarget(target, root, axis = 'vertical', allowOverflowIntent = false) {
// `getParentNode` crosses shadow boundaries (and slots), so a target inside a shadow root
// still reaches a scrollable ancestor in the light DOM.
let node = isHTMLElement(target) ? target : null;
while (isHTMLElement(node) && node !== root && !isLastTraversableNode(node)) {
if (isScrollable(node, axis, allowOverflowIntent)) {
return node;
}
node = getParentNode(node);
}
return isScrollable(root, axis, allowOverflowIntent) ? root : null;
}