-
Notifications
You must be signed in to change notification settings - Fork 16
/
SeeMoreUtil.js
88 lines (77 loc) · 2.44 KB
/
SeeMoreUtil.js
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { PixelRatio } from 'react-native';
import reactNativeTextSize from 'react-native-text-size';
/**
* When difference between partialTextWidth and widthLimit is less than
* this value, we mark the truncation index.
*/
const DIFFERENCE_THRESHOLD = 10;
/**
* Finds the point where the text will be truncated, leaving enough space to show
* the "read more" link
*
* @param text {string} Text for which you need to find the truncation index
* @param numberOfLines {number} Number of lines being displayed
* @param fontSize {number} Font size
* @param fontFamily {string} Font family
* @param fontWeight {string} Font weight
* @param containerWidth {number} Width of the container in which the text will be contained
* @param seeMoreText {string} See more text
*/
async function getTruncationIndex(
text,
numberOfLines,
fontSize,
fontFamily,
fontWeight,
containerWidth,
seeMoreText,
) {
const scaledFontSize = Math.round(fontSize * PixelRatio.getFontScale());
const { width: totalTextWidth } = await reactNativeTextSize.measure({
text,
fontSize: scaledFontSize,
fontFamily,
fontWeight,
});
/**
* Max possible width of the text when it is collapsed.
* 10 is approx value of white space width per line.
*/
const widthLimit = (containerWidth - 10) * numberOfLines;
if (totalTextWidth < widthLimit) {
return undefined;
}
let index = 0;
let start = 0;
let end = text.length - 1;
while (start <= end) {
const middle = start + (end - start) / 2;
// eslint-disable-next-line no-await-in-loop
const { width: partialTextWidth } = await reactNativeTextSize.measure({
text: text.slice(0, middle),
fontSize: scaledFontSize,
fontFamily,
fontWeight,
});
if (Math.abs(widthLimit - partialTextWidth) <= DIFFERENCE_THRESHOLD) {
index = middle;
break;
} else if (partialTextWidth > widthLimit) {
end = middle - 1;
} else {
start = middle + 1;
}
}
let truncationIndex = Math.floor(index) - (seeMoreText.length + 10);
// If there is a new line character before this truncation index, this will break
// So we find the first new line character before truncationIndex and set that as the
// new truncation index
const newLineCharacterIndex = text.slice(0, truncationIndex).indexOf('\n');
if (newLineCharacterIndex > -1) {
truncationIndex = newLineCharacterIndex;
}
return truncationIndex;
}
export default {
getTruncationIndex,
};