@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,376 @@
1
+ /**
2
+ * SmartContainers - Automatic container detection and management system
3
+ * Core component of ProteusJS container query system
4
+ */
5
+
6
+ import { logger } from '../utils/Logger';
7
+
8
+ export interface ContainerInfo {
9
+ element: Element;
10
+ type: 'block' | 'inline' | 'grid' | 'flex';
11
+ confidence: number;
12
+ priority: 'low' | 'medium' | 'high';
13
+ dimensions: {
14
+ width: number;
15
+ height: number;
16
+ aspectRatio: number;
17
+ };
18
+ children: number;
19
+ hasResponsiveContent: boolean;
20
+ }
21
+
22
+ export interface ContainerDetectionOptions {
23
+ includeInline?: boolean;
24
+ minConfidence?: number;
25
+ excludeSelectors?: string[];
26
+ includeSelectors?: string[];
27
+ }
28
+
29
+ export class SmartContainers {
30
+ private containers: Map<Element, ContainerInfo> = new Map();
31
+ private observer: ResizeObserver | null = null;
32
+ private mutationObserver: MutationObserver | null = null;
33
+ private isActive: boolean = false;
34
+
35
+ constructor() {
36
+ this.setupObservers();
37
+ }
38
+
39
+ /**
40
+ * Automatically detect containers in the document
41
+ */
42
+ public async detectContainers(options: ContainerDetectionOptions = {}): Promise<ContainerInfo[]> {
43
+ const {
44
+ includeInline = false,
45
+ minConfidence = 0.5,
46
+ excludeSelectors = ['script', 'style', 'meta', 'link'],
47
+ includeSelectors = []
48
+ } = options;
49
+
50
+ const containers: ContainerInfo[] = [];
51
+ const elements = this.getAllElements(includeSelectors, excludeSelectors);
52
+
53
+ for (const element of elements) {
54
+ const containerInfo = this.analyzeElement(element, includeInline);
55
+
56
+ if (containerInfo && containerInfo.confidence >= minConfidence) {
57
+ containers.push(containerInfo);
58
+ this.containers.set(element, containerInfo);
59
+
60
+ // Start observing this container
61
+ if (this.observer) {
62
+ this.observer.observe(element);
63
+ }
64
+ }
65
+ }
66
+
67
+ // Sort by priority and confidence
68
+ containers.sort((a, b) => {
69
+ const priorityWeight = { high: 3, medium: 2, low: 1 };
70
+ const aPriority = priorityWeight[a.priority];
71
+ const bPriority = priorityWeight[b.priority];
72
+
73
+ if (aPriority !== bPriority) {
74
+ return bPriority - aPriority;
75
+ }
76
+
77
+ return b.confidence - a.confidence;
78
+ });
79
+
80
+ return containers;
81
+ }
82
+
83
+ /**
84
+ * Calculate container units (cw, ch, cmin, cmax)
85
+ */
86
+ public calculateContainerUnit(element: Element, unit: string): number {
87
+ const rect = element.getBoundingClientRect();
88
+ const { width, height } = rect;
89
+
90
+ switch (unit) {
91
+ case 'cw': // Container width unit (1cw = 1% of container width)
92
+ return width / 100;
93
+
94
+ case 'ch': // Container height unit (1ch = 1% of container height)
95
+ return height / 100;
96
+
97
+ case 'cmin': // Container minimum unit (1cmin = 1% of smaller dimension)
98
+ return Math.min(width, height) / 100;
99
+
100
+ case 'cmax': // Container maximum unit (1cmax = 1% of larger dimension)
101
+ return Math.max(width, height) / 100;
102
+
103
+ case 'cqi': // Container inline size (same as cw for horizontal writing)
104
+ return width / 100;
105
+
106
+ case 'cqb': // Container block size (same as ch for horizontal writing)
107
+ return height / 100;
108
+
109
+ default:
110
+ logger.warn(`Unknown container unit "${unit}"`);
111
+ return 0;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Get container information for a specific element
117
+ */
118
+ public getContainerInfo(element: Element): ContainerInfo | null {
119
+ return this.containers.get(element) || null;
120
+ }
121
+
122
+ /**
123
+ * Update container information when dimensions change
124
+ */
125
+ public updateContainer(element: Element): ContainerInfo | null {
126
+ const existingInfo = this.containers.get(element);
127
+ if (!existingInfo) return null;
128
+
129
+ const updatedInfo = this.analyzeElement(element, true);
130
+ if (updatedInfo) {
131
+ this.containers.set(element, updatedInfo);
132
+ return updatedInfo;
133
+ }
134
+
135
+ return existingInfo;
136
+ }
137
+
138
+ /**
139
+ * Start monitoring containers for changes
140
+ */
141
+ public startMonitoring(): void {
142
+ this.isActive = true;
143
+
144
+ if (this.observer) {
145
+ // Re-observe all registered containers
146
+ this.containers.forEach((_, element) => {
147
+ this.observer!.observe(element);
148
+ });
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Stop monitoring containers
154
+ */
155
+ public stopMonitoring(): void {
156
+ this.isActive = false;
157
+
158
+ if (this.observer) {
159
+ this.observer.disconnect();
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Clean up resources
165
+ */
166
+ public destroy(): void {
167
+ this.stopMonitoring();
168
+
169
+ if (this.mutationObserver) {
170
+ this.mutationObserver.disconnect();
171
+ }
172
+
173
+ this.containers.clear();
174
+ }
175
+
176
+ /**
177
+ * Setup ResizeObserver and MutationObserver
178
+ */
179
+ private setupObservers(): void {
180
+ // Setup ResizeObserver for container dimension changes
181
+ if (typeof ResizeObserver !== 'undefined') {
182
+ this.observer = new ResizeObserver((entries) => {
183
+ if (!this.isActive) return;
184
+
185
+ for (const entry of entries) {
186
+ this.updateContainer(entry.target);
187
+ }
188
+ });
189
+ }
190
+
191
+ // Setup MutationObserver for DOM changes
192
+ if (typeof MutationObserver !== 'undefined') {
193
+ this.mutationObserver = new MutationObserver((mutations) => {
194
+ if (!this.isActive) return;
195
+
196
+ for (const mutation of mutations) {
197
+ if (mutation.type === 'childList') {
198
+ // Re-analyze containers when children change
199
+ mutation.target.parentElement && this.updateContainer(mutation.target.parentElement);
200
+ }
201
+ }
202
+ });
203
+
204
+ this.mutationObserver.observe(document.body, {
205
+ childList: true,
206
+ subtree: true
207
+ });
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Get all elements to analyze
213
+ */
214
+ private getAllElements(includeSelectors: string[], excludeSelectors: string[]): Element[] {
215
+ let elements: Element[];
216
+
217
+ if (includeSelectors.length > 0) {
218
+ elements = Array.from(document.querySelectorAll(includeSelectors.join(', ')));
219
+ } else {
220
+ elements = Array.from(document.querySelectorAll('*'));
221
+ }
222
+
223
+ // Filter out excluded elements
224
+ if (excludeSelectors.length > 0) {
225
+ const excludeSelector = excludeSelectors.join(', ');
226
+ elements = elements.filter(el => !el.matches(excludeSelector));
227
+ }
228
+
229
+ return elements;
230
+ }
231
+
232
+ /**
233
+ * Analyze an element to determine if it's a good container candidate
234
+ */
235
+ private analyzeElement(element: Element, includeInline: boolean): ContainerInfo | null {
236
+ const rect = element.getBoundingClientRect();
237
+ const computedStyle = window.getComputedStyle(element);
238
+ const children = element.children.length;
239
+
240
+ // Skip elements that are too small or invisible
241
+ if (rect.width < 50 || rect.height < 50 || computedStyle.display === 'none') {
242
+ return null;
243
+ }
244
+
245
+ // Determine container type
246
+ const display = computedStyle.display;
247
+ let type: ContainerInfo['type'];
248
+ let confidence = 0;
249
+
250
+ if (display.includes('grid')) {
251
+ type = 'grid';
252
+ confidence += 0.4;
253
+ } else if (display.includes('flex')) {
254
+ type = 'flex';
255
+ confidence += 0.3;
256
+ } else if (display === 'block' || display === 'flow-root') {
257
+ type = 'block';
258
+ confidence += 0.2;
259
+ } else if (includeInline && (display === 'inline-block' || display === 'inline')) {
260
+ type = 'inline';
261
+ confidence += 0.1;
262
+ } else {
263
+ return null;
264
+ }
265
+
266
+ // Increase confidence based on various factors
267
+ if (children > 0) confidence += 0.2;
268
+ if (children > 3) confidence += 0.1;
269
+ if (rect.width > 200) confidence += 0.1;
270
+ if (rect.height > 200) confidence += 0.1;
271
+ if (element.classList.length > 0) confidence += 0.1;
272
+ if (element.id) confidence += 0.1;
273
+
274
+ // Check for responsive content indicators
275
+ const hasResponsiveContent = this.hasResponsiveContent(element);
276
+ if (hasResponsiveContent) confidence += 0.2;
277
+
278
+ // Determine priority
279
+ let priority: ContainerInfo['priority'] = 'low';
280
+ if (element.matches('main, article, section, aside, nav') ||
281
+ element.getAttribute('role') === 'main' ||
282
+ element.getAttribute('role') === 'banner' ||
283
+ element.getAttribute('role') === 'navigation' ||
284
+ element.getAttribute('role') === 'contentinfo') {
285
+ priority = 'high';
286
+ } else if (element.matches('div, header, footer, form') ||
287
+ element.getAttribute('role') === 'complementary') {
288
+ priority = 'medium';
289
+ }
290
+
291
+ return {
292
+ element,
293
+ type,
294
+ confidence: Math.min(confidence, 1),
295
+ priority,
296
+ dimensions: {
297
+ width: rect.width,
298
+ height: rect.height,
299
+ aspectRatio: rect.width / rect.height
300
+ },
301
+ children,
302
+ hasResponsiveContent
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Check if element contains responsive content
308
+ */
309
+ private hasResponsiveContent(element: Element): boolean {
310
+ // Check for responsive images
311
+ const images = element.querySelectorAll('img[srcset], picture, img[sizes]');
312
+ if (images.length > 0) return true;
313
+
314
+ // Check for responsive videos
315
+ const videos = element.querySelectorAll('video, iframe[src*="youtube"], iframe[src*="vimeo"]');
316
+ if (videos.length > 0) return true;
317
+
318
+ // Check for CSS Grid or Flexbox children
319
+ const gridFlexChildren = Array.from(element.children).some(child => {
320
+ const style = window.getComputedStyle(child);
321
+ return style.display.includes('grid') || style.display.includes('flex');
322
+ });
323
+
324
+ return gridFlexChildren;
325
+ }
326
+
327
+ /**
328
+ * Get container performance metrics
329
+ */
330
+ public getMetrics(): {
331
+ totalContainers: number;
332
+ activeContainers: number;
333
+ averageConfidence: number;
334
+ typeDistribution: Record<string, number>;
335
+ } {
336
+ const containers = Array.from(this.containers.values());
337
+ const typeDistribution: Record<string, number> = {};
338
+
339
+ containers.forEach(container => {
340
+ typeDistribution[container.type] = (typeDistribution[container.type] || 0) + 1;
341
+ });
342
+
343
+ const averageConfidence = containers.length > 0
344
+ ? containers.reduce((sum, c) => sum + c.confidence, 0) / containers.length
345
+ : 0;
346
+
347
+ return {
348
+ totalContainers: containers.length,
349
+ activeContainers: this.isActive ? containers.length : 0,
350
+ averageConfidence,
351
+ typeDistribution
352
+ };
353
+ }
354
+
355
+ /**
356
+ * Force re-analysis of all containers
357
+ */
358
+ public refreshContainers(): Promise<ContainerInfo[]> {
359
+ this.containers.clear();
360
+ return this.detectContainers();
361
+ }
362
+
363
+ /**
364
+ * Get containers by type
365
+ */
366
+ public getContainersByType(type: ContainerInfo['type']): ContainerInfo[] {
367
+ return Array.from(this.containers.values()).filter(c => c.type === type);
368
+ }
369
+
370
+ /**
371
+ * Get high-confidence containers
372
+ */
373
+ public getHighConfidenceContainers(minConfidence: number = 0.7): ContainerInfo[] {
374
+ return Array.from(this.containers.values()).filter(c => c.confidence >= minConfidence);
375
+ }
376
+ }