11/**
2- * Copyright IBM Corp. 2016, 2023
2+ * Copyright IBM Corp. 2016, 2025
33 *
44 * This source code is licensed under the Apache-2.0 license found in the
55 * LICENSE file in the root directory of this source tree.
88import cx from 'classnames' ;
99import React , {
1010 ForwardedRef ,
11+ forwardRef ,
1112 ReactNode ,
1213 useEffect ,
1314 useRef ,
1415 useState ,
16+ type MutableRefObject ,
17+ type Ref ,
1518} from 'react' ;
1619import PropTypes from 'prop-types' ;
1720import { usePrefix } from '../../internal/usePrefix' ;
1821import { ForwardRefReturn , ReactAttr } from '../../types/common' ;
22+ import { useMergedRefs } from '../../internal/useMergedRefs' ;
1923
20- function useIsTruncated ( ref ) {
24+ /**
25+ * Determines if the content of an element is truncated.
26+ *
27+ * Merges a forwarded ref with a local ref to check the element's dimensions.
28+ *
29+ * @template T
30+ * @param forwardedRef - A ref passed from the parent component.
31+ * @param deps - Dependencies to re-run the truncation check.
32+ * @returns An object containing the truncation state and the merged ref.
33+ */
34+ const useIsTruncated = < T extends HTMLElement > (
35+ forwardedRef ?: Ref < T > ,
36+ deps : any [ ] = [ ]
37+ ) => {
38+ const localRef = useRef < T > ( null ) ;
39+ const mergedRef = useMergedRefs ( [
40+ ...( forwardedRef ? [ forwardedRef ] : [ ] ) ,
41+ localRef ,
42+ ] ) ;
2143 const [ isTruncated , setIsTruncated ] = useState ( false ) ;
2244
2345 useEffect ( ( ) => {
24- const element = ref . current ;
25- const { offsetWidth, scrollWidth } = element ;
26- setIsTruncated ( offsetWidth < scrollWidth ) ;
27- } , [ ref , setIsTruncated ] ) ;
46+ const element = localRef . current ;
2847
29- return isTruncated ;
30- }
48+ if ( element ) {
49+ const { offsetWidth, scrollWidth } = element ;
50+
51+ setIsTruncated ( offsetWidth < scrollWidth ) ;
52+ }
53+ } , [ localRef , ...deps ] ) ;
54+
55+ return { isTruncated, ref : mergedRef } ;
56+ } ;
3157
3258export interface ListBoxMenuItemProps extends ReactAttr < HTMLLIElement > {
3359 /**
@@ -58,7 +84,7 @@ export interface ListBoxMenuItemProps extends ReactAttr<HTMLLIElement> {
5884
5985export type ListBoxMenuItemForwardedRef =
6086 | ( ForwardedRef < HTMLLIElement > & {
61- menuItemOptionRef ?: React . Ref < HTMLDivElement > ;
87+ menuItemOptionRef ?: Ref < HTMLDivElement > ;
6288 } )
6389 | null ;
6490
@@ -72,20 +98,26 @@ export type ListBoxMenuItemComponent = ForwardRefReturn<
7298 * name, alongside any classes for any corresponding states, for a generic list
7399 * box menu item.
74100 */
75- const ListBoxMenuItem = React . forwardRef < HTMLLIElement , ListBoxMenuItemProps > (
76- function ListBoxMenuItem (
77- {
78- children,
79- isActive = false ,
80- isHighlighted = false ,
81- title,
82- ...rest
83- } : ListBoxMenuItemProps ,
84- forwardedRef : ListBoxMenuItemForwardedRef
85- ) {
101+ const ListBoxMenuItem = forwardRef < HTMLLIElement , ListBoxMenuItemProps > (
102+ (
103+ { children, isActive = false , isHighlighted = false , title, ...rest } ,
104+ forwardedRef
105+ ) => {
86106 const prefix = usePrefix ( ) ;
87- const ref = useRef ( null ) ;
88- const isTruncated = useIsTruncated ( forwardedRef ?. menuItemOptionRef || ref ) ;
107+
108+ const menuItemOptionRefProp =
109+ forwardedRef && typeof forwardedRef !== 'function'
110+ ? (
111+ forwardedRef as MutableRefObject < HTMLLIElement | null > & {
112+ menuItemOptionRef ?: Ref < HTMLDivElement > ;
113+ }
114+ ) . menuItemOptionRef
115+ : undefined ;
116+
117+ const { isTruncated, ref : menuItemOptionRef } = useIsTruncated (
118+ menuItemOptionRefProp ,
119+ [ children ]
120+ ) ;
89121 const className = cx ( `${ prefix } --list-box__menu-item` , {
90122 [ `${ prefix } --list-box__menu-item--active` ] : isActive ,
91123 [ `${ prefix } --list-box__menu-item--highlighted` ] : isHighlighted ,
@@ -98,7 +130,7 @@ const ListBoxMenuItem = React.forwardRef<HTMLLIElement, ListBoxMenuItemProps>(
98130 title = { isTruncated ? title : undefined } >
99131 < div
100132 className = { `${ prefix } --list-box__menu-item__option` }
101- ref = { forwardedRef ?. menuItemOptionRef || ref } >
133+ ref = { menuItemOptionRef } >
102134 { children }
103135 </ div >
104136 </ li >
0 commit comments