docs: fix scrolling issue with sidebar (#2791)
This was an annoying change. Next.js feels like it should be preserving the scroll position but it doesn't, it re-renders. Drive-by change to make the transition at the bottom not animate everything (this might have been the CPU usage you were seeing @si14 ### Change Type - [x] `documentation` — Changes to the documentation only[^2] ### Release Notes - Docs: fix up scrolling.
This commit is contained in:
parent
056481899c
commit
c47360d236
2 changed files with 30 additions and 5 deletions
|
@ -12,7 +12,7 @@ import {
|
|||
import * as Accordion from '@radix-ui/react-accordion'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { createContext, useContext, useEffect } from 'react'
|
||||
import { UIEvent, createContext, useContext, useEffect, useRef } from 'react'
|
||||
import { SectionLinks } from './Header'
|
||||
import { Chevron } from './Icons'
|
||||
import { Search } from './Search'
|
||||
|
@ -28,21 +28,46 @@ const linkContext = createContext<{
|
|||
sectionId: string | null
|
||||
} | null>(null)
|
||||
|
||||
// N.B. UGH, the sidebar's scroll position keeps getting lost when navigation occurs
|
||||
// and we keep track of the last known position here outside of the component because
|
||||
// it keeps re-rendering.
|
||||
let scrollPosition = 0
|
||||
|
||||
export function Sidebar({ headings, links, sectionId, categoryId, articleId }: SidebarProps) {
|
||||
const activeId = articleId ?? categoryId ?? sectionId
|
||||
const sidebarRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const pathName = usePathname()
|
||||
|
||||
useEffect(() => {
|
||||
document.body.classList.remove('sidebar-open')
|
||||
|
||||
document.querySelector('.sidebar__nav [data-active=true]')?.scrollIntoView({ block: 'center' })
|
||||
const sidebarEl = sidebarRef.current
|
||||
if (!sidebarEl) return
|
||||
|
||||
sidebarEl.scrollTo(0, scrollPosition)
|
||||
|
||||
const activeLink = document.querySelector('.sidebar__nav [data-active=true]') as HTMLElement
|
||||
if (
|
||||
activeLink &&
|
||||
activeLink.offsetTop < sidebarEl.scrollTop &&
|
||||
activeLink.offsetTop > sidebarEl.scrollTop + sidebarEl.clientHeight
|
||||
) {
|
||||
// The above will *mostly* work to keep the position but we have some accordions that will collapse
|
||||
// (like in the Reference docs) and we need to scroll to the active item.
|
||||
activeLink.scrollIntoView({ block: 'center' })
|
||||
}
|
||||
}, [pathName])
|
||||
|
||||
const handleScroll = (e: UIEvent) => {
|
||||
e.stopPropagation()
|
||||
scrollPosition = sidebarRef.current?.scrollTop ?? 0
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<linkContext.Provider value={{ activeId, articleId, categoryId, sectionId }}>
|
||||
<div className="sidebar scroll-light" onScroll={(e) => e.stopPropagation()}>
|
||||
<div ref={sidebarRef} className="sidebar scroll-light" onScroll={handleScroll}>
|
||||
<Search />
|
||||
<div className="sidebar__section__links">
|
||||
<SectionLinks sectionId={sectionId} />
|
||||
|
|
|
@ -675,7 +675,7 @@ body {
|
|||
}
|
||||
|
||||
.footer__fancybox__item {
|
||||
transition: all 3s;
|
||||
transition: opacity 3s;
|
||||
opacity: 0;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
|
@ -714,7 +714,7 @@ body {
|
|||
}
|
||||
|
||||
.footer__fancybox__item:hover {
|
||||
transition: all 0s;
|
||||
transition: opacity 0s;
|
||||
opacity: 0.32;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue