react-native-skia-responsive-text
Version:
A library providing a wrapper for the React Native Skia Text component, offering features like user-friendly text alignment, efficient multiline text management, and straightforward text truncation.
117 lines (97 loc) • 3.12 kB
text/typescript
import { SkFont } from '@shopify/react-native-skia';
import { ELLIPSIS } from '../constants';
import { TextLineData } from '../types';
export const trimLineStart = (
line: TextLineData,
font: SkFont,
width: number,
prefix = ELLIPSIS
): TextLineData => {
// If the line is too short, return it as is
if (line.width <= width) {
return line;
}
// Go from the first char and find how many chars must be sliced to
// display ellipsis at the beginning
let firstIndex = 0;
let lineWidth = font.getTextWidth(line.text) + font.getTextWidth(prefix);
while (lineWidth > width && firstIndex < line.text.length) {
lineWidth -= font.getTextWidth(line.text[firstIndex]!);
firstIndex++;
}
const text = `${prefix}${line.text.slice(firstIndex).trimStart()}`;
return {
text,
width: font.getTextWidth(text)
};
};
export const trimLineEnd = (
line: TextLineData,
font: SkFont,
width: number,
suffix = ELLIPSIS
): TextLineData => {
// If the line is too short, return it as is
if (line.width <= width) {
return line;
}
// Go from the last char and find how many chars must be sliced to
// display ellipsis at the end or clip the end of the line
let lastIndex = line.text.length - 1;
let lineWidth = font.getTextWidth(line.text) + font.getTextWidth(suffix);
while (lineWidth > width && lastIndex >= 0) {
lineWidth -= font.getTextWidth(line.text[lastIndex]!);
lastIndex--;
}
const text = `${line.text.slice(0, lastIndex + 1).trimEnd()}${suffix}`;
return {
text,
width: font.getTextWidth(text)
};
};
export const trimLineCenter = (
line: TextLineData,
font: SkFont,
width: number,
infix = ELLIPSIS
): TextLineData => {
// If the line is too short, return it as is
if (line.width <= width) {
return line;
}
// Get first half of the line in terms of width
let firstHalfWidth = 0;
let firstHalfIndex = 0;
while (firstHalfWidth < line.width / 2) {
firstHalfWidth += font.getTextWidth(line.text[firstHalfIndex]!);
firstHalfIndex++;
}
// Get second half of the line in terms of width
let secondHalfWidth = 0;
let secondHalfIndex = line.text.length - 1;
while (secondHalfWidth < line.width / 2) {
secondHalfWidth += font.getTextWidth(line.text[secondHalfIndex]!);
secondHalfIndex--;
}
// Remove chars from the end of the first half and from the start of the second half
// until the line width with infix is less than or equal to the width
let lineWidth = firstHalfWidth + secondHalfWidth + font.getTextWidth(infix);
while (lineWidth > width) {
if (firstHalfWidth > secondHalfWidth) {
const delta = font.getTextWidth(line.text[--firstHalfIndex]!);
firstHalfWidth -= delta;
lineWidth -= delta;
} else {
const delta = font.getTextWidth(line.text[++secondHalfIndex]!);
secondHalfWidth -= delta;
lineWidth -= delta;
}
}
const text = `${line.text
.slice(0, firstHalfIndex)
.trimEnd()}${infix}${line.text.slice(secondHalfIndex + 1).trimStart()}`;
return {
text,
width: font.getTextWidth(text)
};
};