ndla-ui
Version:
UI component library for NDLA.
187 lines (167 loc) • 7.83 kB
JavaScript
var _extends = Object.assign || 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; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/**
* Copyright (c) 2016-present, NDLA.
*
* This source code is licensed under the GPLv3 license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import BEMHelper from 'react-bem-helper';
import { isMobile, isIE } from 'react-device-detect';
import { Fade } from '../Animation';
var classes = new BEMHelper({
name: 'tooltip',
prefix: 'c-'
});
var Tooltip = function (_Component) {
_inherits(Tooltip, _Component);
function Tooltip(props) {
_classCallCheck(this, Tooltip);
var _this = _possibleConstructorReturn(this, (Tooltip.__proto__ || Object.getPrototypeOf(Tooltip)).call(this, props));
_this.state = {
showTooltip: false
};
_this.handleShowTooltip = _this.handleShowTooltip.bind(_this);
_this.handleHideTooltip = _this.handleHideTooltip.bind(_this);
_this.handleKeyPress = _this.handleKeyPress.bind(_this);
_this.contentRef = React.createRef();
_this.tooltipRef = React.createRef();
_this.widthRef = 0;
_this.heightRef = 0;
_this.leftRef = 0;
_this.tooltipRefWidth = props.tooltip ? props.tooltip.length * 5 : 0; // Estimate incase user only uses keyboard navigation.
_this.currentStyles = {};
return _this;
}
_createClass(Tooltip, [{
key: 'getPosition',
value: function getPosition() {
if (this.state.showTooltip) {
this.currentStyles = {};
this.widthRef = this.contentRef.current.offsetWidth;
this.heightRef = this.contentRef.current.offsetHeight;
var elementRect = this.contentRef.current.getBoundingClientRect();
this.leftRef = elementRect.left;
var tooltipWidth = this.tooltipRef.current ? this.tooltipRef.current.offsetWidth : this.tooltipRefWidth;
this.tooltipRefWidth = tooltipWidth;
if (isIE) {
// IE is bad with transform % + px..
this.currentStyles.left = '-' + (this.tooltipRef.current.offsetWidth - this.widthRef) / 2 + 'px';
this.currentStyles.top = '-' + (this.tooltipRef.current.offsetHeight + 10) + 'px';
} else if (this.props.align === 'top' || this.props.align === 'bottom' || this.props.align === 'left' && this.leftRef - tooltipWidth < 20 || this.props.align === 'right' && this.leftRef + this.widthRef + tooltipWidth > window.innerWidth - 40) {
var centeredLeft = this.leftRef + this.widthRef / 2;
var moveHorizontal = Math.max(centeredLeft + tooltipWidth / 2 + 20 - window.innerWidth, 0);
if (moveHorizontal === 0) {
moveHorizontal = Math.min(-(tooltipWidth / 2 - centeredLeft + 20), 0);
}
if (this.props.align === 'bottom') {
this.currentStyles.transform = 'translate(calc(-50% + ' + (this.widthRef / 2 - moveHorizontal) + 'px), calc(' + this.heightRef + 'px + 0.25rem))';
} else {
this.currentStyles.transform = 'translate(calc(-50% + ' + (this.widthRef / 2 - moveHorizontal) + 'px), calc(-100% - 0.25rem))';
}
} else if (this.props.align === 'left') {
this.currentStyles.transform = 'translate(calc(-100% - 0.25rem), calc(-50% + ' + this.heightRef / 2 + 'px))';
} else {
this.currentStyles.transform = 'translate(calc(' + this.widthRef + 'px + 0.25rem), calc(-50% + ' + this.heightRef / 2 + 'px))';
}
}
return this.currentStyles;
}
}, {
key: 'handleShowTooltip',
value: function handleShowTooltip() {
this.setState({ showTooltip: !this.props.disabled });
}
}, {
key: 'handleHideTooltip',
value: function handleHideTooltip() {
this.setState({ showTooltip: false });
}
}, {
key: 'handleKeyPress',
value: function handleKeyPress(e) {
if (e.key === 'Enter') {
try {
this.contentRef.current.querySelectorAll('[type="button"], a')[0].click();
} catch (err) {
console.log('error', err); // eslint-disable-line no-console
}
}
}
}, {
key: 'render',
value: function render() {
// If phone ignore all tooltips //
if (isMobile) {
return React.createElement(
'div',
{
className: classes('').className + ' ' + this.props.tooltipContainerClass },
React.createElement(
'span',
{ className: 'c-tooltip__content ' + this.props.className },
this.props.children
)
);
}
return React.createElement(
'div',
{
className: classes('').className + ' ' + this.props.tooltipContainerClass },
React.createElement(
Fade,
{ 'in': this.state.showTooltip, delay: this.props.delay },
React.createElement(
'span',
_extends({
role: 'tooltip'
}, classes('tooltip'), {
style: this.getPosition(),
ref: this.tooltipRef }),
this.props.tooltip
)
),
React.createElement(
'span',
{
role: 'button',
tabIndex: 0,
'aria-label': this.props.tooltip,
ref: this.contentRef,
onMouseEnter: this.handleShowTooltip,
onMouseOut: this.handleHideTooltip,
onMouseMove: this.handleShowTooltip,
onFocus: this.handleShowTooltip,
onKeyPress: this.handleKeyPress,
onBlur: this.handleHideTooltip,
className: 'c-tooltip__content ' + this.props.className },
this.props.children
)
);
}
}]);
return Tooltip;
}(Component);
Tooltip.propTypes = {
children: PropTypes.node.isRequired,
tooltip: PropTypes.string.isRequired,
delay: PropTypes.number,
disabled: PropTypes.bool,
align: PropTypes.oneOf(['left', 'right', 'top', 'bottom']),
className: PropTypes.string,
tooltipContainerClass: PropTypes.string
};
Tooltip.defaultProps = {
align: 'top',
disabled: false,
delay: 0,
className: '',
tooltipContainerClass: ''
};
export default Tooltip;