uicore-ts 1.1.57 → 1.1.59
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/compiledScripts/UITextMeasurement.d.ts +48 -7
- package/compiledScripts/UITextMeasurement.js +121 -60
- package/compiledScripts/UITextMeasurement.js.map +2 -2
- package/compiledScripts/UITextView.d.ts +4 -0
- package/compiledScripts/UITextView.js +59 -7
- package/compiledScripts/UITextView.js.map +2 -2
- package/compiledScripts/UIView.d.ts +1 -0
- package/compiledScripts/UIView.js +4 -0
- package/compiledScripts/UIView.js.map +2 -2
- package/package.json +1 -1
- package/scripts/UITextMeasurement.ts +360 -75
- package/scripts/UITextView.ts +79 -31
- package/scripts/UIView.ts +5 -0
|
@@ -1,9 +1,29 @@
|
|
|
1
|
+
export interface TextMeasurementStyle {
|
|
2
|
+
font: string;
|
|
3
|
+
fontSize: number;
|
|
4
|
+
lineHeight: number;
|
|
5
|
+
whiteSpace: string;
|
|
6
|
+
paddingLeft: number;
|
|
7
|
+
paddingRight: number;
|
|
8
|
+
paddingTop: number;
|
|
9
|
+
paddingBottom: number;
|
|
10
|
+
}
|
|
1
11
|
export declare class UITextMeasurement {
|
|
2
12
|
private static canvas;
|
|
3
13
|
private static context;
|
|
4
|
-
private static
|
|
5
|
-
private static
|
|
14
|
+
private static globalStyleCache;
|
|
15
|
+
private static elementToCacheKey;
|
|
6
16
|
private static measurementElement;
|
|
17
|
+
/**
|
|
18
|
+
* Generate a cache key based only on styles that affect text measurement
|
|
19
|
+
* Ignores position, color, transform, etc.
|
|
20
|
+
*/
|
|
21
|
+
private static generateStyleCacheKey;
|
|
22
|
+
/**
|
|
23
|
+
* Extract cache key from element's classList
|
|
24
|
+
* Elements with same classes likely have same text measurement styles
|
|
25
|
+
*/
|
|
26
|
+
private static getSemanticCacheKey;
|
|
7
27
|
/**
|
|
8
28
|
* Get or create the canvas context for text measurement
|
|
9
29
|
*/
|
|
@@ -25,13 +45,14 @@ export declare class UITextMeasurement {
|
|
|
25
45
|
*/
|
|
26
46
|
private static measureWithDOM;
|
|
27
47
|
/**
|
|
28
|
-
*
|
|
48
|
+
* Get or extract styles from element (with smart global caching)
|
|
49
|
+
* Returns cached styles if available, otherwise computes once and caches globally
|
|
29
50
|
*/
|
|
30
|
-
private static
|
|
51
|
+
private static getElementStyles;
|
|
31
52
|
/**
|
|
32
|
-
*
|
|
53
|
+
* Parse line height from computed style
|
|
33
54
|
*/
|
|
34
|
-
private static
|
|
55
|
+
private static parseLineHeight;
|
|
35
56
|
/**
|
|
36
57
|
* Measure text width using Canvas API
|
|
37
58
|
*/
|
|
@@ -46,7 +67,7 @@ export declare class UITextMeasurement {
|
|
|
46
67
|
* Calculate intrinsic content size for text - SMART METHOD
|
|
47
68
|
* Automatically chooses the most efficient measurement technique
|
|
48
69
|
*/
|
|
49
|
-
static calculateTextSize(element: HTMLElement, content: string, constrainingWidth?: number, constrainingHeight?: number): {
|
|
70
|
+
static calculateTextSize(element: HTMLElement, content: string, constrainingWidth?: number, constrainingHeight?: number, providedStyles?: TextMeasurementStyle): {
|
|
50
71
|
width: number;
|
|
51
72
|
height: number;
|
|
52
73
|
};
|
|
@@ -58,8 +79,28 @@ export declare class UITextMeasurement {
|
|
|
58
79
|
* Clear all caches (call when fonts change or for cleanup)
|
|
59
80
|
*/
|
|
60
81
|
static clearCaches(): void;
|
|
82
|
+
/**
|
|
83
|
+
* Invalidate cached styles for a specific element
|
|
84
|
+
*/
|
|
85
|
+
static invalidateElement(element: HTMLElement): void;
|
|
86
|
+
/**
|
|
87
|
+
* Invalidate cache for elements with specific class
|
|
88
|
+
* Useful when you change a CSS class definition
|
|
89
|
+
*/
|
|
90
|
+
static invalidateClass(className: string): void;
|
|
91
|
+
/**
|
|
92
|
+
* Pre-warm the cache by measuring a representative element
|
|
93
|
+
* Useful at app startup to avoid first-paint delays
|
|
94
|
+
*/
|
|
95
|
+
static prewarmCache(elements: HTMLElement[]): void;
|
|
61
96
|
/**
|
|
62
97
|
* Clean up measurement element (call on app cleanup)
|
|
63
98
|
*/
|
|
64
99
|
static cleanup(): void;
|
|
65
100
|
}
|
|
101
|
+
export interface UITextViewMeasurementMethods {
|
|
102
|
+
intrinsicContentSizeEfficient(constrainingWidth?: number, constrainingHeight?: number): {
|
|
103
|
+
width: number;
|
|
104
|
+
height: number;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -22,6 +22,49 @@ __export(UITextMeasurement_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(UITextMeasurement_exports);
|
|
24
24
|
class UITextMeasurement {
|
|
25
|
+
static generateStyleCacheKey(computed) {
|
|
26
|
+
const relevantProps = [
|
|
27
|
+
computed.fontFamily,
|
|
28
|
+
computed.fontSize,
|
|
29
|
+
computed.fontWeight,
|
|
30
|
+
computed.fontStyle,
|
|
31
|
+
computed.fontVariant,
|
|
32
|
+
computed.lineHeight,
|
|
33
|
+
computed.letterSpacing,
|
|
34
|
+
computed.wordSpacing,
|
|
35
|
+
computed.textTransform,
|
|
36
|
+
computed.whiteSpace,
|
|
37
|
+
computed.wordBreak,
|
|
38
|
+
computed.wordWrap,
|
|
39
|
+
computed.paddingLeft,
|
|
40
|
+
computed.paddingRight,
|
|
41
|
+
computed.paddingTop,
|
|
42
|
+
computed.paddingBottom,
|
|
43
|
+
computed.borderLeftWidth,
|
|
44
|
+
computed.borderRightWidth,
|
|
45
|
+
computed.borderTopWidth,
|
|
46
|
+
computed.borderBottomWidth,
|
|
47
|
+
computed.boxSizing
|
|
48
|
+
];
|
|
49
|
+
return relevantProps.join("|");
|
|
50
|
+
}
|
|
51
|
+
static getSemanticCacheKey(element) {
|
|
52
|
+
const existingKey = this.elementToCacheKey.get(element);
|
|
53
|
+
if (existingKey) {
|
|
54
|
+
return existingKey;
|
|
55
|
+
}
|
|
56
|
+
const classList = Array.from(element.classList).sort().join(" ");
|
|
57
|
+
const tagName = element.tagName.toLowerCase();
|
|
58
|
+
const semanticKey = `${tagName}::${classList}`;
|
|
59
|
+
if (this.globalStyleCache.has(semanticKey)) {
|
|
60
|
+
this.elementToCacheKey.set(element, semanticKey);
|
|
61
|
+
return semanticKey;
|
|
62
|
+
}
|
|
63
|
+
const computed = window.getComputedStyle(element);
|
|
64
|
+
const styleCacheKey = this.generateStyleCacheKey(computed);
|
|
65
|
+
this.elementToCacheKey.set(element, styleCacheKey);
|
|
66
|
+
return styleCacheKey;
|
|
67
|
+
}
|
|
25
68
|
static getContext() {
|
|
26
69
|
if (!this.context) {
|
|
27
70
|
this.canvas = document.createElement("canvas");
|
|
@@ -52,17 +95,13 @@ class UITextMeasurement {
|
|
|
52
95
|
}
|
|
53
96
|
return this.measurementElement;
|
|
54
97
|
}
|
|
55
|
-
static measureWithDOM(element, content, constrainingWidth, constrainingHeight) {
|
|
98
|
+
static measureWithDOM(element, content, constrainingWidth, constrainingHeight, providedStyles) {
|
|
56
99
|
const measureEl = this.getMeasurementElement();
|
|
57
|
-
const
|
|
58
|
-
measureEl.style.font =
|
|
59
|
-
measureEl.style.lineHeight =
|
|
60
|
-
measureEl.style.whiteSpace =
|
|
61
|
-
measureEl.style.
|
|
62
|
-
measureEl.style.wordWrap = style.wordWrap;
|
|
63
|
-
measureEl.style.padding = style.padding;
|
|
64
|
-
measureEl.style.border = style.border;
|
|
65
|
-
measureEl.style.boxSizing = style.boxSizing;
|
|
100
|
+
const styles = this.getElementStyles(element, providedStyles);
|
|
101
|
+
measureEl.style.font = styles.font;
|
|
102
|
+
measureEl.style.lineHeight = styles.lineHeight + "px";
|
|
103
|
+
measureEl.style.whiteSpace = styles.whiteSpace;
|
|
104
|
+
measureEl.style.padding = `${styles.paddingTop}px ${styles.paddingRight}px ${styles.paddingBottom}px ${styles.paddingLeft}px`;
|
|
66
105
|
if (constrainingWidth) {
|
|
67
106
|
measureEl.style.width = constrainingWidth + "px";
|
|
68
107
|
measureEl.style.maxWidth = constrainingWidth + "px";
|
|
@@ -88,25 +127,37 @@ class UITextMeasurement {
|
|
|
88
127
|
};
|
|
89
128
|
return result;
|
|
90
129
|
}
|
|
91
|
-
static
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
130
|
+
static getElementStyles(element, providedStyles) {
|
|
131
|
+
if (providedStyles) {
|
|
132
|
+
return providedStyles;
|
|
133
|
+
}
|
|
134
|
+
const cacheKey = this.getSemanticCacheKey(element);
|
|
135
|
+
const cached = this.globalStyleCache.get(cacheKey);
|
|
136
|
+
if (cached) {
|
|
137
|
+
return cached;
|
|
95
138
|
}
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
139
|
+
const computed = window.getComputedStyle(element);
|
|
140
|
+
const fontSize = parseFloat(computed.fontSize);
|
|
141
|
+
const styles = {
|
|
142
|
+
font: [
|
|
143
|
+
computed.fontStyle,
|
|
144
|
+
computed.fontVariant,
|
|
145
|
+
computed.fontWeight,
|
|
146
|
+
computed.fontSize,
|
|
147
|
+
computed.fontFamily
|
|
148
|
+
].join(" "),
|
|
149
|
+
fontSize,
|
|
150
|
+
lineHeight: this.parseLineHeight(computed.lineHeight, fontSize),
|
|
151
|
+
whiteSpace: computed.whiteSpace,
|
|
152
|
+
paddingLeft: parseFloat(computed.paddingLeft) || 0,
|
|
153
|
+
paddingRight: parseFloat(computed.paddingRight) || 0,
|
|
154
|
+
paddingTop: parseFloat(computed.paddingTop) || 0,
|
|
155
|
+
paddingBottom: parseFloat(computed.paddingBottom) || 0
|
|
156
|
+
};
|
|
157
|
+
this.globalStyleCache.set(cacheKey, styles);
|
|
158
|
+
return styles;
|
|
106
159
|
}
|
|
107
|
-
static
|
|
108
|
-
const style = window.getComputedStyle(element);
|
|
109
|
-
const lineHeight = style.lineHeight;
|
|
160
|
+
static parseLineHeight(lineHeight, fontSize) {
|
|
110
161
|
if (lineHeight === "normal") {
|
|
111
162
|
return fontSize * 1.2;
|
|
112
163
|
}
|
|
@@ -179,16 +230,12 @@ class UITextMeasurement {
|
|
|
179
230
|
}
|
|
180
231
|
return lines.length > 0 ? lines : [""];
|
|
181
232
|
}
|
|
182
|
-
static calculateTextSize(element, content, constrainingWidth, constrainingHeight) {
|
|
233
|
+
static calculateTextSize(element, content, constrainingWidth, constrainingHeight, providedStyles) {
|
|
183
234
|
if (!content || content.length === 0) {
|
|
184
|
-
const
|
|
185
|
-
const paddingTop = parseFloat(style.paddingTop) || 0;
|
|
186
|
-
const paddingBottom = parseFloat(style.paddingBottom) || 0;
|
|
187
|
-
const paddingLeft = parseFloat(style.paddingLeft) || 0;
|
|
188
|
-
const paddingRight = parseFloat(style.paddingRight) || 0;
|
|
235
|
+
const styles = this.getElementStyles(element, providedStyles);
|
|
189
236
|
return {
|
|
190
|
-
width: paddingLeft + paddingRight,
|
|
191
|
-
height: paddingTop + paddingBottom
|
|
237
|
+
width: styles.paddingLeft + styles.paddingRight,
|
|
238
|
+
height: styles.paddingTop + styles.paddingBottom
|
|
192
239
|
};
|
|
193
240
|
}
|
|
194
241
|
const isPlain = this.isPlainText(content);
|
|
@@ -198,7 +245,8 @@ class UITextMeasurement {
|
|
|
198
245
|
element,
|
|
199
246
|
content,
|
|
200
247
|
constrainingWidth,
|
|
201
|
-
constrainingHeight
|
|
248
|
+
constrainingHeight,
|
|
249
|
+
providedStyles
|
|
202
250
|
);
|
|
203
251
|
}
|
|
204
252
|
if (hasSimple) {
|
|
@@ -207,44 +255,57 @@ class UITextMeasurement {
|
|
|
207
255
|
element,
|
|
208
256
|
plainText,
|
|
209
257
|
constrainingWidth,
|
|
210
|
-
constrainingHeight
|
|
258
|
+
constrainingHeight,
|
|
259
|
+
providedStyles
|
|
211
260
|
);
|
|
212
261
|
}
|
|
213
262
|
return this.measureWithDOM(
|
|
214
263
|
element,
|
|
215
264
|
content,
|
|
216
265
|
constrainingWidth,
|
|
217
|
-
constrainingHeight
|
|
266
|
+
constrainingHeight,
|
|
267
|
+
providedStyles
|
|
218
268
|
);
|
|
219
269
|
}
|
|
220
|
-
static calculatePlainTextSize(element, text, constrainingWidth, constrainingHeight) {
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
const whiteSpace = style.whiteSpace;
|
|
224
|
-
const fontSize = parseFloat(style.fontSize);
|
|
225
|
-
const lineHeight = this.getLineHeight(element, fontSize);
|
|
226
|
-
const paddingLeft = parseFloat(style.paddingLeft) || 0;
|
|
227
|
-
const paddingRight = parseFloat(style.paddingRight) || 0;
|
|
228
|
-
const paddingTop = parseFloat(style.paddingTop) || 0;
|
|
229
|
-
const paddingBottom = parseFloat(style.paddingBottom) || 0;
|
|
230
|
-
const availableWidth = constrainingWidth ? constrainingWidth - paddingLeft - paddingRight : Infinity;
|
|
270
|
+
static calculatePlainTextSize(element, text, constrainingWidth, constrainingHeight, providedStyles) {
|
|
271
|
+
const styles = this.getElementStyles(element, providedStyles);
|
|
272
|
+
const availableWidth = constrainingWidth ? constrainingWidth - styles.paddingLeft - styles.paddingRight : Infinity;
|
|
231
273
|
let width;
|
|
232
274
|
let height;
|
|
233
|
-
if (whiteSpace === "nowrap" || whiteSpace === "pre" || !constrainingWidth) {
|
|
234
|
-
width = this.measureTextWidth(text, font) + paddingLeft + paddingRight;
|
|
235
|
-
height = lineHeight + paddingTop + paddingBottom;
|
|
275
|
+
if (styles.whiteSpace === "nowrap" || styles.whiteSpace === "pre" || !constrainingWidth) {
|
|
276
|
+
width = this.measureTextWidth(text, styles.font) + styles.paddingLeft + styles.paddingRight;
|
|
277
|
+
height = styles.lineHeight + styles.paddingTop + styles.paddingBottom;
|
|
236
278
|
} else {
|
|
237
|
-
const lines = this.wrapText(text, availableWidth, font, whiteSpace);
|
|
279
|
+
const lines = this.wrapText(text, availableWidth, styles.font, styles.whiteSpace);
|
|
238
280
|
width = Math.max(
|
|
239
|
-
...lines.map((line) => this.measureTextWidth(line, font))
|
|
240
|
-
) + paddingLeft + paddingRight;
|
|
241
|
-
height = lines.length * lineHeight + paddingTop + paddingBottom;
|
|
281
|
+
...lines.map((line) => this.measureTextWidth(line, styles.font))
|
|
282
|
+
) + styles.paddingLeft + styles.paddingRight;
|
|
283
|
+
height = lines.length * styles.lineHeight + styles.paddingTop + styles.paddingBottom;
|
|
242
284
|
}
|
|
243
285
|
return { width, height };
|
|
244
286
|
}
|
|
245
287
|
static clearCaches() {
|
|
246
|
-
this.
|
|
247
|
-
this.
|
|
288
|
+
this.globalStyleCache.clear();
|
|
289
|
+
this.elementToCacheKey = /* @__PURE__ */ new WeakMap();
|
|
290
|
+
}
|
|
291
|
+
static invalidateElement(element) {
|
|
292
|
+
const cacheKey = this.elementToCacheKey.get(element);
|
|
293
|
+
if (cacheKey) {
|
|
294
|
+
this.globalStyleCache.delete(cacheKey);
|
|
295
|
+
this.elementToCacheKey.delete(element);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
static invalidateClass(className) {
|
|
299
|
+
for (const [key] of this.globalStyleCache.entries()) {
|
|
300
|
+
if (key.includes(className)) {
|
|
301
|
+
this.globalStyleCache.delete(key);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
static prewarmCache(elements) {
|
|
306
|
+
elements.forEach((el) => {
|
|
307
|
+
this.getElementStyles(el);
|
|
308
|
+
});
|
|
248
309
|
}
|
|
249
310
|
static cleanup() {
|
|
250
311
|
if (this.measurementElement && this.measurementElement.parentElement) {
|
|
@@ -258,8 +319,8 @@ class UITextMeasurement {
|
|
|
258
319
|
}
|
|
259
320
|
UITextMeasurement.canvas = null;
|
|
260
321
|
UITextMeasurement.context = null;
|
|
261
|
-
UITextMeasurement.
|
|
262
|
-
UITextMeasurement.
|
|
322
|
+
UITextMeasurement.globalStyleCache = /* @__PURE__ */ new Map();
|
|
323
|
+
UITextMeasurement.elementToCacheKey = /* @__PURE__ */ new WeakMap();
|
|
263
324
|
UITextMeasurement.measurementElement = null;
|
|
264
325
|
// Annotate the CommonJS export names for ESM import in node:
|
|
265
326
|
0 && (module.exports = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../scripts/UITextMeasurement.ts"],
|
|
4
|
-
"sourcesContent": ["// UITextMeasurement.ts - Efficient text measurement without DOM reflows\n\nexport class UITextMeasurement {\n \n private static canvas: HTMLCanvasElement | null = null;\n private static context: CanvasRenderingContext2D | null = null;\n \n // Cache for computed font strings to avoid repeated style parsing\n private static fontCache = new Map<string, string>();\n \n // Cache for line height calculations\n private static lineHeightCache = new Map<string, number>();\n \n // Temporary element for complex HTML measurements (reused to avoid allocations)\n private static measurementElement: HTMLDivElement | null = null;\n \n /**\n * Get or create the canvas context for text measurement\n */\n private static getContext(): CanvasRenderingContext2D {\n if (!this.context) {\n this.canvas = document.createElement('canvas');\n this.context = this.canvas.getContext('2d')!;\n }\n return this.context;\n }\n \n /**\n * Detect if content is plain text or complex HTML\n */\n private static isPlainText(content: string): boolean {\n // Check for HTML tags (excluding simple formatting like <b>, <i>, <span>)\n const hasComplexHTML = /<(?!\\/?(b|i|em|strong|span|br)\\b)[^>]+>/i.test(content);\n return !hasComplexHTML;\n }\n \n /**\n * Check if content has only simple inline formatting\n */\n private static hasSimpleFormatting(content: string): boolean {\n // Only <b>, <i>, <strong>, <em>, <span> with inline styles\n const simpleTagPattern = /^[^<]*(?:<\\/?(?:b|i|em|strong|span)(?:\\s+style=\"[^\"]*\")?>[^<]*)*$/i;\n return simpleTagPattern.test(content);\n }\n \n /**\n * Get or create measurement element for complex HTML\n */\n private static getMeasurementElement(): HTMLDivElement {\n if (!this.measurementElement) {\n this.measurementElement = document.createElement('div');\n this.measurementElement.style.cssText = `\n position: absolute;\n visibility: hidden;\n pointer-events: none;\n top: -9999px;\n left: -9999px;\n width: auto;\n height: auto;\n `;\n }\n return this.measurementElement;\n }\n \n /**\n * Fast measurement using DOM (but optimized to minimize reflows)\n */\n private static measureWithDOM(\n element: HTMLElement,\n content: string,\n constrainingWidth?: number,\n constrainingHeight?: number\n ): { width: number; height: number } {\n const measureEl = this.getMeasurementElement();\n const style = window.getComputedStyle(element);\n \n // Copy relevant styles\n measureEl.style.font = this.getFontString(element);\n measureEl.style.lineHeight = style.lineHeight;\n measureEl.style.whiteSpace = style.whiteSpace;\n measureEl.style.wordBreak = style.wordBreak;\n measureEl.style.wordWrap = style.wordWrap;\n measureEl.style.padding = style.padding;\n measureEl.style.border = style.border;\n measureEl.style.boxSizing = style.boxSizing;\n \n // Set constraints\n if (constrainingWidth) {\n measureEl.style.width = constrainingWidth + 'px';\n measureEl.style.maxWidth = constrainingWidth + 'px';\n } else {\n measureEl.style.width = 'auto';\n measureEl.style.maxWidth = 'none';\n }\n \n if (constrainingHeight) {\n measureEl.style.height = constrainingHeight + 'px';\n measureEl.style.maxHeight = constrainingHeight + 'px';\n } else {\n measureEl.style.height = 'auto';\n measureEl.style.maxHeight = 'none';\n }\n \n // Set content\n measureEl.innerHTML = content;\n \n // Add to DOM only if not already there\n if (!measureEl.parentElement) {\n document.body.appendChild(measureEl);\n }\n \n // Single reflow for both measurements\n const rect = measureEl.getBoundingClientRect();\n const result = {\n width: rect.width || measureEl.scrollWidth,\n height: rect.height || measureEl.scrollHeight\n };\n \n return result;\n }\n \n /**\n * Extract font properties from computed style and create font string\n */\n private static getFontString(element: HTMLElement): string {\n const cacheKey = element.className + element.id;\n \n if (this.fontCache.has(cacheKey)) {\n return this.fontCache.get(cacheKey)!;\n }\n \n const style = window.getComputedStyle(element);\n const font = [\n style.fontStyle,\n style.fontVariant,\n style.fontWeight,\n style.fontSize,\n style.fontFamily\n ].join(' ');\n \n this.fontCache.set(cacheKey, font);\n return font;\n }\n \n /**\n * Get line height in pixels\n */\n private static getLineHeight(element: HTMLElement, fontSize: number): number {\n const style = window.getComputedStyle(element);\n const lineHeight = style.lineHeight;\n \n if (lineHeight === 'normal') {\n // Browsers typically use 1.2 as default line height\n return fontSize * 1.2;\n }\n \n if (lineHeight.endsWith('px')) {\n return parseFloat(lineHeight);\n }\n \n // If it's a unitless number, multiply by font size\n const numericLineHeight = parseFloat(lineHeight);\n if (!isNaN(numericLineHeight)) {\n return fontSize * numericLineHeight;\n }\n \n return fontSize * 1.2; // fallback\n }\n \n /**\n * Measure text width using Canvas API\n */\n static measureTextWidth(text: string, font: string): number {\n const ctx = this.getContext();\n ctx.font = font;\n return ctx.measureText(text).width;\n }\n \n /**\n * Split text into lines based on width constraint\n */\n private static wrapText(\n text: string,\n maxWidth: number,\n font: string,\n whiteSpace: string\n ): string[] {\n // No wrapping needed\n if (whiteSpace === 'nowrap' || whiteSpace === 'pre') {\n return [text];\n }\n \n const ctx = this.getContext();\n ctx.font = font;\n \n const lines: string[] = [];\n const paragraphs = text.split('\\n');\n \n for (const paragraph of paragraphs) {\n if (whiteSpace === 'pre-wrap') {\n // Preserve whitespace but wrap at maxWidth\n lines.push(...this.wrapPreservingWhitespace(paragraph, maxWidth, ctx));\n } else {\n // Normal wrapping (collapse whitespace)\n lines.push(...this.wrapNormal(paragraph, maxWidth, ctx));\n }\n }\n \n return lines;\n }\n \n private static wrapNormal(\n text: string,\n maxWidth: number,\n ctx: CanvasRenderingContext2D\n ): string[] {\n const words = text.split(/\\s+/).filter(w => w.length > 0);\n const lines: string[] = [];\n let currentLine = '';\n \n for (const word of words) {\n const testLine = currentLine ? `${currentLine} ${word}` : word;\n const metrics = ctx.measureText(testLine);\n \n if (metrics.width > maxWidth && currentLine) {\n lines.push(currentLine);\n currentLine = word;\n } else {\n currentLine = testLine;\n }\n }\n \n if (currentLine) {\n lines.push(currentLine);\n }\n \n return lines.length > 0 ? lines : [''];\n }\n \n private static wrapPreservingWhitespace(\n text: string,\n maxWidth: number,\n ctx: CanvasRenderingContext2D\n ): string[] {\n const lines: string[] = [];\n let currentLine = '';\n \n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const testLine = currentLine + char;\n const metrics = ctx.measureText(testLine);\n \n if (metrics.width > maxWidth && currentLine) {\n lines.push(currentLine);\n currentLine = char;\n } else {\n currentLine = testLine;\n }\n }\n \n if (currentLine) {\n lines.push(currentLine);\n }\n \n return lines.length > 0 ? lines : [''];\n }\n \n /**\n * Calculate intrinsic content size for text - SMART METHOD\n * Automatically chooses the most efficient measurement technique\n */\n static calculateTextSize(\n element: HTMLElement,\n content: string,\n constrainingWidth?: number,\n constrainingHeight?: number\n ): { width: number; height: number } {\n // Empty content\n if (!content || content.length === 0) {\n const style = window.getComputedStyle(element);\n const paddingTop = parseFloat(style.paddingTop) || 0;\n const paddingBottom = parseFloat(style.paddingBottom) || 0;\n const paddingLeft = parseFloat(style.paddingLeft) || 0;\n const paddingRight = parseFloat(style.paddingRight) || 0;\n \n return {\n width: paddingLeft + paddingRight,\n height: paddingTop + paddingBottom\n };\n }\n \n // Check complexity of content\n const isPlain = this.isPlainText(content);\n const hasSimple = this.hasSimpleFormatting(content);\n \n // Strategy 1: Pure canvas for plain text (fastest)\n if (isPlain) {\n return this.calculatePlainTextSize(\n element,\n content,\n constrainingWidth,\n constrainingHeight\n );\n }\n \n // Strategy 2: Optimized DOM for simple formatting (fast)\n if (hasSimple) {\n // For simple formatting, we can still use canvas but need to strip tags\n const plainText = content.replace(/<[^>]+>/g, '');\n return this.calculatePlainTextSize(\n element,\n plainText,\n constrainingWidth,\n constrainingHeight\n );\n }\n \n // Strategy 3: DOM measurement for complex HTML (slower but accurate)\n return this.measureWithDOM(\n element,\n content,\n constrainingWidth,\n constrainingHeight\n );\n }\n \n /**\n * Calculate size for plain text using canvas (no HTML)\n */\n private static calculatePlainTextSize(\n element: HTMLElement,\n text: string,\n constrainingWidth?: number,\n constrainingHeight?: number\n ): { width: number; height: number } {\n const font = this.getFontString(element);\n const style = window.getComputedStyle(element);\n const whiteSpace = style.whiteSpace;\n \n // Get font size in pixels\n const fontSize = parseFloat(style.fontSize);\n const lineHeight = this.getLineHeight(element, fontSize);\n \n // Get padding\n const paddingLeft = parseFloat(style.paddingLeft) || 0;\n const paddingRight = parseFloat(style.paddingRight) || 0;\n const paddingTop = parseFloat(style.paddingTop) || 0;\n const paddingBottom = parseFloat(style.paddingBottom) || 0;\n \n // Adjust constraining width for padding\n const availableWidth = constrainingWidth\n ? constrainingWidth - paddingLeft - paddingRight\n : Infinity;\n \n // Calculate dimensions\n let width: number;\n let height: number;\n \n if (whiteSpace === 'nowrap' || whiteSpace === 'pre' || !constrainingWidth) {\n // Single line or no width constraint\n width = this.measureTextWidth(text, font) + paddingLeft + paddingRight;\n height = lineHeight + paddingTop + paddingBottom;\n } else {\n // Multi-line text\n const lines = this.wrapText(text, availableWidth, font, whiteSpace);\n \n // Find the widest line\n width = Math.max(\n ...lines.map(line => this.measureTextWidth(line, font))\n ) + paddingLeft + paddingRight;\n \n height = (lines.length * lineHeight) + paddingTop + paddingBottom;\n }\n \n return { width, height };\n }\n \n /**\n * Clear all caches (call when fonts change or for cleanup)\n */\n static clearCaches(): void {\n this.fontCache.clear();\n this.lineHeightCache.clear();\n }\n \n /**\n * Clean up measurement element (call on app cleanup)\n */\n static cleanup(): void {\n if (this.measurementElement && this.measurementElement.parentElement) {\n document.body.removeChild(this.measurementElement);\n }\n this.measurementElement = null;\n this.canvas = null;\n this.context = null;\n this.clearCaches();\n }\n}\n\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["// UITextMeasurement.ts - Efficient text measurement without DOM reflows\n\nexport interface TextMeasurementStyle {\n font: string;\n fontSize: number;\n lineHeight: number;\n whiteSpace: string;\n paddingLeft: number;\n paddingRight: number;\n paddingTop: number;\n paddingBottom: number;\n}\n\nexport class UITextMeasurement {\n private static canvas: HTMLCanvasElement | null = null;\n private static context: CanvasRenderingContext2D | null = null;\n \n // Global cache for style objects using semantic cache key\n private static globalStyleCache = new Map<string, TextMeasurementStyle>();\n \n // Per-element cache to map element -> cache key\n private static elementToCacheKey = new WeakMap<HTMLElement, string>();\n \n // Temporary element for complex HTML measurements (reused to avoid allocations)\n private static measurementElement: HTMLDivElement | null = null;\n \n /**\n * Generate a cache key based only on styles that affect text measurement\n * Ignores position, color, transform, etc.\n */\n private static generateStyleCacheKey(computed: CSSStyleDeclaration): string {\n // Only include properties that affect text layout\n const relevantProps = [\n computed.fontFamily,\n computed.fontSize,\n computed.fontWeight,\n computed.fontStyle,\n computed.fontVariant,\n computed.lineHeight,\n computed.letterSpacing,\n computed.wordSpacing,\n computed.textTransform,\n computed.whiteSpace,\n computed.wordBreak,\n computed.wordWrap,\n computed.paddingLeft,\n computed.paddingRight,\n computed.paddingTop,\n computed.paddingBottom,\n computed.borderLeftWidth,\n computed.borderRightWidth,\n computed.borderTopWidth,\n computed.borderBottomWidth,\n computed.boxSizing\n ];\n \n // Create a hash-like key from relevant properties\n return relevantProps.join('|');\n }\n \n /**\n * Extract cache key from element's classList\n * Elements with same classes likely have same text measurement styles\n */\n private static getSemanticCacheKey(element: HTMLElement): string {\n // Check if we already computed a cache key for this element\n const existingKey = this.elementToCacheKey.get(element);\n if (existingKey) {\n return existingKey;\n }\n \n // Try to use class-based caching first (fastest)\n const classList = Array.from(element.classList).sort().join(' ');\n const tagName = element.tagName.toLowerCase();\n \n // Semantic key based on tag + classes\n const semanticKey = `${tagName}::${classList}`;\n \n // Check if we have styles for this semantic key\n if (this.globalStyleCache.has(semanticKey)) {\n this.elementToCacheKey.set(element, semanticKey);\n return semanticKey;\n }\n \n // If not cached, compute and use style-based key\n const computed = window.getComputedStyle(element);\n const styleCacheKey = this.generateStyleCacheKey(computed);\n \n // Use the style-based key\n this.elementToCacheKey.set(element, styleCacheKey);\n \n return styleCacheKey;\n }\n \n /**\n * Get or create the canvas context for text measurement\n */\n private static getContext(): CanvasRenderingContext2D {\n if (!this.context) {\n this.canvas = document.createElement('canvas');\n this.context = this.canvas.getContext('2d')!;\n }\n return this.context;\n }\n \n /**\n * Detect if content is plain text or complex HTML\n */\n private static isPlainText(content: string): boolean {\n // Check for HTML tags (excluding simple formatting like <b>, <i>, <span>)\n const hasComplexHTML = /<(?!\\/?(b|i|em|strong|span|br)\\b)[^>]+>/i.test(content);\n return !hasComplexHTML;\n }\n \n /**\n * Check if content has only simple inline formatting\n */\n private static hasSimpleFormatting(content: string): boolean {\n // Only <b>, <i>, <strong>, <em>, <span> with inline styles\n const simpleTagPattern = /^[^<]*(?:<\\/?(?:b|i|em|strong|span)(?:\\s+style=\"[^\"]*\")?>[^<]*)*$/i;\n return simpleTagPattern.test(content);\n }\n \n /**\n * Get or create measurement element for complex HTML\n */\n private static getMeasurementElement(): HTMLDivElement {\n if (!this.measurementElement) {\n this.measurementElement = document.createElement('div');\n this.measurementElement.style.cssText = `\n position: absolute;\n visibility: hidden;\n pointer-events: none;\n top: -9999px;\n left: -9999px;\n width: auto;\n height: auto;\n `;\n }\n return this.measurementElement;\n }\n \n /**\n * Fast measurement using DOM (but optimized to minimize reflows)\n */\n private static measureWithDOM(\n element: HTMLElement,\n content: string,\n constrainingWidth?: number,\n constrainingHeight?: number,\n providedStyles?: TextMeasurementStyle\n ): { width: number; height: number } {\n const measureEl = this.getMeasurementElement();\n const styles = this.getElementStyles(element, providedStyles);\n \n // Copy relevant styles\n measureEl.style.font = styles.font;\n measureEl.style.lineHeight = styles.lineHeight + 'px';\n measureEl.style.whiteSpace = styles.whiteSpace;\n measureEl.style.padding = `${styles.paddingTop}px ${styles.paddingRight}px ${styles.paddingBottom}px ${styles.paddingLeft}px`;\n \n // Set constraints\n if (constrainingWidth) {\n measureEl.style.width = constrainingWidth + 'px';\n measureEl.style.maxWidth = constrainingWidth + 'px';\n } else {\n measureEl.style.width = 'auto';\n measureEl.style.maxWidth = 'none';\n }\n \n if (constrainingHeight) {\n measureEl.style.height = constrainingHeight + 'px';\n measureEl.style.maxHeight = constrainingHeight + 'px';\n } else {\n measureEl.style.height = 'auto';\n measureEl.style.maxHeight = 'none';\n }\n \n // Set content\n measureEl.innerHTML = content;\n \n // Add to DOM only if not already there\n if (!measureEl.parentElement) {\n document.body.appendChild(measureEl);\n }\n \n // Single reflow for both measurements\n const rect = measureEl.getBoundingClientRect();\n const result = {\n width: rect.width || measureEl.scrollWidth,\n height: rect.height || measureEl.scrollHeight\n };\n \n return result;\n }\n \n /**\n * Get or extract styles from element (with smart global caching)\n * Returns cached styles if available, otherwise computes once and caches globally\n */\n private static getElementStyles(element: HTMLElement, providedStyles?: TextMeasurementStyle): TextMeasurementStyle {\n // Use provided styles if available (avoids getComputedStyle entirely)\n if (providedStyles) {\n return providedStyles;\n }\n \n // Get semantic cache key\n const cacheKey = this.getSemanticCacheKey(element);\n \n // Check global cache\n const cached = this.globalStyleCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n \n // Compute once and cache globally (this is the only getComputedStyle call)\n const computed = window.getComputedStyle(element);\n const fontSize = parseFloat(computed.fontSize);\n \n const styles: TextMeasurementStyle = {\n font: [\n computed.fontStyle,\n computed.fontVariant,\n computed.fontWeight,\n computed.fontSize,\n computed.fontFamily\n ].join(' '),\n fontSize: fontSize,\n lineHeight: this.parseLineHeight(computed.lineHeight, fontSize),\n whiteSpace: computed.whiteSpace,\n paddingLeft: parseFloat(computed.paddingLeft) || 0,\n paddingRight: parseFloat(computed.paddingRight) || 0,\n paddingTop: parseFloat(computed.paddingTop) || 0,\n paddingBottom: parseFloat(computed.paddingBottom) || 0\n };\n \n this.globalStyleCache.set(cacheKey, styles);\n return styles;\n }\n \n /**\n * Parse line height from computed style\n */\n private static parseLineHeight(lineHeight: string, fontSize: number): number {\n if (lineHeight === 'normal') {\n return fontSize * 1.2;\n }\n \n if (lineHeight.endsWith('px')) {\n return parseFloat(lineHeight);\n }\n \n const numericLineHeight = parseFloat(lineHeight);\n if (!isNaN(numericLineHeight)) {\n return fontSize * numericLineHeight;\n }\n \n return fontSize * 1.2;\n }\n \n /**\n * Measure text width using Canvas API\n */\n static measureTextWidth(text: string, font: string): number {\n const ctx = this.getContext();\n ctx.font = font;\n return ctx.measureText(text).width;\n }\n \n /**\n * Split text into lines based on width constraint\n */\n private static wrapText(\n text: string,\n maxWidth: number,\n font: string,\n whiteSpace: string\n ): string[] {\n // No wrapping needed\n if (whiteSpace === 'nowrap' || whiteSpace === 'pre') {\n return [text];\n }\n \n const ctx = this.getContext();\n ctx.font = font;\n \n const lines: string[] = [];\n const paragraphs = text.split('\\n');\n \n for (const paragraph of paragraphs) {\n if (whiteSpace === 'pre-wrap') {\n // Preserve whitespace but wrap at maxWidth\n lines.push(...this.wrapPreservingWhitespace(paragraph, maxWidth, ctx));\n } else {\n // Normal wrapping (collapse whitespace)\n lines.push(...this.wrapNormal(paragraph, maxWidth, ctx));\n }\n }\n \n return lines;\n }\n \n private static wrapNormal(\n text: string,\n maxWidth: number,\n ctx: CanvasRenderingContext2D\n ): string[] {\n const words = text.split(/\\s+/).filter(w => w.length > 0);\n const lines: string[] = [];\n let currentLine = '';\n \n for (const word of words) {\n const testLine = currentLine ? `${currentLine} ${word}` : word;\n const metrics = ctx.measureText(testLine);\n \n if (metrics.width > maxWidth && currentLine) {\n lines.push(currentLine);\n currentLine = word;\n } else {\n currentLine = testLine;\n }\n }\n \n if (currentLine) {\n lines.push(currentLine);\n }\n \n return lines.length > 0 ? lines : [''];\n }\n \n private static wrapPreservingWhitespace(\n text: string,\n maxWidth: number,\n ctx: CanvasRenderingContext2D\n ): string[] {\n const lines: string[] = [];\n let currentLine = '';\n \n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const testLine = currentLine + char;\n const metrics = ctx.measureText(testLine);\n \n if (metrics.width > maxWidth && currentLine) {\n lines.push(currentLine);\n currentLine = char;\n } else {\n currentLine = testLine;\n }\n }\n \n if (currentLine) {\n lines.push(currentLine);\n }\n \n return lines.length > 0 ? lines : [''];\n }\n \n /**\n * Calculate intrinsic content size for text - SMART METHOD\n * Automatically chooses the most efficient measurement technique\n */\n static calculateTextSize(\n element: HTMLElement,\n content: string,\n constrainingWidth?: number,\n constrainingHeight?: number,\n providedStyles?: TextMeasurementStyle\n ): { width: number; height: number } {\n // Empty content\n if (!content || content.length === 0) {\n const styles = this.getElementStyles(element, providedStyles);\n return {\n width: styles.paddingLeft + styles.paddingRight,\n height: styles.paddingTop + styles.paddingBottom\n };\n }\n \n // Check complexity of content\n const isPlain = this.isPlainText(content);\n const hasSimple = this.hasSimpleFormatting(content);\n \n // Strategy 1: Pure canvas for plain text (fastest)\n if (isPlain) {\n return this.calculatePlainTextSize(\n element,\n content,\n constrainingWidth,\n constrainingHeight,\n providedStyles\n );\n }\n \n // Strategy 2: Optimized DOM for simple formatting (fast)\n if (hasSimple) {\n // For simple formatting, we can still use canvas but need to strip tags\n const plainText = content.replace(/<[^>]+>/g, '');\n return this.calculatePlainTextSize(\n element,\n plainText,\n constrainingWidth,\n constrainingHeight,\n providedStyles\n );\n }\n \n // Strategy 3: DOM measurement for complex HTML (slower but accurate)\n return this.measureWithDOM(\n element,\n content,\n constrainingWidth,\n constrainingHeight,\n providedStyles\n );\n }\n \n /**\n * Calculate size for plain text using canvas (no HTML)\n */\n private static calculatePlainTextSize(\n element: HTMLElement,\n text: string,\n constrainingWidth?: number,\n constrainingHeight?: number,\n providedStyles?: TextMeasurementStyle\n ): { width: number; height: number } {\n const styles = this.getElementStyles(element, providedStyles);\n \n // Adjust constraining width for padding\n const availableWidth = constrainingWidth\n ? constrainingWidth - styles.paddingLeft - styles.paddingRight\n : Infinity;\n \n // Calculate dimensions\n let width: number;\n let height: number;\n \n if (styles.whiteSpace === 'nowrap' || styles.whiteSpace === 'pre' || !constrainingWidth) {\n // Single line or no width constraint\n width = this.measureTextWidth(text, styles.font) + styles.paddingLeft + styles.paddingRight;\n height = styles.lineHeight + styles.paddingTop + styles.paddingBottom;\n } else {\n // Multi-line text\n const lines = this.wrapText(text, availableWidth, styles.font, styles.whiteSpace);\n \n // Find the widest line\n width = Math.max(\n ...lines.map(line => this.measureTextWidth(line, styles.font))\n ) + styles.paddingLeft + styles.paddingRight;\n \n height = (lines.length * styles.lineHeight) + styles.paddingTop + styles.paddingBottom;\n }\n \n return { width, height };\n }\n \n /**\n * Clear all caches (call when fonts change or for cleanup)\n */\n static clearCaches(): void {\n this.globalStyleCache.clear();\n this.elementToCacheKey = new WeakMap();\n }\n \n /**\n * Invalidate cached styles for a specific element\n */\n static invalidateElement(element: HTMLElement): void {\n const cacheKey = this.elementToCacheKey.get(element);\n if (cacheKey) {\n this.globalStyleCache.delete(cacheKey);\n this.elementToCacheKey.delete(element);\n }\n }\n \n /**\n * Invalidate cache for elements with specific class\n * Useful when you change a CSS class definition\n */\n static invalidateClass(className: string): void {\n // Clear all cache keys that contain this class\n for (const [key] of this.globalStyleCache.entries()) {\n if (key.includes(className)) {\n this.globalStyleCache.delete(key);\n }\n }\n }\n \n /**\n * Pre-warm the cache by measuring a representative element\n * Useful at app startup to avoid first-paint delays\n */\n static prewarmCache(elements: HTMLElement[]): void {\n elements.forEach(el => {\n this.getElementStyles(el);\n });\n }\n \n /**\n * Clean up measurement element (call on app cleanup)\n */\n static cleanup(): void {\n if (this.measurementElement && this.measurementElement.parentElement) {\n document.body.removeChild(this.measurementElement);\n }\n this.measurementElement = null;\n this.canvas = null;\n this.context = null;\n this.clearCaches();\n }\n}\n\n// Extension methods to add to UITextView\nexport interface UITextViewMeasurementMethods {\n intrinsicContentSizeEfficient(\n constrainingWidth?: number,\n constrainingHeight?: number\n ): { width: number; height: number };\n}\n\n// ==================== INTEGRATION CODE ====================\n// Add these methods to UITextView class:\n\n/*\n // In UITextView class:\n \n // Add this property to track content complexity and cached styles\n private _useFastMeasurement: boolean | undefined;\n private _cachedMeasurementStyles: TextMeasurementStyle | undefined;\n \n // Call this when styles change (fontSize, padding, etc.)\n private _invalidateMeasurementStyles(): void {\n this._cachedMeasurementStyles = undefined;\n UITextMeasurement.invalidateElement(this.viewHTMLElement);\n this._intrinsicSizesCache = {};\n }\n \n // Extract styles ONCE and cache them (avoids getComputedStyle)\n private _getMeasurementStyles(): TextMeasurementStyle {\n if (this._cachedMeasurementStyles) {\n return this._cachedMeasurementStyles;\n }\n \n // Only call getComputedStyle once and cache the result\n const computed = window.getComputedStyle(this.viewHTMLElement);\n const fontSize = parseFloat(computed.fontSize);\n \n this._cachedMeasurementStyles = {\n font: [\n computed.fontStyle,\n computed.fontVariant,\n computed.fontWeight,\n computed.fontSize,\n computed.fontFamily\n ].join(' '),\n fontSize: fontSize,\n lineHeight: this._parseLineHeight(computed.lineHeight, fontSize),\n whiteSpace: computed.whiteSpace,\n paddingLeft: parseFloat(computed.paddingLeft) || 0,\n paddingRight: parseFloat(computed.paddingRight) || 0,\n paddingTop: parseFloat(computed.paddingTop) || 0,\n paddingBottom: parseFloat(computed.paddingBottom) || 0\n };\n \n return this._cachedMeasurementStyles;\n }\n \n private _parseLineHeight(lineHeight: string, fontSize: number): number {\n if (lineHeight === 'normal') {\n return fontSize * 1.2;\n }\n if (lineHeight.endsWith('px')) {\n return parseFloat(lineHeight);\n }\n const numericLineHeight = parseFloat(lineHeight);\n if (!isNaN(numericLineHeight)) {\n return fontSize * numericLineHeight;\n }\n return fontSize * 1.2;\n }\n \n // Override the intrinsic size method\n override intrinsicContentSizeWithConstraints(\n constrainingHeight: number = 0,\n constrainingWidth: number = 0\n ): UIRectangle {\n const cacheKey = \"h_\" + constrainingHeight + \"__w_\" + constrainingWidth;\n const cachedResult = this._intrinsicSizesCache[cacheKey];\n if (cachedResult) {\n return cachedResult;\n }\n \n // Determine measurement strategy\n const shouldUseFastPath = this._useFastMeasurement ?? this._shouldUseFastMeasurement();\n \n let result: UIRectangle;\n \n if (shouldUseFastPath) {\n // Fast path: canvas-based measurement with pre-extracted styles\n const styles = this._getMeasurementStyles();\n const size = UITextMeasurement.calculateTextSize(\n this.viewHTMLElement,\n this.text || this.innerHTML,\n constrainingWidth || undefined,\n constrainingHeight || undefined,\n styles // Pass pre-computed styles to avoid getComputedStyle!\n );\n result = new UIRectangle(0, 0, size.height, size.width);\n } else {\n // Fallback: original DOM-based measurement for complex content\n result = super.intrinsicContentSizeWithConstraints(constrainingHeight, constrainingWidth);\n }\n \n this._intrinsicSizesCache[cacheKey] = result.copy();\n return result;\n }\n \n // Helper to determine if we can use fast measurement\n private _shouldUseFastMeasurement(): boolean {\n const content = this.text || this.innerHTML;\n \n // If using dynamic innerHTML with parameters, use DOM measurement\n if (this._innerHTMLKey || this._localizedTextObject) {\n return false;\n }\n \n // Check for notification badges\n if (this.notificationAmount > 0) {\n return false; // Has span with colored text\n }\n \n // Check content complexity\n const hasComplexHTML = /<(?!\\/?(b|i|em|strong|span|br)\\b)[^>]+>/i.test(content);\n \n return !hasComplexHTML;\n }\n \n // Optional: Allow manual override for specific instances\n setUseFastMeasurement(useFast: boolean): void {\n this._useFastMeasurement = useFast;\n this._intrinsicSizesCache = {};\n }\n \n // Optional: Force re-evaluation of measurement strategy\n invalidateMeasurementStrategy(): void {\n this._useFastMeasurement = undefined;\n this._invalidateMeasurementStyles();\n }\n \n // Update fontSize setter to invalidate cached styles\n override set fontSize(fontSize: number) {\n this.style.fontSize = \"\" + fontSize + \"pt\";\n this._intrinsicHeightCache = new UIObject() as any;\n this._intrinsicWidthCache = new UIObject() as any;\n this._invalidateMeasurementStyles(); // Invalidate when font changes\n }\n \n // Update the text setter to invalidate measurement strategy\n override set text(text: string) {\n this._text = text;\n \n var notificationText = \"\";\n \n if (this.notificationAmount) {\n notificationText = \"<span style=\\\"color: \" + UITextView.notificationTextColor.stringValue + \";\\\">\" +\n (\" (\" + this.notificationAmount + \")\").bold() + \"</span>\";\n }\n \n if (this.viewHTMLElement.innerHTML != this.textPrefix + text + this.textSuffix + notificationText) {\n this.viewHTMLElement.innerHTML = this.textPrefix + FIRST(text, \"\") + this.textSuffix + notificationText;\n }\n \n if (this.changesOften) {\n this._intrinsicHeightCache = new UIObject() as any;\n this._intrinsicWidthCache = new UIObject() as any;\n }\n \n // Invalidate measurement strategy when text changes significantly\n this._useFastMeasurement = undefined;\n this._intrinsicSizesCache = {};\n \n this.setNeedsLayout();\n }\n */\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -41,6 +41,7 @@ export declare class UITextView extends UIView {
|
|
|
41
41
|
static _pxToPt: number;
|
|
42
42
|
_text?: string;
|
|
43
43
|
private _useFastMeasurement;
|
|
44
|
+
private _cachedMeasurementStyles;
|
|
44
45
|
constructor(elementID?: string, textViewType?: string | ValueOf<typeof UITextView.type>, viewHTMLElement?: null);
|
|
45
46
|
static _determinePXAndPTRatios(): void;
|
|
46
47
|
static type: {
|
|
@@ -87,6 +88,9 @@ export declare class UITextView extends UIView {
|
|
|
87
88
|
layoutSubviews(): void;
|
|
88
89
|
intrinsicContentHeight(constrainingWidth?: number): any;
|
|
89
90
|
intrinsicContentWidth(constrainingHeight?: number): any;
|
|
91
|
+
private _invalidateMeasurementStyles;
|
|
92
|
+
private _getMeasurementStyles;
|
|
93
|
+
private _parseLineHeight;
|
|
90
94
|
intrinsicContentSizeWithConstraints(constrainingHeight?: number, constrainingWidth?: number): UIRectangle;
|
|
91
95
|
private _shouldUseFastMeasurement;
|
|
92
96
|
setUseFastMeasurement(useFast: boolean): void;
|
|
@@ -89,6 +89,7 @@ const _UITextView = class extends import_UIView.UIView {
|
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
91
|
this.style.whiteSpace = "pre-wrap";
|
|
92
|
+
this.invalidateMeasurementStrategy();
|
|
92
93
|
}
|
|
93
94
|
get notificationAmount() {
|
|
94
95
|
return this._notificationAmount;
|
|
@@ -122,26 +123,33 @@ const _UITextView = class extends import_UIView.UIView {
|
|
|
122
123
|
}
|
|
123
124
|
this._useFastMeasurement = void 0;
|
|
124
125
|
this._intrinsicSizesCache = {};
|
|
126
|
+
this.invalidateMeasurementStrategy();
|
|
127
|
+
this._invalidateMeasurementStyles();
|
|
125
128
|
this.setNeedsLayout();
|
|
126
129
|
}
|
|
127
130
|
set innerHTML(innerHTML) {
|
|
128
131
|
this.text = innerHTML;
|
|
132
|
+
this.invalidateMeasurementStrategy();
|
|
129
133
|
}
|
|
130
134
|
get innerHTML() {
|
|
131
135
|
return this.viewHTMLElement.innerHTML;
|
|
132
136
|
}
|
|
133
137
|
setText(key, defaultString, parameters) {
|
|
134
138
|
this.setInnerHTML(key, defaultString, parameters);
|
|
139
|
+
this.invalidateMeasurementStrategy();
|
|
135
140
|
}
|
|
136
141
|
get fontSize() {
|
|
137
|
-
const style = window.getComputedStyle(this.viewHTMLElement, null).fontSize;
|
|
142
|
+
const style = this.style.fontSize || window.getComputedStyle(this.viewHTMLElement, null).fontSize;
|
|
138
143
|
const result = parseFloat(style) * _UITextView._pxToPt;
|
|
139
144
|
return result;
|
|
140
145
|
}
|
|
141
146
|
set fontSize(fontSize) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
if (fontSize != this.fontSize) {
|
|
148
|
+
this.style.fontSize = "" + fontSize + "pt";
|
|
149
|
+
this._intrinsicHeightCache = new import_UIObject.UIObject();
|
|
150
|
+
this._intrinsicWidthCache = new import_UIObject.UIObject();
|
|
151
|
+
this._invalidateMeasurementStyles();
|
|
152
|
+
}
|
|
145
153
|
}
|
|
146
154
|
useAutomaticFontSize(minFontSize = import_UIObject.nil, maxFontSize = import_UIObject.nil) {
|
|
147
155
|
this._automaticFontSizeSelection = import_UIObject.YES;
|
|
@@ -217,6 +225,48 @@ const _UITextView = class extends import_UIView.UIView {
|
|
|
217
225
|
}
|
|
218
226
|
return result;
|
|
219
227
|
}
|
|
228
|
+
_invalidateMeasurementStyles() {
|
|
229
|
+
this._cachedMeasurementStyles = void 0;
|
|
230
|
+
import_UITextMeasurement.UITextMeasurement.invalidateElement(this.viewHTMLElement);
|
|
231
|
+
this._intrinsicSizesCache = {};
|
|
232
|
+
}
|
|
233
|
+
_getMeasurementStyles() {
|
|
234
|
+
if (this._cachedMeasurementStyles) {
|
|
235
|
+
return this._cachedMeasurementStyles;
|
|
236
|
+
}
|
|
237
|
+
const computed = window.getComputedStyle(this.viewHTMLElement);
|
|
238
|
+
const fontSize = parseFloat(computed.fontSize);
|
|
239
|
+
this._cachedMeasurementStyles = {
|
|
240
|
+
font: [
|
|
241
|
+
computed.fontStyle,
|
|
242
|
+
computed.fontVariant,
|
|
243
|
+
computed.fontWeight,
|
|
244
|
+
computed.fontSize,
|
|
245
|
+
computed.fontFamily
|
|
246
|
+
].join(" "),
|
|
247
|
+
fontSize,
|
|
248
|
+
lineHeight: this._parseLineHeight(computed.lineHeight, fontSize),
|
|
249
|
+
whiteSpace: computed.whiteSpace,
|
|
250
|
+
paddingLeft: parseFloat(computed.paddingLeft) || 0,
|
|
251
|
+
paddingRight: parseFloat(computed.paddingRight) || 0,
|
|
252
|
+
paddingTop: parseFloat(computed.paddingTop) || 0,
|
|
253
|
+
paddingBottom: parseFloat(computed.paddingBottom) || 0
|
|
254
|
+
};
|
|
255
|
+
return this._cachedMeasurementStyles;
|
|
256
|
+
}
|
|
257
|
+
_parseLineHeight(lineHeight, fontSize) {
|
|
258
|
+
if (lineHeight === "normal") {
|
|
259
|
+
return fontSize * 1.2;
|
|
260
|
+
}
|
|
261
|
+
if (lineHeight.endsWith("px")) {
|
|
262
|
+
return parseFloat(lineHeight);
|
|
263
|
+
}
|
|
264
|
+
const numericLineHeight = parseFloat(lineHeight);
|
|
265
|
+
if (!isNaN(numericLineHeight)) {
|
|
266
|
+
return fontSize * numericLineHeight;
|
|
267
|
+
}
|
|
268
|
+
return fontSize * 1.2;
|
|
269
|
+
}
|
|
220
270
|
intrinsicContentSizeWithConstraints(constrainingHeight = 0, constrainingWidth = 0) {
|
|
221
271
|
var _a;
|
|
222
272
|
const cacheKey = "h_" + constrainingHeight + "__w_" + constrainingWidth;
|
|
@@ -227,11 +277,13 @@ const _UITextView = class extends import_UIView.UIView {
|
|
|
227
277
|
const shouldUseFastPath = (_a = this._useFastMeasurement) != null ? _a : this._shouldUseFastMeasurement();
|
|
228
278
|
let result;
|
|
229
279
|
if (shouldUseFastPath) {
|
|
280
|
+
const styles = this._getMeasurementStyles();
|
|
230
281
|
const size = import_UITextMeasurement.UITextMeasurement.calculateTextSize(
|
|
231
282
|
this.viewHTMLElement,
|
|
232
283
|
this.text || this.innerHTML,
|
|
233
284
|
constrainingWidth || void 0,
|
|
234
|
-
constrainingHeight || void 0
|
|
285
|
+
constrainingHeight || void 0,
|
|
286
|
+
styles
|
|
235
287
|
);
|
|
236
288
|
result = new import_UIRectangle.UIRectangle(0, 0, size.height, size.width);
|
|
237
289
|
} else {
|
|
@@ -242,7 +294,7 @@ const _UITextView = class extends import_UIView.UIView {
|
|
|
242
294
|
}
|
|
243
295
|
_shouldUseFastMeasurement() {
|
|
244
296
|
const content = this.text || this.innerHTML;
|
|
245
|
-
if (
|
|
297
|
+
if (this._innerHTMLKey || this._localizedTextObject) {
|
|
246
298
|
return false;
|
|
247
299
|
}
|
|
248
300
|
if (this.notificationAmount > 0) {
|
|
@@ -257,7 +309,7 @@ const _UITextView = class extends import_UIView.UIView {
|
|
|
257
309
|
}
|
|
258
310
|
invalidateMeasurementStrategy() {
|
|
259
311
|
this._useFastMeasurement = void 0;
|
|
260
|
-
this.
|
|
312
|
+
this._invalidateMeasurementStyles();
|
|
261
313
|
}
|
|
262
314
|
intrinsicContentSize() {
|
|
263
315
|
const result = this.intrinsicContentSizeWithConstraints(import_UIObject.nil, import_UIObject.nil);
|