import "core-js/modules/web.dom.iterable";
import "core-js/modules/es6.array.iterator";
import "core-js/modules/es6.object.keys";
import "core-js/modules/es6.object.assign";
import "core-js/modules/es6.regexp.match";
import "core-js/modules/es7.array.includes";
import "core-js/modules/es6.string.includes";

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }

import React from 'react';
import PropTypes from 'prop-types';
import { omit, uniqueId } from 'lodash';
/**
 * List is container component used to help group list items.
 * @category containers
 * @component list-item
 * @variations collab-ui-react
 */

var List =
/*#__PURE__*/
function (_React$Component) {
  _inheritsLoose(List, _React$Component);

  function List() {
    var _this;

    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
    _this.state = {
      activeIndex: null,
      focus: null,
      id: _this.props.id || uniqueId('cui-list-'),
      last: 0
    };

    _this.getChildContext = function () {
      return {
        setSelected: function setSelected(e, idx, value, label) {
          return _this.setSelected(e, idx, value, label);
        },
        handleListKeyDown: function handleListKeyDown(e, idx) {
          return _this.handleListKeyDown(e, idx);
        }
      };
    };

    _this.determineInitialFocus = function () {
      var nonDisabledIndex = React.Children.toArray(_this.props.children).reduceRight(function (agg, child, idx) {
        return !child.props.disabled && !child.props.isReadOnly ? idx : agg;
      }, null);

      _this.setFocus(nonDisabledIndex);
    };

    _this.setSelected = function (e, index, value, label) {
      var _this$props = _this.props,
          children = _this$props.children,
          onSelect = _this$props.onSelect;
      var activeIndex = _this.state.activeIndex;

      _this.setFocus(index); // Don't do anything if onSelect Event Handler is present


      if (onSelect) {
        return onSelect(e, value, index, label);
      } // Don't do anything if index is the same or outside of the bounds


      if (index === activeIndex || index < 0 || index >= children.length) return; // Keep reference to last index for event handler

      var last = activeIndex; // Call change event handler

      _this.setState({
        activeIndex: index,
        last: last
      });
    };

    _this.setFocus = function (index) {
      _this.setState({
        focus: index
      });
    };

    _this.getIncludesFirstCharacter = function (str, char) {
      return str.charAt(0).toLowerCase().includes(char);
    };

    _this.setFocusByFirstCharacter = function (char, currentIdx, length) {
      var children = _this.props.children;
      var newIndex = React.Children.toArray(children).reduce(function (agg, child, idx, arr) {
        var index = currentIdx + idx + 1 > length ? Math.abs(currentIdx + idx - length) : currentIdx + idx + 1;
        var label = arr[index].props.role === 'listItem' || arr[index].type.displayName === 'SelectOption' ? arr[index].props.label : arr[index].props.header;
        return !agg.length && !arr[index].props.disabled && !arr[index].props.isReadOnly && !['ListSeparator'].includes(arr[index].type.displayName) && _this.getIncludesFirstCharacter(label, char) ? agg.concat(index) : agg;
      }, []);
      !isNaN(newIndex[0]) && _this.setFocus(newIndex[0]);
    };

    _this.handleListKeyDown = function (e, idx) {
      var children = _this.props.children;
      var newIndex, clickEvent;
      var tgt = e.currentTarget;
      var char = e.key;
      var flag = false;
      var length = React.Children.toArray(children).length - 1;

      var getNewIndex = function getNewIndex(currentIndex, change) {
        var getPossibleIndex = function getPossibleIndex() {
          if (currentIndex + change < 0) {
            return length;
          } else if (currentIndex + change > length) {
            return 0;
          }

          return currentIndex + change;
        };

        var possibleIndex = getPossibleIndex();
        var potentialTarget = React.Children.toArray(_this.props.children)[possibleIndex];
        return potentialTarget.props.disabled || potentialTarget.props.isReadOnly || potentialTarget.type.displayName === "ListSeparator" ? getNewIndex(possibleIndex, change) : possibleIndex;
      };

      var isPrintableCharacter = function isPrintableCharacter(str) {
        return str.length === 1 && str.match(/\S/);
      };

      switch (e.which) {
        case 32:
        case 13:
          try {
            clickEvent = new MouseEvent('click', {
              view: window,
              bubbles: true,
              cancelable: true
            });
          } catch (err) {
            if (document.createEvent) {
              // DOM Level 3 for IE 9+
              clickEvent = document.createEvent('MouseEvents');
              clickEvent.initEvent('click', true, true);
            }
          }

          tgt.dispatchEvent(clickEvent);
          flag = true;
          break;

        case 38:
        case 37:
          newIndex = getNewIndex(idx, -1);

          _this.setFocus(newIndex);

          flag = true;
          break;

        case 39:
        case 40:
          newIndex = getNewIndex(idx, 1);

          _this.setFocus(newIndex);

          flag = true;
          break;

        case 33:
        case 36:
          _this.setFocus(0);

          flag = true;
          break;

        case 34:
        case 35:
          _this.setFocus(length);

          flag = true;
          break;

        default:
          if (isPrintableCharacter(char)) {
            _this.setFocusByFirstCharacter(char, idx, length);

            flag = true;
          }

          break;
      }

      if (flag) {
        e.stopPropagation();
        e.preventDefault();
      }
    };

    return _this;
  }

  var _proto = List.prototype;

  _proto.componentDidMount = function componentDidMount() {
    var focusFirst = this.props.focusFirst;
    focusFirst && this.determineInitialFocus();
  };

  _proto.render = function render() {
    var _this2 = this;

    var _this$props2 = this.props,
        active = _this$props2.active,
        children = _this$props2.children,
        className = _this$props2.className,
        isMulti = _this$props2.isMulti,
        itemRole = _this$props2.itemRole,
        role = _this$props2.role,
        tabType = _this$props2.tabType,
        type = _this$props2.type,
        wrap = _this$props2.wrap,
        props = _objectWithoutPropertiesLoose(_this$props2, ["active", "children", "className", "isMulti", "itemRole", "role", "tabType", "type", "wrap"]);

    var _this$state = this.state,
        activeIndex = _this$state.activeIndex,
        focus = _this$state.focus,
        id = _this$state.id;
    var visibleClass = this.context.visibleClass;
    var otherProps = omit(Object.assign({}, props), ['focusFirst']);
    var setListItems = React.Children.map(children, function (child, idx) {
      var activeIndicator = typeof active === 'number' || Array.isArray(active) ? active : activeIndex;

      switch (child.type.displayName) {
        case 'ListItem':
        case 'ListItemMeeting':
          return React.cloneElement(child, Object.assign({
            active: idx === activeIndicator
          }, type && {
            type: type
          }, {
            focus: focus === idx,
            itemIndex: idx,
            role: itemRole,
            id: id + "__list-item"
          }, focus === idx && {
            ref: function ref(_ref) {
              return _this2.activeChild = _ref;
            }
          }));

        case 'SpaceListItem':
          return React.cloneElement(child, Object.assign({
            active: idx === activeIndicator,
            focus: focus === idx,
            itemIndex: idx,
            role: itemRole,
            id: id + "__sl-item"
          }, focus === idx && {
            ref: function ref(_ref2) {
              return _this2.activeChild = _ref2;
            }
          }));

        case 'SpaceListMeeting':
          return React.cloneElement(child, Object.assign({
            active: idx === activeIndicator,
            focus: focus === idx,
            itemIndex: idx,
            role: itemRole,
            id: id + "__sl-item"
          }, focus === idx && {
            ref: function ref(_ref3) {
              return _this2.activeChild = _ref3;
            }
          }));

        case 'SelectOption':
          return React.cloneElement(child, Object.assign({
            active: Array.isArray(activeIndicator) ? activeIndicator.includes(idx) : idx === activeIndicator,
            focus: focus === idx,
            itemIndex: idx,
            role: itemRole,
            isMulti: isMulti,
            id: id + "__so-item"
          }, focus === idx && {
            ref: function ref(_ref4) {
              return _this2.activeChild = _ref4;
            }
          }));

        default:
          return child;
      }
    });
    var ActiveDescendantId = this.activeChild && this.activeChild.id;
    /* eslint-disable jsx-a11y/aria-activedescendant-has-tabindex */

    return React.createElement("div", _extends({
      className: 'cui-list' + (" cui-list" + (tabType && "--" + tabType || '')) + (" cui-list" + (wrap && "--wrap" || '')) + ("" + (visibleClass && " " + visibleClass || '')) + ("" + (className && " " + className || '')),
      role: role,
      "aria-activedescendant": ActiveDescendantId
    }, otherProps), setListItems);
    /* eslint-enable*/
  };

  return List;
}(React.Component);

List.childContextTypes = {
  setSelected: PropTypes.func,
  handleListKeyDown: PropTypes.func
};
List.propTypes = {
  /** @prop Optional active prop to pass active prop to children | null */
  active: PropTypes.oneOfType([PropTypes.number, PropTypes.array]),

  /** @prop Children nodes to render inside List | null */
  children: PropTypes.node,

  /** @prop Optional css class string | '' */
  className: PropTypes.string,

  /** @prop Sets first List item to have focus | true */
  focusFirst: PropTypes.bool,

  /** @prop Optional ID value of List | null */
  id: PropTypes.string,

  /** @prop Optional prop to know if multiple children can be active | false */
  isMulti: PropTypes.bool,

  /** @prop Optional tabType prop type to manually set child role | 'listItem' */
  itemRole: PropTypes.string,

  /** @prop Callback function invoked by user selecting an interactive item within List | null */
  onSelect: PropTypes.func,

  /** @prop Sets the ARIA role for the Nav, in the context of a TabContainer | 'list' */
  role: PropTypes.string,

  /** @prop Sets the orientation of the List | 'vertical' */
  tabType: PropTypes.oneOf(['vertical', 'horizontal']),

  /** @prop Sets List size | null */
  type: PropTypes.oneOf(['small', 'large', 'space', 'xlarge']),

  /** @prop Optional wrap prop type to wrap items to next row */
  wrap: PropTypes.bool
};
List.defaultProps = {
  active: null,
  children: null,
  className: '',
  id: null,
  isMulti: false,
  itemRole: 'listItem',
  focusFirst: true,
  onSelect: null,
  role: 'list',
  tabType: 'vertical',
  type: null,
  wrap: false
};
List.contextTypes = {
  visibleClass: PropTypes.string
};
List.displayName = 'List';
export default List;