import { Tooltip } from '@chakra-ui/react'; import debounce from 'lodash/debounce'; import React from 'react'; import useFontFaceObserver from 'use-font-face-observer'; import { BODY_TYPEFACE } from 'theme/foundations/typography'; interface Props { children: React.ReactNode; label: string; } const TruncatedTextTooltip = ({ children, label }: Props) => { const childRef = React.useRef(null); const [ isTruncated, setTruncated ] = React.useState(false); const isFontFaceLoaded = useFontFaceObserver([ { family: BODY_TYPEFACE }, ]); const updatedTruncateState = React.useCallback(() => { if (childRef.current) { const scrollWidth = childRef.current.scrollWidth; const clientWidth = childRef.current.clientWidth; if (scrollWidth > clientWidth) { setTruncated(true); } else { setTruncated(false); } } }, []); // FIXME: that should be useLayoutEffect, but it keeps complaining about SSR // let's keep it as it is until the first issue React.useEffect(() => { updatedTruncateState(); }, [ updatedTruncateState, isFontFaceLoaded ]); // we want to do recalculation when isFontFaceLoaded flag is changed // but we don't want to create more resize event listeners // that's why there are separate useEffect hooks React.useEffect(() => { const handleResize = debounce(updatedTruncateState, 1000); window.addEventListener('resize', handleResize); return function cleanup() { window.removeEventListener('resize', handleResize); }; }, [ updatedTruncateState ]); // as for now it supports only one child // and it is not cleared how to manage case with two or more children const child = React.Children.only(children) as React.ReactElement & { ref?: React.Ref; }; const modifiedChildren = React.cloneElement( child, { ref: childRef }, ); if (isTruncated) { return { modifiedChildren }; } return modifiedChildren; }; export default React.memo(TruncatedTextTooltip);