lazy-render-virtual-scroll 1.12.0 → 1.13.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/dist/adapters/react/index.d.ts +91 -2
- package/dist/cjs/adapters/react/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/cjs/adapters/react/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/cjs/adapters/react/adapters/react/components/index.d.ts +2 -0
- package/dist/cjs/adapters/react/adapters/react/components/index.d.ts.map +1 -1
- package/dist/cjs/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/cjs/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/cjs/adapters/react/components/index.d.ts +2 -0
- package/dist/cjs/adapters/react/components/index.d.ts.map +1 -1
- package/dist/cjs/adapters/react/core/AccessibilityManager.d.ts +86 -0
- package/dist/cjs/adapters/react/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/AnimationManager.d.ts +63 -0
- package/dist/cjs/adapters/react/core/AnimationManager.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/cjs/adapters/react/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/cjs/adapters/react/core/PerformanceDashboard.d.ts +60 -0
- package/dist/cjs/adapters/react/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/cjs/adapters/react/index.d.ts +4 -0
- package/dist/cjs/adapters/react/index.d.ts.map +1 -1
- package/dist/cjs/adapters/react/index.js +282 -0
- package/dist/cjs/adapters/react/index.js.map +1 -1
- package/dist/cjs/angular/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/cjs/angular/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/cjs/angular/adapters/react/components/index.d.ts +2 -0
- package/dist/cjs/angular/adapters/react/components/index.d.ts.map +1 -1
- package/dist/cjs/angular/core/AccessibilityManager.d.ts +86 -0
- package/dist/cjs/angular/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/cjs/angular/core/AnimationManager.d.ts +63 -0
- package/dist/cjs/angular/core/AnimationManager.d.ts.map +1 -0
- package/dist/cjs/angular/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/cjs/angular/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/cjs/angular/core/PerformanceDashboard.d.ts +60 -0
- package/dist/cjs/angular/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/cjs/angular/index.d.ts +4 -0
- package/dist/cjs/angular/index.d.ts.map +1 -1
- package/dist/cjs/core/AccessibilityManager.d.ts +86 -0
- package/dist/cjs/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/cjs/core/AnimationManager.d.ts +63 -0
- package/dist/cjs/core/AnimationManager.d.ts.map +1 -0
- package/dist/cjs/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/cjs/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/cjs/core/PerformanceDashboard.d.ts +60 -0
- package/dist/cjs/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +756 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/svelte/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/cjs/svelte/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/cjs/svelte/adapters/react/components/index.d.ts +2 -0
- package/dist/cjs/svelte/adapters/react/components/index.d.ts.map +1 -1
- package/dist/cjs/svelte/core/AccessibilityManager.d.ts +86 -0
- package/dist/cjs/svelte/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/cjs/svelte/core/AnimationManager.d.ts +63 -0
- package/dist/cjs/svelte/core/AnimationManager.d.ts.map +1 -0
- package/dist/cjs/svelte/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/cjs/svelte/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/cjs/svelte/core/PerformanceDashboard.d.ts +60 -0
- package/dist/cjs/svelte/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/cjs/svelte/index.d.ts +4 -0
- package/dist/cjs/svelte/index.d.ts.map +1 -1
- package/dist/cjs/vue/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/cjs/vue/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/cjs/vue/adapters/react/components/index.d.ts +2 -0
- package/dist/cjs/vue/adapters/react/components/index.d.ts.map +1 -1
- package/dist/cjs/vue/core/AccessibilityManager.d.ts +86 -0
- package/dist/cjs/vue/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/cjs/vue/core/AnimationManager.d.ts +63 -0
- package/dist/cjs/vue/core/AnimationManager.d.ts.map +1 -0
- package/dist/cjs/vue/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/cjs/vue/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/cjs/vue/core/PerformanceDashboard.d.ts +60 -0
- package/dist/cjs/vue/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/cjs/vue/index.d.ts +4 -0
- package/dist/cjs/vue/index.d.ts.map +1 -1
- package/dist/esm/adapters/react/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/esm/adapters/react/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/esm/adapters/react/adapters/react/components/index.d.ts +2 -0
- package/dist/esm/adapters/react/adapters/react/components/index.d.ts.map +1 -1
- package/dist/esm/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/esm/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/esm/adapters/react/components/index.d.ts +2 -0
- package/dist/esm/adapters/react/components/index.d.ts.map +1 -1
- package/dist/esm/adapters/react/core/AccessibilityManager.d.ts +86 -0
- package/dist/esm/adapters/react/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/AnimationManager.d.ts +63 -0
- package/dist/esm/adapters/react/core/AnimationManager.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/esm/adapters/react/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/esm/adapters/react/core/PerformanceDashboard.d.ts +60 -0
- package/dist/esm/adapters/react/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/esm/adapters/react/index.d.ts +4 -0
- package/dist/esm/adapters/react/index.d.ts.map +1 -1
- package/dist/esm/adapters/react/index.js +282 -1
- package/dist/esm/adapters/react/index.js.map +1 -1
- package/dist/esm/angular/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/esm/angular/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/esm/angular/adapters/react/components/index.d.ts +2 -0
- package/dist/esm/angular/adapters/react/components/index.d.ts.map +1 -1
- package/dist/esm/angular/core/AccessibilityManager.d.ts +86 -0
- package/dist/esm/angular/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/esm/angular/core/AnimationManager.d.ts +63 -0
- package/dist/esm/angular/core/AnimationManager.d.ts.map +1 -0
- package/dist/esm/angular/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/esm/angular/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/esm/angular/core/PerformanceDashboard.d.ts +60 -0
- package/dist/esm/angular/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/esm/angular/index.d.ts +4 -0
- package/dist/esm/angular/index.d.ts.map +1 -1
- package/dist/esm/core/AccessibilityManager.d.ts +86 -0
- package/dist/esm/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/esm/core/AnimationManager.d.ts +63 -0
- package/dist/esm/core/AnimationManager.d.ts.map +1 -0
- package/dist/esm/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/esm/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/esm/core/PerformanceDashboard.d.ts +60 -0
- package/dist/esm/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +753 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/svelte/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/esm/svelte/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/esm/svelte/adapters/react/components/index.d.ts +2 -0
- package/dist/esm/svelte/adapters/react/components/index.d.ts.map +1 -1
- package/dist/esm/svelte/core/AccessibilityManager.d.ts +86 -0
- package/dist/esm/svelte/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/esm/svelte/core/AnimationManager.d.ts +63 -0
- package/dist/esm/svelte/core/AnimationManager.d.ts.map +1 -0
- package/dist/esm/svelte/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/esm/svelte/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/esm/svelte/core/PerformanceDashboard.d.ts +60 -0
- package/dist/esm/svelte/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/esm/svelte/index.d.ts +4 -0
- package/dist/esm/svelte/index.d.ts.map +1 -1
- package/dist/esm/vue/adapters/react/components/PerformanceMonitor.d.ts +10 -0
- package/dist/esm/vue/adapters/react/components/PerformanceMonitor.d.ts.map +1 -0
- package/dist/esm/vue/adapters/react/components/index.d.ts +2 -0
- package/dist/esm/vue/adapters/react/components/index.d.ts.map +1 -1
- package/dist/esm/vue/core/AccessibilityManager.d.ts +86 -0
- package/dist/esm/vue/core/AccessibilityManager.d.ts.map +1 -0
- package/dist/esm/vue/core/AnimationManager.d.ts +63 -0
- package/dist/esm/vue/core/AnimationManager.d.ts.map +1 -0
- package/dist/esm/vue/core/PerformanceAnalytics.d.ts +83 -0
- package/dist/esm/vue/core/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/esm/vue/core/PerformanceDashboard.d.ts +60 -0
- package/dist/esm/vue/core/PerformanceDashboard.d.ts.map +1 -0
- package/dist/esm/vue/index.d.ts +4 -0
- package/dist/esm/vue/index.d.ts.map +1 -1
- package/dist/index.d.ts +289 -1
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -2922,6 +2922,758 @@ class IntelligentPagination {
|
|
|
2922
2922
|
}
|
|
2923
2923
|
}
|
|
2924
2924
|
|
|
2925
|
+
/**
|
|
2926
|
+
* Performance Analytics Engine
|
|
2927
|
+
* Tracks render time, memory usage, and network performance
|
|
2928
|
+
*/
|
|
2929
|
+
class PerformanceAnalytics {
|
|
2930
|
+
constructor() {
|
|
2931
|
+
this.renderTimeHistory = [];
|
|
2932
|
+
this.memoryHistory = [];
|
|
2933
|
+
this.networkLatencyHistory = [];
|
|
2934
|
+
this.frameTimestamps = [];
|
|
2935
|
+
this.droppedFrames = 0;
|
|
2936
|
+
this.jankCount = 0;
|
|
2937
|
+
this.MAX_HISTORY = 100;
|
|
2938
|
+
this.JANK_THRESHOLD = 50; // ms
|
|
2939
|
+
}
|
|
2940
|
+
/**
|
|
2941
|
+
* Track render time for an item
|
|
2942
|
+
*/
|
|
2943
|
+
trackRenderTime(renderTime) {
|
|
2944
|
+
this.renderTimeHistory.push(renderTime);
|
|
2945
|
+
if (this.renderTimeHistory.length > this.MAX_HISTORY) {
|
|
2946
|
+
this.renderTimeHistory.shift();
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
/**
|
|
2950
|
+
* Track memory usage
|
|
2951
|
+
*/
|
|
2952
|
+
trackMemoryUsage(memoryMB) {
|
|
2953
|
+
this.memoryHistory.push(memoryMB);
|
|
2954
|
+
if (this.memoryHistory.length > this.MAX_HISTORY) {
|
|
2955
|
+
this.memoryHistory.shift();
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
/**
|
|
2959
|
+
* Track network request latency
|
|
2960
|
+
*/
|
|
2961
|
+
trackNetworkLatency(latency) {
|
|
2962
|
+
this.networkLatencyHistory.push(latency);
|
|
2963
|
+
if (this.networkLatencyHistory.length > this.MAX_HISTORY) {
|
|
2964
|
+
this.networkLatencyHistory.shift();
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
/**
|
|
2968
|
+
* Track frame timing for FPS calculation
|
|
2969
|
+
*/
|
|
2970
|
+
trackFrame() {
|
|
2971
|
+
const now = performance.now();
|
|
2972
|
+
this.frameTimestamps.push(now);
|
|
2973
|
+
// Keep only last 60 frames (1 second at 60fps)
|
|
2974
|
+
if (this.frameTimestamps.length > 60) {
|
|
2975
|
+
this.frameTimestamps.shift();
|
|
2976
|
+
}
|
|
2977
|
+
// Detect jank (frame took longer than JANK_THRESHOLD)
|
|
2978
|
+
if (this.frameTimestamps.length >= 2) {
|
|
2979
|
+
const frameTime = now - this.frameTimestamps[this.frameTimestamps.length - 2];
|
|
2980
|
+
if (frameTime > this.JANK_THRESHOLD) {
|
|
2981
|
+
this.jankCount++;
|
|
2982
|
+
this.droppedFrames++;
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
/**
|
|
2987
|
+
* Get current FPS
|
|
2988
|
+
*/
|
|
2989
|
+
getCurrentFPS() {
|
|
2990
|
+
if (this.frameTimestamps.length < 2)
|
|
2991
|
+
return 60;
|
|
2992
|
+
const now = performance.now();
|
|
2993
|
+
const oneSecondAgo = now - 1000;
|
|
2994
|
+
const framesInLastSecond = this.frameTimestamps.filter(t => t > oneSecondAgo).length;
|
|
2995
|
+
return framesInLastSecond;
|
|
2996
|
+
}
|
|
2997
|
+
/**
|
|
2998
|
+
* Get comprehensive performance metrics
|
|
2999
|
+
*/
|
|
3000
|
+
getMetrics() {
|
|
3001
|
+
return {
|
|
3002
|
+
renderTime: {
|
|
3003
|
+
average: this.getAverage(this.renderTimeHistory),
|
|
3004
|
+
min: Math.min(...this.renderTimeHistory, 0),
|
|
3005
|
+
max: Math.max(...this.renderTimeHistory, 0),
|
|
3006
|
+
count: this.renderTimeHistory.length
|
|
3007
|
+
},
|
|
3008
|
+
memoryUsage: {
|
|
3009
|
+
current: this.memoryHistory[this.memoryHistory.length - 1] || 0,
|
|
3010
|
+
peak: Math.max(...this.memoryHistory, 0),
|
|
3011
|
+
trend: this.getTrend(this.memoryHistory)
|
|
3012
|
+
},
|
|
3013
|
+
networkPerformance: {
|
|
3014
|
+
averageLatency: this.getAverage(this.networkLatencyHistory),
|
|
3015
|
+
averageSpeed: 0, // Would need actual network speed data
|
|
3016
|
+
failedRequests: 0 // Would need to track failures
|
|
3017
|
+
},
|
|
3018
|
+
scrollPerformance: {
|
|
3019
|
+
averageFPS: this.getCurrentFPS(),
|
|
3020
|
+
droppedFrames: this.droppedFrames,
|
|
3021
|
+
jankCount: this.jankCount
|
|
3022
|
+
}
|
|
3023
|
+
};
|
|
3024
|
+
}
|
|
3025
|
+
/**
|
|
3026
|
+
* Get average from array
|
|
3027
|
+
*/
|
|
3028
|
+
getAverage(arr) {
|
|
3029
|
+
if (arr.length === 0)
|
|
3030
|
+
return 0;
|
|
3031
|
+
return arr.reduce((a, b) => a + b, 0) / arr.length;
|
|
3032
|
+
}
|
|
3033
|
+
/**
|
|
3034
|
+
* Get trend from array
|
|
3035
|
+
*/
|
|
3036
|
+
getTrend(arr) {
|
|
3037
|
+
if (arr.length < 10)
|
|
3038
|
+
return 'stable';
|
|
3039
|
+
const recent = arr.slice(-10);
|
|
3040
|
+
const older = arr.slice(-20, -10);
|
|
3041
|
+
const recentAvg = this.getAverage(recent);
|
|
3042
|
+
const olderAvg = this.getAverage(older);
|
|
3043
|
+
const change = (recentAvg - olderAvg) / olderAvg;
|
|
3044
|
+
if (change > 0.1)
|
|
3045
|
+
return 'increasing';
|
|
3046
|
+
if (change < -0.1)
|
|
3047
|
+
return 'decreasing';
|
|
3048
|
+
return 'stable';
|
|
3049
|
+
}
|
|
3050
|
+
/**
|
|
3051
|
+
* Reset all metrics
|
|
3052
|
+
*/
|
|
3053
|
+
reset() {
|
|
3054
|
+
this.renderTimeHistory = [];
|
|
3055
|
+
this.memoryHistory = [];
|
|
3056
|
+
this.networkLatencyHistory = [];
|
|
3057
|
+
this.frameTimestamps = [];
|
|
3058
|
+
this.droppedFrames = 0;
|
|
3059
|
+
this.jankCount = 0;
|
|
3060
|
+
}
|
|
3061
|
+
/**
|
|
3062
|
+
* Get performance score (0-100)
|
|
3063
|
+
*/
|
|
3064
|
+
getPerformanceScore() {
|
|
3065
|
+
const metrics = this.getMetrics();
|
|
3066
|
+
let score = 100;
|
|
3067
|
+
// Penalize low FPS
|
|
3068
|
+
if (metrics.scrollPerformance.averageFPS < 60) {
|
|
3069
|
+
score -= (60 - metrics.scrollPerformance.averageFPS) * 0.5;
|
|
3070
|
+
}
|
|
3071
|
+
// Penalize high render times
|
|
3072
|
+
if (metrics.renderTime.average > 16) {
|
|
3073
|
+
score -= (metrics.renderTime.average - 16) * 0.3;
|
|
3074
|
+
}
|
|
3075
|
+
// Penalize jank
|
|
3076
|
+
score -= metrics.scrollPerformance.jankCount * 0.2;
|
|
3077
|
+
// Penalize memory increase
|
|
3078
|
+
if (metrics.memoryUsage.trend === 'increasing') {
|
|
3079
|
+
score -= 10;
|
|
3080
|
+
}
|
|
3081
|
+
return Math.max(0, Math.min(100, score));
|
|
3082
|
+
}
|
|
3083
|
+
/**
|
|
3084
|
+
* Get optimization recommendations
|
|
3085
|
+
*/
|
|
3086
|
+
getRecommendations() {
|
|
3087
|
+
const recommendations = [];
|
|
3088
|
+
const metrics = this.getMetrics();
|
|
3089
|
+
if (metrics.scrollPerformance.averageFPS < 30) {
|
|
3090
|
+
recommendations.push('Critical: FPS is very low. Consider reducing item complexity or increasing batch size.');
|
|
3091
|
+
}
|
|
3092
|
+
else if (metrics.scrollPerformance.averageFPS < 60) {
|
|
3093
|
+
recommendations.push('Warning: FPS below 60. Consider optimizing render performance.');
|
|
3094
|
+
}
|
|
3095
|
+
if (metrics.renderTime.average > 50) {
|
|
3096
|
+
recommendations.push('Warning: High render time. Consider simplifying item components.');
|
|
3097
|
+
}
|
|
3098
|
+
if (metrics.memoryUsage.trend === 'increasing') {
|
|
3099
|
+
recommendations.push('Warning: Memory usage increasing. Check for memory leaks.');
|
|
3100
|
+
}
|
|
3101
|
+
if (metrics.scrollPerformance.jankCount > 10) {
|
|
3102
|
+
recommendations.push('Warning: Frequent jank detected. Consider smoothing scroll animations.');
|
|
3103
|
+
}
|
|
3104
|
+
if (recommendations.length === 0) {
|
|
3105
|
+
recommendations.push('Performance is optimal. No issues detected.');
|
|
3106
|
+
}
|
|
3107
|
+
return recommendations;
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
/**
|
|
3112
|
+
* Performance Dashboard
|
|
3113
|
+
* Real-time performance monitoring and bottleneck identification
|
|
3114
|
+
*/
|
|
3115
|
+
class PerformanceDashboard {
|
|
3116
|
+
constructor(analytics) {
|
|
3117
|
+
this.updateInterval = 1000; // 1 second
|
|
3118
|
+
this.listeners = [];
|
|
3119
|
+
this.intervalId = null;
|
|
3120
|
+
this.isMonitoring = false;
|
|
3121
|
+
this.analytics = analytics;
|
|
3122
|
+
}
|
|
3123
|
+
/**
|
|
3124
|
+
* Start real-time monitoring
|
|
3125
|
+
*/
|
|
3126
|
+
startMonitoring() {
|
|
3127
|
+
if (this.isMonitoring)
|
|
3128
|
+
return;
|
|
3129
|
+
this.isMonitoring = true;
|
|
3130
|
+
this.intervalId = window.setInterval(() => {
|
|
3131
|
+
const data = this.getDashboardData();
|
|
3132
|
+
this.notifyListeners(data);
|
|
3133
|
+
}, this.updateInterval);
|
|
3134
|
+
}
|
|
3135
|
+
/**
|
|
3136
|
+
* Stop monitoring
|
|
3137
|
+
*/
|
|
3138
|
+
stopMonitoring() {
|
|
3139
|
+
if (!this.isMonitoring)
|
|
3140
|
+
return;
|
|
3141
|
+
this.isMonitoring = false;
|
|
3142
|
+
if (this.intervalId !== null) {
|
|
3143
|
+
clearInterval(this.intervalId);
|
|
3144
|
+
this.intervalId = null;
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
/**
|
|
3148
|
+
* Get current dashboard data
|
|
3149
|
+
*/
|
|
3150
|
+
getDashboardData() {
|
|
3151
|
+
const metrics = this.analytics.getMetrics();
|
|
3152
|
+
const score = this.analytics.getPerformanceScore();
|
|
3153
|
+
const recommendations = this.analytics.getRecommendations();
|
|
3154
|
+
// Identify bottlenecks
|
|
3155
|
+
const bottlenecks = this.identifyBottlenecks(metrics);
|
|
3156
|
+
return {
|
|
3157
|
+
overallScore: score,
|
|
3158
|
+
fps: metrics.scrollPerformance.averageFPS,
|
|
3159
|
+
renderTime: metrics.renderTime.average,
|
|
3160
|
+
memoryUsage: metrics.memoryUsage.current,
|
|
3161
|
+
networkLatency: metrics.networkPerformance.averageLatency,
|
|
3162
|
+
recommendations,
|
|
3163
|
+
bottlenecks
|
|
3164
|
+
};
|
|
3165
|
+
}
|
|
3166
|
+
/**
|
|
3167
|
+
* Identify performance bottlenecks
|
|
3168
|
+
*/
|
|
3169
|
+
identifyBottlenecks(metrics) {
|
|
3170
|
+
const bottlenecks = [];
|
|
3171
|
+
// FPS bottleneck
|
|
3172
|
+
if (metrics.scrollPerformance.averageFPS < 30) {
|
|
3173
|
+
bottlenecks.push('CRITICAL: Low FPS - Rendering is the bottleneck');
|
|
3174
|
+
}
|
|
3175
|
+
else if (metrics.scrollPerformance.averageFPS < 60) {
|
|
3176
|
+
bottlenecks.push('WARNING: Below 60 FPS - Consider optimizing renders');
|
|
3177
|
+
}
|
|
3178
|
+
// Render time bottleneck
|
|
3179
|
+
if (metrics.renderTime.average > 50) {
|
|
3180
|
+
bottlenecks.push('HIGH: Slow render times - Simplify item components');
|
|
3181
|
+
}
|
|
3182
|
+
else if (metrics.renderTime.average > 16) {
|
|
3183
|
+
bottlenecks.push('MEDIUM: Render time above frame budget');
|
|
3184
|
+
}
|
|
3185
|
+
// Memory bottleneck
|
|
3186
|
+
if (metrics.memoryUsage.trend === 'increasing') {
|
|
3187
|
+
bottlenecks.push('WARNING: Memory leak detected - Check cleanup logic');
|
|
3188
|
+
}
|
|
3189
|
+
// Network bottleneck
|
|
3190
|
+
if (metrics.networkPerformance.averageLatency > 500) {
|
|
3191
|
+
bottlenecks.push('HIGH: Network latency - Implement better caching');
|
|
3192
|
+
}
|
|
3193
|
+
// Jank bottleneck
|
|
3194
|
+
if (metrics.scrollPerformance.jankCount > 20) {
|
|
3195
|
+
bottlenecks.push('CRITICAL: Frequent jank - Smooth scroll performance');
|
|
3196
|
+
}
|
|
3197
|
+
if (bottlenecks.length === 0) {
|
|
3198
|
+
bottlenecks.push('No bottlenecks detected - Performance is optimal');
|
|
3199
|
+
}
|
|
3200
|
+
return bottlenecks;
|
|
3201
|
+
}
|
|
3202
|
+
/**
|
|
3203
|
+
* Add listener for dashboard updates
|
|
3204
|
+
*/
|
|
3205
|
+
addListener(callback) {
|
|
3206
|
+
this.listeners.push(callback);
|
|
3207
|
+
}
|
|
3208
|
+
/**
|
|
3209
|
+
* Remove listener
|
|
3210
|
+
*/
|
|
3211
|
+
removeListener(callback) {
|
|
3212
|
+
const index = this.listeners.indexOf(callback);
|
|
3213
|
+
if (index > -1) {
|
|
3214
|
+
this.listeners.splice(index, 1);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
/**
|
|
3218
|
+
* Notify all listeners
|
|
3219
|
+
*/
|
|
3220
|
+
notifyListeners(data) {
|
|
3221
|
+
this.listeners.forEach(listener => {
|
|
3222
|
+
try {
|
|
3223
|
+
listener(data);
|
|
3224
|
+
}
|
|
3225
|
+
catch (error) {
|
|
3226
|
+
console.error('Dashboard listener error:', error);
|
|
3227
|
+
}
|
|
3228
|
+
});
|
|
3229
|
+
}
|
|
3230
|
+
/**
|
|
3231
|
+
* Export metrics as JSON
|
|
3232
|
+
*/
|
|
3233
|
+
exportMetrics() {
|
|
3234
|
+
const metrics = this.analytics.getMetrics();
|
|
3235
|
+
return JSON.stringify(metrics, null, 2);
|
|
3236
|
+
}
|
|
3237
|
+
/**
|
|
3238
|
+
* Get performance report
|
|
3239
|
+
*/
|
|
3240
|
+
getPerformanceReport() {
|
|
3241
|
+
const data = this.getDashboardData();
|
|
3242
|
+
let report = '=== PERFORMANCE REPORT ===\n\n';
|
|
3243
|
+
report += `Overall Score: ${data.overallScore}/100\n`;
|
|
3244
|
+
report += `FPS: ${data.fps}\n`;
|
|
3245
|
+
report += `Average Render Time: ${data.renderTime.toFixed(2)}ms\n`;
|
|
3246
|
+
report += `Memory Usage: ${data.memoryUsage.toFixed(2)}MB\n`;
|
|
3247
|
+
report += `Network Latency: ${data.networkLatency.toFixed(2)}ms\n\n`;
|
|
3248
|
+
report += 'BOTTLENECKS:\n';
|
|
3249
|
+
data.bottlenecks.forEach(b => {
|
|
3250
|
+
report += ` - ${b}\n`;
|
|
3251
|
+
});
|
|
3252
|
+
report += '\nRECOMMENDATIONS:\n';
|
|
3253
|
+
data.recommendations.forEach(r => {
|
|
3254
|
+
report += ` - ${r}\n`;
|
|
3255
|
+
});
|
|
3256
|
+
return report;
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
/**
|
|
3261
|
+
* Accessibility Manager
|
|
3262
|
+
* Handles keyboard navigation, screen reader compatibility, and ARIA attributes
|
|
3263
|
+
*/
|
|
3264
|
+
class AccessibilityManager {
|
|
3265
|
+
constructor(config) {
|
|
3266
|
+
this.focusedIndex = -1;
|
|
3267
|
+
this.containerElement = null;
|
|
3268
|
+
this.itemElements = [];
|
|
3269
|
+
this.config = {
|
|
3270
|
+
enableKeyboardNav: true,
|
|
3271
|
+
enableScreenReader: true,
|
|
3272
|
+
enableARIA: true,
|
|
3273
|
+
...config
|
|
3274
|
+
};
|
|
3275
|
+
}
|
|
3276
|
+
/**
|
|
3277
|
+
* Initialize accessibility features
|
|
3278
|
+
*/
|
|
3279
|
+
initialize(container) {
|
|
3280
|
+
this.containerElement = container;
|
|
3281
|
+
// Set ARIA roles
|
|
3282
|
+
if (this.config.enableARIA) {
|
|
3283
|
+
this.setupARIA();
|
|
3284
|
+
}
|
|
3285
|
+
// Setup keyboard navigation
|
|
3286
|
+
if (this.config.enableKeyboardNav) {
|
|
3287
|
+
this.setupKeyboardNav();
|
|
3288
|
+
}
|
|
3289
|
+
// Setup screen reader announcements
|
|
3290
|
+
if (this.config.enableScreenReader) {
|
|
3291
|
+
this.setupScreenReader();
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
/**
|
|
3295
|
+
* Setup ARIA attributes
|
|
3296
|
+
*/
|
|
3297
|
+
setupARIA() {
|
|
3298
|
+
if (!this.containerElement)
|
|
3299
|
+
return;
|
|
3300
|
+
// Set list role
|
|
3301
|
+
this.containerElement.setAttribute('role', 'list');
|
|
3302
|
+
this.containerElement.setAttribute('aria-label', 'Virtual scroll list');
|
|
3303
|
+
// Set tabindex for keyboard focus
|
|
3304
|
+
this.containerElement.setAttribute('tabindex', '0');
|
|
3305
|
+
}
|
|
3306
|
+
/**
|
|
3307
|
+
* Setup keyboard navigation
|
|
3308
|
+
*/
|
|
3309
|
+
setupKeyboardNav() {
|
|
3310
|
+
if (!this.containerElement)
|
|
3311
|
+
return;
|
|
3312
|
+
this.containerElement.addEventListener('keydown', (e) => {
|
|
3313
|
+
this.handleKeyDown(e);
|
|
3314
|
+
});
|
|
3315
|
+
}
|
|
3316
|
+
/**
|
|
3317
|
+
* Handle keyboard events
|
|
3318
|
+
*/
|
|
3319
|
+
handleKeyDown(e) {
|
|
3320
|
+
switch (e.key) {
|
|
3321
|
+
case 'ArrowDown':
|
|
3322
|
+
e.preventDefault();
|
|
3323
|
+
this.focusNext();
|
|
3324
|
+
break;
|
|
3325
|
+
case 'ArrowUp':
|
|
3326
|
+
e.preventDefault();
|
|
3327
|
+
this.focusPrevious();
|
|
3328
|
+
break;
|
|
3329
|
+
case 'Home':
|
|
3330
|
+
e.preventDefault();
|
|
3331
|
+
this.focusFirst();
|
|
3332
|
+
break;
|
|
3333
|
+
case 'End':
|
|
3334
|
+
e.preventDefault();
|
|
3335
|
+
this.focusLast();
|
|
3336
|
+
break;
|
|
3337
|
+
case 'PageDown':
|
|
3338
|
+
e.preventDefault();
|
|
3339
|
+
this.focusPageDown();
|
|
3340
|
+
break;
|
|
3341
|
+
case 'PageUp':
|
|
3342
|
+
e.preventDefault();
|
|
3343
|
+
this.focusPageUp();
|
|
3344
|
+
break;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Focus next item
|
|
3349
|
+
*/
|
|
3350
|
+
focusNext() {
|
|
3351
|
+
if (this.focusedIndex < this.itemElements.length - 1) {
|
|
3352
|
+
this.focusedIndex++;
|
|
3353
|
+
this.focusItem(this.focusedIndex);
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
/**
|
|
3357
|
+
* Focus previous item
|
|
3358
|
+
*/
|
|
3359
|
+
focusPrevious() {
|
|
3360
|
+
if (this.focusedIndex > 0) {
|
|
3361
|
+
this.focusedIndex--;
|
|
3362
|
+
this.focusItem(this.focusedIndex);
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
/**
|
|
3366
|
+
* Focus first item
|
|
3367
|
+
*/
|
|
3368
|
+
focusFirst() {
|
|
3369
|
+
this.focusedIndex = 0;
|
|
3370
|
+
this.focusItem(0);
|
|
3371
|
+
}
|
|
3372
|
+
/**
|
|
3373
|
+
* Focus last item
|
|
3374
|
+
*/
|
|
3375
|
+
focusLast() {
|
|
3376
|
+
this.focusedIndex = this.itemElements.length - 1;
|
|
3377
|
+
this.focusItem(this.focusedIndex);
|
|
3378
|
+
}
|
|
3379
|
+
/**
|
|
3380
|
+
* Focus page down (10 items)
|
|
3381
|
+
*/
|
|
3382
|
+
focusPageDown() {
|
|
3383
|
+
this.focusedIndex = Math.min(this.focusedIndex + 10, this.itemElements.length - 1);
|
|
3384
|
+
this.focusItem(this.focusedIndex);
|
|
3385
|
+
}
|
|
3386
|
+
/**
|
|
3387
|
+
* Focus page up (10 items)
|
|
3388
|
+
*/
|
|
3389
|
+
focusPageUp() {
|
|
3390
|
+
this.focusedIndex = Math.max(this.focusedIndex - 10, 0);
|
|
3391
|
+
this.focusItem(this.focusedIndex);
|
|
3392
|
+
}
|
|
3393
|
+
/**
|
|
3394
|
+
* Focus specific item
|
|
3395
|
+
*/
|
|
3396
|
+
focusItem(index) {
|
|
3397
|
+
if (index >= 0 && index < this.itemElements.length) {
|
|
3398
|
+
const element = this.itemElements[index];
|
|
3399
|
+
element.focus();
|
|
3400
|
+
element.scrollIntoView({ block: 'nearest' });
|
|
3401
|
+
// Announce to screen readers
|
|
3402
|
+
this.announce(`Item ${index + 1} of ${this.itemElements.length}`);
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
/**
|
|
3406
|
+
* Setup screen reader support
|
|
3407
|
+
*/
|
|
3408
|
+
setupScreenReader() {
|
|
3409
|
+
// Create live region for announcements
|
|
3410
|
+
const liveRegion = document.createElement('div');
|
|
3411
|
+
liveRegion.setAttribute('role', 'status');
|
|
3412
|
+
liveRegion.setAttribute('aria-live', 'polite');
|
|
3413
|
+
liveRegion.setAttribute('aria-atomic', 'true');
|
|
3414
|
+
liveRegion.className = 'sr-only';
|
|
3415
|
+
liveRegion.style.cssText = `
|
|
3416
|
+
position: absolute;
|
|
3417
|
+
width: 1px;
|
|
3418
|
+
height: 1px;
|
|
3419
|
+
padding: 0;
|
|
3420
|
+
margin: -1px;
|
|
3421
|
+
overflow: hidden;
|
|
3422
|
+
clip: rect(0, 0, 0, 0);
|
|
3423
|
+
white-space: nowrap;
|
|
3424
|
+
border: 0;
|
|
3425
|
+
`;
|
|
3426
|
+
document.body.appendChild(liveRegion);
|
|
3427
|
+
}
|
|
3428
|
+
/**
|
|
3429
|
+
* Announce message to screen readers
|
|
3430
|
+
*/
|
|
3431
|
+
announce(message) {
|
|
3432
|
+
const liveRegion = document.querySelector('[role="status"][aria-live="polite"]');
|
|
3433
|
+
if (liveRegion) {
|
|
3434
|
+
liveRegion.textContent = message;
|
|
3435
|
+
// Clear after announcement
|
|
3436
|
+
setTimeout(() => {
|
|
3437
|
+
liveRegion.textContent = '';
|
|
3438
|
+
}, 1000);
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
/**
|
|
3442
|
+
* Update item elements
|
|
3443
|
+
*/
|
|
3444
|
+
updateItems(elements) {
|
|
3445
|
+
this.itemElements = elements;
|
|
3446
|
+
// Set ARIA attributes on items
|
|
3447
|
+
if (this.config.enableARIA) {
|
|
3448
|
+
elements.forEach((el, index) => {
|
|
3449
|
+
el.setAttribute('role', 'listitem');
|
|
3450
|
+
el.setAttribute('aria-setsize', elements.length.toString());
|
|
3451
|
+
el.setAttribute('aria-posinset', (index + 1).toString());
|
|
3452
|
+
el.setAttribute('tabindex', '-1');
|
|
3453
|
+
});
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
/**
|
|
3457
|
+
* Set focused index from outside
|
|
3458
|
+
*/
|
|
3459
|
+
setFocusedIndex(index) {
|
|
3460
|
+
this.focusedIndex = index;
|
|
3461
|
+
}
|
|
3462
|
+
/**
|
|
3463
|
+
* Get current focused index
|
|
3464
|
+
*/
|
|
3465
|
+
getFocusedIndex() {
|
|
3466
|
+
return this.focusedIndex;
|
|
3467
|
+
}
|
|
3468
|
+
/**
|
|
3469
|
+
* Cleanup accessibility features
|
|
3470
|
+
*/
|
|
3471
|
+
cleanup() {
|
|
3472
|
+
if (this.containerElement) {
|
|
3473
|
+
this.containerElement.removeEventListener('keydown', this.handleKeyDown.bind(this));
|
|
3474
|
+
}
|
|
3475
|
+
const liveRegion = document.querySelector('[role="status"][aria-live="polite"]');
|
|
3476
|
+
if (liveRegion) {
|
|
3477
|
+
liveRegion.remove();
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
/**
|
|
3483
|
+
* Animation Manager
|
|
3484
|
+
* Handles smooth transitions, staggered animations, and performance-optimized animations
|
|
3485
|
+
*/
|
|
3486
|
+
class AnimationManager {
|
|
3487
|
+
constructor(config) {
|
|
3488
|
+
this.activeAnimations = new Map();
|
|
3489
|
+
this.prefersReducedMotion = false;
|
|
3490
|
+
this.config = {
|
|
3491
|
+
enableTransitions: true,
|
|
3492
|
+
enableStagger: true,
|
|
3493
|
+
staggerDelay: 50,
|
|
3494
|
+
transitionDuration: 300,
|
|
3495
|
+
easingFunction: 'ease-out',
|
|
3496
|
+
...config
|
|
3497
|
+
};
|
|
3498
|
+
// Check for reduced motion preference
|
|
3499
|
+
if (typeof window !== 'undefined') {
|
|
3500
|
+
this.prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3503
|
+
/**
|
|
3504
|
+
* Animate item entrance
|
|
3505
|
+
*/
|
|
3506
|
+
animateEntrance(element, index) {
|
|
3507
|
+
if (this.prefersReducedMotion || !this.config.enableTransitions) {
|
|
3508
|
+
element.style.opacity = '1';
|
|
3509
|
+
element.style.transform = 'none';
|
|
3510
|
+
return Promise.resolve();
|
|
3511
|
+
}
|
|
3512
|
+
return new Promise((resolve) => {
|
|
3513
|
+
// Initial state
|
|
3514
|
+
element.style.opacity = '0';
|
|
3515
|
+
element.style.transform = 'translateY(20px)';
|
|
3516
|
+
element.style.transition = `opacity ${this.config.transitionDuration}ms ${this.config.easingFunction},
|
|
3517
|
+
transform ${this.config.transitionDuration}ms ${this.config.easingFunction}`;
|
|
3518
|
+
// Trigger reflow
|
|
3519
|
+
element.offsetHeight;
|
|
3520
|
+
// Animate to final state
|
|
3521
|
+
if (this.config.enableStagger) {
|
|
3522
|
+
setTimeout(() => {
|
|
3523
|
+
element.style.opacity = '1';
|
|
3524
|
+
element.style.transform = 'translateY(0)';
|
|
3525
|
+
setTimeout(resolve, this.config.transitionDuration);
|
|
3526
|
+
}, index * this.config.staggerDelay);
|
|
3527
|
+
}
|
|
3528
|
+
else {
|
|
3529
|
+
element.style.opacity = '1';
|
|
3530
|
+
element.style.transform = 'translateY(0)';
|
|
3531
|
+
setTimeout(resolve, this.config.transitionDuration);
|
|
3532
|
+
}
|
|
3533
|
+
});
|
|
3534
|
+
}
|
|
3535
|
+
/**
|
|
3536
|
+
* Animate item exit
|
|
3537
|
+
*/
|
|
3538
|
+
animateExit(element) {
|
|
3539
|
+
if (this.prefersReducedMotion || !this.config.enableTransitions) {
|
|
3540
|
+
element.style.opacity = '0';
|
|
3541
|
+
return Promise.resolve();
|
|
3542
|
+
}
|
|
3543
|
+
return new Promise((resolve) => {
|
|
3544
|
+
element.style.transition = `opacity ${this.config.transitionDuration}ms ${this.config.easingFunction}`;
|
|
3545
|
+
element.style.opacity = '0';
|
|
3546
|
+
setTimeout(resolve, this.config.transitionDuration);
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
/**
|
|
3550
|
+
* Animate scroll indicator
|
|
3551
|
+
*/
|
|
3552
|
+
animateScrollIndicator(element, direction) {
|
|
3553
|
+
if (this.prefersReducedMotion)
|
|
3554
|
+
return;
|
|
3555
|
+
const translation = direction === 'down' ? 'translateY(5px)' : 'translateY(-5px)';
|
|
3556
|
+
element.style.transition = `transform 200ms ${this.config.easingFunction}`;
|
|
3557
|
+
element.style.transform = translation;
|
|
3558
|
+
setTimeout(() => {
|
|
3559
|
+
element.style.transform = 'translateY(0)';
|
|
3560
|
+
}, 200);
|
|
3561
|
+
}
|
|
3562
|
+
/**
|
|
3563
|
+
* Smooth scroll to position
|
|
3564
|
+
*/
|
|
3565
|
+
smoothScroll(container, targetPosition, duration = 500) {
|
|
3566
|
+
return new Promise((resolve) => {
|
|
3567
|
+
if (this.prefersReducedMotion) {
|
|
3568
|
+
container.scrollTop = targetPosition;
|
|
3569
|
+
resolve();
|
|
3570
|
+
return;
|
|
3571
|
+
}
|
|
3572
|
+
const startPosition = container.scrollTop;
|
|
3573
|
+
const distance = targetPosition - startPosition;
|
|
3574
|
+
const startTime = performance.now();
|
|
3575
|
+
const easeInOutQuad = (t) => {
|
|
3576
|
+
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
3577
|
+
};
|
|
3578
|
+
const animate = (currentTime) => {
|
|
3579
|
+
const timeElapsed = currentTime - startTime;
|
|
3580
|
+
const progress = Math.min(timeElapsed / duration, 1);
|
|
3581
|
+
const ease = easeInOutQuad(progress);
|
|
3582
|
+
container.scrollTop = startPosition + distance * ease;
|
|
3583
|
+
if (timeElapsed < duration) {
|
|
3584
|
+
requestAnimationFrame(animate);
|
|
3585
|
+
}
|
|
3586
|
+
else {
|
|
3587
|
+
resolve();
|
|
3588
|
+
}
|
|
3589
|
+
};
|
|
3590
|
+
requestAnimationFrame(animate);
|
|
3591
|
+
});
|
|
3592
|
+
}
|
|
3593
|
+
/**
|
|
3594
|
+
* Animate loading skeleton
|
|
3595
|
+
*/
|
|
3596
|
+
animateSkeleton(element) {
|
|
3597
|
+
if (this.prefersReducedMotion)
|
|
3598
|
+
return;
|
|
3599
|
+
element.style.background = 'linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)';
|
|
3600
|
+
element.style.backgroundSize = '200% 100%';
|
|
3601
|
+
element.style.animation = 'skeleton-loading 1.5s infinite';
|
|
3602
|
+
// Add keyframes if not already present
|
|
3603
|
+
if (!document.getElementById('skeleton-keyframes')) {
|
|
3604
|
+
const style = document.createElement('style');
|
|
3605
|
+
style.id = 'skeleton-keyframes';
|
|
3606
|
+
style.textContent = `
|
|
3607
|
+
@keyframes skeleton-loading {
|
|
3608
|
+
0% { background-position: 200% 0; }
|
|
3609
|
+
100% { background-position: -200% 0; }
|
|
3610
|
+
}
|
|
3611
|
+
`;
|
|
3612
|
+
document.head.appendChild(style);
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
/**
|
|
3616
|
+
* Stop skeleton animation
|
|
3617
|
+
*/
|
|
3618
|
+
stopSkeletonAnimation(element) {
|
|
3619
|
+
element.style.animation = '';
|
|
3620
|
+
element.style.background = '';
|
|
3621
|
+
element.style.backgroundSize = '';
|
|
3622
|
+
}
|
|
3623
|
+
/**
|
|
3624
|
+
* Animate item highlight
|
|
3625
|
+
*/
|
|
3626
|
+
animateHighlight(element, color = '#ffeb3b', duration = 1000) {
|
|
3627
|
+
if (this.prefersReducedMotion)
|
|
3628
|
+
return Promise.resolve();
|
|
3629
|
+
return new Promise((resolve) => {
|
|
3630
|
+
const originalBackground = element.style.background;
|
|
3631
|
+
element.style.transition = `background ${duration / 2}ms ${this.config.easingFunction}`;
|
|
3632
|
+
element.style.background = color;
|
|
3633
|
+
setTimeout(() => {
|
|
3634
|
+
element.style.transition = `background ${duration / 2}ms ${this.config.easingFunction}`;
|
|
3635
|
+
element.style.background = originalBackground;
|
|
3636
|
+
setTimeout(resolve, duration / 2);
|
|
3637
|
+
}, duration / 2);
|
|
3638
|
+
});
|
|
3639
|
+
}
|
|
3640
|
+
/**
|
|
3641
|
+
* Batch animate multiple elements
|
|
3642
|
+
*/
|
|
3643
|
+
async batchAnimate(elements, animation) {
|
|
3644
|
+
const promises = elements.map((el, index) => {
|
|
3645
|
+
if (animation === 'entrance') {
|
|
3646
|
+
return this.animateEntrance(el, index);
|
|
3647
|
+
}
|
|
3648
|
+
else {
|
|
3649
|
+
return this.animateExit(el);
|
|
3650
|
+
}
|
|
3651
|
+
});
|
|
3652
|
+
await Promise.all(promises);
|
|
3653
|
+
}
|
|
3654
|
+
/**
|
|
3655
|
+
* Cancel active animations
|
|
3656
|
+
*/
|
|
3657
|
+
cancelAnimations() {
|
|
3658
|
+
this.activeAnimations.forEach((animation) => {
|
|
3659
|
+
animation.cancel();
|
|
3660
|
+
});
|
|
3661
|
+
this.activeAnimations.clear();
|
|
3662
|
+
}
|
|
3663
|
+
/**
|
|
3664
|
+
* Check if reduced motion is preferred
|
|
3665
|
+
*/
|
|
3666
|
+
hasReducedMotion() {
|
|
3667
|
+
return this.prefersReducedMotion;
|
|
3668
|
+
}
|
|
3669
|
+
/**
|
|
3670
|
+
* Update animation config
|
|
3671
|
+
*/
|
|
3672
|
+
updateConfig(config) {
|
|
3673
|
+
this.config = { ...this.config, ...config };
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
|
|
2925
3677
|
class ScrollObserver {
|
|
2926
3678
|
constructor(container, callback, options) {
|
|
2927
3679
|
this.observer = null;
|
|
@@ -3291,7 +4043,9 @@ const LazyScrollElement = typeof window !== 'undefined' && typeof HTMLElement !=
|
|
|
3291
4043
|
? LazyScrollElementClass // Will be replaced with actual element in browser
|
|
3292
4044
|
: LazyScrollElementClass; // SSR-safe fallback
|
|
3293
4045
|
|
|
4046
|
+
exports.AccessibilityManager = AccessibilityManager;
|
|
3294
4047
|
exports.AdaptiveBufferCalculator = AdaptiveBufferCalculator;
|
|
4048
|
+
exports.AnimationManager = AnimationManager;
|
|
3295
4049
|
exports.BatchSizeOptimizer = BatchSizeOptimizer;
|
|
3296
4050
|
exports.ContentComplexityAnalyzer = ContentComplexityAnalyzer;
|
|
3297
4051
|
exports.DevicePerformanceMonitor = DevicePerformanceMonitor;
|
|
@@ -3308,6 +4062,8 @@ exports.MemoryManager = MemoryManager;
|
|
|
3308
4062
|
exports.NetworkAwarePrefetchManager = NetworkAwarePrefetchManager;
|
|
3309
4063
|
exports.NetworkAwareRequestQueue = NetworkAwareRequestQueue;
|
|
3310
4064
|
exports.NetworkSpeedDetector = NetworkSpeedDetector;
|
|
4065
|
+
exports.PerformanceAnalytics = PerformanceAnalytics;
|
|
4066
|
+
exports.PerformanceDashboard = PerformanceDashboard;
|
|
3311
4067
|
exports.PerformanceOptimizer = PerformanceOptimizer;
|
|
3312
4068
|
exports.PreemptiveCache = PreemptiveCache;
|
|
3313
4069
|
exports.PrefetchManager = PrefetchManager;
|