Mp 2758 updated tooltip component (#238)

* update tooltip styling

* refactor Tooltip and fix build

*  add Tooltip unit tests

* remove width and height

* update tests and yarn format script

* Apply suggestions from code review

Co-authored-by: Yusuf Seyrek <yusufseyrek@users.noreply.github.com>

---------

Co-authored-by: Yusuf Seyrek <yusufseyrek@users.noreply.github.com>
This commit is contained in:
Bob van der Helm 2023-05-31 10:34:26 +02:00 committed by GitHub
parent e651e9c797
commit ac7e82b0a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 161 additions and 40 deletions

View File

@ -1,6 +1,7 @@
import { render, screen } from '@testing-library/react'
import Card from 'components/Card'
import { shallow } from 'enzyme'
import Card from 'components/Card'
import Text from 'components/Text'
import Button from 'components/Button'

View File

@ -1,5 +1,6 @@
import { render, fireEvent } from '@testing-library/react'
import { fireEvent, render } from '@testing-library/react'
import BigNumber from 'bignumber.js'
import TokenInput from 'components/TokenInput'
import { ASSETS } from 'constants/assets'

View File

@ -0,0 +1,45 @@
import { render } from '@testing-library/react'
import { Tooltip } from 'components/Tooltip'
describe('<Tooltip />', () => {
const defaultProps = {
content: <></>,
}
it('should render', () => {
const { container } = render(<Tooltip {...defaultProps} type='info' />)
expect(container).toBeInTheDocument()
})
it('should handle `children` prop correctly', () => {
const { getByTestId } = render(
<Tooltip {...defaultProps} type='info'>
<p data-testid='test-child'>Test text</p>
</Tooltip>,
)
expect(getByTestId('test-child')).toBeInTheDocument()
})
it('should handle `className` prop correctly', () => {
const testClass = 'test-class'
const { container } = render(<Tooltip {...defaultProps} type='info' className={testClass} />)
expect(container.getElementsByClassName(testClass)).toHaveLength(1)
})
describe('should handle `underline` prop correctly', () => {
it('should have border class when children are passed', () => {
const { container } = render(
<Tooltip {...defaultProps} type='info' underline>
<></>
</Tooltip>,
)
expect(container.getElementsByClassName('border-b-1')).toHaveLength(1)
})
it('should not have border class when children are passed', () => {
const { container } = render(<Tooltip {...defaultProps} type='info' underline />)
expect(container.getElementsByClassName('border-b-1')).toHaveLength(0)
})
})
})

View File

@ -0,0 +1,44 @@
import { render } from '@testing-library/react'
import { TooltipType } from 'components/Tooltip'
import TooltipContent from 'components/Tooltip/TooltipContent'
describe('<Tooltip />', () => {
const defaultProps = {
content: <></>,
}
it('should render', () => {
const { container } = render(<TooltipContent {...defaultProps} type='info' />)
expect(container).toBeInTheDocument()
})
it('should handle `type` prop correctly', () => {
const types = { info: 'bg-white/20', warning: 'bg-warning', error: 'bg-error' }
Object.entries(types).forEach(([key, value]) => {
const { container } = render(<TooltipContent {...defaultProps} type={key as TooltipType} />)
expect(container.getElementsByClassName(value)).toHaveLength(1)
})
})
describe('should handle `content` props correctly', () => {
it('should render Text component when type is string', () => {
const testText = 'testText'
const { getByTestId } = render(
<TooltipContent {...defaultProps} type='info' content={testText} />,
)
const textComponent = getByTestId('text-component')
expect(textComponent).toHaveTextContent(testText)
})
it('should render content when type is ReactNode', () => {
const testNode = <p data-testid='test-node'>Test node</p>
const { queryByTestId } = render(
<TooltipContent {...defaultProps} type='info' content={testNode} />,
)
expect(queryByTestId('text-component')).not.toBeInTheDocument()
expect(queryByTestId('test-node')).toBeInTheDocument()
})
})
})

View File

@ -7,7 +7,7 @@
"dev": "next dev",
"test": "jest",
"lint": "eslint ./src/ && yarn prettier-check",
"format": "eslint ./src/ --fix && prettier --write ./src/",
"format": "eslint ./src/ ./__tests__/ --fix && prettier --write ./src/ ./__tests__/",
"prettier-check": "prettier --ignore-path .gitignore --check ./src/",
"start": "next start",
"validate-env": "node ./validate-env"

View File

@ -72,7 +72,7 @@ export const BorrowCapacity = ({
</div>
)}
</div>
<Tooltip content={<Text size='sm'>Borrow Capacity Tooltip</Text>}>
<Tooltip type='info' content={<Text size='sm'>Borrow Capacity Tooltip</Text>}>
<div className='relative'>
<div
className='overflow-hidden rounded-3xl border-r-2 border-r-loss '

View File

@ -28,7 +28,7 @@ export const Gauge = ({
const circlePercent = 100 - percentageValue
return (
<Tooltip content={tooltip}>
<Tooltip type='info' content={tooltip}>
<div className={classNames('relative', `w-${diameter / 4} h-${diameter / 4}`)}>
<svg
viewBox='2 -2 28 36'

View File

@ -1,3 +1,3 @@
<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.99935 5.66797V9.0013M8.99935 12.3346H9.00768M17.3327 9.0013C17.3327 13.6037 13.6017 17.3346 8.99935 17.3346C4.39698 17.3346 0.666016 13.6037 0.666016 9.0013C0.666016 4.39893 4.39698 0.667969 8.99935 0.667969C13.6017 0.667969 17.3327 4.39893 17.3327 9.0013Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.74105 6.66602V9.99935M9.74105 13.3327H9.74938M18.0744 9.99935C18.0744 14.6017 14.3434 18.3327 9.74105 18.3327C5.13868 18.3327 1.40771 14.6017 1.40771 9.99935C1.40771 5.39698 5.13868 1.66602 9.74105 1.66602C14.3434 1.66602 18.0744 5.39698 18.0744 9.99935Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 421 B

After

Width:  |  Height:  |  Size: 436 B

View File

@ -67,6 +67,8 @@ export default function Settings() {
Reduce Motion
</Text>
<Tooltip
type='info'
interactive
content={
<Text size='sm'>
Turns off all animations inside the dApp. Turning animations off can increase
@ -83,6 +85,7 @@ export default function Settings() {
Display Currency
</Text>
<Tooltip
type='info'
content={
<Text size='sm'>
Sets the denomination of values to a different currency. While OSMO is the

View File

@ -21,7 +21,7 @@ export default function SwitchWithLabel(props: Props) {
<Text className='mr-2 text-white/70' size='sm'>
{props.label}
</Text>
{props.tooltip && <Tooltip content={<Text size='sm'>{props.tooltip}</Text>} />}
{props.tooltip && <Tooltip type='info' content={<Text size='sm'>{props.tooltip}</Text>} />}
</div>
<Switch
name={props.name}

View File

@ -23,6 +23,7 @@ export default function Text(props: Props) {
return (
<HtmlElement
data-testid='text-component'
className={classNames(
props.className,
props.uppercase ? `text-${sizeClass}-caps` : `text-${sizeClass}`,

View File

@ -12,6 +12,7 @@ import { BN } from 'utils/helpers'
import { FormattedNumber } from 'components/FormattedNumber'
import Button from 'components/Button'
import { ExclamationMarkTriangle } from 'components/Icons'
import { Tooltip } from 'components/Tooltip'
interface Props {
amount: BigNumber
@ -82,7 +83,13 @@ export default function TokenInput(props: Props) {
/>
{props.warning && (
<div className='grid items-center px-2'>
<ExclamationMarkTriangle className='text-warning' />
<Tooltip
content={`You don't have any ${props.asset.symbol}. Please first deposit ${props.asset.symbol} into your credit account before.`}
type='info'
interactive
>
<ExclamationMarkTriangle className='text-warning' />
</Tooltip>
</div>
)}
</div>

View File

@ -0,0 +1,31 @@
import classNames from 'classnames'
import { ReactNode } from 'react'
import { ExclamationMarkCircled } from 'components/Icons'
import Text from 'components/Text'
import { TooltipType } from '.'
interface Props {
content: ReactNode | string
type: TooltipType
}
export default function TooltipContent(props: Props) {
return (
<div
className={classNames(
'flex max-w-[320px] flex-1 gap-2 rounded-sm p-3 text-xs shadow-tooltip backdrop-blur-lg',
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-base before:p-[1px] before:border-glas',
props.type === 'info' && 'bg-white/20',
props.type === 'warning' && 'bg-warning',
props.type === 'error' && 'bg-error',
)}
>
<div>
<ExclamationMarkCircled className='w-5 gap-3 text-white' />
</div>
{typeof props.content === 'string' ? <Text size='sm'>{props.content}</Text> : props.content}
</div>
)
}

View File

@ -2,62 +2,50 @@ import Tippy from '@tippyjs/react'
import classNames from 'classnames'
import { ReactNode } from 'react'
import { ExclamationMarkCircled, Questionmark } from 'components/Icons'
import { Questionmark } from 'components/Icons'
import useStore from 'store'
import TooltipContent from './TooltipContent'
interface Props {
children?: ReactNode | string
content: ReactNode | string
type: TooltipType
children?: ReactNode | string
className?: string
delay?: number
inderactive?: boolean
interactive?: boolean
underline?: boolean
}
export const Tooltip = ({
children,
content,
className,
delay = 0,
inderactive = false,
underline = false,
}: Props) => {
export type TooltipType = 'info' | 'warning' | 'error'
export const Tooltip = (props: Props) => {
const enableAnimations = useStore((s) => s.enableAnimations)
return (
<Tippy
appendTo={() => document.body}
interactive={inderactive}
appendTo={() => document.querySelector('dialog[open]') ?? document.body}
interactive={props.interactive}
animation={false}
delay={[delay, 0]}
render={(attrs) => {
return (
<div
className='max-w-[320px] rounded-lg bg-black/80 p-4 pl-12 text-xs shadow-tooltip backdrop-blur-lg'
{...attrs}
>
<ExclamationMarkCircled className='absolute left-4 top-3.5 h-5 w-5 text-white' />
{content}
</div>
)
}}
delay={[props.delay ?? 0, 0]}
render={() => <TooltipContent type={props.type} content={props.content} />}
>
{children ? (
{props.children ? (
<span
className={classNames(
underline &&
props.underline &&
'border-b-1 cursor-pointer border border-x-0 border-t-0 border-dashed border-white/50 hover:border-transparent',
enableAnimations && 'transition-all',
className,
props.className,
)}
>
{children}
{props.children}
</span>
) : (
<span
className={classNames(
'inline-block w-[18px] cursor-pointer opacity-40 hover:opacity-80',
className,
props.className,
)}
>
<Questionmark />

View File

@ -78,7 +78,7 @@ module.exports = {
axlusdc: '#478edc',
body: '#0D0012',
'body-dark': '#141621',
error: '#F97066',
error: '#F04438',
'error-bg': '#FDA29B',
grey: '#3a3c49',
'grey-dark': '#1a1c25',