Skip to content

Commit

Permalink
Implemented inline-style-prefixer
Browse files Browse the repository at this point in the history
User agent based prefixing for client and server side rendering. When
rendering server-side define `navigator.userAgent` after receiving
request headers but before rendering styles. A warning will be shown
when attempting to use server-side rendering without defining a user
agent. Client side rendering should automatically work as all modern
browsers provide user agent via the navigator property.
  • Loading branch information
Daviejoe100 authored and TheUltDev committed Nov 1, 2015
1 parent 68baf9b commit b12bcdd
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 63 deletions.
3 changes: 2 additions & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"react-dom": "^0.14.0",
"react-motion": "^0.3.1",
"react-swipeable-views": "^0.3.0",
"react-tap-event-plugin": "^0.2.0"
"react-tap-event-plugin": "^0.2.0",
"inline-style-prefixer": "^0.3.3"
},
"devDependencies": {
"raw-loader": "^0.5.1",
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
},
"homepage": "http://material-ui.com/",
"peerDependencies": {
"inline-style-prefixer": "^0.3.3",
"react": "^0.14.0",
"react-dom": "^0.14.0",
"react-tap-event-plugin": "^0.2.0",
Expand All @@ -54,6 +55,7 @@
"gulp": "^3.9.0",
"gulp-eslint": "^1.0.0",
"html-webpack-plugin": "^1.6.1",
"inline-style-prefixer": "^0.3.3",
"karma": "^0.13.3",
"karma-browserify": "^4.2.1",
"karma-chai-sinon": "^0.1.5",
Expand Down
11 changes: 6 additions & 5 deletions src/circular-progress.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,16 @@ const CircularProgress = React.createClass({
if (!this.isMounted()) return;
if (this.props.mode !== "indeterminate") return;

AutoPrefix.set(wrapper.style, "transform", null);
AutoPrefix.set(wrapper.style, "transform", "rotate(0deg)");
wrapper.style.transform = null;
wrapper.style.transform = "rotate(0deg)";
wrapper.style.transitionDuration = "0ms";
wrapper.style = AutoPrefix.all(wrapper.style);

setTimeout(() => {
AutoPrefix.set(wrapper.style, "transform", "rotate(1800deg)");
wrapper.style.transform = "rotate(1800deg)";
wrapper.style.transitionDuration = "10s";
//wrapper.style.webkitTransitionTimingFunction = "linear";
AutoPrefix.set(wrapper.style, "transitionTimingFunction", "linear");
wrapper.style.transitionTimingFunction = "linear";
wrapper.style = AutoPrefix.all(wrapper.style);
}, 50);
},

Expand Down
4 changes: 2 additions & 2 deletions src/left-nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,9 @@ const LeftNav = React.createClass({

_setPosition(translateX) {
let leftNav = ReactDOM.findDOMNode(this.refs.clickAwayableElement);
leftNav.style[AutoPrefix.single('transform')] =
'translate3d(' + (this._getTranslateMultiplier() * translateX) + 'px, 0, 0)';
let transformCSS = 'translate3d(' + (this._getTranslateMultiplier() * translateX) + 'px, 0, 0)';
this.refs.overlay.setOpacity(1 - translateX / this._getMaxTranslateX());
AutoPrefix.set(leftNav.style, 'transform', transformCSS);
},

_getTranslateX(currentX) {
Expand Down
7 changes: 3 additions & 4 deletions src/menus/menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,10 @@ const Menu = React.createClass({

componentWillLeave(callback) {
let rootStyle = ReactDOM.findDOMNode(this).style;

AutoPrefix.set(rootStyle, 'transition', Transitions.easeOut('250ms', ['opacity', 'transform']));
AutoPrefix.set(rootStyle, 'transform', 'translate3d(0,-8px,0)');
rootStyle.transition = Transitions.easeOut('250ms', ['opacity', 'transform']);
rootStyle.transform = 'translate3d(0,-8px,0)';
rootStyle.opacity = 0;

rootStyle = AutoPrefix.all(rootStyle);
setTimeout(() => {
if (this.isMounted()) callback();
}, 250);
Expand Down
25 changes: 15 additions & 10 deletions src/refresh-indicator.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,19 +250,24 @@ const RefreshIndicator = React.createClass({
const perimeter = Math.PI * 2 * circle.radiu;
const arcLen = perimeter * 0.64;

let strokeDasharray, strokeDashoffset, transitionDuration;
if (currStep === 0) {
path.style.strokeDasharray = '1, 200';
path.style.strokeDashoffset = 0;
path.style[this.prefixed('transitionDuration')] = '0ms';
strokeDasharray = '1, 200';
strokeDashoffset = 0;
transitionDuration = '0ms';
} else if (currStep === 1) {
path.style.strokeDasharray = arcLen + ', 200';
path.style.strokeDashoffset = -15;
path.style[this.prefixed('transitionDuration')] = '750ms';
strokeDasharray = arcLen + ', 200';
strokeDashoffset = -15;
transitionDuration = '750ms';
} else {
path.style.strokeDasharray = arcLen + ',200';
path.style.strokeDashoffset = -(perimeter - 1);
path.style[this.prefixed('transitionDuration')] = '850ms';
strokeDasharray = arcLen + ',200';
strokeDashoffset = -(perimeter - 1);
transitionDuration = '850ms';
}

AutoPrefix.set(path.style, "strokeDasharray", strokeDasharray);
AutoPrefix.set(path.style, "strokeDashoffset", strokeDashoffset);
AutoPrefix.set(path.style, "transitionDuration", transitionDuration);
},

_rotateWrapper(wrapper) {
Expand All @@ -278,7 +283,7 @@ const RefreshIndicator = React.createClass({
setTimeout(() => {
if (this.isMounted()) {
AutoPrefix.set(wrapper.style, "transform", "rotate(1800deg)");
wrapper.style.transitionDuration = "10s";
AutoPrefix.set(wrapper.style, "transitionDuration", "10s");
AutoPrefix.set(wrapper.style, "transitionTimingFunction", "linear");
}
}, 50);
Expand Down
4 changes: 2 additions & 2 deletions src/ripples/focus-ripple.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,14 @@ const FocusRipple = React.createClass({

const startScale = 'scale(1)';
const endScale = 'scale(0.85)';
let currentScale = innerCircle.style[AutoPrefix.single('transform')];
let currentScale = innerCircle.style.transform;
let nextScale;

currentScale = currentScale || startScale;
nextScale = currentScale === startScale ?
endScale : startScale;

innerCircle.style[AutoPrefix.single('transform')] = nextScale;
AutoPrefix.set(innerCircle.style, 'transform', nextScale);
this._timeout = setTimeout(this._pulsate, pulsateDuration);
},

Expand Down
68 changes: 30 additions & 38 deletions src/styles/auto-prefix.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,44 @@
const isBrowser = require('../utils/is-browser');
import InlineStylePrefixer from 'inline-style-prefixer';

const Modernizr = isBrowser ? require('../utils/modernizr.custom') : undefined;

//Keep track of already prefixed keys so we can skip Modernizr prefixing
let prefixedKeys = {};
const prefixers = {};

module.exports = {

all(styles) {
let prefixedStyle = {};
for (let key in styles) {
prefixedStyle[this.single(key)] = styles[key];
getPrefixer() {
let userAgent;

// Server-side renderer needs to supply user agent
if (typeof navigator === 'undefined') {
console.warn(`Material-UI expects the global navigator.userAgent to be defined for server-side rendering. Set this property when receiving the request headers.`)
userAgent = '*';
} else {
userAgent = navigator.userAgent;
}
return prefixedStyle;
},

set(style, key, value) {
style[this.single(key)] = value;
// Get prefixing instance for this user agent
let prefixer = prefixers[userAgent];
// None found, create a new instance
if (!prefixer) {
prefixer = new InlineStylePrefixer(userAgent);
prefixers[userAgent] = prefixer;
}
return prefixer;
},

single(key) {

//If a browser doesn't exist, we can't prefix with Modernizr so
//just return the key
if (!isBrowser) return key;

//Check if we've prefixed this key before, just return it
if (prefixedKeys.hasOwnProperty(key)) return prefixedKeys[key];

//Key hasn't been prefixed yet, prefix with Modernizr
const prefKey = Modernizr.prefixed(key);

// Windows 7 Firefox has an issue with the implementation of Modernizr.prefixed
// and is capturing 'false' as the CSS property name instead of the non-prefixed version.
if (prefKey === false) return key;

//Save the key off for the future and return the prefixed key
prefixedKeys[key] = prefKey;
return prefKey;

all(styles) {
return this.getPrefixer().prefix(styles);
},

singleHyphened(key) {
let str = this.single(key);
set(style, key, value) {
style[key] = value;
style = this.getPrefixer().prefix(style);
},

return !str ? key : str.replace(/([A-Z])/g, (str, m1) => {
return '-' + m1.toLowerCase();
}).replace(/^ms-/, '-ms-');
getPrefix(key) {
let style = {};
style[key] = true;
let prefixes = Object.keys(this.getPrefixer().prefix(style));
return prefixes ? prefixes[0] : key;
},

};
2 changes: 1 addition & 1 deletion src/styles/transitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module.exports = {
delay = delay || '0ms';
easeFunction = easeFunction || "linear";

return AutoPrefix.singleHyphened(property) + ' ' +
return property + ' ' +
duration + ' ' +
easeFunction + ' ' +
delay;
Expand Down

0 comments on commit b12bcdd

Please sign in to comment.