/**
 * Bundle of @devexpress/dx-react-core
 * Generated: 2017-11-10
 * Version: 1.0.0-beta.1
 * License: https://js.devexpress.com/Licensing
 */

(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('prop-types'), require('@devexpress/dx-core'), require('react-dom')) :
	typeof define === 'function' && define.amd ? define(['exports', 'react', 'prop-types', '@devexpress/dx-core', 'react-dom'], factory) :
	(factory((global.DevExpress = global.DevExpress || {}, global.DevExpress.DXReactCore = {}),global.React,global.PropTypes,global.DevExpress.DXCore,global.ReactDOM));
}(this, (function (exports,React,PropTypes,dxCore,reactDom) { 'use strict';

React = React && React.hasOwnProperty('default') ? React['default'] : React;
PropTypes = PropTypes && PropTypes.hasOwnProperty('default') ? PropTypes['default'] : PropTypes;

var asyncGenerator = function () {
  function AwaitValue(value) {
    this.value = value;
  }

  function AsyncGenerator(gen) {
    var front, back;

    function send(key, arg) {
      return new Promise(function (resolve, reject) {
        var request = {
          key: key,
          arg: arg,
          resolve: resolve,
          reject: reject,
          next: null
        };

        if (back) {
          back = back.next = request;
        } else {
          front = back = request;
          resume(key, arg);
        }
      });
    }

    function resume(key, arg) {
      try {
        var result = gen[key](arg);
        var value = result.value;

        if (value instanceof AwaitValue) {
          Promise.resolve(value.value).then(function (arg) {
            resume("next", arg);
          }, function (arg) {
            resume("throw", arg);
          });
        } else {
          settle(result.done ? "return" : "normal", result.value);
        }
      } catch (err) {
        settle("throw", err);
      }
    }

    function settle(type, value) {
      switch (type) {
        case "return":
          front.resolve({
            value: value,
            done: true
          });
          break;

        case "throw":
          front.reject(value);
          break;

        default:
          front.resolve({
            value: value,
            done: false
          });
          break;
      }

      front = front.next;

      if (front) {
        resume(front.key, front.arg);
      } else {
        back = null;
      }
    }

    this._invoke = send;

    if (typeof gen.return !== "function") {
      this.return = undefined;
    }
  }

  if (typeof Symbol === "function" && Symbol.asyncIterator) {
    AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
      return this;
    };
  }

  AsyncGenerator.prototype.next = function (arg) {
    return this._invoke("next", arg);
  };

  AsyncGenerator.prototype.throw = function (arg) {
    return this._invoke("throw", arg);
  };

  AsyncGenerator.prototype.return = function (arg) {
    return this._invoke("return", arg);
  };

  return {
    wrap: function (fn) {
      return function () {
        return new AsyncGenerator(fn.apply(this, arguments));
      };
    },
    await: function (value) {
      return new AwaitValue(value);
    }
  };
}();





var classCallCheck = function (instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
};

var createClass = function () {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  return function (Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps);
    return Constructor;
  };
}();





var defineProperty = function (obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    });
  } else {
    obj[key] = value;
  }

  return obj;
};

var _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;
};



var inherits = function (subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
  }

  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
  if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
};











var possibleConstructorReturn = function (self, call) {
  if (!self) {
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  }

  return call && (typeof call === "object" || typeof call === "function") ? call : self;
};





var slicedToArray = function () {
  function sliceIterator(arr, i) {
    var _arr = [];
    var _n = true;
    var _d = false;
    var _e = undefined;

    try {
      for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
        _arr.push(_s.value);

        if (i && _arr.length === i) break;
      }
    } catch (err) {
      _d = true;
      _e = err;
    } finally {
      try {
        if (!_n && _i["return"]) _i["return"]();
      } finally {
        if (_d) throw _e;
      }
    }

    return _arr;
  }

  return function (arr, i) {
    if (Array.isArray(arr)) {
      return arr;
    } else if (Symbol.iterator in Object(arr)) {
      return sliceIterator(arr, i);
    } else {
      throw new TypeError("Invalid attempt to destructure non-iterable instance");
    }
  };
}();













var toConsumableArray = function (arr) {
  if (Array.isArray(arr)) {
    for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];

    return arr2;
  } else {
    return Array.from(arr);
  }
};

var getActionExecutor = function getActionExecutor(pluginHost, actionToExecuteName) {
  var actionsToExecute = pluginHost.collect(actionToExecuteName + 'Action').slice().reverse();
  return function (startingPayload) {
    var payload = startingPayload;
    // eslint-disable-next-line no-use-before-define

    var _getAvaliableGetters = getAvaliableGetters(pluginHost),
        getters = _getAvaliableGetters.getters;
    // eslint-disable-next-line no-use-before-define


    var actions = getAvaliableActions(pluginHost, function (actionName) {
      return actionName === actionToExecuteName ? function (newPayload) {
        payload = newPayload;
      } : getActionExecutor(pluginHost, actionName);
    });
    for (var i = 0; i < actionsToExecute.length; i += 1) {
      var result = actionsToExecute[i](payload, getters, actions);
      if (result === false) {
        break;
      }
    }
  };
};

var getAvaliableGetters = function getAvaliableGetters(pluginHost) {
  var getGetterValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function (getterName) {
    return pluginHost.get(getterName + 'Getter');
  };

  var trackedDependencies = {};
  var getters = pluginHost.knownKeys('Getter').reduce(function (acc, getterName) {
    Object.defineProperty(acc, getterName, {
      get: function get$$1() {
        var result = getGetterValue(getterName);
        trackedDependencies[getterName] = result;
        return result;
      }
    });
    return acc;
  }, {});

  return { getters: getters, trackedDependencies: trackedDependencies };
};

var isTrackedDependenciesChanged = function isTrackedDependenciesChanged(pluginHost, prevTrackedDependencies) {
  var getGetterValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function (getterName) {
    return pluginHost.get(getterName + 'Getter');
  };

  var trackedDependencies = Object.keys(prevTrackedDependencies).reduce(function (acc, getterName) {
    return Object.assign(acc, defineProperty({}, getterName, getGetterValue(getterName)));
  }, {});

  return !dxCore.shallowEqual(prevTrackedDependencies, trackedDependencies);
};

var getAvaliableActions = function getAvaliableActions(pluginHost) {
  var getAction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function (actionName) {
    return getActionExecutor(pluginHost, actionName);
  };
  return pluginHost.knownKeys('Action').reduce(function (acc, actionName) {
    Object.defineProperty(acc, actionName, {
      get: function get$$1() {
        return getAction(actionName);
      }
    });
    return acc;
  }, {});
};

var UPDATE_CONNECTION = 'updateConnection';

var Getter = function (_React$PureComponent) {
  inherits(Getter, _React$PureComponent);

  function Getter() {
    classCallCheck(this, Getter);
    return possibleConstructorReturn(this, (Getter.__proto__ || Object.getPrototypeOf(Getter)).apply(this, arguments));
  }

  createClass(Getter, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      var _this2 = this;

      var pluginHost = this.context.pluginHost;
      var name = this.props.name;


      var lastComputed = void 0;
      var lastTrackedDependencies = {};
      var lastResult = void 0;

      this.plugin = defineProperty({
        position: function position() {
          return _this2.props.position();
        }
      }, name + 'Getter', function (_undefined) {
        function undefined(_x) {
          return _undefined.apply(this, arguments);
        }

        undefined.toString = function () {
          return _undefined.toString();
        };

        return undefined;
      }(function (original) {
        var _props = _this2.props,
            value = _props.value,
            computed = _props.computed;

        if (value !== undefined) return value;

        var getGetterValue = function getGetterValue(getterName) {
          return getterName === name ? original : pluginHost.get(getterName + 'Getter', _this2.plugin);
        };

        if (computed === lastComputed && !isTrackedDependenciesChanged(pluginHost, lastTrackedDependencies, getGetterValue)) {
          return lastResult;
        }

        var _getAvaliableGetters = getAvaliableGetters(pluginHost, getGetterValue),
            getters = _getAvaliableGetters.getters,
            trackedDependencies = _getAvaliableGetters.trackedDependencies;

        var actions = getAvaliableActions(pluginHost);

        lastComputed = computed;
        lastTrackedDependencies = trackedDependencies;
        lastResult = computed(getters, actions);
        return lastResult;
      }));

      pluginHost.registerPlugin(this.plugin);
    }
  }, {
    key: 'componentDidUpdate',
    value: function componentDidUpdate() {
      var pluginHost = this.context.pluginHost;


      pluginHost.broadcast(UPDATE_CONNECTION);
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      var pluginHost = this.context.pluginHost;


      pluginHost.unregisterPlugin(this.plugin);
    }
  }, {
    key: 'render',
    value: function render() {
      return null;
    }
  }]);
  return Getter;
}(React.PureComponent);

Getter.propTypes = {
  position: PropTypes.func,
  name: PropTypes.string.isRequired,
  value: PropTypes.any,
  computed: PropTypes.func
};

Getter.defaultProps = {
  value: undefined,
  computed: null,
  position: null
};

Getter.contextTypes = {
  pluginHost: PropTypes.object.isRequired
};

var Action = function (_React$PureComponent) {
  inherits(Action, _React$PureComponent);

  function Action() {
    classCallCheck(this, Action);
    return possibleConstructorReturn(this, (Action.__proto__ || Object.getPrototypeOf(Action)).apply(this, arguments));
  }

  createClass(Action, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      var _this2 = this;

      var pluginHost = this.context.pluginHost;
      var name = this.props.name;


      this.plugin = defineProperty({
        position: function position() {
          return _this2.props.position();
        }
      }, name + 'Action', function undefined(params, getters, actions) {
        var action = _this2.props.action;

        action(params, getters, actions);
      });

      pluginHost.registerPlugin(this.plugin);
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      var pluginHost = this.context.pluginHost;


      pluginHost.unregisterPlugin(this.plugin);
    }
  }, {
    key: 'render',
    value: function render() {
      return null;
    }
  }]);
  return Action;
}(React.PureComponent);

Action.propTypes = {
  position: PropTypes.func,
  name: PropTypes.string.isRequired,
  action: PropTypes.func.isRequired
};

Action.defaultProps = {
  position: null
};

Action.contextTypes = {
  pluginHost: PropTypes.object.isRequired
};

var RERENDER_TEMPLATE = 'rerenderTemplate';

var globalTemplateId = 0;
var Template = function (_React$PureComponent) {
  inherits(Template, _React$PureComponent);

  function Template(props, context) {
    classCallCheck(this, Template);

    var _this = possibleConstructorReturn(this, (Template.__proto__ || Object.getPrototypeOf(Template)).call(this, props, context));

    globalTemplateId += 1;
    _this.id = globalTemplateId;
    return _this;
  }

  createClass(Template, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      var _this2 = this;

      var pluginHost = this.context.pluginHost;
      var name = this.props.name;


      this.plugin = defineProperty({
        position: function position() {
          return _this2.props.position();
        }
      }, name + 'Template', {
        id: this.id,
        predicate: function predicate(params) {
          return _this2.props.predicate ? _this2.props.predicate(params) : true;
        },
        children: function children() {
          return _this2.props.children;
        }
      });
      pluginHost.registerPlugin(this.plugin);
    }
  }, {
    key: 'componentDidUpdate',
    value: function componentDidUpdate() {
      var pluginHost = this.context.pluginHost;

      pluginHost.broadcast(RERENDER_TEMPLATE, this.id);
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      var pluginHost = this.context.pluginHost;

      pluginHost.unregisterPlugin(this.plugin);
    }
  }, {
    key: 'render',
    value: function render() {
      return null;
    }
  }]);
  return Template;
}(React.PureComponent);

Template.propTypes = {
  position: PropTypes.func,
  name: PropTypes.string.isRequired,
  predicate: PropTypes.func,
  children: PropTypes.oneOfType([PropTypes.func, PropTypes.node])
};

Template.defaultProps = {
  predicate: null,
  children: null,
  position: null
};

Template.contextTypes = {
  pluginHost: PropTypes.object.isRequired
};

var PluginIndexer = function PluginIndexer(_ref, _ref2) {
  var children = _ref.children;
  var positionContext = _ref2.positionContext;
  return React.createElement(
    'div',
    { style: { display: 'none' } },
    React.Children.map(children, function (child, index) {
      if (!child || !child.type) return child;

      var childPosition = function childPosition() {
        var calculatedPosition = positionContext && positionContext() || [];
        return [].concat(toConsumableArray(calculatedPosition), [index]);
      };

      if (child.type === Getter || child.type === Action || child.type === Template) {
        return React.cloneElement(child, { position: childPosition });
      }

      return React.createElement(
        PluginIndexerContext,
        { position: childPosition },
        child
      );
    })
  );
};

PluginIndexer.propTypes = {
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])
};

PluginIndexer.defaultProps = {
  children: null
};

PluginIndexer.contextTypes = {
  positionContext: PropTypes.func
};

var PluginIndexerContext = function (_React$Component) {
  inherits(PluginIndexerContext, _React$Component);

  function PluginIndexerContext() {
    classCallCheck(this, PluginIndexerContext);
    return possibleConstructorReturn(this, (PluginIndexerContext.__proto__ || Object.getPrototypeOf(PluginIndexerContext)).apply(this, arguments));
  }

  createClass(PluginIndexerContext, [{
    key: 'getChildContext',
    value: function getChildContext() {
      return {
        positionContext: this.props.position
      };
    }
  }, {
    key: 'render',
    value: function render() {
      return this.props.children;
    }
  }]);
  return PluginIndexerContext;
}(React.Component);

PluginIndexerContext.propTypes = {
  position: PropTypes.func.isRequired,
  children: PropTypes.node.isRequired
};

PluginIndexerContext.childContextTypes = {
  positionContext: PropTypes.func
};

var TemplatePlaceholder = function (_React$Component) {
  inherits(TemplatePlaceholder, _React$Component);

  function TemplatePlaceholder(props, context) {
    classCallCheck(this, TemplatePlaceholder);

    var _this = possibleConstructorReturn(this, (TemplatePlaceholder.__proto__ || Object.getPrototypeOf(TemplatePlaceholder)).call(this, props, context));

    _this.subscription = defineProperty({}, RERENDER_TEMPLATE, function (id) {
      if (_this.template && _this.template.id === id) {
        _this.forceUpdate();
      }
    });
    return _this;
  }

  createClass(TemplatePlaceholder, [{
    key: 'getChildContext',
    value: function getChildContext() {
      var _this2 = this;

      return {
        templateHost: {
          templates: function templates() {
            return _this2.restTemplates;
          },
          params: function params() {
            return _this2.params;
          }
        }
      };
    }
  }, {
    key: 'componentWillMount',
    value: function componentWillMount() {
      var pluginHost = this.context.pluginHost;

      pluginHost.registerSubscription(this.subscription);
    }
  }, {
    key: 'shouldComponentUpdate',
    value: function shouldComponentUpdate(nextProps) {
      var _getRenderingData = this.getRenderingData(nextProps),
          params = _getRenderingData.params;

      return !dxCore.shallowEqual(params, this.params) || this.props.children !== nextProps.children;
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      var pluginHost = this.context.pluginHost;

      pluginHost.unregisterSubscription(this.subscription);
    }
  }, {
    key: 'getRenderingData',
    value: function getRenderingData(props) {
      var name = props.name,
          params = props.params;

      if (name) {
        var pluginHost = this.context.pluginHost;

        return {
          params: params,
          templates: pluginHost.collect(name + 'Template').filter(function (template) {
            return template.predicate(params);
          }).reverse()
        };
      }
      var templateHost = this.context.templateHost;

      return {
        params: params || templateHost.params(),
        templates: templateHost.templates()
      };
    }
  }, {
    key: 'render',
    value: function render() {
      var _getRenderingData2 = this.getRenderingData(this.props),
          params = _getRenderingData2.params,
          templates = _getRenderingData2.templates;

      this.params = params;

      var _templates = slicedToArray(templates, 1);

      this.template = _templates[0];

      this.restTemplates = templates.slice(1);

      var content = null;
      if (this.template) {
        var templateContent = this.template.children;


        content = templateContent();
        if (content && typeof content === 'function') {
          content = content(params);
        }
      }

      var templatePlaceholder = this.props.children;

      return templatePlaceholder ? templatePlaceholder(content) : content;
    }
  }]);
  return TemplatePlaceholder;
}(React.Component);

TemplatePlaceholder.propTypes = {
  name: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
  params: PropTypes.object, // eslint-disable-line react/no-unused-prop-types
  children: PropTypes.func
};

TemplatePlaceholder.defaultProps = {
  name: undefined,
  params: undefined,
  children: undefined
};

TemplatePlaceholder.contextTypes = {
  templateHost: PropTypes.object,
  pluginHost: PropTypes.object.isRequired
};

TemplatePlaceholder.childContextTypes = {
  templateHost: PropTypes.object.isRequired
};

var PluginHost$1 = function (_React$PureComponent) {
  inherits(PluginHost$$1, _React$PureComponent);

  function PluginHost$$1(props) {
    classCallCheck(this, PluginHost$$1);

    var _this = possibleConstructorReturn(this, (PluginHost$$1.__proto__ || Object.getPrototypeOf(PluginHost$$1)).call(this, props));

    _this.host = new dxCore.PluginHost();
    return _this;
  }

  createClass(PluginHost$$1, [{
    key: 'getChildContext',
    value: function getChildContext() {
      return {
        pluginHost: this.host
      };
    }
  }, {
    key: 'render',
    value: function render() {
      var children = this.props.children;


      return React.createElement(
        'div',
        null,
        React.createElement(
          PluginIndexer,
          null,
          React.createElement(Template, { name: 'root' }),
          children
        ),
        React.createElement(TemplatePlaceholder, { name: 'root' })
      );
    }
  }]);
  return PluginHost$$1;
}(React.PureComponent);

PluginHost$1.propTypes = {
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])
};

PluginHost$1.defaultProps = {
  children: null
};

PluginHost$1.childContextTypes = {
  pluginHost: PropTypes.object.isRequired
};

var PluginContainer = function (_React$PureComponent) {
  inherits(PluginContainer, _React$PureComponent);

  function PluginContainer() {
    classCallCheck(this, PluginContainer);
    return possibleConstructorReturn(this, (PluginContainer.__proto__ || Object.getPrototypeOf(PluginContainer)).apply(this, arguments));
  }

  createClass(PluginContainer, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      var _context = this.context,
          pluginHost = _context.pluginHost,
          position = _context.positionContext;
      var _props = this.props,
          pluginName = _props.pluginName,
          dependencies = _props.dependencies;

      this.plugin = {
        position: position,
        pluginName: pluginName,
        dependencies: dependencies,
        container: true
      };
      pluginHost.registerPlugin(this.plugin);
    }
  }, {
    key: 'componentWillUpdate',
    value: function componentWillUpdate() {
      this.context.pluginHost.ensureDependencies();
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      var pluginHost = this.context.pluginHost;

      pluginHost.unregisterPlugin(this.plugin);
    }
  }, {
    key: 'render',
    value: function render() {
      var children = this.props.children;

      return React.createElement(
        PluginIndexer,
        null,
        children
      );
    }
  }]);
  return PluginContainer;
}(React.PureComponent);

PluginContainer.propTypes = {
  children: PropTypes.node.isRequired,
  pluginName: PropTypes.string,
  dependencies: PropTypes.arrayOf(PropTypes.shape({
    pluginName: PropTypes.string,
    optional: PropTypes.bool
  }))
};

PluginContainer.defaultProps = {
  pluginName: '',
  dependencies: []
};

PluginContainer.contextTypes = {
  pluginHost: PropTypes.object.isRequired,
  positionContext: PropTypes.func.isRequired
};

function changeDetector(watch, onChange) {
  var lastArg = null;
  return function () {
    var args = watch();
    if (lastArg === null || !dxCore.argumentsShallowEqual(lastArg, args)) {
      onChange(args);
    }
    lastArg = args;
  };
}

var Watcher = function (_React$PureComponent) {
  inherits(Watcher, _React$PureComponent);

  function Watcher(props, context) {
    classCallCheck(this, Watcher);

    var _this = possibleConstructorReturn(this, (Watcher.__proto__ || Object.getPrototypeOf(Watcher)).call(this, props, context));

    var pluginHost = context.pluginHost;

    var getter = function getter(getterName) {
      return pluginHost.get(getterName + 'Getter');
    };
    var action = function action(actionName) {
      return getActionExecutor(pluginHost, actionName);
    };
    var _this$props = _this.props,
        watch = _this$props.watch,
        onChange = _this$props.onChange;


    _this.detectChanges = changeDetector(function () {
      return watch(getter);
    }, function (args) {
      return onChange.apply(null, [action].concat(toConsumableArray(args)));
    });

    _this.subscription = defineProperty({}, UPDATE_CONNECTION, _this.detectChanges);
    return _this;
  }

  createClass(Watcher, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      var pluginHost = this.context.pluginHost;


      this.detectChanges();
      pluginHost.registerSubscription(this.subscription);
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      var pluginHost = this.context.pluginHost;


      pluginHost.unregisterSubscription(this.subscription);
    }
  }, {
    key: 'render',
    value: function render() {
      return null;
    }
  }]);
  return Watcher;
}(React.PureComponent);
Watcher.propTypes = {
  watch: PropTypes.func.isRequired,
  onChange: PropTypes.func.isRequired
};
Watcher.contextTypes = {
  pluginHost: PropTypes.object.isRequired
};

var TemplateConnector = function (_React$Component) {
  inherits(TemplateConnector, _React$Component);

  function TemplateConnector(props, context) {
    classCallCheck(this, TemplateConnector);

    var _this = possibleConstructorReturn(this, (TemplateConnector.__proto__ || Object.getPrototypeOf(TemplateConnector)).call(this, props, context));

    _this.trackedDependencies = {};
    _this.subscription = defineProperty({}, UPDATE_CONNECTION, function () {
      return _this.updateConnection();
    });
    return _this;
  }

  createClass(TemplateConnector, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      var pluginHost = this.context.pluginHost;

      pluginHost.registerSubscription(this.subscription);
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      var pluginHost = this.context.pluginHost;

      pluginHost.unregisterSubscription(this.subscription);
    }
  }, {
    key: 'updateConnection',
    value: function updateConnection() {
      var pluginHost = this.context.pluginHost;


      if (isTrackedDependenciesChanged(pluginHost, this.trackedDependencies)) {
        this.forceUpdate();
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var children = this.props.children;
      var pluginHost = this.context.pluginHost;

      var _getAvaliableGetters = getAvaliableGetters(pluginHost),
          getters = _getAvaliableGetters.getters,
          trackedDependencies = _getAvaliableGetters.trackedDependencies;

      this.trackedDependencies = trackedDependencies;
      var actions = getAvaliableActions(pluginHost);

      return children(getters, actions);
    }
  }]);
  return TemplateConnector;
}(React.Component);

TemplateConnector.propTypes = {
  children: PropTypes.func.isRequired
};

TemplateConnector.contextTypes = {
  pluginHost: PropTypes.object.isRequired
};

var TIMEOUT = 180;

var TouchStrategy = function () {
  function TouchStrategy(delegate) {
    classCallCheck(this, TouchStrategy);

    this.delegate = delegate;
    this.touchStartTimeout = null;
    this.dragging = false;
  }

  createClass(TouchStrategy, [{
    key: "start",
    value: function start(e) {
      var _this = this;

      var _e$touches$ = e.touches[0],
          x = _e$touches$.clientX,
          y = _e$touches$.clientY;

      this.touchStartTimeout = setTimeout(function () {
        _this.delegate.onStart({ x: x, y: y });
        _this.dragging = true;
      }, TIMEOUT);
    }
  }, {
    key: "move",
    value: function move(e) {
      clearTimeout(this.touchStartTimeout);
      if (this.dragging) {
        var _e$touches$2 = e.touches[0],
            clientX = _e$touches$2.clientX,
            clientY = _e$touches$2.clientY;

        e.preventDefault();
        this.delegate.onMove({ x: clientX, y: clientY });
      }
    }
  }, {
    key: "end",
    value: function end(e) {
      clearTimeout(this.touchStartTimeout);
      if (this.dragging) {
        var _e$changedTouches$ = e.changedTouches[0],
            clientX = _e$changedTouches$.clientX,
            clientY = _e$changedTouches$.clientY;

        this.delegate.onEnd({ x: clientX, y: clientY });
      }
      this.mouseInitialOffset = null;
      this.dragging = false;
    }
  }]);
  return TouchStrategy;
}();

/* globals document:true */

var gestureCover = null;
var toggleGestureCover = function toggleGestureCover(toggle, cursor) {
  var style = {
    pointerEvents: toggle ? 'all' : 'none'
  };
  if (toggle && cursor) {
    style = _extends({}, style, {
      cursor: cursor
    });
  }
  if (!gestureCover) {
    style = _extends({}, style, {
      position: 'fixed',
      top: 0,
      right: 0,
      left: 0,
      bottom: 0,
      opacity: 0,
      zIndex: 2147483647
    });

    gestureCover = document.createElement('div');
    document.body.appendChild(gestureCover);
  }
  Object.keys(style).forEach(function (key) {
    gestureCover.style[key] = style[key];
  });
};

/* globals window:true document:true */

var BOUNDARY = 10;
var clamp = function clamp(value, min, max) {
  return Math.max(Math.min(value, max), min);
};
var isBoundExceeded = function isBoundExceeded(_ref, _ref2) {
  var initialX = _ref.x,
      initialY = _ref.y;
  var x = _ref2.x,
      y = _ref2.y;
  return clamp(x, initialX - BOUNDARY, initialX + BOUNDARY) !== x || clamp(y, initialY - BOUNDARY, initialY + BOUNDARY) !== y;
};

var MouseStrategy = function () {
  function MouseStrategy(delegate) {
    classCallCheck(this, MouseStrategy);

    this.delegate = delegate;
    this.mouseInitialOffset = null;
    this.dragging = false;
  }

  createClass(MouseStrategy, [{
    key: 'start',
    value: function start(e) {
      var x = e.clientX,
          y = e.clientY;

      this.e = e;
      this.mouseInitialOffset = { x: x, y: y };
    }
  }, {
    key: 'move',
    value: function move(e) {
      var x = e.clientX,
          y = e.clientY;

      var dragStarted = false;
      if (!this.dragging && this.mouseInitialOffset) {
        if (isBoundExceeded(this.mouseInitialOffset, { x: x, y: y })) {
          this.delegate.onStart(this.mouseInitialOffset);
          if (window.getSelection) {
            window.getSelection().removeAllRanges();
          }
          dragStarted = true;
          this.dragging = true;
        }
      }
      if (this.dragging) {
        e.preventDefault();
        this.delegate.onMove({ x: x, y: y });
      }
      if (dragStarted) {
        var _window$getComputedSt = window.getComputedStyle(document.elementFromPoint(x, y)),
            cursor = _window$getComputedSt.cursor;

        toggleGestureCover(true, cursor);
      }
    }
  }, {
    key: 'end',
    value: function end(e) {
      if (this.dragging) {
        var x = e.clientX,
            y = e.clientY;

        toggleGestureCover(false);
        this.delegate.onEnd({ x: x, y: y });
      }
      this.mouseInitialOffset = null;
      this.dragging = false;
    }
  }]);
  return MouseStrategy;
}();

/* globals window:true */

var eventEmitter = null;
var getSharedEventEmitter = function getSharedEventEmitter() {
  if (!eventEmitter) {
    eventEmitter = new dxCore.EventEmitter();

    ['mousemove', 'mouseup', 'touchmove', 'touchend', 'touchcancel'].forEach(function (name) {
      return window.addEventListener(name, function (e) {
        return eventEmitter.emit([name, e]);
      }, { passive: false });
    });
  }
  return eventEmitter;
};

var touchEvents = false;
var touchEventsSupported = function touchEventsSupported() {
  if (!touchEvents) {
    touchEvents = 'ontouchstart' in window;
  }
  return touchEvents;
};

// eslint-disable-next-line camelcase
var Draggable = function (_React$Component) {
  inherits(Draggable, _React$Component);

  function Draggable(props, context) {
    classCallCheck(this, Draggable);

    var _this = possibleConstructorReturn(this, (Draggable.__proto__ || Object.getPrototypeOf(Draggable)).call(this, props, context));

    var delegate = {
      onStart: function onStart(_ref) {
        var x = _ref.x,
            y = _ref.y;
        var onStart = _this.props.onStart;

        if (!onStart) return;
        reactDom.unstable_batchedUpdates(function () {
          onStart({ x: x, y: y });
        });
      },
      onMove: function onMove(_ref2) {
        var x = _ref2.x,
            y = _ref2.y;
        var onUpdate = _this.props.onUpdate;

        if (!onUpdate) return;
        reactDom.unstable_batchedUpdates(function () {
          onUpdate({ x: x, y: y });
        });
      },
      onEnd: function onEnd(_ref3) {
        var x = _ref3.x,
            y = _ref3.y;
        var onEnd = _this.props.onEnd;

        if (!onEnd) return;
        reactDom.unstable_batchedUpdates(function () {
          onEnd({ x: x, y: y });
        });
      }
    };

    _this.mouseStrategy = new MouseStrategy(delegate);
    _this.touchStrategy = new TouchStrategy(delegate);

    _this.listener = _this.listener.bind(_this);
    return _this;
  }

  createClass(Draggable, [{
    key: 'componentDidMount',
    value: function componentDidMount() {
      getSharedEventEmitter().subscribe(this.listener);
    }
  }, {
    key: 'shouldComponentUpdate',
    value: function shouldComponentUpdate(nextProps) {
      return nextProps.children !== this.props.children;
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      getSharedEventEmitter().unsubscribe(this.listener);
    }
  }, {
    key: 'listener',
    value: function listener(_ref4) {
      var _ref5 = slicedToArray(_ref4, 2),
          name = _ref5[0],
          e = _ref5[1];

      switch (name) {
        case 'mousemove':
          this.mouseStrategy.move(e);
          break;
        case 'mouseup':
          this.mouseStrategy.end(e);
          break;
        case 'touchmove':
          {
            this.touchStrategy.move(e);
            break;
          }
        case 'touchend':
        case 'touchcancel':
          {
            this.touchStrategy.end(e);
            break;
          }
        default:
          break;
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var _this2 = this;

      return React.cloneElement(React.Children.only(this.props.children), {
        onMouseDown: function onMouseDown(e) {
          if (touchEventsSupported()) return;
          _this2.mouseStrategy.start(e);
          e.stopPropagation();
        },
        onTouchStart: function onTouchStart(e) {
          _this2.touchStrategy.start(e);
          e.stopPropagation();
        }
      });
    }
  }]);
  return Draggable;
}(React.Component);

Draggable.propTypes = {
  children: PropTypes.node.isRequired,
  onStart: PropTypes.func,
  onUpdate: PropTypes.func,
  onEnd: PropTypes.func
};

Draggable.defaultProps = {
  onStart: undefined,
  onUpdate: undefined,
  onEnd: undefined
};

var DragDropContextCore = function () {
  function DragDropContextCore() {
    classCallCheck(this, DragDropContextCore);

    this.payload = null;
    this.dragEmitter = new dxCore.EventEmitter();
  }

  createClass(DragDropContextCore, [{
    key: 'start',
    value: function start(payload, clientOffset) {
      this.payload = payload;
      this.dragEmitter.emit({ payload: this.payload, clientOffset: clientOffset });
    }
  }, {
    key: 'update',
    value: function update(clientOffset) {
      this.dragEmitter.emit({ payload: this.payload, clientOffset: clientOffset });
    }
  }, {
    key: 'end',
    value: function end(clientOffset) {
      this.dragEmitter.emit({ payload: this.payload, clientOffset: clientOffset, end: true });
      this.payload = null;
    }
  }]);
  return DragDropContextCore;
}();

var DragDropContext = function (_React$Component) {
  inherits(DragDropContext, _React$Component);

  function DragDropContext(props) {
    classCallCheck(this, DragDropContext);

    var _this = possibleConstructorReturn(this, (DragDropContext.__proto__ || Object.getPrototypeOf(DragDropContext)).call(this, props));

    _this.dragDropContext = new DragDropContextCore();

    _this.dragDropContext.dragEmitter.subscribe(function (_ref) {
      var payload = _ref.payload,
          clientOffset = _ref.clientOffset,
          end = _ref.end;

      _this.props.onChange({
        payload: end ? null : payload,
        clientOffset: end ? null : clientOffset
      });
    });
    return _this;
  }

  createClass(DragDropContext, [{
    key: 'getChildContext',
    value: function getChildContext() {
      return {
        dragDropContext: this.dragDropContext
      };
    }
  }, {
    key: 'shouldComponentUpdate',
    value: function shouldComponentUpdate(nextProps) {
      return nextProps.children !== this.props.children;
    }
  }, {
    key: 'render',
    value: function render() {
      return this.props.children;
    }
  }]);
  return DragDropContext;
}(React.Component);

DragDropContext.childContextTypes = {
  dragDropContext: PropTypes.object.isRequired
};

DragDropContext.propTypes = {
  children: PropTypes.node.isRequired,
  onChange: PropTypes.func
};

DragDropContext.defaultProps = {
  onChange: function onChange() {}
};

var DragSource = function (_React$Component) {
  inherits(DragSource, _React$Component);

  function DragSource() {
    classCallCheck(this, DragSource);
    return possibleConstructorReturn(this, (DragSource.__proto__ || Object.getPrototypeOf(DragSource)).apply(this, arguments));
  }

  createClass(DragSource, [{
    key: 'shouldComponentUpdate',
    value: function shouldComponentUpdate(nextProps) {
      return nextProps.children !== this.props.children;
    }
  }, {
    key: 'render',
    value: function render() {
      var _this2 = this;

      var dragDropContext = this.context.dragDropContext;
      var _props = this.props,
          _onStart = _props.onStart,
          _onUpdate = _props.onUpdate,
          _onEnd = _props.onEnd;

      return React.createElement(
        Draggable,
        {
          onStart: function onStart(_ref) {
            var x = _ref.x,
                y = _ref.y;

            dragDropContext.start(_this2.props.getPayload(), { x: x, y: y });
            _onStart({ clientOffset: { x: x, y: y } });
          },
          onUpdate: function onUpdate(_ref2) {
            var x = _ref2.x,
                y = _ref2.y;

            dragDropContext.update({ x: x, y: y });
            _onUpdate({ clientOffset: { x: x, y: y } });
          },
          onEnd: function onEnd(_ref3) {
            var x = _ref3.x,
                y = _ref3.y;

            dragDropContext.end({ x: x, y: y });
            _onEnd({ clientOffset: { x: x, y: y } });
          }
        },
        this.props.children
      );
    }
  }]);
  return DragSource;
}(React.Component);

DragSource.contextTypes = {
  dragDropContext: PropTypes.object.isRequired
};

DragSource.propTypes = {
  children: PropTypes.node.isRequired,
  getPayload: PropTypes.func.isRequired,
  onStart: PropTypes.func,
  onUpdate: PropTypes.func,
  onEnd: PropTypes.func
};

DragSource.defaultProps = {
  onStart: function onStart() {},
  onUpdate: function onUpdate() {},
  onEnd: function onEnd() {}
};

var clamp$1 = function clamp(value, min, max) {
  return Math.max(Math.min(value, max), min);
};

var DropTarget = function (_React$Component) {
  inherits(DropTarget, _React$Component);

  function DropTarget(props, context) {
    classCallCheck(this, DropTarget);

    var _this = possibleConstructorReturn(this, (DropTarget.__proto__ || Object.getPrototypeOf(DropTarget)).call(this, props, context));

    _this.node = null;
    _this.isOver = false;

    _this.handleDrag = _this.handleDrag.bind(_this);
    return _this;
  }

  createClass(DropTarget, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      var dragEmitter = this.context.dragDropContext.dragEmitter;

      dragEmitter.subscribe(this.handleDrag);
    }
  }, {
    key: 'shouldComponentUpdate',
    value: function shouldComponentUpdate(nextProps) {
      return nextProps.children !== this.props.children;
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      var dragEmitter = this.context.dragDropContext.dragEmitter;

      dragEmitter.unsubscribe(this.handleDrag);
    }
  }, {
    key: 'handleDrag',
    value: function handleDrag(_ref) {
      var payload = _ref.payload,
          clientOffset = _ref.clientOffset,
          end = _ref.end;

      var _findDOMNode$getBound = reactDom.findDOMNode(this).getBoundingClientRect(),
          left = _findDOMNode$getBound.left,
          top = _findDOMNode$getBound.top,
          right = _findDOMNode$getBound.right,
          bottom = _findDOMNode$getBound.bottom; // eslint-disable-line react/no-find-dom-node


      var isOver = clientOffset && clamp$1(clientOffset.x, left, right) === clientOffset.x && clamp$1(clientOffset.y, top, bottom) === clientOffset.y;

      if (!this.isOver && isOver) this.props.onEnter({ payload: payload, clientOffset: clientOffset });
      if (this.isOver && isOver) this.props.onOver({ payload: payload, clientOffset: clientOffset });
      if (this.isOver && !isOver) this.props.onLeave({ payload: payload, clientOffset: clientOffset });
      if (isOver && end) this.props.onDrop({ payload: payload, clientOffset: clientOffset });

      this.isOver = isOver && !end;
    }
  }, {
    key: 'render',
    value: function render() {
      var children = this.props.children;

      return React.Children.only(children);
    }
  }]);
  return DropTarget;
}(React.Component);

DropTarget.contextTypes = {
  dragDropContext: PropTypes.object.isRequired
};

DropTarget.propTypes = {
  children: PropTypes.node.isRequired,
  onEnter: PropTypes.func,
  onOver: PropTypes.func,
  onLeave: PropTypes.func,
  onDrop: PropTypes.func
};

DropTarget.defaultProps = {
  onEnter: function onEnter() {},
  onOver: function onOver() {},
  onLeave: function onLeave() {},
  onDrop: function onDrop() {}
};

var TemplateRenderer = function TemplateRenderer(_ref) {
  var template = _ref.template,
      params = _ref.params,
      children = _ref.children;
  return template(children ? _extends({}, params, { children: children }) : params);
};

TemplateRenderer.propTypes = {
  template: PropTypes.func.isRequired,
  params: PropTypes.object,
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])
};

var combineTemplates = function combineTemplates() {
  var userTemplate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {
    return undefined;
  };
  var defaultTemplate = arguments[1];
  return function (props) {
    var result = userTemplate(props);
    if (result === undefined) {
      result = defaultTemplate(props);
    }
    return result;
  };
};

exports.PluginHost = PluginHost$1;
exports.PluginContainer = PluginContainer;
exports.Action = Action;
exports.Getter = Getter;
exports.Watcher = Watcher;
exports.Template = Template;
exports.TemplatePlaceholder = TemplatePlaceholder;
exports.TemplateConnector = TemplateConnector;
exports.Draggable = Draggable;
exports.DragDropContext = DragDropContext;
exports.DragSource = DragSource;
exports.DropTarget = DropTarget;
exports.TemplateRenderer = TemplateRenderer;
exports.combineTemplates = combineTemplates;

Object.defineProperty(exports, '__esModule', { value: true });

})));
//# sourceMappingURL=dx-react-core.umd.js.map
