@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,532 @@
1
+ /**
2
+ * Lazy Evaluation System for ProteusJS
3
+ * Viewport-based component activation with idle callbacks and progressive enhancement
4
+ */
5
+
6
+ export interface LazyConfig {
7
+ rootMargin: string;
8
+ threshold: number[];
9
+ useIdleCallback: boolean;
10
+ idleTimeout: number;
11
+ progressiveEnhancement: boolean;
12
+ cacheResults: boolean;
13
+ priorityQueue: boolean;
14
+ maxConcurrent: number;
15
+ }
16
+
17
+ export interface LazyComponent {
18
+ id: string;
19
+ element: Element;
20
+ activator: () => Promise<void>;
21
+ priority: 'high' | 'normal' | 'low';
22
+ dependencies: string[];
23
+ activated: boolean;
24
+ cached: boolean;
25
+ timestamp: number;
26
+ }
27
+
28
+ export interface LazyMetrics {
29
+ totalComponents: number;
30
+ activatedComponents: number;
31
+ pendingComponents: number;
32
+ cacheHits: number;
33
+ cacheMisses: number;
34
+ averageActivationTime: number;
35
+ idleCallbacksUsed: number;
36
+ }
37
+
38
+ export class LazyEvaluationSystem {
39
+ private config: Required<LazyConfig>;
40
+ private components: Map<string, LazyComponent> = new Map();
41
+ private intersectionObserver: IntersectionObserver | null = null;
42
+ private activationQueue: LazyComponent[] = [];
43
+ private cache: Map<string, any> = new Map();
44
+ private metrics: LazyMetrics;
45
+ private isProcessing: boolean = false;
46
+ private activeActivations: Set<string> = new Set();
47
+
48
+ constructor(config: Partial<LazyConfig> = {}) {
49
+ this.config = {
50
+ rootMargin: '50px',
51
+ threshold: [0, 0.1, 0.5, 1.0],
52
+ useIdleCallback: true,
53
+ idleTimeout: 5000,
54
+ progressiveEnhancement: true,
55
+ cacheResults: true,
56
+ priorityQueue: true,
57
+ maxConcurrent: 3,
58
+ ...config
59
+ };
60
+
61
+ this.metrics = this.createInitialMetrics();
62
+ this.setupIntersectionObserver();
63
+ }
64
+
65
+ /**
66
+ * Register a lazy component
67
+ */
68
+ public register(
69
+ element: Element,
70
+ activator: () => Promise<void>,
71
+ options: {
72
+ id?: string;
73
+ priority?: 'high' | 'normal' | 'low';
74
+ dependencies?: string[];
75
+ immediate?: boolean;
76
+ } = {}
77
+ ): string {
78
+ const id = options.id || this.generateId();
79
+
80
+ const component: LazyComponent = {
81
+ id,
82
+ element,
83
+ activator,
84
+ priority: options.priority || 'normal',
85
+ dependencies: options.dependencies || [],
86
+ activated: false,
87
+ cached: false,
88
+ timestamp: performance.now()
89
+ };
90
+
91
+ this.components.set(id, component);
92
+ this.metrics.totalComponents++;
93
+
94
+ if (options.immediate) {
95
+ this.activateComponent(component);
96
+ } else {
97
+ this.observeComponent(component);
98
+ }
99
+
100
+ return id;
101
+ }
102
+
103
+ /**
104
+ * Unregister a component
105
+ */
106
+ public unregister(id: string): void {
107
+ const component = this.components.get(id);
108
+ if (component) {
109
+ this.intersectionObserver?.unobserve(component.element);
110
+ this.components.delete(id);
111
+ this.cache.delete(id);
112
+ this.metrics.totalComponents--;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Force activate a component
118
+ */
119
+ public async activate(id: string): Promise<void> {
120
+ const component = this.components.get(id);
121
+ if (component && !component.activated) {
122
+ await this.activateComponent(component);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Preload components with high priority
128
+ */
129
+ public preloadHighPriority(): void {
130
+ const highPriorityComponents = Array.from(this.components.values())
131
+ .filter(c => c.priority === 'high' && !c.activated);
132
+
133
+ highPriorityComponents.forEach(component => {
134
+ this.scheduleActivation(component);
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Get cached result
140
+ */
141
+ public getCached<T>(key: string): T | null {
142
+ if (!this.config.cacheResults) return null;
143
+
144
+ const cached = this.cache.get(key);
145
+ if (cached) {
146
+ this.metrics.cacheHits++;
147
+ return cached;
148
+ }
149
+
150
+ this.metrics.cacheMisses++;
151
+ return null;
152
+ }
153
+
154
+ /**
155
+ * Set cached result
156
+ */
157
+ public setCached<T>(key: string, value: T): void {
158
+ if (this.config.cacheResults) {
159
+ this.cache.set(key, value);
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Get current metrics
165
+ */
166
+ public getMetrics(): LazyMetrics {
167
+ return { ...this.metrics };
168
+ }
169
+
170
+ /**
171
+ * Clear cache
172
+ */
173
+ public clearCache(): void {
174
+ this.cache.clear();
175
+ }
176
+
177
+ /**
178
+ * Destroy the lazy evaluation system
179
+ */
180
+ public destroy(): void {
181
+ this.intersectionObserver?.disconnect();
182
+ this.components.clear();
183
+ this.cache.clear();
184
+ this.activationQueue = [];
185
+ this.activeActivations.clear();
186
+ }
187
+
188
+ /**
189
+ * Setup intersection observer
190
+ */
191
+ private setupIntersectionObserver(): void {
192
+ if (!window.IntersectionObserver) {
193
+ console.warn('IntersectionObserver not supported, falling back to immediate activation');
194
+ return;
195
+ }
196
+
197
+ this.intersectionObserver = new IntersectionObserver(
198
+ (entries) => {
199
+ entries.forEach(entry => {
200
+ if (entry.isIntersecting) {
201
+ const component = this.findComponentByElement(entry.target);
202
+ if (component && !component.activated) {
203
+ this.scheduleActivation(component);
204
+ }
205
+ }
206
+ });
207
+ },
208
+ {
209
+ rootMargin: this.config.rootMargin,
210
+ threshold: this.config.threshold
211
+ }
212
+ );
213
+ }
214
+
215
+ /**
216
+ * Observe component for intersection
217
+ */
218
+ private observeComponent(component: LazyComponent): void {
219
+ if (this.intersectionObserver) {
220
+ this.intersectionObserver.observe(component.element);
221
+ } else {
222
+ // Fallback: activate immediately if no intersection observer
223
+ this.scheduleActivation(component);
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Schedule component activation
229
+ */
230
+ private scheduleActivation(component: LazyComponent): void {
231
+ if (this.config.priorityQueue) {
232
+ this.addToQueue(component);
233
+ this.processQueue();
234
+ } else {
235
+ this.activateComponent(component);
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Add component to activation queue
241
+ */
242
+ private addToQueue(component: LazyComponent): void {
243
+ // Check if already in queue
244
+ if (this.activationQueue.some(c => c.id === component.id)) {
245
+ return;
246
+ }
247
+
248
+ this.activationQueue.push(component);
249
+
250
+ // Sort by priority
251
+ this.activationQueue.sort((a, b) => {
252
+ const priorityOrder = { high: 0, normal: 1, low: 2 };
253
+ const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
254
+
255
+ if (priorityDiff !== 0) {
256
+ return priorityDiff;
257
+ }
258
+
259
+ // Then by timestamp (older first)
260
+ return a.timestamp - b.timestamp;
261
+ });
262
+ }
263
+
264
+ /**
265
+ * Process activation queue
266
+ */
267
+ private async processQueue(): Promise<void> {
268
+ if (this.isProcessing || this.activationQueue.length === 0) {
269
+ return;
270
+ }
271
+
272
+ this.isProcessing = true;
273
+
274
+ try {
275
+ while (this.activationQueue.length > 0 &&
276
+ this.activeActivations.size < this.config.maxConcurrent) {
277
+
278
+ const component = this.activationQueue.shift();
279
+ if (component && !component.activated && this.areDependenciesSatisfied(component)) {
280
+ this.activateComponent(component);
281
+ }
282
+ }
283
+ } finally {
284
+ this.isProcessing = false;
285
+
286
+ // Schedule next processing if queue is not empty
287
+ if (this.activationQueue.length > 0) {
288
+ this.scheduleNextProcessing();
289
+ }
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Schedule next queue processing
295
+ */
296
+ private scheduleNextProcessing(): void {
297
+ if (this.config.useIdleCallback && window.requestIdleCallback) {
298
+ window.requestIdleCallback(
299
+ () => this.processQueue(),
300
+ { timeout: this.config.idleTimeout }
301
+ );
302
+ this.metrics.idleCallbacksUsed++;
303
+ } else {
304
+ setTimeout(() => this.processQueue(), 16); // Next frame
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Activate a component
310
+ */
311
+ private async activateComponent(component: LazyComponent): Promise<void> {
312
+ if (component.activated || this.activeActivations.has(component.id)) {
313
+ return;
314
+ }
315
+
316
+ this.activeActivations.add(component.id);
317
+ const startTime = performance.now();
318
+
319
+ try {
320
+ // Check cache first
321
+ const cacheKey = `component-${component.id}`;
322
+ let result = this.getCached(cacheKey);
323
+
324
+ if (!result) {
325
+ // Progressive enhancement check
326
+ if (this.config.progressiveEnhancement && !this.isEnhancementSupported(component)) {
327
+ console.warn(`Progressive enhancement not supported for component ${component.id}`);
328
+ return;
329
+ }
330
+
331
+ // Execute activator
332
+ result = await component.activator();
333
+
334
+ // Cache result if enabled
335
+ if (this.config.cacheResults) {
336
+ this.setCached(cacheKey, result);
337
+ component.cached = true;
338
+ }
339
+ }
340
+
341
+ component.activated = true;
342
+ this.metrics.activatedComponents++;
343
+ this.metrics.pendingComponents = this.metrics.totalComponents - this.metrics.activatedComponents;
344
+
345
+ // Update average activation time
346
+ const activationTime = performance.now() - startTime;
347
+ this.metrics.averageActivationTime =
348
+ (this.metrics.averageActivationTime + activationTime) / 2;
349
+
350
+ // Stop observing this component
351
+ this.intersectionObserver?.unobserve(component.element);
352
+
353
+ } catch (error) {
354
+ console.error(`Failed to activate component ${component.id}:`, error);
355
+ } finally {
356
+ this.activeActivations.delete(component.id);
357
+
358
+ // Continue processing queue
359
+ if (this.activationQueue.length > 0) {
360
+ this.scheduleNextProcessing();
361
+ }
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Check if component dependencies are satisfied
367
+ */
368
+ private areDependenciesSatisfied(component: LazyComponent): boolean {
369
+ return component.dependencies.every(depId => {
370
+ const dependency = this.components.get(depId);
371
+ return dependency?.activated || false;
372
+ });
373
+ }
374
+
375
+ /**
376
+ * Check if progressive enhancement is supported
377
+ */
378
+ private isEnhancementSupported(component: LazyComponent): boolean {
379
+ // Basic feature detection
380
+ const requiredFeatures = [
381
+ 'IntersectionObserver',
382
+ 'ResizeObserver',
383
+ 'requestAnimationFrame'
384
+ ];
385
+
386
+ return requiredFeatures.every(feature => feature in window);
387
+ }
388
+
389
+ /**
390
+ * Find component by element
391
+ */
392
+ private findComponentByElement(element: Element): LazyComponent | undefined {
393
+ return Array.from(this.components.values())
394
+ .find(component => component.element === element);
395
+ }
396
+
397
+ /**
398
+ * Generate unique component ID
399
+ */
400
+ private generateId(): string {
401
+ return `lazy-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
402
+ }
403
+
404
+ /**
405
+ * Create initial metrics
406
+ */
407
+ private createInitialMetrics(): LazyMetrics {
408
+ return {
409
+ totalComponents: 0,
410
+ activatedComponents: 0,
411
+ pendingComponents: 0,
412
+ cacheHits: 0,
413
+ cacheMisses: 0,
414
+ averageActivationTime: 0,
415
+ idleCallbacksUsed: 0
416
+ };
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Lazy evaluation decorators and utilities
422
+ */
423
+ export class LazyUtils {
424
+ /**
425
+ * Create a lazy-loaded image
426
+ */
427
+ static lazyImage(
428
+ img: HTMLImageElement,
429
+ src: string,
430
+ options: { placeholder?: string; fadeIn?: boolean } = {}
431
+ ): Promise<void> {
432
+ return new Promise((resolve, reject) => {
433
+ // Set placeholder
434
+ if (options.placeholder) {
435
+ img.src = options.placeholder;
436
+ }
437
+
438
+ // Create new image for loading
439
+ const loader = new Image();
440
+
441
+ loader.onload = () => {
442
+ img.src = src;
443
+
444
+ if (options.fadeIn) {
445
+ img.style.opacity = '0';
446
+ img.style.transition = 'opacity 0.3s ease';
447
+
448
+ requestAnimationFrame(() => {
449
+ img.style.opacity = '1';
450
+ });
451
+ }
452
+
453
+ resolve();
454
+ };
455
+
456
+ loader.onerror = reject;
457
+ loader.src = src;
458
+ });
459
+ }
460
+
461
+ /**
462
+ * Create a lazy-loaded script
463
+ */
464
+ static lazyScript(src: string, options: { async?: boolean; defer?: boolean } = {}): Promise<void> {
465
+ return new Promise((resolve, reject) => {
466
+ const script = document.createElement('script');
467
+ script.src = src;
468
+ script.async = options.async !== false;
469
+ script.defer = options.defer || false;
470
+
471
+ script.onload = () => resolve();
472
+ script.onerror = reject;
473
+
474
+ document.head.appendChild(script);
475
+ });
476
+ }
477
+
478
+ /**
479
+ * Create a lazy-loaded CSS
480
+ */
481
+ static lazyCSS(href: string, media: string = 'all'): Promise<void> {
482
+ return new Promise((resolve, reject) => {
483
+ const link = document.createElement('link');
484
+ link.rel = 'stylesheet';
485
+ link.href = href;
486
+ link.media = 'print'; // Load as print to avoid blocking
487
+
488
+ link.onload = () => {
489
+ link.media = media; // Switch to target media
490
+ resolve();
491
+ };
492
+
493
+ link.onerror = reject;
494
+ document.head.appendChild(link);
495
+ });
496
+ }
497
+
498
+ /**
499
+ * Lazy function execution with memoization
500
+ */
501
+ static lazy<T>(fn: () => T): () => T {
502
+ let cached: T;
503
+ let executed = false;
504
+
505
+ return () => {
506
+ if (!executed) {
507
+ cached = fn();
508
+ executed = true;
509
+ }
510
+ return cached;
511
+ };
512
+ }
513
+
514
+ /**
515
+ * Debounced lazy execution
516
+ */
517
+ static lazyDebounced<T extends (...args: any[]) => any>(
518
+ fn: T,
519
+ delay: number
520
+ ): (...args: Parameters<T>) => Promise<ReturnType<T>> {
521
+ let timeoutId: number;
522
+
523
+ return (...args: Parameters<T>): Promise<ReturnType<T>> => {
524
+ return new Promise((resolve) => {
525
+ clearTimeout(timeoutId);
526
+ timeoutId = window.setTimeout(() => {
527
+ resolve(fn(...args));
528
+ }, delay);
529
+ });
530
+ };
531
+ }
532
+ }