From f0bd94364990ad2677f1ace1a3a492f71e7c899d Mon Sep 17 00:00:00 2001 From: patternfly-build Date: Fri, 10 Oct 2025 16:07:29 +0000 Subject: [PATCH 1/8] chore(release): releasing packages [ci skip] - @patternfly/react-code-editor@6.4.0-prerelease.3 - @patternfly/react-core@6.4.0-prerelease.3 - @patternfly/react-docs@7.4.0-prerelease.4 - @patternfly/react-drag-drop@6.4.0-prerelease.3 - demo-app-ts@6.0.0-prerelease.163 - @patternfly/react-table@6.4.0-prerelease.4 - @patternfly/react-templates@6.4.0-prerelease.3 --- .../src/components/Truncate/Truncate.tsx | 54 ------------------- 1 file changed, 54 deletions(-) diff --git a/packages/react-core/src/components/Truncate/Truncate.tsx b/packages/react-core/src/components/Truncate/Truncate.tsx index a4c9306330b..af71ab1cea0 100644 --- a/packages/react-core/src/components/Truncate/Truncate.tsx +++ b/packages/react-core/src/components/Truncate/Truncate.tsx @@ -2,8 +2,6 @@ import { Fragment, useEffect, useRef, useState, forwardRef, useImperativeHandle import styles from '@patternfly/react-styles/css/components/Truncate/truncate'; import { css } from '@patternfly/react-styles'; import { Tooltip, TooltipPosition, TooltipProps } from '../Tooltip'; -import { getReferenceElement } from '../../helpers'; -import { getResizeObserver } from '../../helpers/resizeObserver'; export enum TruncatePosition { start = 'start', @@ -79,70 +77,18 @@ const TruncateBase: React.FunctionComponent = ({ ...props }: TruncateProps) => { const [isTruncated, setIsTruncated] = useState(true); - const [parentElement, setParentElement] = useState(null); - const [textElement, setTextElement] = useState(null); const [shouldRenderByMaxChars, setShouldRenderByMaxChars] = useState(maxCharsDisplayed > 0); const textRef = useRef(null); useImperativeHandle(innerRef, () => textRef.current!); const defaultSubParentRef = useRef(null); const subParentRef = tooltipProps?.triggerRef || defaultSubParentRef; - const observer = useRef(null); if (maxCharsDisplayed <= 0) { // eslint-disable-next-line no-console console.warn('Truncate: the maxCharsDisplayed must be greater than 0, otherwise no content will be visible.'); } - const getActualWidth = (element: Element) => { - const computedStyle = getComputedStyle(element); - - return ( - parseFloat(computedStyle.width) - - parseFloat(computedStyle.paddingLeft) - - parseFloat(computedStyle.paddingRight) - - parseFloat(computedStyle.borderRight) - - parseFloat(computedStyle.borderLeft) - ); - }; - - const calculateTotalTextWidth = (element: Element, trailingNumChars: number, content: string) => { - const firstTextWidth = element.scrollWidth; - const firstTextLength = content.length; - return (firstTextWidth / firstTextLength) * trailingNumChars + firstTextWidth; - }; - - useEffect(() => { - if (textRef && textRef.current && !textElement) { - setTextElement(textRef.current); - } - }, [textRef, textElement]); - - useEffect(() => { - const refElement = getReferenceElement(subParentRef); - if (refElement?.parentElement && !parentElement) { - setParentElement(refElement.parentElement); - } - }, [subParentRef, parentElement]); - - useEffect(() => { - if (textElement && parentElement && !observer.current && !shouldRenderByMaxChars) { - const totalTextWidth = calculateTotalTextWidth(textElement, trailingNumChars, content); - const textWidth = position === 'middle' ? totalTextWidth : textElement.scrollWidth; - - const handleResize = () => { - const parentWidth = getActualWidth(parentElement); - setIsTruncated(textWidth >= parentWidth); - }; - - const observer = getResizeObserver(parentElement, handleResize); - - return () => { - observer(); - }; - } - }, [textElement, parentElement, trailingNumChars, content, position, shouldRenderByMaxChars]); - useEffect(() => { if (shouldRenderByMaxChars) { setIsTruncated(content.length > maxCharsDisplayed); From 2109481a20b4c1036e8eeb6d23613d10ef99d2a5 Mon Sep 17 00:00:00 2001 From: gitdallas <5322142+gitdallas@users.noreply.github.com> Date: Tue, 14 Oct 2025 10:05:20 -0500 Subject: [PATCH 2/8] check truncated before showing tooltip Signed-off-by: gitdallas <5322142+gitdallas@users.noreply.github.com> --- .../src/components/Truncate/Truncate.tsx | 65 ++++++++++++++++--- .../Truncate/__tests__/Truncate.test.tsx | 6 +- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/packages/react-core/src/components/Truncate/Truncate.tsx b/packages/react-core/src/components/Truncate/Truncate.tsx index af71ab1cea0..eec2d043032 100644 --- a/packages/react-core/src/components/Truncate/Truncate.tsx +++ b/packages/react-core/src/components/Truncate/Truncate.tsx @@ -74,10 +74,15 @@ const TruncateBase: React.FunctionComponent = ({ omissionContent = '\u2026', content, innerRef, + onMouseEnter, + onMouseLeave, + onFocus, + onBlur, ...props }: TruncateProps) => { const [isTruncated, setIsTruncated] = useState(true); const [shouldRenderByMaxChars, setShouldRenderByMaxChars] = useState(maxCharsDisplayed > 0); + const [showTooltip, setShowTooltip] = useState(false); const textRef = useRef(null); useImperativeHandle(innerRef, () => textRef.current!); @@ -93,12 +98,49 @@ const TruncateBase: React.FunctionComponent = ({ if (shouldRenderByMaxChars) { setIsTruncated(content.length > maxCharsDisplayed); } - }, [shouldRenderByMaxChars]); + }, [shouldRenderByMaxChars, content.length, maxCharsDisplayed]); useEffect(() => { setShouldRenderByMaxChars(maxCharsDisplayed > 0); }, [maxCharsDisplayed]); + // Check if content is truncated (called on hover/focus) + const checkTruncation = (): boolean => { + if (shouldRenderByMaxChars) { + return isTruncated; + } + + if (!textRef.current) { + return false; + } + + return textRef.current.scrollWidth > textRef.current.clientWidth; + }; + + const handleMouseEnter = (e: React.MouseEvent) => { + if (checkTruncation()) { + setShowTooltip(true); + } + onMouseEnter?.(e); + }; + + const handleMouseLeave = (e: React.MouseEvent) => { + setShowTooltip(false); + onMouseLeave?.(e); + }; + + const handleFocus = (e: React.FocusEvent) => { + if (checkTruncation()) { + setShowTooltip(true); + } + onFocus?.(e); + }; + + const handleBlur = (e: React.FocusEvent) => { + setShowTooltip(false); + onBlur?.(e); + }; + const lrmEntity = ; const isStartPosition = position === TruncatePosition.start; const isEndPosition = position === TruncatePosition.end; @@ -186,6 +228,10 @@ const TruncateBase: React.FunctionComponent = ({ href={href} className={css(styles.truncate, shouldRenderByMaxChars && styles.modifiers.fixed, className)} {...(isTruncated && !href && !tooltipProps?.triggerRef && { tabIndex: 0 })} + onMouseEnter={handleMouseEnter} + onMouseLeave={handleMouseLeave} + onFocus={handleFocus} + onBlur={handleBlur} {...props} > {!shouldRenderByMaxChars ? renderResizeObserverContent() : renderMaxDisplayContent()} @@ -194,15 +240,14 @@ const TruncateBase: React.FunctionComponent = ({ return ( <> - {isTruncated && ( -