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

Vendor prefix #128

Merged
merged 6 commits into from
May 7, 2015
Merged
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) {
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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary since it runs in the browser. You can test all prefixes and once you found one that works, it becomes the prefix for the rest of the session.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm not following you. What part is unnecessary? The code determines the prefix at the top of the file, and caches the result for individual properties/values.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh apologies, I was completely misreading this. Need more coffee 💩

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah no problem. Thanks much for taking a look!

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