Skip to content

New openOnClick prop to toggle between old hover and click events #979

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions docs/docs/examples/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ sidebar_position: 1

Events available in ReactTooltip component.

:::danger

This has been deprecated. Use the `openOnClick` tooltip prop instead.

:::

import { Tooltip } from 'react-tooltip'
import 'react-tooltip/dist/react-tooltip.css'

Expand Down Expand Up @@ -34,15 +40,6 @@ export const TooltipAnchor = ({ children, id, ...rest }) => {
)
}

:::note

In a previous version, `click` had a different behavior, so it made sense to be enabled alongside `hover`.
Since that's changed, enabling both events `events={['hover', 'click']}` has the same effect of simply enabling `hover`.

In the future, we should simply have a prop to enable `click` mode.

:::

### Using `hover`

:::info
Expand Down
31 changes: 16 additions & 15 deletions docs/docs/options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,20 @@ import 'react-tooltip/dist/react-tooltip.css';

#### Available attributes

| name | type | required | default | values | description |
| ------------------------------ | ------- | -------- | ---------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| data-tooltip-id | string | false | | | The id set on the tooltip element (same as V4's `data-for`) |
| data-tooltip-content | string | false | | | Content to de displayed in tooltip (`html` is priorized over `content`) |
| data-tooltip-html | string | false | | | HTML content to de displayed in tooltip |
| data-tooltip-place | string | false | `top` | `top` `right` `bottom` `left` | Position relative to the anchor element where the tooltip will be rendered (if possible) |
| data-tooltip-offset | number | false | `10` | any `number` | Space between the tooltip element and anchor element (arrow not included in calculation) |
| data-tooltip-variant | string | false | `dark` | `dark` `light` `success` `warning` `error` `info` | Change the tooltip style with default presets |
| data-tooltip-wrapper | string | false | `div` | `div` `span` | Element wrapper for the tooltip container, can be `div`, `span`, `p` or any valid HTML tag |
| data-tooltip-events | string | false | `hover` | `hover click` `hover` `click` | Events to watch for when handling the tooltip state |
| data-tooltip-position-strategy | string | false | `absolute` | `absolute` `fixed` | The position strategy used for the tooltip. Set to `fixed` if you run into issues with `overflow: hidden` on the tooltip parent container |
| data-tooltip-show | number | false | | any `number` | The delay (in ms) before showing the tooltip |
| data-tooltip-hide | number | false | | any `number` | The delay (in ms) before hiding the tooltip |
| data-tooltip-float | boolean | false | `false` | `true` `false` | Tooltip will follow the mouse position when it moves inside the anchor element (same as V4's `effect="float"`) |
| name | type | required | default | values | description |
| ------------------------------ | ---------- | --------- | ----------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| data-tooltip-id | string | false | | | The id set on the tooltip element (same as V4's `data-for`) |
| data-tooltip-content | string | false | | | Content to de displayed in tooltip (`html` is priorized over `content`) |
| data-tooltip-html | string | false | | | HTML content to de displayed in tooltip |
| data-tooltip-place | string | false | `top` | `top` `right` `bottom` `left` | Position relative to the anchor element where the tooltip will be rendered (if possible) |
| data-tooltip-offset | number | false | `10` | any `number` | Space between the tooltip element and anchor element (arrow not included in calculation) |
| data-tooltip-variant | string | false | `dark` | `dark` `light` `success` `warning` `error` `info` | Change the tooltip style with default presets |
| data-tooltip-wrapper | string | false | `div` | `div` `span` | Element wrapper for the tooltip container, can be `div`, `span`, `p` or any valid HTML tag |
| ~~data-tooltip-events~~ | ~~string~~ | ~~false~~ | ~~`hover`~~ | ~~`hover click` `hover` `click`~~ | ~~Events to watch for when handling the tooltip state~~ <br/>**DEPRECATED**<br/>Use `openOnClick` tooltip prop instead |
| data-tooltip-position-strategy | string | false | `absolute` | `absolute` `fixed` | The position strategy used for the tooltip. Set to `fixed` if you run into issues with `overflow: hidden` on the tooltip parent container |
| data-tooltip-show | number | false | | any `number` | The delay (in ms) before showing the tooltip |
| data-tooltip-hide | number | false | | any `number` | The delay (in ms) before hiding the tooltip |
| data-tooltip-float | boolean | false | `false` | `true` `false` | Tooltip will follow the mouse position when it moves inside the anchor element (same as V4's `effect="float"`) |

### Props

Expand Down Expand Up @@ -109,7 +109,8 @@ import 'react-tooltip/dist/react-tooltip.css'
| `variant` | `string` | no | `dark` | `dark` `light` `success` `warning` `error` `info` | Change the tooltip style with default presets |
| `wrapper` | HTML tag | no | `div` | `div` `span` `p` ... | Element wrapper for the tooltip container, can be `div`, `span`, `p` or any valid HTML tag |
| `children` | React node | no | `undefined` | valid React children | The tooltip children have lower priority compared to the `content` prop and the `data-tooltip-content` attribute. Useful for setting default content |
| `events` | `string[]` | no | `hover` | `hover` `click` | Events to watch for when handling the tooltip state |
| ~~`events`~~ | ~~`string[]`~~ | ~~no~~ | ~~`hover`~~ | ~~`hover` `click`~~ | ~~Events to watch for when handling the tooltip state~~ <br/>**DEPRECATED**<br/>Use `openOnClick` tooltip prop instead |
| `openOnClick` | `boolean` | no | `false` | `true` `false` | Controls whether the tooltip should open when clicking (`true`) or hovering (`false`) the anchor element |
| `positionStrategy` | `string` | no | `absolute` | `absolute` `fixed` | The position strategy used for the tooltip. Set to `fixed` if you run into issues with `overflow: hidden` on the tooltip parent container |
| `delayShow` | `number` | no | | any `number` | The delay (in ms) before showing the tooltip |
| `delayHide` | `number` | no | | any `number` | The delay (in ms) before hiding the tooltip |
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/upgrade-guide/changelog-v4-v5.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ If you run into any problems with the tooltip not updating after changes are mad
## New Props

- [x] `classNameArrow`
- [x] `events` (or `data-tooltip-events` on anchor element) - `['hover', 'click']` - default: `['hover']` (always an array when using as prop, even with only one option, when using as data attribute: `data-tooltip-events="hover click"`)
- [x] `openOnClick` - `boolean` - when set, the tooltip will open on click instead of on hover
- [x] `isOpen` - `boolean` (to control tooltip state) - if not used, tooltip state will be handled internally
- [x] `setIsOpen` - `function` (to control tooltip state) - if not used, tooltip state will be handled internally
- [x] `position` - `{ x: number; y: number }` - similar to V4's `overridePosition`
Expand Down
20 changes: 11 additions & 9 deletions src/components/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const Tooltip = ({
place = 'top',
offset = 10,
events = ['hover'],
openOnClick = false,
positionStrategy = 'absolute',
middlewares,
wrapper: WrapperElement,
Expand Down Expand Up @@ -60,6 +61,8 @@ const Tooltip = ({
const [anchorsBySelect, setAnchorsBySelect] = useState<HTMLElement[]>([])
const mounted = useRef(false)

const shouldOpenOnClick = openOnClick || events.includes('click')

/**
* useLayoutEffect runs before useEffect,
* but should be used carefully because of caveats
Expand Down Expand Up @@ -255,10 +258,11 @@ const Tooltip = ({

const handleClickOutsideAnchors = (event: MouseEvent) => {
const anchorById = document.querySelector<HTMLElement>(`[id='${anchorId}']`)
if (anchorById?.contains(event.target as HTMLElement)) {
const anchors = [anchorById, ...anchorsBySelect]
if (anchors.some((anchor) => anchor?.contains(event.target as HTMLElement))) {
return
}
if (anchorsBySelect.some((anchor) => anchor.contains(event.target as HTMLElement))) {
if (tooltipRef.current?.contains(event.target as HTMLElement)) {
return
}
handleShow(false)
Expand Down Expand Up @@ -294,12 +298,10 @@ const Tooltip = ({

const enabledEvents: { event: string; listener: (event?: Event) => void }[] = []

if (events.find((event: string) => event === 'click')) {
if (shouldOpenOnClick) {
window.addEventListener('click', handleClickOutsideAnchors)
enabledEvents.push({ event: 'click', listener: handleClickTooltipAnchor })
}

if (events.find((event: string) => event === 'hover')) {
} else {
enabledEvents.push(
{ event: 'mouseenter', listener: debouncedHandleShowTooltip },
{ event: 'mouseleave', listener: debouncedHandleHideTooltip },
Expand All @@ -322,7 +324,7 @@ const Tooltip = ({
handleHideTooltip()
}

if (clickable) {
if (clickable && !shouldOpenOnClick) {
tooltipRef.current?.addEventListener('mouseenter', handleMouseEnterTooltip)
tooltipRef.current?.addEventListener('mouseleave', handleMouseLeaveTooltip)
}
Expand All @@ -334,13 +336,13 @@ const Tooltip = ({
})

return () => {
if (events.find((event: string) => event === 'click')) {
if (shouldOpenOnClick) {
window.removeEventListener('click', handleClickOutsideAnchors)
}
if (closeOnEsc) {
window.removeEventListener('keydown', handleEsc)
}
if (clickable) {
if (clickable && !shouldOpenOnClick) {
tooltipRef.current?.removeEventListener('mouseenter', handleMouseEnterTooltip)
tooltipRef.current?.removeEventListener('mouseleave', handleMouseLeaveTooltip)
}
Expand Down
4 changes: 4 additions & 0 deletions src/components/Tooltip/TooltipTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ export interface ITooltip {
anchorSelect?: string
wrapper: WrapperType
children?: ChildrenType
/**
* @deprecated Use `openOnClick` instead.
*/
events?: EventsType[]
openOnClick?: boolean
positionStrategy?: PositionStrategy
middlewares?: Middleware[]
delayShow?: number
Expand Down
2 changes: 2 additions & 0 deletions src/components/TooltipController/TooltipController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const TooltipController = ({
wrapper = 'div',
children = null,
events = ['hover'],
openOnClick = false,
positionStrategy = 'absolute',
middlewares,
delayShow = 0,
Expand Down Expand Up @@ -209,6 +210,7 @@ const TooltipController = ({
offset: tooltipOffset,
wrapper: tooltipWrapper,
events: tooltipEvents,
openOnClick,
positionStrategy: tooltipPositionStrategy,
middlewares,
delayShow: tooltipDelayShow,
Expand Down
7 changes: 7 additions & 0 deletions src/components/TooltipController/TooltipControllerTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ export interface ITooltipController {
anchorSelect?: string
wrapper?: WrapperType
children?: ChildrenType
/**
* @deprecated Use `openOnClick` instead.
*/
events?: EventsType[]
openOnClick?: boolean
positionStrategy?: PositionStrategy
middlewares?: Middleware[]
delayShow?: number
Expand All @@ -54,6 +58,9 @@ declare module 'react' {
'data-tooltip-variant'?: VariantType
'data-tooltip-offset'?: number
'data-tooltip-wrapper'?: WrapperType
/**
* @deprecated Use `openOnClick` tooltip prop instead.
*/
'data-tooltip-events'?: EventsType[]
'data-tooltip-position-strategy'?: PositionStrategy
'data-tooltip-delay-show'?: number
Expand Down