eliseumds
6/14/2016 - 7:52 PM

<ElementQuery

<ElementQuery

import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import isNumber from 'lodash/isNumber';
import elementResizeDetector from 'element-resize-detector';

let erd;

if (__CLIENT__) {
  erd = elementResizeDetector({
    strategy: 'scroll'
  });
}

export default class ElementQuery extends Component {
  static propTypes = {
    minWidth: PropTypes.number,
    maxWidth: PropTypes.number,
    minHeight: PropTypes.number,
    maxHeight: PropTypes.number,
    children: PropTypes.any,
    // "values" are used for server-side rendering
    values: PropTypes.shape({
      width: PropTypes.number,
      height: PropTypes.number
    })
  };

  componentDidMount() {
    this.$parent = ReactDOM.findDOMNode(this).parentElement;
    erd.listenTo(this.$parent, this.onResize.bind(this));
  }

  componentWillUnmount() {
    erd.removeAllListeners(this.$parent);
    erd.uninstall(this.$parent);
  }

  onResize() {
    this.forceUpdate();
  }

  isInsideRange(value, min, max) {
    return (isNumber(min) ? value >= min : true) &&
           (isNumber(max) ? value <= max : true);
  }

  matchesRules() {
    const { values, minWidth, maxWidth, minHeight, maxHeight } = this.props;

    if (__SERVER__ && values) {
      return this.isInsideRange(values.width, minWidth, maxWidth) &&
             this.isInsideRange(values.height, minHeight, maxHeight);
    }

    // TODO: should we always show the elements by default on the server?
    if (!this.$parent) {
      return true;
    }

    const width = this.$parent.offsetWidth;
    const height = this.$parent.offsetHeight;

    return this.isInsideRange(width, minWidth, maxWidth) &&
           this.isInsideRange(height, minHeight, maxHeight);
  }

  render() {
    if (this.matchesRules()) {
      return this.props.children;
    }

    return <span />;
  }
}