UNPKG

@kubit-ui-web/react-components

Version:

Kubit React Components is a customizable, accessible library of React web components, designed to enhance your application's user experience

104 lines 4.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useScrollBlock = void 0; const react_1 = require("react"); const useScrollBlock_utils_1 = require("./utils/useScrollBlock.utils"); const useScrollBlock = () => { const blockedScroll = (0, react_1.useRef)(false); const elementsToOmitRef = (0, react_1.useRef)([]); // Disable scroll in all the elements except the ones that are passed in the elementsToOmit array when blocking scroll const preventScrollOnUnomittedElements = (0, react_1.useCallback)((e) => { const target = e.target; if (target instanceof Node && !elementsToOmitRef.current.some(element => element?.contains(target))) { e.preventDefault(); } }, []); // Disable scroll in the omitted elements if is not a scrollable element const preventScrollOnOmittedElements = (0, react_1.useCallback)((e) => { const target = e.target; if (!(target instanceof Element) || (0, useScrollBlock_utils_1.getFirstScrollableElement)({ element: target, parentsToStop: elementsToOmitRef.current })) { return; } e.preventDefault(); }, []); // In order to avoid scroll the document when there is no scroll for an omitted element: // Allow to scroll a pixel if the scroll is at the top or bottom // More info: https://medium.com/turo-engineering/ios-mobile-scroll-in-web-react-1d92d910604b (Level 4) const preventScrollBackgroundOnOmittedElements = (0, react_1.useCallback)((e) => { const target = e.target; if (!(target instanceof Element)) { return; } const firstScrollableElement = (0, useScrollBlock_utils_1.getFirstScrollableElement)({ element: target, parentsToStop: elementsToOmitRef.current, }); if (!firstScrollableElement) { return; } const { scrollTop, scrollHeight } = firstScrollableElement; let offsetHeight = null; if (firstScrollableElement instanceof HTMLElement) { offsetHeight = firstScrollableElement.offsetHeight; } // If at top, bump down 1px if (scrollTop <= 0) { firstScrollableElement.scrollTo(0, 1); return; } // If at bottom, bump up 1px if (offsetHeight !== null && scrollTop + offsetHeight >= scrollHeight) { firstScrollableElement.scrollTo(0, scrollHeight - offsetHeight - 1); } }, []); const blockScroll = ({ elementsToOmit = [] } = {}) => { if (typeof document === 'undefined') { return; } const html = document.documentElement; const { body } = document; if (!body || !body.style || blockedScroll.current) { return; } elementsToOmitRef.current = elementsToOmit; elementsToOmitRef.current.forEach(element => { element?.addEventListener('touchmove', preventScrollOnOmittedElements, { passive: false }); element?.addEventListener('touchstart', preventScrollBackgroundOnOmittedElements); }); document.addEventListener('touchmove', preventScrollOnUnomittedElements, { passive: false }); const scrollBarWidth = window.innerWidth - html.clientWidth; const bodyPaddingRight = parseInt(window.getComputedStyle(body).getPropertyValue('padding-right'), 10) || 0; html.style.position = 'relative'; /* [1] */ body.style.position = 'relative'; /* [1] */ html.style.overflow = 'clip'; /* [2] */ body.style.overflow = 'clip'; /* [2] */ body.style.paddingRight = `${bodyPaddingRight + scrollBarWidth}px`; blockedScroll.current = true; }; const allowScroll = () => { if (typeof document === 'undefined') { return; } const html = document.documentElement; const { body } = document; if (!body || !body.style || !blockedScroll.current) { return; } elementsToOmitRef.current.forEach(element => { element?.removeEventListener('touchmove', preventScrollOnOmittedElements); element?.removeEventListener('touchstart', preventScrollBackgroundOnOmittedElements); }); document.removeEventListener('touchmove', preventScrollOnUnomittedElements); html.style.position = ''; html.style.overflow = ''; body.style.position = ''; body.style.overflow = ''; body.style.paddingRight = ''; blockedScroll.current = false; }; return { blockScroll, allowScroll }; }; exports.useScrollBlock = useScrollBlock; //# sourceMappingURL=useScrollBlock.js.map