huge-table
Version:
Table component to handle huge sets of data, based on Facebook's FixedDataTable
94 lines (82 loc) • 2.85 kB
JavaScript
import React from 'react';
import Portal from 'react-portal';
import PropTypes from 'prop-types';
export default class OverflowExpander extends React.Component {
static propTypes = {
availableWidth: PropTypes.number.isRequired,
children: PropTypes.any,
}
constructor(props) {
super(props);
this.state = {
doesOverflow: false,
showPopover: false,
};
}
componentDidMount() {
this.setState({ //eslint-disable-line react/no-did-mount-set-state
doesOverflow: this.doesOverflow(),
});
}
componentDidUpdate(prevProps, prevState) {
const doesOverflow = this.doesOverflow();
if (prevState.doesOverflow !== doesOverflow) {
this.setState({ //eslint-disable-line react/no-did-update-set-state
doesOverflow,
});
}
}
doesOverflow = () => {
const size = this.refs.measure.clientWidth;
return size >= this.props.availableWidth;
}
handleMouseEnter = (e) => {
const clientRect = e.target.getBoundingClientRect();
const docWidth = document.body.getBoundingClientRect().width;
const leftSide = clientRect.left + this.props.availableWidth > docWidth / 2;
const arrowWidth = 11;
this.setState({
showPopover: true,
popoverAnchorLeft: leftSide ? 'auto' : clientRect.left + this.props.availableWidth,
popoverAnchorRight: leftSide ? docWidth - clientRect.left + arrowWidth : 'auto',
popoverAnchorTop: (clientRect.top + clientRect.bottom) / 2,
popoverSide: leftSide ? 'left' : 'right',
});
}
handleMouseLeave = () => {
this.setState({
showPopover: false,
});
}
render() {
return (
<span onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} style={{
display: 'inline-block',
width: this.props.availableWidth,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}>
<span ref="measure" style={{
position: 'absolute',
visibility: 'hidden',
}}>{this.props.children}</span>
<span>{this.props.children}</span>
<Portal isOpened={!!(this.state.doesOverflow && this.state.showPopover)}>
<div className={`popover fade ${this.state.popoverSide} in`} style={{
display: 'block',
position: 'absolute',
top: this.state.popoverAnchorTop,
left: this.state.popoverAnchorLeft,
right: this.state.popoverAnchorRight,
transform: 'translateY(-50%)',
backgroundColor: '#fff',
}}>
<div className="arrow" style={{top: '50%'}}></div>
<div className="popover-content" style={{wordWrap: 'break-word', overflow: 'hidden', marginRight: '14px'}}>{this.props.children}</div>
</div>
</Portal>
</span>
);
}
}