@@ -18,6 +18,25 @@ function keyEvent(key: number, mods = 0): ZrevEvent {
1818 return { kind : "key" , timeMs : 0 , key, mods, action : "down" } ;
1919}
2020
21+ function mouseEvent (
22+ x : number ,
23+ y : number ,
24+ mouseKind : 1 | 2 | 3 | 4 | 5 ,
25+ opts : Readonly < { wheelX ?: number ; wheelY ?: number } > = { } ,
26+ ) : ZrevEvent {
27+ return {
28+ kind : "mouse" ,
29+ timeMs : 0 ,
30+ x,
31+ y,
32+ mouseKind,
33+ mods : 0 ,
34+ buttons : 0 ,
35+ wheelX : opts . wheelX ?? 0 ,
36+ wheelY : opts . wheelY ?? 0 ,
37+ } ;
38+ }
39+
2140function createNoopBackend ( ) : RuntimeBackend {
2241 return {
2342 start : async ( ) => { } ,
@@ -243,6 +262,42 @@ describe("WidgetRenderer integration battery", () => {
243262 assert . deepEqual ( selected , [ "b:1" ] ) ;
244263 } ) ;
245264
265+ test ( "virtualList onScroll fires for wheel and key-driven scroll" , ( ) => {
266+ const backend = createNoopBackend ( ) ;
267+ const renderer = new WidgetRenderer < void > ( {
268+ backend,
269+ requestRender : ( ) => { } ,
270+ } ) ;
271+
272+ const scrolled : Array < Readonly < { scrollTop : number ; range : [ number , number ] } > > = [ ] ;
273+
274+ const vnode = ui . virtualList ( {
275+ id : "v" ,
276+ items : new Array < number > ( 100 ) . fill ( 0 ) . map ( ( _ , i ) => i ) ,
277+ itemHeight : 1 ,
278+ renderItem : ( item ) => ui . text ( String ( item ) ) ,
279+ onScroll : ( scrollTop , range ) => scrolled . push ( Object . freeze ( { scrollTop, range } ) ) ,
280+ } ) ;
281+
282+ const res = renderer . submitFrame (
283+ ( ) => vnode ,
284+ undefined ,
285+ { cols : 20 , rows : 10 } ,
286+ defaultTheme ,
287+ noRenderHooks ( ) ,
288+ ) ;
289+ assert . ok ( res . ok ) ;
290+
291+ renderer . routeEngineEvent ( mouseEvent ( 1 , 1 , 5 , { wheelY : 1 } ) ) ;
292+ renderer . routeEngineEvent ( keyEvent ( 3 /* TAB */ ) ) ;
293+ renderer . routeEngineEvent ( keyEvent ( 13 /* END */ ) ) ;
294+
295+ assert . deepEqual ( scrolled , [
296+ { scrollTop : 3 , range : [ 0 , 16 ] } ,
297+ { scrollTop : 90 , range : [ 87 , 100 ] } ,
298+ ] ) ;
299+ } ) ;
300+
246301 test ( "table routing moves focused row and activates on Enter" , ( ) => {
247302 const backend = createNoopBackend ( ) ;
248303 const renderer = new WidgetRenderer < void > ( {
0 commit comments