styleToCssString.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /**
  2. * CSS properties which accept numbers but are not in units of "px".
  3. */
  4. var isUnitlessNumber = {
  5. boxFlex: true,
  6. boxFlexGroup: true,
  7. columnCount: true,
  8. flex: true,
  9. flexGrow: true,
  10. flexPositive: true,
  11. flexShrink: true,
  12. flexNegative: true,
  13. fontWeight: true,
  14. lineClamp: true,
  15. lineHeight: true,
  16. opacity: true,
  17. order: true,
  18. orphans: true,
  19. widows: true,
  20. zIndex: true,
  21. zoom: true,
  22. // SVG-related properties
  23. fillOpacity: true,
  24. strokeDashoffset: true,
  25. strokeOpacity: true,
  26. strokeWidth: true,
  27. };
  28. /**
  29. * @param {string} prefix vendor-specific prefix, eg: Webkit
  30. * @param {string} key style name, eg: transitionDuration
  31. * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
  32. * WebkitTransitionDuration
  33. */
  34. function prefixKey(prefix, key) {
  35. return prefix + key.charAt(0).toUpperCase() + key.substring(1);
  36. }
  37. /**
  38. * Support style names that may come passed in prefixed by adding permutations
  39. * of vendor prefixes.
  40. */
  41. var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
  42. // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
  43. // infinite loop, because it iterates over the newly added props too.
  44. Object.keys(isUnitlessNumber).forEach(function(prop) {
  45. prefixes.forEach(function(prefix) {
  46. isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
  47. });
  48. });
  49. var msPattern = /^ms-/;
  50. var _uppercasePattern = /([A-Z])/g;
  51. /**
  52. * Hyphenates a camelcased string, for example:
  53. *
  54. * > hyphenate('backgroundColor')
  55. * < "background-color"
  56. *
  57. * For CSS style names, use `hyphenateStyleName` instead which works properly
  58. * with all vendor prefixes, including `ms`.
  59. *
  60. * @param {string} string
  61. * @return {string}
  62. */
  63. function hyphenate(string) {
  64. return string.replace(_uppercasePattern, '-$1').toLowerCase();
  65. }
  66. /**
  67. * Hyphenates a camelcased CSS property name, for example:
  68. *
  69. * > hyphenateStyleName('backgroundColor')
  70. * < "background-color"
  71. * > hyphenateStyleName('MozTransition')
  72. * < "-moz-transition"
  73. * > hyphenateStyleName('msTransition')
  74. * < "-ms-transition"
  75. *
  76. * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix
  77. * is converted to `-ms-`.
  78. *
  79. * @param {string} string
  80. * @return {string}
  81. */
  82. function hyphenateStyleName(string) {
  83. return hyphenate(string).replace(msPattern, '-ms-');
  84. }
  85. var isArray = Array.isArray;
  86. var keys = Object.keys;
  87. var counter = 1;
  88. // Follows syntax at https://developer.mozilla.org/en-US/docs/Web/CSS/content,
  89. // including multiple space separated values.
  90. var unquotedContentValueRegex = /^(normal|none|(\b(url\([^)]*\)|chapter_counter|attr\([^)]*\)|(no-)?(open|close)-quote|inherit)((\b\s*)|$|\s+))+)$/;
  91. function buildRule(key, value, exclude) {
  92. if (
  93. (key.toString().match(exclude) === null)
  94. && !isUnitlessNumber[key]
  95. && typeof value === 'number'
  96. ) {
  97. value = '' + value + 'px';
  98. } else if (key === 'content' && !unquotedContentValueRegex.test(value)) {
  99. value = '\'' + value.replace(/'/g, '\\\'') + '\'';
  100. }
  101. return hyphenateStyleName(key) + ': ' + value + '; ';
  102. }
  103. function styleToCssString(rules, options) {
  104. var exclude = options ? options.exclude : null
  105. var result = ''
  106. if (typeof rules === 'string') {
  107. rules = rules.trim()
  108. return rules.slice(-1) === ';' ? `${rules} ` : `${rules}; `
  109. }
  110. if (!rules || keys(rules).length === 0) {
  111. return result;
  112. }
  113. var styleKeys = keys(rules);
  114. for (var j = 0, l = styleKeys.length; j < l; j++) {
  115. var styleKey = styleKeys[j];
  116. var value = rules[styleKey];
  117. if (isArray(value)) {
  118. for (var i = 0, len = value.length; i < len; i++) {
  119. result += buildRule(styleKey, value[i], exclude);
  120. }
  121. } else {
  122. result += buildRule(styleKey, value, exclude);
  123. }
  124. }
  125. return result;
  126. }
  127. export default styleToCssString