UNPKG

@tanstack/angular-virtual

Version:

Headless UI for virtualizing scrollable elements in Angular

77 lines 12.5 kB
import { AfterRenderPhase, DestroyRef, afterNextRender, computed, effect, inject, signal, untracked, } from '@angular/core'; import { Virtualizer, elementScroll, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, windowScroll, } from '@tanstack/virtual-core'; import { proxyVirtualizer } from './proxy'; export * from '@tanstack/virtual-core'; export * from './types'; function createVirtualizerBase(options) { let virtualizer; function lazyInit() { virtualizer ??= new Virtualizer(options()); return virtualizer; } const virtualizerSignal = signal(virtualizer, { equal: () => false }); // two-way sync options effect(() => { const _options = options(); lazyInit(); virtualizerSignal.set(virtualizer); virtualizer.setOptions({ ..._options, onChange: (instance, sync) => { // update virtualizerSignal so that dependent computeds recompute. virtualizerSignal.set(instance); _options.onChange?.(instance, sync); }, }); // update virtualizerSignal so that dependent computeds recompute. virtualizerSignal.set(virtualizer); }, { allowSignalWrites: true }); const scrollElement = computed(() => options().getScrollElement()); // let the virtualizer know when the scroll element is changed effect(() => { const el = scrollElement(); if (el) { untracked(virtualizerSignal)._willUpdate(); } }, { allowSignalWrites: true }); let cleanup; afterNextRender(() => (virtualizer ?? lazyInit())._didMount(), { phase: AfterRenderPhase.Read, }); inject(DestroyRef).onDestroy(() => cleanup?.()); return proxyVirtualizer(virtualizerSignal, lazyInit); } export function injectVirtualizer(options) { const resolvedOptions = computed(() => { return { observeElementRect: observeElementRect, observeElementOffset: observeElementOffset, scrollToFn: elementScroll, getScrollElement: () => { const elementOrRef = options().scrollElement; return ((isElementRef(elementOrRef) ? elementOrRef.nativeElement : elementOrRef) ?? null); }, ...options(), }; }); return createVirtualizerBase(resolvedOptions); } function isElementRef(elementOrRef) { return elementOrRef != null && 'nativeElement' in elementOrRef; } export function injectWindowVirtualizer(options) { const resolvedOptions = computed(() => { return { getScrollElement: () => (typeof document !== 'undefined' ? window : null), observeElementRect: observeWindowRect, observeElementOffset: observeWindowOffset, scrollToFn: windowScroll, initialOffset: () => typeof document !== 'undefined' ? window.scrollY : 0, ...options(), }; }); return createVirtualizerBase(resolvedOptions); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixVQUFVLEVBQ1YsZUFBZSxFQUNmLFFBQVEsRUFDUixNQUFNLEVBQ04sTUFBTSxFQUNOLE1BQU0sRUFDTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUE7QUFDdEIsT0FBTyxFQUNMLFdBQVcsRUFDWCxhQUFhLEVBQ2Isb0JBQW9CLEVBQ3BCLGtCQUFrQixFQUNsQixtQkFBbUIsRUFDbkIsaUJBQWlCLEVBQ2pCLFlBQVksR0FDYixNQUFNLHdCQUF3QixDQUFBO0FBQy9CLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLFNBQVMsQ0FBQTtBQUsxQyxjQUFjLHdCQUF3QixDQUFBO0FBQ3RDLGNBQWMsU0FBUyxDQUFBO0FBRXZCLFNBQVMscUJBQXFCLENBSTVCLE9BQWlFO0lBRWpFLElBQUksV0FBc0QsQ0FBQTtJQUMxRCxTQUFTLFFBQVE7UUFDZixXQUFXLEtBQUssSUFBSSxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQTtRQUMxQyxPQUFPLFdBQVcsQ0FBQTtJQUNwQixDQUFDO0lBRUQsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLENBQUMsV0FBWSxFQUFFLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUE7SUFFdEUsdUJBQXVCO0lBQ3ZCLE1BQU0sQ0FDSixHQUFHLEVBQUU7UUFDSCxNQUFNLFFBQVEsR0FBRyxPQUFPLEVBQUUsQ0FBQTtRQUMxQixRQUFRLEVBQUUsQ0FBQTtRQUNWLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQTtRQUNsQyxXQUFXLENBQUMsVUFBVSxDQUFDO1lBQ3JCLEdBQUcsUUFBUTtZQUNYLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRSxJQUFJLEVBQUUsRUFBRTtnQkFDM0Isa0VBQWtFO2dC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LENBQUE7QUFDckUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyUmVuZGVyUGhhc2UsXG4gIERlc3Ryb3lSZWYsXG4gIGFmdGVyTmV4dFJlbmRlcixcbiAgY29tcHV0ZWQsXG4gIGVmZmVjdCxcbiAgaW5qZWN0LFxuICBzaWduYWwsXG4gIHVudHJhY2tlZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSdcbmltcG9ydCB7XG4gIFZpcnR1YWxpemVyLFxuICBlbGVtZW50U2Nyb2xsLFxuICBvYnNlcnZlRWxlbWVudE9mZnNldCxcbiAgb2JzZXJ2ZUVsZW1lbnRSZWN0LFxuICBvYnNlcnZlV2luZG93T2Zmc2V0LFxuICBvYnNlcnZlV2luZG93UmVjdCxcbiAgd2luZG93U2Nyb2xsLFxufSBmcm9tICdAdGFuc3RhY2svdmlydHVhbC1jb3JlJ1xuaW1wb3J0IHsgcHJveHlWaXJ0dWFsaXplciB9IGZyb20gJy4vcHJveHknXG5pbXBvcnQgdHlwZSB7IEVsZW1lbnRSZWYsIFNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnXG5pbXBvcnQgdHlwZSB7IFBhcnRpYWxLZXlzLCBWaXJ0dWFsaXplck9wdGlvbnMgfSBmcm9tICdAdGFuc3RhY2svdmlydHVhbC1jb3JlJ1xuaW1wb3J0IHR5cGUgeyBBbmd1bGFyVmlydHVhbGl6ZXIgfSBmcm9tICcuL3R5cGVzJ1xuXG5leHBvcnQgKiBmcm9tICdAdGFuc3RhY2svdmlydHVhbC1jb3JlJ1xuZXhwb3J0ICogZnJvbSAnLi90eXBlcydcblxuZnVuY3Rpb24gY3JlYXRlVmlydHVhbGl6ZXJCYXNlPFxuICBUU2Nyb2xsRWxlbWVudCBleHRlbmRzIEVsZW1lbnQgfCBXaW5kb3csXG4gIFRJdGVtRWxlbWVudCBleHRlbmRzIEVsZW1lbnQsXG4+KFxuICBvcHRpb25zOiBTaWduYWw8VmlydHVhbGl6ZXJPcHRpb25zPFRTY3JvbGxFbGVtZW50LCBUSXRlbUVsZW1lbnQ+Pixcbik6IEFuZ3VsYXJWaXJ0dWFsaXplcjxUU2Nyb2xsRWxlbWVudCwgVEl0ZW1FbGVtZW50PiB7XG4gIGxldCB2aXJ0dWFsaXplcjogVmlydHVhbGl6ZXI8VFNjcm9sbEVsZW1lbnQsIFRJdGVtRWxlbWVudD5cbiAgZnVuY3Rpb24gbGF6eUluaXQoKSB7XG4gICAgdmlydHVhbGl6ZXIgPz89IG5ldyBWaXJ0dWFsaXplcihvcHRpb25zKCkpXG4gICAgcmV0dXJuIHZpcnR1YWxpemVyXG4gIH1cblxuICBjb25zdCB2aXJ0dWFsaXplclNpZ25hbCA9IHNpZ25hbCh2aXJ0dWFsaXplciEsIHsgZXF1YWw6ICgpID0+IGZhbHNlIH0pXG5cbiAgLy8gdHdvLXdheSBzeW5jIG9wdGlvbnNcbiAgZWZmZWN0KFxuICAgICgpID0+IHtcbiAgICAgIGNvbnN0IF9vcHRpb25zID0gb3B0aW9ucygpXG4gICAgICBsYXp5SW5pdCgpXG4gICAgICB2aXJ0dWFsaXplclNpZ25hbC5zZXQodmlydHVhbGl6ZXIpXG4gICAgICB2aXJ0dWFsaXplci5zZXRPcHRpb25zKHtcbiAgICAgICAgLi4uX29wdGlvbnMsXG4gICAgICAgIG9uQ2hhbmdlOiAoaW5zdGFuY2UsIHN5bmMpID0+IHtcbiAgICAgICAgICAvLyB1cGRhdGUgdmlydHVhbGl6ZXJTaWduYWwgc28gdGhhdCBkZXBlbmRlbnQgY29tcHV0ZWRzIHJlY29tcHV0ZS5cbiAgICAgICAgICB2aXJ0dWFsaXplclNpZ25hbC5zZXQoaW5zdGFuY2UpXG4gICAgICAgICAgX29wdGlvbnMub25DaGFuZ2U/LihpbnN0YW5jZSwgc3luYylcbiAgICAgICAgfSxcbiAgICAgIH0pXG4gICAgICAvLyB1cGRhdGUgdmlydHVhbGl6ZXJTaWduYWwgc28gdGhhdCBkZXBlbmRlbnQgY29tcHV0ZWRzIHJlY29tcHV0ZS5cbiAgICAgIHZpcnR1YWxpemVyU2lnbmFsLnNldCh2aXJ0dWFsaXplcilcbiAgICB9LFxuICAgIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfSxcbiAgKVxuXG4gIGNvbnN0IHNjcm9sbEVsZW1lbnQgPSBjb21wdXRlZCgoKSA9PiBvcHRpb25zKCkuZ2V0U2Nyb2xsRWxlbWVudCgpKVxuICAvLyBsZXQgdGhlIHZpcnR1YWxpemVyIGtub3cgd2hlbiB0aGUgc2Nyb2xsIGVsZW1lbnQgaXMgY2hhbmdlZFxuICBlZmZlY3QoXG4gICAgKCkgPT4ge1xuICAgICAgY29uc3QgZWwgPSBzY3JvbGxFbGVtZW50KClcbiAgICAgIGlmIChlbCkge1xuICAgICAgICB1bnRyYWNrZWQodmlydHVhbGl6ZXJTaWduYWwpLl93aWxsVXBkYXRlKClcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfSxcbiAgKVxuXG4gIGxldCBjbGVhbnVwOiAoKSA9PiB2b2lkIHwgdW5kZWZpbmVkXG4gIGFmdGVyTmV4dFJlbmRlcigoKSA9PiAodmlydHVhbGl6ZXIgPz8gbGF6eUluaXQoKSkuX2RpZE1vdW50KCksIHtcbiAgICBwaGFzZTogQWZ0ZXJSZW5kZXJQaGFzZS5SZWFkLFxuICB9KVxuXG4gIGluamVjdChEZXN0cm95UmVmKS5vbkRlc3Ryb3koKCkgPT4gY2xlYW51cD8uKCkpXG5cbiAgcmV0dXJuIHByb3h5VmlydHVhbGl6ZXIodmlydHVhbGl6ZXJTaWduYWwsIGxhenlJbml0KVxufVxuXG5leHBvcnQgZnVuY3Rpb24gaW5qZWN0VmlydHVhbGl6ZXI8XG4gIFRTY3JvbGxFbGVtZW50IGV4dGVuZHMgRWxlbWVudCxcbiAgVEl0ZW1FbGVtZW50IGV4dGVuZHMgRWxlbWVudCxcbj4oXG4gIG9wdGlvbnM6ICgpID0+IFBhcnRpYWxLZXlzPFxuICAgIE9taXQ8VmlydHVhbGl6ZXJPcHRpb25zPFRTY3JvbGxFbGVtZW50LCBUSXRlbUVsZW1lbnQ+LCAnZ2V0U2Nyb2xsRWxlbWVudCc+LFxuICAgICdvYnNlcnZlRWxlbWVudFJlY3QnIHwgJ29ic2VydmVFbGVtZW50T2Zmc2V0JyB8ICdzY3JvbGxUb0ZuJ1xuICA+ICYge1xuICAgIHNjcm9sbEVsZW1lbnQ6IEVsZW1lbnRSZWY8VFNjcm9sbEVsZW1lbnQ+IHwgVFNjcm9sbEVsZW1lbnQgfCB1bmRlZmluZWRcbiAgfSxcbik6IEFuZ3VsYXJWaXJ0dWFsaXplcjxUU2Nyb2xsRWxlbWVudCwgVEl0ZW1FbGVtZW50PiB7XG4gIGNvbnN0IHJlc29sdmVkT3B0aW9ucyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICByZXR1cm4ge1xuICAgICAgb2JzZXJ2ZUVsZW1lbnRSZWN0OiBvYnNlcnZlRWxlbWVudFJlY3QsXG4gICAgICBvYnNlcnZlRWxlbWVudE9mZnNldDogb2JzZXJ2ZUVsZW1lbnRPZmZzZXQsXG4gICAgICBzY3JvbGxUb0ZuOiBlbGVtZW50U2Nyb2xsLFxuICAgICAgZ2V0U2Nyb2xsRWxlbWVudDogKCkgPT4ge1xuICAgICAgICBjb25zdCBlbGVtZW50T3JSZWYgPSBvcHRpb25zKCkuc2Nyb2xsRWxlbWVudFxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIChpc0VsZW1lbnRSZWYoZWxlbWVudE9yUmVmKVxuICAgICAgICAgICAgPyBlbGVtZW50T3JSZWYubmF0aXZlRWxlbWVudFxuICAgICAgICAgICAgOiBlbGVtZW50T3JSZWYpID8/IG51bGxcbiAgICAgICAgKVxuICAgICAgfSxcbiAgICAgIC4uLm9wdGlvbnMoKSxcbiAgICB9XG4gIH0pXG4gIHJldHVybiBjcmVhdGVWaXJ0dWFsaXplckJhc2U8VFNjcm9sbEVsZW1lbnQsIFRJdGVtRWxlbWVudD4ocmVzb2x2ZWRPcHRpb25zKVxufVxuXG5mdW5jdGlvbiBpc0VsZW1lbnRSZWY8VCBleHRlbmRzIEVsZW1lbnQ+KFxuICBlbGVtZW50T3JSZWY6IEVsZW1lbnRSZWY8VD4gfCBUIHwgdW5kZWZpbmVkLFxuKTogZWxlbWVudE9yUmVmIGlzIEVsZW1lbnRSZWY8VD4ge1xuICByZXR1cm4gZWxlbWVudE9yUmVmICE9IG51bGwgJiYgJ25hdGl2ZUVsZW1lbnQnIGluIGVsZW1lbnRPclJlZlxufVxuXG5leHBvcnQgZnVuY3Rpb24gaW5qZWN0V2luZG93VmlydHVhbGl6ZXI8VEl0ZW1FbGVtZW50IGV4dGVuZHMgRWxlbWVudD4oXG4gIG9wdGlvbnM6ICgpID0+IFBhcnRpYWxLZXlzPFxuICAgIFZpcnR1YWxpemVyT3B0aW9uczxXaW5kb3csIFRJdGVtRWxlbWVudD4sXG4gICAgfCAnZ2V0U2Nyb2xsRWxlbWVudCdcbiAgICB8ICdvYnNlcnZlRWxlbWVudFJlY3QnXG4gICAgfCAnb2JzZXJ2ZUVsZW1lbnRPZmZzZXQnXG4gICAgfCAnc2Nyb2xsVG9GbidcbiAgPixcbik6IEFuZ3VsYXJWaXJ0dWFsaXplcjxXaW5kb3csIFRJdGVtRWxlbWVudD4ge1xuICBjb25zdCByZXNvbHZlZE9wdGlvbnMgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGdldFNjcm9sbEVsZW1lbnQ6ICgpID0+ICh0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnID8gd2luZG93IDogbnVsbCksXG4gICAgICBvYnNlcnZlRWxlbWVudFJlY3Q6IG9ic2VydmVXaW5kb3dSZWN0LFxuICAgICAgb2JzZXJ2ZUVsZW1lbnRPZmZzZXQ6IG9ic2VydmVXaW5kb3dPZmZzZXQsXG4gICAgICBzY3JvbGxUb0ZuOiB3aW5kb3dTY3JvbGwsXG4gICAgICBpbml0aWFsT2Zmc2V0OiAoKSA9PlxuICAgICAgICB0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnID8gd2luZG93LnNjcm9sbFkgOiAwLFxuICAgICAgLi4ub3B0aW9ucygpLFxuICAgIH1cbiAgfSlcbiAgcmV0dXJuIGNyZWF0ZVZpcnR1YWxpemVyQmFzZTxXaW5kb3csIFRJdGVtRWxlbWVudD4ocmVzb2x2ZWRPcHRpb25zKVxufVxuIl19