@tanstack/angular-virtual
Version:
Headless UI for virtualizing scrollable elements in Angular
91 lines • 11.7 kB
JavaScript
import { computed, untracked } from '@angular/core';
export function proxyVirtualizer(virtualizerSignal, lazyInit) {
return new Proxy(virtualizerSignal, {
apply() {
return virtualizerSignal();
},
get(target, property) {
const untypedTarget = target;
if (untypedTarget[property]) {
return untypedTarget[property];
}
let virtualizer = untracked(virtualizerSignal);
if (virtualizer == null) {
virtualizer = lazyInit();
untracked(() => virtualizerSignal.set(virtualizer));
}
// Create computed signals for each property that represents a reactive value
if (typeof property === 'string' &&
[
'getTotalSize',
'getVirtualItems',
'isScrolling',
'options',
'range',
'scrollDirection',
'scrollElement',
'scrollOffset',
'scrollRect',
'measureElementCache',
'measurementsCache',
].includes(property)) {
const isFunction = typeof virtualizer[property] === 'function';
Object.defineProperty(untypedTarget, property, {
value: isFunction
? computed(() => target()[property]())
: computed(() => target()[property]),
configurable: true,
enumerable: true,
});
}
// Create plain signals for functions that accept arguments and return reactive values
if (typeof property === 'string' &&
[
'getOffsetForAlignment',
'getOffsetForIndex',
'getVirtualItemForOffset',
'indexFromElement',
].includes(property)) {
const fn = virtualizer[property];
Object.defineProperty(untypedTarget, property, {
value: toComputed(virtualizerSignal, fn),
configurable: true,
enumerable: true,
});
}
return untypedTarget[property] || virtualizer[property];
},
has(_, property) {
return !!untracked(virtualizerSignal)[property];
},
ownKeys() {
return Reflect.ownKeys(untracked(virtualizerSignal));
},
getOwnPropertyDescriptor() {
return {
enumerable: true,
configurable: true,
};
},
});
}
function toComputed(signal, fn) {
const computedCache = {};
return (...args) => {
// Cache computeds by their arguments to avoid re-creating the computed on each call
const serializedArgs = serializeArgs(...args);
if (computedCache.hasOwnProperty(serializedArgs)) {
return computedCache[serializedArgs]?.();
}
const computedSignal = computed(() => {
void signal();
return fn(...args);
});
computedCache[serializedArgs] = computedSignal;
return computedSignal();
};
}
function serializeArgs(...args) {
return JSON.stringify(args);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFLbkQsTUFBTSxVQUFVLGdCQUFnQixDQUs5QixpQkFBb0MsRUFDcEMsUUFBaUI7SUFFakIsT0FBTyxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsRUFBRTtRQUNsQyxLQUFLO1lBQ0gsT0FBTyxpQkFBaUIsRUFBRSxDQUFBO1FBQzVCLENBQUM7UUFDRCxHQUFHLENBQUMsTUFBTSxFQUFFLFFBQVE7WUFDbEIsTUFBTSxhQUFhLEdBQUcsTUFBYSxDQUFBO1lBQ25DLElBQUksYUFBYSxDQUFDLFFBQVEsQ0FBQyxFQUFFO2dCQUMzQixPQUFPLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQTthQUMvQjtZQUNELElBQUksV0FBVyxHQUFHLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFBO1lBQzlDLElBQUksV0FBVyxJQUFJLElBQUksRUFBRTtnQkFDdkIsV0FBVyxHQUFHLFFBQVEsRUFBRSxDQUFBO2dCQUN4QixTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUE7YUFDcEQ7WUFFRCw2RUFBNkU7WUFDN0UsSUFDRSxPQUFPLFFBQVEsS0FBSyxRQUFRO2dCQUM1QjtvQkFDRSxjQUFjO29CQUNkLGlCQUFpQjtvQkFDakIsYUFBYTtvQkFDYixTQUFTO29CQUNULE9BQU87b0JBQ1AsaUJBQWlCO29CQUNqQixlQUFlO29CQUNmLGNBQWM7b0JBQ2QsWUFBWTtvQkFDWixxQkFBcUI7b0JBQ3JCLG1CQUFtQjtpQkFDcEIsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQ3BCO2dCQUNBLE1BQU0sVUFBVSxHQUNkLE9BQU8sV0FBVyxDQUFDLFFBQW1CLENBQUMsS0FBSyxVQUFVLENBQUE7Z0JBQ3hELE1BQU0sQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFLFFBQVEsRUFBRTtvQkFDN0MsS0FBSyxFQUFFLFVBQVU7d0JBQ2YsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBRSxNQUFNLEVBQUUsQ0FBQyxRQUFtQixDQUFjLEVBQUUsQ0FBQzt3QkFDL0QsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFtQixDQUFDLENBQUM7b0JBQ2pELFlBQVksRUFBRSxJQUFJO29CQUNsQixVQUFVLEVBQUUsSUFBSTtpQkFDakIsQ0FBQyxDQUFBO2FBQ0g7WUFFRCxzRkFBc0Y7WUFDdEYsSUFDRSxPQUFPLFFBQVEsS0FBSyxRQUFRO2dCQUM1QjtvQkFDRSx1QkFBdUI7b0JBQ3ZCLG1CQUFtQjtvQkFDbkIseUJBQXlCO29CQUN6QixrQkFBa0I7aUJBQ25CLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxFQUNwQjtnQkFDQSxNQUFNLEVBQUUsR0FBRyxXQUFXLENBQUMsUUFBbUIsQ0FBYSxDQUFBO2dCQUN2RCxNQUFNLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRSxRQUFRLEVBQUU7b0JBQzdDLEtBQUssRUFBRSxVQUFVLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDO29CQUN4QyxZQUFZLEVBQUUsSUFBSTtvQkFDbEIsVUFBVSxFQUFFLElBQUk7aUJBQ2pCLENBQUMsQ0FBQTthQUNIO1lBRUQsT0FBTyxhQUFhLENBQUMsUUFBUSxDQUFDLElBQUksV0FBVyxDQUFDLFFBQW1CLENBQUMsQ0FBQTtRQUNwRSxDQUFDO1FBQ0QsR0FBRyxDQUFDLENBQUMsRUFBRSxRQUFnQjtZQUNyQixPQUFPLENBQUMsQ0FBQyxTQUFTLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxRQUFtQixDQUFDLENBQUE7UUFDNUQsQ0FBQztRQUNELE9BQU87WUFDTCxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQTtRQUN0RCxDQUFDO1FBQ0Qsd0JBQXdCO1lBQ3RCLE9BQU87Z0JBQ0wsVUFBVSxFQUFFLElBQUk7Z0JBQ2hCLFlBQVksRUFBRSxJQUFJO2FBQ25CLENBQUE7UUFDSCxDQUFDO0tBQ0YsQ0FBd0MsQ0FBQTtBQUMzQyxDQUFDO0FBRUQsU0FBUyxVQUFVLENBQ2pCLE1BQWlCLEVBQ2pCLEVBQVk7SUFFWixNQUFNLGFBQWEsR0FBb0MsRUFBRSxDQUFBO0lBRXpELE9BQU8sQ0FBQyxHQUFHLElBQWdCLEVBQUUsRUFBRTtRQUM3QixvRkFBb0Y7UUFDcEYsTUFBTSxjQUFjLEdBQUcsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUE7UUFDN0MsSUFBSSxhQUFhLENBQUMsY0FBYyxDQUFDLGNBQWMsQ0FBQyxFQUFFO1lBQ2hELE9BQU8sYUFBYSxDQUFDLGNBQWMsQ0FBQyxFQUFFLEVBQUUsQ0FBQTtTQUN6QztRQUNELE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUU7WUFDbkMsS0FBSyxNQUFNLEVBQUUsQ0FBQTtZQUNiLE9BQU8sRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUE7UUFDcEIsQ0FBQyxDQUFDLENBQUE7UUFFRixhQUFhLENBQUMsY0FBYyxDQUFDLEdBQUcsY0FBYyxDQUFBO1FBRTlDLE9BQU8sY0FBYyxFQUFFLENBQUE7SUFDekIsQ0FBQyxDQUFBO0FBQ0gsQ0FBQztBQUVELFNBQVMsYUFBYSxDQUFDLEdBQUcsSUFBZ0I7SUFDeEMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFBO0FBQzdCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjb21wdXRlZCwgdW50cmFja2VkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSdcbmltcG9ydCB0eXBlIHsgU2lnbmFsLCBXcml0YWJsZVNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnXG5pbXBvcnQgdHlwZSB7IFZpcnR1YWxpemVyIH0gZnJvbSAnQHRhbnN0YWNrL3ZpcnR1YWwtY29yZSdcbmltcG9ydCB0eXBlIHsgQW5ndWxhclZpcnR1YWxpemVyIH0gZnJvbSAnLi90eXBlcydcblxuZXhwb3J0IGZ1bmN0aW9uIHByb3h5VmlydHVhbGl6ZXI8XG4gIFYgZXh0ZW5kcyBWaXJ0dWFsaXplcjxhbnksIGFueT4sXG4gIFMgZXh0ZW5kcyBFbGVtZW50IHwgV2luZG93ID0gViBleHRlbmRzIFZpcnR1YWxpemVyPGluZmVyIFUsIGFueT4gPyBVIDogbmV2ZXIsXG4gIEkgZXh0ZW5kcyBFbGVtZW50ID0gViBleHRlbmRzIFZpcnR1YWxpemVyPGFueSwgaW5mZXIgVT4gPyBVIDogbmV2ZXIsXG4+KFxuICB2aXJ0dWFsaXplclNpZ25hbDogV3JpdGFibGVTaWduYWw8Vj4sXG4gIGxhenlJbml0OiAoKSA9PiBWLFxuKTogQW5ndWxhclZpcnR1YWxpemVyPFMsIEk+IHtcbiAgcmV0dXJuIG5ldyBQcm94eSh2aXJ0dWFsaXplclNpZ25hbCwge1xuICAgIGFwcGx5KCkge1xuICAgICAgcmV0dXJuIHZpcnR1YWxpemVyU2lnbmFsKClcbiAgICB9LFxuICAgIGdldCh0YXJnZXQsIHByb3BlcnR5KSB7XG4gICAgICBjb25zdCB1bnR5cGVkVGFyZ2V0ID0gdGFyZ2V0IGFzIGFueVxuICAgICAgaWYgKHVudHlwZWRUYXJnZXRbcHJvcGVydHldKSB7XG4gICAgICAgIHJldHVybiB1bnR5cGVkVGFyZ2V0W3Byb3BlcnR5XVxuICAgICAgfVxuICAgICAgbGV0IHZpcnR1YWxpemVyID0gdW50cmFja2VkKHZpcnR1YWxpemVyU2lnbmFsKVxuICAgICAgaWYgKHZpcnR1YWxpemVyID09IG51bGwpIHtcbiAgICAgICAgdmlydHVhbGl6ZXIgPSBsYXp5SW5pdCgpXG4gICAgICAgIHVudHJhY2tlZCgoKSA9PiB2aXJ0dWFsaXplclNpZ25hbC5zZXQodmlydHVhbGl6ZXIpKVxuICAgICAgfVxuXG4gICAgICAvLyBDcmVhdGUgY29tcHV0ZWQgc2lnbmFscyBmb3IgZWFjaCBwcm9wZXJ0eSB0aGF0IHJlcHJlc2VudHMgYSByZWFjdGl2ZSB2YWx1ZVxuICAgICAgaWYgKFxuICAgICAgICB0eXBlb2YgcHJvcGVydHkgPT09ICdzdHJpbmcnICYmXG4gICAgICAgIFtcbiAgICAgICAgICAnZ2V0VG90YWxTaXplJyxcbiAgICAgICAgICAnZ2V0VmlydHVhbEl0ZW1zJyxcbiAgICAgICAgICAnaXNTY3JvbGxpbmcnLFxuICAgICAgICAgICdvcHRpb25zJyxcbiAgICAgICAgICAncmFuZ2UnLFxuICAgICAgICAgICdzY3JvbGxEaXJlY3Rpb24nLFxuICAgICAgICAgICdzY3JvbGxFbGVtZW50JyxcbiAgICAgICAgICAnc2Nyb2xsT2Zmc2V0JyxcbiAgICAgICAgICAnc2Nyb2xsUmVjdCcsXG4gICAgICAgICAgJ21lYXN1cmVFbGVtZW50Q2FjaGUnLFxuICAgICAgICAgICdtZWFzdXJlbWVudHNDYWNoZScsXG4gICAgICAgIF0uaW5jbHVkZXMocHJvcGVydHkpXG4gICAgICApIHtcbiAgICAgICAgY29uc3QgaXNGdW5jdGlvbiA9XG4gICAgICAgICAgdHlwZW9mIHZpcnR1YWxpemVyW3Byb3BlcnR5IGFzIGtleW9mIFZdID09PSAnZnVuY3Rpb24nXG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh1bnR5cGVkVGFyZ2V0LCBwcm9wZXJ0eSwge1xuICAgICAgICAgIHZhbHVlOiBpc0Z1bmN0aW9uXG4gICAgICAgICAgICA/IGNvbXB1dGVkKCgpID0+ICh0YXJnZXQoKVtwcm9wZXJ0eSBhcyBrZXlvZiBWXSBhcyBGdW5jdGlvbikoKSlcbiAgICAgICAgICAgIDogY29tcHV0ZWQoKCkgPT4gdGFyZ2V0KClbcHJvcGVydHkgYXMga2V5b2YgVl0pLFxuICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICB9KVxuICAgICAgfVxuXG4gICAgICAvLyBDcmVhdGUgcGxhaW4gc2lnbmFscyBmb3IgZnVuY3Rpb25zIHRoYXQgYWNjZXB0IGFyZ3VtZW50cyBhbmQgcmV0dXJuIHJlYWN0aXZlIHZhbHVlc1xuICAgICAgaWYgKFxuICAgICAgICB0eXBlb2YgcHJvcGVydHkgPT09ICdzdHJpbmcnICYmXG4gICAgICAgIFtcbiAgICAgICAgICAnZ2V0T2Zmc2V0Rm9yQWxpZ25tZW50JyxcbiAgICAgICAgICAnZ2V0T2Zmc2V0Rm9ySW5kZXgnLFxuICAgICAgICAgICdnZXRWaXJ0dWFsSXRlbUZvck9mZnNldCcsXG4gICAgICAgICAgJ2luZGV4RnJvbUVsZW1lbnQnLFxuICAgICAgICBdLmluY2x1ZGVzKHByb3BlcnR5KVxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IGZuID0gdmlydHVhbGl6ZXJbcHJvcGVydHkgYXMga2V5b2YgVl0gYXMgRnVuY3Rpb25cbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHVudHlwZWRUYXJnZXQsIHByb3BlcnR5LCB7XG4gICAgICAgICAgdmFsdWU6IHRvQ29tcHV0ZWQodmlydHVhbGl6ZXJTaWduYWwsIGZuKSxcbiAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgfSlcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHVudHlwZWRUYXJnZXRbcHJvcGVydHldIHx8IHZpcnR1YWxpemVyW3Byb3BlcnR5IGFzIGtleW9mIFZdXG4gICAgfSxcbiAgICBoYXMoXywgcHJvcGVydHk6IHN0cmluZykge1xuICAgICAgcmV0dXJuICEhdW50cmFja2VkKHZpcnR1YWxpemVyU2lnbmFsKVtwcm9wZXJ0eSBhcyBrZXlvZiBWXVxuICAgIH0sXG4gICAgb3duS2V5cygpIHtcbiAgICAgIHJldHVybiBSZWZsZWN0Lm93bktleXModW50cmFja2VkKHZpcnR1YWxpemVyU2lnbmFsKSlcbiAgICB9LFxuICAgIGdldE93blByb3BlcnR5RGVzY3JpcHRvcigpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgIH1cbiAgICB9LFxuICB9KSBhcyB1bmtub3duIGFzIEFuZ3VsYXJWaXJ0dWFsaXplcjxTLCBJPlxufVxuXG5mdW5jdGlvbiB0b0NvbXB1dGVkPFYgZXh0ZW5kcyBWaXJ0dWFsaXplcjxhbnksIGFueT4+KFxuICBzaWduYWw6IFNpZ25hbDxWPixcbiAgZm46IEZ1bmN0aW9uLFxuKSB7XG4gIGNvbnN0IGNvbXB1dGVkQ2FjaGU6IFJlY29yZDxzdHJpbmcsIFNpZ25hbDx1bmtub3duPj4gPSB7fVxuXG4gIHJldHVybiAoLi4uYXJnczogQXJyYXk8YW55PikgPT4ge1xuICAgIC8vIENhY2hlIGNvbXB1dGVkcyBieSB0aGVpciBhcmd1bWVudHMgdG8gYXZvaWQgcmUtY3JlYXRpbmcgdGhlIGNvbXB1dGVkIG9uIGVhY2ggY2FsbFxuICAgIGNvbnN0IHNlcmlhbGl6ZWRBcmdzID0gc2VyaWFsaXplQXJncyguLi5hcmdzKVxuICAgIGlmIChjb21wdXRlZENhY2hlLmhhc093blByb3BlcnR5KHNlcmlhbGl6ZWRBcmdzKSkge1xuICAgICAgcmV0dXJuIGNvbXB1dGVkQ2FjaGVbc2VyaWFsaXplZEFyZ3NdPy4oKVxuICAgIH1cbiAgICBjb25zdCBjb21wdXRlZFNpZ25hbCA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICAgIHZvaWQgc2lnbmFsKClcbiAgICAgIHJldHVybiBmbiguLi5hcmdzKVxuICAgIH0pXG5cbiAgICBjb21wdXRlZENhY2hlW3NlcmlhbGl6ZWRBcmdzXSA9IGNvbXB1dGVkU2lnbmFsXG5cbiAgICByZXR1cm4gY29tcHV0ZWRTaWduYWwoKVxuICB9XG59XG5cbmZ1bmN0aW9uIHNlcmlhbGl6ZUFyZ3MoLi4uYXJnczogQXJyYXk8YW55Pikge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoYXJncylcbn1cbiJdfQ==