lazy-render-virtual-scroll 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -288
- package/backend-helpers/README.md +233 -0
- package/backend-helpers/example.ts +114 -0
- package/backend-helpers/frontend-example.tsx +122 -0
- package/backend-helpers/pagination.ts +159 -0
- package/dist/adapters/react/index.d.ts +187 -1
- package/dist/cjs/adapters/react/LazyList.js +377 -0
- package/dist/cjs/adapters/react/LazyList.js.map +1 -1
- package/dist/cjs/adapters/react/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/cjs/adapters/react/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/cjs/adapters/react/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/cjs/adapters/react/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/components/index.d.ts +7 -0
- package/dist/cjs/adapters/react/adapters/react/components/index.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/hooks/index.d.ts +7 -0
- package/dist/cjs/adapters/react/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/cjs/adapters/react/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/cjs/adapters/react/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/cjs/adapters/react/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/index.d.ts +2 -0
- package/dist/cjs/adapters/react/adapters/react/index.d.ts.map +1 -1
- package/dist/cjs/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/cjs/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/cjs/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/cjs/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/cjs/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/cjs/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/cjs/adapters/react/components/index.d.ts +7 -0
- package/dist/cjs/adapters/react/components/index.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/cjs/adapters/react/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/cjs/adapters/react/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/Engine.d.ts +3 -0
- package/dist/cjs/adapters/react/core/Engine.d.ts.map +1 -1
- package/dist/cjs/adapters/react/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/cjs/adapters/react/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/IntelligentPagination.d.ts +113 -0
- package/dist/cjs/adapters/react/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/PreemptiveCache.d.ts +83 -0
- package/dist/cjs/adapters/react/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/cjs/adapters/react/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/RequestDeduplicator.d.ts +35 -0
- package/dist/cjs/adapters/react/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/cjs/adapters/react/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/VariableHeightManager.d.ts +84 -0
- package/dist/cjs/adapters/react/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/cjs/adapters/react/hooks/index.d.ts +7 -0
- package/dist/cjs/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/cjs/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/cjs/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/cjs/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/cjs/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/cjs/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/cjs/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/cjs/adapters/react/index.d.ts +9 -0
- package/dist/cjs/adapters/react/index.d.ts.map +1 -1
- package/dist/cjs/adapters/react/index.js +1738 -0
- package/dist/cjs/adapters/react/index.js.map +1 -1
- package/dist/cjs/adapters/react/useLazyList.js +377 -0
- package/dist/cjs/adapters/react/useLazyList.js.map +1 -1
- package/dist/cjs/angular/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/cjs/angular/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/cjs/angular/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/cjs/angular/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/components/index.d.ts +7 -0
- package/dist/cjs/angular/adapters/react/components/index.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/hooks/index.d.ts +7 -0
- package/dist/cjs/angular/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/cjs/angular/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/cjs/angular/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/cjs/angular/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/index.d.ts +2 -0
- package/dist/cjs/angular/adapters/react/index.d.ts.map +1 -1
- package/dist/cjs/angular/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/cjs/angular/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/cjs/angular/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/cjs/angular/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/cjs/angular/core/Engine.d.ts +3 -0
- package/dist/cjs/angular/core/Engine.d.ts.map +1 -1
- package/dist/cjs/angular/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/cjs/angular/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/cjs/angular/core/IntelligentPagination.d.ts +113 -0
- package/dist/cjs/angular/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/cjs/angular/core/PreemptiveCache.d.ts +83 -0
- package/dist/cjs/angular/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/cjs/angular/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/cjs/angular/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/cjs/angular/core/RequestDeduplicator.d.ts +35 -0
- package/dist/cjs/angular/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/cjs/angular/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/cjs/angular/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/cjs/angular/core/VariableHeightManager.d.ts +84 -0
- package/dist/cjs/angular/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/cjs/angular/index.d.ts +9 -0
- package/dist/cjs/angular/index.d.ts.map +1 -1
- package/dist/cjs/angular/index.js +377 -0
- package/dist/cjs/angular/index.js.map +1 -1
- package/dist/cjs/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/cjs/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/cjs/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/cjs/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/cjs/core/Engine.d.ts +3 -0
- package/dist/cjs/core/Engine.d.ts.map +1 -1
- package/dist/cjs/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/cjs/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/cjs/core/IntelligentPagination.d.ts +113 -0
- package/dist/cjs/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/cjs/core/PreemptiveCache.d.ts +83 -0
- package/dist/cjs/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/cjs/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/cjs/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/cjs/core/RequestDeduplicator.d.ts +35 -0
- package/dist/cjs/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/cjs/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/cjs/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/cjs/core/VariableHeightManager.d.ts +84 -0
- package/dist/cjs/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1545 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/svelte/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/cjs/svelte/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/cjs/svelte/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/cjs/svelte/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/components/index.d.ts +7 -0
- package/dist/cjs/svelte/adapters/react/components/index.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/hooks/index.d.ts +7 -0
- package/dist/cjs/svelte/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/cjs/svelte/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/cjs/svelte/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/cjs/svelte/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/index.d.ts +2 -0
- package/dist/cjs/svelte/adapters/react/index.d.ts.map +1 -1
- package/dist/cjs/svelte/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/cjs/svelte/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/cjs/svelte/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/cjs/svelte/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/cjs/svelte/core/Engine.d.ts +3 -0
- package/dist/cjs/svelte/core/Engine.d.ts.map +1 -1
- package/dist/cjs/svelte/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/cjs/svelte/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/cjs/svelte/core/IntelligentPagination.d.ts +113 -0
- package/dist/cjs/svelte/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/cjs/svelte/core/PreemptiveCache.d.ts +83 -0
- package/dist/cjs/svelte/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/cjs/svelte/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/cjs/svelte/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/cjs/svelte/core/RequestDeduplicator.d.ts +35 -0
- package/dist/cjs/svelte/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/cjs/svelte/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/cjs/svelte/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/cjs/svelte/core/VariableHeightManager.d.ts +84 -0
- package/dist/cjs/svelte/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/cjs/svelte/index.d.ts +9 -0
- package/dist/cjs/svelte/index.d.ts.map +1 -1
- package/dist/cjs/svelte/index.js +377 -0
- package/dist/cjs/svelte/index.js.map +1 -1
- package/dist/cjs/vue/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/cjs/vue/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/cjs/vue/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/cjs/vue/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/components/index.d.ts +7 -0
- package/dist/cjs/vue/adapters/react/components/index.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/hooks/index.d.ts +7 -0
- package/dist/cjs/vue/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/cjs/vue/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/cjs/vue/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/cjs/vue/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/index.d.ts +2 -0
- package/dist/cjs/vue/adapters/react/index.d.ts.map +1 -1
- package/dist/cjs/vue/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/cjs/vue/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/cjs/vue/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/cjs/vue/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/cjs/vue/core/Engine.d.ts +3 -0
- package/dist/cjs/vue/core/Engine.d.ts.map +1 -1
- package/dist/cjs/vue/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/cjs/vue/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/cjs/vue/core/IntelligentPagination.d.ts +113 -0
- package/dist/cjs/vue/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/cjs/vue/core/PreemptiveCache.d.ts +83 -0
- package/dist/cjs/vue/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/cjs/vue/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/cjs/vue/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/cjs/vue/core/RequestDeduplicator.d.ts +35 -0
- package/dist/cjs/vue/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/cjs/vue/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/cjs/vue/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/cjs/vue/core/VariableHeightManager.d.ts +84 -0
- package/dist/cjs/vue/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/cjs/vue/index.d.ts +9 -0
- package/dist/cjs/vue/index.d.ts.map +1 -1
- package/dist/cjs/vue/index.js +377 -0
- package/dist/cjs/vue/index.js.map +1 -1
- package/dist/esm/adapters/react/LazyList.js +377 -0
- package/dist/esm/adapters/react/LazyList.js.map +1 -1
- package/dist/esm/adapters/react/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/esm/adapters/react/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/esm/adapters/react/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/esm/adapters/react/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/components/index.d.ts +7 -0
- package/dist/esm/adapters/react/adapters/react/components/index.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/hooks/index.d.ts +7 -0
- package/dist/esm/adapters/react/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/esm/adapters/react/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/esm/adapters/react/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/esm/adapters/react/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/index.d.ts +2 -0
- package/dist/esm/adapters/react/adapters/react/index.d.ts.map +1 -1
- package/dist/esm/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/esm/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/esm/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/esm/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/esm/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/esm/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/esm/adapters/react/components/index.d.ts +7 -0
- package/dist/esm/adapters/react/components/index.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/esm/adapters/react/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/esm/adapters/react/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/Engine.d.ts +3 -0
- package/dist/esm/adapters/react/core/Engine.d.ts.map +1 -1
- package/dist/esm/adapters/react/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/esm/adapters/react/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/IntelligentPagination.d.ts +113 -0
- package/dist/esm/adapters/react/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/PreemptiveCache.d.ts +83 -0
- package/dist/esm/adapters/react/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/esm/adapters/react/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/RequestDeduplicator.d.ts +35 -0
- package/dist/esm/adapters/react/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/esm/adapters/react/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/VariableHeightManager.d.ts +84 -0
- package/dist/esm/adapters/react/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/esm/adapters/react/hooks/index.d.ts +7 -0
- package/dist/esm/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/esm/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/esm/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/esm/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/esm/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/esm/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/esm/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/esm/adapters/react/index.d.ts +9 -0
- package/dist/esm/adapters/react/index.d.ts.map +1 -1
- package/dist/esm/adapters/react/index.js +1733 -1
- package/dist/esm/adapters/react/index.js.map +1 -1
- package/dist/esm/adapters/react/useLazyList.js +377 -0
- package/dist/esm/adapters/react/useLazyList.js.map +1 -1
- package/dist/esm/angular/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/esm/angular/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/esm/angular/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/esm/angular/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/components/index.d.ts +7 -0
- package/dist/esm/angular/adapters/react/components/index.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/hooks/index.d.ts +7 -0
- package/dist/esm/angular/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/esm/angular/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/esm/angular/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/esm/angular/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/index.d.ts +2 -0
- package/dist/esm/angular/adapters/react/index.d.ts.map +1 -1
- package/dist/esm/angular/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/esm/angular/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/esm/angular/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/esm/angular/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/esm/angular/core/Engine.d.ts +3 -0
- package/dist/esm/angular/core/Engine.d.ts.map +1 -1
- package/dist/esm/angular/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/esm/angular/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/esm/angular/core/IntelligentPagination.d.ts +113 -0
- package/dist/esm/angular/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/esm/angular/core/PreemptiveCache.d.ts +83 -0
- package/dist/esm/angular/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/esm/angular/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/esm/angular/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/esm/angular/core/RequestDeduplicator.d.ts +35 -0
- package/dist/esm/angular/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/esm/angular/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/esm/angular/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/esm/angular/core/VariableHeightManager.d.ts +84 -0
- package/dist/esm/angular/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/esm/angular/index.d.ts +9 -0
- package/dist/esm/angular/index.d.ts.map +1 -1
- package/dist/esm/angular/index.js +377 -0
- package/dist/esm/angular/index.js.map +1 -1
- package/dist/esm/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/esm/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/esm/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/esm/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/esm/core/Engine.d.ts +3 -0
- package/dist/esm/core/Engine.d.ts.map +1 -1
- package/dist/esm/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/esm/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/esm/core/IntelligentPagination.d.ts +113 -0
- package/dist/esm/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/esm/core/PreemptiveCache.d.ts +83 -0
- package/dist/esm/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/esm/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/esm/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/esm/core/RequestDeduplicator.d.ts +35 -0
- package/dist/esm/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/esm/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/esm/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/esm/core/VariableHeightManager.d.ts +84 -0
- package/dist/esm/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1537 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/svelte/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/esm/svelte/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/esm/svelte/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/esm/svelte/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/components/index.d.ts +7 -0
- package/dist/esm/svelte/adapters/react/components/index.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/hooks/index.d.ts +7 -0
- package/dist/esm/svelte/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/esm/svelte/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/esm/svelte/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/esm/svelte/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/index.d.ts +2 -0
- package/dist/esm/svelte/adapters/react/index.d.ts.map +1 -1
- package/dist/esm/svelte/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/esm/svelte/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/esm/svelte/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/esm/svelte/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/esm/svelte/core/Engine.d.ts +3 -0
- package/dist/esm/svelte/core/Engine.d.ts.map +1 -1
- package/dist/esm/svelte/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/esm/svelte/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/esm/svelte/core/IntelligentPagination.d.ts +113 -0
- package/dist/esm/svelte/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/esm/svelte/core/PreemptiveCache.d.ts +83 -0
- package/dist/esm/svelte/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/esm/svelte/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/esm/svelte/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/esm/svelte/core/RequestDeduplicator.d.ts +35 -0
- package/dist/esm/svelte/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/esm/svelte/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/esm/svelte/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/esm/svelte/core/VariableHeightManager.d.ts +84 -0
- package/dist/esm/svelte/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/esm/svelte/index.d.ts +9 -0
- package/dist/esm/svelte/index.d.ts.map +1 -1
- package/dist/esm/svelte/index.js +377 -0
- package/dist/esm/svelte/index.js.map +1 -1
- package/dist/esm/vue/adapters/react/components/AdaptiveScrollView.d.ts +16 -0
- package/dist/esm/vue/adapters/react/components/AdaptiveScrollView.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/components/IntelligentLazyList.d.ts +16 -0
- package/dist/esm/vue/adapters/react/components/IntelligentLazyList.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/components/SmartInfiniteScroll.d.ts +15 -0
- package/dist/esm/vue/adapters/react/components/SmartInfiniteScroll.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/components/index.d.ts +7 -0
- package/dist/esm/vue/adapters/react/components/index.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/hooks/index.d.ts +7 -0
- package/dist/esm/vue/adapters/react/hooks/index.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/hooks/useAdaptiveLoading.d.ts +39 -0
- package/dist/esm/vue/adapters/react/hooks/useAdaptiveLoading.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/hooks/useIntelligentScroll.d.ts +37 -0
- package/dist/esm/vue/adapters/react/hooks/useIntelligentScroll.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/hooks/useSmartPagination.d.ts +57 -0
- package/dist/esm/vue/adapters/react/hooks/useSmartPagination.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/index.d.ts +2 -0
- package/dist/esm/vue/adapters/react/index.d.ts.map +1 -1
- package/dist/esm/vue/core/BatchSizeOptimizer.d.ts +84 -0
- package/dist/esm/vue/core/BatchSizeOptimizer.d.ts.map +1 -0
- package/dist/esm/vue/core/DynamicHeightEngine.d.ts +107 -0
- package/dist/esm/vue/core/DynamicHeightEngine.d.ts.map +1 -0
- package/dist/esm/vue/core/Engine.d.ts +3 -0
- package/dist/esm/vue/core/Engine.d.ts.map +1 -1
- package/dist/esm/vue/core/HeightMeasurementCache.d.ts +92 -0
- package/dist/esm/vue/core/HeightMeasurementCache.d.ts.map +1 -0
- package/dist/esm/vue/core/IntelligentPagination.d.ts +113 -0
- package/dist/esm/vue/core/IntelligentPagination.d.ts.map +1 -0
- package/dist/esm/vue/core/PreemptiveCache.d.ts +83 -0
- package/dist/esm/vue/core/PreemptiveCache.d.ts.map +1 -0
- package/dist/esm/vue/core/PriorityRequestQueue.d.ts +56 -0
- package/dist/esm/vue/core/PriorityRequestQueue.d.ts.map +1 -0
- package/dist/esm/vue/core/RequestDeduplicator.d.ts +35 -0
- package/dist/esm/vue/core/RequestDeduplicator.d.ts.map +1 -0
- package/dist/esm/vue/core/SmartPrefetchAlgorithm.d.ts +63 -0
- package/dist/esm/vue/core/SmartPrefetchAlgorithm.d.ts.map +1 -0
- package/dist/esm/vue/core/VariableHeightManager.d.ts +84 -0
- package/dist/esm/vue/core/VariableHeightManager.d.ts.map +1 -0
- package/dist/esm/vue/index.d.ts +9 -0
- package/dist/esm/vue/index.d.ts.map +1 -1
- package/dist/esm/vue/index.js +377 -0
- package/dist/esm/vue/index.js.map +1 -1
- package/dist/index.d.ts +681 -1
- package/package.json +7 -2
package/dist/cjs/index.js
CHANGED
|
@@ -1238,6 +1238,380 @@ class GPUAccelerator {
|
|
|
1238
1238
|
}
|
|
1239
1239
|
}
|
|
1240
1240
|
|
|
1241
|
+
/**
|
|
1242
|
+
* Batch Size Optimizer
|
|
1243
|
+
* Dynamically adjusts batch size based on scroll speed, network, and performance
|
|
1244
|
+
*/
|
|
1245
|
+
class BatchSizeOptimizer {
|
|
1246
|
+
constructor(config, networkDetector, performanceMonitor) {
|
|
1247
|
+
this.scrollSpeedHistory = [];
|
|
1248
|
+
this.renderTimeHistory = [];
|
|
1249
|
+
this.HISTORY_SIZE = 10;
|
|
1250
|
+
this.config = {
|
|
1251
|
+
minBatchSize: (config === null || config === void 0 ? void 0 : config.minBatchSize) || 10,
|
|
1252
|
+
maxBatchSize: (config === null || config === void 0 ? void 0 : config.maxBatchSize) || 100,
|
|
1253
|
+
baseBatchSize: (config === null || config === void 0 ? void 0 : config.baseBatchSize) || 50,
|
|
1254
|
+
scrollSpeedThreshold: (config === null || config === void 0 ? void 0 : config.scrollSpeedThreshold) || 1.0
|
|
1255
|
+
};
|
|
1256
|
+
this.currentBatchSize = this.config.baseBatchSize;
|
|
1257
|
+
this.networkDetector = networkDetector || new NetworkSpeedDetector();
|
|
1258
|
+
this.performanceMonitor = performanceMonitor || new DevicePerformanceMonitor();
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Calculate optimal batch size based on all factors
|
|
1262
|
+
*/
|
|
1263
|
+
async calculateOptimalBatchSize(scrollSpeed) {
|
|
1264
|
+
// Track scroll speed history
|
|
1265
|
+
this.trackScrollSpeed(scrollSpeed);
|
|
1266
|
+
// Get network quality
|
|
1267
|
+
const networkQuality = await this.networkDetector.assessConnectionQuality();
|
|
1268
|
+
// Get performance score
|
|
1269
|
+
const performanceScore = await this.performanceMonitor.assessPerformance();
|
|
1270
|
+
// Calculate batch size based on scroll speed
|
|
1271
|
+
const speedMultiplier = this.calculateSpeedMultiplier(scrollSpeed);
|
|
1272
|
+
// Calculate batch size based on network
|
|
1273
|
+
const networkMultiplier = this.calculateNetworkMultiplier(networkQuality);
|
|
1274
|
+
// Calculate batch size based on performance
|
|
1275
|
+
const performanceMultiplier = this.calculatePerformanceMultiplier(performanceScore);
|
|
1276
|
+
// Calculate final batch size
|
|
1277
|
+
const optimalBatchSize = Math.round(this.config.baseBatchSize * speedMultiplier * networkMultiplier * performanceMultiplier);
|
|
1278
|
+
// Apply min/max bounds
|
|
1279
|
+
this.currentBatchSize = Math.max(this.config.minBatchSize, Math.min(this.config.maxBatchSize, optimalBatchSize));
|
|
1280
|
+
return this.currentBatchSize;
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Calculate multiplier based on scroll speed
|
|
1284
|
+
*/
|
|
1285
|
+
calculateSpeedMultiplier(scrollSpeed) {
|
|
1286
|
+
const avgScrollSpeed = this.getAverageScrollSpeed();
|
|
1287
|
+
// Fast scrolling = larger batches (preload more)
|
|
1288
|
+
if (Math.abs(avgScrollSpeed) > this.config.scrollSpeedThreshold * 2) {
|
|
1289
|
+
return 1.5; // 50% more items
|
|
1290
|
+
}
|
|
1291
|
+
else if (Math.abs(avgScrollSpeed) > this.config.scrollSpeedThreshold) {
|
|
1292
|
+
return 1.2; // 20% more items
|
|
1293
|
+
}
|
|
1294
|
+
else if (Math.abs(avgScrollSpeed) < 0.3) {
|
|
1295
|
+
return 0.8; // 20% fewer items (user reading carefully)
|
|
1296
|
+
}
|
|
1297
|
+
return 1.0; // Normal batch size
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Calculate multiplier based on network quality
|
|
1301
|
+
*/
|
|
1302
|
+
calculateNetworkMultiplier(quality) {
|
|
1303
|
+
switch (quality) {
|
|
1304
|
+
case 'excellent':
|
|
1305
|
+
return 1.3; // Load more on fast network
|
|
1306
|
+
case 'good':
|
|
1307
|
+
return 1.1; // Slightly more
|
|
1308
|
+
case 'poor':
|
|
1309
|
+
return 0.6; // Load less on slow network
|
|
1310
|
+
case 'offline':
|
|
1311
|
+
return 0.3; // Minimal loading when offline
|
|
1312
|
+
default:
|
|
1313
|
+
return 1.0;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Calculate multiplier based on device performance
|
|
1318
|
+
*/
|
|
1319
|
+
calculatePerformanceMultiplier(score) {
|
|
1320
|
+
// score is 0-1 (0 = poor, 1 = excellent)
|
|
1321
|
+
if (score > 0.8) {
|
|
1322
|
+
return 1.2; // High-performance device
|
|
1323
|
+
}
|
|
1324
|
+
else if (score > 0.5) {
|
|
1325
|
+
return 1.0; // Average device
|
|
1326
|
+
}
|
|
1327
|
+
else {
|
|
1328
|
+
return 0.7; // Low-performance device
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
/**
|
|
1332
|
+
* Track scroll speed for averaging
|
|
1333
|
+
*/
|
|
1334
|
+
trackScrollSpeed(speed) {
|
|
1335
|
+
this.scrollSpeedHistory.push(speed);
|
|
1336
|
+
if (this.scrollSpeedHistory.length > this.HISTORY_SIZE) {
|
|
1337
|
+
this.scrollSpeedHistory.shift();
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Get average scroll speed
|
|
1342
|
+
*/
|
|
1343
|
+
getAverageScrollSpeed() {
|
|
1344
|
+
if (this.scrollSpeedHistory.length === 0)
|
|
1345
|
+
return 0;
|
|
1346
|
+
const sum = this.scrollSpeedHistory.reduce((a, b) => a + b, 0);
|
|
1347
|
+
return sum / this.scrollSpeedHistory.length;
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Track render time for performance monitoring
|
|
1351
|
+
*/
|
|
1352
|
+
trackRenderTime(renderTime) {
|
|
1353
|
+
this.renderTimeHistory.push(renderTime);
|
|
1354
|
+
if (this.renderTimeHistory.length > this.HISTORY_SIZE) {
|
|
1355
|
+
this.renderTimeHistory.shift();
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Get average render time
|
|
1360
|
+
*/
|
|
1361
|
+
getAverageRenderTime() {
|
|
1362
|
+
if (this.renderTimeHistory.length === 0)
|
|
1363
|
+
return 0;
|
|
1364
|
+
const sum = this.renderTimeHistory.reduce((a, b) => a + b, 0);
|
|
1365
|
+
return sum / this.renderTimeHistory.length;
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Get current batch metrics
|
|
1369
|
+
*/
|
|
1370
|
+
getMetrics() {
|
|
1371
|
+
return {
|
|
1372
|
+
currentBatchSize: this.currentBatchSize,
|
|
1373
|
+
scrollSpeed: this.getAverageScrollSpeed(),
|
|
1374
|
+
networkQuality: 'good', // Would need to cache this
|
|
1375
|
+
performanceScore: 0.8, // Would need to cache this
|
|
1376
|
+
avgRenderTime: this.getAverageRenderTime()
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Get current batch size
|
|
1381
|
+
*/
|
|
1382
|
+
getCurrentBatchSize() {
|
|
1383
|
+
return this.currentBatchSize;
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Reset optimizer
|
|
1387
|
+
*/
|
|
1388
|
+
reset() {
|
|
1389
|
+
this.scrollSpeedHistory = [];
|
|
1390
|
+
this.renderTimeHistory = [];
|
|
1391
|
+
this.currentBatchSize = this.config.baseBatchSize;
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Get optimization statistics
|
|
1395
|
+
*/
|
|
1396
|
+
getStats() {
|
|
1397
|
+
return {
|
|
1398
|
+
avgScrollSpeed: this.getAverageScrollSpeed(),
|
|
1399
|
+
avgRenderTime: this.getAverageRenderTime(),
|
|
1400
|
+
currentBatchSize: this.currentBatchSize,
|
|
1401
|
+
totalAdjustments: this.scrollSpeedHistory.length
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
/**
|
|
1407
|
+
* Request Deduplication
|
|
1408
|
+
* Prevents duplicate requests from being sent
|
|
1409
|
+
*/
|
|
1410
|
+
class RequestDeduplicator {
|
|
1411
|
+
constructor() {
|
|
1412
|
+
this.pendingRequests = new Map();
|
|
1413
|
+
this.requestCount = new Map();
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Execute request with deduplication
|
|
1417
|
+
* If same request is already pending, return existing promise
|
|
1418
|
+
*/
|
|
1419
|
+
async request(key, requestFn, ttl = 5000 // Time to live in ms
|
|
1420
|
+
) {
|
|
1421
|
+
// Check if same request is already pending
|
|
1422
|
+
if (this.pendingRequests.has(key)) {
|
|
1423
|
+
console.log(`[RequestDeduplicator] Deduplicating request: ${key}`);
|
|
1424
|
+
return this.pendingRequests.get(key);
|
|
1425
|
+
}
|
|
1426
|
+
// Create new request
|
|
1427
|
+
const promise = requestFn()
|
|
1428
|
+
.then(result => {
|
|
1429
|
+
this.pendingRequests.delete(key);
|
|
1430
|
+
this.requestCount.delete(key);
|
|
1431
|
+
return result;
|
|
1432
|
+
})
|
|
1433
|
+
.catch(error => {
|
|
1434
|
+
this.pendingRequests.delete(key);
|
|
1435
|
+
this.requestCount.delete(key);
|
|
1436
|
+
throw error;
|
|
1437
|
+
});
|
|
1438
|
+
// Store pending request
|
|
1439
|
+
this.pendingRequests.set(key, promise);
|
|
1440
|
+
// Track request count for analytics
|
|
1441
|
+
const count = this.requestCount.get(key) || 0;
|
|
1442
|
+
this.requestCount.set(key, count + 1);
|
|
1443
|
+
// Auto cleanup after TTL
|
|
1444
|
+
setTimeout(() => {
|
|
1445
|
+
if (this.pendingRequests.has(key)) {
|
|
1446
|
+
this.pendingRequests.delete(key);
|
|
1447
|
+
}
|
|
1448
|
+
}, ttl);
|
|
1449
|
+
return promise;
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Clear specific request
|
|
1453
|
+
*/
|
|
1454
|
+
clear(key) {
|
|
1455
|
+
this.pendingRequests.delete(key);
|
|
1456
|
+
this.requestCount.delete(key);
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Clear all requests
|
|
1460
|
+
*/
|
|
1461
|
+
clearAll() {
|
|
1462
|
+
this.pendingRequests.clear();
|
|
1463
|
+
this.requestCount.clear();
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Get pending request count
|
|
1467
|
+
*/
|
|
1468
|
+
getPendingCount() {
|
|
1469
|
+
return this.pendingRequests.size;
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* Get request statistics
|
|
1473
|
+
*/
|
|
1474
|
+
getStats() {
|
|
1475
|
+
const totalRequests = Array.from(this.requestCount.values()).reduce((a, b) => a + b, 0);
|
|
1476
|
+
const deduplicated = totalRequests - this.pendingRequests.size;
|
|
1477
|
+
return {
|
|
1478
|
+
pending: this.pendingRequests.size,
|
|
1479
|
+
totalRequests,
|
|
1480
|
+
deduplicationRate: totalRequests > 0 ? deduplicated / totalRequests : 0
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
/**
|
|
1486
|
+
* Priority-based Request Queue
|
|
1487
|
+
* Processes high-priority requests first
|
|
1488
|
+
*/
|
|
1489
|
+
exports.Priority = void 0;
|
|
1490
|
+
(function (Priority) {
|
|
1491
|
+
Priority[Priority["LOW"] = 0] = "LOW";
|
|
1492
|
+
Priority[Priority["NORMAL"] = 1] = "NORMAL";
|
|
1493
|
+
Priority[Priority["HIGH"] = 2] = "HIGH";
|
|
1494
|
+
Priority[Priority["CRITICAL"] = 3] = "CRITICAL";
|
|
1495
|
+
})(exports.Priority || (exports.Priority = {}));
|
|
1496
|
+
class PriorityRequestQueue {
|
|
1497
|
+
constructor(maxConcurrent = 2) {
|
|
1498
|
+
this.queues = new Map();
|
|
1499
|
+
this.processing = false;
|
|
1500
|
+
this.maxConcurrent = 2;
|
|
1501
|
+
this.activeRequests = 0;
|
|
1502
|
+
this.maxConcurrent = maxConcurrent;
|
|
1503
|
+
// Initialize priority queues
|
|
1504
|
+
Object.values(exports.Priority).forEach(priority => {
|
|
1505
|
+
if (typeof priority === 'number') {
|
|
1506
|
+
this.queues.set(priority, []);
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Add request with priority
|
|
1512
|
+
*/
|
|
1513
|
+
add(requestFn, priority = exports.Priority.NORMAL) {
|
|
1514
|
+
return new Promise((resolve, reject) => {
|
|
1515
|
+
const request = {
|
|
1516
|
+
priority,
|
|
1517
|
+
requestFn: () => requestFn(),
|
|
1518
|
+
resolve,
|
|
1519
|
+
reject,
|
|
1520
|
+
timestamp: Date.now()
|
|
1521
|
+
};
|
|
1522
|
+
// Add to appropriate priority queue
|
|
1523
|
+
const queue = this.queues.get(priority) || [];
|
|
1524
|
+
queue.push(request);
|
|
1525
|
+
this.queues.set(priority, queue);
|
|
1526
|
+
// Start processing if not already processing
|
|
1527
|
+
if (!this.processing) {
|
|
1528
|
+
this.processQueue();
|
|
1529
|
+
}
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Process queue by priority
|
|
1534
|
+
*/
|
|
1535
|
+
async processQueue() {
|
|
1536
|
+
if (this.processing)
|
|
1537
|
+
return;
|
|
1538
|
+
this.processing = true;
|
|
1539
|
+
while (this.hasPendingRequests() && this.activeRequests < this.maxConcurrent) {
|
|
1540
|
+
// Get highest priority request
|
|
1541
|
+
const request = this.getNextRequest();
|
|
1542
|
+
if (!request)
|
|
1543
|
+
break;
|
|
1544
|
+
this.activeRequests++;
|
|
1545
|
+
// Execute request
|
|
1546
|
+
request.requestFn()
|
|
1547
|
+
.then(request.resolve)
|
|
1548
|
+
.catch(request.reject)
|
|
1549
|
+
.finally(() => {
|
|
1550
|
+
this.activeRequests--;
|
|
1551
|
+
this.processQueue();
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
this.processing = false;
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Get next request by priority
|
|
1558
|
+
*/
|
|
1559
|
+
getNextRequest() {
|
|
1560
|
+
// Process from highest priority to lowest
|
|
1561
|
+
for (let priority = exports.Priority.CRITICAL; priority >= exports.Priority.LOW; priority--) {
|
|
1562
|
+
const queue = this.queues.get(priority);
|
|
1563
|
+
if (queue && queue.length > 0) {
|
|
1564
|
+
return queue.shift() || null;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
return null;
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* Check if there are pending requests
|
|
1571
|
+
*/
|
|
1572
|
+
hasPendingRequests() {
|
|
1573
|
+
for (const queue of this.queues.values()) {
|
|
1574
|
+
if (queue.length > 0)
|
|
1575
|
+
return true;
|
|
1576
|
+
}
|
|
1577
|
+
return false;
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Get queue statistics
|
|
1581
|
+
*/
|
|
1582
|
+
getStats() {
|
|
1583
|
+
var _a, _b, _c, _d;
|
|
1584
|
+
const byPriority = {
|
|
1585
|
+
critical: ((_a = this.queues.get(exports.Priority.CRITICAL)) === null || _a === void 0 ? void 0 : _a.length) || 0,
|
|
1586
|
+
high: ((_b = this.queues.get(exports.Priority.HIGH)) === null || _b === void 0 ? void 0 : _b.length) || 0,
|
|
1587
|
+
normal: ((_c = this.queues.get(exports.Priority.NORMAL)) === null || _c === void 0 ? void 0 : _c.length) || 0,
|
|
1588
|
+
low: ((_d = this.queues.get(exports.Priority.LOW)) === null || _d === void 0 ? void 0 : _d.length) || 0
|
|
1589
|
+
};
|
|
1590
|
+
return {
|
|
1591
|
+
totalPending: Object.values(byPriority).reduce((a, b) => a + b, 0),
|
|
1592
|
+
byPriority,
|
|
1593
|
+
activeRequests: this.activeRequests
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Clear all queues
|
|
1598
|
+
*/
|
|
1599
|
+
clear() {
|
|
1600
|
+
this.queues.forEach(queue => queue.length = 0);
|
|
1601
|
+
this.processing = false;
|
|
1602
|
+
this.activeRequests = 0;
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* Clear specific priority queue
|
|
1606
|
+
*/
|
|
1607
|
+
clearPriority(priority) {
|
|
1608
|
+
const queue = this.queues.get(priority);
|
|
1609
|
+
if (queue) {
|
|
1610
|
+
queue.length = 0;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1241
1615
|
class Engine {
|
|
1242
1616
|
constructor(config) {
|
|
1243
1617
|
this.fetchMoreCallback = null;
|
|
@@ -1256,6 +1630,9 @@ class Engine {
|
|
|
1256
1630
|
this.performanceOptimizer = new PerformanceOptimizer();
|
|
1257
1631
|
this.memoryManager = new MemoryManager(1000); // Cache up to 1000 items
|
|
1258
1632
|
this.gpuAccelerator = new GPUAccelerator();
|
|
1633
|
+
this.batchSizeOptimizer = new BatchSizeOptimizer();
|
|
1634
|
+
this.requestDeduplicator = new RequestDeduplicator();
|
|
1635
|
+
this.priorityRequestQueue = new PriorityRequestQueue(2);
|
|
1259
1636
|
this.totalItems = this.config.totalItems || Number.MAX_SAFE_INTEGER;
|
|
1260
1637
|
this.state = {
|
|
1261
1638
|
scrollTop: 0,
|
|
@@ -1386,6 +1763,1165 @@ class Engine {
|
|
|
1386
1763
|
}
|
|
1387
1764
|
}
|
|
1388
1765
|
|
|
1766
|
+
/**
|
|
1767
|
+
* Height Measurement Cache
|
|
1768
|
+
* Dynamically measures and caches item heights for variable height support
|
|
1769
|
+
*/
|
|
1770
|
+
class HeightMeasurementCache {
|
|
1771
|
+
constructor(estimatedHeight = 100) {
|
|
1772
|
+
this.heightMap = new Map();
|
|
1773
|
+
this.offsetMap = new Map();
|
|
1774
|
+
this.totalHeight = 0;
|
|
1775
|
+
this.accessCount = 0;
|
|
1776
|
+
this.hitCount = 0;
|
|
1777
|
+
this.DEFAULT_TTL = 60000; // 1 minute
|
|
1778
|
+
this.estimatedHeight = estimatedHeight;
|
|
1779
|
+
}
|
|
1780
|
+
/**
|
|
1781
|
+
* Measure and cache height for an item
|
|
1782
|
+
*/
|
|
1783
|
+
measureHeight(index, element) {
|
|
1784
|
+
const height = element.offsetHeight;
|
|
1785
|
+
this.heightMap.set(index, {
|
|
1786
|
+
height,
|
|
1787
|
+
measured: true,
|
|
1788
|
+
timestamp: Date.now()
|
|
1789
|
+
});
|
|
1790
|
+
// Recalculate offsets
|
|
1791
|
+
this.recalculateOffsets();
|
|
1792
|
+
return height;
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Get height for an item (measured or estimated)
|
|
1796
|
+
*/
|
|
1797
|
+
getHeight(index) {
|
|
1798
|
+
this.accessCount++;
|
|
1799
|
+
const entry = this.heightMap.get(index);
|
|
1800
|
+
if (entry) {
|
|
1801
|
+
this.hitCount++;
|
|
1802
|
+
return entry.height;
|
|
1803
|
+
}
|
|
1804
|
+
// Return estimated height for unmeasured items
|
|
1805
|
+
return this.estimatedHeight;
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* Get offset (cumulative height) for an item
|
|
1809
|
+
*/
|
|
1810
|
+
getOffset(index) {
|
|
1811
|
+
const offset = this.offsetMap.get(index);
|
|
1812
|
+
return offset !== undefined ? offset : index * this.estimatedHeight;
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* Check if item height is measured
|
|
1816
|
+
*/
|
|
1817
|
+
isMeasured(index) {
|
|
1818
|
+
return this.heightMap.has(index);
|
|
1819
|
+
}
|
|
1820
|
+
/**
|
|
1821
|
+
* Mark item as needing remeasurement
|
|
1822
|
+
*/
|
|
1823
|
+
invalidate(index) {
|
|
1824
|
+
const entry = this.heightMap.get(index);
|
|
1825
|
+
if (entry) {
|
|
1826
|
+
entry.measured = false;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
/**
|
|
1830
|
+
* Clear specific item from cache
|
|
1831
|
+
*/
|
|
1832
|
+
clear(index) {
|
|
1833
|
+
this.heightMap.delete(index);
|
|
1834
|
+
this.recalculateOffsets();
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Clear entire cache
|
|
1838
|
+
*/
|
|
1839
|
+
clearAll() {
|
|
1840
|
+
this.heightMap.clear();
|
|
1841
|
+
this.offsetMap.clear();
|
|
1842
|
+
this.totalHeight = 0;
|
|
1843
|
+
this.accessCount = 0;
|
|
1844
|
+
this.hitCount = 0;
|
|
1845
|
+
}
|
|
1846
|
+
/**
|
|
1847
|
+
* Recalculate all offsets
|
|
1848
|
+
*/
|
|
1849
|
+
recalculateOffsets() {
|
|
1850
|
+
this.offsetMap.clear();
|
|
1851
|
+
let currentOffset = 0;
|
|
1852
|
+
// We need to calculate offsets for all items
|
|
1853
|
+
// This is called when heights change
|
|
1854
|
+
const indices = Array.from(this.heightMap.keys()).sort((a, b) => a - b);
|
|
1855
|
+
for (const index of indices) {
|
|
1856
|
+
this.offsetMap.set(index, currentOffset);
|
|
1857
|
+
const entry = this.heightMap.get(index);
|
|
1858
|
+
if (entry) {
|
|
1859
|
+
currentOffset += entry.height;
|
|
1860
|
+
}
|
|
1861
|
+
else {
|
|
1862
|
+
currentOffset += this.estimatedHeight;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
this.totalHeight = currentOffset;
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* Get total height of all items
|
|
1869
|
+
*/
|
|
1870
|
+
getTotalHeight(totalItems) {
|
|
1871
|
+
if (this.heightMap.size === 0) {
|
|
1872
|
+
return totalItems * this.estimatedHeight;
|
|
1873
|
+
}
|
|
1874
|
+
// Calculate based on measured + estimated
|
|
1875
|
+
let total = 0;
|
|
1876
|
+
for (let i = 0; i < totalItems; i++) {
|
|
1877
|
+
total += this.getHeight(i);
|
|
1878
|
+
}
|
|
1879
|
+
return total;
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1882
|
+
* Find item index at a specific scroll position
|
|
1883
|
+
*/
|
|
1884
|
+
findIndexAtPosition(position, totalItems) {
|
|
1885
|
+
let low = 0;
|
|
1886
|
+
let high = totalItems - 1;
|
|
1887
|
+
while (low <= high) {
|
|
1888
|
+
const mid = Math.floor((low + high) / 2);
|
|
1889
|
+
const offset = this.getOffset(mid);
|
|
1890
|
+
if (offset < position) {
|
|
1891
|
+
low = mid + 1;
|
|
1892
|
+
}
|
|
1893
|
+
else if (offset > position) {
|
|
1894
|
+
high = mid - 1;
|
|
1895
|
+
}
|
|
1896
|
+
else {
|
|
1897
|
+
return mid;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
return low;
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Get cache statistics
|
|
1904
|
+
*/
|
|
1905
|
+
getStats(totalItems) {
|
|
1906
|
+
const measuredItems = this.heightMap.size;
|
|
1907
|
+
const estimatedItems = totalItems - measuredItems;
|
|
1908
|
+
return {
|
|
1909
|
+
totalItems,
|
|
1910
|
+
measuredItems,
|
|
1911
|
+
estimatedItems,
|
|
1912
|
+
cacheSize: this.heightMap.size,
|
|
1913
|
+
hitRate: this.accessCount > 0 ? this.hitCount / this.accessCount : 0
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
/**
|
|
1917
|
+
* Update estimated height
|
|
1918
|
+
*/
|
|
1919
|
+
updateEstimatedHeight(height) {
|
|
1920
|
+
this.estimatedHeight = height;
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
* Get estimated height
|
|
1924
|
+
*/
|
|
1925
|
+
getEstimatedHeight() {
|
|
1926
|
+
return this.estimatedHeight;
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* Cleanup old entries (older than TTL)
|
|
1930
|
+
*/
|
|
1931
|
+
cleanup(ttl = this.DEFAULT_TTL) {
|
|
1932
|
+
const now = Date.now();
|
|
1933
|
+
const toDelete = [];
|
|
1934
|
+
this.heightMap.forEach((entry, index) => {
|
|
1935
|
+
if (now - entry.timestamp > ttl) {
|
|
1936
|
+
toDelete.push(index);
|
|
1937
|
+
}
|
|
1938
|
+
});
|
|
1939
|
+
toDelete.forEach(index => this.clear(index));
|
|
1940
|
+
}
|
|
1941
|
+
/**
|
|
1942
|
+
* Get all measured heights
|
|
1943
|
+
*/
|
|
1944
|
+
getAllHeights() {
|
|
1945
|
+
const heights = new Map();
|
|
1946
|
+
this.heightMap.forEach((entry, index) => {
|
|
1947
|
+
heights.set(index, entry.height);
|
|
1948
|
+
});
|
|
1949
|
+
return heights;
|
|
1950
|
+
}
|
|
1951
|
+
/**
|
|
1952
|
+
* Set heights in bulk (for initial data load)
|
|
1953
|
+
*/
|
|
1954
|
+
setHeightsBulk(heights) {
|
|
1955
|
+
heights.forEach((height, index) => {
|
|
1956
|
+
this.heightMap.set(index, {
|
|
1957
|
+
height,
|
|
1958
|
+
measured: true,
|
|
1959
|
+
timestamp: Date.now()
|
|
1960
|
+
});
|
|
1961
|
+
});
|
|
1962
|
+
this.recalculateOffsets();
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
/**
|
|
1967
|
+
* Variable Height Manager
|
|
1968
|
+
* Manages variable height items with efficient position calculations
|
|
1969
|
+
*/
|
|
1970
|
+
class VariableHeightManager {
|
|
1971
|
+
constructor(config) {
|
|
1972
|
+
this.totalItems = 0;
|
|
1973
|
+
this.lastMeasuredIndex = -1;
|
|
1974
|
+
this.config = {
|
|
1975
|
+
estimatedHeight: (config === null || config === void 0 ? void 0 : config.estimatedHeight) || 100,
|
|
1976
|
+
minHeight: (config === null || config === void 0 ? void 0 : config.minHeight) || 50,
|
|
1977
|
+
maxHeight: (config === null || config === void 0 ? void 0 : config.maxHeight) || 500,
|
|
1978
|
+
bufferSize: (config === null || config === void 0 ? void 0 : config.bufferSize) || 5
|
|
1979
|
+
};
|
|
1980
|
+
this.heightCache = new HeightMeasurementCache(this.config.estimatedHeight);
|
|
1981
|
+
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Set total number of items
|
|
1984
|
+
*/
|
|
1985
|
+
setTotalItems(total) {
|
|
1986
|
+
this.totalItems = total;
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* Measure item height from DOM element
|
|
1990
|
+
*/
|
|
1991
|
+
measureElement(index, element) {
|
|
1992
|
+
if (!element) {
|
|
1993
|
+
return this.config.estimatedHeight;
|
|
1994
|
+
}
|
|
1995
|
+
const height = element.offsetHeight;
|
|
1996
|
+
// Clamp height between min and max
|
|
1997
|
+
const clampedHeight = Math.max(this.config.minHeight, Math.min(this.config.maxHeight, height));
|
|
1998
|
+
this.heightCache.measureHeight(index, { offsetHeight: clampedHeight });
|
|
1999
|
+
this.lastMeasuredIndex = Math.max(this.lastMeasuredIndex, index);
|
|
2000
|
+
return clampedHeight;
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* Get item position (offset and height)
|
|
2004
|
+
*/
|
|
2005
|
+
getItemPosition(index) {
|
|
2006
|
+
const offset = this.heightCache.getOffset(index);
|
|
2007
|
+
const height = this.heightCache.getHeight(index);
|
|
2008
|
+
return {
|
|
2009
|
+
index,
|
|
2010
|
+
offset,
|
|
2011
|
+
height
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* Calculate visible range for variable heights
|
|
2016
|
+
*/
|
|
2017
|
+
calculateVisibleRange(scrollTop, viewportHeight) {
|
|
2018
|
+
// Find start index based on scroll position
|
|
2019
|
+
const startIndex = this.heightCache.findIndexAtPosition(scrollTop, this.totalItems);
|
|
2020
|
+
// Calculate how many items fit in viewport
|
|
2021
|
+
let endIndex = startIndex;
|
|
2022
|
+
let currentOffset = this.heightCache.getOffset(startIndex);
|
|
2023
|
+
while (endIndex < this.totalItems && currentOffset < scrollTop + viewportHeight) {
|
|
2024
|
+
const height = this.heightCache.getHeight(endIndex);
|
|
2025
|
+
currentOffset += height;
|
|
2026
|
+
endIndex++;
|
|
2027
|
+
}
|
|
2028
|
+
// Add buffer
|
|
2029
|
+
const bufferedStart = Math.max(0, startIndex - this.config.bufferSize);
|
|
2030
|
+
const bufferedEnd = Math.min(this.totalItems - 1, endIndex + this.config.bufferSize);
|
|
2031
|
+
return {
|
|
2032
|
+
start: bufferedStart,
|
|
2033
|
+
end: bufferedEnd
|
|
2034
|
+
};
|
|
2035
|
+
}
|
|
2036
|
+
/**
|
|
2037
|
+
* Get total height of all items
|
|
2038
|
+
*/
|
|
2039
|
+
getTotalHeight() {
|
|
2040
|
+
return this.heightCache.getTotalHeight(this.totalItems);
|
|
2041
|
+
}
|
|
2042
|
+
/**
|
|
2043
|
+
* Scroll to specific item index
|
|
2044
|
+
*/
|
|
2045
|
+
scrollToIndex(index) {
|
|
2046
|
+
const offset = this.heightCache.getOffset(index);
|
|
2047
|
+
return offset;
|
|
2048
|
+
}
|
|
2049
|
+
/**
|
|
2050
|
+
* Get items to render for current viewport
|
|
2051
|
+
*/
|
|
2052
|
+
getItemsToRender(scrollTop, viewportHeight) {
|
|
2053
|
+
const visibleRange = this.calculateVisibleRange(scrollTop, viewportHeight);
|
|
2054
|
+
const items = [];
|
|
2055
|
+
for (let i = visibleRange.start; i <= visibleRange.end; i++) {
|
|
2056
|
+
items.push(this.getItemPosition(i));
|
|
2057
|
+
}
|
|
2058
|
+
return {
|
|
2059
|
+
items,
|
|
2060
|
+
totalHeight: this.getTotalHeight()
|
|
2061
|
+
};
|
|
2062
|
+
}
|
|
2063
|
+
/**
|
|
2064
|
+
* Handle height change (when item height changes dynamically)
|
|
2065
|
+
*/
|
|
2066
|
+
onHeightChange(index, newHeight) {
|
|
2067
|
+
const oldHeight = this.heightCache.getHeight(index);
|
|
2068
|
+
const heightDiff = newHeight - oldHeight;
|
|
2069
|
+
// Update cache
|
|
2070
|
+
this.heightCache.measureHeight(index, { offsetHeight: newHeight });
|
|
2071
|
+
// If height changed significantly, may need to adjust scroll position
|
|
2072
|
+
if (Math.abs(heightDiff) > 50) {
|
|
2073
|
+
// Large height change - may need to recalculate
|
|
2074
|
+
this.heightCache.invalidate(index);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
/**
|
|
2078
|
+
* Get cache statistics
|
|
2079
|
+
*/
|
|
2080
|
+
getCacheStats() {
|
|
2081
|
+
return this.heightCache.getStats(this.totalItems);
|
|
2082
|
+
}
|
|
2083
|
+
/**
|
|
2084
|
+
* Clear cache for specific range
|
|
2085
|
+
*/
|
|
2086
|
+
clearRange(startIndex, endIndex) {
|
|
2087
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
2088
|
+
this.heightCache.clear(i);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
/**
|
|
2092
|
+
* Clear entire cache
|
|
2093
|
+
*/
|
|
2094
|
+
clearCache() {
|
|
2095
|
+
this.heightCache.clearAll();
|
|
2096
|
+
this.lastMeasuredIndex = -1;
|
|
2097
|
+
}
|
|
2098
|
+
/**
|
|
2099
|
+
* Get last measured index
|
|
2100
|
+
*/
|
|
2101
|
+
getLastMeasuredIndex() {
|
|
2102
|
+
return this.lastMeasuredIndex;
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Check if item is measured
|
|
2106
|
+
*/
|
|
2107
|
+
isItemMeasured(index) {
|
|
2108
|
+
return this.heightCache.isMeasured(index);
|
|
2109
|
+
}
|
|
2110
|
+
/**
|
|
2111
|
+
* Get measured items count
|
|
2112
|
+
*/
|
|
2113
|
+
getMeasuredCount() {
|
|
2114
|
+
return this.heightCache.getStats(this.totalItems).measuredItems;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
/**
|
|
2119
|
+
* Dynamic Height Engine
|
|
2120
|
+
* Core engine for variable height virtual scrolling
|
|
2121
|
+
*/
|
|
2122
|
+
class DynamicHeightEngine {
|
|
2123
|
+
constructor(config = {}) {
|
|
2124
|
+
this.containerElement = null;
|
|
2125
|
+
this.itemElements = new Map();
|
|
2126
|
+
this.config = {
|
|
2127
|
+
itemHeight: config.estimatedItemHeight || 100,
|
|
2128
|
+
viewportHeight: config.viewportHeight || 400,
|
|
2129
|
+
bufferSize: config.heightBufferSize || 5,
|
|
2130
|
+
estimatedItemHeight: config.estimatedItemHeight || 100,
|
|
2131
|
+
minItemHeight: config.minItemHeight || 50,
|
|
2132
|
+
maxItemHeight: config.maxItemHeight || 500,
|
|
2133
|
+
heightBufferSize: config.heightBufferSize || 5
|
|
2134
|
+
};
|
|
2135
|
+
this.variableHeightManager = new VariableHeightManager({
|
|
2136
|
+
estimatedHeight: this.config.estimatedItemHeight,
|
|
2137
|
+
minHeight: this.config.minItemHeight,
|
|
2138
|
+
maxHeight: this.config.maxItemHeight,
|
|
2139
|
+
bufferSize: this.config.heightBufferSize
|
|
2140
|
+
});
|
|
2141
|
+
this.heightCache = new HeightMeasurementCache(this.config.estimatedItemHeight);
|
|
2142
|
+
this.state = {
|
|
2143
|
+
scrollTop: 0,
|
|
2144
|
+
visibleRange: { start: 0, end: 0 },
|
|
2145
|
+
loadedItems: 0,
|
|
2146
|
+
isLoading: false,
|
|
2147
|
+
totalContentHeight: 0,
|
|
2148
|
+
measuredItems: 0,
|
|
2149
|
+
estimatedItems: 0
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
/**
|
|
2153
|
+
* Initialize with container element
|
|
2154
|
+
*/
|
|
2155
|
+
init(container) {
|
|
2156
|
+
this.containerElement = container;
|
|
2157
|
+
this.setupScrollListener();
|
|
2158
|
+
}
|
|
2159
|
+
/**
|
|
2160
|
+
* Setup scroll listener
|
|
2161
|
+
*/
|
|
2162
|
+
setupScrollListener() {
|
|
2163
|
+
if (!this.containerElement)
|
|
2164
|
+
return;
|
|
2165
|
+
this.containerElement.addEventListener('scroll', () => {
|
|
2166
|
+
this.onScroll();
|
|
2167
|
+
}, { passive: true });
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* Handle scroll event
|
|
2171
|
+
*/
|
|
2172
|
+
onScroll() {
|
|
2173
|
+
if (!this.containerElement)
|
|
2174
|
+
return;
|
|
2175
|
+
const scrollTop = this.containerElement.scrollTop;
|
|
2176
|
+
this.state.scrollTop = scrollTop;
|
|
2177
|
+
// Recalculate visible range
|
|
2178
|
+
this.updateVisibleRange();
|
|
2179
|
+
}
|
|
2180
|
+
/**
|
|
2181
|
+
* Update visible range based on scroll position
|
|
2182
|
+
*/
|
|
2183
|
+
updateVisibleRange() {
|
|
2184
|
+
if (!this.containerElement)
|
|
2185
|
+
return;
|
|
2186
|
+
const viewportHeight = this.containerElement.clientHeight;
|
|
2187
|
+
const visibleRange = this.variableHeightManager.calculateVisibleRange(this.state.scrollTop, viewportHeight);
|
|
2188
|
+
this.state.visibleRange = visibleRange;
|
|
2189
|
+
// Update state with measured/estimated counts
|
|
2190
|
+
const stats = this.variableHeightManager.getCacheStats();
|
|
2191
|
+
this.state.measuredItems = stats.measuredItems;
|
|
2192
|
+
this.state.estimatedItems = stats.estimatedItems;
|
|
2193
|
+
this.state.totalContentHeight = this.variableHeightManager.getTotalHeight();
|
|
2194
|
+
}
|
|
2195
|
+
/**
|
|
2196
|
+
* Measure item height from DOM element
|
|
2197
|
+
*/
|
|
2198
|
+
measureItem(index, element) {
|
|
2199
|
+
const height = this.variableHeightManager.measureElement(index, element);
|
|
2200
|
+
// Store element reference
|
|
2201
|
+
this.itemElements.set(index, element);
|
|
2202
|
+
// Update state
|
|
2203
|
+
const stats = this.variableHeightManager.getCacheStats();
|
|
2204
|
+
this.state.measuredItems = stats.measuredItems;
|
|
2205
|
+
this.state.estimatedItems = stats.estimatedItems;
|
|
2206
|
+
this.state.totalContentHeight = this.variableHeightManager.getTotalHeight();
|
|
2207
|
+
// Trigger re-render if needed
|
|
2208
|
+
this.onHeightMeasured(index, height);
|
|
2209
|
+
return height;
|
|
2210
|
+
}
|
|
2211
|
+
/**
|
|
2212
|
+
* Called when item height is measured
|
|
2213
|
+
*/
|
|
2214
|
+
onHeightMeasured(index, height) {
|
|
2215
|
+
// Can be overridden to trigger UI updates
|
|
2216
|
+
// For example, update styles or trigger re-render
|
|
2217
|
+
}
|
|
2218
|
+
/**
|
|
2219
|
+
* Get items to render for current viewport
|
|
2220
|
+
*/
|
|
2221
|
+
getItemsToRender() {
|
|
2222
|
+
if (!this.containerElement) {
|
|
2223
|
+
return {
|
|
2224
|
+
items: [],
|
|
2225
|
+
totalHeight: 0,
|
|
2226
|
+
visibleRange: { start: 0, end: 0 }
|
|
2227
|
+
};
|
|
2228
|
+
}
|
|
2229
|
+
const { items, totalHeight } = this.variableHeightManager.getItemsToRender(this.state.scrollTop, this.containerElement.clientHeight);
|
|
2230
|
+
return {
|
|
2231
|
+
items,
|
|
2232
|
+
totalHeight,
|
|
2233
|
+
visibleRange: this.state.visibleRange
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2236
|
+
/**
|
|
2237
|
+
* Scroll to specific item index
|
|
2238
|
+
*/
|
|
2239
|
+
scrollToIndex(index) {
|
|
2240
|
+
if (!this.containerElement)
|
|
2241
|
+
return;
|
|
2242
|
+
const offset = this.variableHeightManager.scrollToIndex(index);
|
|
2243
|
+
this.containerElement.scrollTop = offset;
|
|
2244
|
+
// Update state
|
|
2245
|
+
this.state.scrollTop = offset;
|
|
2246
|
+
this.updateVisibleRange();
|
|
2247
|
+
}
|
|
2248
|
+
/**
|
|
2249
|
+
* Set total number of items
|
|
2250
|
+
*/
|
|
2251
|
+
setTotalItems(total) {
|
|
2252
|
+
this.variableHeightManager.setTotalItems(total);
|
|
2253
|
+
this.state.loadedItems = total;
|
|
2254
|
+
this.state.totalContentHeight = this.variableHeightManager.getTotalHeight();
|
|
2255
|
+
}
|
|
2256
|
+
/**
|
|
2257
|
+
* Get current state
|
|
2258
|
+
*/
|
|
2259
|
+
getState() {
|
|
2260
|
+
return { ...this.state };
|
|
2261
|
+
}
|
|
2262
|
+
/**
|
|
2263
|
+
* Get cache statistics
|
|
2264
|
+
*/
|
|
2265
|
+
getCacheStats() {
|
|
2266
|
+
return this.variableHeightManager.getCacheStats();
|
|
2267
|
+
}
|
|
2268
|
+
/**
|
|
2269
|
+
* Clear cache for range
|
|
2270
|
+
*/
|
|
2271
|
+
clearCacheRange(startIndex, endIndex) {
|
|
2272
|
+
this.variableHeightManager.clearRange(startIndex, endIndex);
|
|
2273
|
+
// Clear element references
|
|
2274
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
2275
|
+
this.itemElements.delete(i);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
/**
|
|
2279
|
+
* Clear entire cache
|
|
2280
|
+
*/
|
|
2281
|
+
clearCache() {
|
|
2282
|
+
this.variableHeightManager.clearCache();
|
|
2283
|
+
this.itemElements.clear();
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Cleanup
|
|
2287
|
+
*/
|
|
2288
|
+
cleanup() {
|
|
2289
|
+
if (this.containerElement) {
|
|
2290
|
+
this.containerElement.removeEventListener('scroll', this.onScroll.bind(this));
|
|
2291
|
+
}
|
|
2292
|
+
this.clearCache();
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* Update viewport height
|
|
2296
|
+
*/
|
|
2297
|
+
updateViewportHeight(height) {
|
|
2298
|
+
this.config.viewportHeight = height;
|
|
2299
|
+
this.updateVisibleRange();
|
|
2300
|
+
}
|
|
2301
|
+
/**
|
|
2302
|
+
* Get item offset for styling
|
|
2303
|
+
*/
|
|
2304
|
+
getItemOffset(index) {
|
|
2305
|
+
return this.variableHeightManager.getItemPosition(index).offset;
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* Get item height
|
|
2309
|
+
*/
|
|
2310
|
+
getItemHeight(index) {
|
|
2311
|
+
return this.variableHeightManager.getItemPosition(index).height;
|
|
2312
|
+
}
|
|
2313
|
+
/**
|
|
2314
|
+
* Check if item is measured
|
|
2315
|
+
*/
|
|
2316
|
+
isItemMeasured(index) {
|
|
2317
|
+
return this.variableHeightManager.isItemMeasured(index);
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
/**
|
|
2322
|
+
* Smart Prefetch Algorithm
|
|
2323
|
+
* Recognizes scroll patterns and predicts data loading needs
|
|
2324
|
+
*/
|
|
2325
|
+
class SmartPrefetchAlgorithm {
|
|
2326
|
+
constructor() {
|
|
2327
|
+
this.velocityHistory = [];
|
|
2328
|
+
this.directionHistory = [];
|
|
2329
|
+
this.HISTORY_SIZE = 20;
|
|
2330
|
+
this.lastPrefetchTime = 0;
|
|
2331
|
+
this.prefetchCooldown = 500; // ms
|
|
2332
|
+
}
|
|
2333
|
+
/**
|
|
2334
|
+
* Analyze scroll pattern
|
|
2335
|
+
*/
|
|
2336
|
+
analyzeScrollPattern(velocity, acceleration, direction) {
|
|
2337
|
+
this.trackVelocity(velocity);
|
|
2338
|
+
this.trackDirection(direction);
|
|
2339
|
+
const avgVelocity = this.getAverageVelocity();
|
|
2340
|
+
const velocityVariance = this.getVelocityVariance();
|
|
2341
|
+
const directionChanges = this.countDirectionChanges();
|
|
2342
|
+
// Determine pattern type
|
|
2343
|
+
let pattern;
|
|
2344
|
+
if (Math.abs(avgVelocity) > 2.0) {
|
|
2345
|
+
pattern = {
|
|
2346
|
+
type: 'fast-scroll',
|
|
2347
|
+
velocity: avgVelocity,
|
|
2348
|
+
acceleration,
|
|
2349
|
+
direction,
|
|
2350
|
+
confidence: 0.9
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
else if (Math.abs(avgVelocity) < 0.3) {
|
|
2354
|
+
pattern = {
|
|
2355
|
+
type: 'paused',
|
|
2356
|
+
velocity: avgVelocity,
|
|
2357
|
+
acceleration,
|
|
2358
|
+
direction: 'stationary',
|
|
2359
|
+
confidence: 0.95
|
|
2360
|
+
};
|
|
2361
|
+
}
|
|
2362
|
+
else if (directionChanges > 5) {
|
|
2363
|
+
pattern = {
|
|
2364
|
+
type: 'oscillating',
|
|
2365
|
+
velocity: avgVelocity,
|
|
2366
|
+
acceleration,
|
|
2367
|
+
direction,
|
|
2368
|
+
confidence: 0.85
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
else if (velocityVariance < 0.5) {
|
|
2372
|
+
pattern = {
|
|
2373
|
+
type: 'steady',
|
|
2374
|
+
velocity: avgVelocity,
|
|
2375
|
+
acceleration,
|
|
2376
|
+
direction,
|
|
2377
|
+
confidence: 0.9
|
|
2378
|
+
};
|
|
2379
|
+
}
|
|
2380
|
+
else {
|
|
2381
|
+
pattern = {
|
|
2382
|
+
type: 'slow-scroll',
|
|
2383
|
+
velocity: avgVelocity,
|
|
2384
|
+
acceleration,
|
|
2385
|
+
direction,
|
|
2386
|
+
confidence: 0.8
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
return pattern;
|
|
2390
|
+
}
|
|
2391
|
+
/**
|
|
2392
|
+
* Predict prefetch needs based on scroll pattern
|
|
2393
|
+
*/
|
|
2394
|
+
predictPrefetchNeeds(pattern, visibleEnd, totalLoaded) {
|
|
2395
|
+
const now = Date.now();
|
|
2396
|
+
// Check cooldown
|
|
2397
|
+
if (now - this.lastPrefetchTime < this.prefetchCooldown) {
|
|
2398
|
+
return {
|
|
2399
|
+
shouldPrefetch: false,
|
|
2400
|
+
prefetchDistance: 0,
|
|
2401
|
+
batchSize: 0,
|
|
2402
|
+
priority: 'low',
|
|
2403
|
+
confidence: 1.0
|
|
2404
|
+
};
|
|
2405
|
+
}
|
|
2406
|
+
let prediction;
|
|
2407
|
+
switch (pattern.type) {
|
|
2408
|
+
case 'fast-scroll':
|
|
2409
|
+
prediction = {
|
|
2410
|
+
shouldPrefetch: true,
|
|
2411
|
+
prefetchDistance: 1500, // Far ahead for fast scrolling
|
|
2412
|
+
batchSize: 30, // Large batch
|
|
2413
|
+
priority: 'critical',
|
|
2414
|
+
confidence: pattern.confidence
|
|
2415
|
+
};
|
|
2416
|
+
break;
|
|
2417
|
+
case 'steady':
|
|
2418
|
+
prediction = {
|
|
2419
|
+
shouldPrefetch: visibleEnd >= totalLoaded - 800,
|
|
2420
|
+
prefetchDistance: 800,
|
|
2421
|
+
batchSize: 20,
|
|
2422
|
+
priority: 'high',
|
|
2423
|
+
confidence: pattern.confidence
|
|
2424
|
+
};
|
|
2425
|
+
break;
|
|
2426
|
+
case 'slow-scroll':
|
|
2427
|
+
prediction = {
|
|
2428
|
+
shouldPrefetch: visibleEnd >= totalLoaded - 400,
|
|
2429
|
+
prefetchDistance: 400,
|
|
2430
|
+
batchSize: 10,
|
|
2431
|
+
priority: 'normal',
|
|
2432
|
+
confidence: pattern.confidence
|
|
2433
|
+
};
|
|
2434
|
+
break;
|
|
2435
|
+
case 'oscillating':
|
|
2436
|
+
prediction = {
|
|
2437
|
+
shouldPrefetch: visibleEnd >= totalLoaded - 600,
|
|
2438
|
+
prefetchDistance: 600,
|
|
2439
|
+
batchSize: 15,
|
|
2440
|
+
priority: 'normal',
|
|
2441
|
+
confidence: pattern.confidence * 0.8 // Lower confidence for oscillating
|
|
2442
|
+
};
|
|
2443
|
+
break;
|
|
2444
|
+
case 'paused':
|
|
2445
|
+
prediction = {
|
|
2446
|
+
shouldPrefetch: false, // User paused, no need to prefetch
|
|
2447
|
+
prefetchDistance: 0,
|
|
2448
|
+
batchSize: 0,
|
|
2449
|
+
priority: 'low',
|
|
2450
|
+
confidence: pattern.confidence
|
|
2451
|
+
};
|
|
2452
|
+
break;
|
|
2453
|
+
default:
|
|
2454
|
+
prediction = {
|
|
2455
|
+
shouldPrefetch: visibleEnd >= totalLoaded - 500,
|
|
2456
|
+
prefetchDistance: 500,
|
|
2457
|
+
batchSize: 15,
|
|
2458
|
+
priority: 'normal',
|
|
2459
|
+
confidence: 0.7
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
// Update last prefetch time if prefetching
|
|
2463
|
+
if (prediction.shouldPrefetch) {
|
|
2464
|
+
this.lastPrefetchTime = now;
|
|
2465
|
+
}
|
|
2466
|
+
return prediction;
|
|
2467
|
+
}
|
|
2468
|
+
/**
|
|
2469
|
+
* Track velocity history
|
|
2470
|
+
*/
|
|
2471
|
+
trackVelocity(velocity) {
|
|
2472
|
+
this.velocityHistory.push(velocity);
|
|
2473
|
+
if (this.velocityHistory.length > this.HISTORY_SIZE) {
|
|
2474
|
+
this.velocityHistory.shift();
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
/**
|
|
2478
|
+
* Track direction history
|
|
2479
|
+
*/
|
|
2480
|
+
trackDirection(direction) {
|
|
2481
|
+
this.directionHistory.push(direction);
|
|
2482
|
+
if (this.directionHistory.length > this.HISTORY_SIZE) {
|
|
2483
|
+
this.directionHistory.shift();
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
/**
|
|
2487
|
+
* Get average velocity
|
|
2488
|
+
*/
|
|
2489
|
+
getAverageVelocity() {
|
|
2490
|
+
if (this.velocityHistory.length === 0)
|
|
2491
|
+
return 0;
|
|
2492
|
+
const sum = this.velocityHistory.reduce((a, b) => a + b, 0);
|
|
2493
|
+
return sum / this.velocityHistory.length;
|
|
2494
|
+
}
|
|
2495
|
+
/**
|
|
2496
|
+
* Get velocity variance
|
|
2497
|
+
*/
|
|
2498
|
+
getVelocityVariance() {
|
|
2499
|
+
if (this.velocityHistory.length < 2)
|
|
2500
|
+
return 0;
|
|
2501
|
+
const avg = this.getAverageVelocity();
|
|
2502
|
+
const squaredDiffs = this.velocityHistory.map(v => Math.pow(v - avg, 2));
|
|
2503
|
+
const avgSquaredDiff = squaredDiffs.reduce((a, b) => a + b, 0) / squaredDiffs.length;
|
|
2504
|
+
return Math.sqrt(avgSquaredDiff);
|
|
2505
|
+
}
|
|
2506
|
+
/**
|
|
2507
|
+
* Count direction changes
|
|
2508
|
+
*/
|
|
2509
|
+
countDirectionChanges() {
|
|
2510
|
+
if (this.directionHistory.length < 2)
|
|
2511
|
+
return 0;
|
|
2512
|
+
let changes = 0;
|
|
2513
|
+
for (let i = 1; i < this.directionHistory.length; i++) {
|
|
2514
|
+
if (this.directionHistory[i] !== this.directionHistory[i - 1] &&
|
|
2515
|
+
this.directionHistory[i] !== 'stationary' &&
|
|
2516
|
+
this.directionHistory[i - 1] !== 'stationary') {
|
|
2517
|
+
changes++;
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
return changes;
|
|
2521
|
+
}
|
|
2522
|
+
/**
|
|
2523
|
+
* Reset history
|
|
2524
|
+
*/
|
|
2525
|
+
reset() {
|
|
2526
|
+
this.velocityHistory = [];
|
|
2527
|
+
this.directionHistory = [];
|
|
2528
|
+
this.lastPrefetchTime = 0;
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* Get prediction confidence
|
|
2532
|
+
*/
|
|
2533
|
+
getConfidence() {
|
|
2534
|
+
if (this.velocityHistory.length < 5)
|
|
2535
|
+
return 0.5; // Not enough data
|
|
2536
|
+
return Math.min(this.velocityHistory.length / this.HISTORY_SIZE, 1.0);
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
/**
|
|
2541
|
+
* Preemptive Caching
|
|
2542
|
+
* Caches data before it's needed based on predictions
|
|
2543
|
+
*/
|
|
2544
|
+
class PreemptiveCache {
|
|
2545
|
+
constructor(config) {
|
|
2546
|
+
this.cache = new Map();
|
|
2547
|
+
this.accessHistory = [];
|
|
2548
|
+
this.config = {
|
|
2549
|
+
maxSize: (config === null || config === void 0 ? void 0 : config.maxSize) || 1000,
|
|
2550
|
+
defaultTTL: (config === null || config === void 0 ? void 0 : config.defaultTTL) || 300000, // 5 minutes
|
|
2551
|
+
cleanupThreshold: (config === null || config === void 0 ? void 0 : config.cleanupThreshold) || 800
|
|
2552
|
+
};
|
|
2553
|
+
}
|
|
2554
|
+
/**
|
|
2555
|
+
* Preemptively cache data with priority
|
|
2556
|
+
*/
|
|
2557
|
+
preemptiveCache(index, data, priority = 'normal') {
|
|
2558
|
+
// Check if we need to cleanup
|
|
2559
|
+
if (this.cache.size >= this.config.cleanupThreshold) {
|
|
2560
|
+
this.cleanup();
|
|
2561
|
+
}
|
|
2562
|
+
const entry = {
|
|
2563
|
+
data,
|
|
2564
|
+
timestamp: Date.now(),
|
|
2565
|
+
priority,
|
|
2566
|
+
accessCount: 0,
|
|
2567
|
+
expiry: Date.now() + this.config.defaultTTL
|
|
2568
|
+
};
|
|
2569
|
+
this.cache.set(index, entry);
|
|
2570
|
+
}
|
|
2571
|
+
/**
|
|
2572
|
+
* Get cached data
|
|
2573
|
+
*/
|
|
2574
|
+
get(index) {
|
|
2575
|
+
const entry = this.cache.get(index);
|
|
2576
|
+
if (!entry) {
|
|
2577
|
+
return null;
|
|
2578
|
+
}
|
|
2579
|
+
// Check expiry
|
|
2580
|
+
if (Date.now() > entry.expiry) {
|
|
2581
|
+
this.cache.delete(index);
|
|
2582
|
+
return null;
|
|
2583
|
+
}
|
|
2584
|
+
// Update access count
|
|
2585
|
+
entry.accessCount++;
|
|
2586
|
+
this.trackAccess(index);
|
|
2587
|
+
return entry.data;
|
|
2588
|
+
}
|
|
2589
|
+
/**
|
|
2590
|
+
* Check if data is cached
|
|
2591
|
+
*/
|
|
2592
|
+
has(index) {
|
|
2593
|
+
const entry = this.cache.get(index);
|
|
2594
|
+
if (!entry)
|
|
2595
|
+
return false;
|
|
2596
|
+
// Check expiry
|
|
2597
|
+
if (Date.now() > entry.expiry) {
|
|
2598
|
+
this.cache.delete(index);
|
|
2599
|
+
return false;
|
|
2600
|
+
}
|
|
2601
|
+
return true;
|
|
2602
|
+
}
|
|
2603
|
+
/**
|
|
2604
|
+
* Get cached data for range
|
|
2605
|
+
*/
|
|
2606
|
+
getRange(startIndex, endIndex) {
|
|
2607
|
+
const results = [];
|
|
2608
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
2609
|
+
const data = this.get(i);
|
|
2610
|
+
if (data !== null) {
|
|
2611
|
+
results.push(data);
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
return results;
|
|
2615
|
+
}
|
|
2616
|
+
/**
|
|
2617
|
+
* Delete cached data
|
|
2618
|
+
*/
|
|
2619
|
+
delete(index) {
|
|
2620
|
+
return this.cache.delete(index);
|
|
2621
|
+
}
|
|
2622
|
+
/**
|
|
2623
|
+
* Clear cache
|
|
2624
|
+
*/
|
|
2625
|
+
clear() {
|
|
2626
|
+
this.cache.clear();
|
|
2627
|
+
this.accessHistory = [];
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Cleanup old/low-priority entries
|
|
2631
|
+
*/
|
|
2632
|
+
cleanup() {
|
|
2633
|
+
const now = Date.now();
|
|
2634
|
+
const toDelete = [];
|
|
2635
|
+
// First pass: remove expired entries
|
|
2636
|
+
this.cache.forEach((entry, index) => {
|
|
2637
|
+
if (now > entry.expiry) {
|
|
2638
|
+
toDelete.push(index);
|
|
2639
|
+
}
|
|
2640
|
+
});
|
|
2641
|
+
// Second pass: remove low-priority entries if still over limit
|
|
2642
|
+
if (this.cache.size - toDelete.length > this.config.maxSize) {
|
|
2643
|
+
const sortedByPriority = Array.from(this.cache.entries())
|
|
2644
|
+
.filter(([index]) => !toDelete.includes(index))
|
|
2645
|
+
.sort((a, b) => {
|
|
2646
|
+
const priorityOrder = { critical: 4, high: 3, normal: 2, low: 1 };
|
|
2647
|
+
return priorityOrder[a[1].priority] - priorityOrder[b[1].priority];
|
|
2648
|
+
});
|
|
2649
|
+
// Remove lowest priority entries
|
|
2650
|
+
const toRemove = Math.ceil(sortedByPriority.length * 0.2); // Remove 20%
|
|
2651
|
+
for (let i = 0; i < toRemove; i++) {
|
|
2652
|
+
toDelete.push(sortedByPriority[i][0]);
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
// Delete marked entries
|
|
2656
|
+
toDelete.forEach(index => this.cache.delete(index));
|
|
2657
|
+
}
|
|
2658
|
+
/**
|
|
2659
|
+
* Track access for analytics
|
|
2660
|
+
*/
|
|
2661
|
+
trackAccess(index) {
|
|
2662
|
+
this.accessHistory.push(index);
|
|
2663
|
+
if (this.accessHistory.length > 100) {
|
|
2664
|
+
this.accessHistory.shift();
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
/**
|
|
2668
|
+
* Get cache statistics
|
|
2669
|
+
*/
|
|
2670
|
+
getStats() {
|
|
2671
|
+
const byPriority = {
|
|
2672
|
+
critical: 0,
|
|
2673
|
+
high: 0,
|
|
2674
|
+
normal: 0,
|
|
2675
|
+
low: 0
|
|
2676
|
+
};
|
|
2677
|
+
let totalAccessCount = 0;
|
|
2678
|
+
this.cache.forEach(entry => {
|
|
2679
|
+
byPriority[entry.priority]++;
|
|
2680
|
+
totalAccessCount += entry.accessCount;
|
|
2681
|
+
});
|
|
2682
|
+
return {
|
|
2683
|
+
size: this.cache.size,
|
|
2684
|
+
maxSize: this.config.maxSize,
|
|
2685
|
+
hitRate: this.accessHistory.length > 0 ?
|
|
2686
|
+
this.accessHistory.filter(i => this.has(i)).length / this.accessHistory.length : 0,
|
|
2687
|
+
avgAccessCount: this.cache.size > 0 ? totalAccessCount / this.cache.size : 0,
|
|
2688
|
+
byPriority
|
|
2689
|
+
};
|
|
2690
|
+
}
|
|
2691
|
+
/**
|
|
2692
|
+
* Get all cached indices
|
|
2693
|
+
*/
|
|
2694
|
+
getCachedIndices() {
|
|
2695
|
+
return Array.from(this.cache.keys());
|
|
2696
|
+
}
|
|
2697
|
+
/**
|
|
2698
|
+
* Preemptively cache range
|
|
2699
|
+
*/
|
|
2700
|
+
cacheRange(startIndex, endIndex, dataFetcher, priority) {
|
|
2701
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
2702
|
+
if (!this.has(i)) {
|
|
2703
|
+
const data = dataFetcher(i);
|
|
2704
|
+
this.preemptiveCache(i, data, priority);
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
/**
|
|
2709
|
+
* Get memory usage estimate
|
|
2710
|
+
*/
|
|
2711
|
+
getMemoryUsage() {
|
|
2712
|
+
// Rough estimate based on cache size
|
|
2713
|
+
return this.cache.size * 1024; // Assume ~1KB per entry
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
/**
|
|
2718
|
+
* Intelligent Pagination
|
|
2719
|
+
* Adaptive page size with cursor-based pagination
|
|
2720
|
+
*/
|
|
2721
|
+
class IntelligentPagination {
|
|
2722
|
+
constructor() {
|
|
2723
|
+
this.currentPage = 1;
|
|
2724
|
+
this.basePageSize = 50;
|
|
2725
|
+
this.adaptivePageSize = 50;
|
|
2726
|
+
this.totalItems = 0;
|
|
2727
|
+
this.loadHistory = [];
|
|
2728
|
+
this.MIN_PAGE_SIZE = 20;
|
|
2729
|
+
this.MAX_PAGE_SIZE = 200;
|
|
2730
|
+
}
|
|
2731
|
+
/**
|
|
2732
|
+
* Get current pagination state
|
|
2733
|
+
*/
|
|
2734
|
+
getState() {
|
|
2735
|
+
const totalPages = Math.ceil(this.totalItems / this.adaptivePageSize);
|
|
2736
|
+
const hasMore = this.currentPage < totalPages;
|
|
2737
|
+
return {
|
|
2738
|
+
currentPage: this.currentPage,
|
|
2739
|
+
pageSize: this.adaptivePageSize,
|
|
2740
|
+
totalItems: this.totalItems,
|
|
2741
|
+
totalPages,
|
|
2742
|
+
hasMore,
|
|
2743
|
+
cursor: this.createCursor(this.currentPage),
|
|
2744
|
+
nextCursor: hasMore ? this.createCursor(this.currentPage + 1) : undefined,
|
|
2745
|
+
prevCursor: this.currentPage > 1 ? this.createCursor(this.currentPage - 1) : undefined
|
|
2746
|
+
};
|
|
2747
|
+
}
|
|
2748
|
+
/**
|
|
2749
|
+
* Set total items
|
|
2750
|
+
*/
|
|
2751
|
+
setTotalItems(total) {
|
|
2752
|
+
this.totalItems = total;
|
|
2753
|
+
}
|
|
2754
|
+
/**
|
|
2755
|
+
* Go to next page
|
|
2756
|
+
*/
|
|
2757
|
+
nextPage() {
|
|
2758
|
+
const state = this.getState();
|
|
2759
|
+
if (state.hasMore) {
|
|
2760
|
+
this.currentPage++;
|
|
2761
|
+
}
|
|
2762
|
+
return this.getState();
|
|
2763
|
+
}
|
|
2764
|
+
/**
|
|
2765
|
+
* Go to previous page
|
|
2766
|
+
*/
|
|
2767
|
+
prevPage() {
|
|
2768
|
+
if (this.currentPage > 1) {
|
|
2769
|
+
this.currentPage--;
|
|
2770
|
+
}
|
|
2771
|
+
return this.getState();
|
|
2772
|
+
}
|
|
2773
|
+
/**
|
|
2774
|
+
* Go to specific page
|
|
2775
|
+
*/
|
|
2776
|
+
goToPage(page) {
|
|
2777
|
+
const totalPages = Math.ceil(this.totalItems / this.adaptivePageSize);
|
|
2778
|
+
this.currentPage = Math.max(1, Math.min(page, totalPages));
|
|
2779
|
+
return this.getState();
|
|
2780
|
+
}
|
|
2781
|
+
/**
|
|
2782
|
+
* Record load time for adaptive sizing
|
|
2783
|
+
*/
|
|
2784
|
+
recordLoadTime(page, loadTimeMs) {
|
|
2785
|
+
this.loadHistory.push({ page, loadTime: loadTimeMs });
|
|
2786
|
+
// Keep last 10 load times
|
|
2787
|
+
if (this.loadHistory.length > 10) {
|
|
2788
|
+
this.loadHistory.shift();
|
|
2789
|
+
}
|
|
2790
|
+
// Adjust page size based on load time
|
|
2791
|
+
this.adaptPageSize();
|
|
2792
|
+
}
|
|
2793
|
+
/**
|
|
2794
|
+
* Adapt page size based on performance
|
|
2795
|
+
*/
|
|
2796
|
+
adaptPageSize() {
|
|
2797
|
+
if (this.loadHistory.length < 3)
|
|
2798
|
+
return;
|
|
2799
|
+
const avgLoadTime = this.loadHistory.reduce((a, b) => a.loadTime + b.loadTime, 0) / this.loadHistory.length;
|
|
2800
|
+
// Target: 100-300ms load time
|
|
2801
|
+
if (avgLoadTime < 100) {
|
|
2802
|
+
// Fast loads - increase page size
|
|
2803
|
+
this.adaptivePageSize = Math.min(this.MAX_PAGE_SIZE, Math.round(this.adaptivePageSize * 1.2));
|
|
2804
|
+
}
|
|
2805
|
+
else if (avgLoadTime > 300) {
|
|
2806
|
+
// Slow loads - decrease page size
|
|
2807
|
+
this.adaptivePageSize = Math.max(this.MIN_PAGE_SIZE, Math.round(this.adaptivePageSize * 0.8));
|
|
2808
|
+
}
|
|
2809
|
+
// Optimal load time - keep current size
|
|
2810
|
+
}
|
|
2811
|
+
/**
|
|
2812
|
+
* Create cursor for page
|
|
2813
|
+
*/
|
|
2814
|
+
createCursor(page) {
|
|
2815
|
+
const cursorData = {
|
|
2816
|
+
page,
|
|
2817
|
+
limit: this.adaptivePageSize,
|
|
2818
|
+
timestamp: Date.now()
|
|
2819
|
+
};
|
|
2820
|
+
// Add checksum for validation
|
|
2821
|
+
cursorData.checksum = this.calculateChecksum(cursorData);
|
|
2822
|
+
return Buffer.from(JSON.stringify(cursorData)).toString('base64');
|
|
2823
|
+
}
|
|
2824
|
+
/**
|
|
2825
|
+
* Decode cursor
|
|
2826
|
+
*/
|
|
2827
|
+
decodeCursor(cursor) {
|
|
2828
|
+
try {
|
|
2829
|
+
const decoded = JSON.parse(Buffer.from(cursor, 'base64').toString('utf-8'));
|
|
2830
|
+
// Validate checksum
|
|
2831
|
+
if (decoded.checksum && !this.validateChecksum(decoded)) {
|
|
2832
|
+
return null;
|
|
2833
|
+
}
|
|
2834
|
+
return decoded;
|
|
2835
|
+
}
|
|
2836
|
+
catch (_a) {
|
|
2837
|
+
return null;
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
/**
|
|
2841
|
+
* Go to page from cursor
|
|
2842
|
+
*/
|
|
2843
|
+
goToCursor(cursor) {
|
|
2844
|
+
const decoded = this.decodeCursor(cursor);
|
|
2845
|
+
if (decoded) {
|
|
2846
|
+
this.currentPage = decoded.page;
|
|
2847
|
+
this.adaptivePageSize = decoded.limit;
|
|
2848
|
+
}
|
|
2849
|
+
return this.getState();
|
|
2850
|
+
}
|
|
2851
|
+
/**
|
|
2852
|
+
* Calculate checksum for cursor validation
|
|
2853
|
+
*/
|
|
2854
|
+
calculateChecksum(data) {
|
|
2855
|
+
const str = `${data.page}-${data.limit}-${data.timestamp}`;
|
|
2856
|
+
let hash = 0;
|
|
2857
|
+
for (let i = 0; i < str.length; i++) {
|
|
2858
|
+
const char = str.charCodeAt(i);
|
|
2859
|
+
hash = ((hash << 5) - hash) + char;
|
|
2860
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
2861
|
+
}
|
|
2862
|
+
return hash.toString(36);
|
|
2863
|
+
}
|
|
2864
|
+
/**
|
|
2865
|
+
* Validate cursor checksum
|
|
2866
|
+
*/
|
|
2867
|
+
validateChecksum(data) {
|
|
2868
|
+
if (!data.checksum)
|
|
2869
|
+
return false;
|
|
2870
|
+
const { checksum, ...rest } = data;
|
|
2871
|
+
return this.calculateChecksum(rest) === checksum;
|
|
2872
|
+
}
|
|
2873
|
+
/**
|
|
2874
|
+
* Get items to fetch for current page
|
|
2875
|
+
*/
|
|
2876
|
+
getFetchRange() {
|
|
2877
|
+
return {
|
|
2878
|
+
skip: (this.currentPage - 1) * this.adaptivePageSize,
|
|
2879
|
+
limit: this.adaptivePageSize
|
|
2880
|
+
};
|
|
2881
|
+
}
|
|
2882
|
+
/**
|
|
2883
|
+
* Reset pagination
|
|
2884
|
+
*/
|
|
2885
|
+
reset() {
|
|
2886
|
+
this.currentPage = 1;
|
|
2887
|
+
this.adaptivePageSize = this.basePageSize;
|
|
2888
|
+
this.loadHistory = [];
|
|
2889
|
+
}
|
|
2890
|
+
/**
|
|
2891
|
+
* Get load history for analytics
|
|
2892
|
+
*/
|
|
2893
|
+
getLoadHistory() {
|
|
2894
|
+
return [...this.loadHistory];
|
|
2895
|
+
}
|
|
2896
|
+
/**
|
|
2897
|
+
* Get average load time
|
|
2898
|
+
*/
|
|
2899
|
+
getAverageLoadTime() {
|
|
2900
|
+
if (this.loadHistory.length === 0)
|
|
2901
|
+
return 0;
|
|
2902
|
+
return this.loadHistory.reduce((a, b) => a + b.loadTime, 0) / this.loadHistory.length;
|
|
2903
|
+
}
|
|
2904
|
+
/**
|
|
2905
|
+
* Set base page size
|
|
2906
|
+
*/
|
|
2907
|
+
setBasePageSize(size) {
|
|
2908
|
+
this.basePageSize = Math.max(this.MIN_PAGE_SIZE, Math.min(this.MAX_PAGE_SIZE, size));
|
|
2909
|
+
this.adaptivePageSize = this.basePageSize;
|
|
2910
|
+
}
|
|
2911
|
+
/**
|
|
2912
|
+
* Get current page size
|
|
2913
|
+
*/
|
|
2914
|
+
getPageSize() {
|
|
2915
|
+
return this.adaptivePageSize;
|
|
2916
|
+
}
|
|
2917
|
+
/**
|
|
2918
|
+
* Get current page number
|
|
2919
|
+
*/
|
|
2920
|
+
getCurrentPage() {
|
|
2921
|
+
return this.currentPage;
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
|
|
1389
2925
|
class ScrollObserver {
|
|
1390
2926
|
constructor(container, callback, options) {
|
|
1391
2927
|
this.observer = null;
|
|
@@ -1756,10 +3292,14 @@ const LazyScrollElement = typeof window !== 'undefined' && typeof HTMLElement !=
|
|
|
1756
3292
|
: LazyScrollElementClass; // SSR-safe fallback
|
|
1757
3293
|
|
|
1758
3294
|
exports.AdaptiveBufferCalculator = AdaptiveBufferCalculator;
|
|
3295
|
+
exports.BatchSizeOptimizer = BatchSizeOptimizer;
|
|
1759
3296
|
exports.ContentComplexityAnalyzer = ContentComplexityAnalyzer;
|
|
1760
3297
|
exports.DevicePerformanceMonitor = DevicePerformanceMonitor;
|
|
3298
|
+
exports.DynamicHeightEngine = DynamicHeightEngine;
|
|
1761
3299
|
exports.Engine = Engine;
|
|
1762
3300
|
exports.GPUAccelerator = GPUAccelerator;
|
|
3301
|
+
exports.HeightMeasurementCache = HeightMeasurementCache;
|
|
3302
|
+
exports.IntelligentPagination = IntelligentPagination;
|
|
1763
3303
|
exports.IntelligentScrollDetector = IntelligentScrollDetector;
|
|
1764
3304
|
exports.LazyList = LazyList;
|
|
1765
3305
|
exports.LazyScroll = LazyScroll;
|
|
@@ -1769,9 +3309,14 @@ exports.NetworkAwarePrefetchManager = NetworkAwarePrefetchManager;
|
|
|
1769
3309
|
exports.NetworkAwareRequestQueue = NetworkAwareRequestQueue;
|
|
1770
3310
|
exports.NetworkSpeedDetector = NetworkSpeedDetector;
|
|
1771
3311
|
exports.PerformanceOptimizer = PerformanceOptimizer;
|
|
3312
|
+
exports.PreemptiveCache = PreemptiveCache;
|
|
1772
3313
|
exports.PrefetchManager = PrefetchManager;
|
|
3314
|
+
exports.PriorityRequestQueue = PriorityRequestQueue;
|
|
3315
|
+
exports.RequestDeduplicator = RequestDeduplicator;
|
|
1773
3316
|
exports.RequestQueue = RequestQueue;
|
|
1774
3317
|
exports.ScrollObserver = ScrollObserver;
|
|
3318
|
+
exports.SmartPrefetchAlgorithm = SmartPrefetchAlgorithm;
|
|
3319
|
+
exports.VariableHeightManager = VariableHeightManager;
|
|
1775
3320
|
exports.WindowManager = WindowManager;
|
|
1776
3321
|
exports.createLazyScroll = createLazyScroll;
|
|
1777
3322
|
exports.debounce = debounce;
|