From 19fe0ff5ce3147ada4d6668d4cd84706877a3533 Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Tue, 20 May 2025 15:41:53 -0700 Subject: [PATCH] UI: Improve `TooltipTruncatedText` and now underlying `useCheckTruncatedElement` (#29232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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 --- changes/27667-fix-TooltipTruncatedText | 1 + .../TooltipTruncatedText.tsx | 22 ++++++---------- .../TooltipTruncatedText/_styles.scss | 2 -- frontend/hooks/useCheckTruncatedElement.ts | 26 +++++++++++++------ 4 files changed, 27 insertions(+), 24 deletions(-) create mode 100644 changes/27667-fix-TooltipTruncatedText diff --git a/changes/27667-fix-TooltipTruncatedText b/changes/27667-fix-TooltipTruncatedText new file mode 100644 index 0000000000..b3d4073674 --- /dev/null +++ b/changes/27667-fix-TooltipTruncatedText @@ -0,0 +1 @@ +- Improve effectiveness of app-wide text-truncation-into-tooltip functionality. diff --git a/frontend/components/TooltipTruncatedText/TooltipTruncatedText.tsx b/frontend/components/TooltipTruncatedText/TooltipTruncatedText.tsx index 306c77ec35..90c6ea59e8 100644 --- a/frontend/components/TooltipTruncatedText/TooltipTruncatedText.tsx +++ b/frontend/components/TooltipTruncatedText/TooltipTruncatedText.tsx @@ -1,9 +1,10 @@ -import React, { useState, useRef, useLayoutEffect } from "react"; +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; @@ -30,22 +31,15 @@ const TooltipTruncatedText = ({ // Tooltip visibility logic: Enable only when text is truncated const ref = useRef(null); - const [tooltipDisabled, setTooltipDisabled] = useState(true); - - useLayoutEffect(() => { - if (ref?.current !== null) { - const scrollWidth = ref.current.scrollWidth; - const offsetWidth = ref.current.offsetWidth; - setTooltipDisabled(scrollWidth <= offsetWidth); - } - }, [ref]); - // End + const isTruncated = useCheckTruncatedElement(ref); const tooltipId = uniqueId(); return ( -
+
- {value} +
+ {value} +
<> {tooltip ?? value} diff --git a/frontend/components/TooltipTruncatedText/_styles.scss b/frontend/components/TooltipTruncatedText/_styles.scss index eb0af333f9..1748ea01d0 100644 --- a/frontend/components/TooltipTruncatedText/_styles.scss +++ b/frontend/components/TooltipTruncatedText/_styles.scss @@ -11,8 +11,6 @@ } .truncated { - display: inline-block; - max-width: 99%; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; diff --git a/frontend/hooks/useCheckTruncatedElement.ts b/frontend/hooks/useCheckTruncatedElement.ts index 3e8bdc195f..2a3cb5f756 100644 --- a/frontend/hooks/useCheckTruncatedElement.ts +++ b/frontend/hooks/useCheckTruncatedElement.ts @@ -9,17 +9,27 @@ export const useCheckTruncatedElement = ( ) => { const [isTruncated, setIsTruncated] = useState(false); + const updateIsTruncated = (element: HTMLElement) => { + const { scrollWidth, clientWidth } = element; + setIsTruncated(scrollWidth > clientWidth); + }; + useLayoutEffect(() => { + const resizeObserver = new ResizeObserver((entries) => { + entries.forEach((entry) => { + updateIsTruncated(entry.target as HTMLElement); + }); + }); const element = ref.current; - function updateIsTruncated() { - if (element) { - const { scrollWidth, clientWidth } = element; - setIsTruncated(scrollWidth > clientWidth); - } + if (element) { + updateIsTruncated(element); + resizeObserver.observe(ref.current as HTMLElement); } - window.addEventListener("resize", updateIsTruncated); - updateIsTruncated(); - return () => window.removeEventListener("resize", updateIsTruncated); + return () => { + if (element) { + resizeObserver.unobserve(element); + } + }; }, [ref]); return isTruncated;