2
2
* Copyright (C) Microsoft Corporation. All rights reserved.
3
3
*--------------------------------------------------------*/
4
4
5
+ import { ComponentChild , ComponentType , Fragment , FunctionComponent , h } from 'preact' ;
6
+ import VirtualList from 'preact-virtual-list' ;
5
7
import { useCallback , useEffect , useLayoutEffect , useMemo , useRef , useState } from 'preact/hooks' ;
6
8
import { addToSet , removeFromSet , toggleInSet } from 'vscode-js-profile-core/out/esm/array' ;
7
9
import { ICommonNode } from 'vscode-js-profile-core/out/esm/common/model' ;
8
10
import { IGraphNode } from 'vscode-js-profile-core/out/esm/cpu/model' ;
9
11
import { ITreeNode } from 'vscode-js-profile-core/out/esm/heap/model' ;
10
12
import { IQueryResults } from 'vscode-js-profile-core/out/esm/ql' ;
13
+ import styles from './time-view.css' ;
11
14
import { SortFn } from './types' ;
12
15
13
16
const getGlobalUniqueId = ( node : ICommonNode ) => {
@@ -19,19 +22,28 @@ const getGlobalUniqueId = (node: ICommonNode) => {
19
22
return parts . join ( '-' ) ;
20
23
} ;
21
24
22
- const useTimeView = < T extends IGraphNode | ITreeNode > ( {
23
- data,
24
- query,
25
- initSortFn,
26
- } : {
25
+ type NodeAtDepth < T > = { node : T ; depth : number ; position : number } ;
26
+
27
+ export interface IRowProps < T > {
28
+ node : T ;
29
+ depth : number ;
30
+ position : number ;
31
+ expanded : boolean ;
32
+ onExpanded : ( isExpanded : boolean , target : T ) => void ;
33
+ onKeyDown : ( evt : KeyboardEvent , target : T ) => void ;
34
+ onFocus : ( target : T ) => void ;
35
+ }
36
+
37
+ export const makeBaseTimeView = < T extends IGraphNode | ITreeNode > ( ) : FunctionComponent < {
27
38
query : IQueryResults < T > ;
28
39
data : T [ ] ;
29
- initSortFn : SortFn ;
30
- } ) => {
40
+ sortFn : SortFn | undefined ;
41
+ header : ComponentChild ;
42
+ row : ComponentType < IRowProps < T > > ;
43
+ } > => ( { data, header, query, sortFn, row : Row } ) => {
31
44
type NodeAtDepth = { node : T ; depth : number ; position : number } ;
32
45
33
46
const listRef = useRef < { base : HTMLElement } > ( ) ;
34
- const [ sortFn , setSortFn ] = useState < SortFn | undefined > ( ( ) => initSortFn ) ;
35
47
const [ focused , setFocused ] = useState < T | undefined > ( undefined ) ;
36
48
const [ expanded , setExpanded ] = useState < ReadonlySet < T > > ( new Set ( ) ) ;
37
49
@@ -148,16 +160,45 @@ const useTimeView = <T extends IGraphNode | ITreeNode>({
148
160
} ) ;
149
161
} , [ focused ] ) ;
150
162
151
- return {
152
- listRef,
153
- rendered,
154
- onKeyDown,
155
- expanded,
156
- setExpanded,
157
- setFocused,
158
- sortFn,
159
- setSortFn,
163
+ const onExpanded = ( isExpanded : boolean , node : T ) => {
164
+ setExpanded ( prev => {
165
+ const next = new Set ( prev ) ;
166
+ if ( isExpanded ) {
167
+ next . add ( node ) ;
168
+ } else {
169
+ next . delete ( node ) ;
170
+ }
171
+
172
+ return next . size !== prev . size ? next : prev ;
173
+ } ) ;
160
174
} ;
161
- } ;
162
175
163
- export default useTimeView ;
176
+ const renderRow = useCallback (
177
+ ( row : NodeAtDepth ) => (
178
+ < Row
179
+ onKeyDown = { onKeyDown }
180
+ node = { row . node }
181
+ depth = { row . depth }
182
+ position = { row . position }
183
+ expanded = { expanded . has ( row . node ) }
184
+ onExpanded = { onExpanded }
185
+ onFocus = { setFocused }
186
+ />
187
+ ) ,
188
+ [ expanded , setExpanded , onKeyDown ] ,
189
+ ) ;
190
+
191
+ return (
192
+ < Fragment >
193
+ { header }
194
+ < VirtualList
195
+ ref = { listRef }
196
+ className = { styles . rows }
197
+ data = { rendered }
198
+ renderRow = { renderRow }
199
+ rowHeight = { 25 }
200
+ overscanCount = { 100 }
201
+ />
202
+ </ Fragment >
203
+ ) ;
204
+ } ;
0 commit comments