[site/hooks][m]: useHeadingsObserver simplified

This commit is contained in:
olayway 2022-06-01 16:31:17 +02:00
parent 683d1b7503
commit bfb8c52953
2 changed files with 53 additions and 0 deletions

View File

@ -7,6 +7,10 @@ export const Heading = ({ level, observer }) => (props) => {
* set by observer's `rootMargin` */
if (observer) {
observer.observe(document.getElementById(props.id));
return () => {
observer.unobserve(document.getElementById(props.id));
}
}
});

View File

@ -0,0 +1,49 @@
import { useState, useEffect } from 'react';
/* Creates an Intersection Observer to keep track of headings intersecting
* a section of the viewport defined by the rootMargin */
const getIntersectionObserver = (callback) => {
if (typeof window !== 'undefined') {
return new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
callback(entry);
});
},
{
root: null,
rootMargin: "-65px 0% -85% 0%" // 65px is a navbar height
}
);
}
};
const useHeadingsObserver = () => {
const [activeHeading, setActiveHeading] = useState("");
const [observer, setObserver] = useState(getIntersectionObserver((entry) => {
if (entry.isIntersecting) {
setActiveHeading(entry.target.id);
}
}));
/* On initial render activeHeading will be `null`, since the observer
* has not been instantiated yet. However, we still want to highlight
* the current heading in the ToC based on the current url. */
useEffect(() => {
if (!activeHeading) {
return
}
const tocLink = document.querySelector(`.toc-link[href="#${activeHeading}"]`)
tocLink.classList.add("active");
return () => {
tocLink.classList.remove("active")
}
}, [activeHeading])
return observer;
}
export default useHeadingsObserver;