fleet/frontend/components/TooltipTruncatedText/TooltipTruncatedText.tsx
jacobshandling 19fe0ff5ce
UI: Improve TooltipTruncatedText and now underlying useCheckTruncatedElement (#29232)
## For #27667 

- Have `TooltipTruncatedText` component use `useCheckTruncatedElement`
to track its current state of truncation.
- Update `useCheckTruncatedElement` to re-evaluate truncation state
based on changes to the width of
the element itself as opposed to changes to viewport width. This
facilitates truncation when the
width of the element is updated due to user interaction / change in UI
state other than window resize, e.g. checking a policy in the policy
software automations modal (see issue description for details
reproduction instructions there).

**Truncation with tooltip successful for UI state changes:**

![ezgif-27969fb4a17d3e](https://github.com/user-attachments/assets/66156bd5-7948-4e73-9c11-4a08fde44189)

Truncation with tooltip successful for viewport resizing:

![ezgif-2515f715b05436](https://github.com/user-attachments/assets/8ef70579-1e89-4a4b-9fd0-93a4776d3151)

![ezgif-24a953c65500d9](https://github.com/user-attachments/assets/fc2f302b-6f7e-463e-97d2-9978b97c5601)

- [x] Changes file added for user-visible changes in `changes/⁄
- [x] Manual QA for all new/changed functionality

---------

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
2025-05-20 15:41:53 -07:00

65 lines
2.1 KiB
TypeScript

import React, { useRef } from "react";
import { uniqueId } from "lodash";
import classnames from "classnames";
import ReactTooltip from "react-tooltip";
import { COLORS } from "styles/var/colors";
import { useCheckTruncatedElement } from "hooks/useCheckTruncatedElement";
interface ITooltipTruncatedTextCellProps {
value: React.ReactNode;
/** Tooltip to display. If this is provided then this will be rendered as the tooltip content. If
* not, the value will be displayed as the tooltip content. Default: undefined */
tooltip?: React.ReactNode;
/** If set to `true` the text inside the tooltip will break on words instead of any character.
* By default the tooltip text breaks on any character. Default: false */
tooltipBreakOnWord?: boolean;
className?: string;
}
const baseClass = "tooltip-truncated-text";
const TooltipTruncatedText = ({
value,
tooltip,
tooltipBreakOnWord = false,
className,
}: ITooltipTruncatedTextCellProps): JSX.Element => {
const classNames = classnames(baseClass, className, {
"tooltip-break-on-word": tooltipBreakOnWord,
});
// Tooltip visibility logic: Enable only when text is truncated
const ref = useRef<HTMLInputElement>(null);
const isTruncated = useCheckTruncatedElement(ref);
const tooltipId = uniqueId();
return (
<div className={classNames}>
<div className="tooltip-truncated" data-tip data-for={tooltipId}>
<div ref={ref} className={isTruncated ? "truncated" : undefined}>
{value}
</div>
</div>
<ReactTooltip
place="top"
effect="solid"
backgroundColor={COLORS["tooltip-bg"]}
id={tooltipId}
data-html
className="truncated-tooltip" // responsive widths
clickable
delayHide={200} // need delay set to hover using clickable
disable={!isTruncated}
>
<>
{tooltip ?? value}
<div className="safari-hack">&nbsp;</div>
{/* Fixes triple click selecting next element in Safari */}
</>
</ReactTooltip>
</div>
);
};
export default TooltipTruncatedText;