/
tooltip.js
120 lines (103 loc) · 3.2 KB
/
tooltip.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import React from 'react';
import PropTypes from 'prop-types';
import 'pui-css-tooltips';
import classnames from 'classnames';
export class Tooltip extends React.Component {
static propTypes = {
visible: PropTypes.bool,
size: PropTypes.oneOf(['auto','sm', 'md', 'lg']),
isSticky: PropTypes.bool
}
static defaultProps = {
visible: true,
size: 'auto',
isSticky: false
}
constructor(props) {
super(props);
}
render() {
let {isSticky, visible, size, className, children, ...others} = this.props;
const newClasses = classnames('tooltip-container', visible ? 'tooltip-container-visible' : 'tooltip-container-hidden',
size === 'auto' ? null : `tooltip-${size}`,
isSticky? 'tooltip-hoverable': null,
className);
return (
<div className={newClasses} {...others}>
<div className="tooltip-content">{children}</div>
</div>
);
}
}
export class TooltipTrigger extends React.Component {
static propTypes = {
tooltip: PropTypes.oneOfType([PropTypes.node, PropTypes.object]).isRequired,
placement: PropTypes.oneOf(['left', 'right', 'bottom', 'top']),
trigger: PropTypes.oneOf(['hover', 'click']),
clickHideDelay: PropTypes.number,
onEntered: PropTypes.func,
onExited: PropTypes.func,
theme: PropTypes.oneOf(['dark', 'light']),
size: PropTypes.oneOf(['auto', 'sm', 'md', 'lg']),
isSticky: PropTypes.bool
}
static defaultProps = {
placement: 'top',
trigger: 'hover',
clickHideDelay: 1000,
onEntered: () => {},
onExited: () => {},
theme: 'dark',
size: 'auto',
isSticky: false
}
constructor(props) {
super(props);
this.state = {visible: false};
}
hoverHandler(e) {
this.setState({visible: e.type === 'mouseenter'});
}
clickHandler() {
this.setState({visible: true});
setTimeout(() => {
this.setState({visible: false});
}, this.props.clickHideDelay);
}
componentDidUpdate(prevProps, prevState) {
if(prevState.visible && !this.state.visible) {
this.props.onExited();
} else if(!prevState.visible && this.state.visible) {
this.props.onEntered();
}
}
render() {
const {isSticky, placement, tooltip, trigger, className, clickHideDelay, onEntered, onExited, theme, size, ...others} = this.props;
const {visible} = this.state;
let placementClass;
if(placement !== 'top') {
placementClass = `tooltip-${placement}`;
}
let triggerHandler;
switch(trigger) {
case 'click':
triggerHandler = {onClick: this.clickHandler.bind(this)};
break;
default:
triggerHandler = {
onMouseEnter: this.hoverHandler.bind(this),
onMouseLeave: this.hoverHandler.bind(this)
};
break;
}
const newClasses = classnames('tooltip', className, placementClass,
theme === 'light' ? 'tooltip-light' : null);
const newProps = Object.assign({className: newClasses}, triggerHandler, others);
return (
<div {...newProps}>
{this.props.children}
<Tooltip {...{isSticky, size: this.props.size, visible}}>{tooltip}</Tooltip>
</div>
);
}
}