@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,411 @@
1
+ /**
2
+ * Element Queries for ProteusJS
3
+ * Advanced container-based queries with complex logic support
4
+ */
5
+
6
+ import type { ElementQuery } from '../types';
7
+ import { BreakpointSystem } from './BreakpointSystem';
8
+
9
+ export interface QueryCondition {
10
+ property: 'width' | 'height' | 'aspect-ratio' | 'content-size' | 'orientation';
11
+ operator: 'min' | 'max' | 'exact' | 'range';
12
+ value: number | string | [number, number];
13
+ unit?: string;
14
+ }
15
+
16
+ export interface QueryRule {
17
+ conditions: QueryCondition[];
18
+ logic: 'and' | 'or';
19
+ callback?: (matches: boolean, element: Element) => void;
20
+ cssClass?: string;
21
+ cssProperties?: Record<string, string>;
22
+ }
23
+
24
+ export interface QueryResult {
25
+ matches: boolean;
26
+ matchedConditions: QueryCondition[];
27
+ failedConditions: QueryCondition[];
28
+ element: Element;
29
+ timestamp: number;
30
+ }
31
+
32
+ export class ElementQueries {
33
+ private queries: Map<Element, QueryRule[]> = new Map();
34
+ private lastResults: Map<Element, QueryResult[]> = new Map();
35
+ private breakpointSystem: BreakpointSystem;
36
+
37
+ constructor(breakpointSystem: BreakpointSystem) {
38
+ this.breakpointSystem = breakpointSystem;
39
+ }
40
+
41
+ /**
42
+ * Add element query rule
43
+ */
44
+ public addQuery(
45
+ element: Element,
46
+ rule: QueryRule
47
+ ): () => void {
48
+ if (!this.queries.has(element)) {
49
+ this.queries.set(element, []);
50
+ }
51
+
52
+ const rules = this.queries.get(element)!;
53
+ rules.push(rule);
54
+
55
+ // Initial evaluation
56
+ this.evaluateElement(element);
57
+
58
+ // Return removal function
59
+ return () => this.removeQuery(element, rule);
60
+ }
61
+
62
+ /**
63
+ * Remove specific query rule
64
+ */
65
+ public removeQuery(element: Element, rule: QueryRule): boolean {
66
+ const rules = this.queries.get(element);
67
+ if (!rules) return false;
68
+
69
+ const index = rules.indexOf(rule);
70
+ if (index === -1) return false;
71
+
72
+ rules.splice(index, 1);
73
+
74
+ if (rules.length === 0) {
75
+ this.queries.delete(element);
76
+ this.lastResults.delete(element);
77
+ } else {
78
+ this.evaluateElement(element);
79
+ }
80
+
81
+ return true;
82
+ }
83
+
84
+ /**
85
+ * Remove all queries for element
86
+ */
87
+ public removeAllQueries(element: Element): boolean {
88
+ const hadQueries = this.queries.has(element);
89
+ this.queries.delete(element);
90
+ this.lastResults.delete(element);
91
+ return hadQueries;
92
+ }
93
+
94
+ /**
95
+ * Evaluate all queries for an element
96
+ */
97
+ public evaluateElement(element: Element): QueryResult[] {
98
+ const rules = this.queries.get(element);
99
+ if (!rules || rules.length === 0) return [];
100
+
101
+ const dimensions = this.getElementDimensions(element);
102
+ const results: QueryResult[] = [];
103
+
104
+ rules.forEach(rule => {
105
+ const result = this.evaluateRule(element, rule, dimensions);
106
+ results.push(result);
107
+
108
+ // Apply effects if query matches
109
+ if (result.matches) {
110
+ this.applyQueryEffects(element, rule);
111
+ } else {
112
+ this.removeQueryEffects(element, rule);
113
+ }
114
+
115
+ // Call callback if provided
116
+ if (rule.callback) {
117
+ rule.callback(result.matches, element);
118
+ }
119
+ });
120
+
121
+ this.lastResults.set(element, results);
122
+ return results;
123
+ }
124
+
125
+ /**
126
+ * Evaluate all elements
127
+ */
128
+ public evaluateAll(): Map<Element, QueryResult[]> {
129
+ const allResults = new Map<Element, QueryResult[]>();
130
+
131
+ this.queries.forEach((rules, element) => {
132
+ const results = this.evaluateElement(element);
133
+ allResults.set(element, results);
134
+ });
135
+
136
+ return allResults;
137
+ }
138
+
139
+ /**
140
+ * Get last evaluation results for element
141
+ */
142
+ public getLastResults(element: Element): QueryResult[] {
143
+ return this.lastResults.get(element) || [];
144
+ }
145
+
146
+ /**
147
+ * Check if any query matches for element
148
+ */
149
+ public hasMatches(element: Element): boolean {
150
+ const results = this.getLastResults(element);
151
+ return results.some(result => result.matches);
152
+ }
153
+
154
+ /**
155
+ * Get matching queries for element
156
+ */
157
+ public getMatches(element: Element): QueryResult[] {
158
+ const results = this.getLastResults(element);
159
+ return results.filter(result => result.matches);
160
+ }
161
+
162
+ /**
163
+ * Create query from CSS-like syntax
164
+ */
165
+ public parseQuery(queryString: string): QueryRule {
166
+ // Parse CSS-like query syntax: "(min-width: 300px) and (max-height: 500px)"
167
+ const conditions: QueryCondition[] = [];
168
+ let logic: 'and' | 'or' = 'and';
169
+
170
+ // Simple parser for basic queries
171
+ const conditionRegex = /\(([^)]+)\)/g;
172
+ const matches = Array.from(queryString.matchAll(conditionRegex));
173
+
174
+ matches.forEach(match => {
175
+ const conditionStr = match[1]!.trim();
176
+ const condition = this.parseCondition(conditionStr);
177
+ if (condition) {
178
+ conditions.push(condition);
179
+ }
180
+ });
181
+
182
+ // Detect logic operator
183
+ if (queryString.includes(' or ')) {
184
+ logic = 'or';
185
+ }
186
+
187
+ return { conditions, logic };
188
+ }
189
+
190
+ /**
191
+ * Get query statistics
192
+ */
193
+ public getStats(): object {
194
+ const totalElements = this.queries.size;
195
+ const totalQueries = Array.from(this.queries.values())
196
+ .reduce((sum, rules) => sum + rules.length, 0);
197
+
198
+ const matchingElements = Array.from(this.lastResults.entries())
199
+ .filter(([element, results]) => results.some(r => r.matches))
200
+ .length;
201
+
202
+ return {
203
+ totalElements,
204
+ totalQueries,
205
+ matchingElements,
206
+ averageQueriesPerElement: totalElements > 0 ? totalQueries / totalElements : 0
207
+ };
208
+ }
209
+
210
+ /**
211
+ * Clear all queries
212
+ */
213
+ public clear(): void {
214
+ // Remove effects from all elements
215
+ this.queries.forEach((rules, element) => {
216
+ rules.forEach(rule => {
217
+ this.removeQueryEffects(element, rule);
218
+ });
219
+ });
220
+
221
+ this.queries.clear();
222
+ this.lastResults.clear();
223
+ }
224
+
225
+ /**
226
+ * Evaluate a single rule against element dimensions
227
+ */
228
+ private evaluateRule(
229
+ element: Element,
230
+ rule: QueryRule,
231
+ dimensions: ElementDimensions
232
+ ): QueryResult {
233
+ const matchedConditions: QueryCondition[] = [];
234
+ const failedConditions: QueryCondition[] = [];
235
+
236
+ rule.conditions.forEach(condition => {
237
+ const matches = this.evaluateCondition(condition, dimensions);
238
+ if (matches) {
239
+ matchedConditions.push(condition);
240
+ } else {
241
+ failedConditions.push(condition);
242
+ }
243
+ });
244
+
245
+ let overallMatch: boolean;
246
+ if (rule.logic === 'and') {
247
+ overallMatch = failedConditions.length === 0;
248
+ } else {
249
+ overallMatch = matchedConditions.length > 0;
250
+ }
251
+
252
+ return {
253
+ matches: overallMatch,
254
+ matchedConditions,
255
+ failedConditions,
256
+ element,
257
+ timestamp: Date.now()
258
+ };
259
+ }
260
+
261
+ /**
262
+ * Evaluate a single condition
263
+ */
264
+ private evaluateCondition(
265
+ condition: QueryCondition,
266
+ dimensions: ElementDimensions
267
+ ): boolean {
268
+ const { property, operator, value } = condition;
269
+ let targetValue: number;
270
+
271
+ switch (property) {
272
+ case 'width':
273
+ targetValue = dimensions.width;
274
+ break;
275
+ case 'height':
276
+ targetValue = dimensions.height;
277
+ break;
278
+ case 'aspect-ratio':
279
+ targetValue = dimensions.aspectRatio;
280
+ break;
281
+ case 'content-size':
282
+ targetValue = dimensions.contentSize;
283
+ break;
284
+ case 'orientation':
285
+ targetValue = dimensions.width > dimensions.height ? 1 : 0; // 1 for landscape, 0 for portrait
286
+ break;
287
+ default:
288
+ return false;
289
+ }
290
+
291
+ switch (operator) {
292
+ case 'min':
293
+ return targetValue >= (value as number);
294
+ case 'max':
295
+ return targetValue <= (value as number);
296
+ case 'exact':
297
+ return Math.abs(targetValue - (value as number)) < 1;
298
+ case 'range':
299
+ const [min, max] = value as [number, number];
300
+ return targetValue >= min && targetValue <= max;
301
+ default:
302
+ return false;
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Parse condition string
308
+ */
309
+ private parseCondition(conditionStr: string): QueryCondition | null {
310
+ // Parse conditions like "min-width: 300px", "aspect-ratio: 16/9"
311
+ const parts = conditionStr.split(':').map(s => s.trim());
312
+ if (parts.length !== 2) return null;
313
+
314
+ const [propertyOperator, valueStr] = parts;
315
+
316
+ // Parse property and operator
317
+ let property: QueryCondition['property'];
318
+ let operator: QueryCondition['operator'];
319
+
320
+ if (propertyOperator!.startsWith('min-')) {
321
+ operator = 'min';
322
+ property = propertyOperator!.substring(4) as any;
323
+ } else if (propertyOperator!.startsWith('max-')) {
324
+ operator = 'max';
325
+ property = propertyOperator!.substring(4) as any;
326
+ } else {
327
+ operator = 'exact';
328
+ property = propertyOperator! as any;
329
+ }
330
+
331
+ // Parse value
332
+ let value: number | string | [number, number];
333
+
334
+ if (property === 'aspect-ratio' && valueStr!.includes('/')) {
335
+ const [w, h] = valueStr!.split('/').map(Number);
336
+ value = w! / h!;
337
+ } else if (valueStr!.includes('-')) {
338
+ // Range value like "300-500"
339
+ const [min, max] = valueStr!.split('-').map(s => parseFloat(s));
340
+ value = [min!, max!];
341
+ operator = 'range';
342
+ } else {
343
+ value = parseFloat(valueStr!);
344
+ }
345
+
346
+ return { property, operator, value };
347
+ }
348
+
349
+ /**
350
+ * Get element dimensions
351
+ */
352
+ private getElementDimensions(element: Element): ElementDimensions {
353
+ const rect = element.getBoundingClientRect();
354
+ const width = rect.width;
355
+ const height = rect.height;
356
+
357
+ return {
358
+ width,
359
+ height,
360
+ aspectRatio: height > 0 ? width / height : 0,
361
+ contentSize: Math.sqrt(width * height), // Geometric mean
362
+ orientation: width > height ? 'landscape' : 'portrait'
363
+ };
364
+ }
365
+
366
+ /**
367
+ * Apply query effects (CSS classes, properties)
368
+ */
369
+ private applyQueryEffects(element: Element, rule: QueryRule): void {
370
+ const htmlElement = element as HTMLElement;
371
+
372
+ // Apply CSS class
373
+ if (rule.cssClass) {
374
+ htmlElement.classList.add(rule.cssClass);
375
+ }
376
+
377
+ // Apply CSS properties
378
+ if (rule.cssProperties) {
379
+ Object.entries(rule.cssProperties).forEach(([property, value]) => {
380
+ htmlElement.style.setProperty(property, value);
381
+ });
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Remove query effects
387
+ */
388
+ private removeQueryEffects(element: Element, rule: QueryRule): void {
389
+ const htmlElement = element as HTMLElement;
390
+
391
+ // Remove CSS class
392
+ if (rule.cssClass) {
393
+ htmlElement.classList.remove(rule.cssClass);
394
+ }
395
+
396
+ // Remove CSS properties
397
+ if (rule.cssProperties) {
398
+ Object.keys(rule.cssProperties).forEach(property => {
399
+ htmlElement.style.removeProperty(property);
400
+ });
401
+ }
402
+ }
403
+ }
404
+
405
+ interface ElementDimensions {
406
+ width: number;
407
+ height: number;
408
+ aspectRatio: number;
409
+ contentSize: number;
410
+ orientation: 'landscape' | 'portrait';
411
+ }