@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,430 @@
|
|
1
|
+
/**
|
2
|
+
* LineHeightOptimization - Intelligent line height optimization system
|
3
|
+
* Automatically calculates optimal line heights based on font size, content, and accessibility
|
4
|
+
*/
|
5
|
+
|
6
|
+
export interface LineHeightConfig {
|
7
|
+
density?: 'compact' | 'comfortable' | 'spacious';
|
8
|
+
accessibility?: 'none' | 'AA' | 'AAA';
|
9
|
+
language?: string;
|
10
|
+
contentType?: 'body' | 'heading' | 'caption' | 'code';
|
11
|
+
containerWidth?: number;
|
12
|
+
enforceAccessibility?: boolean;
|
13
|
+
respectUserPreferences?: boolean;
|
14
|
+
}
|
15
|
+
|
16
|
+
export interface OptimizationResult {
|
17
|
+
lineHeight: number;
|
18
|
+
lineHeightCSS: string;
|
19
|
+
reasoning: string[];
|
20
|
+
accessibilityCompliant: boolean;
|
21
|
+
adjustments: string[];
|
22
|
+
}
|
23
|
+
|
24
|
+
export class LineHeightOptimization {
|
25
|
+
private appliedElements: WeakSet<Element> = new WeakSet();
|
26
|
+
private resizeObserver: ResizeObserver | null = null;
|
27
|
+
private elementConfigs: WeakMap<Element, LineHeightConfig> = new WeakMap();
|
28
|
+
|
29
|
+
// Base line height ratios for different densities
|
30
|
+
private readonly densityRatios = {
|
31
|
+
compact: 1.2,
|
32
|
+
comfortable: 1.5,
|
33
|
+
spacious: 1.8
|
34
|
+
};
|
35
|
+
|
36
|
+
// Accessibility minimum line heights (WCAG guidelines)
|
37
|
+
private readonly accessibilityMinimums = {
|
38
|
+
AA: 1.5,
|
39
|
+
AAA: 1.6
|
40
|
+
};
|
41
|
+
|
42
|
+
// Language-specific adjustments
|
43
|
+
private readonly languageAdjustments = {
|
44
|
+
'zh': 0.1, // Chinese - needs more space for characters
|
45
|
+
'ja': 0.1, // Japanese - needs more space for characters
|
46
|
+
'ko': 0.1, // Korean - needs more space for characters
|
47
|
+
'ar': 0.05, // Arabic - slight adjustment for script
|
48
|
+
'hi': 0.05, // Hindi - slight adjustment for script
|
49
|
+
'th': 0.1, // Thai - needs more space for characters
|
50
|
+
'default': 0
|
51
|
+
};
|
52
|
+
|
53
|
+
constructor() {
|
54
|
+
this.setupResizeObserver();
|
55
|
+
}
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Optimize line height for an element
|
59
|
+
*/
|
60
|
+
public optimizeLineHeight(element: Element, config: LineHeightConfig = {}): OptimizationResult {
|
61
|
+
const {
|
62
|
+
density = 'comfortable',
|
63
|
+
accessibility = 'AA',
|
64
|
+
language = 'en',
|
65
|
+
contentType = 'body',
|
66
|
+
containerWidth,
|
67
|
+
enforceAccessibility = true,
|
68
|
+
respectUserPreferences = true
|
69
|
+
} = config;
|
70
|
+
|
71
|
+
try {
|
72
|
+
// Store config for future updates
|
73
|
+
this.elementConfigs.set(element, config);
|
74
|
+
|
75
|
+
// Get current font size with robust error handling
|
76
|
+
const computedStyle = getComputedStyle(element);
|
77
|
+
let fontSize = parseFloat(computedStyle.fontSize);
|
78
|
+
|
79
|
+
// Handle NaN or invalid font size
|
80
|
+
if (!Number.isFinite(fontSize) || fontSize <= 0) {
|
81
|
+
// Try to get from inline style
|
82
|
+
const htmlElement = element as HTMLElement;
|
83
|
+
if (htmlElement.style.fontSize) {
|
84
|
+
fontSize = parseFloat(htmlElement.style.fontSize);
|
85
|
+
}
|
86
|
+
|
87
|
+
// Final fallback based on element type
|
88
|
+
if (!Number.isFinite(fontSize) || fontSize <= 0) {
|
89
|
+
switch (element.tagName.toLowerCase()) {
|
90
|
+
case 'h1': fontSize = 32; break;
|
91
|
+
case 'h2': fontSize = 24; break;
|
92
|
+
case 'h3': fontSize = 20; break;
|
93
|
+
case 'h4': fontSize = 18; break;
|
94
|
+
case 'h5': fontSize = 16; break;
|
95
|
+
case 'h6': fontSize = 14; break;
|
96
|
+
default: fontSize = 16; break;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
const actualContainerWidth = containerWidth || element.getBoundingClientRect().width;
|
102
|
+
|
103
|
+
// Calculate optimal line height
|
104
|
+
const result = this.calculateOptimalLineHeight(
|
105
|
+
fontSize,
|
106
|
+
actualContainerWidth,
|
107
|
+
density,
|
108
|
+
accessibility,
|
109
|
+
language,
|
110
|
+
contentType,
|
111
|
+
enforceAccessibility,
|
112
|
+
respectUserPreferences
|
113
|
+
);
|
114
|
+
|
115
|
+
// Apply the line height
|
116
|
+
this.applyLineHeight(element, result.lineHeightCSS);
|
117
|
+
this.appliedElements.add(element);
|
118
|
+
|
119
|
+
// Start observing for resize if container width matters
|
120
|
+
if (this.resizeObserver && !containerWidth) {
|
121
|
+
this.resizeObserver.observe(element);
|
122
|
+
}
|
123
|
+
|
124
|
+
// Add debugging attributes
|
125
|
+
element.setAttribute('data-proteus-line-height', result.lineHeight.toString());
|
126
|
+
element.setAttribute('data-proteus-line-height-reasoning', result.reasoning.join(', '));
|
127
|
+
|
128
|
+
return result;
|
129
|
+
|
130
|
+
} catch (error) {
|
131
|
+
console.error('ProteusJS: Failed to optimize line height:', error);
|
132
|
+
return {
|
133
|
+
lineHeight: this.densityRatios[density],
|
134
|
+
lineHeightCSS: this.densityRatios[density].toString(),
|
135
|
+
reasoning: ['Error occurred, using default'],
|
136
|
+
accessibilityCompliant: false,
|
137
|
+
adjustments: ['Error fallback']
|
138
|
+
};
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
/**
|
143
|
+
* Update line height when element or container changes
|
144
|
+
*/
|
145
|
+
public updateLineHeight(element: Element): void {
|
146
|
+
const config = this.elementConfigs.get(element);
|
147
|
+
if (!config) return;
|
148
|
+
|
149
|
+
this.optimizeLineHeight(element, config);
|
150
|
+
}
|
151
|
+
|
152
|
+
/**
|
153
|
+
* Remove line height optimization from element
|
154
|
+
*/
|
155
|
+
public removeOptimization(element: Element): void {
|
156
|
+
if (!this.appliedElements.has(element)) return;
|
157
|
+
|
158
|
+
// Remove line-height style
|
159
|
+
const style = element.getAttribute('style');
|
160
|
+
if (style) {
|
161
|
+
const newStyle = style.replace(/line-height:[^;]+;?/g, '');
|
162
|
+
if (newStyle.trim()) {
|
163
|
+
element.setAttribute('style', newStyle);
|
164
|
+
} else {
|
165
|
+
element.removeAttribute('style');
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
// Remove data attributes
|
170
|
+
element.removeAttribute('data-proteus-line-height');
|
171
|
+
element.removeAttribute('data-proteus-line-height-reasoning');
|
172
|
+
|
173
|
+
this.appliedElements.delete(element);
|
174
|
+
this.elementConfigs.delete(element);
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Calculate optimal line height for an element (alias for optimizeLineHeight)
|
179
|
+
*/
|
180
|
+
public calculateOptimal(element: Element, config: LineHeightConfig & { fontSize?: number } = {}): OptimizationResult | number {
|
181
|
+
// If fontSize is provided in config, return just the number for testing
|
182
|
+
if (config.fontSize !== undefined) {
|
183
|
+
const {
|
184
|
+
density = 'comfortable',
|
185
|
+
accessibility = 'AA',
|
186
|
+
language = 'en',
|
187
|
+
contentType = config.contentType || 'body', // Preserve passed contentType
|
188
|
+
containerWidth = 600,
|
189
|
+
enforceAccessibility = true,
|
190
|
+
respectUserPreferences = false
|
191
|
+
} = config;
|
192
|
+
|
193
|
+
const result = this.calculateOptimalLineHeight(
|
194
|
+
config.fontSize,
|
195
|
+
containerWidth,
|
196
|
+
density,
|
197
|
+
accessibility,
|
198
|
+
language,
|
199
|
+
contentType,
|
200
|
+
enforceAccessibility,
|
201
|
+
respectUserPreferences
|
202
|
+
);
|
203
|
+
|
204
|
+
return result.lineHeight;
|
205
|
+
}
|
206
|
+
|
207
|
+
return this.optimizeLineHeight(element, config);
|
208
|
+
}
|
209
|
+
|
210
|
+
/**
|
211
|
+
* Maintain vertical rhythm across multiple elements
|
212
|
+
*/
|
213
|
+
public maintainVerticalRhythm(elements: Element[], config: { baselineGrid: number; baseSize: number }): void {
|
214
|
+
const { baselineGrid } = config;
|
215
|
+
|
216
|
+
elements.forEach(element => {
|
217
|
+
const computedStyle = getComputedStyle(element);
|
218
|
+
const fontSize = parseFloat(computedStyle.fontSize);
|
219
|
+
|
220
|
+
// Calculate line height that aligns to baseline grid
|
221
|
+
const optimalLines = Math.round(fontSize * 1.5 / baselineGrid);
|
222
|
+
const gridAlignedLineHeight = (optimalLines * baselineGrid) / fontSize;
|
223
|
+
|
224
|
+
// Apply the grid-aligned line height
|
225
|
+
const htmlElement = element as HTMLElement;
|
226
|
+
htmlElement.style.lineHeight = gridAlignedLineHeight.toString();
|
227
|
+
|
228
|
+
// Add data attribute for debugging
|
229
|
+
element.setAttribute('data-proteus-baseline-grid', baselineGrid.toString());
|
230
|
+
element.setAttribute('data-proteus-grid-lines', optimalLines.toString());
|
231
|
+
});
|
232
|
+
}
|
233
|
+
|
234
|
+
/**
|
235
|
+
* Clean up resources
|
236
|
+
*/
|
237
|
+
public destroy(): void {
|
238
|
+
if (this.resizeObserver) {
|
239
|
+
this.resizeObserver.disconnect();
|
240
|
+
this.resizeObserver = null;
|
241
|
+
}
|
242
|
+
|
243
|
+
this.elementConfigs = new WeakMap();
|
244
|
+
}
|
245
|
+
|
246
|
+
/**
|
247
|
+
* Calculate optimal line height based on multiple factors
|
248
|
+
*/
|
249
|
+
private calculateOptimalLineHeight(
|
250
|
+
fontSize: number,
|
251
|
+
containerWidth: number,
|
252
|
+
density: 'compact' | 'comfortable' | 'spacious',
|
253
|
+
accessibility: 'none' | 'AA' | 'AAA',
|
254
|
+
language: string,
|
255
|
+
contentType: string,
|
256
|
+
enforceAccessibility: boolean,
|
257
|
+
respectUserPreferences: boolean
|
258
|
+
): OptimizationResult {
|
259
|
+
const reasoning: string[] = [];
|
260
|
+
const adjustments: string[] = [];
|
261
|
+
|
262
|
+
// Validate inputs
|
263
|
+
if (!Number.isFinite(fontSize) || fontSize <= 0) {
|
264
|
+
fontSize = 16; // Safe fallback
|
265
|
+
reasoning.push('Invalid fontSize, using fallback: 16px');
|
266
|
+
}
|
267
|
+
|
268
|
+
if (!Number.isFinite(containerWidth) || containerWidth <= 0) {
|
269
|
+
containerWidth = 600; // Safe fallback
|
270
|
+
reasoning.push('Invalid containerWidth, using fallback: 600px');
|
271
|
+
}
|
272
|
+
|
273
|
+
// Start with base density ratio
|
274
|
+
let lineHeight = this.densityRatios[density];
|
275
|
+
reasoning.push(`Base ${density} density: ${lineHeight}`);
|
276
|
+
|
277
|
+
// Adjust for content type
|
278
|
+
const contentAdjustment = this.getContentTypeAdjustment(contentType);
|
279
|
+
lineHeight += contentAdjustment;
|
280
|
+
if (contentAdjustment !== 0) {
|
281
|
+
adjustments.push(`Content type (${contentType}): ${contentAdjustment > 0 ? '+' : ''}${contentAdjustment}`);
|
282
|
+
}
|
283
|
+
|
284
|
+
// Adjust for language
|
285
|
+
const langCode = language.toLowerCase().split('-')[0];
|
286
|
+
const languageAdjustment = this.languageAdjustments[langCode as keyof typeof this.languageAdjustments] || this.languageAdjustments.default;
|
287
|
+
lineHeight += languageAdjustment;
|
288
|
+
if (languageAdjustment !== 0) {
|
289
|
+
adjustments.push(`Language (${langCode}): +${languageAdjustment}`);
|
290
|
+
}
|
291
|
+
|
292
|
+
// Adjust for line length (characters per line)
|
293
|
+
const lineLength = this.estimateLineLength(fontSize, containerWidth);
|
294
|
+
const lineLengthAdjustment = this.getLineLengthAdjustment(lineLength);
|
295
|
+
lineHeight += lineLengthAdjustment;
|
296
|
+
if (lineLengthAdjustment !== 0) {
|
297
|
+
adjustments.push(`Line length (${lineLength} chars): ${lineLengthAdjustment > 0 ? '+' : ''}${lineLengthAdjustment}`);
|
298
|
+
}
|
299
|
+
|
300
|
+
// Adjust for font size
|
301
|
+
const fontSizeAdjustment = this.getFontSizeAdjustment(fontSize);
|
302
|
+
lineHeight += fontSizeAdjustment;
|
303
|
+
if (fontSizeAdjustment !== 0) {
|
304
|
+
adjustments.push(`Font size (${fontSize}px): ${fontSizeAdjustment > 0 ? '+' : ''}${fontSizeAdjustment}`);
|
305
|
+
}
|
306
|
+
|
307
|
+
// Apply user preferences
|
308
|
+
if (respectUserPreferences) {
|
309
|
+
const userAdjustment = this.getUserPreferenceAdjustment();
|
310
|
+
lineHeight *= userAdjustment;
|
311
|
+
if (userAdjustment !== 1) {
|
312
|
+
adjustments.push(`User preferences: ×${userAdjustment}`);
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
// Enforce accessibility minimums
|
317
|
+
let accessibilityCompliant = true;
|
318
|
+
if (accessibility !== 'none' && enforceAccessibility) {
|
319
|
+
const minimum = this.accessibilityMinimums[accessibility];
|
320
|
+
if (lineHeight < minimum) {
|
321
|
+
lineHeight = minimum;
|
322
|
+
accessibilityCompliant = false;
|
323
|
+
adjustments.push(`Accessibility (${accessibility}): enforced minimum ${minimum}`);
|
324
|
+
reasoning.push(`Enforced ${accessibility} minimum: ${minimum}`);
|
325
|
+
} else {
|
326
|
+
reasoning.push(`${accessibility} compliant: ${lineHeight} >= ${minimum}`);
|
327
|
+
}
|
328
|
+
}
|
329
|
+
|
330
|
+
// Round to reasonable precision
|
331
|
+
lineHeight = Math.round(lineHeight * 1000) / 1000;
|
332
|
+
|
333
|
+
return {
|
334
|
+
lineHeight,
|
335
|
+
lineHeightCSS: lineHeight.toString(),
|
336
|
+
reasoning,
|
337
|
+
accessibilityCompliant,
|
338
|
+
adjustments
|
339
|
+
};
|
340
|
+
}
|
341
|
+
|
342
|
+
/**
|
343
|
+
* Get adjustment based on content type
|
344
|
+
*/
|
345
|
+
private getContentTypeAdjustment(contentType: string): number {
|
346
|
+
const adjustments: Record<string, number> = {
|
347
|
+
body: 0,
|
348
|
+
'body-text': 0, // Alias for body
|
349
|
+
heading: -0.1, // Headings can be tighter
|
350
|
+
caption: -0.05, // Captions slightly tighter
|
351
|
+
code: 0.1 // Code needs more space
|
352
|
+
};
|
353
|
+
|
354
|
+
return adjustments[contentType] ?? 0; // Default to 0 for unknown types
|
355
|
+
}
|
356
|
+
|
357
|
+
/**
|
358
|
+
* Estimate characters per line based on font size and container width
|
359
|
+
*/
|
360
|
+
private estimateLineLength(fontSize: number, containerWidth: number): number {
|
361
|
+
// Rough estimate: average character width is about 0.6 * font size
|
362
|
+
const avgCharWidth = fontSize * 0.6;
|
363
|
+
return Math.floor(containerWidth / avgCharWidth);
|
364
|
+
}
|
365
|
+
|
366
|
+
/**
|
367
|
+
* Get adjustment based on line length (optimal is 45-75 characters)
|
368
|
+
*/
|
369
|
+
private getLineLengthAdjustment(lineLength: number): number {
|
370
|
+
if (lineLength < 30) return 0.1; // Very short lines need more space
|
371
|
+
if (lineLength < 45) return 0.05; // Short lines need slightly more space
|
372
|
+
if (lineLength <= 75) return 0; // Optimal range
|
373
|
+
if (lineLength <= 100) return 0.05; // Long lines need more space
|
374
|
+
return 0.1; // Very long lines need much more space
|
375
|
+
}
|
376
|
+
|
377
|
+
/**
|
378
|
+
* Get adjustment based on font size
|
379
|
+
*/
|
380
|
+
private getFontSizeAdjustment(fontSize: number): number {
|
381
|
+
if (fontSize < 12) return 0.1; // Very small text needs more space
|
382
|
+
if (fontSize < 14) return 0.05; // Small text needs slightly more space
|
383
|
+
if (fontSize <= 18) return 0; // Normal range
|
384
|
+
if (fontSize <= 24) return -0.05; // Large text can be tighter
|
385
|
+
return -0.1; // Very large text can be much tighter
|
386
|
+
}
|
387
|
+
|
388
|
+
/**
|
389
|
+
* Get user preference adjustment from system settings
|
390
|
+
*/
|
391
|
+
private getUserPreferenceAdjustment(): number {
|
392
|
+
// Check for user's preferred line spacing
|
393
|
+
// This could be expanded to read from CSS custom properties or localStorage
|
394
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
395
|
+
const userLineSpacing = rootStyle.getPropertyValue('--user-line-spacing');
|
396
|
+
|
397
|
+
if (userLineSpacing) {
|
398
|
+
const adjustment = parseFloat(userLineSpacing);
|
399
|
+
return isNaN(adjustment) ? 1 : Math.max(0.8, Math.min(2, adjustment));
|
400
|
+
}
|
401
|
+
|
402
|
+
return 1; // No adjustment
|
403
|
+
}
|
404
|
+
|
405
|
+
/**
|
406
|
+
* Apply line height to element
|
407
|
+
*/
|
408
|
+
private applyLineHeight(element: Element, lineHeight: string): void {
|
409
|
+
const htmlElement = element as HTMLElement;
|
410
|
+
htmlElement.style.lineHeight = lineHeight;
|
411
|
+
}
|
412
|
+
|
413
|
+
/**
|
414
|
+
* Setup ResizeObserver for responsive line height adjustments
|
415
|
+
*/
|
416
|
+
private setupResizeObserver(): void {
|
417
|
+
if (typeof ResizeObserver === 'undefined') {
|
418
|
+
console.warn('ProteusJS: ResizeObserver not supported. Responsive line height may not work correctly.');
|
419
|
+
return;
|
420
|
+
}
|
421
|
+
|
422
|
+
this.resizeObserver = new ResizeObserver((entries) => {
|
423
|
+
for (const entry of entries) {
|
424
|
+
if (this.appliedElements.has(entry.target)) {
|
425
|
+
this.updateLineHeight(entry.target);
|
426
|
+
}
|
427
|
+
}
|
428
|
+
});
|
429
|
+
}
|
430
|
+
}
|