@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,227 @@
1
+ /**
2
+ * Integration tests for ProteusJS
3
+ * Tests the complete system working together
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { ProteusJS } from './core/ProteusJS';
8
+
9
+ describe('ProteusJS Integration', () => {
10
+ let proteus: ProteusJS;
11
+ let testContainer: HTMLElement;
12
+
13
+ beforeEach(() => {
14
+ // Reset singleton
15
+ (ProteusJS as any).instance = null;
16
+
17
+ // Create test container
18
+ testContainer = document.createElement('div');
19
+ testContainer.className = 'test-container';
20
+ testContainer.style.width = '500px';
21
+ testContainer.style.height = '300px';
22
+ document.body.appendChild(testContainer);
23
+
24
+ // Initialize ProteusJS
25
+ proteus = new ProteusJS({
26
+ debug: true,
27
+ autoInit: false,
28
+ containers: {
29
+ autoDetect: false,
30
+ breakpoints: {
31
+ sm: '300px',
32
+ md: '500px',
33
+ lg: '800px'
34
+ }
35
+ }
36
+ });
37
+ });
38
+
39
+ afterEach(() => {
40
+ if (proteus) {
41
+ proteus.destroy();
42
+ }
43
+ if (testContainer && testContainer.parentNode) {
44
+ testContainer.parentNode.removeChild(testContainer);
45
+ }
46
+ });
47
+
48
+ describe('System Integration', () => {
49
+ it('should initialize all systems', () => {
50
+ proteus.init();
51
+
52
+ expect(proteus.isInitialized()).toBe(true);
53
+ expect(proteus.getEventSystem()).toBeDefined();
54
+ expect(proteus.getPluginSystem()).toBeDefined();
55
+ expect(proteus.getPerformanceMonitor()).toBeDefined();
56
+ expect(proteus.getMemoryManager()).toBeDefined();
57
+ expect(proteus.getObserverManager()).toBeDefined();
58
+ expect(proteus.getContainerManager()).toBeDefined();
59
+ });
60
+
61
+ it('should create containers', () => {
62
+ proteus.init();
63
+
64
+ const container = proteus.container(testContainer);
65
+ expect(container).toBeDefined();
66
+
67
+ const containerManager = proteus.getContainerManager();
68
+ expect(containerManager.getContainer(testContainer)).toBeDefined();
69
+ });
70
+
71
+ it('should apply fluid typography', () => {
72
+ proteus.init();
73
+
74
+ const textElement = document.createElement('p');
75
+ textElement.textContent = 'Test text';
76
+ testContainer.appendChild(textElement);
77
+
78
+ proteus.fluidType(textElement, {
79
+ minSize: 16,
80
+ maxSize: 24,
81
+ minContainer: 300,
82
+ maxContainer: 800,
83
+ unit: 'px',
84
+ containerUnit: 'cw',
85
+ curve: 'linear'
86
+ });
87
+
88
+ expect(textElement.style.fontSize).toBeTruthy();
89
+ });
90
+
91
+ it('should generate typographic scales', () => {
92
+ proteus.init();
93
+
94
+ const scale = proteus.createTypeScale({
95
+ ratio: 1.2,
96
+ baseSize: 16,
97
+ baseUnit: 'px',
98
+ levels: 5,
99
+ direction: 'both'
100
+ });
101
+
102
+ expect(scale).toBeDefined();
103
+ expect(scale.levels).toHaveLength(11); // 5 up + 5 down + 1 base
104
+ expect(scale.cssCustomProperties).toBeDefined();
105
+ });
106
+ });
107
+
108
+ describe('Performance Monitoring', () => {
109
+ it('should track performance metrics', () => {
110
+ proteus.init();
111
+
112
+ const performanceMonitor = proteus.getPerformanceMonitor();
113
+ performanceMonitor.start();
114
+
115
+ const metrics = performanceMonitor.getMetrics();
116
+ expect(metrics).toBeDefined();
117
+ expect(typeof metrics.frameRate).toBe('number');
118
+ expect(typeof metrics.memoryUsage).toBe('number');
119
+ });
120
+ });
121
+
122
+ describe('Memory Management', () => {
123
+ it('should track and cleanup resources', () => {
124
+ proteus.init();
125
+
126
+ const memoryManager = proteus.getMemoryManager();
127
+
128
+ // Register a test resource
129
+ const resourceId = memoryManager.register({
130
+ id: 'test-resource',
131
+ type: 'observer',
132
+ cleanup: vi.fn(),
133
+ element: testContainer
134
+ });
135
+
136
+ expect(resourceId).toBe('test-resource');
137
+
138
+ const info = memoryManager.getMemoryInfo();
139
+ expect(info).toHaveProperty('managedResources', 1);
140
+
141
+ // Cleanup
142
+ const cleaned = memoryManager.unregister(resourceId);
143
+ expect(cleaned).toBe(true);
144
+ });
145
+ });
146
+
147
+ describe('Container Queries', () => {
148
+ it('should respond to container size changes', async () => {
149
+ proteus.init();
150
+
151
+ const container = proteus.container(testContainer, {
152
+ breakpoints: {
153
+ small: '200px',
154
+ medium: '400px',
155
+ large: '600px'
156
+ }
157
+ });
158
+
159
+ // Simulate size change
160
+ testContainer.style.width = '450px';
161
+
162
+ // Wait for observer to trigger
163
+ await new Promise(resolve => setTimeout(resolve, 50));
164
+
165
+ const state = (container as any).getState();
166
+ expect(state.width).toBe(450);
167
+ expect(state.activeBreakpoints).toContain('small');
168
+ expect(state.activeBreakpoints).toContain('medium');
169
+ });
170
+ });
171
+
172
+ describe('Event System', () => {
173
+ it('should emit and handle events', () => {
174
+ proteus.init();
175
+
176
+ const eventSystem = proteus.getEventSystem();
177
+ const mockCallback = vi.fn();
178
+
179
+ eventSystem.on('test-event', mockCallback);
180
+ eventSystem.emit('test-event', { data: 'test' });
181
+
182
+ expect(mockCallback).toHaveBeenCalledWith(
183
+ expect.objectContaining({
184
+ type: 'test-event',
185
+ detail: { data: 'test' }
186
+ })
187
+ );
188
+ });
189
+ });
190
+
191
+ describe('Plugin System', () => {
192
+ it('should register and install plugins', () => {
193
+ proteus.init();
194
+
195
+ const pluginSystem = proteus.getPluginSystem();
196
+ const mockPlugin = {
197
+ name: 'test-plugin',
198
+ version: '1.0.0',
199
+ install: vi.fn(),
200
+ uninstall: vi.fn()
201
+ };
202
+
203
+ pluginSystem.register(mockPlugin);
204
+ pluginSystem.install('test-plugin');
205
+
206
+ expect(mockPlugin.install).toHaveBeenCalledWith(proteus);
207
+ expect(pluginSystem.isInstalled('test-plugin')).toBe(true);
208
+ });
209
+ });
210
+
211
+ describe('Error Handling', () => {
212
+ it('should handle initialization errors gracefully', () => {
213
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
214
+
215
+ // Mock unsupported browser
216
+ vi.spyOn(ProteusJS, 'isSupported').mockReturnValue(false);
217
+
218
+ proteus.init();
219
+
220
+ expect(consoleSpy).toHaveBeenCalledWith(
221
+ 'ProteusJS: Browser not supported. Missing required APIs.'
222
+ );
223
+
224
+ consoleSpy.mockRestore();
225
+ });
226
+ });
227
+ });
@@ -0,0 +1,429 @@
1
+ /**
2
+ * Adaptive Grid System for ProteusJS
3
+ * Container-aware CSS Grid with auto-column calculation and masonry support
4
+ */
5
+
6
+ export interface GridConfig {
7
+ minColumnWidth: number;
8
+ maxColumns: number;
9
+ gap: number | 'fluid';
10
+ aspectRatio?: number;
11
+ masonry: boolean;
12
+ autoFlow: 'row' | 'column' | 'row dense' | 'column dense';
13
+ alignment: {
14
+ justify: 'start' | 'end' | 'center' | 'stretch' | 'space-around' | 'space-between' | 'space-evenly';
15
+ align: 'start' | 'end' | 'center' | 'stretch';
16
+ };
17
+ responsive: boolean;
18
+ breakpoints?: Record<string, Partial<GridConfig>>;
19
+ }
20
+
21
+ export interface GridState {
22
+ columns: number;
23
+ rows: number;
24
+ gap: number;
25
+ itemWidth: number;
26
+ itemHeight: number;
27
+ containerWidth: number;
28
+ containerHeight: number;
29
+ }
30
+
31
+ export class AdaptiveGrid {
32
+ private element: Element;
33
+ private config: Required<GridConfig>;
34
+ private state: GridState;
35
+ private resizeObserver: ResizeObserver | null = null;
36
+ private mutationObserver: MutationObserver | null = null;
37
+
38
+ constructor(element: Element, config: Partial<GridConfig> = {}) {
39
+ this.element = element;
40
+ this.config = {
41
+ minColumnWidth: 250,
42
+ maxColumns: 12,
43
+ gap: 16,
44
+ aspectRatio: 1,
45
+ masonry: false,
46
+ autoFlow: 'row',
47
+ alignment: {
48
+ justify: 'stretch',
49
+ align: 'stretch'
50
+ },
51
+ responsive: true,
52
+ breakpoints: {},
53
+ ...config
54
+ };
55
+
56
+ this.state = this.createInitialState();
57
+ this.setupGrid();
58
+ }
59
+
60
+ /**
61
+ * Initialize and activate the grid
62
+ */
63
+ public activate(): void {
64
+ this.updateGrid();
65
+ this.setupObservers();
66
+ }
67
+
68
+ /**
69
+ * Deactivate and clean up the grid
70
+ */
71
+ public deactivate(): void {
72
+ this.cleanupObservers();
73
+ this.removeGridStyles();
74
+ }
75
+
76
+ /**
77
+ * Update grid configuration
78
+ */
79
+ public updateConfig(newConfig: Partial<GridConfig>): void {
80
+ this.config = { ...this.config, ...newConfig };
81
+ this.updateGrid();
82
+ }
83
+
84
+ /**
85
+ * Get current grid state
86
+ */
87
+ public getState(): GridState {
88
+ return { ...this.state };
89
+ }
90
+
91
+ /**
92
+ * Force grid recalculation
93
+ */
94
+ public recalculate(): void {
95
+ this.updateGrid();
96
+ }
97
+
98
+ /**
99
+ * Add items to the grid
100
+ */
101
+ public addItems(items: Element[]): void {
102
+ const fragment = document.createDocumentFragment();
103
+ items.forEach(item => {
104
+ this.prepareGridItem(item);
105
+ fragment.appendChild(item);
106
+ });
107
+ this.element.appendChild(fragment);
108
+ this.updateGrid();
109
+ }
110
+
111
+ /**
112
+ * Remove items from the grid
113
+ */
114
+ public removeItems(items: Element[]): void {
115
+ items.forEach(item => {
116
+ if (item.parentNode === this.element) {
117
+ this.element.removeChild(item);
118
+ }
119
+ });
120
+ this.updateGrid();
121
+ }
122
+
123
+ /**
124
+ * Get optimal column count for container width
125
+ */
126
+ public calculateOptimalColumns(containerWidth: number): number {
127
+ const availableWidth = containerWidth - this.getGapValue();
128
+ const minWidth = this.config.minColumnWidth;
129
+
130
+ // Calculate maximum possible columns based on min width
131
+ const maxPossibleColumns = Math.floor((availableWidth + this.getGapValue()) / (minWidth + this.getGapValue()));
132
+
133
+ // Respect max columns limit
134
+ return Math.min(maxPossibleColumns, this.config.maxColumns);
135
+ }
136
+
137
+ /**
138
+ * Setup initial grid styles
139
+ */
140
+ private setupGrid(): void {
141
+ const htmlElement = this.element as HTMLElement;
142
+ htmlElement.style.display = 'grid';
143
+
144
+ if (this.config.masonry) {
145
+ this.setupMasonryGrid();
146
+ } else {
147
+ this.setupRegularGrid();
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Setup regular CSS Grid
153
+ */
154
+ private setupRegularGrid(): void {
155
+ const htmlElement = this.element as HTMLElement;
156
+
157
+ htmlElement.style.gridAutoFlow = this.config.autoFlow;
158
+ htmlElement.style.justifyContent = this.config.alignment.justify;
159
+ htmlElement.style.alignContent = this.config.alignment.align;
160
+ htmlElement.style.justifyItems = this.config.alignment.justify;
161
+ htmlElement.style.alignItems = this.config.alignment.align;
162
+ }
163
+
164
+ /**
165
+ * Setup masonry grid using CSS Grid Level 3 or fallback
166
+ */
167
+ private setupMasonryGrid(): void {
168
+ const htmlElement = this.element as HTMLElement;
169
+
170
+ // Check for native masonry support
171
+ if (this.supportsMasonry()) {
172
+ htmlElement.style.gridTemplateRows = 'masonry';
173
+ } else {
174
+ // Fallback to JavaScript masonry
175
+ this.implementJavaScriptMasonry();
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Update grid layout
181
+ */
182
+ private updateGrid(): void {
183
+ const containerRect = this.element.getBoundingClientRect();
184
+ const containerWidth = containerRect.width;
185
+ const containerHeight = containerRect.height;
186
+
187
+ // Apply responsive config if needed
188
+ const activeConfig = this.getActiveConfig(containerWidth);
189
+
190
+ // Calculate optimal columns
191
+ const columns = this.calculateOptimalColumns(containerWidth);
192
+ const gap = this.getGapValue();
193
+
194
+ // Calculate item dimensions
195
+ const itemWidth = (containerWidth - gap * (columns - 1)) / columns;
196
+ const itemHeight = activeConfig.aspectRatio
197
+ ? itemWidth / activeConfig.aspectRatio
198
+ : 0; // Auto height
199
+
200
+ // Update state
201
+ this.state = {
202
+ columns,
203
+ rows: Math.ceil(this.getItemCount() / columns),
204
+ gap,
205
+ itemWidth,
206
+ itemHeight,
207
+ containerWidth,
208
+ containerHeight
209
+ };
210
+
211
+ // Apply grid styles
212
+ this.applyGridStyles();
213
+
214
+ // Handle masonry layout
215
+ if (activeConfig.masonry && !this.supportsMasonry()) {
216
+ this.updateMasonryLayout();
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Apply calculated grid styles
222
+ */
223
+ private applyGridStyles(): void {
224
+ const htmlElement = this.element as HTMLElement;
225
+ const { columns, gap, itemHeight } = this.state;
226
+
227
+ // Set grid template columns
228
+ htmlElement.style.gridTemplateColumns = `repeat(${columns}, 1fr)`;
229
+
230
+ // Set gap
231
+ htmlElement.style.gap = `${gap}px`;
232
+
233
+ // Set row height if aspect ratio is specified
234
+ if (itemHeight > 0) {
235
+ htmlElement.style.gridAutoRows = `${itemHeight}px`;
236
+ } else {
237
+ htmlElement.style.gridAutoRows = 'auto';
238
+ }
239
+
240
+ // Prepare all grid items
241
+ Array.from(this.element.children).forEach(child => {
242
+ this.prepareGridItem(child);
243
+ });
244
+ }
245
+
246
+ /**
247
+ * Prepare individual grid item
248
+ */
249
+ private prepareGridItem(item: Element): void {
250
+ const htmlItem = item as HTMLElement;
251
+
252
+ // Ensure proper box-sizing
253
+ htmlItem.style.boxSizing = 'border-box';
254
+
255
+ // Handle aspect ratio for items if specified
256
+ if (this.config.aspectRatio && !this.config.masonry) {
257
+ htmlItem.style.aspectRatio = this.config.aspectRatio.toString();
258
+ }
259
+
260
+ // Add grid item class for styling
261
+ htmlItem.classList.add('proteus-grid-item');
262
+ }
263
+
264
+ /**
265
+ * Implement JavaScript masonry layout
266
+ */
267
+ private implementJavaScriptMasonry(): void {
268
+ const items = Array.from(this.element.children) as HTMLElement[];
269
+ const { columns, gap } = this.state;
270
+
271
+ // Create column height trackers
272
+ const columnHeights = new Array(columns).fill(0);
273
+
274
+ items.forEach((item, index) => {
275
+ // Find shortest column
276
+ const shortestColumnIndex = columnHeights.indexOf(Math.min(...columnHeights));
277
+
278
+ // Position item
279
+ const column = shortestColumnIndex;
280
+ const row = Math.floor(columnHeights[shortestColumnIndex] / (this.state.itemHeight + gap));
281
+
282
+ item.style.gridColumnStart = (column + 1).toString();
283
+ item.style.gridRowStart = (row + 1).toString();
284
+
285
+ // Update column height
286
+ const itemHeight = item.getBoundingClientRect().height || this.state.itemHeight;
287
+ columnHeights[shortestColumnIndex] += itemHeight + gap;
288
+ });
289
+ }
290
+
291
+ /**
292
+ * Update masonry layout
293
+ */
294
+ private updateMasonryLayout(): void {
295
+ // Wait for layout to settle, then update masonry
296
+ requestAnimationFrame(() => {
297
+ this.implementJavaScriptMasonry();
298
+ });
299
+ }
300
+
301
+ /**
302
+ * Setup observers for responsive behavior
303
+ */
304
+ private setupObservers(): void {
305
+ if (!this.config.responsive) return;
306
+
307
+ // Resize observer for container size changes
308
+ this.resizeObserver = new ResizeObserver(() => {
309
+ this.updateGrid();
310
+ });
311
+ this.resizeObserver.observe(this.element);
312
+
313
+ // Mutation observer for content changes
314
+ this.mutationObserver = new MutationObserver(() => {
315
+ this.updateGrid();
316
+ });
317
+ this.mutationObserver.observe(this.element, {
318
+ childList: true,
319
+ subtree: false
320
+ });
321
+ }
322
+
323
+ /**
324
+ * Clean up observers
325
+ */
326
+ private cleanupObservers(): void {
327
+ if (this.resizeObserver) {
328
+ this.resizeObserver.disconnect();
329
+ this.resizeObserver = null;
330
+ }
331
+
332
+ if (this.mutationObserver) {
333
+ this.mutationObserver.disconnect();
334
+ this.mutationObserver = null;
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Remove grid styles
340
+ */
341
+ private removeGridStyles(): void {
342
+ const htmlElement = this.element as HTMLElement;
343
+
344
+ // Remove grid styles
345
+ htmlElement.style.removeProperty('display');
346
+ htmlElement.style.removeProperty('grid-template-columns');
347
+ htmlElement.style.removeProperty('grid-template-rows');
348
+ htmlElement.style.removeProperty('gap');
349
+ htmlElement.style.removeProperty('grid-auto-flow');
350
+ htmlElement.style.removeProperty('justify-content');
351
+ htmlElement.style.removeProperty('align-content');
352
+ htmlElement.style.removeProperty('justify-items');
353
+ htmlElement.style.removeProperty('align-items');
354
+ htmlElement.style.removeProperty('grid-auto-rows');
355
+
356
+ // Remove item styles
357
+ Array.from(this.element.children).forEach(child => {
358
+ const htmlChild = child as HTMLElement;
359
+ htmlChild.style.removeProperty('grid-column-start');
360
+ htmlChild.style.removeProperty('grid-row-start');
361
+ htmlChild.style.removeProperty('aspect-ratio');
362
+ htmlChild.classList.remove('proteus-grid-item');
363
+ });
364
+ }
365
+
366
+ /**
367
+ * Get active configuration based on container width
368
+ */
369
+ private getActiveConfig(containerWidth: number): Required<GridConfig> {
370
+ let activeConfig = { ...this.config };
371
+
372
+ // Apply breakpoint-specific configs
373
+ if (this.config.breakpoints) {
374
+ const sortedBreakpoints = Object.entries(this.config.breakpoints)
375
+ .map(([name, config]) => ({ name, width: parseInt(name), config }))
376
+ .sort((a, b) => a.width - b.width);
377
+
378
+ for (const breakpoint of sortedBreakpoints) {
379
+ if (containerWidth >= breakpoint.width) {
380
+ activeConfig = { ...activeConfig, ...breakpoint.config };
381
+ }
382
+ }
383
+ }
384
+
385
+ return activeConfig;
386
+ }
387
+
388
+ /**
389
+ * Get gap value in pixels
390
+ */
391
+ private getGapValue(): number {
392
+ if (this.config.gap === 'fluid') {
393
+ // Fluid gap based on container width
394
+ const containerWidth = this.element.getBoundingClientRect().width;
395
+ return Math.max(8, Math.min(32, containerWidth * 0.02));
396
+ }
397
+ return this.config.gap as number;
398
+ }
399
+
400
+ /**
401
+ * Get number of grid items
402
+ */
403
+ private getItemCount(): number {
404
+ return this.element.children.length;
405
+ }
406
+
407
+ /**
408
+ * Check if native masonry is supported
409
+ */
410
+ private supportsMasonry(): boolean {
411
+ if (typeof CSS === 'undefined' || !CSS.supports) return false;
412
+ return CSS.supports('grid-template-rows', 'masonry');
413
+ }
414
+
415
+ /**
416
+ * Create initial state
417
+ */
418
+ private createInitialState(): GridState {
419
+ return {
420
+ columns: 1,
421
+ rows: 1,
422
+ gap: 16,
423
+ itemWidth: 0,
424
+ itemHeight: 0,
425
+ containerWidth: 0,
426
+ containerHeight: 0
427
+ };
428
+ }
429
+ }