@redocly/theme
Version:
Shared UI components lib
62 lines (51 loc) • 1.77 kB
text/typescript
import { useEffect, useState, useMemo } from 'react';
import throttle from 'lodash.throttle';
import type { Location } from 'react-router-dom';
import { useNavbarHeight } from './use-navbar-height';
export type UseActiveSectionIdReturnType = string;
export function useActiveSectionId(
location: Location,
hasOverviewPage = false,
withNavbar = true,
sectionOffset = 150, // use 150px to account next section visibility;
): UseActiveSectionIdReturnType {
const [itemId, setItemId] = useState<string>('');
const navbarHeight = useNavbarHeight(location);
const heightOffset = (withNavbar ? navbarHeight : 0) + sectionOffset;
const scrollListener = useMemo(
() =>
throttle(() => {
const sections = document.querySelectorAll('[data-section-id]');
if (sections.length < 2) {
setItemId('');
return;
}
if (window.scrollY <= 0) {
setItemId(sections[0].getAttribute('data-section-id') || '');
return;
}
for (let i = 0; i < sections.length; i++) {
const section = sections[i];
const rect = section.getBoundingClientRect();
if (rect.y < heightOffset && rect.bottom > heightOffset) {
setItemId(section.getAttribute('data-section-id') || '');
return;
}
}
if (hasOverviewPage) {
setItemId('');
}
}, 150),
[heightOffset, hasOverviewPage],
);
useEffect(() => {
window.addEventListener('scroll', scrollListener, { capture: false });
setTimeout(() => {
scrollListener();
}, 10);
return () => {
window.removeEventListener('scroll', scrollListener);
};
}, [location, heightOffset, scrollListener]);
return itemId;
}