-
-
Notifications
You must be signed in to change notification settings - Fork 247
/
calculateNodeHeight.ts
73 lines (58 loc) · 2.29 KB
/
calculateNodeHeight.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import forceHiddenStyles from './forceHiddenStyles';
import { SizingData } from './getSizingData';
// TODO: use labelled tuples once they are avaiable:
// export type CalculatedNodeHeights = [height: number, rowHeight: number];
// https://github.com/microsoft/TypeScript/issues/28259
export type CalculatedNodeHeights = number[];
let hiddenTextarea: HTMLTextAreaElement | null = null;
const getHeight = (node: HTMLElement, sizingData: SizingData): number => {
const height = node.scrollHeight;
if (sizingData.sizingStyle.boxSizing === 'border-box') {
// border-box: add border, since height = content + padding + border
return height + sizingData.borderSize;
}
// remove padding, since height = content
return height - sizingData.paddingSize;
};
export default function calculateNodeHeight(
sizingData: SizingData,
value: string,
minRows = 1,
maxRows = Infinity,
): CalculatedNodeHeights {
if (!hiddenTextarea) {
hiddenTextarea = document.createElement('textarea');
hiddenTextarea.setAttribute('tabindex', '-1');
hiddenTextarea.setAttribute('aria-hidden', 'true');
forceHiddenStyles(hiddenTextarea);
}
if (hiddenTextarea.parentNode === null) {
document.body.appendChild(hiddenTextarea);
}
const { paddingSize, borderSize, sizingStyle } = sizingData;
const { boxSizing } = sizingStyle;
Object.keys(sizingStyle).forEach((_key) => {
const key = _key as keyof typeof sizingStyle;
hiddenTextarea!.style[key] = sizingStyle[key] as any;
});
forceHiddenStyles(hiddenTextarea);
hiddenTextarea.value = value;
let height = getHeight(hiddenTextarea, sizingData);
// Double set and calc due to Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1795904
hiddenTextarea.value = value;
height = getHeight(hiddenTextarea, sizingData);
// measure height of a textarea with a single row
hiddenTextarea.value = 'x';
const rowHeight = hiddenTextarea.scrollHeight - paddingSize;
let minHeight = rowHeight * minRows;
if (boxSizing === 'border-box') {
minHeight = minHeight + paddingSize + borderSize;
}
height = Math.max(minHeight, height);
let maxHeight = rowHeight * maxRows;
if (boxSizing === 'border-box') {
maxHeight = maxHeight + paddingSize + borderSize;
}
height = Math.min(maxHeight, height);
return [height, rowHeight];
}