Skip to content

Commit

Permalink
feat(ui/toooltip): add Tooltip component
Browse files Browse the repository at this point in the history
  • Loading branch information
jozefhruska committed Oct 16, 2020
1 parent 46a82b3 commit 4ac1177
Show file tree
Hide file tree
Showing 11 changed files with 385 additions and 98 deletions.
86 changes: 86 additions & 0 deletions packages/ui/__stories__/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react'

import { Tooltip } from '../src/Tooltip'

import utilStyles from './utils.scss'

export default {
title: 'Components/Tooltip',
component: Tooltip,
}

export const Default = () => (
<div className={utilStyles.wrapperCentered}>
<Tooltip id="tooltip-default" content={'Tooltip content'}>
<button aria-labelledby="tooltip-default">Hover me</button>
</Tooltip>
</div>
)

Default.parameters = {
design: {
type: 'figma',
url: 'https://www.figma.com/file/kaC3jgqMSgqMEgnv7TIse1/%F0%9F%93%90Sign-in-flow?node-id=118%3A2349',
},
}

export const TopPlacement = () => (
<div className={utilStyles.wrapperCentered}>
<Tooltip id="tooltip-placement-top" placement="top" content={'Tooltip content'}>
<button aria-labelledby="tooltip-placement-top">Hover me</button>
</Tooltip>
</div>
)

export const RightPlacement = () => (
<div className={utilStyles.wrapperCentered}>
<Tooltip id="tooltip-placement-right" placement="right" content={'Tooltip content'}>
<button aria-labelledby="tooltip-placement-right">Hover me</button>
</Tooltip>
</div>
)

export const BottomPlacement = () => (
<div className={utilStyles.wrapperCentered}>
<Tooltip id="tooltip-placement-bottom" placement="bottom" content={'Tooltip content'}>
<button aria-labelledby="tooltip-placement-bottom">Hover me</button>
</Tooltip>
</div>
)

export const LeftPlacement = () => (
<div className={utilStyles.wrapperCentered}>
<Tooltip id="tooltip-placement-left" placement="left" content={'Tooltip content'}>
<button aria-labelledby="tooltip-placement-left">Hover me</button>
</Tooltip>
</div>
)

export const InteractiveContent = () => (
<div className={utilStyles.wrapperCentered} style={{ minHeight: '250px' }}>
<Tooltip
id="tooltip-interactive-content"
content={
<>
<p>
Parley come about mutiny swing the lead to go on account run a shot across the bow schooner fathom bounty carouser. Maroon
killick keel driver scourge of the seven seas Jolly Roger hands spyglass Brethren of the Coast booty. Boom rigging gally Plate
Fleet pink dance the hempen jig bilge water measured fer yer chains take a caulk tender.
</p>

<button>Aye Captain!</button>
</>
}
>
<button aria-labelledby="tooltip-interactive-content">Hover me</button>
</Tooltip>
</div>
)

export const Disabled = () => (
<div className={utilStyles.wrapperCentered}>
<Tooltip id="tooltip-disabled" content={'Tooltip content'} disabled>
<button aria-labelledby="tooltip-disabled">Hover me</button>
</Tooltip>
</div>
)
5 changes: 5 additions & 0 deletions packages/ui/__stories__/utils.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.wrapperCentered {
display: flex;
flex-direction: column;
align-items: center;
}
2 changes: 1 addition & 1 deletion packages/ui/__tests__/Link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('Link', () => {

expect(tooltip.props()).toMatchObject({
placement: 'top',
overlay: 'Check our website',
content: 'Check our website',
})

const anchor = tooltip.find('a')
Expand Down
123 changes: 76 additions & 47 deletions packages/ui/__tests__/Tooltip.test.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,93 @@
import React from 'react'
import { mount } from 'enzyme'
import RCTooltip from 'rc-tooltip'
import { act } from 'react-dom/test-utils'
import { mountAndCheckA11Y } from '@hazelcast/test-helpers'
import waitForExpect from 'wait-for-expect'

import { Tooltip, TooltipProps } from '../src/Tooltip'
import { Tooltip } from '../src/Tooltip'

import styles from '../src/Tooltip.module.scss'
waitForExpect.defaults.interval = 50
waitForExpect.defaults.timeout = 1000

describe('Tooltip', () => {
test('renders children without Tooltip if "overlay" is undefined', () => {
const Child = () => <div />
test('Renders correctly if "content" property is defined.', async () => {
const wrapper = await mountAndCheckA11Y(
<Tooltip content="Tooltip content">
<button data-test="tooltip-reference">Hover me</button>
</Tooltip>,
)

const wrapper = mount(
<Tooltip overlay={undefined}>
<Child />
expect(wrapper.find('[data-test="tooltip-container"]').exists()).toBeTruthy()
expect(wrapper.find('[data-test="tooltip-reference-wrapper"]').exists()).toBeTruthy()
expect(wrapper.find('[data-test="tooltip-reference"]').exists()).toBeTruthy()
})

test('Shows tooltip overlay on hover of the target element.', async () => {
const wrapper = await mountAndCheckA11Y(
<Tooltip content="Tooltip content">
<button data-test="tooltip-reference">Hover me</button>
</Tooltip>,
)

expect(wrapper.exists(RCTooltip)).toBeFalsy()
expect(wrapper.exists(Child)).toBeTruthy()
expect(wrapper.find('[data-test="tooltip-overlay"]').exists()).toBeFalsy()

// eslint-disable-next-line @typescript-eslint/require-await
await act(async () => {
wrapper.find('[data-test="tooltip-container"]').simulate('mouseenter')
})

wrapper.update()
const tooltipOverlay = wrapper.find('[data-test="tooltip-overlay"]')

expect(tooltipOverlay.exists()).toBeTruthy()
expect(tooltipOverlay.text()).toEqual('Tooltip content')

// eslint-disable-next-line @typescript-eslint/require-await
await act(async () => {
wrapper.find('[data-test="tooltip-container"]').simulate('mouseleave')
})

setTimeout(() => {
wrapper.update()
console.log(wrapper.find('[data-test="tooltip-overlay"]').debug())
expect(wrapper.find('[data-test="tooltip-overlay"]')).toBeFalsy()
}, 100)
})

test('renders children with Tooltip if "overlay" is defined', () => {
const Child = () => <div />

const props: TooltipProps = {
trigger: ['hover'],
mouseEnterDelay: 100,
mouseLeaveDelay: 200,
overlayStyle: { top: 300 },
prefixCls: 'testPrefix',
transitionName: 'testName',
onVisibleChange: () => undefined,
afterVisibleChange: () => undefined,
visible: true,
defaultVisible: false,
placement: 'top',
align: {},
onPopupAlign: () => undefined,
overlay: 'testOverlay',
arrowContent: 'testContent',
getTooltipContainer: () => document.body,
destroyTooltipOnHide: true,
id: 'testId',
}

const wrapper = mount(
<Tooltip {...props} wrapMaxWidth={false}>
<Child />
test('Shows tooltip overlay on hover of the target element if content is undefined.', async () => {
const wrapper = await mountAndCheckA11Y(
<Tooltip content={undefined}>
<button data-test="tooltip-reference">Hover me</button>
</Tooltip>,
)

const expectedProps: TooltipProps = {
...props,
children: <Child />,
overlayClassName: styles.overlay,
}
expect(wrapper.find('[data-test="tooltip-overlay"]').exists()).toBeFalsy()

// eslint-disable-next-line @typescript-eslint/require-await
await act(async () => {
wrapper.find('[data-test="tooltip-container"]').simulate('mouseenter')
})

wrapper.update()

expect(wrapper.find('[data-test="tooltip-overlay"]').exists()).toBeFalsy()
})

test('Shows tooltip overlay on hover of the target element if tooltip is disabled.', async () => {
const wrapper = await mountAndCheckA11Y(
<Tooltip content="Tooltip content" disabled>
<button data-test="tooltip-reference">Hover me</button>
</Tooltip>,
)

expect(wrapper.find('[data-test="tooltip-overlay"]').exists()).toBeFalsy()

// eslint-disable-next-line @typescript-eslint/require-await
await act(async () => {
wrapper.find('[data-test="tooltip-container"]').simulate('mouseenter')
})

wrapper.update()

const tooltip = wrapper.find(RCTooltip)
expect(tooltip.exists()).toBeTruthy()
expect(tooltip.props()).toEqual(expectedProps)
expect(tooltip.exists(Child)).toBeTruthy()
expect(wrapper.find('[data-test="tooltip-overlay"]').exists()).toBeFalsy()
})
})
33 changes: 33 additions & 0 deletions packages/ui/package-lock.json

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

2 changes: 2 additions & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@
"dependencies": {
"@hazelcast/helpers": "^0.0.1",
"@hazelcast/services": "^0.0.1",
"@popperjs/core": "^2.5.3",
"classnames": "^2.2.6",
"formik": "^2.2.0",
"rc-tooltip": "^4.2.3",
"react-feather": "^2.0.8",
"react-popper": "^2.2.3",
"uuid": "^8.3.1"
},
"devDependencies": {
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/src/Help.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { HelpCircle } from 'react-feather'
import cn from 'classnames'

import { Icon } from './Icon'
import { Tooltip } from './Tooltip'
import { Tooltip, TooltipProps } from './Tooltip'

import styleConsts from '../styles/constants/index.scss'

Expand All @@ -14,12 +14,12 @@ export const helpTooltipId = (inputId: string): string => `${inputId}-help`
export interface HelpProps {
parentId: string
helperText: string | ReactElement
placement?: string
placement?: TooltipProps['placement']
className?: string
}

export const Help: FC<HelpProps> = ({ helperText, placement = 'top', parentId, className }) => (
<Tooltip placement={placement} overlay={helperText} id={helpTooltipId(parentId)}>
<Tooltip placement={placement} content={helperText} id={helpTooltipId(parentId)}>
<div className={cn(styles.container, className)}>
<Icon ariaLabel="Help" color={styleConsts.colorPrimary} icon={HelpCircle} className={styles.icon} />
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const Link: FC<LinkProps> = ({
const idRef = useRef(`${uuid()}-link`)

return (
<Tooltip placement="top" overlay={tooltip} id={idRef.current}>
<Tooltip placement="top" content={tooltip} id={idRef.current}>
<a
className={cn(linkTypes[type], className)}
href={href}
Expand Down

0 comments on commit 4ac1177

Please sign in to comment.