@sc4rfurryx/proteusjs 1.0.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.
Files changed (82) hide show
  1. package/API.md +438 -0
  2. package/FEATURES.md +286 -0
  3. package/LICENSE +21 -0
  4. package/README.md +645 -0
  5. package/dist/.tsbuildinfo +1 -0
  6. package/dist/proteus.cjs.js +16014 -0
  7. package/dist/proteus.cjs.js.map +1 -0
  8. package/dist/proteus.d.ts +3018 -0
  9. package/dist/proteus.esm.js +16005 -0
  10. package/dist/proteus.esm.js.map +1 -0
  11. package/dist/proteus.esm.min.js +8 -0
  12. package/dist/proteus.esm.min.js.map +1 -0
  13. package/dist/proteus.js +16020 -0
  14. package/dist/proteus.js.map +1 -0
  15. package/dist/proteus.min.js +8 -0
  16. package/dist/proteus.min.js.map +1 -0
  17. package/package.json +98 -0
  18. package/src/__tests__/mvp-integration.test.ts +518 -0
  19. package/src/accessibility/AccessibilityEngine.ts +2106 -0
  20. package/src/accessibility/ScreenReaderSupport.ts +444 -0
  21. package/src/accessibility/__tests__/ScreenReaderSupport.test.ts +435 -0
  22. package/src/animations/FLIPAnimationSystem.ts +491 -0
  23. package/src/compatibility/BrowserCompatibility.ts +1076 -0
  24. package/src/containers/BreakpointSystem.ts +347 -0
  25. package/src/containers/ContainerBreakpoints.ts +726 -0
  26. package/src/containers/ContainerManager.ts +370 -0
  27. package/src/containers/ContainerUnits.ts +336 -0
  28. package/src/containers/ContextIsolation.ts +394 -0
  29. package/src/containers/ElementQueries.ts +411 -0
  30. package/src/containers/SmartContainer.ts +536 -0
  31. package/src/containers/SmartContainers.ts +376 -0
  32. package/src/containers/__tests__/ContainerBreakpoints.test.ts +411 -0
  33. package/src/containers/__tests__/SmartContainers.test.ts +281 -0
  34. package/src/content/ResponsiveImages.ts +570 -0
  35. package/src/core/EventSystem.ts +147 -0
  36. package/src/core/MemoryManager.ts +321 -0
  37. package/src/core/PerformanceMonitor.ts +238 -0
  38. package/src/core/PluginSystem.ts +275 -0
  39. package/src/core/ProteusJS.test.ts +164 -0
  40. package/src/core/ProteusJS.ts +962 -0
  41. package/src/developer/PerformanceProfiler.ts +567 -0
  42. package/src/developer/VisualDebuggingTools.ts +656 -0
  43. package/src/developer/ZeroConfigSystem.ts +593 -0
  44. package/src/index.ts +35 -0
  45. package/src/integration.test.ts +227 -0
  46. package/src/layout/AdaptiveGrid.ts +429 -0
  47. package/src/layout/ContentReordering.ts +532 -0
  48. package/src/layout/FlexboxEnhancer.ts +406 -0
  49. package/src/layout/FlowLayout.ts +545 -0
  50. package/src/layout/SpacingSystem.ts +512 -0
  51. package/src/observers/IntersectionObserverPolyfill.ts +289 -0
  52. package/src/observers/ObserverManager.ts +299 -0
  53. package/src/observers/ResizeObserverPolyfill.ts +179 -0
  54. package/src/performance/BatchDOMOperations.ts +519 -0
  55. package/src/performance/CSSOptimizationEngine.ts +646 -0
  56. package/src/performance/CacheOptimizationSystem.ts +601 -0
  57. package/src/performance/EfficientEventHandler.ts +740 -0
  58. package/src/performance/LazyEvaluationSystem.ts +532 -0
  59. package/src/performance/MemoryManagementSystem.ts +497 -0
  60. package/src/performance/PerformanceMonitor.ts +931 -0
  61. package/src/performance/__tests__/BatchDOMOperations.test.ts +309 -0
  62. package/src/performance/__tests__/EfficientEventHandler.test.ts +268 -0
  63. package/src/performance/__tests__/PerformanceMonitor.test.ts +422 -0
  64. package/src/polyfills/BrowserPolyfills.ts +586 -0
  65. package/src/polyfills/__tests__/BrowserPolyfills.test.ts +328 -0
  66. package/src/test/setup.ts +115 -0
  67. package/src/theming/SmartThemeSystem.ts +591 -0
  68. package/src/types/index.ts +134 -0
  69. package/src/typography/ClampScaling.ts +356 -0
  70. package/src/typography/FluidTypography.ts +759 -0
  71. package/src/typography/LineHeightOptimization.ts +430 -0
  72. package/src/typography/LineHeightOptimizer.ts +326 -0
  73. package/src/typography/TextFitting.ts +355 -0
  74. package/src/typography/TypographicScale.ts +428 -0
  75. package/src/typography/VerticalRhythm.ts +369 -0
  76. package/src/typography/__tests__/FluidTypography.test.ts +432 -0
  77. package/src/typography/__tests__/LineHeightOptimization.test.ts +436 -0
  78. package/src/utils/Logger.ts +173 -0
  79. package/src/utils/debounce.ts +259 -0
  80. package/src/utils/performance.ts +371 -0
  81. package/src/utils/support.ts +106 -0
  82. package/src/utils/version.ts +24 -0
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Memory Manager for ProteusJS
3
+ * Prevents memory leaks and manages resource cleanup
4
+ */
5
+
6
+ export interface ManagedResource {
7
+ id: string;
8
+ type: 'observer' | 'listener' | 'timer' | 'animation' | 'cache';
9
+ cleanup: () => void;
10
+ element?: Element;
11
+ timestamp: number;
12
+ }
13
+
14
+ export class MemoryManager {
15
+ private resources: Map<string, ManagedResource> = new Map();
16
+ private elementResources: Map<Element, Set<string>> = new Map();
17
+ private mutationObserver: MutationObserver | null = null;
18
+ private cleanupInterval: number | null = null;
19
+ private isMonitoring: boolean = false;
20
+
21
+ constructor() {
22
+ this.setupDOMObserver();
23
+ this.startPeriodicCleanup();
24
+ }
25
+
26
+ /**
27
+ * Register a resource for automatic cleanup
28
+ */
29
+ public register(resource: Omit<ManagedResource, 'timestamp'>): string {
30
+ const fullResource: ManagedResource = {
31
+ ...resource,
32
+ timestamp: Date.now()
33
+ };
34
+
35
+ this.resources.set(resource.id, fullResource);
36
+
37
+ // Track element-specific resources
38
+ if (resource.element) {
39
+ if (!this.elementResources.has(resource.element)) {
40
+ this.elementResources.set(resource.element, new Set());
41
+ }
42
+ this.elementResources.get(resource.element)!.add(resource.id);
43
+ }
44
+
45
+ return resource.id;
46
+ }
47
+
48
+ /**
49
+ * Unregister and cleanup a resource
50
+ */
51
+ public unregister(resourceId: string): boolean {
52
+ const resource = this.resources.get(resourceId);
53
+ if (!resource) return false;
54
+
55
+ try {
56
+ resource.cleanup();
57
+ } catch (error) {
58
+ console.error(`ProteusJS: Error cleaning up resource ${resourceId}:`, error);
59
+ }
60
+
61
+ this.resources.delete(resourceId);
62
+
63
+ // Remove from element tracking
64
+ if (resource.element) {
65
+ const elementResources = this.elementResources.get(resource.element);
66
+ if (elementResources) {
67
+ elementResources.delete(resourceId);
68
+ if (elementResources.size === 0) {
69
+ this.elementResources.delete(resource.element);
70
+ }
71
+ }
72
+ }
73
+
74
+ return true;
75
+ }
76
+
77
+ /**
78
+ * Cleanup all resources associated with an element
79
+ */
80
+ public cleanupElement(element: Element): number {
81
+ const resourceIds = this.elementResources.get(element);
82
+ if (!resourceIds) return 0;
83
+
84
+ let cleanedCount = 0;
85
+ resourceIds.forEach(resourceId => {
86
+ if (this.unregister(resourceId)) {
87
+ cleanedCount++;
88
+ }
89
+ });
90
+
91
+ return cleanedCount;
92
+ }
93
+
94
+ /**
95
+ * Cleanup resources by type
96
+ */
97
+ public cleanupByType(type: ManagedResource['type']): number {
98
+ let cleanedCount = 0;
99
+ const toCleanup: string[] = [];
100
+
101
+ this.resources.forEach((resource, id) => {
102
+ if (resource.type === type) {
103
+ toCleanup.push(id);
104
+ }
105
+ });
106
+
107
+ toCleanup.forEach(id => {
108
+ if (this.unregister(id)) {
109
+ cleanedCount++;
110
+ }
111
+ });
112
+
113
+ return cleanedCount;
114
+ }
115
+
116
+ /**
117
+ * Cleanup old resources based on age
118
+ */
119
+ public cleanupOldResources(maxAge: number = 300000): number { // 5 minutes default
120
+ let cleanedCount = 0;
121
+ const now = Date.now();
122
+ const toCleanup: string[] = [];
123
+
124
+ this.resources.forEach((resource, id) => {
125
+ if (now - resource.timestamp > maxAge) {
126
+ toCleanup.push(id);
127
+ }
128
+ });
129
+
130
+ toCleanup.forEach(id => {
131
+ if (this.unregister(id)) {
132
+ cleanedCount++;
133
+ }
134
+ });
135
+
136
+ return cleanedCount;
137
+ }
138
+
139
+ /**
140
+ * Force garbage collection if available
141
+ */
142
+ public forceGarbageCollection(): void {
143
+ if ('gc' in window && typeof (window as any).gc === 'function') {
144
+ try {
145
+ (window as any).gc();
146
+ } catch (error) {
147
+ // Ignore errors - gc might not be available
148
+ }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Get memory usage information
154
+ */
155
+ public getMemoryInfo(): object {
156
+ const info: any = {
157
+ managedResources: this.resources.size,
158
+ trackedElements: this.elementResources.size,
159
+ resourcesByType: {} as Record<string, number>
160
+ };
161
+
162
+ // Count resources by type
163
+ this.resources.forEach(resource => {
164
+ info.resourcesByType[resource.type] = (info.resourcesByType[resource.type] || 0) + 1;
165
+ });
166
+
167
+ // Add browser memory info if available
168
+ if ('memory' in performance) {
169
+ const memory = (performance as any).memory;
170
+ info.browserMemory = {
171
+ usedJSHeapSize: memory.usedJSHeapSize,
172
+ totalJSHeapSize: memory.totalJSHeapSize,
173
+ jsHeapSizeLimit: memory.jsHeapSizeLimit
174
+ };
175
+ }
176
+
177
+ return info;
178
+ }
179
+
180
+ /**
181
+ * Check for potential memory leaks
182
+ */
183
+ public detectLeaks(): string[] {
184
+ const warnings: string[] = [];
185
+ const now = Date.now();
186
+
187
+ // Check for too many resources
188
+ if (this.resources.size > 1000) {
189
+ warnings.push(`High number of managed resources: ${this.resources.size}`);
190
+ }
191
+
192
+ // Check for old resources
193
+ let oldResourceCount = 0;
194
+ this.resources.forEach(resource => {
195
+ if (now - resource.timestamp > 600000) { // 10 minutes
196
+ oldResourceCount++;
197
+ }
198
+ });
199
+
200
+ if (oldResourceCount > 50) {
201
+ warnings.push(`Many old resources detected: ${oldResourceCount}`);
202
+ }
203
+
204
+ // Check for orphaned element resources
205
+ let orphanedCount = 0;
206
+ this.elementResources.forEach((resourceIds, element) => {
207
+ if (!document.contains(element)) {
208
+ orphanedCount += resourceIds.size;
209
+ }
210
+ });
211
+
212
+ if (orphanedCount > 0) {
213
+ warnings.push(`Orphaned element resources detected: ${orphanedCount}`);
214
+ }
215
+
216
+ return warnings;
217
+ }
218
+
219
+ /**
220
+ * Cleanup all resources and stop monitoring
221
+ */
222
+ public destroy(): void {
223
+ // Cleanup all resources
224
+ const resourceIds = Array.from(this.resources.keys());
225
+ resourceIds.forEach(id => this.unregister(id));
226
+
227
+ // Stop monitoring
228
+ this.stopMonitoring();
229
+
230
+ // Clear maps
231
+ this.resources.clear();
232
+ this.elementResources.clear();
233
+ }
234
+
235
+ /**
236
+ * Start monitoring for memory leaks
237
+ */
238
+ public startMonitoring(): void {
239
+ if (this.isMonitoring) return;
240
+ this.isMonitoring = true;
241
+ }
242
+
243
+ /**
244
+ * Stop monitoring
245
+ */
246
+ public stopMonitoring(): void {
247
+ if (!this.isMonitoring) return;
248
+
249
+ this.isMonitoring = false;
250
+
251
+ if (this.mutationObserver) {
252
+ this.mutationObserver.disconnect();
253
+ this.mutationObserver = null;
254
+ }
255
+
256
+ if (this.cleanupInterval) {
257
+ clearInterval(this.cleanupInterval);
258
+ this.cleanupInterval = null;
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Setup DOM mutation observer to detect removed elements
264
+ */
265
+ private setupDOMObserver(): void {
266
+ if (typeof MutationObserver === 'undefined') return;
267
+
268
+ this.mutationObserver = new MutationObserver((mutations) => {
269
+ mutations.forEach(mutation => {
270
+ if (mutation.type === 'childList') {
271
+ mutation.removedNodes.forEach(node => {
272
+ if (node.nodeType === Node.ELEMENT_NODE) {
273
+ this.handleElementRemoval(node as Element);
274
+ }
275
+ });
276
+ }
277
+ });
278
+ });
279
+
280
+ this.mutationObserver.observe(document.body, {
281
+ childList: true,
282
+ subtree: true
283
+ });
284
+ }
285
+
286
+ /**
287
+ * Handle element removal from DOM
288
+ */
289
+ private handleElementRemoval(element: Element): void {
290
+ // Cleanup resources for this element
291
+ this.cleanupElement(element);
292
+
293
+ // Also check descendants
294
+ const descendants = element.querySelectorAll('*');
295
+ descendants.forEach(descendant => {
296
+ this.cleanupElement(descendant);
297
+ });
298
+ }
299
+
300
+ /**
301
+ * Start periodic cleanup
302
+ */
303
+ private startPeriodicCleanup(): void {
304
+ this.cleanupInterval = window.setInterval(() => {
305
+ // Cleanup orphaned resources
306
+ let orphanedCount = 0;
307
+ this.elementResources.forEach((resourceIds, element) => {
308
+ if (!document.contains(element)) {
309
+ orphanedCount += this.cleanupElement(element);
310
+ }
311
+ });
312
+
313
+ // Cleanup very old resources
314
+ const oldCount = this.cleanupOldResources(600000); // 10 minutes
315
+
316
+ if (orphanedCount > 0 || oldCount > 0) {
317
+ console.log(`ProteusJS: Cleaned up ${orphanedCount} orphaned and ${oldCount} old resources`);
318
+ }
319
+ }, 60000); // Run every minute
320
+ }
321
+ }
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Performance Monitor for ProteusJS
3
+ * Tracks and optimizes performance metrics
4
+ */
5
+
6
+ export interface PerformanceMetrics {
7
+ frameRate: number;
8
+ memoryUsage: number;
9
+ responseTime: number;
10
+ observerCount: number;
11
+ eventCount: number;
12
+ lastUpdate: number;
13
+ }
14
+
15
+ export class PerformanceMonitor {
16
+ private metrics: PerformanceMetrics;
17
+ private frameCount: number = 0;
18
+ private lastFrameTime: number = 0;
19
+ private frameRateHistory: number[] = [];
20
+ private responseTimeHistory: number[] = [];
21
+ private isMonitoring: boolean = false;
22
+ private animationFrameId: number | null = null;
23
+ private performanceLevel: 'low' | 'medium' | 'high';
24
+
25
+ constructor(performanceLevel: 'low' | 'medium' | 'high' = 'high') {
26
+ this.performanceLevel = performanceLevel;
27
+ this.metrics = {
28
+ frameRate: 0,
29
+ memoryUsage: 0,
30
+ responseTime: 0,
31
+ observerCount: 0,
32
+ eventCount: 0,
33
+ lastUpdate: Date.now()
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Start performance monitoring
39
+ */
40
+ public start(): void {
41
+ if (this.isMonitoring) return;
42
+
43
+ this.isMonitoring = true;
44
+ this.lastFrameTime = performance.now();
45
+ this.scheduleFrame();
46
+ }
47
+
48
+ /**
49
+ * Stop performance monitoring
50
+ */
51
+ public stop(): void {
52
+ if (!this.isMonitoring) return;
53
+
54
+ this.isMonitoring = false;
55
+ if (this.animationFrameId) {
56
+ cancelAnimationFrame(this.animationFrameId);
57
+ this.animationFrameId = null;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Get current performance metrics
63
+ */
64
+ public getMetrics(): PerformanceMetrics {
65
+ return { ...this.metrics };
66
+ }
67
+
68
+ /**
69
+ * Record response time for an operation
70
+ */
71
+ public recordResponseTime(startTime: number): void {
72
+ const responseTime = performance.now() - startTime;
73
+ this.responseTimeHistory.push(responseTime);
74
+
75
+ // Keep only last 100 measurements
76
+ if (this.responseTimeHistory.length > 100) {
77
+ this.responseTimeHistory.shift();
78
+ }
79
+
80
+ // Calculate average response time
81
+ this.metrics.responseTime = this.responseTimeHistory.reduce((a, b) => a + b, 0) / this.responseTimeHistory.length;
82
+ }
83
+
84
+ /**
85
+ * Update observer count
86
+ */
87
+ public updateObserverCount(count: number): void {
88
+ this.metrics.observerCount = count;
89
+ }
90
+
91
+ /**
92
+ * Update event count
93
+ */
94
+ public updateEventCount(count: number): void {
95
+ this.metrics.eventCount = count;
96
+ }
97
+
98
+ /**
99
+ * Check if performance is within acceptable limits
100
+ */
101
+ public isPerformanceGood(): boolean {
102
+ const targetFrameRate = this.getTargetFrameRate();
103
+ const targetResponseTime = this.getTargetResponseTime();
104
+
105
+ return this.metrics.frameRate >= targetFrameRate &&
106
+ this.metrics.responseTime <= targetResponseTime;
107
+ }
108
+
109
+ /**
110
+ * Get performance recommendations
111
+ */
112
+ public getRecommendations(): string[] {
113
+ const recommendations: string[] = [];
114
+
115
+ if (this.metrics.frameRate < this.getTargetFrameRate()) {
116
+ recommendations.push('Frame rate is below target. Consider reducing animation complexity.');
117
+ }
118
+
119
+ if (this.metrics.responseTime > this.getTargetResponseTime()) {
120
+ recommendations.push('Response time is too high. Consider optimizing calculations.');
121
+ }
122
+
123
+ if (this.metrics.observerCount > this.getMaxObservers()) {
124
+ recommendations.push('Too many observers active. Consider lazy evaluation.');
125
+ }
126
+
127
+ if (this.metrics.memoryUsage > this.getMaxMemoryUsage()) {
128
+ recommendations.push('Memory usage is high. Check for memory leaks.');
129
+ }
130
+
131
+ return recommendations;
132
+ }
133
+
134
+ /**
135
+ * Get performance score (0-100)
136
+ */
137
+ public getPerformanceScore(): number {
138
+ const frameRateScore = Math.min(this.metrics.frameRate / this.getTargetFrameRate(), 1) * 30;
139
+ const responseTimeScore = Math.max(1 - (this.metrics.responseTime / this.getTargetResponseTime()), 0) * 30;
140
+ const memoryScore = Math.max(1 - (this.metrics.memoryUsage / this.getMaxMemoryUsage()), 0) * 20;
141
+ const observerScore = Math.max(1 - (this.metrics.observerCount / this.getMaxObservers()), 0) * 20;
142
+
143
+ return Math.round(frameRateScore + responseTimeScore + memoryScore + observerScore);
144
+ }
145
+
146
+ /**
147
+ * Schedule next frame for monitoring
148
+ */
149
+ private scheduleFrame(): void {
150
+ if (!this.isMonitoring) return;
151
+
152
+ this.animationFrameId = requestAnimationFrame((currentTime) => {
153
+ this.updateFrameRate(currentTime);
154
+ this.updateMemoryUsage();
155
+ this.metrics.lastUpdate = Date.now();
156
+ this.scheduleFrame();
157
+ });
158
+ }
159
+
160
+ /**
161
+ * Update frame rate calculation
162
+ */
163
+ private updateFrameRate(currentTime: number): void {
164
+ const deltaTime = currentTime - this.lastFrameTime;
165
+ this.lastFrameTime = currentTime;
166
+
167
+ if (deltaTime > 0) {
168
+ const currentFrameRate = 1000 / deltaTime;
169
+ this.frameRateHistory.push(currentFrameRate);
170
+
171
+ // Keep only last 60 measurements (1 second at 60fps)
172
+ if (this.frameRateHistory.length > 60) {
173
+ this.frameRateHistory.shift();
174
+ }
175
+
176
+ // Calculate average frame rate
177
+ this.metrics.frameRate = this.frameRateHistory.reduce((a, b) => a + b, 0) / this.frameRateHistory.length;
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Update memory usage
183
+ */
184
+ private updateMemoryUsage(): void {
185
+ if ('memory' in performance) {
186
+ const memory = (performance as any).memory;
187
+ this.metrics.memoryUsage = memory.usedJSHeapSize / 1024 / 1024; // MB
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Get target frame rate based on performance level
193
+ */
194
+ private getTargetFrameRate(): number {
195
+ switch (this.performanceLevel) {
196
+ case 'low': return 30;
197
+ case 'medium': return 45;
198
+ case 'high': return 60;
199
+ default: return 60;
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Get target response time based on performance level
205
+ */
206
+ private getTargetResponseTime(): number {
207
+ switch (this.performanceLevel) {
208
+ case 'low': return 100; // 100ms
209
+ case 'medium': return 80; // 80ms
210
+ case 'high': return 60; // 60ms
211
+ default: return 60;
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Get maximum allowed observers
217
+ */
218
+ private getMaxObservers(): number {
219
+ switch (this.performanceLevel) {
220
+ case 'low': return 50;
221
+ case 'medium': return 100;
222
+ case 'high': return 200;
223
+ default: return 200;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Get maximum allowed memory usage (MB)
229
+ */
230
+ private getMaxMemoryUsage(): number {
231
+ switch (this.performanceLevel) {
232
+ case 'low': return 50;
233
+ case 'medium': return 100;
234
+ case 'high': return 200;
235
+ default: return 200;
236
+ }
237
+ }
238
+ }