import classNames from 'classnames'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { Manager, Popper, Reference } from 'react-popper'; import Portal from 'Components/Portal'; import { kinds, tooltipPositions } from 'Helpers/Props'; import dimensions from 'Styles/Variables/dimensions'; import { isMobile as isMobileUtil } from 'Utilities/browser'; import styles from './Tooltip.css'; let maxWidth = null; function getMaxWidth() { const windowWidth = window.innerWidth; if (windowWidth >= parseInt(dimensions.breakpointLarge)) { maxWidth = 800; } else if (windowWidth >= parseInt(dimensions.breakpointMedium)) { maxWidth = 650; } else if (windowWidth >= parseInt(dimensions.breakpointSmall)) { maxWidth = 500; } else { maxWidth = 450; } return maxWidth; } class Tooltip extends Component { // // Lifecycle constructor(props, context) { super(props, context); this._scheduleUpdate = null; this._closeTimeout = null; this._maxWidth = maxWidth || getMaxWidth(); this.state = { isOpen: false }; } componentDidUpdate() { if (this._scheduleUpdate && this.state.isOpen) { this._scheduleUpdate(); } } componentWillUnmount() { if (this._closeTimeout) { this._closeTimeout = clearTimeout(this._closeTimeout); } } // // Control computeMaxSize = (data) => { const { top, right, bottom, left } = data.offsets.reference; const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; if ((/^top/).test(data.placement)) { data.styles.maxHeight = top - 20; } else if ((/^bottom/).test(data.placement)) { data.styles.maxHeight = windowHeight - bottom - 20; } else if ((/^right/).test(data.placement)) { data.styles.maxWidth = Math.min(this._maxWidth, windowWidth - right - 20); data.styles.maxHeight = top - 20; } else { data.styles.maxWidth = Math.min(this._maxWidth, left - 20); data.styles.maxHeight = top - 20; } return data; }; // // Listeners onMeasure = ({ width }) => { this.setState({ width }); }; onClick = () => { if (isMobileUtil()) { this.setState({ isOpen: !this.state.isOpen }); } }; onMouseEnter = () => { if (this._closeTimeout) { this._closeTimeout = clearTimeout(this._closeTimeout); } this.setState({ isOpen: true }); }; onMouseLeave = () => { this._closeTimeout = setTimeout(() => { this.setState({ isOpen: false }); }, 100); }; // // Render render() { const { className, bodyClassName, anchor, tooltip, kind, position, canFlip } = this.props; return ( {({ ref }) => ( {anchor} )} {({ ref, style, placement, arrowProps, scheduleUpdate }) => { this._scheduleUpdate = scheduleUpdate; const popperPlacement = placement ? placement.split('-')[0] : position; const vertical = popperPlacement === 'top' || popperPlacement === 'bottom'; return (
{ this.state.isOpen ?
{tooltip}
: null }
); }} ); } } Tooltip.propTypes = { className: PropTypes.string, bodyClassName: PropTypes.string.isRequired, anchor: PropTypes.node.isRequired, tooltip: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired, kind: PropTypes.oneOf([kinds.DEFAULT, kinds.INVERSE]), position: PropTypes.oneOf(tooltipPositions.all), canFlip: PropTypes.bool.isRequired }; Tooltip.defaultProps = { bodyClassName: styles.body, kind: kinds.DEFAULT, position: tooltipPositions.TOP, canFlip: false }; export default Tooltip;