Skip to content

Commit

Permalink
React 0.12 compatibility.
Browse files Browse the repository at this point in the history
See #97.
  • Loading branch information
STRML committed Dec 21, 2014
1 parent c576daf commit 3d3d4dc
Show file tree
Hide file tree
Showing 16 changed files with 346 additions and 230 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
node_modules/
bundle.js
tests/*.jsx
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ test-server:
@./node_modules/.bin/mocha -R spec -b tests/server.js

test-local:
@./node_modules/.bin/zuul --local 3000 -- tests/browser.js
@./node_modules/.bin/jsx tests/browser-jsx.jsx > tests/browser-jsx.js
@./node_modules/.bin/zuul --local 3000 -- tests/browser.js tests/browser-jsx.js

test-cloud:
@./node_modules/.bin/zuul -- tests/browser.js
Expand Down
9 changes: 8 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ component's `render()` method:

Alternatively, if you don't prefer JSX:

var Locations = React.createFactory(Router.Locations);
var Location = React.createFactory(Router.Location);
Locations(null,
Location({path: "/", handler: MainPage}),
Location({path: "/users/:username", handler: UserPage}))
Expand Down Expand Up @@ -59,6 +61,11 @@ scope, cause JSX doesn't support namespaces yet:
var Locations = Router.Locations
var Location = Router.Location

Otherwise, as of React 0.12, you must create factories:

var Locations = React.createFactory(Router.Locations)
var Location = React.createFactory(Router.Location)

Now you can define your application as a regular React component which renders
into `Locations` router:

Expand Down Expand Up @@ -90,7 +97,7 @@ successful location match.

The final part is to render your `App` component which activates your router:

React.renderComponent(App(), document.body)
React.renderComponent(React.createElement(App), document.body)

In case no location is matched router would render into an empty set of
elements.
Expand Down
7 changes: 3 additions & 4 deletions lib/AsyncRouteRenderingMixin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";

var merge = require('react/lib/merge');
var assign = Object.assign || require('object.assign');
var prefetchAsyncState = require('react-async/lib/prefetchAsyncState');
var isAsyncComponent = require('react-async/lib/isAsyncComponent');
var RouteRenderingMixin = require('./RouteRenderingMixin');
Expand All @@ -16,7 +16,7 @@ var AsyncRouteRenderingMixin = {
var currentHandler = this.state && this.state.handler;
var nextHandler = state && state.handler;

if (nextHandler &&
if (nextHandler && nextHandler.type &&
isAsyncComponent(nextHandler) &&
// if component's type is the same we would need to skip async state
// update
Expand All @@ -42,8 +42,7 @@ var AsyncRouteRenderingMixin = {
if (this.isMounted() &&
this.state.pendingState &&
this.state.pendingState.match === state.match) {

var nextState = merge(this.state.pendingState, {handler: handler});
var nextState = assign({}, this.state.pendingState, {handler: handler});
this.replaceState(nextState, cb);

}
Expand Down
8 changes: 4 additions & 4 deletions lib/CaptureClicks.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var React = require('react');
var urllite = require('urllite/lib/core');
var Environment = require('./environment');
var assign = Object.assign || require('object.assign');

/**
* A container component which captures <a> clicks and, if there's a matching
Expand Down Expand Up @@ -109,11 +110,10 @@ var CaptureClicks = React.createClass({
},

render: function() {
var props = {
var props = assign({}, this.props, {
onClick: this.onClick
};
return this.transferPropsTo(
this.props.component(props, this.props.children));
});
return this.props.component(props, this.props.children);
}

});
Expand Down
7 changes: 4 additions & 3 deletions lib/Link.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var React = require('react');
var NavigatableMixin = require('./NavigatableMixin');
var Environment = require('./environment');
var assign = Object.assign || require('object.assign');

/**
* Link.
Expand Down Expand Up @@ -70,11 +71,11 @@ var Link = React.createClass({
},

render: function() {
var props = {
var props = assign({}, this.props, {
onClick: this.onClick,
href: this._createHref()
};
return this.transferPropsTo(React.DOM.a(props, this.props.children));
});
return React.DOM.a(props, this.props.children);
}
});

Expand Down
103 changes: 37 additions & 66 deletions lib/Route.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,43 @@
"use strict";

var invariant = require('react/lib/invariant');
var merge = require('react/lib/merge');
var mergeInto = require('react/lib/mergeInto');

/**
* Create a new route descriptor from a specification.
*
* @param {Object} spec
* @param {?Object} defaults
*/
function createRoute(spec, defaults) {

var handler = spec.handler;
var path = spec.path;
var ref = spec.ref;
var matchKeys = spec.matchKeys;
var props = merge({}, spec);

delete props.path;
delete props.handler;
delete props.ref;
delete props.matchKeys;

var route = {
path: path,
handler: handler,
props: props,
matchKeys: matchKeys,
ref: ref
};

if (defaults) {
mergeInto(route, defaults);
}

invariant(
typeof route.handler === 'function',
"Route handler should be a component or a function but got: %s", handler
);

invariant(
route.path !== undefined,
"Route should have an URL pattern specified: %s", handler
);

return route;
}

/**
* Regular route descriptor.
*
* @param {Object} spec
*/
function Route(spec) {
return createRoute(spec);
}

/**
* Catch all route descriptor.
*
* @param {Object} spec
*/
function NotFound(spec) {
return createRoute(spec, {path: null});
var React = require('react');

function createClass(name) {
return React.createClass({
propTypes: {
handler: React.PropTypes.oneOfType([
React.PropTypes.node,
React.PropTypes.func
]).isRequired,
path: name === 'NotFound' ?
function(props, propName) {
if (props[propName]) throw new Error("Don't pass a `path` to NotFound.");
}
: React.PropTypes.string.isRequired
},
getDefaultProps: function() {
if (name === 'NotFound') {
return {path: null};
}
return {};
},
render: function() {
throw new Error(name + " is not meant to be directly rendered.");
}
});
}

module.exports = {
Route: Route,
NotFound: NotFound
/**
* Regular route descriptor.
*
* @param {Object} spec
*/
Route: createClass('Route'),
/**
* Catch all route descriptor.
*
* @param {Object} spec
*/
NotFound: createClass('NotFound')
};
6 changes: 3 additions & 3 deletions lib/RouteRenderingMixin.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
"use strict";

var cloneWithProps = require('react/lib/cloneWithProps');
var cloneWithProps = require('react/lib/cloneWithProps');

/**
* Mixin for routers which implements the simplest rendering strategy.
*/
var RouteRenderingMixin = {

renderRouteHandler: function() {
var ref = this.state.match.route && this.state.match.route.ref;
return cloneWithProps(this.state.handler, {ref: ref});
var handler = this.state.handler;
return cloneWithProps(handler, {ref: this.state.match.route.ref});
}

};
Expand Down
7 changes: 6 additions & 1 deletion lib/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var React = require('react');
var RouterMixin = require('./RouterMixin');
var AsyncRouteRenderingMixin = require('./AsyncRouteRenderingMixin');
var assign = Object.assign || require('object.assign');

/**
* Create a new router class
Expand All @@ -29,8 +30,12 @@ function createRouter(name, component) {
},

render: function() {
// Render the Route's handler.
var handler = this.renderRouteHandler();
return this.transferPropsTo(this.props.component(null, handler));
// Pass all props except this component to the Router (containing div/body).
var props = assign({}, this.props);
delete props.component;
return this.props.component(props, handler);
}
});
}
Expand Down
4 changes: 2 additions & 2 deletions lib/RouterMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

var React = require('react');
var invariant = require('react/lib/invariant');
var merge = require('react/lib/merge');
var assign = Object.assign || require('object.assign');
var matchRoutes = require('./matchRoutes');
var Environment = require('./environment');

Expand Down Expand Up @@ -161,7 +161,7 @@ var RouterMixin = {
navigation: navigation
};

navigation = merge(navigation, {match: match});
assign(navigation, {match: match});

if (this.props.onBeforeNavigation &&
this.props.onBeforeNavigation(path, navigation) === false) {
Expand Down
35 changes: 19 additions & 16 deletions lib/matchRoutes.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"use strict";

var pattern = require('url-pattern');
var mergeInto = require('react/lib/mergeInto');
var assign = Object.assign || require('object.assign');
var invariant = require('react/lib/invariant');
var React = require('react');

/**
* Match routes against a path
Expand All @@ -22,17 +23,23 @@ function matchRoutes(routes, path) {
// Simply skip null or undefined to allow ternaries in route definitions
if (!current) continue;

// We expect to be passed an Element. If we weren't, and were just passed props,
// mock an Element's structure.
if (!React.isValidElement(current)) {
current = {props: current, ref: current.ref};
}

if (process.env.NODE_ENV !== "production") {
invariant(
current.handler !== undefined && current.path !== undefined,
current.props.handler !== undefined && current.props.path !== undefined,
"Router should contain either Route or NotFound components " +
"as routes")
}

if (current.path) {
current.pattern = current.pattern || pattern.newPattern(current.path);
if (current.props.path) {
current.props.pattern = current.props.pattern || pattern.newPattern(current.props.path);
if (!page) {
match = current.pattern.match(path);
match = current.props.pattern.match(path);
if (match) {
page = current;
}
Expand All @@ -42,7 +49,7 @@ function matchRoutes(routes, path) {
}
}
}
if (!notFound && current.path === null) {
if (!notFound && current.props.path === null) {
notFound = current;
}
}
Expand Down Expand Up @@ -91,16 +98,12 @@ function Match(path, route, match) {
}

Match.prototype.getHandler = function() {
var props = {};
if (this.match) {
mergeInto(props, this.match);
}
if (this.route && this.route.props) {
mergeInto(props, this.route.props);
}
// we will set ref later during a render call
delete props.ref;
return this.route ? this.route.handler(props) : undefined;
if (!this.route) return undefined;
var props = assign({}, this.route.props, this.match);
delete props.pattern;
delete props.path;
delete props.handler;
return this.route.props.handler(props);
}

module.exports = matchRoutes;
23 changes: 10 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,22 @@
"main": "index.js",
"dependencies": {
"envify": "^1.2.1",
"react": "^0.11.1",
"object.assign": "^1.0.1",
"react": "^0.12.0",
"react-async": "~2.0.0",
"url-pattern": "~0.6.0",
"urllite": "~0.4.0"
},
"peerDependencies": {
"react": "~0.11.0",
"react-async": "~1.0.1"
},
"devDependencies": {
"react": "~0.11.0",
"react-async": "~1.0.1",
"semver": "~2.2.1",
"mocha": "~1.17.1",
"jshint": "~2.4.3",
"zuul": "~1.5.2",
"browserify": "^3.32.1",
"browserify-shim": "^3.3.1",
"jshint": "~2.4.3",
"mocha": "~1.17.1",
"react-tools": "^0.12.0",
"reactify": "^0.15.1",
"semver": "~2.2.1",
"uglify-js": "^2.4.13",
"browserify": "^3.32.1",
"reactify": "^0.14.0"
"zuul": "~1.5.2"
},
"browserify": {
"transform": [
Expand Down
Loading

0 comments on commit 3d3d4dc

Please sign in to comment.