83 lines
2.1 KiB
TypeScript
83 lines
2.1 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import { createPortal } from 'react-dom';
|
|
import styled from '@emotion/styled';
|
|
import { v4 as uuidV4 } from 'uuid';
|
|
|
|
import { AppTooltip } from './AppTooltip';
|
|
|
|
const StyledOverflowingText = styled.div<{ cursorPointer: boolean }>`
|
|
cursor: ${({ cursorPointer }) => (cursorPointer ? 'pointer' : 'inherit')};
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
|
|
font-weight: inherit;
|
|
overflow: hidden;
|
|
text-decoration: inherit;
|
|
text-overflow: ellipsis;
|
|
|
|
white-space: nowrap;
|
|
width: 100%;
|
|
`;
|
|
|
|
export function OverflowingTextWithTooltip({
|
|
text,
|
|
}: {
|
|
text: string | null | undefined;
|
|
}) {
|
|
const textElementId = `title-id-${uuidV4()}`;
|
|
|
|
const textRef = useRef<HTMLDivElement>(null);
|
|
|
|
const [isTitleOverflowing, setIsTitleOverflowing] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const isOverflowing =
|
|
(text?.length ?? 0) > 0 && textRef.current
|
|
? textRef.current?.scrollHeight > textRef.current?.clientHeight ||
|
|
textRef.current.scrollWidth > textRef.current.clientWidth
|
|
: false;
|
|
|
|
if (isTitleOverflowing !== isOverflowing) {
|
|
setIsTitleOverflowing(isOverflowing);
|
|
}
|
|
}, [isTitleOverflowing, text]);
|
|
|
|
function handleTooltipClick(event: React.MouseEvent<HTMLDivElement>) {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
}
|
|
|
|
function handleTooltipMouseUp(event: React.MouseEvent<HTMLDivElement>) {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<StyledOverflowingText
|
|
ref={textRef}
|
|
id={textElementId}
|
|
cursorPointer={isTitleOverflowing}
|
|
>
|
|
{text}
|
|
</StyledOverflowingText>
|
|
{isTitleOverflowing &&
|
|
createPortal(
|
|
<div onMouseUp={handleTooltipMouseUp} onClick={handleTooltipClick}>
|
|
<AppTooltip
|
|
anchorSelect={`#${textElementId}`}
|
|
content={text ?? ''}
|
|
clickable
|
|
delayHide={100}
|
|
offset={5}
|
|
noArrow
|
|
place="bottom"
|
|
positionStrategy="absolute"
|
|
/>
|
|
</div>,
|
|
document.body,
|
|
)}
|
|
</>
|
|
);
|
|
}
|