Skip to content

Commit

Permalink
Feat visu tooltip time (#106)
Browse files Browse the repository at this point in the history
* feat: add time variation to tooltip component

* feat: create tooltip variation - time duration to close

* feat: add tooltip variation, mode time
  • Loading branch information
Ftarganski committed Jan 2, 2024
1 parent df654ad commit 20a23ab
Show file tree
Hide file tree
Showing 8 changed files with 355 additions and 26 deletions.
140 changes: 140 additions & 0 deletions apps/docs/src/stories/Tooltip/Time.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { Button, Tooltip, TooltipTimeProps } from '@droz-js/visu'
import { Meta, StoryObj } from '@storybook/react'
import { Question } from 'phosphor-react'

const meta: Meta<TooltipTimeProps> = {
title: 'Tooltip/Time',
component: Tooltip.Time,
argTypes: {
children: {
control: 'none',
description: 'Trigger do Tooltip.',
table: {
type: {
summary: 'React.ReactNode',
},
},
},
content: {
control: 'text',
description: 'Define o conteúdo exibido no Tooltip.',
table: {
type: { summary: 'React.ReactNode' },
},
type: { name: 'string', required: false },
},
defaultOpen: {
control: 'boolean',
description: 'Define se o Tooltip deve iniciar aberto ou fechado.',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
type: { name: 'boolean', required: false },
},
closeTime: {
control: 'number',
description: 'Define o tempo em milissegundos para fechar o conteúdo do Tooltip.',
table: {
type: { summary: 'number' },
defaultValue: { summary: '2000' },
},
type: { name: 'number', required: false },
},
open: {
control: 'boolean',
description: 'Define se o conteúdo do Tooltip está visível ou não.',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
type: { name: 'boolean', required: false },
},
side: {
control: { type: 'inline-radio' },
description: 'Define o local em que o componente irá aparecer, relativo ao trigger.',
options: ['bottom', 'left', 'right', 'top'],
table: {
type: {
summary: ['bottom', 'left', 'right', 'top'].join('|'),
},
defaultValue: { summary: 'bottom' },
},
type: { name: 'string', required: false },
},
onOpenChange: {
control: 'none',
description: 'Callback executado quando o estado de `open` é alterado.',
table: {
type: { summary: 'function' },
},
type: { name: 'function', required: false },
},

/**
* @deprecated - Deprecated props will be removed in the next major version.
*/
text: {
control: 'none',
name: 'text (deprecated)',
description: '<s>Define o valor em texto do componente.</s> (deprecated) - Use a propriedade `content`.',
table: {
type: { summary: 'text' },
},
type: { name: 'string', required: false },
},
},
args: {
children: '',
content: 'Texto do tooltip',
defaultOpen: false,
closeTime: 2000,
open: false,
side: 'bottom',
},
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/cUmiZr1GhrB9HsRCuOJ0S2/%5BDroz-Nexo%5D-Library?type=design&node-id=3107-18351&t=NDiO1Vda4DCr6uFV-0',
allowFullscreen: true,
},
},
}

export default meta
type TooltipTimeStory = StoryObj<TooltipTimeProps>

export const ComTexto: TooltipTimeStory = {
name: 'Com texto',
render: (args) => {
return (
<Tooltip.Time {...args}>
<Question size={24} />
</Tooltip.Time>
)
},
}

export const ComReactNode: TooltipTimeStory = {
name: 'Com ReactNode',
args: {
content: (
<>
<p>Texto do tooltip</p>
<Button.Root>Button do tooltip</Button.Root>
</>
),
},
argTypes: {
content: {
control: 'none',
},
},
render: (args) => {
return (
<Tooltip.Time {...args}>
<Question size={24} />
</Tooltip.Time>
)
},
}
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions packages/visu/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import LayoutDefault from './layout/Default'
import { Skeleton } from './library'
import { Tooltip } from './library'
import { zodResolver } from '@hookform/resolvers/zod'
import { Eraser } from 'phosphor-react'
import { useState } from 'react'
Expand Down Expand Up @@ -32,9 +32,9 @@ function App() {
<LayoutDefault asChild terminal={[watch(), test]} buttons={[{ icon: <Eraser />, onClick: clearState }]}>
<form onSubmit={handleSubmit(onSubmit)}>
{/* ================================= TEST AREA ================================= */}
<div className="flex h-full w-full flex-col gap-4 ">
<Skeleton className="h-32 w-full" repeat={4} />
</div>
<Tooltip.Time content="Copiado!" closeTime={2000} side="top">
<span>Time</span>
</Tooltip.Time>

{/* ================================= TEST AREA ================================= */}
</form>
Expand Down
4 changes: 1 addition & 3 deletions packages/visu/src/__tests__/Tooltip/Close.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ describe('TooltipClose tests', () => {
fireEvent.click(element)

await waitFor(() => {
expect(screen.getByRole('dialog')).toContainHTML(
'<span data-testid="content">Text1</span>',
)
expect(screen.getByRole('dialog')).toContainHTML('<span data-testid="content">Text1</span>')
})
})

Expand Down
119 changes: 119 additions & 0 deletions packages/visu/src/__tests__/Tooltip/Time.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { Tooltip } from '@library'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

// Testes limitados por conta do Radix
describe('TooltipTime tests', () => {
it('Should render a TooltipTime element', () => {
render(
<Tooltip.Time content="Text1">
<div data-testid="element">Hello</div>
</Tooltip.Time>,
)
const element = screen.getByTestId('element')

expect(element).toBeInTheDocument()
})

it('Should render a text with the prop "content"', async () => {
const user = userEvent.setup()

render(
<Tooltip.Time content="Text1">
<div data-testid="element">Hello</div>
</Tooltip.Time>,
)
const element = screen.getByTestId('element')
await user.click(element)

await waitFor(() => {
expect(screen.getByRole('tooltip')).toHaveTextContent('Text1')
})
})

it('Should render a ReactNode content with the prop "content"', async () => {
const user = userEvent.setup()

render(
<Tooltip.Time content={<span data-testid="content">Text1</span>}>
<div data-testid="element">Hello</div>
</Tooltip.Time>,
)
const element = screen.getByTestId('element')
await user.click(element)

await waitFor(() => {
expect(screen.getByRole('tooltip')).toContainHTML('<span data-testid="content">Text1</span>')
})
})

it('Should render content when trigger gets a click', async () => {
render(
<Tooltip.Time content={<span data-testid="content">Text1</span>}>
<div data-testid="element">Hello</div>
</Tooltip.Time>,
)
const element = screen.getByTestId('element')
fireEvent.click(element)

await waitFor(() => {
expect(screen.getByRole('tooltip')).toContainHTML('<span data-testid="content">Text1</span>')
})
})

it('Should execute "onOpenChange" when "open" value changes', async () => {
const onOpenChange = jest.fn()
console.log(onOpenChange)
render(
<Tooltip.Time content={<span data-testid="content">Text1</span>} onOpenChange={onOpenChange}>
<div data-testid="element">Hello</div>
</Tooltip.Time>,
)
const element = screen.getByTestId('element')
fireEvent.click(element)

await waitFor(() => {
expect(screen.getByRole('tooltip')).toContainHTML('<span data-testid="content">Text1</span>')
expect(onOpenChange).toBeCalledTimes(1)
expect(onOpenChange).toBeCalledWith(true)
})
})

/**
* @deprecated - Teste para uma propriedade deprecated
*/
it('Should render a text with the prop "text"', async () => {
const user = userEvent.setup()

render(
<Tooltip.Time text="Text1">
<div data-testid="element">Hello</div>
</Tooltip.Time>,
)
const element = screen.getByTestId('element')
await user.click(element)

await waitFor(() => {
expect(screen.getByRole('tooltip')).toHaveTextContent('Text1')
})
})

it('Should close the tooltip after the specified closeTime', async () => {
const closeTime = 3500 // Tempo de fechamento em milissegundos

render(
<Tooltip.Time content={<span data-testid="content">Text1</span>} closeTime={closeTime}>
<div data-testid="element">Hello</div>
</Tooltip.Time>,
)
const element = screen.getByTestId('element')
fireEvent.click(element)

await waitFor(() => {
expect(screen.getByRole('tooltip')).toContainHTML('<span data-testid="content">Text1</span>')
setTimeout(() => {
expect(screen.queryByRole('tooltip')).toBeNull()
}, closeTime + 100)
})
})
})
18 changes: 3 additions & 15 deletions packages/visu/src/library/Tooltip/Hover.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import * as RadixTooltip from '@radix-ui/react-tooltip'
import { Position } from '@types'
import { clsx } from 'clsx'
import {
FC,
HTMLAttributes,
ReactNode,
useCallback,
useEffect,
useState,
} from 'react'
import { FC, HTMLAttributes, ReactNode, useCallback, useEffect, useState } from 'react'

export interface TooltipHoverProps
extends Omit<HTMLAttributes<HTMLSpanElement>, 'content'> {
export interface TooltipHoverProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'content'> {
// Optional because we can't remove `text` until the next major release
content?: ReactNode
defaultOpen?: boolean
Expand Down Expand Up @@ -60,11 +52,7 @@ const TooltipHover: FC<TooltipHoverProps> = ({
open={tooltipOpen}
onOpenChange={(value) => handleOpenChange(value)}
>
<RadixTooltip.Trigger
className="z-10"
asChild
onClick={() => handleOpenChange(true)}
>
<RadixTooltip.Trigger className="z-10" asChild onClick={() => handleOpenChange(true)}>
{children}
</RadixTooltip.Trigger>
<RadixTooltip.Portal>
Expand Down
Loading

0 comments on commit 20a23ab

Please sign in to comment.