'use strict'; /** * CSS properties which accept numbers but are not in units of "px". */ var isUnitlessNumber = { boxFlex: true, boxFlexGroup: true, columnCount: true, flex: true, flexGrow: true, flexPositive: true, flexShrink: true, flexNegative: true, fontWeight: true, lineClamp: true, lineHeight: true, opacity: true, order: true, orphans: true, widows: true, zIndex: true, zoom: true, // SVG-related properties fillOpacity: true, strokeDashoffset: true, strokeOpacity: true, strokeWidth: true }; /** * @param {string} prefix vendor-specific prefix, eg: Webkit * @param {string} key style name, eg: transitionDuration * @return {string} style name prefixed with `prefix`, properly camelCased, eg: * WebkitTransitionDuration */ function prefixKey(prefix, key) { return prefix + key.charAt(0).toUpperCase() + key.substring(1); } /** * Support style names that may come passed in prefixed by adding permutations * of vendor prefixes. */ var prefixes = ['Webkit', 'ms', 'Moz', 'O']; // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an // infinite loop, because it iterates over the newly added props too. Object.keys(isUnitlessNumber).forEach(function(prop) { prefixes.forEach(function(prefix) { isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; }); }); var msPattern = /^ms-/; var _uppercasePattern = /([A-Z])/g; /** * Hyphenates a camelcased string, for example: * * > hyphenate('backgroundColor') * < "background-color" * * For CSS style names, use `hyphenateStyleName` instead which works properly * with all vendor prefixes, including `ms`. * * @param {string} string * @return {string} */ function hyphenate(string) { return string.replace(_uppercasePattern, '-$1').toLowerCase(); } /** * Hyphenates a camelcased CSS property name, for example: * * > hyphenateStyleName('backgroundColor') * < "background-color" * > hyphenateStyleName('MozTransition') * < "-moz-transition" * > hyphenateStyleName('msTransition') * < "-ms-transition" * * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix * is converted to `-ms-`. * * @param {string} string * @return {string} */ function hyphenateStyleName(string) { return hyphenate(string).replace(msPattern, '-ms-'); } var isArray = Array.isArray; var keys = Object.keys; var counter = 1; // Follows syntax at https://developer.mozilla.org/en-US/docs/Web/CSS/content, // including multiple space separated values. var unquotedContentValueRegex = /^(normal|none|(\b(url\([^)]*\)|chapter_counter|attr\([^)]*\)|(no-)?(open|close)-quote|inherit)((\b\s*)|$|\s+))+)$/; function buildRule(key, value) { if (!isUnitlessNumber[key] && typeof value === 'number') { value = '' + value + 'px'; } else if (key === 'content' && !unquotedContentValueRegex.test(value)) { value = "'" + value.replace(/'/g, "\\'") + "'"; } return hyphenateStyleName(key) + ': ' + value + '; '; } function styleToCssString(rules) { var result = '' if (typeof rules === 'string') { return rules } if (!rules || keys(rules).length === 0) { return result; } var styleKeys = keys(rules); for (var j = 0, l = styleKeys.length; j < l; j++) { var styleKey = styleKeys[j]; var value = rules[styleKey]; if (isArray(value)) { for (var i = 0, len = value.length; i < len; i++) { result += buildRule(styleKey, value[i]); } } else { result += buildRule(styleKey, value); } } return result; } export default styleToCssString