mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-11 18:33:53 +00:00
69 lines
1.6 KiB
TypeScript
69 lines
1.6 KiB
TypeScript
/**
|
|
* Copied from
|
|
* https://github.com/namhong2001/react-textfit/blob/master/index.tsx
|
|
*/
|
|
|
|
import { HTMLAttributes, PropsWithChildren, useCallback, useEffect, useRef } from 'react';
|
|
|
|
import { bsearch } from './fitText.utils';
|
|
|
|
interface FitTextProps extends HTMLAttributes<HTMLDivElement> {
|
|
mode?: 'single' | 'multi';
|
|
min?: number; // inclusive
|
|
max?: number; // inclusive
|
|
}
|
|
|
|
export function FitText({
|
|
children,
|
|
mode = 'multi',
|
|
min = 16,
|
|
max = 256,
|
|
...elementProps
|
|
}: PropsWithChildren<FitTextProps>) {
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
const isOverflown = useCallback(() => {
|
|
const el = ref.current;
|
|
if (!el) return false;
|
|
return el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;
|
|
}, []);
|
|
|
|
const setFontSize = useCallback(() => {
|
|
const el = ref.current;
|
|
if (!el) return;
|
|
|
|
const originVisibility = el.style.visibility;
|
|
|
|
el.style.visibility = 'hidden';
|
|
const fontSize = bsearch(min, max + 1, (mid) => {
|
|
el.style.fontSize = `${mid}px`;
|
|
return !isOverflown();
|
|
});
|
|
el.style.fontSize = `${fontSize}px`;
|
|
el.style.visibility = originVisibility;
|
|
}, [isOverflown, min, max]);
|
|
|
|
useEffect(() => {
|
|
const el = ref.current;
|
|
if (!el) return;
|
|
|
|
setFontSize();
|
|
const observer = new ResizeObserver(setFontSize);
|
|
observer.observe(el);
|
|
|
|
return () => observer.disconnect();
|
|
}, [children, mode, setFontSize]);
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
style={{
|
|
whiteSpace: mode === 'single' ? 'nowrap' : 'normal',
|
|
}}
|
|
{...elementProps}
|
|
>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|