diff --git a/packages/tooltip/package.json b/packages/tooltip/package.json
index 3f2fa28978..42d9adc6b1 100644
--- a/packages/tooltip/package.json
+++ b/packages/tooltip/package.json
@@ -15,7 +15,6 @@
"dist/"
],
"dependencies": {
- "react-measure": "^2.2.4",
"react-spring": "^8.0.27"
},
"peerDependencies": {
diff --git a/packages/tooltip/src/components/TooltipWrapper.js b/packages/tooltip/src/components/TooltipWrapper.js
index caa8df76b6..2a78e8af35 100644
--- a/packages/tooltip/src/components/TooltipWrapper.js
+++ b/packages/tooltip/src/components/TooltipWrapper.js
@@ -6,11 +6,10 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-import React, { memo, useMemo, useState, useRef, useEffect } from 'react'
+import React, { memo, useMemo } from 'react'
import PropTypes from 'prop-types'
-import Measure from 'react-measure'
import { useSpring, animated } from 'react-spring'
-import { useTheme, useMotionConfig } from '@nivo/core'
+import { useTheme, useMotionConfig, useMeasure } from '@nivo/core'
const TOOLTIP_OFFSET = 14
@@ -22,84 +21,56 @@ const tooltipStyle = {
left: 0,
}
-const TooltipWrapper = memo(({ position, anchor, children }) => {
+const TooltipWrapper = ({ position, anchor, children }) => {
const theme = useTheme()
- const { config: springConfig } = useMotionConfig()
-
- const [dimensions, setDimensions] = useState(null)
- const previousDimensions = useRef(null)
- useEffect(() => {
- previousDimensions.current = dimensions
- })
+ const { animate, config: springConfig } = useMotionConfig()
+ const [measureRef, bounds] = useMeasure()
let x = Math.round(position[0])
let y = Math.round(position[1])
- if (dimensions !== null) {
+
+ const hasDimension = bounds.width > 0 && bounds.height > 0
+ if (hasDimension !== null) {
if (anchor === 'top') {
- x -= dimensions[0] / 2
- y -= dimensions[1] + TOOLTIP_OFFSET
+ x -= bounds.width / 2
+ y -= bounds.height + TOOLTIP_OFFSET
} else if (anchor === 'right') {
x += TOOLTIP_OFFSET
- y -= dimensions[1] / 2
+ y -= bounds.height / 2
} else if (anchor === 'bottom') {
- x -= dimensions[0] / 2
+ x -= bounds.width / 2
y += TOOLTIP_OFFSET
} else if (anchor === 'left') {
- x -= dimensions[0] + TOOLTIP_OFFSET
- y -= dimensions[1] / 2
+ x -= bounds.width + TOOLTIP_OFFSET
+ y -= bounds.height / 2
} else if (anchor === 'center') {
- x -= dimensions[0] / 2
- y -= dimensions[1] / 2
+ x -= bounds.width / 2
+ y -= bounds.height / 2
}
}
- const isInitializing = dimensions === null || previousDimensions.current === null
-
const animatedProps = useSpring({
transform: `translate(${x}px, ${y}px)`,
config: springConfig,
- // the way the animated tooltip works is not ideal for now
- immediate: true, // !animate || isInitializing,
+ immediate: !animate || !hasDimension,
})
const style = useMemo(
() => ({
...tooltipStyle,
...theme.tooltip,
- opacity: isInitializing ? 0 : 1,
+ transform: animatedProps.transform,
+ opacity: hasDimension ? 1 : 0,
}),
- [dimensions, theme.tooltip, isInitializing]
+ [hasDimension, theme.tooltip, animatedProps.transform]
)
- // if we don't have dimensions yet, we use
- // the non animated version with a 0 opacity
- // to avoid a flash effect and weird initial transition
return (
- {
- setDimensions([bounds.width, bounds.height])
- }}
- >
- {({ measureRef }) => {
- return (
-
- {children}
-
- )
- }}
-
+
+ {children}
+
)
-})
+}
TooltipWrapper.displayName = 'TooltipWrapper'
TooltipWrapper.propTypes = {
@@ -111,4 +82,4 @@ TooltipWrapper.defaultProps = {
anchor: 'top',
}
-export default TooltipWrapper
+export default memo(TooltipWrapper)
diff --git a/packages/tooltip/src/hooks.js b/packages/tooltip/src/hooks.js
index cd22862004..a51d549600 100644
--- a/packages/tooltip/src/hooks.js
+++ b/packages/tooltip/src/hooks.js
@@ -6,7 +6,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-import { useState, useContext, useCallback } from 'react'
+import { useState, useContext, useCallback, useMemo } from 'react'
import { tooltipContext } from './context'
export const useTooltipHandlers = container => {
@@ -16,14 +16,17 @@ export const useTooltipHandlers = container => {
position: {},
})
- const showTooltipAt = useCallback((content, [x, y], anchor) => {
- setState({
- isVisible: true,
- position: [x, y],
- anchor,
- content,
- })
- }, [])
+ const showTooltipAt = useCallback(
+ (content, [x, y], anchor) => {
+ setState({
+ isVisible: true,
+ position: [x, y],
+ anchor,
+ content,
+ })
+ },
+ [setState]
+ )
const showTooltipFromEvent = useCallback(
(content, event, anchor) => {
@@ -43,12 +46,12 @@ export const useTooltipHandlers = container => {
content,
})
},
- [container]
+ [container, setState]
)
const hideTooltip = useCallback(() => {
setState({ isVisible: false, content: null })
- })
+ }, [setState])
return {
showTooltipAt,
@@ -61,4 +64,16 @@ export const useTooltipHandlers = container => {
}
}
-export const useTooltip = () => useContext(tooltipContext)
+export const useTooltip = () => {
+ const context = useContext(tooltipContext)
+
+ const memoizedContext = useMemo(() => {
+ return {
+ showTooltipAt: context.showTooltipAt,
+ showTooltipFromEvent: context.showTooltipFromEvent,
+ hideTooltip: context.hideTooltip,
+ }
+ }, [context.showTooltipAt, context.showTooltipFromEvent, context.hideTooltip])
+
+ return memoizedContext
+}