(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global.RtlCssJs = factory());
}(this, (function () { 'use strict';

  /**
   * Takes an array of [keyValue1, keyValue2] pairs and creates an object of {keyValue1: keyValue2, keyValue2: keyValue1}
   * @param {Array} array the array of pairs
   * @return {Object} the {key, value} pair object
   */
  function arrayToObject(array) {
    return array.reduce(function (obj, _ref) {
      var prop1 = _ref[0],
        prop2 = _ref[1];
      obj[prop1] = prop2;
      obj[prop2] = prop1;
      return obj;
    }, {});
  }
  function isBoolean(val) {
    return typeof val === 'boolean';
  }
  function isFunction(val) {
    return typeof val === 'function';
  }
  function isNumber(val) {
    return typeof val === 'number';
  }
  function isNullOrUndefined(val) {
    return val === null || typeof val === 'undefined';
  }
  function isObject(val) {
    return val && typeof val === 'object';
  }
  function isString(val) {
    return typeof val === 'string';
  }
  function includes(inclusive, inclusee) {
    return inclusive.indexOf(inclusee) !== -1;
  }

  /**
   * Flip the sign of a CSS value, possibly with a unit.
   *
   * We can't just negate the value with unary minus due to the units.
   *
   * @private
   * @param {String} value - the original value (for example 77%)
   * @return {String} the result (for example -77%)
   */
  function flipSign(value) {
    if (parseFloat(value) === 0) {
      // Don't mangle zeroes
      return value;
    }
    if (value[0] === '-') {
      return value.slice(1);
    }
    return "-" + value;
  }
  function flipTransformSign(match, prefix, offset, suffix) {
    return prefix + flipSign(offset) + suffix;
  }

  /**
   * Takes a percentage for background position and inverts it.
   * This was copied and modified from CSSJanus:
   * https://github.com/cssjanus/cssjanus/blob/4245f834365f6cfb0239191a151432fb85abab23/src/cssjanus.js#L152-L175
   * @param {String} value - the original value (for example 77%)
   * @return {String} the result (for example 23%)
   */
  function calculateNewBackgroundPosition(value) {
    var idx = value.indexOf('.');
    if (idx === -1) {
      value = 100 - parseFloat(value) + "%";
    } else {
      // Two off, one for the "%" at the end, one for the dot itself
      var len = value.length - idx - 2;
      value = 100 - parseFloat(value);
      value = value.toFixed(len) + "%";
    }
    return value;
  }

  /**
   * This takes a list of CSS values and converts it to an array
   * @param {String} value - something like `1px`, `1px 2em`, or `3pt rgb(150, 230, 550) 40px calc(100% - 5px)`
   * @return {Array} the split values (for example: `['3pt', 'rgb(150, 230, 550)', '40px', 'calc(100% - 5px)']`)
   */
  function getValuesAsList(value) {
    return value.replace(/ +/g, ' ') // remove all extraneous spaces
    .split(' ').map(function (i) {
      return i.trim();
    }) // get rid of extra space before/after each item
    .filter(Boolean) // get rid of empty strings
    // join items which are within parenthese
    // luckily `calc (100% - 5px)` is invalid syntax and it must be `calc(100% - 5px)`, otherwise this would be even more complex
    .reduce(function (_ref2, item) {
      var list = _ref2.list,
        state = _ref2.state;
      var openParansCount = (item.match(/\(/g) || []).length;
      var closedParansCount = (item.match(/\)/g) || []).length;
      if (state.parensDepth > 0) {
        list[list.length - 1] = list[list.length - 1] + " " + item;
      } else {
        list.push(item);
      }
      state.parensDepth += openParansCount - closedParansCount;
      return {
        list: list,
        state: state
      };
    }, {
      list: [],
      state: {
        parensDepth: 0
      }
    }).list;
  }

  /**
   * This is intended for properties that are `top right bottom left` and will switch them to `top left bottom right`
   * @param {String} value - `1px 2px 3px 4px` for example, but also handles cases where there are too few/too many and
   * simply returns the value in those cases (which is the correct behavior)
   * @return {String} the result - `1px 4px 3px 2px` for example.
   */
  function handleQuartetValues(value) {
    var splitValues = getValuesAsList(value);
    if (splitValues.length <= 3 || splitValues.length > 4) {
      return value;
    }
    var top = splitValues[0],
      right = splitValues[1],
      bottom = splitValues[2],
      left = splitValues[3];
    return [top, left, bottom, right].join(' ');
  }

  /**
   *
   * @param {String|Number|Object} value css property value to test
   * @returns If the css property value can(should?) have an RTL equivalent
   */
  function canConvertValue(value) {
    return !isBoolean(value) && !isNullOrUndefined(value);
  }

  /**
   * Splits a shadow style into its separate shadows using the comma delimiter, but creating an exception
   * for comma separated values in parentheses often used for rgba colours.
   * @param {String} value
   * @returns {Array} array of all box shadow values in the string
   */
  function splitShadow(value) {
    var shadows = [];
    var start = 0;
    var end = 0;
    var rgba = false;
    while (end < value.length) {
      if (!rgba && value[end] === ',') {
        shadows.push(value.substring(start, end).trim());
        end++;
        start = end;
      } else if (value[end] === "(") {
        rgba = true;
        end++;
      } else if (value[end] === ')') {
        rgba = false;
        end++;
      } else {
        end++;
      }
    }

    // push the last shadow value if there is one
    // istanbul ignore next
    if (start != end) {
      shadows.push(value.substring(start, end + 1));
    }
    return shadows;
  }

  // some values require a little fudging, that fudging goes here.
  var propertyValueConverters = {
    padding: function padding(_ref) {
      var value = _ref.value;
      if (isNumber(value)) {
        return value;
      }
      return handleQuartetValues(value);
    },
    textShadow: function textShadow(_ref2) {
      var value = _ref2.value;
      var flippedShadows = splitShadow(value).map(function (shadow) {
        // intentionally leaving off the `g` flag here because we only want to change the first number (which is the offset-x)
        return shadow.replace(/(^|\s)(-*)([.|\d]+)/, function (match, whiteSpace, negative, number) {
          if (number === '0') {
            return match;
          }
          var doubleNegative = negative === '' ? '-' : '';
          return "" + whiteSpace + doubleNegative + number;
        });
      });
      return flippedShadows.join(',');
    },
    borderColor: function borderColor(_ref3) {
      var value = _ref3.value;
      return handleQuartetValues(value);
    },
    borderRadius: function borderRadius(_ref4) {
      var value = _ref4.value;
      if (isNumber(value)) {
        return value;
      }
      if (includes(value, '/')) {
        var _value$split = value.split('/'),
          radius1 = _value$split[0],
          radius2 = _value$split[1];
        var convertedRadius1 = propertyValueConverters.borderRadius({
          value: radius1.trim()
        });
        var convertedRadius2 = propertyValueConverters.borderRadius({
          value: radius2.trim()
        });
        return convertedRadius1 + " / " + convertedRadius2;
      }
      var splitValues = getValuesAsList(value);
      switch (splitValues.length) {
        case 2:
          {
            return splitValues.reverse().join(' ');
          }
        case 4:
          {
            var topLeft = splitValues[0],
              topRight = splitValues[1],
              bottomRight = splitValues[2],
              bottomLeft = splitValues[3];
            return [topRight, topLeft, bottomLeft, bottomRight].join(' ');
          }
        default:
          {
            return value;
          }
      }
    },
    background: function background(_ref5) {
      var value = _ref5.value,
        valuesToConvert = _ref5.valuesToConvert,
        isRtl = _ref5.isRtl,
        bgImgDirectionRegex = _ref5.bgImgDirectionRegex,
        bgPosDirectionRegex = _ref5.bgPosDirectionRegex;
      if (isNumber(value)) {
        return value;
      }

      // Yeah, this is in need of a refactor 🙃...
      // but this property is a tough cookie 🍪
      // get the backgroundPosition out of the string by removing everything that couldn't be the backgroundPosition value
      var backgroundPositionValue = value.replace(/(url\(.*?\))|(rgba?\(.*?\))|(hsl\(.*?\))|(#[a-fA-F0-9]+)|((^| )(\D)+( |$))/g, '').trim();
      // replace that backgroundPosition value with the converted version
      value = value.replace(backgroundPositionValue, propertyValueConverters.backgroundPosition({
        value: backgroundPositionValue,
        valuesToConvert: valuesToConvert,
        isRtl: isRtl,
        bgPosDirectionRegex: bgPosDirectionRegex
      }));
      // do the backgroundImage value replacing on the whole value (because why not?)
      return propertyValueConverters.backgroundImage({
        value: value,
        valuesToConvert: valuesToConvert,
        bgImgDirectionRegex: bgImgDirectionRegex
      });
    },
    backgroundImage: function backgroundImage(_ref6) {
      var value = _ref6.value,
        valuesToConvert = _ref6.valuesToConvert,
        bgImgDirectionRegex = _ref6.bgImgDirectionRegex;
      if (!includes(value, 'url(') && !includes(value, 'linear-gradient(')) {
        return value;
      }
      return value.replace(bgImgDirectionRegex, function (match, g1, group2) {
        return match.replace(group2, valuesToConvert[group2]);
      });
    },
    backgroundPosition: function backgroundPosition(_ref7) {
      var value = _ref7.value,
        valuesToConvert = _ref7.valuesToConvert,
        isRtl = _ref7.isRtl,
        bgPosDirectionRegex = _ref7.bgPosDirectionRegex;
      return value
      // intentionally only grabbing the first instance of this because that represents `left`
      .replace(isRtl ? /^((-|\d|\.)+%)/ : null, function (match, group) {
        return calculateNewBackgroundPosition(group);
      }).replace(bgPosDirectionRegex, function (match) {
        return valuesToConvert[match];
      });
    },
    backgroundPositionX: function backgroundPositionX(_ref8) {
      var value = _ref8.value,
        valuesToConvert = _ref8.valuesToConvert,
        isRtl = _ref8.isRtl,
        bgPosDirectionRegex = _ref8.bgPosDirectionRegex;
      if (isNumber(value)) {
        return value;
      }
      return propertyValueConverters.backgroundPosition({
        value: value,
        valuesToConvert: valuesToConvert,
        isRtl: isRtl,
        bgPosDirectionRegex: bgPosDirectionRegex
      });
    },
    transition: function transition(_ref9) {
      var value = _ref9.value,
        propertiesToConvert = _ref9.propertiesToConvert;
      return value.split(/,\s*/g).map(function (transition) {
        var values = transition.split(' ');

        // Property is always defined first
        values[0] = propertiesToConvert[values[0]] || values[0];
        return values.join(' ');
      }).join(', ');
    },
    transitionProperty: function transitionProperty(_ref10) {
      var value = _ref10.value,
        propertiesToConvert = _ref10.propertiesToConvert;
      return value.split(/,\s*/g).map(function (prop) {
        return propertiesToConvert[prop] || prop;
      }).join(', ');
    },
    transform: function transform(_ref11) {
      var value = _ref11.value;
      // This was copied and modified from CSSJanus:
      // https://github.com/cssjanus/cssjanus/blob/4a40f001b1ba35567112d8b8e1d9d95eda4234c3/src/cssjanus.js#L152-L153
      var nonAsciiPattern = "[^\\u0020-\\u007e]";
      var escapePattern = "(?:" + '(?:(?:\\[0-9a-f]{1,6})(?:\\r\\n|\\s)?)' + "|\\\\[^\\r\\n\\f0-9a-f])";
      var signedQuantPattern = "((?:-?" + ('(?:[0-9]*\\.[0-9]+|[0-9]+)' + "(?:\\s*" + '(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)' + "|" + ("-?" + ("(?:[_a-z]|" + nonAsciiPattern + "|" + escapePattern + ")") + ("(?:[_a-z0-9-]|" + nonAsciiPattern + "|" + escapePattern + ")") + "*") + ")?") + ")|(?:inherit|auto))";
      var translateXRegExp = new RegExp("(translateX\\s*\\(\\s*)" + signedQuantPattern + "(\\s*\\))", 'gi');
      var translateRegExp = new RegExp("(translate\\s*\\(\\s*)" + signedQuantPattern + "((?:\\s*,\\s*" + signedQuantPattern + "){0,1}\\s*\\))", 'gi');
      var translate3dRegExp = new RegExp("(translate3d\\s*\\(\\s*)" + signedQuantPattern + "((?:\\s*,\\s*" + signedQuantPattern + "){0,2}\\s*\\))", 'gi');
      var rotateRegExp = new RegExp("(rotate[ZY]?\\s*\\(\\s*)" + signedQuantPattern + "(\\s*\\))", 'gi');
      return value.replace(translateXRegExp, flipTransformSign).replace(translateRegExp, flipTransformSign).replace(translate3dRegExp, flipTransformSign).replace(rotateRegExp, flipTransformSign);
    }
  };
  propertyValueConverters.objectPosition = propertyValueConverters.backgroundPosition;
  propertyValueConverters.margin = propertyValueConverters.padding;
  propertyValueConverters.borderWidth = propertyValueConverters.padding;
  propertyValueConverters.boxShadow = propertyValueConverters.textShadow;
  propertyValueConverters.webkitBoxShadow = propertyValueConverters.boxShadow;
  propertyValueConverters.mozBoxShadow = propertyValueConverters.boxShadow;
  propertyValueConverters.WebkitBoxShadow = propertyValueConverters.boxShadow;
  propertyValueConverters.MozBoxShadow = propertyValueConverters.boxShadow;
  propertyValueConverters.borderStyle = propertyValueConverters.borderColor;
  propertyValueConverters.webkitTransform = propertyValueConverters.transform;
  propertyValueConverters.mozTransform = propertyValueConverters.transform;
  propertyValueConverters.WebkitTransform = propertyValueConverters.transform;
  propertyValueConverters.MozTransform = propertyValueConverters.transform;
  propertyValueConverters.transformOrigin = propertyValueConverters.backgroundPosition;
  propertyValueConverters.webkitTransformOrigin = propertyValueConverters.transformOrigin;
  propertyValueConverters.mozTransformOrigin = propertyValueConverters.transformOrigin;
  propertyValueConverters.WebkitTransformOrigin = propertyValueConverters.transformOrigin;
  propertyValueConverters.MozTransformOrigin = propertyValueConverters.transformOrigin;
  propertyValueConverters.webkitTransition = propertyValueConverters.transition;
  propertyValueConverters.mozTransition = propertyValueConverters.transition;
  propertyValueConverters.WebkitTransition = propertyValueConverters.transition;
  propertyValueConverters.MozTransition = propertyValueConverters.transition;
  propertyValueConverters.webkitTransitionProperty = propertyValueConverters.transitionProperty;
  propertyValueConverters.mozTransitionProperty = propertyValueConverters.transitionProperty;
  propertyValueConverters.WebkitTransitionProperty = propertyValueConverters.transitionProperty;
  propertyValueConverters.MozTransitionProperty = propertyValueConverters.transitionProperty;

  // kebab-case versions

  propertyValueConverters['text-shadow'] = propertyValueConverters.textShadow;
  propertyValueConverters['border-color'] = propertyValueConverters.borderColor;
  propertyValueConverters['border-radius'] = propertyValueConverters.borderRadius;
  propertyValueConverters['background-image'] = propertyValueConverters.backgroundImage;
  propertyValueConverters['background-position'] = propertyValueConverters.backgroundPosition;
  propertyValueConverters['background-position-x'] = propertyValueConverters.backgroundPositionX;
  propertyValueConverters['object-position'] = propertyValueConverters.objectPosition;
  propertyValueConverters['border-width'] = propertyValueConverters.padding;
  propertyValueConverters['box-shadow'] = propertyValueConverters.textShadow;
  propertyValueConverters['-webkit-box-shadow'] = propertyValueConverters.textShadow;
  propertyValueConverters['-moz-box-shadow'] = propertyValueConverters.textShadow;
  propertyValueConverters['border-style'] = propertyValueConverters.borderColor;
  propertyValueConverters['-webkit-transform'] = propertyValueConverters.transform;
  propertyValueConverters['-moz-transform'] = propertyValueConverters.transform;
  propertyValueConverters['transform-origin'] = propertyValueConverters.transformOrigin;
  propertyValueConverters['-webkit-transform-origin'] = propertyValueConverters.transformOrigin;
  propertyValueConverters['-moz-transform-origin'] = propertyValueConverters.transformOrigin;
  propertyValueConverters['-webkit-transition'] = propertyValueConverters.transition;
  propertyValueConverters['-moz-transition'] = propertyValueConverters.transition;
  propertyValueConverters['transition-property'] = propertyValueConverters.transitionProperty;
  propertyValueConverters['-webkit-transition-property'] = propertyValueConverters.transitionProperty;
  propertyValueConverters['-moz-transition-property'] = propertyValueConverters.transitionProperty;

  // this will be an object of properties that map to their corresponding rtl property (their doppelganger)
  var propertiesToConvert = arrayToObject([['paddingLeft', 'paddingRight'], ['marginLeft', 'marginRight'], ['left', 'right'], ['borderLeft', 'borderRight'], ['borderLeftColor', 'borderRightColor'], ['borderLeftStyle', 'borderRightStyle'], ['borderLeftWidth', 'borderRightWidth'], ['borderTopLeftRadius', 'borderTopRightRadius'], ['borderBottomLeftRadius', 'borderBottomRightRadius'],
  // kebab-case versions
  ['padding-left', 'padding-right'], ['margin-left', 'margin-right'], ['border-left', 'border-right'], ['border-left-color', 'border-right-color'], ['border-left-style', 'border-right-style'], ['border-left-width', 'border-right-width'], ['border-top-left-radius', 'border-top-right-radius'], ['border-bottom-left-radius', 'border-bottom-right-radius']]);
  var propsToIgnore = ['content'];

  // this is the same as the propertiesToConvert except for values
  var valuesToConvert = arrayToObject([['ltr', 'rtl'], ['left', 'right'], ['w-resize', 'e-resize'], ['sw-resize', 'se-resize'], ['nw-resize', 'ne-resize']]);

  // Sorry for the regex 😞, but basically thisis used to replace _every_ instance of
  // `ltr`, `rtl`, `right`, and `left` in `backgroundimage` with the corresponding opposite.
  // A situation we're accepting here:
  // url('/left/right/rtl/ltr.png') will be changed to url('/right/left/ltr/rtl.png')
  // Definite trade-offs here, but I think it's a good call.
  var bgImgDirectionRegex = new RegExp('(^|\\W|_)((ltr)|(rtl)|(left)|(right))(\\W|_|$)', 'g');
  var bgPosDirectionRegex = new RegExp('(left)|(right)');

  /**
   * converts properties and values in the CSS in JS object to their corresponding RTL values
   * @param {Object} object the CSS in JS object
   * @return {Object} the RTL converted object
   */
  function convert(object) {
    return Object.keys(object).reduce(function (newObj, originalKey) {
      var originalValue = object[originalKey];
      if (isString(originalValue)) {
        // you're welcome to later code 😺
        originalValue = originalValue.trim();
      }

      // Some properties should never be transformed
      if (includes(propsToIgnore, originalKey)) {
        newObj[originalKey] = originalValue;
        return newObj;
      }
      var _convertProperty = convertProperty(originalKey, originalValue),
        key = _convertProperty.key,
        value = _convertProperty.value;
      newObj[key] = value;
      return newObj;
    }, Array.isArray(object) ? [] : {});
  }

  /**
   * Converts a property and its value to the corresponding RTL key and value
   * @param {String} originalKey the original property key
   * @param {Number|String|Object} originalValue the original css property value
   * @return {Object} the new {key, value} pair
   */
  function convertProperty(originalKey, originalValue) {
    var isNoFlip = /\/\*\s?@noflip\s?\*\//.test(originalValue);
    var key = isNoFlip ? originalKey : getPropertyDoppelganger(originalKey);
    var value = isNoFlip ? originalValue : getValueDoppelganger(key, originalValue);
    return {
      key: key,
      value: value
    };
  }

  /**
   * This gets the RTL version of the given property if it has a corresponding RTL property
   * @param {String} property the name of the property
   * @return {String} the name of the RTL property
   */
  function getPropertyDoppelganger(property) {
    return propertiesToConvert[property] || property;
  }

  /**
   * This converts the given value to the RTL version of that value based on the key
   * @param {String} key this is the key (note: this should be the RTL version of the originalKey)
   * @param {String|Number|Object} originalValue the original css property value. If it's an object, then we'll convert that as well
   * @return {String|Number|Object} the converted value
   */
  function getValueDoppelganger(key, originalValue) {
    if (!canConvertValue(originalValue)) {
      return originalValue;
    }
    if (isObject(originalValue)) {
      return convert(originalValue); // recursion 🌀
    }

    var isNum = isNumber(originalValue);
    var isFunc = isFunction(originalValue);
    var importantlessValue = isNum || isFunc ? originalValue : originalValue.replace(/ !important.*?$/, '');
    var isImportant = !isNum && importantlessValue.length !== originalValue.length;
    var valueConverter = propertyValueConverters[key];
    var newValue;
    if (valueConverter) {
      newValue = valueConverter({
        value: importantlessValue,
        valuesToConvert: valuesToConvert,
        propertiesToConvert: propertiesToConvert,
        isRtl: true,
        bgImgDirectionRegex: bgImgDirectionRegex,
        bgPosDirectionRegex: bgPosDirectionRegex
      });
    } else {
      newValue = valuesToConvert[importantlessValue] || importantlessValue;
    }
    if (isImportant) {
      return newValue + " !important";
    }
    return newValue;
  }

  return convert;

})));
//# sourceMappingURL=rtl-css-js.umd.js.map
