import { Virtualizer, elementScroll, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, windowScroll, } from '@tanstack/virtual-core' import { computed, onScopeDispose, shallowRef, triggerRef, unref, watch, } from 'vue' import type { PartialKeys, VirtualizerOptions } from '@tanstack/virtual-core' import type { Ref } from 'vue' export * from '@tanstack/virtual-core' type MaybeRef = T | Ref function useVirtualizerBase< TScrollElement extends Element | Window, TItemElement extends Element, >( options: MaybeRef>, ): Ref> { const virtualizer = new Virtualizer(unref(options)) const state = shallowRef(virtualizer) const cleanup = virtualizer._didMount() watch( () => unref(options).getScrollElement(), (el) => { if (el) { virtualizer._willUpdate() } }, { immediate: true, }, ) watch( () => unref(options), (options) => { virtualizer.setOptions({ ...options, onChange: (instance, sync) => { triggerRef(state) options.onChange?.(instance, sync) }, }) virtualizer._willUpdate() triggerRef(state) }, { immediate: true, }, ) onScopeDispose(cleanup) return state } export function useVirtualizer< TScrollElement extends Element, TItemElement extends Element, >( options: MaybeRef< PartialKeys< VirtualizerOptions, 'observeElementRect' | 'observeElementOffset' | 'scrollToFn' > >, ): Ref> { return useVirtualizerBase( computed(() => ({ observeElementRect: observeElementRect, observeElementOffset: observeElementOffset, scrollToFn: elementScroll, ...unref(options), })), ) } export function useWindowVirtualizer( options: MaybeRef< PartialKeys< VirtualizerOptions, | 'observeElementRect' | 'observeElementOffset' | 'scrollToFn' | 'getScrollElement' > >, ): Ref> { return useVirtualizerBase( computed(() => ({ getScrollElement: () => (typeof document !== 'undefined' ? window : null), observeElementRect: observeWindowRect, observeElementOffset: observeWindowOffset, scrollToFn: windowScroll, initialOffset: () => typeof document !== 'undefined' ? window.scrollY : 0, ...unref(options), })), ) }