@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.
- package/API.md +438 -0
- package/FEATURES.md +286 -0
- package/LICENSE +21 -0
- package/README.md +645 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/proteus.cjs.js +16014 -0
- package/dist/proteus.cjs.js.map +1 -0
- package/dist/proteus.d.ts +3018 -0
- package/dist/proteus.esm.js +16005 -0
- package/dist/proteus.esm.js.map +1 -0
- package/dist/proteus.esm.min.js +8 -0
- package/dist/proteus.esm.min.js.map +1 -0
- package/dist/proteus.js +16020 -0
- package/dist/proteus.js.map +1 -0
- package/dist/proteus.min.js +8 -0
- package/dist/proteus.min.js.map +1 -0
- package/package.json +98 -0
- package/src/__tests__/mvp-integration.test.ts +518 -0
- package/src/accessibility/AccessibilityEngine.ts +2106 -0
- package/src/accessibility/ScreenReaderSupport.ts +444 -0
- package/src/accessibility/__tests__/ScreenReaderSupport.test.ts +435 -0
- package/src/animations/FLIPAnimationSystem.ts +491 -0
- package/src/compatibility/BrowserCompatibility.ts +1076 -0
- package/src/containers/BreakpointSystem.ts +347 -0
- package/src/containers/ContainerBreakpoints.ts +726 -0
- package/src/containers/ContainerManager.ts +370 -0
- package/src/containers/ContainerUnits.ts +336 -0
- package/src/containers/ContextIsolation.ts +394 -0
- package/src/containers/ElementQueries.ts +411 -0
- package/src/containers/SmartContainer.ts +536 -0
- package/src/containers/SmartContainers.ts +376 -0
- package/src/containers/__tests__/ContainerBreakpoints.test.ts +411 -0
- package/src/containers/__tests__/SmartContainers.test.ts +281 -0
- package/src/content/ResponsiveImages.ts +570 -0
- package/src/core/EventSystem.ts +147 -0
- package/src/core/MemoryManager.ts +321 -0
- package/src/core/PerformanceMonitor.ts +238 -0
- package/src/core/PluginSystem.ts +275 -0
- package/src/core/ProteusJS.test.ts +164 -0
- package/src/core/ProteusJS.ts +962 -0
- package/src/developer/PerformanceProfiler.ts +567 -0
- package/src/developer/VisualDebuggingTools.ts +656 -0
- package/src/developer/ZeroConfigSystem.ts +593 -0
- package/src/index.ts +35 -0
- package/src/integration.test.ts +227 -0
- package/src/layout/AdaptiveGrid.ts +429 -0
- package/src/layout/ContentReordering.ts +532 -0
- package/src/layout/FlexboxEnhancer.ts +406 -0
- package/src/layout/FlowLayout.ts +545 -0
- package/src/layout/SpacingSystem.ts +512 -0
- package/src/observers/IntersectionObserverPolyfill.ts +289 -0
- package/src/observers/ObserverManager.ts +299 -0
- package/src/observers/ResizeObserverPolyfill.ts +179 -0
- package/src/performance/BatchDOMOperations.ts +519 -0
- package/src/performance/CSSOptimizationEngine.ts +646 -0
- package/src/performance/CacheOptimizationSystem.ts +601 -0
- package/src/performance/EfficientEventHandler.ts +740 -0
- package/src/performance/LazyEvaluationSystem.ts +532 -0
- package/src/performance/MemoryManagementSystem.ts +497 -0
- package/src/performance/PerformanceMonitor.ts +931 -0
- package/src/performance/__tests__/BatchDOMOperations.test.ts +309 -0
- package/src/performance/__tests__/EfficientEventHandler.test.ts +268 -0
- package/src/performance/__tests__/PerformanceMonitor.test.ts +422 -0
- package/src/polyfills/BrowserPolyfills.ts +586 -0
- package/src/polyfills/__tests__/BrowserPolyfills.test.ts +328 -0
- package/src/test/setup.ts +115 -0
- package/src/theming/SmartThemeSystem.ts +591 -0
- package/src/types/index.ts +134 -0
- package/src/typography/ClampScaling.ts +356 -0
- package/src/typography/FluidTypography.ts +759 -0
- package/src/typography/LineHeightOptimization.ts +430 -0
- package/src/typography/LineHeightOptimizer.ts +326 -0
- package/src/typography/TextFitting.ts +355 -0
- package/src/typography/TypographicScale.ts +428 -0
- package/src/typography/VerticalRhythm.ts +369 -0
- package/src/typography/__tests__/FluidTypography.test.ts +432 -0
- package/src/typography/__tests__/LineHeightOptimization.test.ts +436 -0
- package/src/utils/Logger.ts +173 -0
- package/src/utils/debounce.ts +259 -0
- package/src/utils/performance.ts +371 -0
- package/src/utils/support.ts +106 -0
- package/src/utils/version.ts +24 -0
@@ -0,0 +1,347 @@
|
|
1
|
+
/**
|
2
|
+
* Breakpoint System for ProteusJS
|
3
|
+
* Manages responsive breakpoint definitions and calculations
|
4
|
+
*/
|
5
|
+
|
6
|
+
import type { BreakpointConfig } from '../types';
|
7
|
+
|
8
|
+
export interface BreakpointDefinition {
|
9
|
+
name: string;
|
10
|
+
value: number; // in pixels
|
11
|
+
unit: string;
|
12
|
+
originalValue: string | number;
|
13
|
+
active: boolean;
|
14
|
+
}
|
15
|
+
|
16
|
+
export interface BreakpointMatch {
|
17
|
+
name: string;
|
18
|
+
matches: boolean;
|
19
|
+
value: number;
|
20
|
+
dimension: number;
|
21
|
+
}
|
22
|
+
|
23
|
+
export class BreakpointSystem {
|
24
|
+
private breakpoints: Map<string, BreakpointDefinition> = new Map();
|
25
|
+
private sortedBreakpoints: BreakpointDefinition[] = [];
|
26
|
+
|
27
|
+
constructor(breakpoints: BreakpointConfig = {}) {
|
28
|
+
this.setBreakpoints(breakpoints);
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Set breakpoints configuration
|
33
|
+
*/
|
34
|
+
public setBreakpoints(breakpoints: BreakpointConfig): void {
|
35
|
+
this.breakpoints.clear();
|
36
|
+
|
37
|
+
Object.entries(breakpoints).forEach(([name, value]) => {
|
38
|
+
const definition = this.parseBreakpoint(name, value);
|
39
|
+
this.breakpoints.set(name, definition);
|
40
|
+
});
|
41
|
+
|
42
|
+
this.updateSortedBreakpoints();
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Add or update a single breakpoint
|
47
|
+
*/
|
48
|
+
public setBreakpoint(name: string, value: string | number): void {
|
49
|
+
const definition = this.parseBreakpoint(name, value);
|
50
|
+
this.breakpoints.set(name, definition);
|
51
|
+
this.updateSortedBreakpoints();
|
52
|
+
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Remove a breakpoint
|
56
|
+
*/
|
57
|
+
public removeBreakpoint(name: string): boolean {
|
58
|
+
const removed = this.breakpoints.delete(name);
|
59
|
+
if (removed) {
|
60
|
+
this.updateSortedBreakpoints();
|
61
|
+
}
|
62
|
+
return removed;
|
63
|
+
}
|
64
|
+
|
65
|
+
/**
|
66
|
+
* Get breakpoint definition
|
67
|
+
*/
|
68
|
+
public getBreakpoint(name: string): BreakpointDefinition | undefined {
|
69
|
+
return this.breakpoints.get(name);
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Get all breakpoints
|
74
|
+
*/
|
75
|
+
public getAllBreakpoints(): BreakpointDefinition[] {
|
76
|
+
return Array.from(this.breakpoints.values());
|
77
|
+
}
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Get sorted breakpoints (smallest to largest)
|
81
|
+
*/
|
82
|
+
public getSortedBreakpoints(): BreakpointDefinition[] {
|
83
|
+
return [...this.sortedBreakpoints];
|
84
|
+
}
|
85
|
+
|
86
|
+
/**
|
87
|
+
* Calculate active breakpoints for given dimensions
|
88
|
+
*/
|
89
|
+
public calculateActiveBreakpoints(
|
90
|
+
width: number,
|
91
|
+
height: number,
|
92
|
+
containerType: 'inline-size' | 'size' | 'block-size' = 'inline-size'
|
93
|
+
): string[] {
|
94
|
+
const dimension = this.getRelevantDimension(width, height, containerType);
|
95
|
+
const active: string[] = [];
|
96
|
+
|
97
|
+
this.sortedBreakpoints.forEach(bp => {
|
98
|
+
if (dimension >= bp.value) {
|
99
|
+
active.push(bp.name);
|
100
|
+
}
|
101
|
+
});
|
102
|
+
|
103
|
+
return active;
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Get breakpoint matches for given dimensions
|
108
|
+
*/
|
109
|
+
public getBreakpointMatches(
|
110
|
+
width: number,
|
111
|
+
height: number,
|
112
|
+
containerType: 'inline-size' | 'size' | 'block-size' = 'inline-size'
|
113
|
+
): BreakpointMatch[] {
|
114
|
+
const dimension = this.getRelevantDimension(width, height, containerType);
|
115
|
+
|
116
|
+
return this.sortedBreakpoints.map(bp => ({
|
117
|
+
name: bp.name,
|
118
|
+
matches: dimension >= bp.value,
|
119
|
+
value: bp.value,
|
120
|
+
dimension
|
121
|
+
}));
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Get the current active breakpoint (largest matching)
|
126
|
+
*/
|
127
|
+
public getCurrentBreakpoint(
|
128
|
+
width: number,
|
129
|
+
height: number,
|
130
|
+
containerType: 'inline-size' | 'size' | 'block-size' = 'inline-size'
|
131
|
+
): string | null {
|
132
|
+
const active = this.calculateActiveBreakpoints(width, height, containerType);
|
133
|
+
return active.length > 0 ? active[active.length - 1]! : null;
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Check if a specific breakpoint is active
|
138
|
+
*/
|
139
|
+
public isBreakpointActive(
|
140
|
+
name: string,
|
141
|
+
width: number,
|
142
|
+
height: number,
|
143
|
+
containerType: 'inline-size' | 'size' | 'block-size' = 'inline-size'
|
144
|
+
): boolean {
|
145
|
+
const bp = this.breakpoints.get(name);
|
146
|
+
if (!bp) return false;
|
147
|
+
|
148
|
+
const dimension = this.getRelevantDimension(width, height, containerType);
|
149
|
+
return dimension >= bp.value;
|
150
|
+
}
|
151
|
+
|
152
|
+
/**
|
153
|
+
* Get breakpoint range (min-max values)
|
154
|
+
*/
|
155
|
+
public getBreakpointRange(name: string): { min: number; max: number | null } | null {
|
156
|
+
const bp = this.breakpoints.get(name);
|
157
|
+
if (!bp) return null;
|
158
|
+
|
159
|
+
const index = this.sortedBreakpoints.findIndex(b => b.name === name);
|
160
|
+
if (index === -1) return null;
|
161
|
+
|
162
|
+
const min = bp.value;
|
163
|
+
const max = index < this.sortedBreakpoints.length - 1
|
164
|
+
? this.sortedBreakpoints[index + 1]!.value - 1
|
165
|
+
: null;
|
166
|
+
|
167
|
+
return { min, max };
|
168
|
+
}
|
169
|
+
|
170
|
+
/**
|
171
|
+
* Generate CSS media queries for breakpoints
|
172
|
+
*/
|
173
|
+
public generateMediaQueries(): Record<string, string> {
|
174
|
+
const queries: Record<string, string> = {};
|
175
|
+
|
176
|
+
this.sortedBreakpoints.forEach((bp) => {
|
177
|
+
const range = this.getBreakpointRange(bp.name);
|
178
|
+
if (!range) return;
|
179
|
+
|
180
|
+
let query = `(min-width: ${range.min}px)`;
|
181
|
+
if (range.max !== null) {
|
182
|
+
query += ` and (max-width: ${range.max}px)`;
|
183
|
+
}
|
184
|
+
|
185
|
+
queries[bp.name] = query;
|
186
|
+
});
|
187
|
+
|
188
|
+
return queries;
|
189
|
+
}
|
190
|
+
|
191
|
+
/**
|
192
|
+
* Generate CSS container queries
|
193
|
+
*/
|
194
|
+
public generateContainerQueries(containerName?: string): Record<string, string> {
|
195
|
+
const queries: Record<string, string> = {};
|
196
|
+
const container = containerName ? `${containerName} ` : '';
|
197
|
+
|
198
|
+
this.sortedBreakpoints.forEach((bp) => {
|
199
|
+
const range = this.getBreakpointRange(bp.name);
|
200
|
+
if (!range) return;
|
201
|
+
|
202
|
+
let query = `@container ${container}(min-width: ${range.min}px)`;
|
203
|
+
if (range.max !== null) {
|
204
|
+
query += ` and (max-width: ${range.max}px)`;
|
205
|
+
}
|
206
|
+
|
207
|
+
queries[bp.name] = query;
|
208
|
+
});
|
209
|
+
|
210
|
+
return queries;
|
211
|
+
}
|
212
|
+
|
213
|
+
/**
|
214
|
+
* Validate breakpoint configuration
|
215
|
+
*/
|
216
|
+
public validateBreakpoints(): { valid: boolean; errors: string[] } {
|
217
|
+
const errors: string[] = [];
|
218
|
+
|
219
|
+
// Check for duplicate values
|
220
|
+
const values = new Map<number, string[]>();
|
221
|
+
this.breakpoints.forEach((bp, name) => {
|
222
|
+
if (!values.has(bp.value)) {
|
223
|
+
values.set(bp.value, []);
|
224
|
+
}
|
225
|
+
values.get(bp.value)!.push(name);
|
226
|
+
});
|
227
|
+
|
228
|
+
values.forEach((names, value) => {
|
229
|
+
if (names.length > 1) {
|
230
|
+
errors.push(`Duplicate breakpoint value ${value}px for: ${names.join(', ')}`);
|
231
|
+
}
|
232
|
+
});
|
233
|
+
|
234
|
+
// Check for invalid values
|
235
|
+
this.breakpoints.forEach((bp, name) => {
|
236
|
+
if (bp.value < 0) {
|
237
|
+
errors.push(`Invalid negative value for breakpoint "${name}": ${bp.value}px`);
|
238
|
+
}
|
239
|
+
if (!isFinite(bp.value)) {
|
240
|
+
errors.push(`Invalid value for breakpoint "${name}": ${bp.originalValue}`);
|
241
|
+
}
|
242
|
+
});
|
243
|
+
|
244
|
+
return {
|
245
|
+
valid: errors.length === 0,
|
246
|
+
errors
|
247
|
+
};
|
248
|
+
}
|
249
|
+
|
250
|
+
/**
|
251
|
+
* Get breakpoint statistics
|
252
|
+
*/
|
253
|
+
public getStats(): object {
|
254
|
+
const values = this.sortedBreakpoints.map(bp => bp.value);
|
255
|
+
return {
|
256
|
+
count: this.breakpoints.size,
|
257
|
+
smallest: values[0] || 0,
|
258
|
+
largest: values[values.length - 1] || 0,
|
259
|
+
average: values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0,
|
260
|
+
units: Array.from(new Set(this.sortedBreakpoints.map(bp => bp.unit))),
|
261
|
+
names: this.sortedBreakpoints.map(bp => bp.name)
|
262
|
+
};
|
263
|
+
}
|
264
|
+
|
265
|
+
/**
|
266
|
+
* Parse breakpoint value into definition
|
267
|
+
*/
|
268
|
+
private parseBreakpoint(name: string, value: string | number): BreakpointDefinition {
|
269
|
+
let pixelValue: number;
|
270
|
+
let unit: string;
|
271
|
+
const originalValue = value;
|
272
|
+
|
273
|
+
if (typeof value === 'number') {
|
274
|
+
pixelValue = value;
|
275
|
+
unit = 'px';
|
276
|
+
} else {
|
277
|
+
const match = value.match(/^(\d*\.?\d+)(px|em|rem|%|vw|vh)?$/);
|
278
|
+
if (!match) {
|
279
|
+
console.warn(`ProteusJS: Invalid breakpoint value "${value}" for "${name}". Using 0px.`);
|
280
|
+
pixelValue = 0;
|
281
|
+
unit = 'px';
|
282
|
+
} else {
|
283
|
+
const numValue = parseFloat(match[1]!);
|
284
|
+
unit = match[2] || 'px';
|
285
|
+
|
286
|
+
// Convert to pixels
|
287
|
+
switch (unit) {
|
288
|
+
case 'px':
|
289
|
+
pixelValue = numValue;
|
290
|
+
break;
|
291
|
+
case 'em':
|
292
|
+
case 'rem':
|
293
|
+
pixelValue = numValue * 16; // Assume 16px base
|
294
|
+
break;
|
295
|
+
case '%':
|
296
|
+
pixelValue = (numValue / 100) * window.innerWidth;
|
297
|
+
break;
|
298
|
+
case 'vw':
|
299
|
+
pixelValue = (numValue / 100) * window.innerWidth;
|
300
|
+
break;
|
301
|
+
case 'vh':
|
302
|
+
pixelValue = (numValue / 100) * window.innerHeight;
|
303
|
+
break;
|
304
|
+
default:
|
305
|
+
pixelValue = numValue;
|
306
|
+
unit = 'px';
|
307
|
+
}
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
return {
|
312
|
+
name,
|
313
|
+
value: pixelValue,
|
314
|
+
unit,
|
315
|
+
originalValue,
|
316
|
+
active: false
|
317
|
+
};
|
318
|
+
}
|
319
|
+
|
320
|
+
/**
|
321
|
+
* Update sorted breakpoints array
|
322
|
+
*/
|
323
|
+
private updateSortedBreakpoints(): void {
|
324
|
+
this.sortedBreakpoints = Array.from(this.breakpoints.values())
|
325
|
+
.sort((a, b) => a.value - b.value);
|
326
|
+
}
|
327
|
+
|
328
|
+
/**
|
329
|
+
* Get relevant dimension based on container type
|
330
|
+
*/
|
331
|
+
private getRelevantDimension(
|
332
|
+
width: number,
|
333
|
+
height: number,
|
334
|
+
containerType: 'inline-size' | 'size' | 'block-size'
|
335
|
+
): number {
|
336
|
+
switch (containerType) {
|
337
|
+
case 'inline-size':
|
338
|
+
return width;
|
339
|
+
case 'block-size':
|
340
|
+
return height;
|
341
|
+
case 'size':
|
342
|
+
return Math.min(width, height);
|
343
|
+
default:
|
344
|
+
return width;
|
345
|
+
}
|
346
|
+
}
|
347
|
+
}
|