diff --git a/docs/package.json b/docs/package.json index 040d240e765941..63697369250ee0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -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", diff --git a/package.json b/package.json index 241ffa990386ff..7047efd49a2a69 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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", diff --git a/src/circular-progress.jsx b/src/circular-progress.jsx index b7902350a04a37..d2584cd93b2ae1 100644 --- a/src/circular-progress.jsx +++ b/src/circular-progress.jsx @@ -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); }, diff --git a/src/left-nav.jsx b/src/left-nav.jsx index 4178fc29841c2c..e01b11c12f19da 100644 --- a/src/left-nav.jsx +++ b/src/left-nav.jsx @@ -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) { diff --git a/src/menus/menu.jsx b/src/menus/menu.jsx index bc5fd33d61a6f3..5981e178b36a19 100644 --- a/src/menus/menu.jsx +++ b/src/menus/menu.jsx @@ -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); diff --git a/src/refresh-indicator.jsx b/src/refresh-indicator.jsx index c7d3ea0f9b3f0b..1ec4f8c3c5ddd5 100644 --- a/src/refresh-indicator.jsx +++ b/src/refresh-indicator.jsx @@ -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) { @@ -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); diff --git a/src/ripples/focus-ripple.jsx b/src/ripples/focus-ripple.jsx index d0c8af2a13ec5e..70eab51c580555 100644 --- a/src/ripples/focus-ripple.jsx +++ b/src/ripples/focus-ripple.jsx @@ -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); }, diff --git a/src/styles/auto-prefix.js b/src/styles/auto-prefix.js index 558ccc325247c6..6ae1ae2f4ba787 100644 --- a/src/styles/auto-prefix.js +++ b/src/styles/auto-prefix.js @@ -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; }, }; diff --git a/src/styles/transitions.js b/src/styles/transitions.js index 0d0949cb981ffd..9f082604fbe6ce 100644 --- a/src/styles/transitions.js +++ b/src/styles/transitions.js @@ -32,7 +32,7 @@ module.exports = { delay = delay || '0ms'; easeFunction = easeFunction || "linear"; - return AutoPrefix.singleHyphened(property) + ' ' + + return property + ' ' + duration + ' ' + easeFunction + ' ' + delay;