|
| 1 | +'use client'; |
| 2 | + |
| 3 | +import {useCallback, useRef} from 'react'; |
| 4 | +import {useLayoutEffect, useResizeObserver} from '@react-aria/utils'; |
| 5 | + |
| 6 | +export function TitleResizer() { |
| 7 | + let titleRef = useRef<HTMLHeadingElement>(null); |
| 8 | + |
| 9 | + // Size the title to fit the available space. |
| 10 | + let updateTitleFontSize = useCallback(() => { |
| 11 | + if (titleRef.current) { |
| 12 | + let fontSize = parseInt(window.getComputedStyle(titleRef.current).fontSize, 10); |
| 13 | + |
| 14 | + // Constrain font size to 58px, or 10% of the window width, whichever is smaller. |
| 15 | + let maxFontSize = Math.min(58, Math.round(window.innerWidth * 0.1)); |
| 16 | + if (fontSize > maxFontSize) { |
| 17 | + fontSize = maxFontSize; |
| 18 | + titleRef.current.style.fontSize = maxFontSize + 'px'; |
| 19 | + } |
| 20 | + |
| 21 | + // If the font size is less than the maximum font size, |
| 22 | + // increase the font size until it overflows. |
| 23 | + while (fontSize < maxFontSize && titleRef.current.scrollWidth <= titleRef.current.clientWidth) { |
| 24 | + fontSize++; |
| 25 | + titleRef.current.style.fontSize = fontSize + 'px'; |
| 26 | + } |
| 27 | + |
| 28 | + // Reduce the font size until it doesn't overflow. |
| 29 | + while (fontSize > 10 && titleRef.current.scrollWidth > titleRef.current.clientWidth + 1) { |
| 30 | + fontSize--; |
| 31 | + titleRef.current.style.fontSize = fontSize + 'px'; |
| 32 | + } |
| 33 | + } |
| 34 | + }, []); |
| 35 | + |
| 36 | + useLayoutEffect(() => { |
| 37 | + titleRef.current = document.querySelector('h1'); |
| 38 | + updateTitleFontSize(); |
| 39 | + }, [updateTitleFontSize]); |
| 40 | + |
| 41 | + useResizeObserver({ |
| 42 | + ref: titleRef, |
| 43 | + onResize: updateTitleFontSize |
| 44 | + }); |
| 45 | + |
| 46 | + return null; |
| 47 | +} |
0 commit comments