Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 19x 19x | import { useEffect } from "react"; import { useOnSmallScreen } from "./useOnSmallScreen"; interface UseDynamicFontSizeProps { element: HTMLHeadingElement | null; maxFontSize: number; minFontSize: number; maxHeight: number; lineNum?: number; } function measureText( pText: string, pFontSize: number, width: number, maxHeight: number, lineNum: number ) { let lDiv: HTMLDivElement | null = document.createElement("div"); document.body.appendChild(lDiv); lDiv.style.fontSize = `${pFontSize}px`; lDiv.style.position = "absolute"; lDiv.style.left = "-1000"; lDiv.style.top = "-1000"; lDiv.style.maxWidth = `${width}px`; lDiv.style.maxHeight = `${maxHeight}px`; lDiv.style.webkitLineClamp = `${lineNum}`; lDiv.style.textOverflow = "ellipsis"; lDiv.style.overflow = "hidden"; lDiv.style.webkitBoxOrient = "vertical"; lDiv.style.display = "-webkit-box"; lDiv.style.lineHeight = "1"; lDiv.textContent = pText; const lResult = { width: lDiv.scrollWidth, height: lDiv.scrollHeight, }; document.body.removeChild(lDiv); lDiv = null; return lResult; } export function fitText( el: HTMLHeadingElement, maxFontSize: number, minFontSize: number, maxHeight: number, lineNum: number ): void { const text = el.textContent; Iif (!text) return; const computedStyles = getComputedStyle(el); let fsize = parseInt(computedStyles.fontSize); fsize = Math.max(fsize, minFontSize); const { width } = el.getBoundingClientRect(); const measured = measureText(text, fsize, width, maxHeight, lineNum); const letsBeTrue = true; if (measured.width > width || measured.height > maxHeight) { while (letsBeTrue) { fsize = parseInt(computedStyles.fontSize); const m = measureText(text, fsize, width, maxHeight, lineNum); if ((m.width > width && fsize > minFontSize) || m.height > maxHeight) { el.style.fontSize = `${--fsize}px`; } else { break; } } } else { while (letsBeTrue) { fsize = parseInt(computedStyles.fontSize); const m = measureText(text, fsize, width, maxHeight, lineNum); if (m.width < width - 4 && fsize < maxFontSize) { el.style.fontSize = `${++fsize}px`; } else { break; } } } } export function useDynamicFontSize({ element, maxFontSize, minFontSize, maxHeight, lineNum = 1, }: UseDynamicFontSizeProps): void { const isSmallScreen = useOnSmallScreen(); useEffect(() => { Iif (isSmallScreen) { Iif (!element) return; element.style.fontSize = `${minFontSize}px`; return; } const handleResize = () => { Iif (element) { fitText(element, maxFontSize, minFontSize, maxHeight, lineNum); } }; window.addEventListener("resize", handleResize); handleResize(); return () => { window.removeEventListener("resize", handleResize); Iif (!element) return; element.style.fontSize = ""; }; }, [ element, maxFontSize, element?.textContent, minFontSize, maxHeight, lineNum, isSmallScreen, ]); } |