Skip to content

Commit 8ebdc21

Browse files
committed
Updated tooltip to support the PR feedback.
1 parent 570ad20 commit 8ebdc21

File tree

9 files changed

+486
-191
lines changed

9 files changed

+486
-191
lines changed

src/components/deprecated-tool-tip/__tests__/__snapshots__/tool-tip.test.tsx.snap

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,3 @@ exports[`DeprecatedToolTip > should match a snapshot and render children 1`] = `
1515
</div>
1616
</DocumentFragment>
1717
`;
18-
19-
exports[`ToolTip > should match a snapshot and render children 1`] = `
20-
<DocumentFragment>
21-
<div
22-
class="mocked-styled-1 el-tool-tip-container"
23-
>
24-
Hover here
25-
<div
26-
class="el-tool-tip-active el-tool-tip-child"
27-
role="tooltip"
28-
>
29-
hello there
30-
</div>
31-
</div>
32-
</DocumentFragment>
33-
`;
Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,60 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`Tooltip > should match snapshot 1`] = `
4-
<DocumentFragment>
3+
exports[`Tooltip with createPortal > should not render the tooltip when hidden 1`] = `
4+
<div>
5+
<button
6+
aria-describedby="tooltip-id-test-static-id"
7+
aria-disabled="false"
8+
class="el-button-size-medium el-button"
9+
data-visible-id="tooltip-id-test-static-id"
10+
role="button"
11+
>
12+
<div
13+
class="mocked-styled-0 el-button-spinner"
14+
/>
15+
<span
16+
class="mocked-styled-1 el-button-label"
17+
>
18+
Hover me
19+
</span>
20+
</button>
21+
</div>
22+
`;
23+
24+
exports[`Tooltip with createPortal > should render the tooltip when visible 1`] = `
25+
<div>
26+
<button
27+
aria-describedby="tooltip-id-test-static-id"
28+
aria-disabled="false"
29+
class="el-button-size-medium el-button"
30+
data-visible-id="tooltip-id-test-static-id"
31+
role="button"
32+
>
33+
<div
34+
class="mocked-styled-0 el-button-spinner"
35+
/>
36+
<span
37+
class="mocked-styled-1 el-button-label"
38+
>
39+
Hover me
40+
</span>
41+
</button>
542
<div
6-
aria-describedby="test-static-id"
7-
class="mocked-styled-0 el-tooltip-container"
43+
aria-hidden="false"
44+
aria-live="assertive"
45+
class="mocked-styled-7 el-tooltip"
46+
data-position="top"
47+
id="tooltip-id-test-static-id"
48+
role="tooltip"
49+
style="max-width: 400px; position: absolute; transform: translate(0px, -4px); margin: 0px;"
850
>
9-
Test
51+
<span
52+
class="mocked-styled-8 el-tooltip-label"
53+
>
54+
Label
55+
:
56+
</span>
57+
This is a tooltip
1058
</div>
11-
</DocumentFragment>
59+
</div>
1260
`;
Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,67 @@
1-
import { render } from '@testing-library/react'
2-
import { Tooltip } from '../index'
1+
import React from 'react'
2+
import { vi } from 'vitest'
3+
import { fireEvent, render } from '@testing-library/react'
4+
import { useTooltip } from '../use-tooltip'
5+
import { Button } from '../../button'
6+
import { Tooltip } from '../tooltip'
37

4-
describe('Tooltip', () => {
5-
test('should match snapshot', () => {
6-
const { asFragment } = render(<Tooltip description="Tooltip Text">Test</Tooltip>)
7-
expect(asFragment()).toMatchSnapshot()
8+
// Mock createPortal for rendering Tooltip to the body
9+
vi.mock('react-dom', async () => {
10+
const actual = await vi.importActual<typeof import('react-dom')>('react-dom')
11+
return {
12+
...actual,
13+
createPortal: (node: React.ReactNode) => node, // Render the node directly
14+
}
15+
})
16+
17+
describe('Tooltip with createPortal', () => {
18+
it('should render the tooltip when visible', () => {
19+
const TestComponent = () => {
20+
const tooltip = useTooltip()
21+
return (
22+
<>
23+
<Button {...tooltip.getTriggerProps()}>Hover me</Button>
24+
<Tooltip
25+
{...tooltip.getTooltipProps()}
26+
label="Label"
27+
description="This is a tooltip"
28+
isVisible={true}
29+
position="top"
30+
maxWidth="400px"
31+
/>
32+
</>
33+
)
34+
}
35+
36+
const { container, getByText } = render(<TestComponent />)
37+
// Trigger visibility
38+
const button = getByText('Hover me')
39+
fireEvent.mouseEnter(button)
40+
41+
// Snapshot test with the tooltip visible
42+
expect(container).toMatchSnapshot()
43+
})
44+
45+
it('should not render the tooltip when hidden', () => {
46+
const TestComponent = () => {
47+
const tooltip = useTooltip()
48+
return (
49+
<>
50+
<Button {...tooltip.getTriggerProps()}>Hover me</Button>
51+
<Tooltip
52+
{...tooltip.getTooltipProps()}
53+
label="Label"
54+
description="This is a tooltip"
55+
isVisible={false}
56+
position="top"
57+
maxWidth="400px"
58+
/>
59+
</>
60+
)
61+
}
62+
63+
const { container } = render(<TestComponent />)
64+
// Snapshot test with the tooltip hidden
65+
expect(container).toMatchSnapshot()
866
})
967
})
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { renderHook } from '@testing-library/react-hooks'
2+
import { render, screen, fireEvent } from '@testing-library/react'
3+
import { useTooltip } from '../use-tooltip'
4+
import { Button } from '../../button'
5+
import { Tooltip } from '../tooltip'
6+
import { describe, expect, test } from 'vitest'
7+
8+
// Helper component to test hook behavior
9+
const TooltipTestComponent = () => {
10+
const tooltip = useTooltip()
11+
12+
return (
13+
<>
14+
<Button {...tooltip.getTriggerProps()}>Hover me</Button>
15+
<Tooltip {...tooltip.getTooltipProps()} description="Tooltip description" />
16+
</>
17+
)
18+
}
19+
20+
describe('useTooltip', () => {
21+
test('should return tooltip and trigger props', () => {
22+
const { result } = renderHook(() => useTooltip())
23+
24+
const triggerProps = result.current.getTriggerProps()
25+
const tooltipProps = result.current.getTooltipProps()
26+
27+
expect(triggerProps).toHaveProperty('aria-describedby')
28+
expect(triggerProps).toHaveProperty('onFocus')
29+
expect(triggerProps).toHaveProperty('onBlur')
30+
expect(triggerProps).toHaveProperty('onMouseEnter')
31+
expect(triggerProps).toHaveProperty('onMouseLeave')
32+
33+
expect(tooltipProps).toHaveProperty('id')
34+
expect(tooltipProps).toHaveProperty('role', 'tooltip')
35+
expect(tooltipProps).toHaveProperty('aria-hidden', true)
36+
})
37+
38+
test('should position the tooltip correctly', () => {
39+
render(<TooltipTestComponent />)
40+
41+
const trigger = screen.getByText('Hover me')
42+
43+
fireEvent.mouseEnter(trigger)
44+
45+
const tooltip = screen.getByText('Tooltip description')
46+
47+
const tooltipStyle = window.getComputedStyle(tooltip)
48+
expect(tooltipStyle.position).toBe('absolute')
49+
// Result for top and left can be negative as we haven't added support for the overflowing tooltip over viewport
50+
// Once support is added remove '-' from the match below
51+
expect(tooltipStyle.transform).toMatch(/translate\(-?\d+px, -?\d+px\)/)
52+
})
53+
54+
test('should clean up event listeners on unmount', () => {
55+
const { unmount } = render(<TooltipTestComponent />)
56+
57+
const removeEventListenerSpy = vi.spyOn(window, 'removeEventListener')
58+
59+
unmount()
60+
61+
expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function))
62+
removeEventListenerSpy.mockRestore()
63+
})
64+
})

src/components/tooltip/styles.ts

Lines changed: 1 addition & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
import { styled } from '@linaria/react'
22

3-
export const ElTooltipContainer = styled.div`
4-
position: relative;
5-
display: inline-block;
6-
overflow: visible;
7-
`
8-
9-
export const ElTooltipChild = styled.div`
3+
export const ElTooltip = styled.div`
104
width: max-content;
115
background: var(--fill-default-darkest, #222b33);
126
color: var(--text-white);
@@ -28,94 +22,6 @@ export const ElTooltipChild = styled.div`
2822
// To do (In Future): Tooltip Positioning to be replaced with css anchor positioning feature
2923
// Currently not supported by wider browser group
3024
// See: https://developer.mozilla.org/en-US/docs/Web/CSS/position-anchor#browser_compatibility
31-
32-
/* Top Position */
33-
&[data-position='top'] {
34-
bottom: 100%;
35-
left: 50%;
36-
transform: translateX(-50%);
37-
margin-bottom: var(--spacing-1);
38-
}
39-
40-
/* Top Start Position */
41-
&[data-position='topStart'] {
42-
bottom: 100%;
43-
left: 0;
44-
margin-bottom: var(--spacing-1);
45-
}
46-
47-
/* Top End Position */
48-
&[data-position='topEnd'] {
49-
bottom: 100%;
50-
right: 0;
51-
margin-bottom: var(--spacing-1);
52-
}
53-
54-
/* Bottom Position */
55-
&[data-position='bottom'] {
56-
top: 100%;
57-
left: 50%;
58-
transform: translateX(-50%);
59-
margin-top: var(--spacing-1);
60-
}
61-
62-
/* Bottom Start Position */
63-
&[data-position='bottomStart'] {
64-
top: 100%;
65-
left: 0;
66-
margin-top: var(--spacing-1);
67-
}
68-
69-
/* Bottom End Position */
70-
&[data-position='bottomEnd'] {
71-
top: 100%;
72-
right: 0;
73-
margin-top: var(--spacing-1);
74-
}
75-
76-
/* Right Position */
77-
&[data-position='right'] {
78-
left: 100%;
79-
top: 50%;
80-
transform: translateY(-50%);
81-
margin-left: var(--spacing-1);
82-
}
83-
84-
/* Right Start Position */
85-
&[data-position='rightStart'] {
86-
left: 100%;
87-
top: 0;
88-
margin-left: var(--spacing-1);
89-
}
90-
91-
/* Right End Position */
92-
&[data-position='rightEnd'] {
93-
left: 100%;
94-
bottom: 0;
95-
margin-left: var(--spacing-1);
96-
}
97-
98-
/* Left Position */
99-
&[data-position='left'] {
100-
right: 100%;
101-
top: 50%;
102-
transform: translateY(-50%);
103-
margin-right: var(--spacing-1);
104-
}
105-
106-
/* Left Start Position */
107-
&[data-position='leftStart'] {
108-
right: 100%;
109-
top: 0;
110-
margin-right: var(--spacing-1);
111-
}
112-
113-
/* Left End Position */
114-
&[data-position='leftEnd'] {
115-
right: 100%;
116-
bottom: 0;
117-
margin-right: var(--spacing-1);
118-
}
11925
`
12026

12127
export const ElTooltipLabel = styled.span`

src/components/tooltip/tooltip.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import * as TooltipStories from './tooltip.stories'
66

77
# Tooltip
88

9+
<Description of={TooltipStories.DisplayTooltipWithoutTrigger} />
10+
<Canvas of={TooltipStories.DisplayTooltipWithoutTrigger} />
11+
<RenderHtmlMarkup of={TooltipStories.DisplayTooltipWithoutTrigger} />
12+
913
<Controls />
1014

15+
<Description of={TooltipStories.BasicUsage} />
1116
<Canvas of={TooltipStories.BasicUsage} />

0 commit comments

Comments
 (0)