@@ -51,7 +51,6 @@ export interface TableOfContentsProviderProps {
5151 children : ReactNode ;
5252 hashNavigation ?: boolean ;
5353}
54-
5554export const TableOfContentsProvider : FC < TableOfContentsProviderProps > = ( {
5655 items,
5756 children,
@@ -62,6 +61,7 @@ export const TableOfContentsProvider: FC<TableOfContentsProviderProps> = ({
6261 const [ selected , setSelected ] = useState < string | undefined > ( items [ 0 ] ?. value ) ;
6362 const [ elements , setElements ] = useState < ( Element | null ) [ ] > ( [ ] ) ;
6463 const [ shouldInstantlyJump , setShouldInstantlyJump ] = useState ( hash !== '' ) ;
64+ const initHashStateRef = useRef ( false ) ;
6565
6666 const values : string [ ] = useMemo (
6767 ( ) => items . flatMap ( ( item ) => getValues ( [ ] , item ) ) ,
@@ -73,6 +73,11 @@ export const TableOfContentsProvider: FC<TableOfContentsProviderProps> = ({
7373 setElements ( values . map ( ( value ) => document . getElementById ( value ) ) ) ;
7474 } , [ values ] ) ;
7575
76+ useEffect ( ( ) => {
77+ if ( hash . length ) return ;
78+ initHashStateRef . current = true ;
79+ } , [ hash ] ) ;
80+
7681 const isActive = useCallback (
7782 ( item : TableOfContentsItemType ) => {
7883 if ( item . value === selected ) return true ;
@@ -154,12 +159,30 @@ export const TableOfContentsProvider: FC<TableOfContentsProviderProps> = ({
154159 newSelectedIndex = index ;
155160 }
156161 }
157- if ( newSelectedIndex !== - 1 && values . at ( newSelectedIndex ) !== undefined ) {
158- setSelected ( values [ newSelectedIndex ] ) ;
159- if ( hashNavigation ) {
160- navigate ( `#${ values [ newSelectedIndex ] } ` , { replace : true } ) ;
161- }
162+
163+ if ( newSelectedIndex === - 1 || values . at ( newSelectedIndex ) === undefined )
164+ return ;
165+
166+ const targetValue = hash . replace ( '#' , '' ) ;
167+ if (
168+ ! initHashStateRef . current &&
169+ targetValue . length &&
170+ values . includes ( targetValue )
171+ ) {
172+ handleSetSelected ( targetValue , {
173+ behavior : 'instant' ,
174+ shouldInstantlyJumpOnMount : true ,
175+ } ) ;
176+ initHashStateRef . current = true ;
177+ return ;
178+ }
179+
180+ setSelected ( values [ newSelectedIndex ] ) ;
181+ if ( hashNavigation ) {
182+ navigate ( `#${ values [ newSelectedIndex ] } ` , { replace : true } ) ;
162183 }
184+ // this effect handles scroll navigation and should not be triggered on hash change
185+ // eslint-disable-next-line react-hooks/exhaustive-deps
163186 } , [ hashNavigation , navigate , values , visible ] ) ;
164187 /* v8 ignore end */
165188
0 commit comments