|
10 | 10 | */ |
11 | 11 |
|
12 | 12 | import cx from 'classnames'; |
| 13 | +import {startTransition, useOptimistic} from 'react'; |
13 | 14 | import {useTocHighlight} from './useTocHighlight'; |
14 | 15 | import {IsInTocContext} from '../MDX/TocContext'; |
15 | 16 | import type {Toc} from '../MDX/TocContext'; |
16 | 17 |
|
| 18 | +function waitForScrollEnd(): Promise<void> { |
| 19 | + return new Promise((resolve) => { |
| 20 | + let settled = false; |
| 21 | + const finish = () => { |
| 22 | + if (settled) return; |
| 23 | + settled = true; |
| 24 | + window.removeEventListener('scrollend', finish); |
| 25 | + resolve(); |
| 26 | + }; |
| 27 | + window.addEventListener('scrollend', finish, {once: true}); |
| 28 | + setTimeout(finish, 1000); |
| 29 | + }); |
| 30 | +} |
| 31 | + |
17 | 32 | export function Toc({headings}: {headings: Toc}) { |
18 | 33 | const {currentIndex} = useTocHighlight(); |
| 34 | + const [optimisticIndex, setOptimisticIndex] = useOptimistic(currentIndex); |
19 | 35 | // TODO: We currently have a mismatch between the headings in the document |
20 | 36 | // and the headings we find in MarkdownPage (i.e. we don't find Recap or Challenges). |
21 | 37 | // Select the max TOC item we have here for now, but remove this after the fix. |
22 | | - const selectedIndex = Math.min(currentIndex, headings.length - 1); |
| 38 | + const selectedIndex = Math.min(optimisticIndex, headings.length - 1); |
23 | 39 | return ( |
24 | 40 | <nav role="navigation" className="pt-20 sticky top-0 end-0"> |
25 | 41 | {headings.length > 0 && ( |
@@ -59,7 +75,13 @@ export function Toc({headings}: {headings: Toc}) { |
59 | 75 | : 'text-secondary dark:text-secondary-dark', |
60 | 76 | 'block hover:text-link dark:hover:text-link-dark leading-normal py-2' |
61 | 77 | )} |
62 | | - href={h.url}> |
| 78 | + href={h.url} |
| 79 | + onClick={() => { |
| 80 | + startTransition(async () => { |
| 81 | + setOptimisticIndex(i); |
| 82 | + await waitForScrollEnd(); |
| 83 | + }); |
| 84 | + }}> |
63 | 85 | {h.text} |
64 | 86 | </a> |
65 | 87 | </li> |
|
0 commit comments