import { useState, useEffect } from 'react' import cx from 'classnames' import { ChevronUpIcon } from '@primer/octicons-react' import styles from './ScrollButton.module.scss' const { transition200, opacity0, opacity100, customFocus } = styles export type ScrollButtonPropsT = { className?: string ariaLabel?: string } export const ScrollButton = ({ className, ariaLabel }: ScrollButtonPropsT) => { const [show, setShow] = useState(false) const [isTallEnough, setIsTallEnough] = useState(false) useEffect(() => { // We cannot determine document.documentElement.scrollTop height because we set the height: 100vh and set overflow to auto to keep the header sticky // That means window.scrollTop height is always 0 // Using IntersectionObserver we can determine if the h1 header is in view or not. If not, we show the scroll to top button, if so, we hide it const h1Element = document.getElementsByTagName('h1')[0] if (!h1Element) { if (process.env.NODE_ENV !== 'production') { throw new Error('No h1 element found in the document.') } return } const observer = new IntersectionObserver( function (entries) { if (entries[0].isIntersecting === false) { setShow(true) } else { setShow(false) } }, { threshold: [0] }, ) observer.observe(h1Element) return () => { observer.disconnect() } }, []) // If the window isn't tall enough, the scroll button will hide some of the content // A11y issue 8822 useEffect(() => { function updateDocumentSize() { setIsTallEnough(document.documentElement.clientHeight > 400) } updateDocumentSize() window.addEventListener('resize', updateDocumentSize) return () => window.removeEventListener('resize', updateDocumentSize) }, []) const onClick = () => { document?.getElementById('github-logo')?.focus() document?.getElementById('main-content')?.scrollIntoView() } return (
) }