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
|
@@ -1236,6 +1236,380 @@ class GPUAccelerator {
|
|
|
1236
1236
|
}
|
|
1237
1237
|
}
|
|
1238
1238
|
|
|
1239
|
+
/**
|
|
1240
|
+
* Batch Size Optimizer
|
|
1241
|
+
* Dynamically adjusts batch size based on scroll speed, network, and performance
|
|
1242
|
+
*/
|
|
1243
|
+
class BatchSizeOptimizer {
|
|
1244
|
+
constructor(config, networkDetector, performanceMonitor) {
|
|
1245
|
+
this.scrollSpeedHistory = [];
|
|
1246
|
+
this.renderTimeHistory = [];
|
|
1247
|
+
this.HISTORY_SIZE = 10;
|
|
1248
|
+
this.config = {
|
|
1249
|
+
minBatchSize: (config === null || config === void 0 ? void 0 : config.minBatchSize) || 10,
|
|
1250
|
+
maxBatchSize: (config === null || config === void 0 ? void 0 : config.maxBatchSize) || 100,
|
|
1251
|
+
baseBatchSize: (config === null || config === void 0 ? void 0 : config.baseBatchSize) || 50,
|
|
1252
|
+
scrollSpeedThreshold: (config === null || config === void 0 ? void 0 : config.scrollSpeedThreshold) || 1.0
|
|
1253
|
+
};
|
|
1254
|
+
this.currentBatchSize = this.config.baseBatchSize;
|
|
1255
|
+
this.networkDetector = networkDetector || new NetworkSpeedDetector();
|
|
1256
|
+
this.performanceMonitor = performanceMonitor || new DevicePerformanceMonitor();
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Calculate optimal batch size based on all factors
|
|
1260
|
+
*/
|
|
1261
|
+
async calculateOptimalBatchSize(scrollSpeed) {
|
|
1262
|
+
// Track scroll speed history
|
|
1263
|
+
this.trackScrollSpeed(scrollSpeed);
|
|
1264
|
+
// Get network quality
|
|
1265
|
+
const networkQuality = await this.networkDetector.assessConnectionQuality();
|
|
1266
|
+
// Get performance score
|
|
1267
|
+
const performanceScore = await this.performanceMonitor.assessPerformance();
|
|
1268
|
+
// Calculate batch size based on scroll speed
|
|
1269
|
+
const speedMultiplier = this.calculateSpeedMultiplier(scrollSpeed);
|
|
1270
|
+
// Calculate batch size based on network
|
|
1271
|
+
const networkMultiplier = this.calculateNetworkMultiplier(networkQuality);
|
|
1272
|
+
// Calculate batch size based on performance
|
|
1273
|
+
const performanceMultiplier = this.calculatePerformanceMultiplier(performanceScore);
|
|
1274
|
+
// Calculate final batch size
|
|
1275
|
+
const optimalBatchSize = Math.round(this.config.baseBatchSize * speedMultiplier * networkMultiplier * performanceMultiplier);
|
|
1276
|
+
// Apply min/max bounds
|
|
1277
|
+
this.currentBatchSize = Math.max(this.config.minBatchSize, Math.min(this.config.maxBatchSize, optimalBatchSize));
|
|
1278
|
+
return this.currentBatchSize;
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Calculate multiplier based on scroll speed
|
|
1282
|
+
*/
|
|
1283
|
+
calculateSpeedMultiplier(scrollSpeed) {
|
|
1284
|
+
const avgScrollSpeed = this.getAverageScrollSpeed();
|
|
1285
|
+
// Fast scrolling = larger batches (preload more)
|
|
1286
|
+
if (Math.abs(avgScrollSpeed) > this.config.scrollSpeedThreshold * 2) {
|
|
1287
|
+
return 1.5; // 50% more items
|
|
1288
|
+
}
|
|
1289
|
+
else if (Math.abs(avgScrollSpeed) > this.config.scrollSpeedThreshold) {
|
|
1290
|
+
return 1.2; // 20% more items
|
|
1291
|
+
}
|
|
1292
|
+
else if (Math.abs(avgScrollSpeed) < 0.3) {
|
|
1293
|
+
return 0.8; // 20% fewer items (user reading carefully)
|
|
1294
|
+
}
|
|
1295
|
+
return 1.0; // Normal batch size
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Calculate multiplier based on network quality
|
|
1299
|
+
*/
|
|
1300
|
+
calculateNetworkMultiplier(quality) {
|
|
1301
|
+
switch (quality) {
|
|
1302
|
+
case 'excellent':
|
|
1303
|
+
return 1.3; // Load more on fast network
|
|
1304
|
+
case 'good':
|
|
1305
|
+
return 1.1; // Slightly more
|
|
1306
|
+
case 'poor':
|
|
1307
|
+
return 0.6; // Load less on slow network
|
|
1308
|
+
case 'offline':
|
|
1309
|
+
return 0.3; // Minimal loading when offline
|
|
1310
|
+
default:
|
|
1311
|
+
return 1.0;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Calculate multiplier based on device performance
|
|
1316
|
+
*/
|
|
1317
|
+
calculatePerformanceMultiplier(score) {
|
|
1318
|
+
// score is 0-1 (0 = poor, 1 = excellent)
|
|
1319
|
+
if (score > 0.8) {
|
|
1320
|
+
return 1.2; // High-performance device
|
|
1321
|
+
}
|
|
1322
|
+
else if (score > 0.5) {
|
|
1323
|
+
return 1.0; // Average device
|
|
1324
|
+
}
|
|
1325
|
+
else {
|
|
1326
|
+
return 0.7; // Low-performance device
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Track scroll speed for averaging
|
|
1331
|
+
*/
|
|
1332
|
+
trackScrollSpeed(speed) {
|
|
1333
|
+
this.scrollSpeedHistory.push(speed);
|
|
1334
|
+
if (this.scrollSpeedHistory.length > this.HISTORY_SIZE) {
|
|
1335
|
+
this.scrollSpeedHistory.shift();
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Get average scroll speed
|
|
1340
|
+
*/
|
|
1341
|
+
getAverageScrollSpeed() {
|
|
1342
|
+
if (this.scrollSpeedHistory.length === 0)
|
|
1343
|
+
return 0;
|
|
1344
|
+
const sum = this.scrollSpeedHistory.reduce((a, b) => a + b, 0);
|
|
1345
|
+
return sum / this.scrollSpeedHistory.length;
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Track render time for performance monitoring
|
|
1349
|
+
*/
|
|
1350
|
+
trackRenderTime(renderTime) {
|
|
1351
|
+
this.renderTimeHistory.push(renderTime);
|
|
1352
|
+
if (this.renderTimeHistory.length > this.HISTORY_SIZE) {
|
|
1353
|
+
this.renderTimeHistory.shift();
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Get average render time
|
|
1358
|
+
*/
|
|
1359
|
+
getAverageRenderTime() {
|
|
1360
|
+
if (this.renderTimeHistory.length === 0)
|
|
1361
|
+
return 0;
|
|
1362
|
+
const sum = this.renderTimeHistory.reduce((a, b) => a + b, 0);
|
|
1363
|
+
return sum / this.renderTimeHistory.length;
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Get current batch metrics
|
|
1367
|
+
*/
|
|
1368
|
+
getMetrics() {
|
|
1369
|
+
return {
|
|
1370
|
+
currentBatchSize: this.currentBatchSize,
|
|
1371
|
+
scrollSpeed: this.getAverageScrollSpeed(),
|
|
1372
|
+
networkQuality: 'good', // Would need to cache this
|
|
1373
|
+
performanceScore: 0.8, // Would need to cache this
|
|
1374
|
+
avgRenderTime: this.getAverageRenderTime()
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* Get current batch size
|
|
1379
|
+
*/
|
|
1380
|
+
getCurrentBatchSize() {
|
|
1381
|
+
return this.currentBatchSize;
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Reset optimizer
|
|
1385
|
+
*/
|
|
1386
|
+
reset() {
|
|
1387
|
+
this.scrollSpeedHistory = [];
|
|
1388
|
+
this.renderTimeHistory = [];
|
|
1389
|
+
this.currentBatchSize = this.config.baseBatchSize;
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Get optimization statistics
|
|
1393
|
+
*/
|
|
1394
|
+
getStats() {
|
|
1395
|
+
return {
|
|
1396
|
+
avgScrollSpeed: this.getAverageScrollSpeed(),
|
|
1397
|
+
avgRenderTime: this.getAverageRenderTime(),
|
|
1398
|
+
currentBatchSize: this.currentBatchSize,
|
|
1399
|
+
totalAdjustments: this.scrollSpeedHistory.length
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
/**
|
|
1405
|
+
* Request Deduplication
|
|
1406
|
+
* Prevents duplicate requests from being sent
|
|
1407
|
+
*/
|
|
1408
|
+
class RequestDeduplicator {
|
|
1409
|
+
constructor() {
|
|
1410
|
+
this.pendingRequests = new Map();
|
|
1411
|
+
this.requestCount = new Map();
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Execute request with deduplication
|
|
1415
|
+
* If same request is already pending, return existing promise
|
|
1416
|
+
*/
|
|
1417
|
+
async request(key, requestFn, ttl = 5000 // Time to live in ms
|
|
1418
|
+
) {
|
|
1419
|
+
// Check if same request is already pending
|
|
1420
|
+
if (this.pendingRequests.has(key)) {
|
|
1421
|
+
console.log(`[RequestDeduplicator] Deduplicating request: ${key}`);
|
|
1422
|
+
return this.pendingRequests.get(key);
|
|
1423
|
+
}
|
|
1424
|
+
// Create new request
|
|
1425
|
+
const promise = requestFn()
|
|
1426
|
+
.then(result => {
|
|
1427
|
+
this.pendingRequests.delete(key);
|
|
1428
|
+
this.requestCount.delete(key);
|
|
1429
|
+
return result;
|
|
1430
|
+
})
|
|
1431
|
+
.catch(error => {
|
|
1432
|
+
this.pendingRequests.delete(key);
|
|
1433
|
+
this.requestCount.delete(key);
|
|
1434
|
+
throw error;
|
|
1435
|
+
});
|
|
1436
|
+
// Store pending request
|
|
1437
|
+
this.pendingRequests.set(key, promise);
|
|
1438
|
+
// Track request count for analytics
|
|
1439
|
+
const count = this.requestCount.get(key) || 0;
|
|
1440
|
+
this.requestCount.set(key, count + 1);
|
|
1441
|
+
// Auto cleanup after TTL
|
|
1442
|
+
setTimeout(() => {
|
|
1443
|
+
if (this.pendingRequests.has(key)) {
|
|
1444
|
+
this.pendingRequests.delete(key);
|
|
1445
|
+
}
|
|
1446
|
+
}, ttl);
|
|
1447
|
+
return promise;
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* Clear specific request
|
|
1451
|
+
*/
|
|
1452
|
+
clear(key) {
|
|
1453
|
+
this.pendingRequests.delete(key);
|
|
1454
|
+
this.requestCount.delete(key);
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* Clear all requests
|
|
1458
|
+
*/
|
|
1459
|
+
clearAll() {
|
|
1460
|
+
this.pendingRequests.clear();
|
|
1461
|
+
this.requestCount.clear();
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Get pending request count
|
|
1465
|
+
*/
|
|
1466
|
+
getPendingCount() {
|
|
1467
|
+
return this.pendingRequests.size;
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* Get request statistics
|
|
1471
|
+
*/
|
|
1472
|
+
getStats() {
|
|
1473
|
+
const totalRequests = Array.from(this.requestCount.values()).reduce((a, b) => a + b, 0);
|
|
1474
|
+
const deduplicated = totalRequests - this.pendingRequests.size;
|
|
1475
|
+
return {
|
|
1476
|
+
pending: this.pendingRequests.size,
|
|
1477
|
+
totalRequests,
|
|
1478
|
+
deduplicationRate: totalRequests > 0 ? deduplicated / totalRequests : 0
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
/**
|
|
1484
|
+
* Priority-based Request Queue
|
|
1485
|
+
* Processes high-priority requests first
|
|
1486
|
+
*/
|
|
1487
|
+
var Priority;
|
|
1488
|
+
(function (Priority) {
|
|
1489
|
+
Priority[Priority["LOW"] = 0] = "LOW";
|
|
1490
|
+
Priority[Priority["NORMAL"] = 1] = "NORMAL";
|
|
1491
|
+
Priority[Priority["HIGH"] = 2] = "HIGH";
|
|
1492
|
+
Priority[Priority["CRITICAL"] = 3] = "CRITICAL";
|
|
1493
|
+
})(Priority || (Priority = {}));
|
|
1494
|
+
class PriorityRequestQueue {
|
|
1495
|
+
constructor(maxConcurrent = 2) {
|
|
1496
|
+
this.queues = new Map();
|
|
1497
|
+
this.processing = false;
|
|
1498
|
+
this.maxConcurrent = 2;
|
|
1499
|
+
this.activeRequests = 0;
|
|
1500
|
+
this.maxConcurrent = maxConcurrent;
|
|
1501
|
+
// Initialize priority queues
|
|
1502
|
+
Object.values(Priority).forEach(priority => {
|
|
1503
|
+
if (typeof priority === 'number') {
|
|
1504
|
+
this.queues.set(priority, []);
|
|
1505
|
+
}
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Add request with priority
|
|
1510
|
+
*/
|
|
1511
|
+
add(requestFn, priority = Priority.NORMAL) {
|
|
1512
|
+
return new Promise((resolve, reject) => {
|
|
1513
|
+
const request = {
|
|
1514
|
+
priority,
|
|
1515
|
+
requestFn: () => requestFn(),
|
|
1516
|
+
resolve,
|
|
1517
|
+
reject,
|
|
1518
|
+
timestamp: Date.now()
|
|
1519
|
+
};
|
|
1520
|
+
// Add to appropriate priority queue
|
|
1521
|
+
const queue = this.queues.get(priority) || [];
|
|
1522
|
+
queue.push(request);
|
|
1523
|
+
this.queues.set(priority, queue);
|
|
1524
|
+
// Start processing if not already processing
|
|
1525
|
+
if (!this.processing) {
|
|
1526
|
+
this.processQueue();
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Process queue by priority
|
|
1532
|
+
*/
|
|
1533
|
+
async processQueue() {
|
|
1534
|
+
if (this.processing)
|
|
1535
|
+
return;
|
|
1536
|
+
this.processing = true;
|
|
1537
|
+
while (this.hasPendingRequests() && this.activeRequests < this.maxConcurrent) {
|
|
1538
|
+
// Get highest priority request
|
|
1539
|
+
const request = this.getNextRequest();
|
|
1540
|
+
if (!request)
|
|
1541
|
+
break;
|
|
1542
|
+
this.activeRequests++;
|
|
1543
|
+
// Execute request
|
|
1544
|
+
request.requestFn()
|
|
1545
|
+
.then(request.resolve)
|
|
1546
|
+
.catch(request.reject)
|
|
1547
|
+
.finally(() => {
|
|
1548
|
+
this.activeRequests--;
|
|
1549
|
+
this.processQueue();
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
this.processing = false;
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Get next request by priority
|
|
1556
|
+
*/
|
|
1557
|
+
getNextRequest() {
|
|
1558
|
+
// Process from highest priority to lowest
|
|
1559
|
+
for (let priority = Priority.CRITICAL; priority >= Priority.LOW; priority--) {
|
|
1560
|
+
const queue = this.queues.get(priority);
|
|
1561
|
+
if (queue && queue.length > 0) {
|
|
1562
|
+
return queue.shift() || null;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
return null;
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Check if there are pending requests
|
|
1569
|
+
*/
|
|
1570
|
+
hasPendingRequests() {
|
|
1571
|
+
for (const queue of this.queues.values()) {
|
|
1572
|
+
if (queue.length > 0)
|
|
1573
|
+
return true;
|
|
1574
|
+
}
|
|
1575
|
+
return false;
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Get queue statistics
|
|
1579
|
+
*/
|
|
1580
|
+
getStats() {
|
|
1581
|
+
var _a, _b, _c, _d;
|
|
1582
|
+
const byPriority = {
|
|
1583
|
+
critical: ((_a = this.queues.get(Priority.CRITICAL)) === null || _a === void 0 ? void 0 : _a.length) || 0,
|
|
1584
|
+
high: ((_b = this.queues.get(Priority.HIGH)) === null || _b === void 0 ? void 0 : _b.length) || 0,
|
|
1585
|
+
normal: ((_c = this.queues.get(Priority.NORMAL)) === null || _c === void 0 ? void 0 : _c.length) || 0,
|
|
1586
|
+
low: ((_d = this.queues.get(Priority.LOW)) === null || _d === void 0 ? void 0 : _d.length) || 0
|
|
1587
|
+
};
|
|
1588
|
+
return {
|
|
1589
|
+
totalPending: Object.values(byPriority).reduce((a, b) => a + b, 0),
|
|
1590
|
+
byPriority,
|
|
1591
|
+
activeRequests: this.activeRequests
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Clear all queues
|
|
1596
|
+
*/
|
|
1597
|
+
clear() {
|
|
1598
|
+
this.queues.forEach(queue => queue.length = 0);
|
|
1599
|
+
this.processing = false;
|
|
1600
|
+
this.activeRequests = 0;
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Clear specific priority queue
|
|
1604
|
+
*/
|
|
1605
|
+
clearPriority(priority) {
|
|
1606
|
+
const queue = this.queues.get(priority);
|
|
1607
|
+
if (queue) {
|
|
1608
|
+
queue.length = 0;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1239
1613
|
class Engine {
|
|
1240
1614
|
constructor(config) {
|
|
1241
1615
|
this.fetchMoreCallback = null;
|
|
@@ -1254,6 +1628,9 @@ class Engine {
|
|
|
1254
1628
|
this.performanceOptimizer = new PerformanceOptimizer();
|
|
1255
1629
|
this.memoryManager = new MemoryManager(1000); // Cache up to 1000 items
|
|
1256
1630
|
this.gpuAccelerator = new GPUAccelerator();
|
|
1631
|
+
this.batchSizeOptimizer = new BatchSizeOptimizer();
|
|
1632
|
+
this.requestDeduplicator = new RequestDeduplicator();
|
|
1633
|
+
this.priorityRequestQueue = new PriorityRequestQueue(2);
|
|
1257
1634
|
this.totalItems = this.config.totalItems || Number.MAX_SAFE_INTEGER;
|
|
1258
1635
|
this.state = {
|
|
1259
1636
|
scrollTop: 0,
|
|
@@ -1514,5 +1891,1360 @@ const LazyList = forwardRef((props, ref) => {
|
|
|
1514
1891
|
});
|
|
1515
1892
|
LazyList.displayName = 'LazyList';
|
|
1516
1893
|
|
|
1517
|
-
|
|
1894
|
+
/**
|
|
1895
|
+
* Smart Prefetch Algorithm
|
|
1896
|
+
* Recognizes scroll patterns and predicts data loading needs
|
|
1897
|
+
*/
|
|
1898
|
+
class SmartPrefetchAlgorithm {
|
|
1899
|
+
constructor() {
|
|
1900
|
+
this.velocityHistory = [];
|
|
1901
|
+
this.directionHistory = [];
|
|
1902
|
+
this.HISTORY_SIZE = 20;
|
|
1903
|
+
this.lastPrefetchTime = 0;
|
|
1904
|
+
this.prefetchCooldown = 500; // ms
|
|
1905
|
+
}
|
|
1906
|
+
/**
|
|
1907
|
+
* Analyze scroll pattern
|
|
1908
|
+
*/
|
|
1909
|
+
analyzeScrollPattern(velocity, acceleration, direction) {
|
|
1910
|
+
this.trackVelocity(velocity);
|
|
1911
|
+
this.trackDirection(direction);
|
|
1912
|
+
const avgVelocity = this.getAverageVelocity();
|
|
1913
|
+
const velocityVariance = this.getVelocityVariance();
|
|
1914
|
+
const directionChanges = this.countDirectionChanges();
|
|
1915
|
+
// Determine pattern type
|
|
1916
|
+
let pattern;
|
|
1917
|
+
if (Math.abs(avgVelocity) > 2.0) {
|
|
1918
|
+
pattern = {
|
|
1919
|
+
type: 'fast-scroll',
|
|
1920
|
+
velocity: avgVelocity,
|
|
1921
|
+
acceleration,
|
|
1922
|
+
direction,
|
|
1923
|
+
confidence: 0.9
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
else if (Math.abs(avgVelocity) < 0.3) {
|
|
1927
|
+
pattern = {
|
|
1928
|
+
type: 'paused',
|
|
1929
|
+
velocity: avgVelocity,
|
|
1930
|
+
acceleration,
|
|
1931
|
+
direction: 'stationary',
|
|
1932
|
+
confidence: 0.95
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
else if (directionChanges > 5) {
|
|
1936
|
+
pattern = {
|
|
1937
|
+
type: 'oscillating',
|
|
1938
|
+
velocity: avgVelocity,
|
|
1939
|
+
acceleration,
|
|
1940
|
+
direction,
|
|
1941
|
+
confidence: 0.85
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
else if (velocityVariance < 0.5) {
|
|
1945
|
+
pattern = {
|
|
1946
|
+
type: 'steady',
|
|
1947
|
+
velocity: avgVelocity,
|
|
1948
|
+
acceleration,
|
|
1949
|
+
direction,
|
|
1950
|
+
confidence: 0.9
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
else {
|
|
1954
|
+
pattern = {
|
|
1955
|
+
type: 'slow-scroll',
|
|
1956
|
+
velocity: avgVelocity,
|
|
1957
|
+
acceleration,
|
|
1958
|
+
direction,
|
|
1959
|
+
confidence: 0.8
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
return pattern;
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Predict prefetch needs based on scroll pattern
|
|
1966
|
+
*/
|
|
1967
|
+
predictPrefetchNeeds(pattern, visibleEnd, totalLoaded) {
|
|
1968
|
+
const now = Date.now();
|
|
1969
|
+
// Check cooldown
|
|
1970
|
+
if (now - this.lastPrefetchTime < this.prefetchCooldown) {
|
|
1971
|
+
return {
|
|
1972
|
+
shouldPrefetch: false,
|
|
1973
|
+
prefetchDistance: 0,
|
|
1974
|
+
batchSize: 0,
|
|
1975
|
+
priority: 'low',
|
|
1976
|
+
confidence: 1.0
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1979
|
+
let prediction;
|
|
1980
|
+
switch (pattern.type) {
|
|
1981
|
+
case 'fast-scroll':
|
|
1982
|
+
prediction = {
|
|
1983
|
+
shouldPrefetch: true,
|
|
1984
|
+
prefetchDistance: 1500, // Far ahead for fast scrolling
|
|
1985
|
+
batchSize: 30, // Large batch
|
|
1986
|
+
priority: 'critical',
|
|
1987
|
+
confidence: pattern.confidence
|
|
1988
|
+
};
|
|
1989
|
+
break;
|
|
1990
|
+
case 'steady':
|
|
1991
|
+
prediction = {
|
|
1992
|
+
shouldPrefetch: visibleEnd >= totalLoaded - 800,
|
|
1993
|
+
prefetchDistance: 800,
|
|
1994
|
+
batchSize: 20,
|
|
1995
|
+
priority: 'high',
|
|
1996
|
+
confidence: pattern.confidence
|
|
1997
|
+
};
|
|
1998
|
+
break;
|
|
1999
|
+
case 'slow-scroll':
|
|
2000
|
+
prediction = {
|
|
2001
|
+
shouldPrefetch: visibleEnd >= totalLoaded - 400,
|
|
2002
|
+
prefetchDistance: 400,
|
|
2003
|
+
batchSize: 10,
|
|
2004
|
+
priority: 'normal',
|
|
2005
|
+
confidence: pattern.confidence
|
|
2006
|
+
};
|
|
2007
|
+
break;
|
|
2008
|
+
case 'oscillating':
|
|
2009
|
+
prediction = {
|
|
2010
|
+
shouldPrefetch: visibleEnd >= totalLoaded - 600,
|
|
2011
|
+
prefetchDistance: 600,
|
|
2012
|
+
batchSize: 15,
|
|
2013
|
+
priority: 'normal',
|
|
2014
|
+
confidence: pattern.confidence * 0.8 // Lower confidence for oscillating
|
|
2015
|
+
};
|
|
2016
|
+
break;
|
|
2017
|
+
case 'paused':
|
|
2018
|
+
prediction = {
|
|
2019
|
+
shouldPrefetch: false, // User paused, no need to prefetch
|
|
2020
|
+
prefetchDistance: 0,
|
|
2021
|
+
batchSize: 0,
|
|
2022
|
+
priority: 'low',
|
|
2023
|
+
confidence: pattern.confidence
|
|
2024
|
+
};
|
|
2025
|
+
break;
|
|
2026
|
+
default:
|
|
2027
|
+
prediction = {
|
|
2028
|
+
shouldPrefetch: visibleEnd >= totalLoaded - 500,
|
|
2029
|
+
prefetchDistance: 500,
|
|
2030
|
+
batchSize: 15,
|
|
2031
|
+
priority: 'normal',
|
|
2032
|
+
confidence: 0.7
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
// Update last prefetch time if prefetching
|
|
2036
|
+
if (prediction.shouldPrefetch) {
|
|
2037
|
+
this.lastPrefetchTime = now;
|
|
2038
|
+
}
|
|
2039
|
+
return prediction;
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Track velocity history
|
|
2043
|
+
*/
|
|
2044
|
+
trackVelocity(velocity) {
|
|
2045
|
+
this.velocityHistory.push(velocity);
|
|
2046
|
+
if (this.velocityHistory.length > this.HISTORY_SIZE) {
|
|
2047
|
+
this.velocityHistory.shift();
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
/**
|
|
2051
|
+
* Track direction history
|
|
2052
|
+
*/
|
|
2053
|
+
trackDirection(direction) {
|
|
2054
|
+
this.directionHistory.push(direction);
|
|
2055
|
+
if (this.directionHistory.length > this.HISTORY_SIZE) {
|
|
2056
|
+
this.directionHistory.shift();
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Get average velocity
|
|
2061
|
+
*/
|
|
2062
|
+
getAverageVelocity() {
|
|
2063
|
+
if (this.velocityHistory.length === 0)
|
|
2064
|
+
return 0;
|
|
2065
|
+
const sum = this.velocityHistory.reduce((a, b) => a + b, 0);
|
|
2066
|
+
return sum / this.velocityHistory.length;
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* Get velocity variance
|
|
2070
|
+
*/
|
|
2071
|
+
getVelocityVariance() {
|
|
2072
|
+
if (this.velocityHistory.length < 2)
|
|
2073
|
+
return 0;
|
|
2074
|
+
const avg = this.getAverageVelocity();
|
|
2075
|
+
const squaredDiffs = this.velocityHistory.map(v => Math.pow(v - avg, 2));
|
|
2076
|
+
const avgSquaredDiff = squaredDiffs.reduce((a, b) => a + b, 0) / squaredDiffs.length;
|
|
2077
|
+
return Math.sqrt(avgSquaredDiff);
|
|
2078
|
+
}
|
|
2079
|
+
/**
|
|
2080
|
+
* Count direction changes
|
|
2081
|
+
*/
|
|
2082
|
+
countDirectionChanges() {
|
|
2083
|
+
if (this.directionHistory.length < 2)
|
|
2084
|
+
return 0;
|
|
2085
|
+
let changes = 0;
|
|
2086
|
+
for (let i = 1; i < this.directionHistory.length; i++) {
|
|
2087
|
+
if (this.directionHistory[i] !== this.directionHistory[i - 1] &&
|
|
2088
|
+
this.directionHistory[i] !== 'stationary' &&
|
|
2089
|
+
this.directionHistory[i - 1] !== 'stationary') {
|
|
2090
|
+
changes++;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
return changes;
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* Reset history
|
|
2097
|
+
*/
|
|
2098
|
+
reset() {
|
|
2099
|
+
this.velocityHistory = [];
|
|
2100
|
+
this.directionHistory = [];
|
|
2101
|
+
this.lastPrefetchTime = 0;
|
|
2102
|
+
}
|
|
2103
|
+
/**
|
|
2104
|
+
* Get prediction confidence
|
|
2105
|
+
*/
|
|
2106
|
+
getConfidence() {
|
|
2107
|
+
if (this.velocityHistory.length < 5)
|
|
2108
|
+
return 0.5; // Not enough data
|
|
2109
|
+
return Math.min(this.velocityHistory.length / this.HISTORY_SIZE, 1.0);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
/**
|
|
2114
|
+
* Preemptive Caching
|
|
2115
|
+
* Caches data before it's needed based on predictions
|
|
2116
|
+
*/
|
|
2117
|
+
class PreemptiveCache {
|
|
2118
|
+
constructor(config) {
|
|
2119
|
+
this.cache = new Map();
|
|
2120
|
+
this.accessHistory = [];
|
|
2121
|
+
this.config = {
|
|
2122
|
+
maxSize: (config === null || config === void 0 ? void 0 : config.maxSize) || 1000,
|
|
2123
|
+
defaultTTL: (config === null || config === void 0 ? void 0 : config.defaultTTL) || 300000, // 5 minutes
|
|
2124
|
+
cleanupThreshold: (config === null || config === void 0 ? void 0 : config.cleanupThreshold) || 800
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Preemptively cache data with priority
|
|
2129
|
+
*/
|
|
2130
|
+
preemptiveCache(index, data, priority = 'normal') {
|
|
2131
|
+
// Check if we need to cleanup
|
|
2132
|
+
if (this.cache.size >= this.config.cleanupThreshold) {
|
|
2133
|
+
this.cleanup();
|
|
2134
|
+
}
|
|
2135
|
+
const entry = {
|
|
2136
|
+
data,
|
|
2137
|
+
timestamp: Date.now(),
|
|
2138
|
+
priority,
|
|
2139
|
+
accessCount: 0,
|
|
2140
|
+
expiry: Date.now() + this.config.defaultTTL
|
|
2141
|
+
};
|
|
2142
|
+
this.cache.set(index, entry);
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* Get cached data
|
|
2146
|
+
*/
|
|
2147
|
+
get(index) {
|
|
2148
|
+
const entry = this.cache.get(index);
|
|
2149
|
+
if (!entry) {
|
|
2150
|
+
return null;
|
|
2151
|
+
}
|
|
2152
|
+
// Check expiry
|
|
2153
|
+
if (Date.now() > entry.expiry) {
|
|
2154
|
+
this.cache.delete(index);
|
|
2155
|
+
return null;
|
|
2156
|
+
}
|
|
2157
|
+
// Update access count
|
|
2158
|
+
entry.accessCount++;
|
|
2159
|
+
this.trackAccess(index);
|
|
2160
|
+
return entry.data;
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* Check if data is cached
|
|
2164
|
+
*/
|
|
2165
|
+
has(index) {
|
|
2166
|
+
const entry = this.cache.get(index);
|
|
2167
|
+
if (!entry)
|
|
2168
|
+
return false;
|
|
2169
|
+
// Check expiry
|
|
2170
|
+
if (Date.now() > entry.expiry) {
|
|
2171
|
+
this.cache.delete(index);
|
|
2172
|
+
return false;
|
|
2173
|
+
}
|
|
2174
|
+
return true;
|
|
2175
|
+
}
|
|
2176
|
+
/**
|
|
2177
|
+
* Get cached data for range
|
|
2178
|
+
*/
|
|
2179
|
+
getRange(startIndex, endIndex) {
|
|
2180
|
+
const results = [];
|
|
2181
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
2182
|
+
const data = this.get(i);
|
|
2183
|
+
if (data !== null) {
|
|
2184
|
+
results.push(data);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
return results;
|
|
2188
|
+
}
|
|
2189
|
+
/**
|
|
2190
|
+
* Delete cached data
|
|
2191
|
+
*/
|
|
2192
|
+
delete(index) {
|
|
2193
|
+
return this.cache.delete(index);
|
|
2194
|
+
}
|
|
2195
|
+
/**
|
|
2196
|
+
* Clear cache
|
|
2197
|
+
*/
|
|
2198
|
+
clear() {
|
|
2199
|
+
this.cache.clear();
|
|
2200
|
+
this.accessHistory = [];
|
|
2201
|
+
}
|
|
2202
|
+
/**
|
|
2203
|
+
* Cleanup old/low-priority entries
|
|
2204
|
+
*/
|
|
2205
|
+
cleanup() {
|
|
2206
|
+
const now = Date.now();
|
|
2207
|
+
const toDelete = [];
|
|
2208
|
+
// First pass: remove expired entries
|
|
2209
|
+
this.cache.forEach((entry, index) => {
|
|
2210
|
+
if (now > entry.expiry) {
|
|
2211
|
+
toDelete.push(index);
|
|
2212
|
+
}
|
|
2213
|
+
});
|
|
2214
|
+
// Second pass: remove low-priority entries if still over limit
|
|
2215
|
+
if (this.cache.size - toDelete.length > this.config.maxSize) {
|
|
2216
|
+
const sortedByPriority = Array.from(this.cache.entries())
|
|
2217
|
+
.filter(([index]) => !toDelete.includes(index))
|
|
2218
|
+
.sort((a, b) => {
|
|
2219
|
+
const priorityOrder = { critical: 4, high: 3, normal: 2, low: 1 };
|
|
2220
|
+
return priorityOrder[a[1].priority] - priorityOrder[b[1].priority];
|
|
2221
|
+
});
|
|
2222
|
+
// Remove lowest priority entries
|
|
2223
|
+
const toRemove = Math.ceil(sortedByPriority.length * 0.2); // Remove 20%
|
|
2224
|
+
for (let i = 0; i < toRemove; i++) {
|
|
2225
|
+
toDelete.push(sortedByPriority[i][0]);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
// Delete marked entries
|
|
2229
|
+
toDelete.forEach(index => this.cache.delete(index));
|
|
2230
|
+
}
|
|
2231
|
+
/**
|
|
2232
|
+
* Track access for analytics
|
|
2233
|
+
*/
|
|
2234
|
+
trackAccess(index) {
|
|
2235
|
+
this.accessHistory.push(index);
|
|
2236
|
+
if (this.accessHistory.length > 100) {
|
|
2237
|
+
this.accessHistory.shift();
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Get cache statistics
|
|
2242
|
+
*/
|
|
2243
|
+
getStats() {
|
|
2244
|
+
const byPriority = {
|
|
2245
|
+
critical: 0,
|
|
2246
|
+
high: 0,
|
|
2247
|
+
normal: 0,
|
|
2248
|
+
low: 0
|
|
2249
|
+
};
|
|
2250
|
+
let totalAccessCount = 0;
|
|
2251
|
+
this.cache.forEach(entry => {
|
|
2252
|
+
byPriority[entry.priority]++;
|
|
2253
|
+
totalAccessCount += entry.accessCount;
|
|
2254
|
+
});
|
|
2255
|
+
return {
|
|
2256
|
+
size: this.cache.size,
|
|
2257
|
+
maxSize: this.config.maxSize,
|
|
2258
|
+
hitRate: this.accessHistory.length > 0 ?
|
|
2259
|
+
this.accessHistory.filter(i => this.has(i)).length / this.accessHistory.length : 0,
|
|
2260
|
+
avgAccessCount: this.cache.size > 0 ? totalAccessCount / this.cache.size : 0,
|
|
2261
|
+
byPriority
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
/**
|
|
2265
|
+
* Get all cached indices
|
|
2266
|
+
*/
|
|
2267
|
+
getCachedIndices() {
|
|
2268
|
+
return Array.from(this.cache.keys());
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* Preemptively cache range
|
|
2272
|
+
*/
|
|
2273
|
+
cacheRange(startIndex, endIndex, dataFetcher, priority) {
|
|
2274
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
2275
|
+
if (!this.has(i)) {
|
|
2276
|
+
const data = dataFetcher(i);
|
|
2277
|
+
this.preemptiveCache(i, data, priority);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
/**
|
|
2282
|
+
* Get memory usage estimate
|
|
2283
|
+
*/
|
|
2284
|
+
getMemoryUsage() {
|
|
2285
|
+
// Rough estimate based on cache size
|
|
2286
|
+
return this.cache.size * 1024; // Assume ~1KB per entry
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
/**
|
|
2291
|
+
* Intelligent Pagination
|
|
2292
|
+
* Adaptive page size with cursor-based pagination
|
|
2293
|
+
*/
|
|
2294
|
+
class IntelligentPagination {
|
|
2295
|
+
constructor() {
|
|
2296
|
+
this.currentPage = 1;
|
|
2297
|
+
this.basePageSize = 50;
|
|
2298
|
+
this.adaptivePageSize = 50;
|
|
2299
|
+
this.totalItems = 0;
|
|
2300
|
+
this.loadHistory = [];
|
|
2301
|
+
this.MIN_PAGE_SIZE = 20;
|
|
2302
|
+
this.MAX_PAGE_SIZE = 200;
|
|
2303
|
+
}
|
|
2304
|
+
/**
|
|
2305
|
+
* Get current pagination state
|
|
2306
|
+
*/
|
|
2307
|
+
getState() {
|
|
2308
|
+
const totalPages = Math.ceil(this.totalItems / this.adaptivePageSize);
|
|
2309
|
+
const hasMore = this.currentPage < totalPages;
|
|
2310
|
+
return {
|
|
2311
|
+
currentPage: this.currentPage,
|
|
2312
|
+
pageSize: this.adaptivePageSize,
|
|
2313
|
+
totalItems: this.totalItems,
|
|
2314
|
+
totalPages,
|
|
2315
|
+
hasMore,
|
|
2316
|
+
cursor: this.createCursor(this.currentPage),
|
|
2317
|
+
nextCursor: hasMore ? this.createCursor(this.currentPage + 1) : undefined,
|
|
2318
|
+
prevCursor: this.currentPage > 1 ? this.createCursor(this.currentPage - 1) : undefined
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
/**
|
|
2322
|
+
* Set total items
|
|
2323
|
+
*/
|
|
2324
|
+
setTotalItems(total) {
|
|
2325
|
+
this.totalItems = total;
|
|
2326
|
+
}
|
|
2327
|
+
/**
|
|
2328
|
+
* Go to next page
|
|
2329
|
+
*/
|
|
2330
|
+
nextPage() {
|
|
2331
|
+
const state = this.getState();
|
|
2332
|
+
if (state.hasMore) {
|
|
2333
|
+
this.currentPage++;
|
|
2334
|
+
}
|
|
2335
|
+
return this.getState();
|
|
2336
|
+
}
|
|
2337
|
+
/**
|
|
2338
|
+
* Go to previous page
|
|
2339
|
+
*/
|
|
2340
|
+
prevPage() {
|
|
2341
|
+
if (this.currentPage > 1) {
|
|
2342
|
+
this.currentPage--;
|
|
2343
|
+
}
|
|
2344
|
+
return this.getState();
|
|
2345
|
+
}
|
|
2346
|
+
/**
|
|
2347
|
+
* Go to specific page
|
|
2348
|
+
*/
|
|
2349
|
+
goToPage(page) {
|
|
2350
|
+
const totalPages = Math.ceil(this.totalItems / this.adaptivePageSize);
|
|
2351
|
+
this.currentPage = Math.max(1, Math.min(page, totalPages));
|
|
2352
|
+
return this.getState();
|
|
2353
|
+
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Record load time for adaptive sizing
|
|
2356
|
+
*/
|
|
2357
|
+
recordLoadTime(page, loadTimeMs) {
|
|
2358
|
+
this.loadHistory.push({ page, loadTime: loadTimeMs });
|
|
2359
|
+
// Keep last 10 load times
|
|
2360
|
+
if (this.loadHistory.length > 10) {
|
|
2361
|
+
this.loadHistory.shift();
|
|
2362
|
+
}
|
|
2363
|
+
// Adjust page size based on load time
|
|
2364
|
+
this.adaptPageSize();
|
|
2365
|
+
}
|
|
2366
|
+
/**
|
|
2367
|
+
* Adapt page size based on performance
|
|
2368
|
+
*/
|
|
2369
|
+
adaptPageSize() {
|
|
2370
|
+
if (this.loadHistory.length < 3)
|
|
2371
|
+
return;
|
|
2372
|
+
const avgLoadTime = this.loadHistory.reduce((a, b) => a.loadTime + b.loadTime, 0) / this.loadHistory.length;
|
|
2373
|
+
// Target: 100-300ms load time
|
|
2374
|
+
if (avgLoadTime < 100) {
|
|
2375
|
+
// Fast loads - increase page size
|
|
2376
|
+
this.adaptivePageSize = Math.min(this.MAX_PAGE_SIZE, Math.round(this.adaptivePageSize * 1.2));
|
|
2377
|
+
}
|
|
2378
|
+
else if (avgLoadTime > 300) {
|
|
2379
|
+
// Slow loads - decrease page size
|
|
2380
|
+
this.adaptivePageSize = Math.max(this.MIN_PAGE_SIZE, Math.round(this.adaptivePageSize * 0.8));
|
|
2381
|
+
}
|
|
2382
|
+
// Optimal load time - keep current size
|
|
2383
|
+
}
|
|
2384
|
+
/**
|
|
2385
|
+
* Create cursor for page
|
|
2386
|
+
*/
|
|
2387
|
+
createCursor(page) {
|
|
2388
|
+
const cursorData = {
|
|
2389
|
+
page,
|
|
2390
|
+
limit: this.adaptivePageSize,
|
|
2391
|
+
timestamp: Date.now()
|
|
2392
|
+
};
|
|
2393
|
+
// Add checksum for validation
|
|
2394
|
+
cursorData.checksum = this.calculateChecksum(cursorData);
|
|
2395
|
+
return Buffer.from(JSON.stringify(cursorData)).toString('base64');
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Decode cursor
|
|
2399
|
+
*/
|
|
2400
|
+
decodeCursor(cursor) {
|
|
2401
|
+
try {
|
|
2402
|
+
const decoded = JSON.parse(Buffer.from(cursor, 'base64').toString('utf-8'));
|
|
2403
|
+
// Validate checksum
|
|
2404
|
+
if (decoded.checksum && !this.validateChecksum(decoded)) {
|
|
2405
|
+
return null;
|
|
2406
|
+
}
|
|
2407
|
+
return decoded;
|
|
2408
|
+
}
|
|
2409
|
+
catch (_a) {
|
|
2410
|
+
return null;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
/**
|
|
2414
|
+
* Go to page from cursor
|
|
2415
|
+
*/
|
|
2416
|
+
goToCursor(cursor) {
|
|
2417
|
+
const decoded = this.decodeCursor(cursor);
|
|
2418
|
+
if (decoded) {
|
|
2419
|
+
this.currentPage = decoded.page;
|
|
2420
|
+
this.adaptivePageSize = decoded.limit;
|
|
2421
|
+
}
|
|
2422
|
+
return this.getState();
|
|
2423
|
+
}
|
|
2424
|
+
/**
|
|
2425
|
+
* Calculate checksum for cursor validation
|
|
2426
|
+
*/
|
|
2427
|
+
calculateChecksum(data) {
|
|
2428
|
+
const str = `${data.page}-${data.limit}-${data.timestamp}`;
|
|
2429
|
+
let hash = 0;
|
|
2430
|
+
for (let i = 0; i < str.length; i++) {
|
|
2431
|
+
const char = str.charCodeAt(i);
|
|
2432
|
+
hash = ((hash << 5) - hash) + char;
|
|
2433
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
2434
|
+
}
|
|
2435
|
+
return hash.toString(36);
|
|
2436
|
+
}
|
|
2437
|
+
/**
|
|
2438
|
+
* Validate cursor checksum
|
|
2439
|
+
*/
|
|
2440
|
+
validateChecksum(data) {
|
|
2441
|
+
if (!data.checksum)
|
|
2442
|
+
return false;
|
|
2443
|
+
const { checksum, ...rest } = data;
|
|
2444
|
+
return this.calculateChecksum(rest) === checksum;
|
|
2445
|
+
}
|
|
2446
|
+
/**
|
|
2447
|
+
* Get items to fetch for current page
|
|
2448
|
+
*/
|
|
2449
|
+
getFetchRange() {
|
|
2450
|
+
return {
|
|
2451
|
+
skip: (this.currentPage - 1) * this.adaptivePageSize,
|
|
2452
|
+
limit: this.adaptivePageSize
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
2455
|
+
/**
|
|
2456
|
+
* Reset pagination
|
|
2457
|
+
*/
|
|
2458
|
+
reset() {
|
|
2459
|
+
this.currentPage = 1;
|
|
2460
|
+
this.adaptivePageSize = this.basePageSize;
|
|
2461
|
+
this.loadHistory = [];
|
|
2462
|
+
}
|
|
2463
|
+
/**
|
|
2464
|
+
* Get load history for analytics
|
|
2465
|
+
*/
|
|
2466
|
+
getLoadHistory() {
|
|
2467
|
+
return [...this.loadHistory];
|
|
2468
|
+
}
|
|
2469
|
+
/**
|
|
2470
|
+
* Get average load time
|
|
2471
|
+
*/
|
|
2472
|
+
getAverageLoadTime() {
|
|
2473
|
+
if (this.loadHistory.length === 0)
|
|
2474
|
+
return 0;
|
|
2475
|
+
return this.loadHistory.reduce((a, b) => a + b.loadTime, 0) / this.loadHistory.length;
|
|
2476
|
+
}
|
|
2477
|
+
/**
|
|
2478
|
+
* Set base page size
|
|
2479
|
+
*/
|
|
2480
|
+
setBasePageSize(size) {
|
|
2481
|
+
this.basePageSize = Math.max(this.MIN_PAGE_SIZE, Math.min(this.MAX_PAGE_SIZE, size));
|
|
2482
|
+
this.adaptivePageSize = this.basePageSize;
|
|
2483
|
+
}
|
|
2484
|
+
/**
|
|
2485
|
+
* Get current page size
|
|
2486
|
+
*/
|
|
2487
|
+
getPageSize() {
|
|
2488
|
+
return this.adaptivePageSize;
|
|
2489
|
+
}
|
|
2490
|
+
/**
|
|
2491
|
+
* Get current page number
|
|
2492
|
+
*/
|
|
2493
|
+
getCurrentPage() {
|
|
2494
|
+
return this.currentPage;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
const useIntelligentScroll = (config) => {
|
|
2499
|
+
const { itemHeight = 50, viewportHeight = 400, bufferSize = 5, fetchMore, enablePrefetch = true, enableCache = true, cacheSize = 1000 } = config;
|
|
2500
|
+
const engineRef = useRef(null);
|
|
2501
|
+
const prefetchAlgoRef = useRef(null);
|
|
2502
|
+
const cacheRef = useRef(null);
|
|
2503
|
+
const paginationRef = useRef(null);
|
|
2504
|
+
const containerRef = useRef(null);
|
|
2505
|
+
const [state, setState] = useState({
|
|
2506
|
+
visibleRange: { start: 0, end: 0 },
|
|
2507
|
+
isLoading: false,
|
|
2508
|
+
scrollVelocity: 0,
|
|
2509
|
+
scrollDirection: 'stationary',
|
|
2510
|
+
scrollPattern: 'paused',
|
|
2511
|
+
prefetchConfidence: 0,
|
|
2512
|
+
cacheHitRate: 0,
|
|
2513
|
+
totalItems: 0
|
|
2514
|
+
});
|
|
2515
|
+
// Initialize intelligent scroll system
|
|
2516
|
+
useEffect(() => {
|
|
2517
|
+
engineRef.current = new Engine({
|
|
2518
|
+
itemHeight,
|
|
2519
|
+
viewportHeight,
|
|
2520
|
+
bufferSize
|
|
2521
|
+
});
|
|
2522
|
+
engineRef.current.setFetchMoreCallback(fetchMore);
|
|
2523
|
+
prefetchAlgoRef.current = new SmartPrefetchAlgorithm();
|
|
2524
|
+
if (enableCache) {
|
|
2525
|
+
cacheRef.current = new PreemptiveCache({ maxSize: cacheSize });
|
|
2526
|
+
}
|
|
2527
|
+
paginationRef.current = new IntelligentPagination();
|
|
2528
|
+
return () => {
|
|
2529
|
+
if (engineRef.current) {
|
|
2530
|
+
engineRef.current.cleanup();
|
|
2531
|
+
}
|
|
2532
|
+
if (cacheRef.current) {
|
|
2533
|
+
cacheRef.current.clear();
|
|
2534
|
+
}
|
|
2535
|
+
};
|
|
2536
|
+
}, []);
|
|
2537
|
+
// Handle scroll events with intelligent analysis
|
|
2538
|
+
const handleScroll = useCallback((scrollTop) => {
|
|
2539
|
+
if (!engineRef.current || !prefetchAlgoRef.current)
|
|
2540
|
+
return;
|
|
2541
|
+
// Update engine
|
|
2542
|
+
engineRef.current.updateScrollPosition(scrollTop);
|
|
2543
|
+
const engineState = engineRef.current.getState();
|
|
2544
|
+
// Analyze scroll pattern
|
|
2545
|
+
const velocity = scrollTop - (engineState.scrollTop || 0);
|
|
2546
|
+
const direction = velocity > 0 ? 'down' : velocity < 0 ? 'up' : 'stationary';
|
|
2547
|
+
const pattern = prefetchAlgoRef.current.analyzeScrollPattern(velocity, 0, // acceleration (would need more tracking)
|
|
2548
|
+
direction);
|
|
2549
|
+
// Update cache stats
|
|
2550
|
+
let cacheHitRate = 0;
|
|
2551
|
+
if (cacheRef.current) {
|
|
2552
|
+
const stats = cacheRef.current.getStats();
|
|
2553
|
+
cacheHitRate = stats.hitRate;
|
|
2554
|
+
}
|
|
2555
|
+
// Update state
|
|
2556
|
+
setState(prev => ({
|
|
2557
|
+
...prev,
|
|
2558
|
+
visibleRange: engineState.visibleRange,
|
|
2559
|
+
isLoading: engineState.isLoading,
|
|
2560
|
+
scrollVelocity: velocity,
|
|
2561
|
+
scrollDirection: direction,
|
|
2562
|
+
scrollPattern: pattern.type,
|
|
2563
|
+
prefetchConfidence: pattern.confidence,
|
|
2564
|
+
cacheHitRate
|
|
2565
|
+
}));
|
|
2566
|
+
// Predict and prefetch if needed
|
|
2567
|
+
if (enablePrefetch && prefetchAlgoRef.current) {
|
|
2568
|
+
const prediction = prefetchAlgoRef.current.predictPrefetchNeeds(pattern, engineState.visibleRange.end, engineState.loadedItems);
|
|
2569
|
+
if (prediction.shouldPrefetch && cacheRef.current) {
|
|
2570
|
+
// Preemptive caching would happen here
|
|
2571
|
+
console.log('Prefetching with priority:', prediction.priority);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
}, [enablePrefetch]);
|
|
2575
|
+
// Set container reference
|
|
2576
|
+
const setContainerRef = useCallback((element) => {
|
|
2577
|
+
containerRef.current = element;
|
|
2578
|
+
if (element) {
|
|
2579
|
+
const scrollHandler = () => {
|
|
2580
|
+
handleScroll(element.scrollTop);
|
|
2581
|
+
};
|
|
2582
|
+
element.addEventListener('scroll', scrollHandler, { passive: true });
|
|
2583
|
+
return () => {
|
|
2584
|
+
element.removeEventListener('scroll', scrollHandler);
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
}, [handleScroll]);
|
|
2588
|
+
// Get cached data
|
|
2589
|
+
const getCachedData = useCallback((index) => {
|
|
2590
|
+
if (cacheRef.current) {
|
|
2591
|
+
return cacheRef.current.get(index);
|
|
2592
|
+
}
|
|
2593
|
+
return null;
|
|
2594
|
+
}, []);
|
|
2595
|
+
// Cache data
|
|
2596
|
+
const cacheData = useCallback((index, data, priority = 'normal') => {
|
|
2597
|
+
if (cacheRef.current) {
|
|
2598
|
+
cacheRef.current.preemptiveCache(index, data, priority);
|
|
2599
|
+
}
|
|
2600
|
+
}, []);
|
|
2601
|
+
// Get pagination state
|
|
2602
|
+
const getPaginationState = useCallback(() => {
|
|
2603
|
+
if (paginationRef.current) {
|
|
2604
|
+
return paginationRef.current.getState();
|
|
2605
|
+
}
|
|
2606
|
+
return null;
|
|
2607
|
+
}, []);
|
|
2608
|
+
return {
|
|
2609
|
+
visibleRange: state.visibleRange,
|
|
2610
|
+
isLoading: state.isLoading,
|
|
2611
|
+
scrollVelocity: state.scrollVelocity,
|
|
2612
|
+
scrollDirection: state.scrollDirection,
|
|
2613
|
+
scrollPattern: state.scrollPattern,
|
|
2614
|
+
prefetchConfidence: state.prefetchConfidence,
|
|
2615
|
+
cacheHitRate: state.cacheHitRate,
|
|
2616
|
+
totalItems: state.totalItems,
|
|
2617
|
+
setContainerRef,
|
|
2618
|
+
getCachedData,
|
|
2619
|
+
cacheData,
|
|
2620
|
+
getPaginationState,
|
|
2621
|
+
refresh: () => {
|
|
2622
|
+
if (containerRef.current) {
|
|
2623
|
+
handleScroll(containerRef.current.scrollTop);
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
};
|
|
2627
|
+
};
|
|
2628
|
+
|
|
2629
|
+
const useAdaptiveLoading = (config) => {
|
|
2630
|
+
const { initialBatchSize = 50, minBatchSize = 20, maxBatchSize = 200, fetchMore, enableNetworkAdaptation = true, enablePerformanceAdaptation = true } = config;
|
|
2631
|
+
const batchSizeOptimizerRef = useRef(null);
|
|
2632
|
+
const networkDetectorRef = useRef(null);
|
|
2633
|
+
const performanceMonitorRef = useRef(null);
|
|
2634
|
+
const [state, setState] = useState({
|
|
2635
|
+
currentBatchSize: initialBatchSize,
|
|
2636
|
+
networkQuality: 'good',
|
|
2637
|
+
performanceScore: 0.8,
|
|
2638
|
+
isLoading: false,
|
|
2639
|
+
loadedItems: 0,
|
|
2640
|
+
avgLoadTime: 0,
|
|
2641
|
+
adaptationCount: 0
|
|
2642
|
+
});
|
|
2643
|
+
const loadTimeHistoryRef = useRef([]);
|
|
2644
|
+
// Initialize adaptive loading system
|
|
2645
|
+
useEffect(() => {
|
|
2646
|
+
if (enableNetworkAdaptation) {
|
|
2647
|
+
networkDetectorRef.current = new NetworkSpeedDetector();
|
|
2648
|
+
}
|
|
2649
|
+
if (enablePerformanceAdaptation) {
|
|
2650
|
+
performanceMonitorRef.current = new DevicePerformanceMonitor();
|
|
2651
|
+
}
|
|
2652
|
+
batchSizeOptimizerRef.current = new BatchSizeOptimizer({
|
|
2653
|
+
minBatchSize,
|
|
2654
|
+
maxBatchSize,
|
|
2655
|
+
baseBatchSize: initialBatchSize
|
|
2656
|
+
});
|
|
2657
|
+
return () => {
|
|
2658
|
+
batchSizeOptimizerRef.current = null;
|
|
2659
|
+
networkDetectorRef.current = null;
|
|
2660
|
+
performanceMonitorRef.current = null;
|
|
2661
|
+
};
|
|
2662
|
+
}, []);
|
|
2663
|
+
// Load data with adaptive batch size
|
|
2664
|
+
const loadMore = useCallback(async () => {
|
|
2665
|
+
if (!batchSizeOptimizerRef.current || state.isLoading)
|
|
2666
|
+
return [];
|
|
2667
|
+
const startTime = performance.now();
|
|
2668
|
+
setState(prev => ({ ...prev, isLoading: true }));
|
|
2669
|
+
try {
|
|
2670
|
+
// Calculate optimal batch size
|
|
2671
|
+
let optimalBatchSize = state.currentBatchSize;
|
|
2672
|
+
if (enableNetworkAdaptation && networkDetectorRef.current) {
|
|
2673
|
+
const networkQuality = await networkDetectorRef.current.assessConnectionQuality();
|
|
2674
|
+
setState(prev => ({ ...prev, networkQuality }));
|
|
2675
|
+
}
|
|
2676
|
+
if (enablePerformanceAdaptation && performanceMonitorRef.current) {
|
|
2677
|
+
const perfScore = await performanceMonitorRef.current.assessPerformance();
|
|
2678
|
+
setState(prev => ({ ...prev, performanceScore: perfScore }));
|
|
2679
|
+
}
|
|
2680
|
+
// Get optimized batch size
|
|
2681
|
+
optimalBatchSize = await batchSizeOptimizerRef.current.calculateOptimalBatchSize(state.loadedItems / 1000 // Rough scroll speed estimate
|
|
2682
|
+
);
|
|
2683
|
+
// Fetch data
|
|
2684
|
+
const newData = await fetchMore();
|
|
2685
|
+
const loadTime = performance.now() - startTime;
|
|
2686
|
+
loadTimeHistoryRef.current.push(loadTime);
|
|
2687
|
+
// Keep last 10 load times
|
|
2688
|
+
if (loadTimeHistoryRef.current.length > 10) {
|
|
2689
|
+
loadTimeHistoryRef.current.shift();
|
|
2690
|
+
}
|
|
2691
|
+
const avgLoadTime = loadTimeHistoryRef.current.reduce((a, b) => a + b, 0) / loadTimeHistoryRef.current.length;
|
|
2692
|
+
// Record load time for future optimization
|
|
2693
|
+
batchSizeOptimizerRef.current.trackRenderTime(loadTime);
|
|
2694
|
+
setState(prev => ({
|
|
2695
|
+
...prev,
|
|
2696
|
+
isLoading: false,
|
|
2697
|
+
loadedItems: prev.loadedItems + newData.length,
|
|
2698
|
+
avgLoadTime,
|
|
2699
|
+
adaptationCount: prev.adaptationCount + 1
|
|
2700
|
+
}));
|
|
2701
|
+
return newData;
|
|
2702
|
+
}
|
|
2703
|
+
catch (error) {
|
|
2704
|
+
console.error('Adaptive loading error:', error);
|
|
2705
|
+
setState(prev => ({ ...prev, isLoading: false }));
|
|
2706
|
+
return [];
|
|
2707
|
+
}
|
|
2708
|
+
}, [state.isLoading, state.currentBatchSize, state.loadedItems, enableNetworkAdaptation, enablePerformanceAdaptation]);
|
|
2709
|
+
// Get current batch size
|
|
2710
|
+
const getCurrentBatchSize = useCallback(() => {
|
|
2711
|
+
if (batchSizeOptimizerRef.current) {
|
|
2712
|
+
return batchSizeOptimizerRef.current.getCurrentBatchSize();
|
|
2713
|
+
}
|
|
2714
|
+
return state.currentBatchSize;
|
|
2715
|
+
}, [state.currentBatchSize]);
|
|
2716
|
+
// Get loading statistics
|
|
2717
|
+
const getStats = useCallback(() => {
|
|
2718
|
+
return {
|
|
2719
|
+
currentBatchSize: state.currentBatchSize,
|
|
2720
|
+
networkQuality: state.networkQuality,
|
|
2721
|
+
performanceScore: state.performanceScore,
|
|
2722
|
+
avgLoadTime: state.avgLoadTime,
|
|
2723
|
+
adaptationCount: state.adaptationCount,
|
|
2724
|
+
loadedItems: state.loadedItems
|
|
2725
|
+
};
|
|
2726
|
+
}, [state]);
|
|
2727
|
+
// Reset adaptive loading
|
|
2728
|
+
const reset = useCallback(() => {
|
|
2729
|
+
loadTimeHistoryRef.current = [];
|
|
2730
|
+
setState(prev => ({
|
|
2731
|
+
...prev,
|
|
2732
|
+
currentBatchSize: initialBatchSize,
|
|
2733
|
+
loadedItems: 0,
|
|
2734
|
+
avgLoadTime: 0,
|
|
2735
|
+
adaptationCount: 0
|
|
2736
|
+
}));
|
|
2737
|
+
if (batchSizeOptimizerRef.current) {
|
|
2738
|
+
batchSizeOptimizerRef.current.reset();
|
|
2739
|
+
}
|
|
2740
|
+
}, [initialBatchSize]);
|
|
2741
|
+
return {
|
|
2742
|
+
...state,
|
|
2743
|
+
loadMore,
|
|
2744
|
+
getCurrentBatchSize,
|
|
2745
|
+
getStats,
|
|
2746
|
+
reset
|
|
2747
|
+
};
|
|
2748
|
+
};
|
|
2749
|
+
|
|
2750
|
+
const useSmartPagination = (config = {}) => {
|
|
2751
|
+
const { initialPage = 1, initialPageSize = 50, minPageSize = 20, maxPageSize = 200, enableAdaptation = true } = config;
|
|
2752
|
+
const paginationRef = useRef(null);
|
|
2753
|
+
const [state, setState] = useState({
|
|
2754
|
+
currentPage: initialPage,
|
|
2755
|
+
pageSize: initialPageSize,
|
|
2756
|
+
totalItems: 0,
|
|
2757
|
+
totalPages: 0,
|
|
2758
|
+
hasMore: false,
|
|
2759
|
+
cursor: undefined,
|
|
2760
|
+
nextCursor: undefined,
|
|
2761
|
+
prevCursor: undefined,
|
|
2762
|
+
avgLoadTime: 0,
|
|
2763
|
+
isAdapting: false
|
|
2764
|
+
});
|
|
2765
|
+
const loadTimeHistoryRef = useRef([]);
|
|
2766
|
+
// Initialize pagination
|
|
2767
|
+
useEffect(() => {
|
|
2768
|
+
paginationRef.current = new IntelligentPagination();
|
|
2769
|
+
if (initialPageSize) {
|
|
2770
|
+
paginationRef.current.setBasePageSize(initialPageSize);
|
|
2771
|
+
}
|
|
2772
|
+
return () => {
|
|
2773
|
+
paginationRef.current = null;
|
|
2774
|
+
};
|
|
2775
|
+
}, []);
|
|
2776
|
+
// Update pagination state
|
|
2777
|
+
const updateState = useCallback(() => {
|
|
2778
|
+
if (!paginationRef.current)
|
|
2779
|
+
return;
|
|
2780
|
+
const paginationState = paginationRef.current.getState();
|
|
2781
|
+
setState(prev => ({
|
|
2782
|
+
...prev,
|
|
2783
|
+
currentPage: paginationState.currentPage,
|
|
2784
|
+
pageSize: paginationState.pageSize,
|
|
2785
|
+
totalItems: paginationState.totalItems,
|
|
2786
|
+
totalPages: paginationState.totalPages,
|
|
2787
|
+
hasMore: paginationState.hasMore,
|
|
2788
|
+
cursor: paginationState.cursor,
|
|
2789
|
+
nextCursor: paginationState.nextCursor,
|
|
2790
|
+
prevCursor: paginationState.prevCursor
|
|
2791
|
+
}));
|
|
2792
|
+
}, []);
|
|
2793
|
+
// Set total items
|
|
2794
|
+
const setTotalItems = useCallback((total) => {
|
|
2795
|
+
if (paginationRef.current) {
|
|
2796
|
+
paginationRef.current.setTotalItems(total);
|
|
2797
|
+
updateState();
|
|
2798
|
+
}
|
|
2799
|
+
}, [updateState]);
|
|
2800
|
+
// Go to next page
|
|
2801
|
+
const nextPage = useCallback(async (loadDataFn) => {
|
|
2802
|
+
if (!paginationRef.current || !state.hasMore)
|
|
2803
|
+
return;
|
|
2804
|
+
const startTime = performance.now();
|
|
2805
|
+
setState(prev => ({ ...prev, isAdapting: true }));
|
|
2806
|
+
try {
|
|
2807
|
+
paginationRef.current.nextPage();
|
|
2808
|
+
if (loadDataFn) {
|
|
2809
|
+
await loadDataFn();
|
|
2810
|
+
}
|
|
2811
|
+
const loadTime = performance.now() - startTime;
|
|
2812
|
+
// Record load time for adaptation
|
|
2813
|
+
if (enableAdaptation && paginationRef.current) {
|
|
2814
|
+
paginationRef.current.recordLoadTime(state.currentPage, loadTime);
|
|
2815
|
+
loadTimeHistoryRef.current.push({ page: state.currentPage, time: loadTime });
|
|
2816
|
+
// Keep last 10 load times
|
|
2817
|
+
if (loadTimeHistoryRef.current.length > 10) {
|
|
2818
|
+
loadTimeHistoryRef.current.shift();
|
|
2819
|
+
}
|
|
2820
|
+
const avgLoadTime = loadTimeHistoryRef.current.reduce((a, b) => a + b.time, 0) / loadTimeHistoryRef.current.length;
|
|
2821
|
+
setState(prev => ({
|
|
2822
|
+
...prev,
|
|
2823
|
+
avgLoadTime,
|
|
2824
|
+
isAdapting: false
|
|
2825
|
+
}));
|
|
2826
|
+
}
|
|
2827
|
+
updateState();
|
|
2828
|
+
}
|
|
2829
|
+
catch (error) {
|
|
2830
|
+
console.error('Next page error:', error);
|
|
2831
|
+
setState(prev => ({ ...prev, isAdapting: false }));
|
|
2832
|
+
}
|
|
2833
|
+
}, [state.hasMore, state.currentPage, enableAdaptation, updateState]);
|
|
2834
|
+
// Go to previous page
|
|
2835
|
+
const prevPage = useCallback(() => {
|
|
2836
|
+
if (!paginationRef.current)
|
|
2837
|
+
return;
|
|
2838
|
+
paginationRef.current.prevPage();
|
|
2839
|
+
updateState();
|
|
2840
|
+
}, [updateState]);
|
|
2841
|
+
// Go to specific page
|
|
2842
|
+
const goToPage = useCallback((page) => {
|
|
2843
|
+
if (!paginationRef.current)
|
|
2844
|
+
return;
|
|
2845
|
+
paginationRef.current.goToPage(page);
|
|
2846
|
+
updateState();
|
|
2847
|
+
}, [updateState]);
|
|
2848
|
+
// Go to cursor
|
|
2849
|
+
const goToCursor = useCallback((cursor) => {
|
|
2850
|
+
if (!paginationRef.current)
|
|
2851
|
+
return;
|
|
2852
|
+
paginationRef.current.goToCursor(cursor);
|
|
2853
|
+
updateState();
|
|
2854
|
+
}, [updateState]);
|
|
2855
|
+
// Get fetch range
|
|
2856
|
+
const getFetchRange = useCallback(() => {
|
|
2857
|
+
if (!paginationRef.current)
|
|
2858
|
+
return { skip: 0, limit: state.pageSize };
|
|
2859
|
+
return paginationRef.current.getFetchRange();
|
|
2860
|
+
}, [state.pageSize]);
|
|
2861
|
+
// Get current cursor
|
|
2862
|
+
const getCurrentCursor = useCallback(() => {
|
|
2863
|
+
if (!paginationRef.current)
|
|
2864
|
+
return state.cursor;
|
|
2865
|
+
return paginationRef.current.getState().cursor;
|
|
2866
|
+
}, [state.cursor]);
|
|
2867
|
+
// Get pagination statistics
|
|
2868
|
+
const getStats = useCallback(() => {
|
|
2869
|
+
if (!paginationRef.current)
|
|
2870
|
+
return null;
|
|
2871
|
+
return {
|
|
2872
|
+
currentPage: state.currentPage,
|
|
2873
|
+
pageSize: state.pageSize,
|
|
2874
|
+
totalItems: state.totalItems,
|
|
2875
|
+
totalPages: state.totalPages,
|
|
2876
|
+
hasMore: state.hasMore,
|
|
2877
|
+
avgLoadTime: state.avgLoadTime,
|
|
2878
|
+
currentCursor: state.cursor,
|
|
2879
|
+
loadHistory: loadTimeHistoryRef.current
|
|
2880
|
+
};
|
|
2881
|
+
}, [state]);
|
|
2882
|
+
// Reset pagination
|
|
2883
|
+
const reset = useCallback(() => {
|
|
2884
|
+
if (paginationRef.current) {
|
|
2885
|
+
paginationRef.current.reset();
|
|
2886
|
+
loadTimeHistoryRef.current = [];
|
|
2887
|
+
updateState();
|
|
2888
|
+
}
|
|
2889
|
+
}, [updateState]);
|
|
2890
|
+
return {
|
|
2891
|
+
...state,
|
|
2892
|
+
nextPage,
|
|
2893
|
+
prevPage,
|
|
2894
|
+
goToPage,
|
|
2895
|
+
goToCursor,
|
|
2896
|
+
setTotalItems,
|
|
2897
|
+
getFetchRange,
|
|
2898
|
+
getCurrentCursor,
|
|
2899
|
+
getStats,
|
|
2900
|
+
reset
|
|
2901
|
+
};
|
|
2902
|
+
};
|
|
2903
|
+
|
|
2904
|
+
const IntelligentLazyList = ({ items, itemHeight, viewportHeight, fetchMore, renderItem, bufferSize = 5, enablePrefetch = true, enableCache = true, className = '', style = {} }) => {
|
|
2905
|
+
const containerRef = useRef(null);
|
|
2906
|
+
const { visibleRange, isLoading, scrollVelocity, scrollDirection, scrollPattern, prefetchConfidence, cacheHitRate, setContainerRef, getCachedData, cacheData } = useIntelligentScroll({
|
|
2907
|
+
itemHeight,
|
|
2908
|
+
viewportHeight,
|
|
2909
|
+
bufferSize,
|
|
2910
|
+
fetchMore,
|
|
2911
|
+
enablePrefetch,
|
|
2912
|
+
enableCache
|
|
2913
|
+
});
|
|
2914
|
+
// Cache items as they load
|
|
2915
|
+
useEffect(() => {
|
|
2916
|
+
if (enableCache) {
|
|
2917
|
+
items.forEach((item, index) => {
|
|
2918
|
+
if (index >= visibleRange.start && index <= visibleRange.end) {
|
|
2919
|
+
cacheData(index, item, 'high');
|
|
2920
|
+
}
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
}, [items, visibleRange, enableCache, cacheData]);
|
|
2924
|
+
// Calculate total height
|
|
2925
|
+
const totalHeight = items.length * itemHeight;
|
|
2926
|
+
const topPadding = visibleRange.start * itemHeight;
|
|
2927
|
+
const bottomPadding = Math.max(0, totalHeight - ((visibleRange.end + 1) * itemHeight));
|
|
2928
|
+
// Get visible items
|
|
2929
|
+
const visibleItems = items.slice(visibleRange.start, visibleRange.end + 1);
|
|
2930
|
+
return (React.createElement("div", { ref: (el) => {
|
|
2931
|
+
containerRef.current = el;
|
|
2932
|
+
setContainerRef(el);
|
|
2933
|
+
}, className: `intelligent-lazy-list ${className}`, style: {
|
|
2934
|
+
height: `${viewportHeight}px`,
|
|
2935
|
+
overflowY: 'auto',
|
|
2936
|
+
position: 'relative',
|
|
2937
|
+
...style
|
|
2938
|
+
} },
|
|
2939
|
+
React.createElement("div", { style: { height: `${topPadding}px` } }),
|
|
2940
|
+
visibleItems.map((item, index) => {
|
|
2941
|
+
const cachedData = getCachedData(visibleRange.start + index);
|
|
2942
|
+
return (React.createElement("div", { key: visibleRange.start + index, style: {
|
|
2943
|
+
height: `${itemHeight}px`,
|
|
2944
|
+
position: 'relative'
|
|
2945
|
+
}, className: "intelligent-lazy-item" }, renderItem(cachedData || item, visibleRange.start + index)));
|
|
2946
|
+
}),
|
|
2947
|
+
React.createElement("div", { style: { height: `${bottomPadding}px` } }),
|
|
2948
|
+
isLoading && (React.createElement("div", { className: "intelligent-lazy-loading", style: {
|
|
2949
|
+
position: 'absolute',
|
|
2950
|
+
bottom: '10px',
|
|
2951
|
+
left: '50%',
|
|
2952
|
+
transform: 'translateX(-50%)',
|
|
2953
|
+
background: 'rgba(0, 0, 0, 0.7)',
|
|
2954
|
+
color: 'white',
|
|
2955
|
+
padding: '8px 16px',
|
|
2956
|
+
borderRadius: '4px',
|
|
2957
|
+
fontSize: '12px'
|
|
2958
|
+
} },
|
|
2959
|
+
"Loading... (Pattern: ",
|
|
2960
|
+
scrollPattern,
|
|
2961
|
+
", Confidence: ",
|
|
2962
|
+
(prefetchConfidence * 100).toFixed(0),
|
|
2963
|
+
"%)")),
|
|
2964
|
+
React.createElement("div", { className: "intelligent-lazy-debug", style: {
|
|
2965
|
+
position: 'absolute',
|
|
2966
|
+
top: '10px',
|
|
2967
|
+
right: '10px',
|
|
2968
|
+
background: 'rgba(0, 0, 0, 0.7)',
|
|
2969
|
+
color: 'white',
|
|
2970
|
+
padding: '8px',
|
|
2971
|
+
borderRadius: '4px',
|
|
2972
|
+
fontSize: '11px',
|
|
2973
|
+
pointerEvents: 'none'
|
|
2974
|
+
} },
|
|
2975
|
+
React.createElement("div", null,
|
|
2976
|
+
"Velocity: ",
|
|
2977
|
+
scrollVelocity.toFixed(2)),
|
|
2978
|
+
React.createElement("div", null,
|
|
2979
|
+
"Direction: ",
|
|
2980
|
+
scrollDirection),
|
|
2981
|
+
React.createElement("div", null,
|
|
2982
|
+
"Pattern: ",
|
|
2983
|
+
scrollPattern),
|
|
2984
|
+
React.createElement("div", null,
|
|
2985
|
+
"Cache Hit: ",
|
|
2986
|
+
(cacheHitRate * 100).toFixed(0),
|
|
2987
|
+
"%"),
|
|
2988
|
+
React.createElement("div", null,
|
|
2989
|
+
"Visible: ",
|
|
2990
|
+
visibleRange.start,
|
|
2991
|
+
"-",
|
|
2992
|
+
visibleRange.end))));
|
|
2993
|
+
};
|
|
2994
|
+
|
|
2995
|
+
const AdaptiveScrollView = ({ children, fetchMore, initialBatchSize = 50, minBatchSize = 20, maxBatchSize = 200, enableNetworkAdaptation = true, enablePerformanceAdaptation = true, className = '', style = {}, onLoadMore }) => {
|
|
2996
|
+
const containerRef = useRef(null);
|
|
2997
|
+
const loadMoreRef = useRef(null);
|
|
2998
|
+
const observerRef = useRef(null);
|
|
2999
|
+
const { currentBatchSize, networkQuality, performanceScore, isLoading, loadedItems, avgLoadTime, adaptationCount, loadMore, getStats } = useAdaptiveLoading({
|
|
3000
|
+
initialBatchSize,
|
|
3001
|
+
minBatchSize,
|
|
3002
|
+
maxBatchSize,
|
|
3003
|
+
fetchMore,
|
|
3004
|
+
enableNetworkAdaptation,
|
|
3005
|
+
enablePerformanceAdaptation
|
|
3006
|
+
});
|
|
3007
|
+
// Setup intersection observer for infinite scroll
|
|
3008
|
+
useEffect(() => {
|
|
3009
|
+
const options = {
|
|
3010
|
+
root: containerRef.current,
|
|
3011
|
+
rootMargin: '100px',
|
|
3012
|
+
threshold: 0
|
|
3013
|
+
};
|
|
3014
|
+
observerRef.current = new IntersectionObserver((entries) => {
|
|
3015
|
+
const entry = entries[0];
|
|
3016
|
+
if (entry.isIntersecting && !isLoading) {
|
|
3017
|
+
loadMore().then((items) => {
|
|
3018
|
+
if (onLoadMore) {
|
|
3019
|
+
onLoadMore(items);
|
|
3020
|
+
}
|
|
3021
|
+
});
|
|
3022
|
+
}
|
|
3023
|
+
}, options);
|
|
3024
|
+
if (loadMoreRef.current) {
|
|
3025
|
+
observerRef.current.observe(loadMoreRef.current);
|
|
3026
|
+
}
|
|
3027
|
+
return () => {
|
|
3028
|
+
if (observerRef.current) {
|
|
3029
|
+
observerRef.current.disconnect();
|
|
3030
|
+
}
|
|
3031
|
+
};
|
|
3032
|
+
}, [isLoading, loadMore, onLoadMore]);
|
|
3033
|
+
// Get network quality color
|
|
3034
|
+
const getNetworkQualityColor = () => {
|
|
3035
|
+
switch (networkQuality) {
|
|
3036
|
+
case 'excellent': return '#4CAF50';
|
|
3037
|
+
case 'good': return '#8BC34A';
|
|
3038
|
+
case 'poor': return '#FF9800';
|
|
3039
|
+
case 'offline': return '#F44336';
|
|
3040
|
+
default: return '#9E9E9E';
|
|
3041
|
+
}
|
|
3042
|
+
};
|
|
3043
|
+
return (React.createElement("div", { ref: containerRef, className: `adaptive-scroll-view ${className}`, style: {
|
|
3044
|
+
overflowY: 'auto',
|
|
3045
|
+
height: '100%',
|
|
3046
|
+
...style
|
|
3047
|
+
} },
|
|
3048
|
+
React.createElement("div", { className: "adaptive-scroll-content" }, children),
|
|
3049
|
+
React.createElement("div", { ref: loadMoreRef, style: {
|
|
3050
|
+
padding: '20px',
|
|
3051
|
+
textAlign: 'center',
|
|
3052
|
+
opacity: isLoading ? 0.5 : 1
|
|
3053
|
+
} }, isLoading ? (React.createElement("div", { className: "adaptive-loading" },
|
|
3054
|
+
React.createElement("div", { style: {
|
|
3055
|
+
display: 'inline-block',
|
|
3056
|
+
width: '20px',
|
|
3057
|
+
height: '20px',
|
|
3058
|
+
border: '2px solid #f3f3f3',
|
|
3059
|
+
borderTop: '2px solid #3498db',
|
|
3060
|
+
borderRadius: '50%',
|
|
3061
|
+
animation: 'spin 1s linear infinite'
|
|
3062
|
+
} }),
|
|
3063
|
+
React.createElement("span", { style: { marginLeft: '8px' } },
|
|
3064
|
+
"Loading ",
|
|
3065
|
+
currentBatchSize,
|
|
3066
|
+
" items..."))) : (React.createElement("div", { className: "adaptive-ready" }, "Scroll for more"))),
|
|
3067
|
+
React.createElement("div", { style: {
|
|
3068
|
+
position: 'fixed',
|
|
3069
|
+
bottom: '10px',
|
|
3070
|
+
right: '10px',
|
|
3071
|
+
background: 'rgba(0, 0, 0, 0.8)',
|
|
3072
|
+
color: 'white',
|
|
3073
|
+
padding: '12px',
|
|
3074
|
+
borderRadius: '8px',
|
|
3075
|
+
fontSize: '11px',
|
|
3076
|
+
fontFamily: 'monospace',
|
|
3077
|
+
zIndex: 1000
|
|
3078
|
+
} },
|
|
3079
|
+
React.createElement("div", { style: { marginBottom: '8px', fontWeight: 'bold' } }, "Adaptive Loading Stats"),
|
|
3080
|
+
React.createElement("div", { style: { display: 'grid', gridTemplateColumns: 'auto auto', gap: '4px' } },
|
|
3081
|
+
React.createElement("span", null, "Batch Size:"),
|
|
3082
|
+
React.createElement("span", null, currentBatchSize),
|
|
3083
|
+
React.createElement("span", null, "Network:"),
|
|
3084
|
+
React.createElement("span", { style: { color: getNetworkQualityColor() } }, networkQuality.toUpperCase()),
|
|
3085
|
+
React.createElement("span", null, "Performance:"),
|
|
3086
|
+
React.createElement("span", null,
|
|
3087
|
+
(performanceScore * 100).toFixed(0),
|
|
3088
|
+
"%"),
|
|
3089
|
+
React.createElement("span", null, "Loaded:"),
|
|
3090
|
+
React.createElement("span", null,
|
|
3091
|
+
loadedItems,
|
|
3092
|
+
" items"),
|
|
3093
|
+
React.createElement("span", null, "Avg Load:"),
|
|
3094
|
+
React.createElement("span", null,
|
|
3095
|
+
avgLoadTime.toFixed(0),
|
|
3096
|
+
"ms"),
|
|
3097
|
+
React.createElement("span", null, "Adaptations:"),
|
|
3098
|
+
React.createElement("span", null, adaptationCount))),
|
|
3099
|
+
React.createElement("style", null, `
|
|
3100
|
+
@keyframes spin {
|
|
3101
|
+
0% { transform: rotate(0deg); }
|
|
3102
|
+
100% { transform: rotate(360deg); }
|
|
3103
|
+
}
|
|
3104
|
+
`)));
|
|
3105
|
+
};
|
|
3106
|
+
|
|
3107
|
+
const SmartInfiniteScroll = ({ fetchMore, renderItem, initialPageSize = 50, minPageSize = 20, maxPageSize = 200, enableAdaptation = true, className = '', style = {}, emptyMessage = 'No more items' }) => {
|
|
3108
|
+
const containerRef = useRef(null);
|
|
3109
|
+
const loadMoreRef = useRef(null);
|
|
3110
|
+
const observerRef = useRef(null);
|
|
3111
|
+
const { currentPage, pageSize, totalItems, totalPages, hasMore, cursor, nextPage, setTotalItems, getFetchRange } = useSmartPagination({
|
|
3112
|
+
initialPage: 1,
|
|
3113
|
+
initialPageSize,
|
|
3114
|
+
minPageSize,
|
|
3115
|
+
maxPageSize,
|
|
3116
|
+
enableAdaptation
|
|
3117
|
+
});
|
|
3118
|
+
const { isLoading, loadedItems, avgLoadTime, loadMore, getStats } = useAdaptiveLoading({
|
|
3119
|
+
initialBatchSize: pageSize,
|
|
3120
|
+
minBatchSize: minPageSize,
|
|
3121
|
+
maxBatchSize: maxPageSize,
|
|
3122
|
+
fetchMore: async () => {
|
|
3123
|
+
const range = getFetchRange();
|
|
3124
|
+
const items = await fetchMore(currentPage, range.limit);
|
|
3125
|
+
setTotalItems(totalItems + items.length);
|
|
3126
|
+
return items;
|
|
3127
|
+
},
|
|
3128
|
+
enableNetworkAdaptation: enableAdaptation,
|
|
3129
|
+
enablePerformanceAdaptation: enableAdaptation
|
|
3130
|
+
});
|
|
3131
|
+
// Setup intersection observer
|
|
3132
|
+
useEffect(() => {
|
|
3133
|
+
const options = {
|
|
3134
|
+
root: containerRef.current,
|
|
3135
|
+
rootMargin: '200px',
|
|
3136
|
+
threshold: 0
|
|
3137
|
+
};
|
|
3138
|
+
observerRef.current = new IntersectionObserver((entries) => {
|
|
3139
|
+
const entry = entries[0];
|
|
3140
|
+
if (entry.isIntersecting && !isLoading && hasMore) {
|
|
3141
|
+
nextPage(async () => {
|
|
3142
|
+
await loadMore();
|
|
3143
|
+
});
|
|
3144
|
+
}
|
|
3145
|
+
}, options);
|
|
3146
|
+
if (loadMoreRef.current) {
|
|
3147
|
+
observerRef.current.observe(loadMoreRef.current);
|
|
3148
|
+
}
|
|
3149
|
+
return () => {
|
|
3150
|
+
if (observerRef.current) {
|
|
3151
|
+
observerRef.current.disconnect();
|
|
3152
|
+
}
|
|
3153
|
+
};
|
|
3154
|
+
}, [isLoading, hasMore, nextPage, loadMore]);
|
|
3155
|
+
// Get pagination stats
|
|
3156
|
+
getStats();
|
|
3157
|
+
return (React.createElement("div", { ref: containerRef, className: `smart-infinite-scroll ${className}`, style: {
|
|
3158
|
+
overflowY: 'auto',
|
|
3159
|
+
height: '100%',
|
|
3160
|
+
...style
|
|
3161
|
+
} },
|
|
3162
|
+
React.createElement("div", { className: "smart-infinite-content" }, loadedItems === 0 && (React.createElement("div", { className: "smart-infinite-empty", style: {
|
|
3163
|
+
padding: '40px',
|
|
3164
|
+
textAlign: 'center',
|
|
3165
|
+
color: '#999'
|
|
3166
|
+
} }, emptyMessage))),
|
|
3167
|
+
React.createElement("div", { ref: loadMoreRef, style: {
|
|
3168
|
+
padding: '30px',
|
|
3169
|
+
textAlign: 'center'
|
|
3170
|
+
} }, isLoading ? (React.createElement("div", { className: "smart-infinite-loading" },
|
|
3171
|
+
React.createElement("div", { style: {
|
|
3172
|
+
display: 'inline-block',
|
|
3173
|
+
width: '24px',
|
|
3174
|
+
height: '24px',
|
|
3175
|
+
border: '3px solid #f3f3f3',
|
|
3176
|
+
borderTop: '3px solid #3498db',
|
|
3177
|
+
borderRadius: '50%',
|
|
3178
|
+
animation: 'smart-spin 1s linear infinite'
|
|
3179
|
+
} }),
|
|
3180
|
+
React.createElement("div", { style: { marginTop: '12px', color: '#666' } },
|
|
3181
|
+
"Loading page ",
|
|
3182
|
+
currentPage + 1,
|
|
3183
|
+
" of ",
|
|
3184
|
+
totalPages,
|
|
3185
|
+
"..."),
|
|
3186
|
+
React.createElement("div", { style: { fontSize: '11px', color: '#999', marginTop: '4px' } },
|
|
3187
|
+
"Batch size: ",
|
|
3188
|
+
pageSize,
|
|
3189
|
+
" \u2022 Avg: ",
|
|
3190
|
+
avgLoadTime.toFixed(0),
|
|
3191
|
+
"ms"))) : hasMore ? (React.createElement("div", { className: "smart-infinite-ready", style: {
|
|
3192
|
+
color: '#999',
|
|
3193
|
+
fontSize: '13px'
|
|
3194
|
+
} }, "Scroll for more items")) : (React.createElement("div", { className: "smart-infinite-end", style: {
|
|
3195
|
+
color: '#999',
|
|
3196
|
+
fontSize: '13px'
|
|
3197
|
+
} }, emptyMessage))),
|
|
3198
|
+
React.createElement("div", { style: {
|
|
3199
|
+
position: 'fixed',
|
|
3200
|
+
bottom: '10px',
|
|
3201
|
+
right: '10px',
|
|
3202
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
3203
|
+
color: 'white',
|
|
3204
|
+
padding: '16px',
|
|
3205
|
+
borderRadius: '12px',
|
|
3206
|
+
fontSize: '11px',
|
|
3207
|
+
fontFamily: 'monospace',
|
|
3208
|
+
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
|
3209
|
+
zIndex: 1000,
|
|
3210
|
+
minWidth: '200px'
|
|
3211
|
+
} },
|
|
3212
|
+
React.createElement("div", { style: { marginBottom: '8px', fontWeight: 'bold', fontSize: '13px' } }, "\uD83D\uDE80 Smart Infinite Scroll"),
|
|
3213
|
+
React.createElement("div", { style: { display: 'grid', gridTemplateColumns: 'auto auto', gap: '6px' } },
|
|
3214
|
+
React.createElement("span", null, "Page:"),
|
|
3215
|
+
React.createElement("span", null,
|
|
3216
|
+
currentPage,
|
|
3217
|
+
" / ",
|
|
3218
|
+
totalPages),
|
|
3219
|
+
React.createElement("span", null, "Page Size:"),
|
|
3220
|
+
React.createElement("span", null,
|
|
3221
|
+
pageSize,
|
|
3222
|
+
" (adaptive)"),
|
|
3223
|
+
React.createElement("span", null, "Loaded:"),
|
|
3224
|
+
React.createElement("span", null,
|
|
3225
|
+
loadedItems,
|
|
3226
|
+
" items"),
|
|
3227
|
+
React.createElement("span", null, "Avg Load:"),
|
|
3228
|
+
React.createElement("span", null,
|
|
3229
|
+
avgLoadTime.toFixed(0),
|
|
3230
|
+
"ms"),
|
|
3231
|
+
React.createElement("span", null, "Cursor:"),
|
|
3232
|
+
React.createElement("span", { style: {
|
|
3233
|
+
fontSize: '9px',
|
|
3234
|
+
wordBreak: 'break-all',
|
|
3235
|
+
maxWidth: '120px',
|
|
3236
|
+
overflow: 'hidden',
|
|
3237
|
+
textOverflow: 'ellipsis'
|
|
3238
|
+
} }, cursor ? cursor.substring(0, 20) + '...' : 'N/A'),
|
|
3239
|
+
React.createElement("span", null, "Has More:"),
|
|
3240
|
+
React.createElement("span", { style: { color: hasMore ? '#4CAF50' : '#F44336' } }, hasMore ? 'Yes' : 'No'))),
|
|
3241
|
+
React.createElement("style", null, `
|
|
3242
|
+
@keyframes smart-spin {
|
|
3243
|
+
0% { transform: rotate(0deg); }
|
|
3244
|
+
100% { transform: rotate(360deg); }
|
|
3245
|
+
}
|
|
3246
|
+
`)));
|
|
3247
|
+
};
|
|
3248
|
+
|
|
3249
|
+
export { AdaptiveScrollView, IntelligentLazyList, LazyList, SmartInfiniteScroll, useAdaptiveLoading, useIntelligentScroll, useLazyList, useSmartPagination };
|
|
1518
3250
|
//# sourceMappingURL=index.js.map
|