diff --git a/README.md b/README.md
index 24405e0..f626bff 100644
--- a/README.md
+++ b/README.md
@@ -21,39 +21,39 @@ This module is pretty straightforward: You specify a set of requirements, and th
## Usage
-A mq element functions like any other React component, which means you can nest them and do all the normal jazz.
+A MediaQuery element functions like any other React component, which means you can nest them and do all the normal jazz.
### Using CSS Media Queries
-```js
-var mq = require('react-responsive');
+```jsx
+var MediaQuery = require('react-responsive');
var A = React.createClass({
render: function(){
return (
Device Test!
-
+
You are a desktop or laptop
-
+
You also have a huge screen
-
-
+
+
You are sized like a tablet or mobile phone though
-
-
-
+
+
+
You are a tablet or mobile phone
-
-
+
+
You are portrait
-
-
+
+
You are landscape
-
-
+
+
You are retina
-
+
);
}
@@ -71,35 +71,81 @@ For a list of all possible shorthands and value types see https://github.com/wea
Any numbers given as a shorthand will be expanded to px (`1234` will become `'1234px'`)
-```js
-var mq = require('react-responsive');
+```jsx
+var MediaQuery = require('react-responsive');
var A = React.createClass({
render: function(){
return (
Device Test!
-
+
You are a desktop or laptop
-
+
You also have a huge screen
-
-
+
+
You are sized like a tablet or mobile phone though
-
-
-
+
+
+
You are a tablet or mobile phone
-
-
+
+
You are portrait
-
-
+
+
You are landscape
-
-
+
+
You are retina
-
+
+
+ );
+ }
+});
+```
+
+### Server rendering
+
+Server rendering can be done by passing static values through the `values` property.
+
+The values property can contain `orientation`, `scan`, `aspectRatio`, `deviceAspectRatio`,
+`height`, `deviceHeight`, `width`, `deviceWidth`, `color`, `colorIndex`, `monochrome`,
+ `resolution` and `type` to be matched against the media query.
+
+`type` can be one of: `all`, `grid`, `aural`, `braille`, `handheld`, `print`, `projection`,
+`screen`, `tty`, `tv` or `embossed`.
+
+```jsx
+var MediaQuery = require('react-responsive');
+
+var A = React.createClass({
+ render: function(){
+ return (
+
+
Device Test!
+
+ You are a desktop or laptop
+
+ You also have a huge screen
+
+
+ You are sized like a tablet or mobile phone though
+
+
+
+ You are a tablet or mobile phone
+
+
+ You are portrait
+
+
+ You are landscape
+
+
+ You are retina
+
);
}
@@ -145,4 +191,4 @@ Pretty much everything. Check out these polyfills:
[downloads-image]: http://img.shields.io/npm/dm/react-responsive.svg
[npm-url]: https://npmjs.org/package/react-responsive
-[npm-image]: http://img.shields.io/npm/v/react-responsive.svg
\ No newline at end of file
+[npm-image]: http://img.shields.io/npm/v/react-responsive.svg
diff --git a/gulpfile.js b/gulpfile.js
index 4d48ab4..a03a751 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -42,6 +42,15 @@ var sampleBundler = watchify(browserify('./samples/sandbox/src/index.jsx', {
}));
sampleBundler.transform(reactify);
+var staticSampleBundler = watchify(browserify('./samples/static/src/index.jsx', {
+ cache: bundleCache,
+ packageCache: pkgCache,
+ fullPaths: true,
+ standalone: 'sample',
+ debug: true
+}));
+staticSampleBundler.transform(reactify);
+
gulp.task('watch', function(){
bundler.on('update', function(){
gulp.start('js');
@@ -79,11 +88,20 @@ gulp.task('samples', function(){
.pipe(gulp.dest('samples/sandbox/dist'))
.pipe(lr());
+ var browserifyStream2 = staticSampleBundler.bundle()
+ // browserify -> gulp transfer
+ .pipe(source('index.js'))
+ .pipe(buffer())
+ .pipe(cached('index'))
+ .pipe(sourcemaps.init({loadMaps: true}))
+ .pipe(sourcemaps.write('.'))
+ .pipe(gulp.dest('samples/static/dist'));
+
var staticStream = gulp.src(['samples/sandbox/src/**/*', '!samples/sandbox/src/**/*.js'])
.pipe(cached('static-samples'))
.pipe(gulp.dest('samples/sandbox/dist'));
- return merge(staticStream, browserifyStream);
+ return merge(staticStream, browserifyStream, browserifyStream2);
});
gulp.task('sample-server', function(cb){
diff --git a/package.json b/package.json
index 3ba3db5..ebeffe0 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
],
"dependencies": {
"lodash.omit": "^3.0.0",
+ "matchmedia": "^0.1.1",
"object-assign": "^2.0.0"
},
"peerDependencies": {
@@ -43,7 +44,7 @@
"jshint-stylish": "^0.4.0",
"merge-stream": "^0.1.5",
"mocha": "^1.20.1",
- "reactify": "^0.14.0",
+ "reactify": "^1.0.0",
"should": "^4.0.4",
"vinyl-buffer": "0.0.0",
"vinyl-source-stream": "^0.1.1",
diff --git a/samples/sandbox/src/index.jsx b/samples/sandbox/src/index.jsx
index 5217022..753956b 100644
--- a/samples/sandbox/src/index.jsx
+++ b/samples/sandbox/src/index.jsx
@@ -1,9 +1,8 @@
-/** @jsx React.DOM */
/* global document, window */
'use strict';
-var mq = require('../../../src');
+var MediaQuery = require('../../../src');
var React = require('react');
window.React = React; // for dev
@@ -13,31 +12,31 @@ var App = React.createClass({
return (
Device Test!
-
+
You are a desktop or laptop
-
+
You also have a huge screen
-
-
+
+
You are sized like a tablet or mobile phone though
-
-
-
+
+
+
You are a tablet or mobile phone
-
+
-
+
You are portrait
-
-
+
+
You are landscape
-
-
+
+
You are retina
-
+
);
}
});
-React.renderComponent(App(), document.body);
\ No newline at end of file
+React.renderComponent(App(), document.body);
diff --git a/samples/static/src/index.jsx b/samples/static/src/index.jsx
new file mode 100644
index 0000000..0a8ceb6
--- /dev/null
+++ b/samples/static/src/index.jsx
@@ -0,0 +1,39 @@
+'use strict';
+
+var MediaQuery = require('../../../src');
+var React = require('react');
+
+var App = React.createClass({
+ displayName: 'demo',
+ render: function(){
+ return (
+
+
Device Test!
+
+ You are a desktop or laptop
+
+ You also have a huge screen
+
+
+ You are sized like a tablet or mobile phone though
+
+
+
+ You are a tablet or mobile phone
+
+
+
+ You are portrait
+
+
+ You are landscape
+
+
+ You are retina
+
+
+ );
+ }
+});
+
+console.log(React.renderToString());
diff --git a/src/index.js b/src/index.js
index 727455a..869860f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -4,13 +4,15 @@
var React = require('react');
var omit = require('lodash.omit');
+var matchMedia = require('matchmedia');
+var hyphenate = require('react/lib/hyphenateStyleName');
var mediaQuery = require('./mediaQuery');
var toQuery = require('./toQuery');
-var matchMedia = typeof window !== 'undefined' ? window.matchMedia : null;
var defaultTypes = {
- component: React.PropTypes.func,
- query: React.PropTypes.string
+ component: React.PropTypes.node,
+ query: React.PropTypes.string,
+ values: React.PropTypes.shape(mediaQuery.matchers)
};
var mediaKeys = Object.keys(mediaQuery.all);
var excludedQueryKeys = Object.keys(defaultTypes);
@@ -21,7 +23,8 @@ var mq = React.createClass({
getDefaultProps: function(){
return {
- component: React.DOM.div
+ component: 'div',
+ values: {}
};
},
@@ -40,6 +43,7 @@ var mq = React.createClass({
},
updateQuery: function(props){
+ var values;
if (props.query) {
this.query = props.query;
} else {
@@ -49,7 +53,16 @@ var mq = React.createClass({
if (!this.query) {
throw new Error('Invalid or missing MediaQuery!');
}
- this._mql = matchMedia(this.query);
+
+ if (props.values) {
+ values = Object.keys(props.values)
+ .reduce(function(result, key){
+ result[hyphenate(key)] = props.values[key];
+ return result;
+ }, {});
+ }
+
+ this._mql = matchMedia(this.query, values);
this._mql.addListener(this.updateMatches);
this.updateMatches();
},
@@ -72,7 +85,7 @@ var mq = React.createClass({
return null;
}
var props = omit(this.props, excludedPropKeys);
- return this.props.component(props, this.props.children);
+ return React.createElement(this.props.component, props, this.props.children);
}
});
diff --git a/src/mediaQuery.js b/src/mediaQuery.js
index a002f06..b774e69 100644
--- a/src/mediaQuery.js
+++ b/src/mediaQuery.js
@@ -6,8 +6,8 @@ var stringOrNumber = PropTypes.oneOfType([
PropTypes.number
]);
-var features = {
- // media features
+// properties that match media queries
+var matchers = {
orientation: PropTypes.oneOf([
'portrait',
'landscape'
@@ -19,45 +19,57 @@ var features = {
]),
aspectRatio: PropTypes.string,
+ deviceAspectRatio: PropTypes.string,
+
+ height: stringOrNumber,
+ deviceHeight: stringOrNumber,
+
+ width: stringOrNumber,
+ deviceWidth: stringOrNumber,
+
+ color: PropTypes.bool,
+
+ colorIndex: PropTypes.bool,
+
+ monochrome: PropTypes.bool,
+ resolution: stringOrNumber
+};
+
+// media features
+var features = {
minAspectRatio: PropTypes.string,
maxAspectRatio: PropTypes.string,
- deviceAspectRatio: PropTypes.string,
minDeviceAspectRatio: PropTypes.string,
maxDeviceAspectRatio: PropTypes.string,
- height: stringOrNumber,
minHeight: stringOrNumber,
maxHeight: stringOrNumber,
- deviceHeight: stringOrNumber,
minDeviceHeight: stringOrNumber,
maxDeviceHeight: stringOrNumber,
- width: stringOrNumber,
minWidth: stringOrNumber,
maxWidth: stringOrNumber,
- deviceWidth: stringOrNumber,
minDeviceWidth: stringOrNumber,
maxDeviceWidth: stringOrNumber,
- color: PropTypes.bool,
minColor: PropTypes.number,
maxColor: PropTypes.number,
- colorIndex: PropTypes.bool,
minColorIndex: PropTypes.number,
maxColorIndex: PropTypes.number,
- monochrome: PropTypes.bool,
minMonochrome: PropTypes.number,
maxMonochrome: PropTypes.number,
- resolution: stringOrNumber,
minResolution: stringOrNumber,
maxResolution: stringOrNumber
};
+assign(features, matchers);
+
// media types
var types = {
+ all: PropTypes.bool,
grid: PropTypes.bool,
aural: PropTypes.bool,
braille: PropTypes.bool,
@@ -74,8 +86,12 @@ var all = {};
assign(all, types);
assign(all, features);
+// add the type property
+assign(matchers, { type: Object.keys(types) });
+
module.exports = {
all: all,
types: types,
+ matchers: matchers,
features: features
};