react-truncate-inside
Version:
React component for adding an ellipsis to the middle of a line of text.
83 lines (82 loc) • 3.2 kB
JavaScript
import * as React from 'react';
import useCanvas from './useCanvas';
/**
* <b>Truncate</b> truncates text based on a given width. The component
takes in a few props, including the text to be truncated, the width of
the container, the number of characters to offset the truncated text,
and the ellipsis to be used.
*/
function Truncate(props) {
var text = props.text, _a = props.width, width = _a === void 0 ? 0 : _a, _b = props.offset, offset = _b === void 0 ? 8 : _b, _c = props.ellipsis, ellipsis = _c === void 0 ? '...' : _c;
var _d = React.useState(0), targetWidth = _d[0], setTargetWidth = _d[1];
var _e = React.useState(false), shouldTruncate = _e[0], setShouldTruncate = _e[1];
var _f = React.useState(false), truncated = _f[0], setTruncated = _f[1];
var containerRef = React.useRef(null);
var canvas = useCanvas();
var setupCanvas = React.useCallback(function () {
if (!containerRef.current)
return;
var style = window.getComputedStyle(containerRef.current);
var font = [
style['font-weight'],
style['font-style'],
style['font-size'],
style['font-family'],
].join(' ');
canvas.font = font;
}, [canvas]);
var calcTargetWidth = React.useCallback(function () {
var _a;
var targetW;
if (width) {
targetW = width;
}
else {
targetW = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width;
}
setTargetWidth(targetW);
var measureWidth = canvas.measureText(text).width;
setShouldTruncate(targetW < measureWidth);
setTruncated(true);
}, [canvas, text, width]);
React.useEffect(function () {
setupCanvas();
calcTargetWidth();
}, [calcTargetWidth, setupCanvas]);
React.useEffect(function () {
var oB = new ResizeObserver(function (entries) {
if (entries.length > 0) {
calcTargetWidth();
}
});
if (containerRef.current) {
oB.observe(containerRef.current);
}
return function () {
oB.disconnect();
};
}, [calcTargetWidth]);
var calculatedText = React.useMemo(function () {
if (!shouldTruncate)
return text;
var len = text.length;
var tail = text.slice(len - offset, len);
var head;
var end = len - offset;
var start = 0;
while (start < end - 1) {
var curr = Math.floor((end - start) / 2 + start);
head = text.slice(0, curr);
if (canvas.measureText(head + ellipsis + tail).width < targetWidth) {
start = curr;
}
else {
end = curr;
}
}
head = text.slice(0, start || 1);
return head + ellipsis + tail;
}, [canvas, ellipsis, offset, shouldTruncate, targetWidth, text]);
return (React.createElement("div", { ref: containerRef, style: { width: width || '100%', whiteSpace: 'nowrap' } }, truncated ? calculatedText : calculatedText));
}
export default Truncate;