UNPKG

@redocly/theme

Version:

Shared UI components lib

62 lines (51 loc) 1.77 kB
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; }