Files
coriolis/src/app/components/Tooltip.jsx
2017-04-21 16:07:41 +01:00

132 lines
3.4 KiB
JavaScript

import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
/**
* Document Root Tooltip
*/
export default class Tooltip extends TranslatedComponent {
static propTypes = {
rect: PropTypes.object.isRequired,
options: PropTypes.object
};
static defaultProps = {
options: {}
};
/**
* Constructor
* @param {Object} props React Component properties
*/
constructor(props) {
super(props);
this._adjustDimensions = this._adjustDimensions.bind(this);
this.state = this._initialDimensions(props);
}
/**
* Get position and reset width/height
* @param {Object} props React Component properties
* @return {Object} Dimenions / state
*/
_initialDimensions(props) {
let { options, rect } = props;
let orientation = options.orientation || 'n';
let top, left;
switch (orientation) {
case 's':
top = Math.round(rect.top + rect.height);
left = Math.round(rect.left + (rect.width / 2));
break;
case 'n':
top = Math.round(rect.top);
left = Math.round(rect.left + (rect.width / 2));
break;
case 'e':
top = Math.round(rect.top + (rect.height / 2));
left = Math.round(rect.left + rect.width);
break;
case 'w':
top = Math.round(rect.top + (rect.height / 2));
left = Math.round(rect.left);
}
return { top, left, arrLeft: left, width: null, height: null, orientation };
}
/**
* Adjusts the position and size of the tooltip if its content
* appear outside of the windows left or right border
* @param {DomElement} elem Tooltip contents container
*/
_adjustDimensions() {
if (this.elem) {
let o = this.state.orientation;
let rect = this.elem.getBoundingClientRect();
// Round widthand height to nearest even number to avoid translate3d text blur
// caused by fractional pixels
let width = Math.ceil(rect.width / 2) * 2;
this.setState({
width,
height: Math.round(rect.height / 2) * 2
});
if (o == 'n' || o == 's') {
let docWidth = document.documentElement.clientWidth;
if (rect.left < 0) {
this.setState({ left: Math.round(width / 4) * 2 });
} else if ((rect.left + width) > docWidth) {
this.setState({ left: docWidth - Math.round(width / 4) * 2 });
}
}
}
}
/**
*Potentially adjust component dimensions after mount
*/
componentDidMount() {
this._adjustDimensions();
}
/**
* Reset width and height on propChange
* @param {Object} nextProps Incoming/Next properties
*/
componentWillReceiveProps(nextProps) {
this.setState(this._initialDimensions(nextProps));
}
/**
* Potentially adjust component dimensions on re-render
*/
componentDidUpdate() {
this._adjustDimensions();
}
/**
* Renders the component
* @return {React.Component} Tooltip
*/
render() {
if (!this.props.children) { // If no content is provided
return null;
}
let { top, left, arrLeft, width, height, orientation } = this.state;
return <div style={{ fontSize: this.context.sizeRatio + 'em' }}>
<div className={ 'arr ' + orientation} style={{ top, left: arrLeft }} />
<div className={ 'tip ' + orientation} style={{ top, left, width, height }} ref={(elem) => this.elem = elem}>
{this.props.children}
</div>
</div>;
}
}