1- import React , { useEffect , useRef , CSSProperties } from 'react'
1+ import React , { useEffect , useRef , CSSProperties , useLayoutEffect } from 'react'
22
33export interface AdjustLabelFitProps {
44 /**
@@ -82,6 +82,8 @@ export const AdjustLabelFit: React.FC<AdjustLabelFitProps> = ({
8282} ) => {
8383 const labelRef = useRef < HTMLSpanElement > ( null )
8484 const containerRef = useRef < HTMLDivElement > ( null )
85+ const prevLabelRef = useRef < string > ( label )
86+
8587 // If label is longer than 140 characters, cut it off
8688 if ( label . length > 140 ) {
8789 label = label . slice ( 0 , 137 ) + '...'
@@ -106,6 +108,21 @@ export const AdjustLabelFit: React.FC<AdjustLabelFitProps> = ({
106108 ...( fontSizeValue ? { fontSize : fontSizeValue } : { } ) ,
107109 }
108110
111+ const resetLabelStyles = ( ) => {
112+ if ( labelRef . current ) {
113+ labelRef . current . style . letterSpacing = '0px'
114+ labelRef . current . style . fontVariationSettings = ''
115+ labelRef . current . textContent = label
116+ labelRef . current . style . wordBreak = 'normal'
117+ labelRef . current . style . whiteSpace = 'nowrap'
118+
119+ // Remove any child spans if they were added in previous calculations
120+ while ( labelRef . current . firstChild ) {
121+ labelRef . current . removeChild ( labelRef . current . firstChild )
122+ }
123+ }
124+ }
125+
109126 const adjustTextToFit = ( ) => {
110127 const labelElement = labelRef . current
111128 const containerElement = containerRef . current
@@ -114,7 +131,8 @@ export const AdjustLabelFit: React.FC<AdjustLabelFitProps> = ({
114131
115132 const DEFAULT_WIDTH = 100
116133 const DEFAULT_OPTICAL_SIZE = 10
117- labelElement . style . letterSpacing = '0px'
134+
135+ resetLabelStyles ( )
118136
119137 // Apply the new width setting
120138 labelElement . style . fontVariationSettings = `'opsz' ${ DEFAULT_OPTICAL_SIZE } , 'wdth' ${ DEFAULT_WIDTH } `
@@ -135,9 +153,7 @@ export const AdjustLabelFit: React.FC<AdjustLabelFitProps> = ({
135153 // Force reflow to ensure measurements are accurate
136154 void labelElement . offsetWidth
137155
138- // Measure the container and text widths
139156 const containerWidth = containerElement . clientWidth
140-
141157 // Remeasure after font size adjustment
142158 void labelElement . offsetWidth
143159 const newTextWidth = labelElement . getBoundingClientRect ( ) . width
@@ -200,7 +216,18 @@ export const AdjustLabelFit: React.FC<AdjustLabelFitProps> = ({
200216 }
201217 }
202218
219+ // Synchronous layout calculation before paint
220+ useLayoutEffect ( ( ) => {
221+ // Check if label has changed
222+ if ( prevLabelRef . current !== label ) {
223+ prevLabelRef . current = label
224+ resetLabelStyles ( )
225+ adjustTextToFit ( )
226+ }
227+ } , [ label ] )
228+
203229 useEffect ( ( ) => {
230+ // Initial adjustment
204231 const adjustmentTimer = requestAnimationFrame ( ( ) => {
205232 adjustTextToFit ( )
206233 } )
@@ -210,27 +237,31 @@ export const AdjustLabelFit: React.FC<AdjustLabelFitProps> = ({
210237 const handleResize = ( ) => {
211238 cancelAnimationFrame ( resizeTimer )
212239 resizeTimer = requestAnimationFrame ( ( ) => {
213- // Reset all styles first before recalculating
214- if ( labelRef . current ) {
215- labelRef . current . style . letterSpacing = '0px'
216- labelRef . current . style . fontVariationSettings = ''
217- labelRef . current . textContent = label
218- // Reset the word break and white space properties
219- labelRef . current . style . wordBreak = 'normal'
220- labelRef . current . style . whiteSpace = 'nowrap'
221- }
240+ resetLabelStyles ( )
222241 adjustTextToFit ( )
223242 } )
224243 }
225244
245+ // Properties change
246+ const handlePropsChange = ( ) => {
247+ resetLabelStyles ( )
248+ adjustTextToFit ( )
249+ }
250+
226251 // Adjust on window resize
227252 window . addEventListener ( 'resize' , handleResize )
253+
254+ // Run adjustment when width or font settings change
255+ if ( width || fontFamily || fontSize || minFontWidth || maxFontWidth || minLetterSpacing ) {
256+ handlePropsChange ( )
257+ }
258+
228259 return ( ) => {
229260 window . removeEventListener ( 'resize' , handleResize )
230261 cancelAnimationFrame ( adjustmentTimer )
231- cancelAnimationFrame ( resizeTimer )
262+ if ( resizeTimer ) cancelAnimationFrame ( resizeTimer )
232263 }
233- } , [ label , width , fontFamily , fontSize , minFontWidth , maxFontWidth , minLetterSpacing ] )
264+ } , [ width , fontFamily , fontSize , minFontWidth , maxFontWidth , minLetterSpacing ] )
234265
235266 return (
236267 < div ref = { containerRef } className = { `adjust-label-fit ${ className } ` } style = { finalContainerStyle } >
0 commit comments