|  | @@ -0,0 +1,101 @@
 | 
	
		
			
				|  |  | +// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
	
		
			
				|  |  | +let melm: any
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +interface TLTextMeasureStyles {
 | 
	
		
			
				|  |  | +  fontStyle?: string
 | 
	
		
			
				|  |  | +  fontVariant?: string
 | 
	
		
			
				|  |  | +  fontWeight?: number
 | 
	
		
			
				|  |  | +  fontSize: number
 | 
	
		
			
				|  |  | +  fontFamily: string
 | 
	
		
			
				|  |  | +  lineHeight: number
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function getMeasurementDiv() {
 | 
	
		
			
				|  |  | +  // A div used for measurement
 | 
	
		
			
				|  |  | +  document.getElementById('__textLabelMeasure')?.remove()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const pre = document.createElement('pre')
 | 
	
		
			
				|  |  | +  pre.id = '__textLabelMeasure'
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  Object.assign(pre.style, {
 | 
	
		
			
				|  |  | +    whiteSpace: 'pre',
 | 
	
		
			
				|  |  | +    width: 'auto',
 | 
	
		
			
				|  |  | +    borderLeft: '2px solid transparent',
 | 
	
		
			
				|  |  | +    borderRight: '1px solid transparent',
 | 
	
		
			
				|  |  | +    borderBottom: '2px solid transparent',
 | 
	
		
			
				|  |  | +    padding: '0px',
 | 
	
		
			
				|  |  | +    margin: '0px',
 | 
	
		
			
				|  |  | +    opacity: '0',
 | 
	
		
			
				|  |  | +    position: 'absolute',
 | 
	
		
			
				|  |  | +    top: '-500px',
 | 
	
		
			
				|  |  | +    left: '0px',
 | 
	
		
			
				|  |  | +    zIndex: '9999',
 | 
	
		
			
				|  |  | +    userSelect: 'none',
 | 
	
		
			
				|  |  | +    pointerEvents: 'none',
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  pre.tabIndex = -1
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  document.body.appendChild(pre)
 | 
	
		
			
				|  |  | +  return pre
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +if (typeof window !== 'undefined') {
 | 
	
		
			
				|  |  | +  melm = getMeasurementDiv()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const cache = new Map<string, [number, number]>()
 | 
	
		
			
				|  |  | +const getKey = (text: string, font: string, padding: number) => {
 | 
	
		
			
				|  |  | +  return `${text}-${font}-${padding}`
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +const hasCached = (text: string, font: string, padding: number) => {
 | 
	
		
			
				|  |  | +  const key = getKey(text, font, padding)
 | 
	
		
			
				|  |  | +  return cache.has(key)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +const getCached = (text: string, font: string, padding: number) => {
 | 
	
		
			
				|  |  | +  const key = getKey(text, font, padding)
 | 
	
		
			
				|  |  | +  return cache.get(key)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +const saveCached = (text: string, font: string, padding: number, size: [number, number]) => {
 | 
	
		
			
				|  |  | +  const key = getKey(text, font, padding)
 | 
	
		
			
				|  |  | +  cache.set(key, size)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export function getTextLabelSize(text: string, fontOrStyles: string | TLTextMeasureStyles, padding = 0) {
 | 
	
		
			
				|  |  | +  if (!text) {
 | 
	
		
			
				|  |  | +    return [16, 32]
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  let font: string
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (typeof fontOrStyles === 'string') {
 | 
	
		
			
				|  |  | +    font = fontOrStyles
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    font = `${fontOrStyles.fontStyle ?? 'normal'} ${fontOrStyles.fontVariant ?? 'normal'} ${
 | 
	
		
			
				|  |  | +      fontOrStyles.fontWeight ?? 'normal'
 | 
	
		
			
				|  |  | +    } ${fontOrStyles.fontSize}px/${fontOrStyles.fontSize * fontOrStyles.lineHeight}px ${
 | 
	
		
			
				|  |  | +      fontOrStyles.fontFamily
 | 
	
		
			
				|  |  | +    }`
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (!hasCached(text, font, padding)) {
 | 
	
		
			
				|  |  | +    if (!melm) {
 | 
	
		
			
				|  |  | +      // We're in SSR
 | 
	
		
			
				|  |  | +      return [10, 10]
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!melm.parent) document.body.appendChild(melm)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    melm.innerHTML = `${text}​`
 | 
	
		
			
				|  |  | +    melm.style.font = font
 | 
	
		
			
				|  |  | +    melm.style.padding = padding + 'px'
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // In tests, offsetWidth and offsetHeight will be 0
 | 
	
		
			
				|  |  | +    const width = melm.offsetWidth || 1
 | 
	
		
			
				|  |  | +    const height = melm.offsetHeight || 1
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    saveCached(text, font, padding, [width, height])
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return getCached(text, font, padding)!
 | 
	
		
			
				|  |  | +}
 |