@fastkit/body-scroll-lock
Version:
@fastkit/body-scroll-lock
160 lines (158 loc) • 5.03 kB
JavaScript
import { IN_WINDOW } from '@fastkit/helpers';
var isIosDevice = IN_WINDOW && !!window.navigator && !!window.navigator.platform && /iP(ad|hone|od)/.test(window.navigator.platform);
var locks = [];
var documentListenerAdded = false;
var initialClientY = -1;
var previousBodyOverflowSetting;
var previousBodyPaddingRight;
var allowTouchMove = (el) => locks.some((lock) => {
if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) {
return true;
}
return false;
});
var preventDefault = (rawEvent) => {
const e = rawEvent || window.event;
if (allowTouchMove(e.target)) {
return true;
}
if (e.touches.length > 1) return true;
if (e.preventDefault) e.preventDefault();
return false;
};
var setOverflowHidden = (options) => {
setTimeout(() => {
if (previousBodyPaddingRight === void 0) {
const reserveScrollBarGap = !!options && options.reserveScrollBarGap === true;
const scrollBarGap = window.innerWidth - document.documentElement.clientWidth;
if (reserveScrollBarGap && scrollBarGap > 0) {
previousBodyPaddingRight = document.body.style.paddingRight;
document.body.style.paddingRight = `${scrollBarGap}px`;
}
}
if (previousBodyOverflowSetting === void 0) {
previousBodyOverflowSetting = document.body.style.overflow;
document.body.style.overflow = "hidden";
}
});
};
var restoreOverflowSetting = () => {
setTimeout(() => {
if (previousBodyPaddingRight !== void 0) {
document.body.style.paddingRight = previousBodyPaddingRight;
previousBodyPaddingRight = void 0;
}
if (previousBodyOverflowSetting !== void 0) {
document.body.style.overflow = previousBodyOverflowSetting;
previousBodyOverflowSetting = void 0;
}
});
};
var isTargetElementTotallyScrolled = (targetElement) => targetElement ? targetElement.scrollHeight - targetElement.scrollTop <= targetElement.clientHeight : false;
var handleScroll = (event, targetElement) => {
const clientY = event.targetTouches[0].clientY - initialClientY;
if (allowTouchMove(event.target)) {
return false;
}
if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {
return preventDefault(event);
}
if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) {
return preventDefault(event);
}
event.stopPropagation();
return true;
};
var disableBodyScroll = (targetElement, options) => {
if (!IN_WINDOW) return;
if (isIosDevice) {
if (!targetElement) {
console.error(
"disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices."
);
return;
}
if (targetElement && !locks.some((lock) => lock.targetElement === targetElement)) {
const lock = {
targetElement,
options: options || {}
};
locks = [...locks, lock];
targetElement.ontouchstart = (event) => {
if (event.targetTouches.length === 1) {
initialClientY = event.targetTouches[0].clientY;
}
};
targetElement.ontouchmove = (event) => {
if (event.targetTouches.length === 1) {
handleScroll(event, targetElement);
}
};
if (!documentListenerAdded) {
document.addEventListener("touchmove", preventDefault, {
passive: false
});
documentListenerAdded = true;
}
}
} else {
setOverflowHidden(options);
const lock = {
targetElement,
options: options || {}
};
locks = [...locks, lock];
}
};
var clearAllBodyScrollLocks = () => {
if (!IN_WINDOW) return;
if (isIosDevice) {
locks.forEach((lock) => {
lock.targetElement.ontouchstart = null;
lock.targetElement.ontouchmove = null;
});
if (documentListenerAdded) {
document.removeEventListener(
"touchmove",
preventDefault,
{ passive: false }
);
documentListenerAdded = false;
}
locks = [];
initialClientY = -1;
} else {
restoreOverflowSetting();
locks = [];
}
};
var enableBodyScroll = (targetElement) => {
if (!IN_WINDOW) return;
if (isIosDevice) {
if (!targetElement) {
console.error(
"enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices."
);
return;
}
targetElement.ontouchstart = null;
targetElement.ontouchmove = null;
locks = locks.filter((lock) => lock.targetElement !== targetElement);
if (documentListenerAdded && locks.length === 0) {
document.removeEventListener(
"touchmove",
preventDefault,
{ passive: false }
);
documentListenerAdded = false;
}
} else {
locks = locks.filter((lock) => lock.targetElement !== targetElement);
if (!locks.length) {
restoreOverflowSetting();
}
}
};
export { clearAllBodyScrollLocks, disableBodyScroll, enableBodyScroll };
//# sourceMappingURL=body-scroll-lock.mjs.map
//# sourceMappingURL=body-scroll-lock.mjs.map