-
-
Notifications
You must be signed in to change notification settings - Fork 1k
/
TooltipWrapper.js
95 lines (81 loc) · 2.48 KB
/
TooltipWrapper.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
* This file is part of the nivo project.
*
* Copyright 2016-present, Raphaël Benitte.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import React, { memo, useRef } from 'react'
import PropTypes from 'prop-types'
import { useSpring, animated } from 'react-spring'
import { useTheme, useMotionConfig, useMeasure } from '@nivo/core'
const TOOLTIP_OFFSET = 14
const tooltipStyle = {
pointerEvents: 'none',
position: 'absolute',
zIndex: 10,
top: 0,
left: 0,
}
const translate = (x, y) => `translate(${x}px, ${y}px)`
const TooltipWrapper = ({ position, anchor, children }) => {
const theme = useTheme()
const { animate, config: springConfig } = useMotionConfig()
const [measureRef, bounds] = useMeasure()
const previousPosition = useRef(false)
let to = undefined
let immediate = false
const hasDimension = bounds.width > 0 && bounds.height > 0
let x = Math.round(position[0])
let y = Math.round(position[1])
if (hasDimension) {
if (anchor === 'top') {
x -= bounds.width / 2
y -= bounds.height + TOOLTIP_OFFSET
} else if (anchor === 'right') {
x += TOOLTIP_OFFSET
y -= bounds.height / 2
} else if (anchor === 'bottom') {
x -= bounds.width / 2
y += TOOLTIP_OFFSET
} else if (anchor === 'left') {
x -= bounds.width + TOOLTIP_OFFSET
y -= bounds.height / 2
} else if (anchor === 'center') {
x -= bounds.width / 2
y -= bounds.height / 2
}
to = {
transform: translate(x, y),
}
if (!previousPosition.current) {
immediate = true
}
previousPosition.current = [x, y]
}
const animatedProps = useSpring({
to,
config: springConfig,
immediate: !animate || immediate,
})
const style = {
...tooltipStyle,
...theme.tooltip,
transform: animatedProps.transform ?? translate(x, y),
}
return (
<animated.div ref={measureRef} style={style}>
{children}
</animated.div>
)
}
TooltipWrapper.propTypes = {
position: PropTypes.array.isRequired,
anchor: PropTypes.oneOf(['top', 'right', 'bottom', 'left', 'center']).isRequired,
children: PropTypes.node.isRequired,
}
TooltipWrapper.defaultProps = {
anchor: 'top',
}
export default memo(TooltipWrapper)