/* eslint-disable jsx-a11y/no-static-element-interactions, react/no-unused-prop-types */
import React from 'react';

class Ellipsify extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      visible: false,
      content: []
    };

    this.show = this.show.bind(this);
  }
  componentWillReceiveProps(nextProps) {
    this.setState({
      visible: nextProps.visible,
      content: ellipsify(nextProps)
    });
  }
  componentWillMount() {
    this.setState({
      content: ellipsify(this.props)
    });
  }
  render() {
    const visible = this.state.visible;
    const atFront = this.props.atFront;

    if (visible) {
      return <div>{this.props.children}</div>;
    }

    const content = this.state.content;
    const more = (
      <div key="more" className={this.props.moreClass} onClick={this.show}>
        {this.props.more ? this.props.more : '…'}
      </div>
    );

    return <div>{atFront ? [more, content] : [content, more]}</div>;
  }
  show() {
    this.setState({
      visible: true,
      content: this.props.children
    });

    this.props.onShow();
  }
}
Ellipsify.propTypes = {
  visible: React.PropTypes.bool,
  visibleItems: React.PropTypes.number,
  separator: React.PropTypes.string,
  more: React.PropTypes.node,
  moreClass: React.PropTypes.string,
  atFront: React.PropTypes.bool,
  onShow: React.PropTypes.func,
  children: React.PropTypes.node
};
Ellipsify.defaultProps = {
  visible: false,
  visibleItems: 5,
  separator: ' ',
  atFront: false,
  onShow: noop,
  moreClass: 'more'
};

function ellipsify(options) {
  const traverse = options.atFront ? ellipsifyFromBack : ellipsifyFromFront;

  return traverse(options, options.children, {
    visible: 0
  });
}

function ellipsifyFromFront(options, children, memo) {
  const ret = [];

  React.Children.forEach(children, (child, i) => {
    const grandChildren = child && child.props && child.props.children;

    if (grandChildren) {
      const newChildren = ellipsifyFromFront(options, grandChildren, memo);

      if (newChildren && newChildren.length) {
        ret.push(
          React.cloneElement(child, { key: `child-${i}` }, newChildren)
        );
      }
    } else {
      const partsLeft = options.visibleItems - memo.visible;

      if (!partsLeft) {
        return;
      }

      const parts = child.split(options.separator);
      const len = parts.length;

      // longer section than parts left, go to zero and slice
      if (len > partsLeft) {
        // slice + combine, memo to max
        memo.visible = options.visibleItems; // eslint-disable-line no-param-reassign

        const extra = parts[0] ? 0 : 1;

        ret.push(parts.slice(0, partsLeft + extra).join(options.separator));
      } else if (len) { // excess parts left, add to memo and return whole
        memo.visible += len; // eslint-disable-line no-param-reassign

        ret.push(parts.join(options.separator));
      }
    }
  });

  return ret;
}

function ellipsifyFromBack(options, children, memo) {
  const ret = [];

  React.Children.forEach(children, (originalChild, i) => {
    const child = Array.isArray(children) ? children[children.length - i - 1] : originalChild;
    const grandChildren = child && child.props && child.props.children;

    if (grandChildren) {
      const newChildren = ellipsifyFromBack(options, grandChildren, memo);

      if (newChildren && newChildren.length) {
        ret.unshift(
          React.cloneElement(child, { key: `child-${i}` }, newChildren)
        );
      }
    } else {
      const partsLeft = options.visibleItems - memo.visible;

      if (!partsLeft) {
        return;
      }

      const parts = child.split(options.separator);
      const len = parts.length;

      // longer section than parts left, slice from the end
      if (len > partsLeft) {
        // slice + combine, memo to max
        memo.visible = options.visibleItems; // eslint-disable-line no-param-reassign

        ret.push(parts.slice(-partsLeft).join(options.separator));
      } else if (len) { // excess parts left, add to memo and return whole
        memo.visible += len; // eslint-disable-line no-param-reassign

        ret.push(parts.join(options.separator));
      }
    }
  });

  return ret;
}

function noop() {}

export default Ellipsify;

@@ -115,14 +115,14 @@
 ;%0A%0Ac
-lass E
+onst e
 llip
@@ -130,518 +130,118 @@
 ify 
-extends React.Component %7B%0A  constructor(props) %7B%0A    super(props);%0A%0A    this.state = %7B%0A      visible: false,%0A      content: %5B%5D%0A    %7D;%0A%0A    this.show = this.show.bind(this);%0A  %7D%0A  componentWillReceiveProps(nextProps) %7B%0A    this.setState(%7B%0A      visible: nextProps.visible,%0A      content: ellipsify(nextProps)%0A    %7D);%0A  %7D%0A  componentWillMount() %7B%0A    this.setState(%7B%0A      content: ellipsify(this.props)%0A    %7D);%0A  %7D%0A  render() %7B%0A    const visible = this.state.visible;%0A    const atFront = this.props.atFront;%0A%0A  
+= (%7B%0A  visible, visibleItems,%0A  separator,%0A  more = '%E2%80%A6',%0A  moreClass,%0A  atFront,%0A  onShow,%0A  children%0A%7D) =%3E %7B%0A
   if
@@ -253,26 +253,24 @@
 ible) %7B%0A    
-  
 return %3Cdiv%3E
@@ -270,27 +270,16 @@
 n %3Cdiv%3E%7B
-this.props.
 children
@@ -291,57 +291,13 @@
 v%3E;%0A
-  
   %7D%0A%0A
-    const content = this.state.content;%0A  
   co
@@ -310,16 +310,8 @@
 re =
- (%0A     
  %3Cdi
@@ -334,27 +334,16 @@
 ssName=%7B
-this.props.
 moreClas
@@ -358,93 +358,134 @@
 ck=%7B
-this.show%7D%3E%0A        %7Bthis.props.more ? this.props.more : '%E2%80%A6'%7D%0A      %3C/div%3E%0A    
+onShow%7D%3E%7Bmore%7D%3C/div%3E;%0A%0A  const content = ellipsifyContent(%7B%0A    atFront,%0A    children,%0A    visibleItems,%0A    separator%0A  %7D
 );%0A%0A
-  
   re
@@ -551,140 +551,13 @@
 v%3E;%0A
-  %7D%0A  show() %7B%0A    this.setState(%7B%0A      visible: true,%0A      content: this.props.children%0A    %7D);%0A%0A    this.props.onShow();%0A  %7D%0A%7D%0AE
+%7D;%0A%0Ae
 llip
@@ -853,17 +853,17 @@
 node%0A%7D;%0A
-E
+e
 llipsify
@@ -1011,16 +1011,23 @@
 llipsify
+Content
 (options

Use stateless function style