@@ -4,16 +4,21 @@ import { useEffect } from 'react'
44import { usePathname } from 'next/navigation'
55
66/**
7- * Module-level flag so the popstate signal survives layout remounts when the
8- * user navigates across sections (e.g., blog ↔ integrations ↔ models), where
9- * the outgoing layout — and its component instances — unmount before the
10- * incoming layout's effect runs.
7+ * Timestamp of the most recent popstate. Module-scoped so it survives layout
8+ * remounts when navigating across sections (e.g., blog ↔ integrations ↔ models),
9+ * where the outgoing layout's component instances unmount before the incoming
10+ * layout's effect runs.
11+ *
12+ * A timestamp window (rather than a sticky boolean) self-expires the signal —
13+ * a hash-only back/forward fires popstate but doesn't change `usePathname`, so
14+ * a boolean would never be consumed and would poison the next real navigation.
1115 */
12- let isPopNavigation = false
16+ let lastPopstateAt = 0
17+ const POPSTATE_WINDOW_MS = 200
1318
1419if ( typeof window !== 'undefined' ) {
1520 window . addEventListener ( 'popstate' , ( ) => {
16- isPopNavigation = true
21+ lastPopstateAt = performance . now ( )
1722 } )
1823}
1924
@@ -23,18 +28,15 @@ if (typeof window !== 'undefined') {
2328 * Next.js's default scroll handling only brings the new Page element into view,
2429 * which often resolves to "no scroll" inside shared layouts (see vercel/next.js#64435).
2530 *
26- * Popstate-driven navigations are skipped so browser back/forward scroll
27- * restoration is preserved, and hash- anchor navigations are skipped so the
28- * browser's native anchor scroll wins .
31+ * Skipped when the pathname change closely follows a popstate (preserving browser
32+ * back/forward scroll restoration) or when a hash anchor is targeted (letting the
33+ * browser's native anchor scroll win) .
2934 */
3035export function ScrollToTop ( ) {
3136 const pathname = usePathname ( )
3237
3338 useEffect ( ( ) => {
34- if ( isPopNavigation ) {
35- isPopNavigation = false
36- return
37- }
39+ if ( performance . now ( ) - lastPopstateAt < POPSTATE_WINDOW_MS ) return
3840 if ( window . location . hash ) return
3941 window . scrollTo ( 0 , 0 )
4042 } , [ pathname ] )
0 commit comments