@ui5/webcomponents-react
Version:
React Wrapper for UI5 Web Components and additional components
85 lines (83 loc) • 3.44 kB
JavaScript
import { useCallback, useEffect, useRef, useState } from 'react';
export const useObserveHeights = (pageRef, topHeaderRef, headerContentRef, anchorBarRef, [headerCollapsed, setHeaderCollapsed], {
noHeader,
fixedHeader = false,
scrollTimeout = {
current: 0
},
preserveHeaderStateOnScroll
}) => {
const [topHeaderHeight, setTopHeaderHeight] = useState(0);
const [headerContentHeight, setHeaderContentHeight] = useState(0);
const [isIntersecting, setIsIntersecting] = useState(true);
const prevScrollTop = useRef(0);
const onScroll = useCallback(e => {
const scrollDown = prevScrollTop.current <= e.target.scrollTop;
prevScrollTop.current = e.target.scrollTop;
if (scrollTimeout.current >= performance.now()) {
return;
}
if (scrollDown && e.target.scrollTop >= headerContentHeight && !headerCollapsed) {
setIsIntersecting(false);
setHeaderCollapsed(true);
} else if (!scrollDown && e.target.scrollTop <= topHeaderHeight + Math.max(0, headerContentHeight - topHeaderHeight) && headerCollapsed) {
setIsIntersecting(true);
setHeaderCollapsed(false);
}
}, [headerContentHeight, topHeaderHeight, headerCollapsed]);
useEffect(() => {
if (headerContentRef.current && headerCollapsed !== undefined) {
setHeaderContentHeight(headerContentRef.current.getBoundingClientRect().height);
}
}, [headerCollapsed]);
useEffect(() => {
const page = pageRef.current;
if (!fixedHeader && !preserveHeaderStateOnScroll) {
page.addEventListener('scroll', onScroll);
}
return () => {
page.removeEventListener('scroll', onScroll);
};
}, [onScroll, fixedHeader, preserveHeaderStateOnScroll]);
// top header
useEffect(() => {
const headerContentResizeObserver = new ResizeObserver(([header]) => {
// Firefox implements `borderBoxSize` as a single content rect, rather than an array
const borderBoxSize = Array.isArray(header.borderBoxSize) ? header.borderBoxSize[0] : header.borderBoxSize;
// Safari doesn't implement `borderBoxSize`
setTopHeaderHeight(borderBoxSize?.blockSize ?? header.target.getBoundingClientRect().height);
});
if (topHeaderRef?.current) {
headerContentResizeObserver.observe(topHeaderRef.current);
}
return () => {
headerContentResizeObserver.disconnect();
};
}, []);
// header content
useEffect(() => {
const headerContentResizeObserver = new ResizeObserver(([headerContent]) => {
if (isIntersecting) {
// Firefox implements `borderBoxSize` as a single content rect, rather than an array
const borderBoxSize = Array.isArray(headerContent.borderBoxSize) ? headerContent.borderBoxSize[0] : headerContent.borderBoxSize;
// Safari doesn't implement `borderBoxSize`
setHeaderContentHeight(borderBoxSize?.blockSize ?? headerContent.target.getBoundingClientRect().height);
}
});
if (headerContentRef?.current) {
headerContentResizeObserver.observe(headerContentRef.current);
}
return () => {
headerContentResizeObserver.disconnect();
};
}, [isIntersecting]);
const anchorBarHeight = anchorBarRef?.current?.offsetHeight ?? 33;
const totalHeaderHeight = (noHeader ? 0 : topHeaderHeight + headerContentHeight) + anchorBarHeight;
return {
topHeaderHeight,
headerContentHeight,
anchorBarHeight,
totalHeaderHeight,
headerCollapsed
};
};