76 lines
2.0 KiB
JavaScript
76 lines
2.0 KiB
JavaScript
import debounce from '@js/theme/utils/debounce';
|
|
|
|
/**
|
|
* Returns sticky element data
|
|
* @param element
|
|
* @returns {{getTop: ((function(): number)), getTopOffset: ((function(): number)), getFullTopOffset: (function(): number)}}
|
|
*/
|
|
export default (element, stickyWrapper, options = {}) => {
|
|
if (!element) {
|
|
throw new Error('Sticky element: element not found');
|
|
}
|
|
|
|
if (!stickyWrapper) {
|
|
throw new Error('Sticky element: stickyWrapper not found');
|
|
}
|
|
|
|
const {
|
|
extraOffsetTop = 0,
|
|
debounceTime = 5,
|
|
zIndex = 100,
|
|
} = options;
|
|
let isSticky = false;
|
|
const getWrapperRect = () => {
|
|
const wrapperRect = stickyWrapper.getBoundingClientRect();
|
|
|
|
return {
|
|
top: wrapperRect.top,
|
|
bottom: wrapperRect.bottom,
|
|
height: wrapperRect.height,
|
|
width: wrapperRect.width,
|
|
};
|
|
};
|
|
const getExtraOffsetTop = typeof extraOffsetTop === 'function' ? extraOffsetTop : () => extraOffsetTop;
|
|
const setElementSticky = () => {
|
|
const { height } = getWrapperRect();
|
|
stickyWrapper.style.height = `${height}px`;
|
|
element.style.top = `${getExtraOffsetTop()}px`;
|
|
element.style.left = 0;
|
|
element.style.right = 0;
|
|
element.style.bottom = 'auto';
|
|
element.style.position = 'fixed';
|
|
element.style.zIndex = zIndex;
|
|
element.classList.add('is-sticky');
|
|
isSticky = true;
|
|
};
|
|
const unsetElementSticky = () => {
|
|
element.style.top = null;
|
|
element.style.bottom = null;
|
|
element.style.position = null;
|
|
element.style.zIndex = null;
|
|
element.classList.remove('is-sticky');
|
|
stickyWrapper.style.height = null;
|
|
isSticky = false;
|
|
};
|
|
const getIsSticky = () => isSticky;
|
|
const handleSticky = () => {
|
|
const { top } = getWrapperRect();
|
|
|
|
if (top <= getExtraOffsetTop()) {
|
|
if (!isSticky) {
|
|
setElementSticky();
|
|
}
|
|
} else if (isSticky) {
|
|
unsetElementSticky();
|
|
}
|
|
};
|
|
|
|
window.addEventListener('scroll', debounce(handleSticky, debounceTime));
|
|
handleSticky();
|
|
|
|
return {
|
|
getExtraOffsetTop,
|
|
getIsSticky,
|
|
};
|
|
};
|