import { Virtualizer, elementScroll, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, windowScroll, } from '@tanstack/virtual-core' import { createComputed, createSignal, mergeProps, onCleanup, onMount, } from 'solid-js' import { createStore, reconcile } from 'solid-js/store' import type { PartialKeys, VirtualizerOptions } from '@tanstack/virtual-core' export * from '@tanstack/virtual-core' function createVirtualizerBase< TScrollElement extends Element | Window, TItemElement extends Element, >( options: VirtualizerOptions, ): Virtualizer { const resolvedOptions: VirtualizerOptions = mergeProps(options) const instance = new Virtualizer( resolvedOptions, ) const [virtualItems, setVirtualItems] = createStore( instance.getVirtualItems(), ) const [totalSize, setTotalSize] = createSignal(instance.getTotalSize()) const handler = { get( target: Virtualizer, prop: keyof Virtualizer, ) { switch (prop) { case 'getVirtualItems': return () => virtualItems case 'getTotalSize': return () => totalSize() default: return Reflect.get(target, prop) } }, } const virtualizer = new Proxy(instance, handler) virtualizer.setOptions(resolvedOptions) onMount(() => { const cleanup = virtualizer._didMount() virtualizer._willUpdate() onCleanup(cleanup) }) createComputed(() => { virtualizer.setOptions( mergeProps(resolvedOptions, options, { onChange: ( instance: Virtualizer, sync: boolean, ) => { instance._willUpdate() setVirtualItems( reconcile(instance.getVirtualItems(), { key: 'index', }), ) setTotalSize(instance.getTotalSize()) options.onChange?.(instance, sync) }, }), ) virtualizer.measure() }) return virtualizer } export function createVirtualizer< TScrollElement extends Element, TItemElement extends Element, >( options: PartialKeys< VirtualizerOptions, 'observeElementRect' | 'observeElementOffset' | 'scrollToFn' >, ): Virtualizer { return createVirtualizerBase( mergeProps( { observeElementRect: observeElementRect, observeElementOffset: observeElementOffset, scrollToFn: elementScroll, }, options, ), ) } export function createWindowVirtualizer( options: PartialKeys< VirtualizerOptions, | 'getScrollElement' | 'observeElementRect' | 'observeElementOffset' | 'scrollToFn' >, ): Virtualizer { return createVirtualizerBase( mergeProps( { getScrollElement: () => typeof document !== 'undefined' ? window : null, observeElementRect: observeWindowRect, observeElementOffset: observeWindowOffset, scrollToFn: windowScroll, initialOffset: () => typeof document !== 'undefined' ? window.scrollY : 0, }, options, ), ) }