Skip to content

Commit a7f42ce

Browse files
authored
fix(eds-core-react): πŸ› Update Tooltip component to use mergeRefs (#4130)
* fix(eds-core-react): πŸ› Update Tooltip component to use mergeRefs This fixes the warning related to accessing element.ref directly, which is no longer supported in React 19. * Add test to cover ref issue * chore: trigger CI rebuild after main branch migration * test: Use explicit ID in Tooltip snapshot test for consistency * Try to remove id to make snapshot deterministic * Fix prettier * resolve eslint errors in tooltip
1 parent 3270720 commit a7f42ce

File tree

3 files changed

+46
-12
lines changed

3 files changed

+46
-12
lines changed

β€Žpackages/eds-core-react/src/components/Tooltip/Tooltip.test.tsxβ€Ž

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/* eslint-disable no-undef */
22
import { fireEvent, render, screen, act } from '@testing-library/react'
33
import { axe } from 'jest-axe'
4+
import '@testing-library/jest-dom'
45
import styled from 'styled-components'
56
import { Tooltip, Button } from '../../'
7+
import { createRef } from 'react'
68

79
const StyledTooltip = styled(Tooltip)`
810
background: red;
@@ -30,6 +32,9 @@ describe('Tooltip', () => {
3032
const content = screen.getByText('Test')
3133
fireEvent.mouseEnter(content)
3234
const tooltip = await screen.findByRole('tooltip')
35+
36+
// Remove the auto-generated ID to make snapshot deterministic
37+
tooltip.removeAttribute('id')
3338
expect(tooltip).toMatchSnapshot()
3439
})
3540
it('Should pass a11y test', async () => {
@@ -76,7 +81,7 @@ describe('Tooltip', () => {
7681
await act(() => new Promise((r) => setTimeout(r, openDelay)))
7782

7883
const tooltip = await screen.findByRole('tooltip')
79-
expect(tooltip).toHaveStyleRule('background', 'red')
84+
expect(tooltip).toHaveStyle('background: red')
8085
})
8186
it('is visible when content is being hovered', async () => {
8287
render(
@@ -174,4 +179,28 @@ describe('Tooltip', () => {
174179

175180
expect(handler).toBeCalled()
176181
})
182+
it('should render correctly when the wrapped component has a ref', async () => {
183+
const buttonRef = createRef<HTMLButtonElement>()
184+
render(
185+
<Tooltip title="Tooltip" enterDelay={0}>
186+
<Button ref={buttonRef}>Test</Button>
187+
</Tooltip>,
188+
)
189+
190+
const button = screen.getByText('Test')
191+
192+
fireEvent.focus(button)
193+
194+
expect(await screen.findByRole('tooltip')).toBeInTheDocument()
195+
})
196+
it('should forward refs to the wrapped component', () => {
197+
const ref = createRef()
198+
render(
199+
<Tooltip title="Tooltip">
200+
<Button ref={ref}>Test</Button>
201+
</Tooltip>,
202+
)
203+
204+
expect(ref.current).toBeInstanceOf(HTMLButtonElement)
205+
})
177206
})

β€Žpackages/eds-core-react/src/components/Tooltip/Tooltip.tsxβ€Ž

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
useMemo,
99
useEffect,
1010
ReactNode,
11+
ReactElement,
1112
} from 'react'
1213
import { createPortal } from 'react-dom'
1314
import styled from 'styled-components'
@@ -136,9 +137,9 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
136137
],
137138
whileElementsMounted: autoUpdate,
138139
})
139-
const anchorRef = useMemo(
140-
() => mergeRefs<HTMLElement>(refs.setReference, children?.ref),
141-
[refs.setReference, children?.ref],
140+
const mergedAnchorRef = useMemo(
141+
() => mergeRefs<HTMLElement>(refs.setReference),
142+
[refs.setReference],
142143
)
143144
const tooltipRef = useMemo(
144145
() => mergeRefs<HTMLDivElement>(refs.setFloating, ref),
@@ -188,12 +189,17 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
188189
}
189190
})
190191

191-
const updatedChildren = cloneElement(children, {
192-
...getReferenceProps({
193-
...children.props,
194-
ref: anchorRef,
195-
}),
196-
})
192+
const updatedChildren = cloneElement(
193+
children as ReactElement<any>, // eslint-disable-line @typescript-eslint/no-explicit-any
194+
{
195+
...getReferenceProps(children.props),
196+
ref: mergeRefs(
197+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
198+
(children as ReactElement<any>).props.ref,
199+
mergedAnchorRef,
200+
),
201+
},
202+
)
197203

198204
useEffect(() => {
199205
if (!elements.floating) return
@@ -228,14 +234,14 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
228234

229235
return (
230236
<>
237+
{updatedChildren}
231238
{shouldOpen &&
232239
open &&
233240
!disabled &&
234241
createPortal(
235242
TooltipEl,
236243
portalContainer ?? rootElement ?? document.body,
237244
)}
238-
{updatedChildren}
239245
</>
240246
)
241247
},

β€Žpackages/eds-core-react/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snapβ€Ž

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ exports[`Tooltip Matches snapshot 1`] = `
5353
<div
5454
class="c0 eds-tooltip "
5555
data-floating-ui-focusable=""
56-
id="Β«r0Β»"
5756
popover="manual"
5857
role="tooltip"
5958
style="position: absolute; top: 14px; left: 8px;"

0 commit comments

Comments
Β (0)