1- import { createVirtualizer , VirtualItem , VirtualizerOptions } from "@tanstack/solid-virtual" ;
2- import { createUniqueId , mergeProps , createMemo , createSignal , onMount , untrack } from "solid-js" ;
3- import { mergeRefs , createGenerateId } from "@kobalte/utils" ;
4- import { isServer } from "solid-js/web" ;
1+ import { createVirtualizer , VirtualItem , VirtualizerOptions } from "@tanstack/solid-virtual"
2+ import { createUniqueId , mergeProps , createMemo , createSignal , onMount , untrack , createEffect , on } from "solid-js"
3+ import { mergeRefs , createGenerateId } from "@kobalte/utils"
4+ import { isServer } from "solid-js/web"
55
6- export type Primitive = string | number | boolean | null | undefined ;
7- export type ObjectWithKey = { [ key : string ] : any } ;
6+ export type Primitive = string | number | boolean | null | undefined
7+ export type ObjectWithKey = { [ key : string ] : any }
88
9- export type KeyFunction < T > = ( item : T , index ?: number ) => string | number ;
9+ export type KeyFunction < T > = ( item : T , index ?: number ) => string | number
1010
1111
1212export interface VirtualizedListArgs < T , ScrollElement extends Element = Element , ItemElement extends Element = Element > extends Partial < VirtualizerOptions < ScrollElement , ItemElement > > {
13- id ?: string ;
14- data : ( ) => T [ ] ;
15- determineKey ?: KeyFunction < T > ;
16- itemHeight ?: number ;
17- width ?: number ;
18- height ?: number ;
19- rootProps ?: Record < string , any > ;
20- containerProps ?: Record < string , any > ;
21- itemProps ?: Record < string , any > ;
13+ id ?: string
14+ data : ( ) => T [ ]
15+ determineKey ?: KeyFunction < T >
16+ itemHeight ?: number
17+ width ?: number
18+ height ?: number
19+ rootProps ?: Record < string , any >
20+ containerProps ?: Record < string , any >
21+ itemProps ?: Record < string , any >
2222}
2323
2424export interface VirtualItemWithExtras extends VirtualItem {
25- isLast : boolean ;
26- isEven : boolean ;
25+ isLast : boolean
26+ isEven : boolean
2727}
2828
2929export interface ItemArgs < T > {
30- data : T ;
31- props : Record < string , any > ;
32- virtualItem : VirtualItemWithExtras ;
30+ data : T
31+ props : Record < string , any >
32+ virtualItem : VirtualItemWithExtras
3333}
3434
3535/**
@@ -49,13 +49,13 @@ export interface ItemArgs<T> {
4949 *
5050 * @example
5151 * const MyList = () => {
52- * const items = () => ['Item 1', 'Item 2', 'Item 3'];
52+ * const items = () => ['Item 1', 'Item 2', 'Item 3']
5353 * const virtualList = createVirtualizedList({
5454 * data: items,
5555 * itemHeight: 30,
5656 * height: 300,
5757 * width: 500,
58- * });
58+ * })
5959 *
6060 * return (
6161 * <div {...virtualList.root}>
@@ -67,62 +67,62 @@ export interface ItemArgs<T> {
6767 * </For>
6868 * </div>
6969 * </div>
70- * );
71- * };
70+ * )
71+ * }
7272 */
7373export function createVirtualizedList < T extends Primitive | ObjectWithKey > ( args : VirtualizedListArgs < T > ) {
74- const id = args . id || createUniqueId ( ) ;
75- const generateId = createGenerateId ( ( ) => id ) ;
74+ const id = ( ) => args . id || createUniqueId ( )
75+ const generateId = ( ) => createGenerateId ( ( ) => id ( ) )
76+
77+ const data = args . data
78+ const count = createMemo ( ( ) => args ?. count ?? data ( ) ?. length ?? 0 )
7679
77- const data = args . data ;
78- const count = createMemo ( ( ) => args . count || data ( ) ?. length || 0 ) ;
79-
8080 // @ts -expect-error
81- const determineKey : KeyFunction < T > = args . determineKey || args . getItemKey || ( ( item : T , index ?: number ) => {
81+ const determineKey : ( ) => KeyFunction < T > = createMemo ( ( ) => args ? .determineKey ?? args ? .getItemKey ?? ( ( item : T , index ?: number ) => {
8282 if ( typeof item === 'object' && item !== null ) {
83- return ( item as ObjectWithKey ) ?. id ??
84- ( item as ObjectWithKey ) ?. Id ??
85- ( item as ObjectWithKey ) ?. ID ??
86- ( item as ObjectWithKey ) ?. uuid ??
87- ( item as ObjectWithKey ) ?. UUID ??
88- ( item as ObjectWithKey ) ?. key ??
89- ( item as ObjectWithKey ) ?. sku ??
90- index ! ;
83+ return ( item as ObjectWithKey ) ?. id ??
84+ ( item as ObjectWithKey ) ?. Id ??
85+ ( item as ObjectWithKey ) ?. ID ??
86+ ( item as ObjectWithKey ) ?. uuid ??
87+ ( item as ObjectWithKey ) ?. UUID ??
88+ ( item as ObjectWithKey ) ?. key ??
89+ ( item as ObjectWithKey ) ?. sku ??
90+ index !
9191 }
92- return item as unknown as string | number ;
93- } ) ;
92+ return item as unknown as string | number
93+ } ) )
9494
95- const horizontal = ( ) => args ?. horizontal ?? false ;
95+ const horizontal = ( ) => args ?. horizontal ?? false
9696
97- const [ rootElement , setRootElement ] = createSignal < Element | null > ( null ) ;
97+ const [ rootElement , setRootElement ] = createSignal < Element | null > ( null )
9898
99- const getScrollElement = ( ) => rootElement ( ) ;
99+ const getScrollElement = ( ) => rootElement ( )
100100
101- const estimateSize = createMemo ( ( ) => args ?. estimateSize || ( ( index : number ) => args . itemHeight || 50 ) ) ;
101+ const estimateSize = createMemo ( ( ) => args ?. estimateSize || ( ( index : number ) => args . itemHeight || 50 ) )
102102
103103 const initialRect = ( ) => ( {
104104 width : args ?. width ?? args . initialRect ?. width ?? 600 ,
105105 height : args ?. height ?? args . initialRect ?. height ?? 400 ,
106- } ) ;
106+ } )
107107
108108 const measureElement = createMemo ( ( ) => {
109- if ( isServer ) return undefined ;
109+ if ( isServer ) return undefined
110110
111- if ( args . measureElement ) return args . measureElement ;
111+ if ( args . measureElement ) return args . measureElement
112112 if ( navigator . userAgent . indexOf ( 'Firefox' ) === - 1 ) {
113113 return ( element : Element ) => {
114- return element ?. getBoundingClientRect ( ) [ horizontal ( ) ? 'width' : 'height' ] ;
115- } ;
114+ return element ?. getBoundingClientRect ( ) [ horizontal ( ) ? 'width' : 'height' ]
115+ }
116116 }
117117
118- return undefined ;
119- } ) ;
118+ return undefined
119+ } )
120120
121121 const reactiveArgs = createMemo ( ( ) => args )
122122
123123 const options : ( ) => VirtualizerOptions < Element , Element > = createMemo ( ( ) => {
124124 const currentArgs = reactiveArgs ( )
125-
125+
126126 return mergeProps ( {
127127 get count ( ) {
128128 return count ( )
@@ -139,47 +139,47 @@ export function createVirtualizedList<T extends Primitive | ObjectWithKey>(args:
139139 initialOffset : currentArgs ?. initialOffset ?? 0 ,
140140 onChange : currentArgs . onChange ,
141141 scrollToFn : currentArgs ?. scrollToFn ?? ( ( offset , { behavior } ) => {
142- const scrollElement = getScrollElement ( ) ;
142+ const scrollElement = getScrollElement ( )
143143 if ( scrollElement ) {
144144 scrollElement . scrollTo ( {
145145 [ horizontal ( ) ? 'left' : 'top' ] : offset ,
146146 behavior,
147- } ) ;
147+ } )
148148 }
149149 } ) ,
150150 observeElementRect : currentArgs ?. observeElementRect ?? ( ( instance , cb ) => {
151- const scrollElement = getScrollElement ( ) ;
152- if ( ! scrollElement ) return ;
153-
151+ const scrollElement = getScrollElement ( )
152+ if ( ! scrollElement ) return
153+
154154 const resizeObserver = new ResizeObserver ( ( ) => {
155- const rect = scrollElement . getBoundingClientRect ( ) ;
156- cb ( rect ) ;
157- } ) ;
158-
159- resizeObserver . observe ( scrollElement ) ;
160-
161- return ( ) => resizeObserver . disconnect ( ) ;
155+ const rect = scrollElement . getBoundingClientRect ( )
156+ cb ( rect )
157+ } )
158+
159+ resizeObserver . observe ( scrollElement )
160+
161+ return ( ) => resizeObserver . disconnect ( )
162162 } ) ,
163163 observeElementOffset : currentArgs ?. observeElementOffset ?? ( ( instance , cb ) => {
164- const scrollElement = getScrollElement ( ) ;
165- if ( ! scrollElement ) return ;
166-
164+ const scrollElement = getScrollElement ( )
165+ if ( ! scrollElement ) return
166+
167167 const handleScroll = ( ) => {
168168 const offset = horizontal ( )
169169 ? scrollElement . scrollLeft
170- : scrollElement . scrollTop ;
171- cb ( offset , true ) ;
172- } ;
173-
170+ : scrollElement . scrollTop
171+ cb ( offset , true )
172+ }
173+
174174 scrollElement . addEventListener ( 'scroll' , handleScroll , {
175175 passive : true ,
176- } ) ;
177-
178- return ( ) => scrollElement . removeEventListener ( 'scroll' , handleScroll ) ;
176+ } )
177+
178+ return ( ) => scrollElement . removeEventListener ( 'scroll' , handleScroll )
179179 } ) ,
180180 debug : currentArgs ?. debug ,
181181 measureElement : measureElement ( ) ,
182- getItemKey : ( index : number ) => determineKey ( data ( ) [ index ] , index ) ,
182+ getItemKey : ( index : number ) => { return determineKey ( ) ( data ( ) [ index ] , index ) } ,
183183 rangeExtractor : currentArgs ?. rangeExtractor ,
184184 scrollMargin : currentArgs ?. scrollMargin ,
185185 gap : currentArgs ?. gap ,
@@ -191,67 +191,72 @@ export function createVirtualizedList<T extends Primitive | ObjectWithKey>(args:
191191 isRtl : currentArgs ?. isRtl ,
192192 } , currentArgs )
193193 }
194- )
194+ )
195195
196- const virtualizer = createMemo ( ( ) => createVirtualizer ( options ( ) ) )
196+ const virtualizer = ( createVirtualizer ( options ( ) ) )
197+
198+ createEffect ( on ( options , ( ) => {
199+ virtualizer . setOptions ( options ( ) )
200+ } , { defer : true } ) )
197201
198202 const rootProps = createMemo ( ( ) => {
199203 const defaultStyle = {
200204 'overflow-y' : horizontal ( ) ? 'hidden' : 'auto' ,
201205 'overflow-x' : horizontal ( ) ? 'auto' : 'hidden' ,
202206 position : 'relative' ,
203207 height : args ?. height ? `${ args . height } px` : '400px' ,
204- width : args ?. width ? `${ args . width } px` : '100%' ,
205- } ;
206- const horizontalAttr = horizontal ( ) ? "" : undefined ;
208+ width : args ?. width ? `${ args . width } px` : '100%' ,
209+ }
210+ const horizontalAttr = horizontal ( ) ? "" : undefined
207211
208212 return mergeProps ( {
209213 id : id ,
210214 style : defaultStyle ,
211215 "data-horizontal" : horizontalAttr ,
212216 "data-list-id" : id ,
213217 ref : mergeRefs ( ( el : Element ) => setRootElement ( el ) , args . rootProps ?. ref ) ,
214- } , args . rootProps || { } ) ;
215- } ) ;
218+ } , args . rootProps || { } )
219+ } )
216220
217221 const containerProps = createMemo ( ( ) => {
218- const containerId = generateId ( 'list' ) ;
222+ const containerId = generateId ( ) ( 'list' )
219223 const defaultStyle = {
220224 position : 'relative' ,
221- height : horizontal ( ) ? '100%' : `${ virtualizer ( ) . getTotalSize ( ) } px` ,
222- width : horizontal ( ) ? `${ virtualizer ( ) . getTotalSize ( ) } px` : '100%' ,
223- } ;
225+ height : horizontal ( ) ? '100%' : `${ virtualizer . getTotalSize ( ) } px` ,
226+ width : horizontal ( ) ? `${ virtualizer . getTotalSize ( ) } px` : '100%' ,
227+ }
224228
225229 return mergeProps ( {
226230 style : defaultStyle ,
227231 "data-list-container" : containerId ,
228- } , args . containerProps || { } ) ;
229- } ) ;
232+ } , args . containerProps || { } )
233+ } )
230234
231- const itemWrapper = ( itemCreator : ( args : ItemArgs < T > ) => any , trackChanges = false ) =>
235+ const itemWrapper = ( itemCreator : ( args : ItemArgs < T > ) => any , trackChanges = false ) =>
232236 ( virtualItem : VirtualItem , virtualItemIndex : ( ) => number ) => {
233237 const createItem = ( ) => {
234- const itemData = data ( ) [ virtualItem . index ] ;
238+ const itemData = data ( ) [ virtualItem . index ]
235239 const style = {
236240 position : 'absolute' ,
237241 top : horizontal ( ) ? 0 : `${ virtualItem . start } px` ,
238242 left : horizontal ( ) ? `${ virtualItem . start } px` : 0 ,
239243 width : horizontal ( ) ? `${ virtualItem . size } px` : '100%' ,
240244 height : horizontal ( ) ? '100%' : `${ virtualItem . size } px` ,
241- } ;
242- const key = determineKey ( itemData , virtualItem . index ) ;
245+ }
246+
247+ const key = determineKey ( ) ( itemData , virtualItem . index )
243248 const itemProps = mergeProps ( {
244249 style,
245250 'data-list-item' : 'true' ,
246251 'data-index' : virtualItem . index ,
247252 key,
248- ref : mergeRefs ( ( el : Element ) => {
249- if ( el ) virtualizer ( ) . measureElement ( el ) ;
253+ ref : mergeRefs ( ( el : Element ) => {
254+ if ( el ) virtualizer . measureElement ( el )
250255 } , args . itemProps ?. ref ) ,
251- } , args ?. itemProps ?? { } ) ;
256+ } , args ?. itemProps ?? { } )
252257
253- const isLast = virtualItem . index === count ( ) - 1 ;
254- const isEven = virtualItem . index % 2 === 0 ;
258+ const isLast = virtualItem . index === count ( ) - 1
259+ const isEven = virtualItem . index % 2 === 0
255260 const itemArgs : ItemArgs < T > = {
256261 data : itemData ,
257262 props : itemProps ,
@@ -260,31 +265,33 @@ export function createVirtualizedList<T extends Primitive | ObjectWithKey>(args:
260265 isLast,
261266 isEven,
262267 } ,
263- } ;
264-
265- return itemCreator ( itemArgs ) ;
268+ }
269+
270+ return itemCreator ( itemArgs )
266271 }
267272
268- return trackChanges ? createMemo ( createItem ) : untrack ( createItem )
273+ return trackChanges ? createMemo ( createItem ) ( ) : untrack ( createItem )
269274 }
270275
271276 return {
272277 id,
273- virtualizer,
278+ get virtualizer ( ) {
279+ return virtualizer
280+ } ,
274281 get root ( ) {
275282 return rootProps ( )
276283 } ,
277284 get count ( ) {
278285 return count ( )
279286 } ,
280- get container ( ) {
287+ get container ( ) {
281288 return containerProps ( )
282289 } ,
283290 items : itemWrapper ,
284291 get item ( ) {
285- return virtualizer ( ) . getVirtualItems ( )
292+ return virtualizer . getVirtualItems ( )
286293 }
287- } ;
294+ }
288295}
289296
290- export default createVirtualizedList ;
297+ export default createVirtualizedList
0 commit comments