({ className, ariaLabel }: ScrollButtonPropsT)
| 8 | } |
| 9 | |
| 10 | export const ScrollButton = ({ className, ariaLabel }: ScrollButtonPropsT) => { |
| 11 | const [show, setShow] = useState(false) |
| 12 | |
| 13 | useEffect(() => { |
| 14 | // We cannot determine document.documentElement.scrollTop height because we set the height: 100vh and set overflow to auto to keep the header sticky |
| 15 | // That means window.scrollTop height is always 0 |
| 16 | // Using IntersectionObserver we can detemine if the h1 header is in view or not. If not, we show the scroll to top button, if so, we hide it |
| 17 | const observer = new IntersectionObserver( |
| 18 | function (entries) { |
| 19 | if (entries[0].isIntersecting === false) { |
| 20 | setShow(true) |
| 21 | } else { |
| 22 | setShow(false) |
| 23 | } |
| 24 | }, |
| 25 | { threshold: [0] } |
| 26 | ) |
| 27 | observer.observe(document.getElementsByTagName('h1')[0]) |
| 28 | return () => { |
| 29 | observer.disconnect() |
| 30 | } |
| 31 | }, []) |
| 32 | |
| 33 | const onClick = () => { |
| 34 | document?.getElementById('github-logo')?.focus() |
| 35 | document?.getElementById('main-content')?.scrollIntoView() |
| 36 | } |
| 37 | |
| 38 | return ( |
| 39 | <div |
| 40 | role="tooltip" |
| 41 | className={cx(className, 'transition-200', show ? 'opacity-100' : 'opacity-0')} |
| 42 | > |
| 43 | <button |
| 44 | onClick={onClick} |
| 45 | className={cx( |
| 46 | 'tooltipped tooltipped-n tooltipped-no-delay color-bg-accent-emphasis color-fg-on-emphasis circle border-0' |
| 47 | )} |
| 48 | style={{ width: 40, height: 40 }} |
| 49 | aria-label={ariaLabel} |
| 50 | > |
| 51 | <ChevronUpIcon /> |
| 52 | </button> |
| 53 | </div> |
| 54 | ) |
| 55 | } |
nothing calls this directly
no outgoing calls
no test coverage detected