Skip to content
This repository has been archived by the owner on Aug 19, 2022. It is now read-only.

Commit

Permalink
Merge pull request #128 from FormidableLabs/vendor-prefix
Browse files Browse the repository at this point in the history
Add automatic vendor prefixing
  • Loading branch information
ianobermiller committed May 7, 2015
2 parents 5ba7ceb + 33eaa1e commit 66dbd7a
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 2 deletions.
7 changes: 7 additions & 0 deletions modules/__mocks__/prefix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

var prefixMock = function (style) {
return style;
};

module.exports = prefixMock;
133 changes: 133 additions & 0 deletions modules/prefix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/**
* Based on https://github.com/jsstyles/css-vendor, but without any dash-case
* shenanigans.
*/

'use strict';

var kebabCase = require('lodash/string/kebabCase');

var jsCssMap = {
Webkit: '-webkit-',
Moz: '-moz-',
// IE did it wrong again ...
ms: '-ms-',
O: '-o-'
};
var testProp = 'Transform';

var domStyle = document.createElement('p').style;
var prefixedPropertyCache = {};
var prefixedValueCache = {};
var jsVendorPrefix = '';
var cssVendorPrefix = '';

for (var js in jsCssMap) {
if ((js + testProp) in domStyle) {
jsVendorPrefix = js;
cssVendorPrefix = jsCssMap[js];
break;
}
}

var _getPrefixedProperty = function (property) {
if (prefixedPropertyCache.hasOwnProperty(property)) {
return prefixedPropertyCache[property];
}

if (property in domStyle) {
// unprefixed
prefixedPropertyCache[property] = {
css: kebabCase(property),
js: property
};
return prefixedPropertyCache[property];
}

var newProperty =
jsVendorPrefix + property[0].toUpperCase() + property.slice(1);
if (newProperty in domStyle) {
// prefixed
prefixedPropertyCache[property] = {
css: cssVendorPrefix + kebabCase(property),
js: newProperty
};
return prefixedPropertyCache[property];
}

// unsupported
return prefixedPropertyCache[property] = false;
};

var _getPrefixedValue = function (property, value) {
// don't test numbers or numbers with units (e.g. 10em)
if (typeof value !== 'string' || !isNaN(parseInt(value, 10))) {
return value;
}

var cacheKey = property + value;

if (prefixedValueCache.hasOwnProperty(cacheKey)) {
return prefixedValueCache[cacheKey];
}

// Clear style first
domStyle[property] = '';

// Test value as it is.
domStyle[property] = value;

// Value is supported as it is. Note that we just make sure it is not an empty
// string. Browsers will sometimes rewrite values, but still accept them. They
// will set the value to an empty string if not supported.
// E.g. for border, "solid 1px black" becomes "1px solid black"
// but "foobar" becomes "", since it is not supported.
if (domStyle[property]) {
prefixedValueCache[cacheKey] = value;
return value;
}

// Test value with vendor prefix.
value = cssVendorPrefix + value;
domStyle[property] = value;

// Value is supported with vendor prefix.
if (domStyle[property]) {
prefixedValueCache[cacheKey] = value;
return value;
}

return prefixedValueCache[cacheKey] = false;
};

// Returns a new style object with vendor prefixes added to property names
// and values.
/*eslint-disable no-console */
var prefix = function (style, mode /* 'css' or 'js' */) {
mode = mode || 'js';
var newStyle = {};
Object.keys(style).forEach(function (property) {
var value = style[property];

var newProperty = _getPrefixedProperty(property);
if (newProperty === false) {
// Ignore unsupported properties
console.warn('Unsupported CSS property ' + property);
return;
}

var newValue = _getPrefixedValue(newProperty.js, value);
if (newValue === false) {
// Ignore unsupported values
console.warn(
'Unsupported CSS value ' + value + ' for property ' + property
);
}

newStyle[newProperty[mode]] = newValue;
});
return newStyle;
};
/*eslint-enable no-console */

module.exports = prefix;
6 changes: 4 additions & 2 deletions modules/resolve-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

var MouseUpListener = require('./mouse-up-listener');
var getState = require('./get-state');
var prefix = require('./prefix');

var React = require('react/addons');
var clone = require('lodash/lang/clone');
Expand Down Expand Up @@ -136,7 +137,8 @@ var resolveStyles = function (component, renderedElement, existingKeyMap) {
!Object.keys(style).some(_isSpecialKey)
) {
if (style) {
newProps.style = style;
// Still perform vendor prefixing, though.
newProps.style = prefix(style);
return React.cloneElement(renderedElement, newProps, newChildren);
} else if (newChildren) {
return React.cloneElement(renderedElement, {}, newChildren);
Expand Down Expand Up @@ -229,7 +231,7 @@ var resolveStyles = function (component, renderedElement, existingKeyMap) {
);
}

newProps.style = newStyle;
newProps.style = prefix(newStyle);

return React.cloneElement(renderedElement, newProps, newChildren);
};
Expand Down

0 comments on commit 66dbd7a

Please sign in to comment.