You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
2.1 KiB
82 lines
2.1 KiB
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*/
|
|
|
|
import {useState, useRef, useEffect} from 'react';
|
|
|
|
const TOP_OFFSET = 85;
|
|
|
|
export function getHeaderAnchors(): HTMLAnchorElement[] {
|
|
return Array.prototype.filter.call(
|
|
document.getElementsByClassName('mdx-header-anchor'),
|
|
function (testElement) {
|
|
return (
|
|
testElement.parentNode.nodeName === 'H1' ||
|
|
testElement.parentNode.nodeName === 'H2' ||
|
|
testElement.parentNode.nodeName === 'H3'
|
|
);
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Sets up Table of Contents highlighting.
|
|
*/
|
|
export function useTocHighlight() {
|
|
const [currentIndex, setCurrentIndex] = useState<number>(0);
|
|
const timeoutRef = useRef<number | null>(null);
|
|
|
|
useEffect(() => {
|
|
function updateActiveLink() {
|
|
const pageHeight = document.body.scrollHeight;
|
|
const scrollPosition = window.scrollY + window.innerHeight;
|
|
const headersAnchors = getHeaderAnchors();
|
|
|
|
if (scrollPosition >= 0 && pageHeight - scrollPosition <= 0) {
|
|
// Scrolled to bottom of page.
|
|
setCurrentIndex(headersAnchors.length - 1);
|
|
return;
|
|
}
|
|
|
|
let index = -1;
|
|
while (index < headersAnchors.length - 1) {
|
|
const headerAnchor = headersAnchors[index + 1];
|
|
const {top} = headerAnchor.getBoundingClientRect();
|
|
|
|
if (top >= TOP_OFFSET) {
|
|
break;
|
|
}
|
|
index += 1;
|
|
}
|
|
|
|
setCurrentIndex(Math.max(index, 0));
|
|
}
|
|
|
|
function throttledUpdateActiveLink() {
|
|
if (timeoutRef.current === null) {
|
|
timeoutRef.current = window.setTimeout(() => {
|
|
timeoutRef.current = null;
|
|
updateActiveLink();
|
|
}, 100);
|
|
}
|
|
}
|
|
|
|
document.addEventListener('scroll', throttledUpdateActiveLink);
|
|
document.addEventListener('resize', throttledUpdateActiveLink);
|
|
|
|
updateActiveLink();
|
|
|
|
return () => {
|
|
if (timeoutRef.current != null) {
|
|
clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = null;
|
|
}
|
|
document.removeEventListener('scroll', throttledUpdateActiveLink);
|
|
document.removeEventListener('resize', throttledUpdateActiveLink);
|
|
};
|
|
}, []);
|
|
|
|
return {
|
|
currentIndex,
|
|
};
|
|
}
|
|
|