Files
optolith-client/js/components/Overlay.js
T

133 lines
3.0 KiB
JavaScript

import React, { Component, PropTypes } from 'react';
import classNames from 'classnames';
export default class Overlay extends Component {
static propTypes = {
className: PropTypes.string,
margin: PropTypes.number,
position: PropTypes.oneOf(['top', 'bottom', 'left', 'right']),
trigger: PropTypes.any
};
static defaultProps = {
margin: 0
};
state = {
style: {},
position: ''
};
alignToElement = () => {
const { margin, position, trigger } = this.props;
const overlay = this.refs.overlay;
const triggerCoordinates = trigger.getBoundingClientRect();
const overlayCoordinates = overlay.getBoundingClientRect();
var top,
left;
const setHorizonally = () => {
left = Math.max(0, triggerCoordinates.left + triggerCoordinates.width / 2 - overlayCoordinates.width / 2);
let right = window.innerWidth - overlayCoordinates.width - left;
if (right < 0) {
left = Math.max(left, left + right);
}
};
const setForTop = () => {
top = triggerCoordinates.top - overlayCoordinates.height - margin;
setHorizonally();
};
const setForBottom = () => {
top = triggerCoordinates.top + triggerCoordinates.height + margin;
setHorizonally();
};
const setVertically = () => {
top = Math.max(0, triggerCoordinates.top + triggerCoordinates.height / 2 - overlayCoordinates.height / 2);
let bottom = window.innerHeight - overlayCoordinates.height - top;
if (bottom < 0) {
top = Math.max(bottom, top + bottom);
}
};
const setForLeft = () => {
top = Math.max(0, triggerCoordinates.left + triggerCoordinates.width / 2 - overlayCoordinates.width / 2);
setVertically();
};
const setForRight = () => {
top = Math.max(0, triggerCoordinates.top + triggerCoordinates.height / 2 - overlayCoordinates.height / 2);
setVertically();
};
let finalPosition = position;
switch (position) {
case 'top':
setForTop();
if (top < 0) {
setForBottom();
finalPosition = 'bottom';
}
break;
case 'bottom':
setForBottom();
if (top + overlayCoordinates.height + margin > window.innerHeight) {
setForTop();
finalPosition = 'top';
}
break;
case 'left':
setForLeft();
if (left < 0) {
setForRight();
finalPosition = 'right';
}
break;
case 'right':
setForRight();
if (left + overlayCoordinates.width + margin > window.innerWidth) {
setForLeft();
finalPosition = 'left';
}
break;
}
this.setState({
style: { top, left },
position: finalPosition
});
};
componentDidMount() {
this.alignToElement();
}
render() {
let { children, className, ...other } = this.props;
let { position, style } = this.state;
className = classNames(this.props.className, {
'overlay': true,
['overlay-' + position]: true
});
delete other.margin;
delete other.node;
delete other.position;
delete other.trigger;
let newOther = { ...other, style };
return (
<div {...newOther} className={className} ref="overlay">
{children}
</div>
);
}
}