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

Vendor prefixing #109

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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, mode) {
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;
7 changes: 5 additions & 2 deletions modules/resolve-styles.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

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

var React = require('react/addons');
var clone = require('lodash/lang/clone');
var isArray = require('lodash/lang/isArray');
Expand Down Expand Up @@ -137,7 +139,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 @@ -230,7 +233,7 @@ var resolveStyles = function (component, renderedElement, existingKeyMap) {
);
}

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

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