// eslint-disable-next-line @typescript-eslint/no-var-requires import getElementTop from '../../utils/get-element-top'; import { TOCStyle, TOCInnerStyle, H2AnchorStyle, H3AnchorStyle, HeaderStyle } from './styles'; import { forwardRef, useEffect } from 'react'; import { useRouter } from 'next/router'; import { MQDesktop } from '../media'; import { Button } from '@cloudscape-design/components'; const stickyHeaderHeight = 124; function scroll(hash) { const header = document.querySelector(`[id="${hash}"]`); const top = getElementTop(header, stickyHeaderHeight); if (top !== window.scrollY) { window.scrollTo({ top }); } } function TableOfContents({ children, title, buttonsRef }, ref) { const router = useRouter(); const MQDesktopJS = MQDesktop.substring(6); const onDesktop = typeof window === 'undefined' ? false : window.matchMedia(MQDesktopJS).matches; if (children.length === 0) { return <>; } window.onload = (_) => { if (window.location.href.includes('#')) { const hash = window.location.href.split('#')[1]; scroll(hash); } }; let headers = []; let headerQueries = []; let activeLink = 0; let previousLink = -1; useEffect(() => { const idSet = new Set(); const headings = document.querySelectorAll('a > h2, a > h3'); const headings2 = document.getElementById('toc').querySelectorAll('a'); for (let i = 0; i < headings.length; ++i) { const id = headings[i].id; let counter = 0; let uniqueId = id; while (idSet.has(uniqueId)) { counter++; uniqueId = id + '-' + counter.toString(); } idSet.add(uniqueId); headings[i].id = uniqueId; if (counter !== 0) { (headings[i].parentElement as HTMLAnchorElement).href = `#${uniqueId}`; headings2[i].href = `#${uniqueId}`; } (headings[i].parentElement as HTMLAnchorElement).onclick = () => { setTimeout(scroll.bind(undefined, uniqueId), 50); return false; }; headings2[i].onclick = () => { setTimeout(scroll.bind(undefined, uniqueId), 50); return false; }; } headers = Array.from(headings).map((heading) => heading.id); headerQueries = headers.map((header) => { return document.querySelector(`[id="${header}"]`); }); const scrollHandler = () => { if (headers) { let i = headerQueries.findIndex( (e) => getElementTop(e, stickyHeaderHeight) - 3 > window.scrollY ); if (i === -1) { i = headers.length; } activeLink = i - 1; if (activeLink !== previousLink) { previousLink = activeLink; headers.forEach((header) => { document .querySelectorAll(`a[href="#${header}"]`) .forEach((aTag) => { aTag.classList.remove('active'); }); }); if (activeLink >= 0) { const activeElement = headers[activeLink]; document .querySelectorAll(`a[href="#${activeElement}"]`) .forEach((aTag) => { aTag.classList.add('active'); }); if (activeElement) { // Update the url hash without updating the history. history.replaceState(history.state, null, '#' + activeElement); } } else { // Next router.replace updates "history.state" so keep using it here so // "history.replaceState" works correctly with back and forward buttons. router.replace( window.location.href.split('#')[0], window.location.href.split('#')[0], { shallow: true, scroll: false } ); } } } }; document.addEventListener('scroll', scrollHandler); return function cleanup() { document.removeEventListener('scroll', scrollHandler); }; }, []); const closeToc = () => { if (typeof document !== 'undefined' && !onDesktop) { const toc = ref.current; const buttons = buttonsRef.current; if (toc) { toc.classList.add('slideOut'), toc.classList.remove('slideIn'); } if (buttons) { buttons.classList.add('slideIn'), buttons.classList.remove('slideOut'); } } }; return ( {!onDesktop && (

On this Page

)}

{title}

{children.map(([name, id, level], index) => { const slugged = `#${id}`; const anchor = (
{name}
); if (level === 'h2') return {anchor}; else return {anchor}; })}
); } export default forwardRef(TableOfContents);