🐛 fix(vscode): 代码阅读预览跳到定义后页面还在长高(注释里的 mermaid 画成图、中文名到了)不再把视口带跑:页面滚动统一交给滚动所有者,跟住跳到的目标、用户自己滚了改钉视口顶部那块,关掉浏览器自带的滚动锚定
This commit is contained in:
1 parent
2fa6319dd4
commit
3c5f5f5f35
24 files changed
+1016
-149
No files matched your search
@@ -1,11 +1,11 @@
|
||||
import type { ScrollPosition } from './occurrences'
|
||||
import type { DocumentMessage, Reveal } from './types'
|
||||
import { useLayoutEffect } from 'react'
|
||||
import { blockPath } from './filter'
|
||||
import { pageLayout } from './pageLayout'
|
||||
import { placementOf } from './placement'
|
||||
import { revealPlan, scrollTopToShow, uncoveredPlan } from './reveal'
|
||||
import { stickyHeight } from './useStickyScroll'
|
||||
import { scrollOwner } from './scrollOwner'
|
||||
import { stickyHeight } from './stickyScroll'
|
||||
|
||||
/** 正在闪的元素和到点摘掉 data-flash 的计时器 */
|
||||
const flashing = new WeakMap<HTMLElement, number>()
|
||||
@@ -28,26 +28,16 @@ export function flash(el: HTMLElement): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* 把 target(一个元素,或查找栏的一处命中这样的一段字)滚进钉住的筛选栏和卡片下面的视口,量之前先把它那一带排版好(pageLayout.settle)。
|
||||
* 已经整个看得见就不滚。beforeScroll 在真正滚动前拿到将要落到的位置。
|
||||
* 把 `locate` 找到的目标(一个元素,或查找栏的一处命中这样的一段字)滚进钉住的筛选栏和卡片下面的视口,量之前先把它那一带排版好([PageLayout.settle](vscode/webview-ui/src/codeReader/pageLayout.ts#PageLayout.settle));已经整个看得见就不滚。
|
||||
* 之后由 [scrollOwner] 跟住它:页面再长高变矮也停在原处,直到用户自己动手。`locate` 每次现找,页面重画以后元素可能换了一个。
|
||||
*/
|
||||
export function showInViewport(target: HTMLElement | Range, beforeScroll?: (position: ScrollPosition) => void): void {
|
||||
export function showInViewport(locate: () => HTMLElement | Range | null): void {
|
||||
const target = locate()
|
||||
const el = target instanceof Range ? target.startContainer.parentElement : target
|
||||
if (el)
|
||||
pageLayout.settle(el)
|
||||
const rect = target.getBoundingClientRect()
|
||||
const pinned = pageLayout.pinnedHeight() + stickyHeight()
|
||||
const top = scrollTopToShow(
|
||||
{ top: rect.top + window.scrollY, bottom: rect.bottom + window.scrollY },
|
||||
window.scrollY,
|
||||
window.innerHeight,
|
||||
pinned,
|
||||
)
|
||||
if (top === undefined)
|
||||
return
|
||||
const position = { x: 0, y: top }
|
||||
beforeScroll?.(position)
|
||||
window.scrollTo(position.x, position.y)
|
||||
scrollOwner.reveal(locate, box => scrollTopToShow(box, window.scrollY, window.innerHeight, pinned))
|
||||
}
|
||||
|
||||
/** 这块自己显示着的、下标(块里的)就是定义处的那个名字。子块里的同名下标不算,免得闪到旁边那张卡片。 */
|
||||
@@ -68,6 +58,7 @@ function nameAt(block: HTMLElement, offset: number): HTMLElement | null {
|
||||
* 每一步之后重新渲染、再进来一次;最后把目标滚进筛选栏下面并闪几下。
|
||||
* 属性行 / 子行是这处定义时闪那一行;这块里显示着这个名字(下标盖住定义处)就闪这个名字,不闪整张卡片;
|
||||
* 名字不在页面上才闪整块。目标被正在编辑的祖先盖住时闪那个祖先(uncoveredPlan)。
|
||||
* 滚过去以后由 [scrollOwner] 跟住目标(① 跟住那块),页面再长高(注释里的图画出来、中文名到了)也停在原处。
|
||||
*/
|
||||
export function useReveal(
|
||||
doc: DocumentMessage | null,
|
||||
@@ -82,15 +73,16 @@ export function useReveal(
|
||||
useLayoutEffect(() => {
|
||||
if (!doc || !reveal)
|
||||
return
|
||||
if (reveal.definition === undefined) {
|
||||
const top = pageLayout.cardForLine(reveal.line)?.top
|
||||
if (top !== undefined)
|
||||
window.scrollTo(0, top - pageLayout.pinnedHeight())
|
||||
const { line, definition } = reveal
|
||||
if (definition === undefined) {
|
||||
const card = pageLayout.cardForLine(line)
|
||||
if (card)
|
||||
scrollOwner.align({ line: card.line, offset: 0, scrollTop: card.top })
|
||||
done()
|
||||
return
|
||||
}
|
||||
const placement = placementOf(doc.blocks)
|
||||
const found = revealPlan(doc.blocks, placement, reveal.line, reveal.definition)
|
||||
const found = revealPlan(doc.blocks, placement, line, definition)
|
||||
const plan = found && uncoveredPlan(found, covered)
|
||||
const path = plan ? blockPath(plan.id) : []
|
||||
if (path.some(id => filtered.has(id))) {
|
||||
@@ -102,14 +94,17 @@ export function useReveal(
|
||||
expand(hidden)
|
||||
return
|
||||
}
|
||||
// 块正在编辑时页面上没有属性表,就闪整块
|
||||
const block = plan ? document.querySelector<HTMLElement>(`.cr-block[data-id="${plan.id}"]`) : null
|
||||
const row = plan?.row === undefined ? null : document.querySelector<HTMLElement>(`:is(.cr-prop-row, .cr-prop-item, .cr-table-row)[data-id="${plan.row}"]`)
|
||||
const base = plan && placement.of(plan.id)?.offset
|
||||
const name = row || !block || base === undefined ? null : nameAt(block, reveal.definition - base)
|
||||
const el = row ?? name ?? block
|
||||
// 块正在编辑时页面上没有属性表,就闪整块
|
||||
const locate = (): HTMLElement | null => {
|
||||
const block = plan ? document.querySelector<HTMLElement>(`.cr-block[data-id="${plan.id}"]`) : null
|
||||
const row = plan?.row === undefined ? null : document.querySelector<HTMLElement>(`:is(.cr-prop-row, .cr-prop-item, .cr-table-row)[data-id="${plan.row}"]`)
|
||||
const name = row || !block || base === undefined ? null : nameAt(block, definition - base)
|
||||
return row ?? name ?? block
|
||||
}
|
||||
const el = locate()
|
||||
if (el) {
|
||||
showInViewport(el)
|
||||
showInViewport(locate)
|
||||
flash(el)
|
||||
}
|
||||
done()
|
||||
|
||||
Reference in new issue
Block a user