text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  
  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 _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  var _appendImportantToEachValue = require('./append-important-to-each-value');
  
  var _appendImportantToEachValue2 = _interopRequireDefault(_appendImportantToEachValue);
  
  var _cssRuleSetToString = require('./css-rule-set-to-string');
  
  var _cssRuleSetToString2 = _interopRequireDefault(_cssRuleSetToString);
  
  var _getState = require('./get-state');
  
  var _getState2 = _interopRequireDefault(_getState);
  
  var _getStateKey = require('./get-state-key');
  
  var _getStateKey2 = _interopRequireDefault(_getStateKey);
  
  var _hash = require('./hash');
  
  var _hash2 = _interopRequireDefault(_hash);
  
  var _mergeStyles = require('./merge-styles');
  
  var _plugins = require('./plugins/');
  
  var _plugins2 = _interopRequireDefault(_plugins);
  
  var _exenv = require('exenv');
  
  var _exenv2 = _interopRequireDefault(_exenv);
  
  var _react = require('react');
  
  var _react2 = _interopRequireDefault(_react);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  var DEFAULT_CONFIG = {
    plugins: [_plugins2.default.mergeStyleArray, _plugins2.default.checkProps, _plugins2.default.resolveMediaQueries, _plugins2.default.resolveInteractionStyles, _plugins2.default.keyframes, _plugins2.default.visited, _plugins2.default.removeNestedStyles, _plugins2.default.prefix, _plugins2.default.checkProps]
  };
  
  // Gross
  var globalState = {};
  
  // Declare early for recursive helpers.
  var resolveStyles = null;
  
  var _shouldResolveStyles = function _shouldResolveStyles(component) {
    return component.type && !component.type._isRadiumEnhanced;
  };
  
  var _resolveChildren = function _resolveChildren(_ref) {
    var children = _ref.children,
        component = _ref.component,
        config = _ref.config,
        existingKeyMap = _ref.existingKeyMap;
  
    if (!children) {
      return children;
    }
  
    var childrenType = typeof children === 'undefined' ? 'undefined' : _typeof(children);
  
    if (childrenType === 'string' || childrenType === 'number') {
      // Don't do anything with a single primitive child
      return children;
    }
  
    if (childrenType === 'function') {
      // Wrap the function, resolving styles on the result
      return function () {
        var result = children.apply(this, arguments);
        if (_react2.default.isValidElement(result)) {
          return resolveStyles(component, result, config, existingKeyMap, true);
        }
        return result;
      };
    }
  
    if (_react2.default.Children.count(children) === 1 && children.type) {
      // If a React Element is an only child, don't wrap it in an array for
      // React.Children.map() for React.Children.only() compatibility.
      var onlyChild = _react2.default.Children.only(children);
      return resolveStyles(component, onlyChild, config, existingKeyMap, true);
    }
  
    return _react2.default.Children.map(children, function (child) {
      if (_react2.default.isValidElement(child)) {
        return resolveStyles(component, child, config, existingKeyMap, true);
      }
  
      return child;
    });
  };
  
  // Recurse over props, just like children
  var _resolveProps = function _resolveProps(_ref2) {
    var component = _ref2.component,
        config = _ref2.config,
        existingKeyMap = _ref2.existingKeyMap,
        props = _ref2.props;
  
    var newProps = props;
  
    Object.keys(props).forEach(function (prop) {
      // We already recurse over children above
      if (prop === 'children') {
        return;
      }
  
      var propValue = props[prop];
      if (_react2.default.isValidElement(propValue)) {
        newProps = _extends({}, newProps);
        newProps[prop] = resolveStyles(component, propValue, config, existingKeyMap, true);
      }
    });
  
    return newProps;
  };
  
  var _buildGetKey = function _buildGetKey(_ref3) {
    var componentName = _ref3.componentName,
        existingKeyMap = _ref3.existingKeyMap,
        renderedElement = _ref3.renderedElement;
  
    // We need a unique key to correlate state changes due to user interaction
    // with the rendered element, so we know to apply the proper interactive
    // styles.
    var originalKey = typeof renderedElement.ref === 'string' ? renderedElement.ref : renderedElement.key;
    var key = (0, _getStateKey2.default)(originalKey);
  
    var alreadyGotKey = false;
    var getKey = function getKey() {
      if (alreadyGotKey) {
        return key;
      }
  
      alreadyGotKey = true;
  
      if (existingKeyMap[key]) {
        var elementName = void 0;
        if (typeof renderedElement.type === 'string') {
          elementName = renderedElement.type;
        } else if (renderedElement.type.constructor) {
          elementName = renderedElement.type.constructor.displayName || renderedElement.type.constructor.name;
        }
  
        throw new Error('Radium requires each element with interactive styles to have a unique ' + 'key, set using either the ref or key prop. ' + (originalKey ? 'Key "' + originalKey + '" is a duplicate.' : 'Multiple elements have no key specified.') + ' ' + 'Component: "' + componentName + '". ' + (elementName ? 'Element: "' + elementName + '".' : ''));
      }
  
      existingKeyMap[key] = true;
  
      return key;
    };
  
    return getKey;
  };
  
  var _setStyleState = function _setStyleState(component, key, stateKey, value) {
    if (!component._radiumIsMounted) {
      return;
    }
  
    var existing = component._lastRadiumState || component.state && component.state._radiumStyleState || {};
  
    var state = { _radiumStyleState: _extends({}, existing) };
    state._radiumStyleState[key] = _extends({}, state._radiumStyleState[key]);
    state._radiumStyleState[key][stateKey] = value;
  
    component._lastRadiumState = state._radiumStyleState;
    component.setState(state);
  };
  
  var _runPlugins = function _runPlugins(_ref4) {
    var component = _ref4.component,
        config = _ref4.config,
        existingKeyMap = _ref4.existingKeyMap,
        props = _ref4.props,
        renderedElement = _ref4.renderedElement;
  
    // Don't run plugins if renderedElement is not a simple ReactDOMElement or has
    // no style.
    if (!_react2.default.isValidElement(renderedElement) || typeof renderedElement.type !== 'string' || !props.style) {
      return props;
    }
  
    var newProps = props;
  
    var plugins = config.plugins || DEFAULT_CONFIG.plugins;
  
    var componentName = component.constructor.displayName || component.constructor.name;
    var getKey = _buildGetKey({
      renderedElement: renderedElement,
      existingKeyMap: existingKeyMap,
      componentName: componentName
    });
    var getComponentField = function getComponentField(key) {
      return component[key];
    };
    var getGlobalState = function getGlobalState(key) {
      return globalState[key];
    };
    var componentGetState = function componentGetState(stateKey, elementKey) {
      return (0, _getState2.default)(component.state, elementKey || getKey(), stateKey);
    };
    var setState = function setState(stateKey, value, elementKey) {
      return _setStyleState(component, elementKey || getKey(), stateKey, value);
    };
  
    var addCSS = function addCSS(css) {
      var styleKeeper = component._radiumStyleKeeper || component.context._radiumStyleKeeper;
      if (!styleKeeper) {
        if (__isTestModeEnabled) {
          return {
            remove: function remove() {}
          };
        }
  
        throw new Error('To use plugins requiring `addCSS` (e.g. keyframes, media queries), ' + 'please wrap your application in the StyleRoot component. Component ' + 'name: `' + componentName + '`.');
      }
  
      return styleKeeper.addCSS(css);
    };
  
    var newStyle = props.style;
  
    plugins.forEach(function (plugin) {
      var result = plugin({
        ExecutionEnvironment: _exenv2.default,
        addCSS: addCSS,
        appendImportantToEachValue: _appendImportantToEachValue2.default,
        componentName: componentName,
        config: config,
        cssRuleSetToString: _cssRuleSetToString2.default,
        getComponentField: getComponentField,
        getGlobalState: getGlobalState,
        getState: componentGetState,
        hash: _hash2.default,
        mergeStyles: _mergeStyles.mergeStyles,
        props: newProps,
        setState: setState,
        isNestedStyle: _mergeStyles.isNestedStyle,
        style: newStyle
      }) || {};
  
      newStyle = result.style || newStyle;
  
      newProps = result.props && Object.keys(result.props).length ? _extends({}, newProps, result.props) : newProps;
  
      var newComponentFields = result.componentFields || {};
      Object.keys(newComponentFields).forEach(function (fieldName) {
        component[fieldName] = newComponentFields[fieldName];
      });
  
      var newGlobalState = result.globalState || {};
      Object.keys(newGlobalState).forEach(function (key) {
        globalState[key] = newGlobalState[key];
      });
    });
  
    if (newStyle !== props.style) {
      newProps = _extends({}, newProps, { style: newStyle });
    }
  
    return newProps;
  };
  
  // Wrapper around React.cloneElement. To avoid processing the same element
  // twice, whenever we clone an element add a special prop to make sure we don't
  // process this element again.
  var _cloneElement = function _cloneElement(renderedElement, newProps, newChildren) {
    // Only add flag if this is a normal DOM element
    if (typeof renderedElement.type === 'string') {
      newProps = _extends({}, newProps, { 'data-radium': true });
    }
  
    return _react2.default.cloneElement(renderedElement, newProps, newChildren);
  };
  
  //
  // The nucleus of Radium. resolveStyles is called on the rendered elements
  // before they are returned in render. It iterates over the elements and
  // children, rewriting props to add event handlers required to capture user
  // interactions (e.g. mouse over). It also replaces the style prop because it
  // adds in the various interaction styles (e.g. :hover).
  //
  resolveStyles = function resolveStyles(component, // ReactComponent, flow+eslint complaining
  renderedElement) {
    var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_CONFIG;
    var existingKeyMap = arguments[3];
    var shouldCheckBeforeResolve = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
  
    // ReactElement
    existingKeyMap = existingKeyMap || {};
    if (!renderedElement ||
    // Bail if we've already processed this element. This ensures that only the
    // owner of an element processes that element, since the owner's render
    // function will be called first (which will always be the case, since you
    // can't know what else to render until you render the parent component).
    renderedElement.props && renderedElement.props['data-radium'] ||
    // Bail if this element is a radium enhanced element, because if it is,
    // then it will take care of resolving its own styles.
    shouldCheckBeforeResolve && !_shouldResolveStyles(renderedElement)) {
      return renderedElement;
    }
  
    var newChildren = _resolveChildren({
      children: renderedElement.props.children,
      component: component,
      config: config,
      existingKeyMap: existingKeyMap
    });
  
    var newProps = _resolveProps({
      component: component,
      config: config,
      existingKeyMap: existingKeyMap,
      props: renderedElement.props
    });
  
    newProps = _runPlugins({
      component: component,
      config: config,
      existingKeyMap: existingKeyMap,
      props: newProps,
      renderedElement: renderedElement
    });
  
    // If nothing changed, don't bother cloning the element. Might be a bit
    // wasteful, as we add the sentinal to stop double-processing when we clone.
    // Assume benign double-processing is better than unneeded cloning.
    if (newChildren === renderedElement.props.children && newProps === renderedElement.props) {
      return renderedElement;
    }
  
    return _cloneElement(renderedElement, newProps !== renderedElement.props ? newProps : {}, newChildren);
  };
  
  // Only for use by tests
  var __isTestModeEnabled = false;
  if (process.env.NODE_ENV !== 'production') {
    resolveStyles.__clearStateForTests = function () {
      globalState = {};
    };
    resolveStyles.__setTestMode = function (isEnabled) {
      __isTestModeEnabled = isEnabled;
    };
  }
  
  exports.default = resolveStyles;
  module.exports = exports['default'];