@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,275 @@
|
|
1
|
+
/**
|
2
|
+
* Plugin System for ProteusJS
|
3
|
+
* Enables extensibility and modular architecture
|
4
|
+
*/
|
5
|
+
|
6
|
+
export interface ProteusPlugin {
|
7
|
+
name: string;
|
8
|
+
version: string;
|
9
|
+
dependencies?: string[];
|
10
|
+
install: (proteus: any) => void;
|
11
|
+
uninstall?: (proteus: any) => void;
|
12
|
+
config?: Record<string, any>;
|
13
|
+
}
|
14
|
+
|
15
|
+
export class PluginSystem {
|
16
|
+
private plugins: Map<string, ProteusPlugin> = new Map();
|
17
|
+
private installedPlugins: Set<string> = new Set();
|
18
|
+
private proteus: any;
|
19
|
+
private initialized: boolean = false;
|
20
|
+
|
21
|
+
constructor(proteus: any) {
|
22
|
+
this.proteus = proteus;
|
23
|
+
}
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Initialize the plugin system
|
27
|
+
*/
|
28
|
+
public init(): void {
|
29
|
+
if (this.initialized) return;
|
30
|
+
this.initialized = true;
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Register a plugin
|
35
|
+
*/
|
36
|
+
public register(plugin: ProteusPlugin): this {
|
37
|
+
if (this.plugins.has(plugin.name)) {
|
38
|
+
console.warn(`ProteusJS: Plugin "${plugin.name}" is already registered`);
|
39
|
+
return this;
|
40
|
+
}
|
41
|
+
|
42
|
+
// Validate plugin
|
43
|
+
if (!this.validatePlugin(plugin)) {
|
44
|
+
throw new Error(`ProteusJS: Invalid plugin "${plugin.name}"`);
|
45
|
+
}
|
46
|
+
|
47
|
+
this.plugins.set(plugin.name, plugin);
|
48
|
+
return this;
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Install a plugin
|
53
|
+
*/
|
54
|
+
public install(pluginName: string): this {
|
55
|
+
const plugin = this.plugins.get(pluginName);
|
56
|
+
if (!plugin) {
|
57
|
+
throw new Error(`ProteusJS: Plugin "${pluginName}" not found`);
|
58
|
+
}
|
59
|
+
|
60
|
+
if (this.installedPlugins.has(pluginName)) {
|
61
|
+
console.warn(`ProteusJS: Plugin "${pluginName}" is already installed`);
|
62
|
+
return this;
|
63
|
+
}
|
64
|
+
|
65
|
+
// Check dependencies
|
66
|
+
if (plugin.dependencies) {
|
67
|
+
for (const dep of plugin.dependencies) {
|
68
|
+
if (!this.installedPlugins.has(dep)) {
|
69
|
+
throw new Error(
|
70
|
+
`ProteusJS: Plugin "${pluginName}" requires dependency "${dep}" to be installed first`
|
71
|
+
);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
try {
|
77
|
+
// Install the plugin
|
78
|
+
plugin.install(this.proteus);
|
79
|
+
this.installedPlugins.add(pluginName);
|
80
|
+
|
81
|
+
// Emit plugin installed event
|
82
|
+
this.proteus.getEventSystem().emit('pluginInstalled', {
|
83
|
+
plugin: pluginName,
|
84
|
+
version: plugin.version
|
85
|
+
});
|
86
|
+
|
87
|
+
console.log(`ProteusJS: Plugin "${pluginName}" v${plugin.version} installed`);
|
88
|
+
} catch (error) {
|
89
|
+
console.error(`ProteusJS: Failed to install plugin "${pluginName}":`, error);
|
90
|
+
throw error;
|
91
|
+
}
|
92
|
+
|
93
|
+
return this;
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* Uninstall a plugin
|
98
|
+
*/
|
99
|
+
public uninstall(pluginName: string): this {
|
100
|
+
const plugin = this.plugins.get(pluginName);
|
101
|
+
if (!plugin) {
|
102
|
+
console.warn(`ProteusJS: Plugin "${pluginName}" not found`);
|
103
|
+
return this;
|
104
|
+
}
|
105
|
+
|
106
|
+
if (!this.installedPlugins.has(pluginName)) {
|
107
|
+
console.warn(`ProteusJS: Plugin "${pluginName}" is not installed`);
|
108
|
+
return this;
|
109
|
+
}
|
110
|
+
|
111
|
+
// Check if other plugins depend on this one
|
112
|
+
const dependents = this.getDependents(pluginName);
|
113
|
+
if (dependents.length > 0) {
|
114
|
+
throw new Error(
|
115
|
+
`ProteusJS: Cannot uninstall plugin "${pluginName}" because it's required by: ${dependents.join(', ')}`
|
116
|
+
);
|
117
|
+
}
|
118
|
+
|
119
|
+
try {
|
120
|
+
// Uninstall the plugin
|
121
|
+
if (plugin.uninstall) {
|
122
|
+
plugin.uninstall(this.proteus);
|
123
|
+
}
|
124
|
+
this.installedPlugins.delete(pluginName);
|
125
|
+
|
126
|
+
// Emit plugin uninstalled event
|
127
|
+
this.proteus.getEventSystem().emit('pluginUninstalled', {
|
128
|
+
plugin: pluginName,
|
129
|
+
version: plugin.version
|
130
|
+
});
|
131
|
+
|
132
|
+
console.log(`ProteusJS: Plugin "${pluginName}" uninstalled`);
|
133
|
+
} catch (error) {
|
134
|
+
console.error(`ProteusJS: Failed to uninstall plugin "${pluginName}":`, error);
|
135
|
+
throw error;
|
136
|
+
}
|
137
|
+
|
138
|
+
return this;
|
139
|
+
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* Check if a plugin is installed
|
143
|
+
*/
|
144
|
+
public isInstalled(pluginName: string): boolean {
|
145
|
+
return this.installedPlugins.has(pluginName);
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* Get list of registered plugins
|
150
|
+
*/
|
151
|
+
public getRegisteredPlugins(): string[] {
|
152
|
+
return Array.from(this.plugins.keys());
|
153
|
+
}
|
154
|
+
|
155
|
+
/**
|
156
|
+
* Get list of installed plugins
|
157
|
+
*/
|
158
|
+
public getInstalledPlugins(): string[] {
|
159
|
+
return Array.from(this.installedPlugins);
|
160
|
+
}
|
161
|
+
|
162
|
+
/**
|
163
|
+
* Get plugin information
|
164
|
+
*/
|
165
|
+
public getPluginInfo(pluginName: string): ProteusPlugin | undefined {
|
166
|
+
return this.plugins.get(pluginName);
|
167
|
+
}
|
168
|
+
|
169
|
+
/**
|
170
|
+
* Install multiple plugins in dependency order
|
171
|
+
*/
|
172
|
+
public installMany(pluginNames: string[]): this {
|
173
|
+
const sortedPlugins = this.sortByDependencies(pluginNames);
|
174
|
+
for (const pluginName of sortedPlugins) {
|
175
|
+
this.install(pluginName);
|
176
|
+
}
|
177
|
+
return this;
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Destroy the plugin system
|
182
|
+
*/
|
183
|
+
public destroy(): void {
|
184
|
+
// Uninstall all plugins in reverse dependency order
|
185
|
+
const installedPlugins = Array.from(this.installedPlugins);
|
186
|
+
const sortedPlugins = this.sortByDependencies(installedPlugins).reverse();
|
187
|
+
|
188
|
+
for (const pluginName of sortedPlugins) {
|
189
|
+
try {
|
190
|
+
this.uninstall(pluginName);
|
191
|
+
} catch (error) {
|
192
|
+
console.error(`ProteusJS: Error uninstalling plugin "${pluginName}":`, error);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
this.plugins.clear();
|
197
|
+
this.installedPlugins.clear();
|
198
|
+
this.initialized = false;
|
199
|
+
}
|
200
|
+
|
201
|
+
/**
|
202
|
+
* Validate plugin structure
|
203
|
+
*/
|
204
|
+
private validatePlugin(plugin: ProteusPlugin): boolean {
|
205
|
+
if (!plugin.name || typeof plugin.name !== 'string') {
|
206
|
+
console.error('ProteusJS: Plugin must have a valid name');
|
207
|
+
return false;
|
208
|
+
}
|
209
|
+
|
210
|
+
if (!plugin.version || typeof plugin.version !== 'string') {
|
211
|
+
console.error('ProteusJS: Plugin must have a valid version');
|
212
|
+
return false;
|
213
|
+
}
|
214
|
+
|
215
|
+
if (!plugin.install || typeof plugin.install !== 'function') {
|
216
|
+
console.error('ProteusJS: Plugin must have an install function');
|
217
|
+
return false;
|
218
|
+
}
|
219
|
+
|
220
|
+
return true;
|
221
|
+
}
|
222
|
+
|
223
|
+
/**
|
224
|
+
* Get plugins that depend on the given plugin
|
225
|
+
*/
|
226
|
+
private getDependents(pluginName: string): string[] {
|
227
|
+
const dependents: string[] = [];
|
228
|
+
|
229
|
+
for (const [name, plugin] of this.plugins) {
|
230
|
+
if (this.installedPlugins.has(name) && plugin.dependencies?.includes(pluginName)) {
|
231
|
+
dependents.push(name);
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
return dependents;
|
236
|
+
}
|
237
|
+
|
238
|
+
/**
|
239
|
+
* Sort plugins by dependency order
|
240
|
+
*/
|
241
|
+
private sortByDependencies(pluginNames: string[]): string[] {
|
242
|
+
const sorted: string[] = [];
|
243
|
+
const visited = new Set<string>();
|
244
|
+
const visiting = new Set<string>();
|
245
|
+
|
246
|
+
const visit = (pluginName: string): void => {
|
247
|
+
if (visiting.has(pluginName)) {
|
248
|
+
throw new Error(`ProteusJS: Circular dependency detected involving plugin "${pluginName}"`);
|
249
|
+
}
|
250
|
+
|
251
|
+
if (visited.has(pluginName)) return;
|
252
|
+
|
253
|
+
visiting.add(pluginName);
|
254
|
+
|
255
|
+
const plugin = this.plugins.get(pluginName);
|
256
|
+
if (plugin?.dependencies) {
|
257
|
+
for (const dep of plugin.dependencies) {
|
258
|
+
if (pluginNames.includes(dep)) {
|
259
|
+
visit(dep);
|
260
|
+
}
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
visiting.delete(pluginName);
|
265
|
+
visited.add(pluginName);
|
266
|
+
sorted.push(pluginName);
|
267
|
+
};
|
268
|
+
|
269
|
+
for (const pluginName of pluginNames) {
|
270
|
+
visit(pluginName);
|
271
|
+
}
|
272
|
+
|
273
|
+
return sorted;
|
274
|
+
}
|
275
|
+
}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
/**
|
2
|
+
* Tests for ProteusJS core functionality
|
3
|
+
*/
|
4
|
+
|
5
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
6
|
+
import { ProteusJS } from './ProteusJS';
|
7
|
+
|
8
|
+
describe('ProteusJS', () => {
|
9
|
+
let proteus: ProteusJS;
|
10
|
+
|
11
|
+
beforeEach(() => {
|
12
|
+
// Reset singleton instance
|
13
|
+
(ProteusJS as any).instance = null;
|
14
|
+
proteus = new ProteusJS({ debug: true, autoInit: false });
|
15
|
+
});
|
16
|
+
|
17
|
+
afterEach(() => {
|
18
|
+
if (proteus) {
|
19
|
+
proteus.destroy();
|
20
|
+
}
|
21
|
+
});
|
22
|
+
|
23
|
+
describe('Initialization', () => {
|
24
|
+
it('should create a singleton instance', () => {
|
25
|
+
const instance1 = new ProteusJS();
|
26
|
+
const instance2 = new ProteusJS();
|
27
|
+
expect(instance1).toBe(instance2);
|
28
|
+
});
|
29
|
+
|
30
|
+
it('should initialize with default config', () => {
|
31
|
+
const config = proteus.getConfig();
|
32
|
+
expect(config.debug).toBe(true);
|
33
|
+
expect(config.accessibility).toBe(true);
|
34
|
+
expect(config.performance).toBe('high');
|
35
|
+
});
|
36
|
+
|
37
|
+
it('should merge custom config with defaults', () => {
|
38
|
+
const customProteus = new ProteusJS({
|
39
|
+
debug: false,
|
40
|
+
performance: 'low',
|
41
|
+
containers: {
|
42
|
+
autoDetect: false
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
const config = customProteus.getConfig();
|
47
|
+
expect(config.debug).toBe(false);
|
48
|
+
expect(config.performance).toBe('low');
|
49
|
+
expect(config.containers.autoDetect).toBe(false);
|
50
|
+
expect(config.accessibility).toBe(true); // Should keep default
|
51
|
+
|
52
|
+
customProteus.destroy();
|
53
|
+
});
|
54
|
+
|
55
|
+
it('should initialize successfully', () => {
|
56
|
+
expect(proteus.isInitialized()).toBe(false);
|
57
|
+
proteus.init();
|
58
|
+
expect(proteus.isInitialized()).toBe(true);
|
59
|
+
});
|
60
|
+
|
61
|
+
it('should not initialize twice', () => {
|
62
|
+
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
63
|
+
|
64
|
+
proteus.init();
|
65
|
+
proteus.init(); // Second call should warn
|
66
|
+
|
67
|
+
expect(consoleSpy).toHaveBeenCalledWith('ProteusJS: Already initialized');
|
68
|
+
consoleSpy.mockRestore();
|
69
|
+
});
|
70
|
+
});
|
71
|
+
|
72
|
+
describe('Configuration', () => {
|
73
|
+
it('should update configuration', () => {
|
74
|
+
proteus.updateConfig({ debug: false });
|
75
|
+
const config = proteus.getConfig();
|
76
|
+
expect(config.debug).toBe(false);
|
77
|
+
});
|
78
|
+
|
79
|
+
it('should emit config update event', () => {
|
80
|
+
const eventSystem = proteus.getEventSystem();
|
81
|
+
const mockCallback = vi.fn();
|
82
|
+
|
83
|
+
eventSystem.on('configUpdate', mockCallback);
|
84
|
+
proteus.updateConfig({ debug: false });
|
85
|
+
|
86
|
+
expect(mockCallback).toHaveBeenCalledWith(
|
87
|
+
expect.objectContaining({
|
88
|
+
type: 'configUpdate',
|
89
|
+
detail: expect.objectContaining({
|
90
|
+
config: expect.any(Object)
|
91
|
+
})
|
92
|
+
})
|
93
|
+
);
|
94
|
+
});
|
95
|
+
});
|
96
|
+
|
97
|
+
describe('Systems', () => {
|
98
|
+
it('should provide access to event system', () => {
|
99
|
+
const eventSystem = proteus.getEventSystem();
|
100
|
+
expect(eventSystem).toBeDefined();
|
101
|
+
expect(typeof eventSystem.on).toBe('function');
|
102
|
+
});
|
103
|
+
|
104
|
+
it('should provide access to plugin system', () => {
|
105
|
+
const pluginSystem = proteus.getPluginSystem();
|
106
|
+
expect(pluginSystem).toBeDefined();
|
107
|
+
expect(typeof pluginSystem.register).toBe('function');
|
108
|
+
});
|
109
|
+
|
110
|
+
it('should provide access to performance monitor', () => {
|
111
|
+
const performanceMonitor = proteus.getPerformanceMonitor();
|
112
|
+
expect(performanceMonitor).toBeDefined();
|
113
|
+
expect(typeof performanceMonitor.getMetrics).toBe('function');
|
114
|
+
});
|
115
|
+
});
|
116
|
+
|
117
|
+
describe('Static methods', () => {
|
118
|
+
it('should return version', () => {
|
119
|
+
const version = ProteusJS.getVersion();
|
120
|
+
expect(typeof version).toBe('string');
|
121
|
+
expect(version).toMatch(/^\d+\.\d+\.\d+$/);
|
122
|
+
});
|
123
|
+
|
124
|
+
it('should return support info', () => {
|
125
|
+
const support = ProteusJS.getSupportInfo();
|
126
|
+
expect(support).toBeDefined();
|
127
|
+
expect(typeof support.resizeObserver).toBe('boolean');
|
128
|
+
expect(typeof support.intersectionObserver).toBe('boolean');
|
129
|
+
});
|
130
|
+
|
131
|
+
it('should check browser support', () => {
|
132
|
+
const isSupported = ProteusJS.isSupported();
|
133
|
+
expect(typeof isSupported).toBe('boolean');
|
134
|
+
});
|
135
|
+
|
136
|
+
it('should get or create global instance', () => {
|
137
|
+
const instance1 = ProteusJS.getInstance();
|
138
|
+
const instance2 = ProteusJS.getInstance();
|
139
|
+
expect(instance1).toBe(instance2);
|
140
|
+
|
141
|
+
instance1.destroy();
|
142
|
+
});
|
143
|
+
});
|
144
|
+
|
145
|
+
describe('Cleanup', () => {
|
146
|
+
it('should destroy properly', () => {
|
147
|
+
proteus.init();
|
148
|
+
expect(proteus.isInitialized()).toBe(true);
|
149
|
+
|
150
|
+
proteus.destroy();
|
151
|
+
expect(proteus.isInitialized()).toBe(false);
|
152
|
+
});
|
153
|
+
|
154
|
+
it('should reset singleton on destroy', () => {
|
155
|
+
proteus.init();
|
156
|
+
proteus.destroy();
|
157
|
+
|
158
|
+
const newInstance = new ProteusJS();
|
159
|
+
expect(newInstance).not.toBe(proteus);
|
160
|
+
|
161
|
+
newInstance.destroy();
|
162
|
+
});
|
163
|
+
});
|
164
|
+
});
|