fix: calc toc scroller range when entry content changed
Signed-off-by: Innei <i@innei.in>
This commit is contained in:
parent
1708533f79
commit
66035fea72
|
|
@ -1,5 +1,6 @@
|
|||
import * as HoverCard from "@radix-ui/react-hover-card"
|
||||
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"
|
||||
|
|
@ -98,13 +99,24 @@ export const Toc: Component = ({ className }) => {
|
|||
const titleBetweenPositionTopRangeMap = [] as [number, number][]
|
||||
for (let i = 0; i < $headings.length - 1; i++) {
|
||||
const $heading = $headings[i]
|
||||
const $nextHeading = $headings[i + 1]
|
||||
const top = Number.parseInt($heading.dataset["containerTop"] || "0")
|
||||
const nextTop = Number.parseInt(
|
||||
$nextHeading.dataset["containerTop"] || "0",
|
||||
)
|
||||
|
||||
titleBetweenPositionTopRangeMap.push([top, nextTop])
|
||||
const headingTop =
|
||||
Number.parseInt($heading.dataset["containerTop"] || "0") ||
|
||||
getElementTop($heading)
|
||||
if (!$heading.dataset) {
|
||||
// @ts-expect-error
|
||||
$heading.dataset["containerTop"] = headingTop.toString()
|
||||
}
|
||||
|
||||
const $nextHeading = $headings[i + 1]
|
||||
|
||||
const nextTop = getElementTop($nextHeading)
|
||||
if (!$nextHeading.dataset) {
|
||||
// @ts-expect-error
|
||||
$nextHeading.dataset["containerTop"] = nextTop.toString()
|
||||
}
|
||||
|
||||
titleBetweenPositionTopRangeMap.push([headingTop, nextTop])
|
||||
}
|
||||
return titleBetweenPositionTopRangeMap
|
||||
}, [$headings])
|
||||
|
|
@ -136,7 +148,6 @@ export const Toc: Component = ({ className }) => {
|
|||
// current top is this range, the precent is ?
|
||||
const precent = (actualTop - start) / (end - start)
|
||||
|
||||
// console.log("currentRange", currentRange, precent)
|
||||
// position , precent
|
||||
setCurrentScrollRange([currentRangeIndex, precent])
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { springScrollToElement } from "@renderer/lib/scroller"
|
||||
import { cn } from "@renderer/lib/utils"
|
||||
import { useWrappedElementSize } from "@renderer/providers/wrapped-element-provider"
|
||||
import { useContext, useId, useLayoutEffect, useRef, useState } from "react"
|
||||
import { useContext, useId, useRef } from "react"
|
||||
|
||||
import { useScrollViewElement } from "../../scroll-area/hooks"
|
||||
import { MarkdownRenderContainerRefContext } from "../context"
|
||||
|
|
@ -23,22 +22,9 @@ export const createHeadingRenderer =
|
|||
const renderContainer = useContext(MarkdownRenderContainerRefContext)
|
||||
const ref = useRef<HTMLHeadingElement>(null)
|
||||
|
||||
const [currentTitleTop, setCurrentTitleTop] = useState(0)
|
||||
const { h } = useWrappedElementSize()
|
||||
useLayoutEffect(() => {
|
||||
const $heading = ref.current
|
||||
if (!$heading) return
|
||||
// const { top } = $heading.getBoundingClientRect()
|
||||
// // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-layout-effect
|
||||
// setCurrentTitleTop(top | 0)
|
||||
const top = getElementTop($heading)
|
||||
setCurrentTitleTop(top)
|
||||
}, [h])
|
||||
|
||||
return (
|
||||
<As
|
||||
ref={ref}
|
||||
data-container-top={currentTitleTop}
|
||||
{...rest}
|
||||
data-rid={rid}
|
||||
className={cn(rest.className, "group relative")}
|
||||
|
|
@ -69,13 +55,3 @@ export const createHeadingRenderer =
|
|||
</As>
|
||||
)
|
||||
}
|
||||
|
||||
const getElementTop = (element: HTMLElement) => {
|
||||
let actualTop = element.offsetTop
|
||||
let current = element.offsetParent as HTMLElement
|
||||
while (current !== null) {
|
||||
actualTop += current.offsetTop
|
||||
current = current.offsetParent as HTMLElement
|
||||
}
|
||||
return actualTop
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,3 +12,13 @@ export const nextFrame = (fn: (...args: any[]) => any) => {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const getElementTop = (element: HTMLElement) => {
|
||||
let actualTop = element.offsetTop
|
||||
let current = element.offsetParent as HTMLElement
|
||||
while (current !== null) {
|
||||
actualTop += current.offsetTop
|
||||
current = current.offsetParent as HTMLElement
|
||||
}
|
||||
return actualTop
|
||||
}
|
||||
|
|
|
|||
|
|
@ -445,8 +445,10 @@ const ContainerToc: FC = () => {
|
|||
<div className="sticky top-0">
|
||||
<Toc
|
||||
className={cn(
|
||||
"flex flex-col items-end animate-in fade-in-0 slide-in-from-bottom-12 easing-spring-soft @[900px]:items-start",
|
||||
"flex flex-col items-end animate-in fade-in-0 slide-in-from-bottom-12 easing-spring-soft",
|
||||
"max-h-[calc(100vh-100px)] overflow-auto scrollbar-none",
|
||||
|
||||
"@[600px]:-translate-x-16 @[900px]:translate-x-0 @[900px]:items-start",
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue