-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Create new tooltip component (#3152)
- Loading branch information
1 parent
8e7daaa
commit 6cc0e88
Showing
6 changed files
with
343 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { render, screen } from '@testing-library/react' | ||
import userEvent from '@testing-library/user-event' | ||
import ResizeObserver from 'resize-observer-polyfill' | ||
|
||
import { Tooltip } from './Tooltip' | ||
|
||
global.ResizeObserver = ResizeObserver | ||
|
||
describe('Tooltip', () => { | ||
it('renders Tooltip correctly', () => { | ||
render( | ||
<Tooltip> | ||
<Tooltip.Root> | ||
<Tooltip.Trigger> | ||
<button>Hover me</button> | ||
</Tooltip.Trigger> | ||
<Tooltip.Portal> | ||
<Tooltip.Content>Tooltip Content</Tooltip.Content> | ||
</Tooltip.Portal> | ||
</Tooltip.Root> | ||
</Tooltip> | ||
) | ||
|
||
const triggerElement = screen.getByText('Hover me') | ||
expect(triggerElement).toBeInTheDocument() | ||
}) | ||
|
||
it('displays the Tooltip Content on hover', async () => { | ||
render( | ||
<Tooltip> | ||
<Tooltip.Root> | ||
<Tooltip.Trigger> | ||
<button>Hover me</button> | ||
</Tooltip.Trigger> | ||
<Tooltip.Portal> | ||
<Tooltip.Content data-state="instant-open"> | ||
Tooltip Content | ||
</Tooltip.Content> | ||
</Tooltip.Portal> | ||
</Tooltip.Root> | ||
</Tooltip> | ||
) | ||
|
||
const triggerElement = await screen.findByText('Hover me') | ||
await userEvent.hover(triggerElement) | ||
|
||
const contentElement = await screen.findByText('Tooltip Content', { | ||
selector: 'div', | ||
}) | ||
expect(contentElement).toBeInTheDocument() | ||
}) | ||
|
||
it('hides the Tooltip Content when not hovered', async () => { | ||
render( | ||
<Tooltip> | ||
<Tooltip.Root> | ||
<Tooltip.Trigger> | ||
<button>Hover me</button> | ||
</Tooltip.Trigger> | ||
<Tooltip.Portal> | ||
<Tooltip.Content>Tooltip Content</Tooltip.Content> | ||
</Tooltip.Portal> | ||
</Tooltip.Root> | ||
</Tooltip> | ||
) | ||
|
||
const contentElement = screen.queryByText('Tooltip Content') | ||
expect(contentElement).not.toBeInTheDocument() | ||
}) | ||
|
||
it('applies custom className to Tooltip Content', async () => { | ||
render( | ||
<Tooltip> | ||
<Tooltip.Root> | ||
<Tooltip.Trigger> | ||
<button>Hover me</button> | ||
</Tooltip.Trigger> | ||
<Tooltip.Portal> | ||
<Tooltip.Content className="border-black" data-state="instant-open"> | ||
Tooltip Content | ||
</Tooltip.Content> | ||
</Tooltip.Portal> | ||
</Tooltip.Root> | ||
</Tooltip> | ||
) | ||
|
||
const triggerElement = await screen.findByText('Hover me') | ||
await userEvent.hover(triggerElement) | ||
|
||
const contentElement = await screen.findByText('Tooltip Content', { | ||
selector: 'div', | ||
}) | ||
expect(contentElement).toHaveClass('border-black') | ||
}) | ||
|
||
it('displays arrow element when Tooltip Content is displayed', async () => { | ||
render( | ||
<Tooltip> | ||
<Tooltip.Root> | ||
<Tooltip.Trigger> | ||
<button>Hover me</button> | ||
</Tooltip.Trigger> | ||
<Tooltip.Portal> | ||
<Tooltip.Content data-state="instant-open"> | ||
Tooltip Content | ||
<Tooltip.Arrow data-testid="tooltip-arrow" /> | ||
</Tooltip.Content> | ||
</Tooltip.Portal> | ||
</Tooltip.Root> | ||
</Tooltip> | ||
) | ||
|
||
const triggerElement = await screen.findByText('Hover me') | ||
await userEvent.hover(triggerElement) | ||
|
||
const arrowElement = await screen.findByTestId('tooltip-arrow') | ||
expect(arrowElement).toBeInTheDocument() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { Meta, StoryObj } from '@storybook/react' | ||
import React, { useState } from 'react' | ||
|
||
import Icon from 'ui/Icon' | ||
|
||
import { Tooltip } from './Tooltip' | ||
|
||
const meta: Meta<typeof Tooltip> = { | ||
title: 'Components/Tooltip', | ||
component: Tooltip, | ||
} | ||
export default meta | ||
|
||
type Story = StoryObj<typeof Tooltip> | ||
|
||
const DefaultStory: React.FC = () => ( | ||
<Tooltip delayDuration={0} skipDelayDuration={100}> | ||
<div className="flex h-screen items-center justify-center"> | ||
<Tooltip.Root> | ||
<Tooltip.Trigger> | ||
<p>hover over me</p> | ||
</Tooltip.Trigger> | ||
<Tooltip.Portal> | ||
<Tooltip.Content side="top"> | ||
<p>This is the tooltip content with plain text.</p> | ||
<Tooltip.Arrow /> | ||
</Tooltip.Content> | ||
</Tooltip.Portal> | ||
</Tooltip.Root> | ||
</div> | ||
</Tooltip> | ||
) | ||
|
||
const WithHtmlContentStory: React.FC = () => ( | ||
<Tooltip delayDuration={0} skipDelayDuration={500}> | ||
<div className="flex h-screen items-center justify-center"> | ||
<Tooltip.Root> | ||
<Tooltip.Trigger> | ||
<button className="rounded border-2 border-red-700 p-4 text-red-700"> | ||
<Icon name="informationCircle" size="lg" /> | ||
</button> | ||
</Tooltip.Trigger> | ||
<Tooltip.Portal> | ||
<Tooltip.Content side="left" className="bg-gray-100 text-black"> | ||
<div> | ||
<p>This is the tooltip content with HTML.</p> | ||
<p> | ||
It can contain HTML elements like <strong>bold text</strong> and{' '} | ||
<em>italic text</em>. | ||
</p> | ||
</div> | ||
<Tooltip.Arrow /> | ||
</Tooltip.Content> | ||
</Tooltip.Portal> | ||
</Tooltip.Root> | ||
</div> | ||
</Tooltip> | ||
) | ||
|
||
const BottomTooltipStory: React.FC = () => { | ||
const [isOpen, setIsOpen] = useState(false) | ||
|
||
return ( | ||
<Tooltip delayDuration={0} skipDelayDuration={500}> | ||
<div className="flex h-screen items-center justify-center"> | ||
<Tooltip.Root onOpenChange={setIsOpen} open={isOpen}> | ||
<Tooltip.Trigger> | ||
<button className="p-4 text-blue-700"> | ||
<Icon name={isOpen ? 'eye' : 'eyeOff'} size="lg" /> | ||
</button> | ||
</Tooltip.Trigger> | ||
<Tooltip.Portal> | ||
<Tooltip.Content side="bottom"> | ||
<p>This is the tooltip content with plain text.</p> | ||
<Tooltip.Arrow className="fill-blue-700" /> | ||
</Tooltip.Content> | ||
</Tooltip.Portal> | ||
</Tooltip.Root> | ||
</div> | ||
</Tooltip> | ||
) | ||
} | ||
|
||
export const Default: Story = { | ||
render: () => <DefaultStory />, | ||
} | ||
|
||
export const WithHtmlContent: Story = { | ||
render: () => <WithHtmlContentStory />, | ||
} | ||
|
||
export const BottomTooltip: Story = { | ||
render: () => <BottomTooltipStory />, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
//https://www.radix-ui.com/primitives/docs/components/tooltip | ||
import * as RadixTooltip from '@radix-ui/react-tooltip' | ||
import React, { forwardRef } from 'react' | ||
|
||
import { cn } from 'shared/utils/cn' | ||
|
||
const TooltipProvider: React.FC<RadixTooltip.TooltipProviderProps> = ({ | ||
children, | ||
...props | ||
}) => <RadixTooltip.Provider {...props}>{children}</RadixTooltip.Provider> | ||
|
||
TooltipProvider.displayName = 'TooltipProvider' | ||
|
||
const TooltipRoot: React.FC<RadixTooltip.TooltipProps> = ({ | ||
children, | ||
...props | ||
}) => <RadixTooltip.Root {...props}>{children}</RadixTooltip.Root> | ||
|
||
TooltipRoot.displayName = 'TooltipRoot' | ||
|
||
const TooltipTrigger = forwardRef< | ||
React.ElementRef<typeof RadixTooltip.Trigger>, | ||
React.ComponentPropsWithoutRef<typeof RadixTooltip.Trigger> | ||
>(({ children, className, ...props }, ref) => ( | ||
<RadixTooltip.Trigger ref={ref} {...props} className={className}> | ||
{children} | ||
</RadixTooltip.Trigger> | ||
)) | ||
|
||
TooltipTrigger.displayName = 'TooltipTrigger' | ||
|
||
interface TooltipContentProps | ||
extends React.ComponentPropsWithoutRef<typeof RadixTooltip.Content> { | ||
sideOffset?: number | ||
} | ||
|
||
const TooltipContent = forwardRef< | ||
React.ElementRef<typeof RadixTooltip.Content>, | ||
TooltipContentProps | ||
>(({ children, className, sideOffset = 5, ...props }, ref) => ( | ||
<RadixTooltip.Content | ||
ref={ref} | ||
sideOffset={sideOffset} | ||
{...props} | ||
className={cn( | ||
'bg-gray-800 px-3 py-2 text-sm text-white shadow-md', | ||
className | ||
)} | ||
> | ||
{children} | ||
</RadixTooltip.Content> | ||
)) | ||
|
||
TooltipContent.displayName = 'TooltipContent' | ||
|
||
const TooltipArrow = forwardRef< | ||
React.ElementRef<typeof RadixTooltip.Arrow>, | ||
React.ComponentPropsWithoutRef<typeof RadixTooltip.Arrow> | ||
>(({ className, ...props }, ref) => ( | ||
<RadixTooltip.Arrow ref={ref} {...props} className={className} /> | ||
)) | ||
|
||
TooltipArrow.displayName = 'TooltipArrow' | ||
|
||
const TooltipPortal: React.FC<RadixTooltip.TooltipPortalProps> = ({ | ||
children, | ||
...props | ||
}) => <RadixTooltip.Portal {...props}>{children}</RadixTooltip.Portal> | ||
|
||
TooltipPortal.displayName = 'TooltipPortal' | ||
|
||
export const Tooltip = Object.assign(TooltipProvider, { | ||
Root: TooltipRoot, | ||
Trigger: TooltipTrigger, | ||
Content: TooltipContent, | ||
Arrow: TooltipArrow, | ||
Portal: TooltipPortal, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { Tooltip } from './Tooltip' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters