@tanstack/angular-virtual
Version:
Headless UI for virtualizing scrollable elements in Angular
1 lines • 12.5 kB
Source Map (JSON)
{"version":3,"file":"tanstack-angular-virtual.mjs","sources":["../../src/proxy.ts","../../src/index.ts","../../src/tanstack-angular-virtual.ts"],"sourcesContent":["import { computed, untracked } from '@angular/core'\nimport type { Signal, WritableSignal } from '@angular/core'\nimport type { Virtualizer } from '@tanstack/virtual-core'\nimport type { AngularVirtualizer } from './types'\n\nexport function proxyVirtualizer<\n V extends Virtualizer<any, any>,\n S extends Element | Window = V extends Virtualizer<infer U, any> ? U : never,\n I extends Element = V extends Virtualizer<any, infer U> ? U : never,\n>(\n virtualizerSignal: WritableSignal<V>,\n lazyInit: () => V,\n): AngularVirtualizer<S, I> {\n return new Proxy(virtualizerSignal, {\n apply() {\n return virtualizerSignal()\n },\n get(target, property) {\n const untypedTarget = target as any\n if (untypedTarget[property]) {\n return untypedTarget[property]\n }\n let virtualizer = untracked(virtualizerSignal)\n if (virtualizer == null) {\n virtualizer = lazyInit()\n untracked(() => virtualizerSignal.set(virtualizer))\n }\n\n // Create computed signals for each property that represents a reactive value\n if (\n typeof property === 'string' &&\n [\n 'getTotalSize',\n 'getVirtualItems',\n 'isScrolling',\n 'options',\n 'range',\n 'scrollDirection',\n 'scrollElement',\n 'scrollOffset',\n 'scrollRect',\n 'measureElementCache',\n 'measurementsCache',\n ].includes(property)\n ) {\n const isFunction =\n typeof virtualizer[property as keyof V] === 'function'\n Object.defineProperty(untypedTarget, property, {\n value: isFunction\n ? computed(() => (target()[property as keyof V] as Function)())\n : computed(() => target()[property as keyof V]),\n configurable: true,\n enumerable: true,\n })\n }\n\n // Create plain signals for functions that accept arguments and return reactive values\n if (\n typeof property === 'string' &&\n [\n 'getOffsetForAlignment',\n 'getOffsetForIndex',\n 'getVirtualItemForOffset',\n 'indexFromElement',\n ].includes(property)\n ) {\n const fn = virtualizer[property as keyof V] as Function\n Object.defineProperty(untypedTarget, property, {\n value: toComputed(virtualizerSignal, fn),\n configurable: true,\n enumerable: true,\n })\n }\n\n return untypedTarget[property] || virtualizer[property as keyof V]\n },\n has(_, property: string) {\n return !!untracked(virtualizerSignal)[property as keyof V]\n },\n ownKeys() {\n return Reflect.ownKeys(untracked(virtualizerSignal))\n },\n getOwnPropertyDescriptor() {\n return {\n enumerable: true,\n configurable: true,\n }\n },\n }) as unknown as AngularVirtualizer<S, I>\n}\n\nfunction toComputed<V extends Virtualizer<any, any>>(\n signal: Signal<V>,\n fn: Function,\n) {\n const computedCache: Record<string, Signal<unknown>> = {}\n\n return (...args: Array<any>) => {\n // Cache computeds by their arguments to avoid re-creating the computed on each call\n const serializedArgs = serializeArgs(...args)\n if (computedCache.hasOwnProperty(serializedArgs)) {\n return computedCache[serializedArgs]?.()\n }\n const computedSignal = computed(() => {\n void signal()\n return fn(...args)\n })\n\n computedCache[serializedArgs] = computedSignal\n\n return computedSignal()\n }\n}\n\nfunction serializeArgs(...args: Array<any>) {\n return JSON.stringify(args)\n}\n","import {\n AfterRenderPhase,\n DestroyRef,\n afterNextRender,\n computed,\n effect,\n inject,\n signal,\n untracked,\n} from '@angular/core'\nimport {\n Virtualizer,\n elementScroll,\n observeElementOffset,\n observeElementRect,\n observeWindowOffset,\n observeWindowRect,\n windowScroll,\n} from '@tanstack/virtual-core'\nimport { proxyVirtualizer } from './proxy'\nimport type { ElementRef, Signal } from '@angular/core'\nimport type { PartialKeys, VirtualizerOptions } from '@tanstack/virtual-core'\nimport type { AngularVirtualizer } from './types'\n\nexport * from '@tanstack/virtual-core'\nexport * from './types'\n\nfunction createVirtualizerBase<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n>(\n options: Signal<VirtualizerOptions<TScrollElement, TItemElement>>,\n): AngularVirtualizer<TScrollElement, TItemElement> {\n let virtualizer: Virtualizer<TScrollElement, TItemElement>\n function lazyInit() {\n virtualizer ??= new Virtualizer(options())\n return virtualizer\n }\n\n const virtualizerSignal = signal(virtualizer!, { equal: () => false })\n\n // two-way sync options\n effect(\n () => {\n const _options = options()\n lazyInit()\n virtualizerSignal.set(virtualizer)\n virtualizer.setOptions({\n ..._options,\n onChange: (instance, sync) => {\n // update virtualizerSignal so that dependent computeds recompute.\n virtualizerSignal.set(instance)\n _options.onChange?.(instance, sync)\n },\n })\n // update virtualizerSignal so that dependent computeds recompute.\n virtualizerSignal.set(virtualizer)\n },\n { allowSignalWrites: true },\n )\n\n const scrollElement = computed(() => options().getScrollElement())\n // let the virtualizer know when the scroll element is changed\n effect(\n () => {\n const el = scrollElement()\n if (el) {\n untracked(virtualizerSignal)._willUpdate()\n }\n },\n { allowSignalWrites: true },\n )\n\n let cleanup: () => void | undefined\n afterNextRender(() => (virtualizer ?? lazyInit())._didMount(), {\n phase: AfterRenderPhase.Read,\n })\n\n inject(DestroyRef).onDestroy(() => cleanup?.())\n\n return proxyVirtualizer(virtualizerSignal, lazyInit)\n}\n\nexport function injectVirtualizer<\n TScrollElement extends Element,\n TItemElement extends Element,\n>(\n options: () => PartialKeys<\n Omit<VirtualizerOptions<TScrollElement, TItemElement>, 'getScrollElement'>,\n 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'\n > & {\n scrollElement: ElementRef<TScrollElement> | TScrollElement | undefined\n },\n): AngularVirtualizer<TScrollElement, TItemElement> {\n const resolvedOptions = computed(() => {\n return {\n observeElementRect: observeElementRect,\n observeElementOffset: observeElementOffset,\n scrollToFn: elementScroll,\n getScrollElement: () => {\n const elementOrRef = options().scrollElement\n return (\n (isElementRef(elementOrRef)\n ? elementOrRef.nativeElement\n : elementOrRef) ?? null\n )\n },\n ...options(),\n }\n })\n return createVirtualizerBase<TScrollElement, TItemElement>(resolvedOptions)\n}\n\nfunction isElementRef<T extends Element>(\n elementOrRef: ElementRef<T> | T | undefined,\n): elementOrRef is ElementRef<T> {\n return elementOrRef != null && 'nativeElement' in elementOrRef\n}\n\nexport function injectWindowVirtualizer<TItemElement extends Element>(\n options: () => PartialKeys<\n VirtualizerOptions<Window, TItemElement>,\n | 'getScrollElement'\n | 'observeElementRect'\n | 'observeElementOffset'\n | 'scrollToFn'\n >,\n): AngularVirtualizer<Window, TItemElement> {\n const resolvedOptions = computed(() => {\n return {\n getScrollElement: () => (typeof document !== 'undefined' ? window : null),\n observeElementRect: observeWindowRect,\n observeElementOffset: observeWindowOffset,\n scrollToFn: windowScroll,\n initialOffset: () =>\n typeof document !== 'undefined' ? window.scrollY : 0,\n ...options(),\n }\n })\n return createVirtualizerBase<Window, TItemElement>(resolvedOptions)\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}