gabrielbull/react-tether2

View on GitHub
src/overflow.js

Summary

Maintainability
B
4 hrs
Test Coverage
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import tether from './index';

@tether(
  function (ownProps) {
    return {
      target: typeof ownProps.target === 'function' ? ownProps.target() : ownProps.target,
      attachment: ownProps.attachment,
      targetAttachment: ownProps.targetAttachment,
      constraints: [
        {
          to: 'scrollParent',
          attachment: 'none'
        }
      ]
    }
  },
  function (state) {
    return { outOfBoundsBottom: state.outOfBoundsBottom ? true : false };
  }
)
class Overflow extends Component {
  static propTypes = {
    target: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
    attachment: PropTypes.string,
    targetAttachment: PropTypes.string
  };

  static defaultProps = {
    attachment: 'top left',
    targetAttachment: 'bottom left'
  };

  originalHeight;

  constructor() {
    super();
    this.state = { outOfBoundsBottom : false, height: null };
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.outOfBoundsBottom) {
      const rect = ReactDOM.findDOMNode(this).getBoundingClientRect();
      if (!this.originalHeight) this.originalHeight = rect.height;
      if (rect.top + this.originalHeight > document.documentElement.clientHeight) {
        const height = document.documentElement.clientHeight - rect.top;
        this.setState({ height });
      }
    } else {
      this.setState({ height: null });
    }
  }

  render() {
    const { style, children, ...props } = this.props;
    const componentStyle = {
      ...style,
      overflow: 'scroll'
    };

    if (this.state.height) {
      componentStyle.height = this.state.height + 'px';
    }

    delete props.target;
    delete props.attachment;
    delete props.targetAttachment;
    delete props.outOfBoundsBottom;
    delete props.constraints;

    return (
      <div style={componentStyle} {...props}>
        {children}
      </div>
    );
  }
}

export default Overflow;