Created
July 24, 2024 08:19
-
-
Save manix84/db71f9ebfb0a1de0fb4198acd323a2ec to your computer and use it in GitHub Desktop.
A React+Typescript hook for determining the correct middle of a string, and adding elipsis in the center.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| This code is licensed under the terms of the MIT license | |
| */ | |
| import { useState, useEffect, useRef, useCallback } from 'react'; | |
| const useMiddleTruncate = (text: string, separator = '...') => { | |
| const [truncatedText, setTruncatedText] = useState(text); | |
| const elementRef = useRef<HTMLDivElement | null>(null); | |
| const resizeTimeoutRef = useRef<number | null>(null); | |
| const getCharWidth = (font: string) => { | |
| const canvas = document.createElement('canvas'); | |
| const context = canvas.getContext('2d'); | |
| if (!context) return 0; | |
| context.font = font; | |
| return context.measureText('n').width; // 'M' is generally the widest character in most fonts | |
| }; | |
| const truncateText = useCallback(() => { | |
| if (!elementRef.current) return; | |
| const elementWidth = elementRef.current.offsetWidth; | |
| const style = getComputedStyle(elementRef.current); | |
| const font = `${style.fontWeight} ${style.fontSize} ${style.fontFamily}`; | |
| const charWidth = getCharWidth(font); | |
| const charsToShow = Math.floor(elementWidth / charWidth);// - separator.length | |
| console.log({ elementWidth, charWidth, charsToShow }); | |
| if (text.length <= charsToShow) { | |
| setTruncatedText(text); | |
| } else { | |
| const frontChars = Math.ceil(charsToShow / 2); | |
| const backChars = Math.floor(charsToShow / 2); | |
| setTruncatedText(text.substring(0, frontChars) + separator + text.substring(text.length - backChars)); | |
| } | |
| }, [text, separator]); | |
| useEffect(() => { | |
| const handleResize = () => { | |
| if (resizeTimeoutRef.current !== null) { | |
| clearTimeout(resizeTimeoutRef.current); | |
| } | |
| resizeTimeoutRef.current = window.setTimeout(() => { | |
| truncateText(); | |
| }, 100); // Adjust the debounce delay as necessary | |
| }; | |
| const resizeObserver = new ResizeObserver(handleResize); | |
| if (elementRef.current) { | |
| resizeObserver.observe(elementRef.current); | |
| } | |
| return () => { | |
| resizeObserver.disconnect(); | |
| if (resizeTimeoutRef.current !== null) { | |
| clearTimeout(resizeTimeoutRef.current); | |
| } | |
| }; | |
| }, [truncateText]); | |
| useEffect(() => { | |
| truncateText(); | |
| }, [text, separator, truncateText]); | |
| return { truncatedText, elementRef }; | |
| }; | |
| export default useMiddleTruncate; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment