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:
parent
e651e9c797
commit
ac7e82b0a4
@ -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'
|
||||
|
||||
|
@ -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'
|
||||
|
||||
|
45
__tests__/components/Tooltip/Tooltip.test.tsx
Normal file
45
__tests__/components/Tooltip/Tooltip.test.tsx
Normal 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)
|
||||
})
|
||||
})
|
||||
})
|
44
__tests__/components/Tooltip/TooltipContent.test.tsx
Normal file
44
__tests__/components/Tooltip/TooltipContent.test.tsx
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
@ -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"
|
||||
|
@ -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 '
|
||||
|
@ -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'
|
||||
|
@ -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 |
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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}`,
|
||||
|
@ -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>
|
||||
|
31
src/components/Tooltip/TooltipContent.tsx
Normal file
31
src/components/Tooltip/TooltipContent.tsx
Normal 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>
|
||||
)
|
||||
}
|
@ -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 />
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user