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 19, 2020
1 parent b8720fb commit 0c28756
Show file tree
Hide file tree
Showing 12 changed files with 478 additions and 122 deletions.
114 changes: 114 additions & 0 deletions packages/ui/__stories__/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
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'}>
{(ref) => (
<button ref={ref} 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'}>
{(ref) => (
<button ref={ref} 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'}>
{(ref) => (
<button ref={ref} 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'}>
{(ref) => (
<button ref={ref} 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'}>
{(ref) => (
<button ref={ref} 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>
</>
}
>
{(ref) => (
<button ref={ref} 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>
{(ref) => (
<button ref={ref} 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
139 changes: 91 additions & 48 deletions packages/ui/__tests__/Tooltip.test.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,107 @@
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 { Tooltip, TooltipProps } from '../src/Tooltip'

import styles from '../src/Tooltip.module.scss'
import { Tooltip } from '../src/Tooltip'

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 id="tooltip-test" content="Tooltip content">
{(ref) => (
<button ref={ref} data-test="tooltip-reference">
Hover me
</button>
)}
</Tooltip>,
)

expect(wrapper.find('[data-test="tooltip-container"]').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 id="tooltip-test" content="Tooltip content">
{(ref) => (
<button ref={ref} data-test="tooltip-reference">
Hover me
</button>
)}
</Tooltip>,
)

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

expect(tooltipOverlay.exists()).toBeFalsy()

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

const wrapper = mount(
<Tooltip overlay={undefined}>
<Child />
wrapper.update()

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

expect(tooltipOverlay.exists()).toBeTruthy()
expect(tooltipOverlay.text()).toEqual('Tooltip content')
expect(tooltipOverlay.prop('id')).toEqual('tooltip-test')

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

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

test('Shows tooltip overlay on hover of the target element if content is undefined.', async () => {
const wrapper = await mountAndCheckA11Y(
<Tooltip id="tooltip-test" content={undefined}>
{(ref) => (
<button ref={ref} 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()

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

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 tooltip is disabled.', async () => {
const wrapper = await mountAndCheckA11Y(
<Tooltip id="tooltip-test" content="Tooltip content" disabled>
{(ref) => (
<button ref={ref} 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()

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 @@ -44,10 +44,12 @@
"dependencies": {
"@hazelcast/helpers": "^0.1.0-alpha.0",
"@hazelcast/services": "^0.1.0-alpha.0",
"@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
24 changes: 15 additions & 9 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/export.scss'

Expand All @@ -14,14 +14,20 @@ 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)}>
<div className={cn(styles.container, className)}>
<Icon ariaLabel="Help" color={styleConsts.colorPrimary} icon={HelpCircle} className={styles.icon} />
</div>
</Tooltip>
)
export const Help: FC<HelpProps> = ({ helperText, placement = 'top', parentId, className }) => {
const tooltipId = helpTooltipId(parentId)

return (
<Tooltip placement={placement} content={helperText} id={tooltipId}>
{(ref) => (
<div ref={ref} className={cn(styles.container, className)} aria-describedby={tooltipId}>
<Icon ariaLabel="Help" color={styleConsts.colorPrimary} icon={HelpCircle} className={styles.icon} />
</div>
)}
</Tooltip>
)
}

0 comments on commit 0c28756

Please sign in to comment.