3
3
import { useBrowseNavigation } from "@/app/[domain]/browse/hooks/useBrowseNavigation" ;
4
4
import { FileHeader } from "@/app/[domain]/components/fileHeader" ;
5
5
import { LightweightCodeHighlighter } from "@/app/[domain]/components/lightweightCodeHighlighter" ;
6
- import { ScrollArea } from "@/components/ui/scroll-area" ;
7
6
import { FindRelatedSymbolsResponse } from "@/features/codeNav/types" ;
8
7
import { RepositoryInfo , SourceRange } from "@/features/search/types" ;
9
8
import { base64Decode } from "@/lib/utils" ;
10
- import { useMemo } from "react" ;
9
+ import { useMemo , useRef } from "react" ;
11
10
import useCaptureEvent from "@/hooks/useCaptureEvent" ;
11
+ import { useVirtualizer } from "@tanstack/react-virtual" ;
12
12
13
13
interface ReferenceListProps {
14
14
data : FindRelatedSymbolsResponse ;
15
15
revisionName : string ;
16
16
}
17
17
18
+ const ESTIMATED_LINE_HEIGHT_PX = 30 ;
19
+ const ESTIMATED_MATCH_CONTAINER_HEIGHT_PX = 30 ;
20
+
18
21
export const ReferenceList = ( {
19
22
data,
20
23
revisionName,
@@ -29,52 +32,102 @@ export const ReferenceList = ({
29
32
const { navigateToPath } = useBrowseNavigation ( ) ;
30
33
const captureEvent = useCaptureEvent ( ) ;
31
34
32
- return (
33
- < ScrollArea className = "h-full" >
34
- { data . files . map ( ( file , index ) => {
35
- const repoInfo = repoInfoMap [ file . repositoryId ] ;
35
+ // Virtualization setup
36
+ const parentRef = useRef < HTMLDivElement > ( null ) ;
37
+ const virtualizer = useVirtualizer ( {
38
+ count : data . files . length ,
39
+ getScrollElement : ( ) => parentRef . current ,
40
+ estimateSize : ( index ) => {
41
+ const file = data . files [ index ] ;
42
+
43
+ const estimatedSize =
44
+ file . matches . length * ESTIMATED_LINE_HEIGHT_PX +
45
+ ESTIMATED_MATCH_CONTAINER_HEIGHT_PX ;
46
+
47
+ return estimatedSize ;
48
+ } ,
49
+ overscan : 5 ,
50
+ enabled : true ,
51
+ } ) ;
36
52
37
- return (
38
- < div key = { index } >
39
- < div className = "bg-accent py-1 px-2 flex flex-row sticky top-0" >
40
- < FileHeader
41
- repo = { {
42
- name : repoInfo . name ,
43
- displayName : repoInfo . displayName ,
44
- codeHostType : repoInfo . codeHostType ,
45
- webUrl : repoInfo . webUrl ,
53
+ return (
54
+ < div
55
+ ref = { parentRef }
56
+ style = { {
57
+ width : "100%" ,
58
+ height : "100%" ,
59
+ overflowY : "auto" ,
60
+ contain : "strict" ,
61
+ } }
62
+ >
63
+ < div
64
+ style = { {
65
+ height : virtualizer . getTotalSize ( ) ,
66
+ width : "100%" ,
67
+ position : "relative" ,
68
+ } }
69
+ >
70
+ { virtualizer . getVirtualItems ( ) . map ( ( virtualRow ) => {
71
+ const file = data . files [ virtualRow . index ] ;
72
+ const repoInfo = repoInfoMap [ file . repositoryId ] ;
73
+ return (
74
+ < div
75
+ key = { virtualRow . key }
76
+ data-index = { virtualRow . index }
77
+ ref = { virtualizer . measureElement }
78
+ style = { {
79
+ position : "absolute" ,
80
+ transform : `translateY(${ virtualRow . start } px)` ,
81
+ top : 0 ,
82
+ left : 0 ,
83
+ width : "100%" ,
84
+ } }
85
+ >
86
+ < div
87
+ className = "bg-accent py-1 px-2 flex flex-row sticky top-0 z-10"
88
+ style = { {
89
+ top : `-${ virtualRow . start } px` ,
46
90
} }
47
- fileName = { file . fileName }
48
- branchDisplayName = { revisionName === "HEAD" ? undefined : revisionName }
49
- />
50
- </ div >
51
- < div className = "divide-y" >
52
- { file . matches
53
- . sort ( ( a , b ) => a . range . start . lineNumber - b . range . start . lineNumber )
54
- . map ( ( match , index ) => (
55
- < ReferenceListItem
56
- key = { index }
57
- lineContent = { match . lineContent }
58
- range = { match . range }
59
- language = { file . language }
60
- onClick = { ( ) => {
61
- captureEvent ( 'wa_explore_menu_reference_clicked' , { } ) ;
62
- navigateToPath ( {
63
- repoName : file . repository ,
64
- revisionName,
65
- path : file . fileName ,
66
- pathType : 'blob' ,
67
- highlightRange : match . range ,
68
- } )
69
- } }
70
- />
71
- ) ) }
91
+ >
92
+ < FileHeader
93
+ repo = { {
94
+ name : repoInfo . name ,
95
+ displayName : repoInfo . displayName ,
96
+ codeHostType : repoInfo . codeHostType ,
97
+ webUrl : repoInfo . webUrl ,
98
+ } }
99
+ fileName = { file . fileName }
100
+ branchDisplayName = { revisionName === "HEAD" ? undefined : revisionName }
101
+ />
102
+ </ div >
103
+ < div className = "divide-y" >
104
+ { file . matches
105
+ . sort ( ( a , b ) => a . range . start . lineNumber - b . range . start . lineNumber )
106
+ . map ( ( match , index ) => (
107
+ < ReferenceListItem
108
+ key = { index }
109
+ lineContent = { match . lineContent }
110
+ range = { match . range }
111
+ language = { file . language }
112
+ onClick = { ( ) => {
113
+ captureEvent ( 'wa_explore_menu_reference_clicked' , { } ) ;
114
+ navigateToPath ( {
115
+ repoName : file . repository ,
116
+ revisionName,
117
+ path : file . fileName ,
118
+ pathType : 'blob' ,
119
+ highlightRange : match . range ,
120
+ } )
121
+ } }
122
+ />
123
+ ) ) }
124
+ </ div >
72
125
</ div >
73
- </ div >
74
- )
75
- } ) }
76
- </ ScrollArea >
77
- )
126
+ ) ;
127
+ } ) }
128
+ </ div >
129
+ </ div >
130
+ ) ;
78
131
}
79
132
80
133
0 commit comments