11import { Fragment , useEffect , useRef , useState } from 'react' ;
22import styles from '@patternfly/react-styles/css/components/Truncate/truncate' ;
33import { css } from '@patternfly/react-styles' ;
4- import { Tooltip , TooltipPosition } from '../Tooltip' ;
4+ import { Tooltip , TooltipPosition , TooltipProps } from '../Tooltip' ;
5+ import { getReferenceElement } from '../../helpers' ;
56import { getResizeObserver } from '../../helpers/resizeObserver' ;
67
78export enum TruncatePosition {
@@ -17,11 +18,15 @@ const truncateStyles = {
1718
1819const minWidthCharacters : number = 12 ;
1920
20- export interface TruncateProps extends React . HTMLProps < HTMLSpanElement > {
21+ export interface TruncateProps extends Omit < React . HTMLProps < HTMLSpanElement | HTMLAnchorElement > , 'ref' > {
2122 /** Class to add to outer span */
2223 className ?: string ;
2324 /** Text to truncate */
2425 content : string ;
26+ /** An HREF to turn the truncate wrapper into an anchor element. For more custom control, use the
27+ * tooltipProps with a triggerRef property passed in.
28+ */
29+ href ?: string ;
2530 /** The number of characters displayed in the second half of a middle truncation. This will be overridden by
2631 * the maxCharsDisplayed prop.
2732 */
@@ -52,24 +57,22 @@ export interface TruncateProps extends React.HTMLProps<HTMLSpanElement> {
5257 | 'left-end'
5358 | 'right-start'
5459 | 'right-end' ;
55- /** @hide The element whose parent to reference when calculating whether truncation should occur. This must be an ancestor
56- * of the ClipboardCopy, and must have a valid width value. For internal use only, do not use as it is not part of the public API
57- * and is subject to change.
58- */
59- refToGetParent ?: React . RefObject < any > ;
60+ /** Additional props to pass to the tooltip. */
61+ tooltipProps ?: Omit < TooltipProps , 'content' > ;
6062}
6163
6264const sliceTrailingContent = ( str : string , slice : number ) => [ str . slice ( 0 , str . length - slice ) , str . slice ( - slice ) ] ;
6365
6466export const Truncate : React . FunctionComponent < TruncateProps > = ( {
6567 className,
68+ href,
6669 position = 'end' ,
6770 tooltipPosition = 'top' ,
71+ tooltipProps,
6872 trailingNumChars = 7 ,
6973 maxCharsDisplayed,
7074 omissionContent = '\u2026' ,
7175 content,
72- refToGetParent,
7376 ...props
7477} : TruncateProps ) => {
7578 const [ isTruncated , setIsTruncated ] = useState ( true ) ;
@@ -78,7 +81,8 @@ export const Truncate: React.FunctionComponent<TruncateProps> = ({
7881 const [ shouldRenderByMaxChars , setShouldRenderByMaxChars ] = useState ( maxCharsDisplayed > 0 ) ;
7982
8083 const textRef = useRef < HTMLElement > ( null ) ;
81- const subParentRef = useRef < HTMLDivElement > ( null ) ;
84+ const defaultSubParentRef = useRef < any > ( null ) ;
85+ const subParentRef = tooltipProps ?. triggerRef || defaultSubParentRef ;
8286 const observer = useRef ( null ) ;
8387
8488 if ( maxCharsDisplayed <= 0 ) {
@@ -108,11 +112,14 @@ export const Truncate: React.FunctionComponent<TruncateProps> = ({
108112 if ( textRef && textRef . current && ! textElement ) {
109113 setTextElement ( textRef . current ) ;
110114 }
115+ } , [ textRef , textElement ] ) ;
111116
112- if ( ( refToGetParent ?. current || ( subParentRef ?. current && subParentRef . current . parentElement ) ) && ! parentElement ) {
113- setParentElement ( refToGetParent ?. current . parentElement || subParentRef ?. current . parentElement ) ;
117+ useEffect ( ( ) => {
118+ const refElement = getReferenceElement ( subParentRef ) ;
119+ if ( refElement ?. parentElement && ! parentElement ) {
120+ setParentElement ( refElement . parentElement ) ;
114121 }
115- } , [ textRef , subParentRef , textElement , parentElement ] ) ;
122+ } , [ subParentRef , parentElement ] ) ;
116123
117124 useEffect ( ( ) => {
118125 if ( textElement && parentElement && ! observer . current && ! shouldRenderByMaxChars ) {
@@ -217,21 +224,29 @@ export const Truncate: React.FunctionComponent<TruncateProps> = ({
217224 ) ;
218225 } ;
219226
227+ const TruncateWrapper = href ? 'a' : 'span' ;
220228 const truncateBody = (
221- < span
222- ref = { subParentRef }
229+ < TruncateWrapper
230+ ref = { ! tooltipProps ?. triggerRef ? ( subParentRef as React . MutableRefObject < any > ) : null }
231+ href = { href }
223232 className = { css ( styles . truncate , shouldRenderByMaxChars && styles . modifiers . fixed , className ) }
224- { ...( isTruncated && { tabIndex : 0 } ) }
233+ { ...( isTruncated && ! href && ! tooltipProps ?. triggerRef && { tabIndex : 0 } ) }
225234 { ...props }
226235 >
227236 { ! shouldRenderByMaxChars ? renderResizeObserverContent ( ) : renderMaxDisplayContent ( ) }
228- </ span >
237+ </ TruncateWrapper >
229238 ) ;
230239
231240 return (
232241 < >
233242 { isTruncated && (
234- < Tooltip hidden = { ! isTruncated } position = { tooltipPosition } content = { content } triggerRef = { subParentRef } />
243+ < Tooltip
244+ hidden = { ! isTruncated }
245+ position = { tooltipPosition }
246+ content = { content }
247+ triggerRef = { subParentRef }
248+ { ...tooltipProps }
249+ />
235250 ) }
236251 { truncateBody }
237252 </ >
0 commit comments