UNPKG

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
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;