UNPKG

11.2 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.propTypes = exports.default = void 0;
7var _react = _interopRequireDefault(require("react"));
8var _propTypes = _interopRequireDefault(require("prop-types"));
9var _PopperContent = _interopRequireDefault(require("./PopperContent"));
10var _utils = require("./utils");
11function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
13const propTypes = {
14 children: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
15 placement: _propTypes.default.oneOf(_utils.PopperPlacements),
16 target: _utils.targetPropType.isRequired,
17 container: _utils.targetPropType,
18 isOpen: _propTypes.default.bool,
19 disabled: _propTypes.default.bool,
20 hideArrow: _propTypes.default.bool,
21 boundariesElement: _propTypes.default.oneOfType([_propTypes.default.string, _utils.DOMElement]),
22 className: _propTypes.default.string,
23 innerClassName: _propTypes.default.string,
24 arrowClassName: _propTypes.default.string,
25 popperClassName: _propTypes.default.string,
26 cssModule: _propTypes.default.object,
27 toggle: _propTypes.default.func,
28 autohide: _propTypes.default.bool,
29 placementPrefix: _propTypes.default.string,
30 delay: _propTypes.default.oneOfType([_propTypes.default.shape({
31 show: _propTypes.default.number,
32 hide: _propTypes.default.number
33 }), _propTypes.default.number]),
34 modifiers: _propTypes.default.array,
35 strategy: _propTypes.default.string,
36 offset: _propTypes.default.arrayOf(_propTypes.default.number),
37 innerRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.string, _propTypes.default.object]),
38 trigger: _propTypes.default.string,
39 fade: _propTypes.default.bool,
40 flip: _propTypes.default.bool
41};
42exports.propTypes = propTypes;
43const DEFAULT_DELAYS = {
44 show: 0,
45 hide: 50
46};
47const defaultProps = {
48 isOpen: false,
49 hideArrow: false,
50 autohide: false,
51 delay: DEFAULT_DELAYS,
52 toggle: function () {},
53 trigger: 'click',
54 fade: true
55};
56function isInDOMSubtree(element, subtreeRoot) {
57 return subtreeRoot && (element === subtreeRoot || subtreeRoot.contains(element));
58}
59function isInDOMSubtrees(element, subtreeRoots = []) {
60 return subtreeRoots && subtreeRoots.length && subtreeRoots.filter(subTreeRoot => isInDOMSubtree(element, subTreeRoot))[0];
61}
62class TooltipPopoverWrapper extends _react.default.Component {
63 constructor(props) {
64 super(props);
65 this._targets = [];
66 this.currentTargetElement = null;
67 this.addTargetEvents = this.addTargetEvents.bind(this);
68 this.handleDocumentClick = this.handleDocumentClick.bind(this);
69 this.removeTargetEvents = this.removeTargetEvents.bind(this);
70 this.toggle = this.toggle.bind(this);
71 this.showWithDelay = this.showWithDelay.bind(this);
72 this.hideWithDelay = this.hideWithDelay.bind(this);
73 this.onMouseOverTooltipContent = this.onMouseOverTooltipContent.bind(this);
74 this.onMouseLeaveTooltipContent = this.onMouseLeaveTooltipContent.bind(this);
75 this.show = this.show.bind(this);
76 this.hide = this.hide.bind(this);
77 this.onEscKeyDown = this.onEscKeyDown.bind(this);
78 this.getRef = this.getRef.bind(this);
79 this.state = {
80 isOpen: props.isOpen
81 };
82 this._isMounted = false;
83 }
84 componentDidMount() {
85 this._isMounted = true;
86 this.updateTarget();
87 }
88 componentWillUnmount() {
89 this._isMounted = false;
90 this.removeTargetEvents();
91 this._targets = null;
92 this.clearShowTimeout();
93 this.clearHideTimeout();
94 }
95 static getDerivedStateFromProps(props, state) {
96 if (props.isOpen && !state.isOpen) {
97 return {
98 isOpen: props.isOpen
99 };
100 }
101 return null;
102 }
103 handleDocumentClick(e) {
104 const triggers = this.props.trigger.split(' ');
105 if (triggers.indexOf('legacy') > -1 && (this.props.isOpen || isInDOMSubtrees(e.target, this._targets))) {
106 if (this._hideTimeout) {
107 this.clearHideTimeout();
108 }
109 if (this.props.isOpen && !isInDOMSubtree(e.target, this._popover)) {
110 this.hideWithDelay(e);
111 } else if (!this.props.isOpen) {
112 this.showWithDelay(e);
113 }
114 } else if (triggers.indexOf('click') > -1 && isInDOMSubtrees(e.target, this._targets)) {
115 if (this._hideTimeout) {
116 this.clearHideTimeout();
117 }
118 if (!this.props.isOpen) {
119 this.showWithDelay(e);
120 } else {
121 this.hideWithDelay(e);
122 }
123 }
124 }
125 onMouseOverTooltipContent() {
126 if (this.props.trigger.indexOf('hover') > -1 && !this.props.autohide) {
127 if (this._hideTimeout) {
128 this.clearHideTimeout();
129 }
130 if (this.state.isOpen && !this.props.isOpen) {
131 this.toggle();
132 }
133 }
134 }
135 onMouseLeaveTooltipContent(e) {
136 if (this.props.trigger.indexOf('hover') > -1 && !this.props.autohide) {
137 if (this._showTimeout) {
138 this.clearShowTimeout();
139 }
140 e.persist();
141 this._hideTimeout = setTimeout(this.hide.bind(this, e), this.getDelay('hide'));
142 }
143 }
144 onEscKeyDown(e) {
145 if (e.key === 'Escape') {
146 this.hide(e);
147 }
148 }
149 getRef(ref) {
150 const {
151 innerRef
152 } = this.props;
153 if (innerRef) {
154 if (typeof innerRef === 'function') {
155 innerRef(ref);
156 } else if (typeof innerRef === 'object') {
157 innerRef.current = ref;
158 }
159 }
160 this._popover = ref;
161 }
162 getDelay(key) {
163 const {
164 delay
165 } = this.props;
166 if (typeof delay === 'object') {
167 return isNaN(delay[key]) ? DEFAULT_DELAYS[key] : delay[key];
168 }
169 return delay;
170 }
171 getCurrentTarget(target) {
172 if (!target) return null;
173 const index = this._targets.indexOf(target);
174 if (index >= 0) return this._targets[index];
175 return this.getCurrentTarget(target.parentElement);
176 }
177 show(e) {
178 if (!this.props.isOpen) {
179 this.clearShowTimeout();
180 this.currentTargetElement = e ? e.currentTarget || this.getCurrentTarget(e.target) : null;
181 if (e && e.composedPath && typeof e.composedPath === 'function') {
182 const path = e.composedPath();
183 this.currentTargetElement = path && path[0] || this.currentTargetElement;
184 }
185 this.toggle(e);
186 }
187 }
188 showWithDelay(e) {
189 if (this._hideTimeout) {
190 this.clearHideTimeout();
191 }
192 this._showTimeout = setTimeout(this.show.bind(this, e), this.getDelay('show'));
193 }
194 hide(e) {
195 if (this.props.isOpen) {
196 this.clearHideTimeout();
197 this.currentTargetElement = null;
198 this.toggle(e);
199 }
200 }
201 hideWithDelay(e) {
202 if (this._showTimeout) {
203 this.clearShowTimeout();
204 }
205 this._hideTimeout = setTimeout(this.hide.bind(this, e), this.getDelay('hide'));
206 }
207 clearShowTimeout() {
208 clearTimeout(this._showTimeout);
209 this._showTimeout = undefined;
210 }
211 clearHideTimeout() {
212 clearTimeout(this._hideTimeout);
213 this._hideTimeout = undefined;
214 }
215 addEventOnTargets(type, handler, isBubble) {
216 this._targets.forEach(target => {
217 target.addEventListener(type, handler, isBubble);
218 });
219 }
220 removeEventOnTargets(type, handler, isBubble) {
221 this._targets.forEach(target => {
222 target.removeEventListener(type, handler, isBubble);
223 });
224 }
225 addTargetEvents() {
226 if (this.props.trigger) {
227 let triggers = this.props.trigger.split(' ');
228 if (triggers.indexOf('manual') === -1) {
229 if (triggers.indexOf('click') > -1 || triggers.indexOf('legacy') > -1) {
230 document.addEventListener('click', this.handleDocumentClick, true);
231 }
232 if (this._targets && this._targets.length) {
233 if (triggers.indexOf('hover') > -1) {
234 this.addEventOnTargets('mouseover', this.showWithDelay, true);
235 this.addEventOnTargets('mouseout', this.hideWithDelay, true);
236 }
237 if (triggers.indexOf('focus') > -1) {
238 this.addEventOnTargets('focusin', this.show, true);
239 this.addEventOnTargets('focusout', this.hide, true);
240 }
241 this.addEventOnTargets('keydown', this.onEscKeyDown, true);
242 }
243 }
244 }
245 }
246 removeTargetEvents() {
247 if (this._targets) {
248 this.removeEventOnTargets('mouseover', this.showWithDelay, true);
249 this.removeEventOnTargets('mouseout', this.hideWithDelay, true);
250 this.removeEventOnTargets('keydown', this.onEscKeyDown, true);
251 this.removeEventOnTargets('focusin', this.show, true);
252 this.removeEventOnTargets('focusout', this.hide, true);
253 }
254 document.removeEventListener('click', this.handleDocumentClick, true);
255 }
256 updateTarget() {
257 const newTarget = (0, _utils.getTarget)(this.props.target, true);
258 if (newTarget !== this._targets) {
259 this.removeTargetEvents();
260 this._targets = newTarget ? Array.from(newTarget) : [];
261 this.currentTargetElement = this.currentTargetElement || this._targets[0];
262 this.addTargetEvents();
263 }
264 }
265 toggle(e) {
266 if (this.props.disabled || !this._isMounted) {
267 return e && e.preventDefault();
268 }
269 return this.props.toggle(e);
270 }
271 render() {
272 if (this.props.isOpen) {
273 this.updateTarget();
274 }
275 const target = this.currentTargetElement || this._targets[0];
276 if (!target) {
277 return null;
278 }
279 const {
280 className,
281 cssModule,
282 innerClassName,
283 isOpen,
284 hideArrow,
285 boundariesElement,
286 placement,
287 placementPrefix,
288 arrowClassName,
289 popperClassName,
290 container,
291 modifiers,
292 strategy,
293 offset,
294 fade,
295 flip,
296 children
297 } = this.props;
298 const attributes = (0, _utils.omit)(this.props, Object.keys(propTypes));
299 const popperClasses = (0, _utils.mapToCssModules)(popperClassName, cssModule);
300 const classes = (0, _utils.mapToCssModules)(innerClassName, cssModule);
301 return /*#__PURE__*/_react.default.createElement(_PopperContent.default, {
302 className: className,
303 target: target,
304 isOpen: isOpen,
305 hideArrow: hideArrow,
306 boundariesElement: boundariesElement,
307 placement: placement,
308 placementPrefix: placementPrefix,
309 arrowClassName: arrowClassName,
310 popperClassName: popperClasses,
311 container: container,
312 modifiers: modifiers,
313 strategy: strategy,
314 offset: offset,
315 cssModule: cssModule,
316 fade: fade,
317 flip: flip
318 }, ({
319 update
320 }) => /*#__PURE__*/_react.default.createElement("div", _extends({}, attributes, {
321 ref: this.getRef,
322 className: classes,
323 role: "tooltip",
324 onMouseOver: this.onMouseOverTooltipContent,
325 onMouseLeave: this.onMouseLeaveTooltipContent,
326 onKeyDown: this.onEscKeyDown
327 }), typeof children === 'function' ? children({
328 update
329 }) : children));
330 }
331}
332TooltipPopoverWrapper.propTypes = propTypes;
333TooltipPopoverWrapper.defaultProps = defaultProps;
334var _default = TooltipPopoverWrapper;
335exports.default = _default;
\No newline at end of file