mediawiki-skins-Citizen/resources/skins.citizen.scripts/scrollObserver.js
alistair3149 3b8022c3c1
refactor(core): ♻️ set up scroll direction observer in setupObservers
This is needed for centralizing the observers.
2024-11-07 19:12:48 -05:00

74 lines
2 KiB
JavaScript

/**
* Initialize a direction observer based on scroll behavior.
*
* @param {Function} onScrollDown - Function to be called when scrolling down.
* @param {Function} onScrollUp - Function to be called when scrolling up.
* @param {number} threshold - The threshold for significant scroll position change.
* @return {Object}
*/
function initDirectionObserver( onScrollDown, onScrollUp, threshold = 0 ) {
let lastScrollTop = 0;
let lastScrollDirection = '';
let isScrolling = false;
const handleScroll = () => {
const currentScrollTop = window.scrollY;
if ( Math.abs( currentScrollTop - lastScrollTop ) < threshold ) {
isScrolling = false;
return;
}
if ( currentScrollTop > lastScrollTop && lastScrollDirection !== 'down' ) {
lastScrollDirection = 'down';
onScrollDown();
} else if ( currentScrollTop < lastScrollTop && lastScrollDirection !== 'up' ) {
lastScrollDirection = 'up';
onScrollUp();
}
lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop;
isScrolling = false;
};
const onScroll = () => {
if ( !isScrolling ) {
window.requestAnimationFrame( handleScroll );
isScrolling = true;
}
};
return {
resume: () => {
window.addEventListener( 'scroll', onScroll );
},
pause: () => {
window.removeEventListener( 'scroll', onScroll );
}
};
}
/**
* Create an observer for showing/hiding feature and for firing scroll event hooks.
*
* @param {Function} show functionality for when feature is visible
* @param {Function} hide functionality for when feature is hidden
* @return {IntersectionObserver}
*/
function initScrollObserver( show, hide ) {
/* eslint-disable-next-line compat/compat */
return new IntersectionObserver( ( entries ) => {
if ( !entries[ 0 ].isIntersecting && entries[ 0 ].boundingClientRect.top < 0 ) {
// Viewport has crossed the bottom edge of the target element.
show();
} else {
// Viewport is above the bottom edge of the target element.
hide();
}
} );
}
module.exports = {
initDirectionObserver,
initScrollObserver
};