@@ -43,6 +43,55 @@ export function Doc({
4343
4444 const isTocVisible = shouldRenderToc && headings && headings . length > 1
4545
46+ const markdownContainerRef = React . useRef < HTMLDivElement > ( null )
47+ const [ activeHeadings , setActiveHeadings ] = React . useState < Array < string > > ( [ ] )
48+
49+ const headingElementRefs = React . useRef <
50+ Record < string , IntersectionObserverEntry >
51+ > ( { } )
52+
53+ React . useEffect ( ( ) => {
54+ const callback = ( headingsList : Array < IntersectionObserverEntry > ) => {
55+ headingElementRefs . current = headingsList . reduce (
56+ ( map , headingElement ) => {
57+ map [ headingElement . target . id ] = headingElement
58+ return map
59+ } ,
60+ headingElementRefs . current
61+ )
62+
63+ const visibleHeadings : Array < IntersectionObserverEntry > = [ ]
64+ Object . keys ( headingElementRefs . current ) . forEach ( ( key ) => {
65+ const headingElement = headingElementRefs . current [ key ]
66+ if ( headingElement . isIntersecting ) {
67+ visibleHeadings . push ( headingElement )
68+ }
69+ } )
70+
71+ if ( visibleHeadings . length >= 1 ) {
72+ setActiveHeadings ( visibleHeadings . map ( ( h ) => h . target . id ) )
73+ }
74+ }
75+
76+ const observer = new IntersectionObserver ( callback , {
77+ rootMargin : '0px' ,
78+ threshold : 0.2 ,
79+ } )
80+
81+ const headingElements = Array . from (
82+ markdownContainerRef . current ?. querySelectorAll (
83+ 'h2[id], h3[id], h4[id], h5[id], h6[id]'
84+ ) ?? [ ]
85+ )
86+ headingElements . forEach ( ( el ) => observer . observe ( el ) )
87+ console . log (
88+ 'observing' ,
89+ headingElements . map ( ( h ) => h . id )
90+ )
91+
92+ return ( ) => observer . disconnect ( )
93+ } , [ ] )
94+
4695 return (
4796 < div
4897 className = { twMerge (
@@ -61,9 +110,11 @@ export function Doc({
61110 < div className = "h-px bg-gray-500 opacity-20" />
62111 < div className = "h-4" />
63112 < div
113+ ref = { markdownContainerRef }
64114 className = { twMerge (
65115 'prose prose-gray prose-sm prose-p:leading-7 dark:prose-invert max-w-none' ,
66- isTocVisible && 'pr-4 lg:pr-6'
116+ isTocVisible && 'pr-4 lg:pr-6' ,
117+ 'styled-markdown-content'
67118 ) }
68119 >
69120 < Markdown htmlMarkup = { markup } />
@@ -83,7 +134,12 @@ export function Doc({
83134
84135 { isTocVisible && (
85136 < div className = "border-l border-gray-500/20 max-w-52 w-full hidden 2xl:block transition-all" >
86- < Toc headings = { headings } colorFrom = { colorFrom } colorTo = { colorTo } />
137+ < Toc
138+ headings = { headings }
139+ activeHeadings = { activeHeadings }
140+ colorFrom = { colorFrom }
141+ colorTo = { colorTo }
142+ />
87143 </ div >
88144 ) }
89145 </ div >
0 commit comments