Files
Webklar.com/node_modules/react-remove-scroll/dist/es2019/handleScroll.js
Basilosaurusrex f027651f9b main repo
2025-11-24 18:09:40 +01:00

96 lines
3.9 KiB
JavaScript

const alwaysContainsScroll = (node) =>
// textarea will always _contain_ scroll inside self. It only can be hidden
node.tagName === 'TEXTAREA';
const elementCanBeScrolled = (node, overflow) => {
if (!(node instanceof Element)) {
return false;
}
const styles = window.getComputedStyle(node);
return (
// not-not-scrollable
styles[overflow] !== 'hidden' &&
// contains scroll inside self
!(styles.overflowY === styles.overflowX && !alwaysContainsScroll(node) && styles[overflow] === 'visible'));
};
const elementCouldBeVScrolled = (node) => elementCanBeScrolled(node, 'overflowY');
const elementCouldBeHScrolled = (node) => elementCanBeScrolled(node, 'overflowX');
export const locationCouldBeScrolled = (axis, node) => {
const ownerDocument = node.ownerDocument;
let current = node;
do {
// Skip over shadow root
if (typeof ShadowRoot !== 'undefined' && current instanceof ShadowRoot) {
current = current.host;
}
const isScrollable = elementCouldBeScrolled(axis, current);
if (isScrollable) {
const [, scrollHeight, clientHeight] = getScrollVariables(axis, current);
if (scrollHeight > clientHeight) {
return true;
}
}
current = current.parentNode;
} while (current && current !== ownerDocument.body);
return false;
};
const getVScrollVariables = ({ scrollTop, scrollHeight, clientHeight }) => [
scrollTop,
scrollHeight,
clientHeight,
];
const getHScrollVariables = ({ scrollLeft, scrollWidth, clientWidth }) => [
scrollLeft,
scrollWidth,
clientWidth,
];
const elementCouldBeScrolled = (axis, node) => axis === 'v' ? elementCouldBeVScrolled(node) : elementCouldBeHScrolled(node);
const getScrollVariables = (axis, node) => axis === 'v' ? getVScrollVariables(node) : getHScrollVariables(node);
const getDirectionFactor = (axis, direction) =>
/**
* If the element's direction is rtl (right-to-left), then scrollLeft is 0 when the scrollbar is at its rightmost position,
* and then increasingly negative as you scroll towards the end of the content.
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
*/
axis === 'h' && direction === 'rtl' ? -1 : 1;
export const handleScroll = (axis, endTarget, event, sourceDelta, noOverscroll) => {
const directionFactor = getDirectionFactor(axis, window.getComputedStyle(endTarget).direction);
const delta = directionFactor * sourceDelta;
// find scrollable target
let target = event.target;
const targetInLock = endTarget.contains(target);
let shouldCancelScroll = false;
const isDeltaPositive = delta > 0;
let availableScroll = 0;
let availableScrollTop = 0;
do {
const [position, scroll, capacity] = getScrollVariables(axis, target);
const elementScroll = scroll - capacity - directionFactor * position;
if (position || elementScroll) {
if (elementCouldBeScrolled(axis, target)) {
availableScroll += elementScroll;
availableScrollTop += position;
}
}
if (target instanceof ShadowRoot) {
target = target.host;
}
else {
target = target.parentNode;
}
} while (
// portaled content
(!targetInLock && target !== document.body) ||
// self content
(targetInLock && (endTarget.contains(target) || endTarget === target)));
// handle epsilon around 0 (non standard zoom levels)
if (isDeltaPositive &&
((noOverscroll && Math.abs(availableScroll) < 1) || (!noOverscroll && delta > availableScroll))) {
shouldCancelScroll = true;
}
else if (!isDeltaPositive &&
((noOverscroll && Math.abs(availableScrollTop) < 1) || (!noOverscroll && -delta > availableScrollTop))) {
shouldCancelScroll = true;
}
return shouldCancelScroll;
};