Files
tom goriunovandGitHub 8c0f80b778 Migrate from Yarn to pnpm (#3323)
* migrate from yarn to pnpm

* feature-reporter: migrate from webpack to vite

* remove unnecessary deps

* bump pnpm to 10.32.1

* fix sitemap and favicon generator tools in docker

* review and workflow fixes

* fix pw test

* update screenshots

* update screenshot and add default maxDiffPixels value
2026-03-02 15:10:44 +01:00

97 lines
2.9 KiB
TypeScript

import { debounce } from 'es-toolkit';
import React from 'react';
import useFontFaceObserver from 'use-font-face-observer';
import type { ExcludeUndefined } from 'types/utils';
import type { TooltipProps } from '../../chakra/tooltip';
import { Tooltip } from '../../chakra/tooltip';
import { useDisclosure } from '../../hooks/useDisclosure';
import { BODY_TYPEFACE } from '../../theme/foundations/typography';
export interface TruncatedTextTooltipProps {
children: React.ReactNode;
label: React.ReactNode;
placement?: ExcludeUndefined<TooltipProps['positioning']>['placement'];
interactive?: boolean;
}
export const TruncatedTextTooltip = React.memo(({ children, label, placement, interactive }: TruncatedTextTooltipProps) => {
const childRef = React.useRef<HTMLElement>(null);
const [ isTruncated, setTruncated ] = React.useState(false);
const { open, onToggle, onOpen, onClose } = useDisclosure();
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<React.ReactNode>;
onClick?: () => void;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
};
const handleClick = React.useCallback(() => {
onToggle();
}, [ onToggle ]);
const modifiedChildren = React.cloneElement(
child,
{
ref: childRef,
onClick: handleClick,
onMouseEnter: onOpen,
onMouseLeave: onClose,
} as React.HTMLAttributes<HTMLElement>,
);
if (isTruncated) {
return (
<Tooltip
content={ label }
contentProps={{ maxW: { base: 'calc(100vw - 8px)', lg: '400px' } }}
positioning={{ placement }}
open={ open }
interactive={ interactive }
>
{ modifiedChildren }
</Tooltip>
);
}
return modifiedChildren;
});