fix: toc range calcation

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei 2024-08-31 12:17:47 +08:00
parent d4581dbb19
commit 2ebcc58414
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
1 changed files with 32 additions and 7 deletions

View File

@ -3,10 +3,22 @@ import { getViewport } from "@renderer/atoms/hooks/viewport"
import { getElementTop } from "@renderer/lib/dom"
import { springScrollToElement } from "@renderer/lib/scroller"
import { cn } from "@renderer/lib/utils"
import { useGetWrappedElementPosition } from "@renderer/providers/wrapped-element-provider"
import {
useGetWrappedElementPosition,
useWrappedElementSize,
} from "@renderer/providers/wrapped-element-provider"
import { AnimatePresence, m } from "framer-motion"
import { throttle } from "lodash-es"
import { memo, useContext, useEffect, useMemo, useRef, useState } from "react"
import {
memo,
startTransition,
useContext,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from "react"
import { useEventCallback } from "usehooks-ts"
import { useScrollViewElement } from "../../scroll-area/hooks"
@ -93,8 +105,10 @@ export const Toc: Component = ({ className }) => {
},
)
const { h } = useWrappedElementSize()
const [currentScrollRange, setCurrentScrollRange] = useState([-1, 0])
const titleBetweenPositionTopRangeMap = useMemo(() => {
const headingRangeParser = () => {
// calculate the range of data-container-top between each two headings
const titleBetweenPositionTopRangeMap = [] as [number, number][]
for (let i = 0; i < $headings.length - 1; i++) {
@ -119,7 +133,16 @@ export const Toc: Component = ({ className }) => {
titleBetweenPositionTopRangeMap.push([headingTop, nextTop])
}
return titleBetweenPositionTopRangeMap
}, [$headings])
}
const [titleBetweenPositionTopRangeMap, setTitleBetweenPositionTopRangeMap] =
useState(headingRangeParser)
useLayoutEffect(() => {
startTransition(() => {
setTitleBetweenPositionTopRangeMap(headingRangeParser)
})
}, [$headings, h])
const throttleCallerRef = useRef<DebouncedFuncLeading<() => void>>()
const getWrappedElPos = useGetWrappedElementPosition()
@ -152,10 +175,11 @@ export const Toc: Component = ({ className }) => {
setCurrentScrollRange([currentRangeIndex, precent])
} else {
const last = titleBetweenPositionTopRangeMap.at(-1) || [0, 0]
if (top > last[1]) {
if (top + winHeight > last[1]) {
setCurrentScrollRange([
titleBetweenPositionTopRangeMap.length - 1,
1,
titleBetweenPositionTopRangeMap.length,
1 - (last[1] - top) / winHeight,
])
} else {
setCurrentScrollRange([-1, 1])
@ -168,6 +192,7 @@ export const Toc: Component = ({ className }) => {
return () => {
scrollContainerElement.removeEventListener("scroll", handler)
handler.cancel()
}
}, [
getWrappedElPos,