From 8bec90da24dfa6dc182b0ab291a8ec72b189147f Mon Sep 17 00:00:00 2001 From: gabrieljablonski Date: Thu, 9 Mar 2023 13:05:50 -0300 Subject: [PATCH 1/2] feat: new `openOnClick` prop --- src/components/Tooltip/Tooltip.tsx | 20 ++++++++++--------- src/components/Tooltip/TooltipTypes.d.ts | 4 ++++ .../TooltipController/TooltipController.tsx | 2 ++ .../TooltipControllerTypes.d.ts | 7 +++++++ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx index eec3337a..30ea4bd0 100644 --- a/src/components/Tooltip/Tooltip.tsx +++ b/src/components/Tooltip/Tooltip.tsx @@ -19,6 +19,7 @@ const Tooltip = ({ place = 'top', offset = 10, events = ['hover'], + openOnClick = false, positionStrategy = 'absolute', middlewares, wrapper: WrapperElement, @@ -60,6 +61,8 @@ const Tooltip = ({ const [anchorsBySelect, setAnchorsBySelect] = useState([]) const mounted = useRef(false) + const shouldOpenOnClick = openOnClick || events.includes('click') + /** * useLayoutEffect runs before useEffect, * but should be used carefully because of caveats @@ -255,10 +258,11 @@ const Tooltip = ({ const handleClickOutsideAnchors = (event: MouseEvent) => { const anchorById = document.querySelector(`[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) @@ -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 }, @@ -322,7 +324,7 @@ const Tooltip = ({ handleHideTooltip() } - if (clickable) { + if (clickable && !shouldOpenOnClick) { tooltipRef.current?.addEventListener('mouseenter', handleMouseEnterTooltip) tooltipRef.current?.addEventListener('mouseleave', handleMouseLeaveTooltip) } @@ -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) } diff --git a/src/components/Tooltip/TooltipTypes.d.ts b/src/components/Tooltip/TooltipTypes.d.ts index f11c8f67..8760a731 100644 --- a/src/components/Tooltip/TooltipTypes.d.ts +++ b/src/components/Tooltip/TooltipTypes.d.ts @@ -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 diff --git a/src/components/TooltipController/TooltipController.tsx b/src/components/TooltipController/TooltipController.tsx index a05389d6..5ea30177 100644 --- a/src/components/TooltipController/TooltipController.tsx +++ b/src/components/TooltipController/TooltipController.tsx @@ -26,6 +26,7 @@ const TooltipController = ({ wrapper = 'div', children = null, events = ['hover'], + openOnClick = false, positionStrategy = 'absolute', middlewares, delayShow = 0, @@ -209,6 +210,7 @@ const TooltipController = ({ offset: tooltipOffset, wrapper: tooltipWrapper, events: tooltipEvents, + openOnClick, positionStrategy: tooltipPositionStrategy, middlewares, delayShow: tooltipDelayShow, diff --git a/src/components/TooltipController/TooltipControllerTypes.d.ts b/src/components/TooltipController/TooltipControllerTypes.d.ts index 14584040..3c9e9437 100644 --- a/src/components/TooltipController/TooltipControllerTypes.d.ts +++ b/src/components/TooltipController/TooltipControllerTypes.d.ts @@ -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 @@ -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 From 2d921d7ef5da446faa4c83c2878fe196b7ad192b Mon Sep 17 00:00:00 2001 From: gabrieljablonski Date: Thu, 9 Mar 2023 13:06:52 -0300 Subject: [PATCH 2/2] docs: deprecate `events` prop and attribute --- docs/docs/examples/events.mdx | 15 +++++------ docs/docs/options.mdx | 31 +++++++++++----------- docs/docs/upgrade-guide/changelog-v4-v5.md | 2 +- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/docs/docs/examples/events.mdx b/docs/docs/examples/events.mdx index 814d5175..e41e927f 100644 --- a/docs/docs/examples/events.mdx +++ b/docs/docs/examples/events.mdx @@ -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' @@ -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 diff --git a/docs/docs/options.mdx b/docs/docs/options.mdx index b4931192..858abdcc 100644 --- a/docs/docs/options.mdx +++ b/docs/docs/options.mdx @@ -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~~
**DEPRECATED**
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 @@ -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~~
**DEPRECATED**
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 | diff --git a/docs/docs/upgrade-guide/changelog-v4-v5.md b/docs/docs/upgrade-guide/changelog-v4-v5.md index 18656899..707a1e40 100644 --- a/docs/docs/upgrade-guide/changelog-v4-v5.md +++ b/docs/docs/upgrade-guide/changelog-v4-v5.md @@ -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`