'use client';
import { useLayoutEffect, useRef, useState } from 'react';
interface Props {
text: string;
baseFontSize?: number; // 시작 폰트 크기 (기본 12px = --font-size-xs)
className?: string; // 추가 스타일 (기본 font-mono)
textAlign?: 'left' | 'right' | 'center';
maxWidth?: number;
}
export default function AutoShrinkText({
text,
baseFontSize = 12,
className = 'font-mono',
textAlign = 'left',
maxWidth: _maxWidth,
}: Props) {
const containerRef = useRef<HTMLDivElement>(null);
const [fontSize, setFontSize] = useState(baseFontSize);
useLayoutEffect(() => {
if (!containerRef.current) return;
const maxWidth = _maxWidth ?? containerRef.current.offsetWidth;
if (maxWidth <= 0) return;
// 1. 브라우저에서 실제로 적용된 폰트 패밀리를 가져옴 (GeistMonoVF 인식)
const computedStyle = window.getComputedStyle(containerRef.current);
const fontFamily = computedStyle.fontFamily;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
if (!context) return;
// 2. 폰트 크기 정밀 계산 루프
let currentSize = baseFontSize;
context.font = `${currentSize}px ${fontFamily}`;
let textWidth = context.measureText(text).width;
// 컨테이너 너비를 넘는 경우 0.1px 단위로 축소 (최소 5px까지)
if (textWidth > maxWidth) {
while (textWidth > maxWidth && currentSize > 5) {
currentSize -= 0.1;
context.font = `${currentSize}px ${fontFamily}`;
textWidth = context.measureText(text).width;
}
setFontSize(currentSize);
} else {
setFontSize(baseFontSize); // 텍스트가 짧으면 기본값 유지
}
}, [text, baseFontSize, _maxWidth]);
const justifyContent =
textAlign === 'right'
? 'flex-end'
: textAlign === 'left'
? 'flex-start'
: textAlign;
return (
<p
ref={containerRef}
className={className}
style={{
width: '100%',
maxWidth: _maxWidth,
overflow: 'hidden',
whiteSpace: 'nowrap',
display: 'flex',
alignItems: 'center',
lineHeight: 1,
justifyContent: justifyContent,
}}
>
<span
style={{
fontSize: `${fontSize}px`,
display: 'inline-block',
}}
>
{text}
</span>
</p>
);
}