docs: fixed sidebar in API reference (#5871)
This commit is contained in:
@@ -22,9 +22,10 @@ export const SidebarItem = ({
|
||||
}: SidebarItemProps) => {
|
||||
const [showLoading, setShowLoading] = useState(false)
|
||||
const { isItemActive, setMobileSidebarOpen: setSidebarOpen } = useSidebar()
|
||||
const active = useMemo(() => {
|
||||
return isItemActive(item, nested)
|
||||
}, [isItemActive, item, nested])
|
||||
const active = useMemo(
|
||||
() => isItemActive(item, nested),
|
||||
[isItemActive, item, nested]
|
||||
)
|
||||
const collapsed = !expandItems && !isItemActive(item, true)
|
||||
const ref = useRef<HTMLLIElement>(null)
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ import React, {
|
||||
useMemo,
|
||||
useRef,
|
||||
type ReactNode,
|
||||
useState,
|
||||
} from "react"
|
||||
import { getScrolledTop as getScrolledTopUtil } from "../../utils"
|
||||
|
||||
type EventFunc = (...args: never[]) => unknown
|
||||
|
||||
@@ -54,7 +56,9 @@ type ScrollController = {
|
||||
/** Disable scroll events in `useScrollPosition`. */
|
||||
disableScrollEvents: () => void
|
||||
/** Retrieves the scrollable element. By default, it's window. */
|
||||
getScrollableElement: () => Element | Window
|
||||
scrollableElement: Element | Window | undefined
|
||||
/** Retrieves the scroll top if the scrollable element */
|
||||
getScrolledTop: () => number
|
||||
}
|
||||
|
||||
function useScrollControllerContextValue(
|
||||
@@ -62,9 +66,19 @@ function useScrollControllerContextValue(
|
||||
): ScrollController {
|
||||
const scrollEventsEnabledRef = useRef(true)
|
||||
|
||||
const getScrollableElement = useCallback(() => {
|
||||
return (document.querySelector(scrollableSelector) as Element) || window
|
||||
}, [scrollableSelector])
|
||||
const [scrollableElement, setScrollableElement] = useState<
|
||||
Element | Window | undefined
|
||||
>()
|
||||
|
||||
useEffect(() => {
|
||||
setScrollableElement(
|
||||
(document.querySelector(scrollableSelector) as Element) || window
|
||||
)
|
||||
}, [])
|
||||
|
||||
const getScrolledTop = () => {
|
||||
return scrollableElement ? getScrolledTopUtil(scrollableElement) : 0
|
||||
}
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
@@ -75,9 +89,10 @@ function useScrollControllerContextValue(
|
||||
disableScrollEvents: () => {
|
||||
scrollEventsEnabledRef.current = false
|
||||
},
|
||||
getScrollableElement,
|
||||
scrollableElement,
|
||||
getScrolledTop,
|
||||
}),
|
||||
[getScrollableElement]
|
||||
[scrollableElement]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -176,7 +191,7 @@ type UseScrollPositionSaver = {
|
||||
}
|
||||
|
||||
function useScrollPositionSaver(): UseScrollPositionSaver {
|
||||
const { getScrollableElement } = useScrollController()
|
||||
const { scrollableElement } = useScrollController()
|
||||
const lastElementRef = useRef<{ elem: HTMLElement | null; top: number }>({
|
||||
elem: null,
|
||||
top: 0,
|
||||
@@ -199,7 +214,7 @@ function useScrollPositionSaver(): UseScrollPositionSaver {
|
||||
const newTop = elem.getBoundingClientRect().top
|
||||
const heightDiff = newTop - top
|
||||
if (heightDiff) {
|
||||
getScrollableElement().scrollBy({ left: 0, top: heightDiff })
|
||||
scrollableElement?.scrollBy({ left: 0, top: heightDiff })
|
||||
}
|
||||
lastElementRef.current = { elem: null, top: 0 }
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import React, {
|
||||
useState,
|
||||
} from "react"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { getScrolledTop } from "../../utils"
|
||||
|
||||
export enum SidebarItemSections {
|
||||
TOP = "top",
|
||||
@@ -129,6 +130,7 @@ export type SidebarProviderProps = {
|
||||
initialItems?: SidebarSectionItemsType
|
||||
shouldHandleHashChange?: boolean
|
||||
shouldHandlePathChange?: boolean
|
||||
scrollableElement?: Element | Window
|
||||
}
|
||||
|
||||
export const SidebarProvider = ({
|
||||
@@ -138,6 +140,7 @@ export const SidebarProvider = ({
|
||||
initialItems,
|
||||
shouldHandleHashChange = false,
|
||||
shouldHandlePathChange = false,
|
||||
scrollableElement,
|
||||
}: SidebarProviderProps) => {
|
||||
const [items, dispatch] = useReducer(reducer, {
|
||||
top: initialItems?.top || [],
|
||||
@@ -148,6 +151,9 @@ export const SidebarProvider = ({
|
||||
const [mobileSidebarOpen, setMobileSidebarOpen] = useState<boolean>(false)
|
||||
const [desktopSidebarOpen, setDesktopSidebarOpen] = useState(true)
|
||||
const pathname = usePathname()
|
||||
const getResolvedScrollableElement = useCallback(() => {
|
||||
return scrollableElement || window
|
||||
}, [scrollableElement])
|
||||
|
||||
const findItemInSection = useCallback(
|
||||
(
|
||||
@@ -249,15 +255,21 @@ export const SidebarProvider = ({
|
||||
}
|
||||
}, [activePath])
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldHandleHashChange) {
|
||||
init()
|
||||
}
|
||||
}, [shouldHandleHashChange])
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldHandleHashChange) {
|
||||
return
|
||||
}
|
||||
|
||||
init()
|
||||
const resolvedScrollableElement = getResolvedScrollableElement()
|
||||
|
||||
const handleScroll = () => {
|
||||
if (window.scrollY === 0) {
|
||||
if (getScrolledTop(resolvedScrollableElement) === 0) {
|
||||
setActivePath("")
|
||||
// can't use next router as it doesn't support
|
||||
// changing url without scrolling
|
||||
@@ -265,14 +277,17 @@ export const SidebarProvider = ({
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("scroll", handleScroll)
|
||||
window.addEventListener("hashchange", handleHashChange)
|
||||
resolvedScrollableElement.addEventListener("scroll", handleScroll)
|
||||
resolvedScrollableElement.addEventListener("hashchange", handleHashChange)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("scroll", handleScroll)
|
||||
window.removeEventListener("hashchange", handleHashChange)
|
||||
resolvedScrollableElement.removeEventListener("scroll", handleScroll)
|
||||
resolvedScrollableElement.removeEventListener(
|
||||
"hashchange",
|
||||
handleHashChange
|
||||
)
|
||||
}
|
||||
}, [handleHashChange, shouldHandleHashChange])
|
||||
}, [handleHashChange, shouldHandleHashChange, getResolvedScrollableElement])
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading && items.top.length && items.bottom.length) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { isElmWindow } from "./is-elm-window"
|
||||
|
||||
export function getScrolledTop(elm?: Element | Window): number {
|
||||
if (!elm) {
|
||||
return 0
|
||||
}
|
||||
return isElmWindow(elm) ? elm.scrollY : elm.scrollTop
|
||||
}
|
||||
@@ -3,4 +3,6 @@ export * from "./capitalize"
|
||||
export * from "./check-sidebar-item-visibility"
|
||||
export * from "./dom-utils"
|
||||
export * from "./format-report-link"
|
||||
export * from "./get-scrolled-top"
|
||||
export * from "./is-elm-window"
|
||||
export * from "./swr-fetcher"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export function isElmWindow(elm: unknown): elm is Window {
|
||||
return typeof window !== "undefined" && elm === window
|
||||
}
|
||||
Reference in New Issue
Block a user