Skip to content

Commit 1bb49e2

Browse files
feat: keep toggle scroll location
1 parent be6bd52 commit 1bb49e2

File tree

3 files changed

+47
-36
lines changed

3 files changed

+47
-36
lines changed

src/webview/SearchSidebar/SearchResultList/TreeItem.tsx

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { useBoolean } from 'react-use'
21
import TreeHeader from './TreeHeader'
32
import type { DisplayResult } from '../../../types'
43
import { MatchList } from './MatchList'
5-
import { memo, useEffect, useRef } from 'react'
6-
import { useToggleResult } from './useListState'
4+
import { memo } from 'react'
5+
import { useToggleResult, useStickyShadow } from './useListState'
76
import * as stylex from '@stylexjs/stylex'
87

98
const styles = stylex.create({
@@ -24,37 +23,15 @@ const styles = stylex.create({
2423
},
2524
})
2625

27-
function useStickyShadow() {
28-
const [isScrolled, setScrolled] = useBoolean(false)
29-
const ref = useRef<HTMLDivElement>(null)
30-
useEffect(() => {
31-
const observer = new IntersectionObserver(entries => {
32-
const entry = entries[0]
33-
if (entry.isIntersecting) {
34-
setScrolled(false)
35-
} else {
36-
setScrolled(true)
37-
}
38-
})
39-
observer.observe(ref.current!)
40-
return () => {
41-
observer.disconnect()
42-
}
43-
})
44-
return {
45-
isScrolled,
46-
ref,
47-
}
48-
}
49-
5026
interface TreeItemProps {
5127
className: string
5228
matches: DisplayResult[]
5329
}
5430

5531
const TreeItem = ({ className, matches }: TreeItemProps) => {
56-
const [isExpanded, toggleIsExpanded] = useToggleResult(matches[0].file)
57-
const { isScrolled, ref } = useStickyShadow()
32+
const filePath = matches[0].file
33+
const [isExpanded, toggleIsExpanded] = useToggleResult(filePath)
34+
const { isScrolled, ref } = useStickyShadow(filePath)
5835
const props = stylex.props(styles.treeItem)
5936

6037
return (

src/webview/SearchSidebar/SearchResultList/useListState.tsx

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// maintains data list's UI state
22
// e.g. toggle expand selected item
33

4-
import { useCallback } from 'react'
4+
import { useCallback, useEffect, useRef } from 'react'
55
import { useBoolean } from 'react-use'
6-
import { onResultChange } from '../../hooks/useSearch'
6+
import { onResultChange, findIndex } from '../../hooks/useSearch'
77
import type { VirtuosoHandle } from 'react-virtuoso'
88

99
let ref: VirtuosoHandle
@@ -24,14 +24,18 @@ export function useToggleResult(filePath: string) {
2424
const toggleIsExpanded = useCallback(() => {
2525
toggleResult(filePath)
2626
toggle()
27-
if (isExpanded) {
28-
// TODO
29-
// ref.scrollToIndex(10)
27+
if (isExpanded && lastActiveFile === filePath) {
28+
const index = findIndex(filePath)
29+
if (index) {
30+
ref.scrollToIndex(index)
31+
}
3032
}
3133
}, [filePath, toggle, isExpanded])
3234
return [isExpanded, toggleIsExpanded] as const
3335
}
3436

37+
let lastActiveFile = ''
38+
3539
function toggleResult(filePath: string) {
3640
if (collapseMap.has(filePath)) {
3741
collapseMap.delete(filePath)
@@ -40,6 +44,32 @@ function toggleResult(filePath: string) {
4044
}
4145
}
4246

47+
export function useStickyShadow(filePath: string) {
48+
const [isScrolled, setScrolled] = useBoolean(false)
49+
const ref = useRef<HTMLDivElement>(null)
50+
useEffect(() => {
51+
const observer = new IntersectionObserver(entries => {
52+
const entry = entries[0]
53+
if (entry.isIntersecting) {
54+
setScrolled(false)
55+
} else {
56+
setScrolled(true)
57+
if (!isScrolled) {
58+
lastActiveFile = filePath
59+
}
60+
}
61+
})
62+
observer.observe(ref.current!)
63+
return () => {
64+
observer.disconnect()
65+
}
66+
}, [isScrolled])
67+
return {
68+
isScrolled,
69+
ref,
70+
}
71+
}
72+
4373
// let activeItem: DisplayResult | null = null
4474

4575
// function setActiveItem(match: DisplayResult) {

src/webview/hooks/useSearch.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export function onResultChange(f: () => void) {
5050
}
5151
}
5252

53-
function byFileName(a: [string, unknown], b: [string, unknown]) {
53+
function byFilePath(a: [string, unknown], b: [string, unknown]) {
5454
return a[0].localeCompare(b[0])
5555
}
5656

@@ -72,7 +72,7 @@ childPort.onMessage('searchResultStreaming', event => {
7272
refreshResultIfStale()
7373
queryInFlight = query
7474
grouped = merge(groupBy(event.searchResult))
75-
grouped.sort(byFileName)
75+
grouped.sort(byFilePath)
7676
notify()
7777
})
7878

@@ -109,7 +109,7 @@ childPort.onMessage('refreshSearchResult', event => {
109109
temp.set(fileName, updatedResults)
110110
}
111111
grouped = [...temp.entries()]
112-
grouped.sort(byFileName)
112+
grouped.sort(byFilePath)
113113
notify()
114114
})
115115

@@ -234,3 +234,7 @@ export function dismissOneFile(filePath: string) {
234234
grouped = grouped.filter(g => g[0] !== filePath)
235235
notify()
236236
}
237+
238+
export function findIndex(filePath: string) {
239+
return grouped.findIndex(g => g[0] === filePath)
240+
}

0 commit comments

Comments
 (0)