mirror of https://github.com/portainer/portainer
77 lines
2.0 KiB
TypeScript
77 lines
2.0 KiB
TypeScript
import { useRef, useState, useEffect, useCallback } from 'react';
|
|
|
|
import { Button } from '@@/buttons';
|
|
|
|
// use enum so that the tailwind classes aren't interpolated
|
|
type MaxLines = 2 | 5 | 10 | 20 | 50;
|
|
const lineClampClasses: Record<MaxLines, string> = {
|
|
2: 'line-clamp-[2]',
|
|
5: 'line-clamp-[5]',
|
|
10: 'line-clamp-[10]',
|
|
20: 'line-clamp-[20]',
|
|
50: 'line-clamp-[50]',
|
|
};
|
|
|
|
interface LineBasedProps {
|
|
children: string;
|
|
maxLines?: MaxLines;
|
|
}
|
|
|
|
export function ExpandableMessageByLines({
|
|
children,
|
|
maxLines = 10,
|
|
}: LineBasedProps) {
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
const [isTruncated, setIsTruncated] = useState(false);
|
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
|
|
const checkTruncation = useCallback(() => {
|
|
const el = contentRef.current;
|
|
if (el) {
|
|
setIsTruncated(el.scrollHeight > el.clientHeight);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
checkTruncation();
|
|
|
|
// Use requestAnimationFrame for better performance
|
|
let rafId: number;
|
|
function handleResize() {
|
|
if (rafId) cancelAnimationFrame(rafId);
|
|
rafId = requestAnimationFrame(checkTruncation);
|
|
}
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
return () => {
|
|
window.removeEventListener('resize', handleResize);
|
|
if (rafId) cancelAnimationFrame(rafId);
|
|
};
|
|
}, [children, maxLines, checkTruncation, isExpanded]);
|
|
|
|
return (
|
|
<div className="flex flex-col items-start">
|
|
<div
|
|
ref={contentRef}
|
|
className={`whitespace-pre-wrap break-words overflow-hidden ${
|
|
isExpanded ? '' : lineClampClasses[maxLines]
|
|
}`}
|
|
>
|
|
{children}
|
|
</div>
|
|
{(isTruncated || isExpanded) && (
|
|
<Button
|
|
color="link"
|
|
size="xsmall"
|
|
onClick={() => setIsExpanded(!isExpanded)}
|
|
className="!ml-0 !p-0 mt-1"
|
|
data-cy="expandable-message-lines-button"
|
|
>
|
|
{isExpanded ? 'Show less' : 'Show more'}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|