Socket
Socket
Sign inDemoInstall

react-router

Package Overview
Dependencies
Maintainers
2
Versions
517
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-router - npm Package Compare versions

Comparing version 1.0.0-beta3 to 1.0.0-beta4

.eslintrc

24

CHANGELOG.md

@@ -0,1 +1,25 @@

v1.0.0-beta4 - Mon, 31 Aug 2015 06:19:34 GMT
--------------------------------------------
- [94509e7](../../commit/94509e7) [added] IndexLink
- [adc0a2f](../../commit/adc0a2f) [added] IndexRoute
- [b86509a](../../commit/b86509a) [added] useRoutes history enhancer [added] RoutingContext component [added] RouteContext mixin [added] Lifecycle mixin
- [e72812d](../../commit/e72812d) [added] <Router initialState>
- [4c6dc1b](../../commit/4c6dc1b) [fixed] Installing on Windows
- [042cffc](../../commit/042cffc) [changed] Removed histories/added history dep
- [af7eb55](../../commit/af7eb55) [added] History.onBeforeChange
- [f4ed900](../../commit/f4ed900) [fixed] correctly updates the window scroll position
- [587e54f](../../commit/587e54f) [added] static `history` singleton getter for `HashHistory` and `BrowserHistory`
- [5bd62b5](../../commit/5bd62b5) [fixed] errors in examples
- [4e2ca3c](../../commit/4e2ca3c) [fixed] URI escape path components with special chars
- [0630488](../../commit/0630488) [fixed] Link module adds extra space
- [26400c1](../../commit/26400c1) [fixed] Use encodeURI for splat params
- [178efc3](../../commit/178efc3) [fixed] <Link href> when using HashHistory
- [41bd525](../../commit/41bd525) [fixed] Properly escape splats
- [4759961](../../commit/4759961) [fixed] URLUtils recognize values containing \n
- [2389c61](../../commit/2389c61) [changed] Export history classes
- [824ed63](../../commit/824ed63) [fixed] <Redirect> handling
- [2447ecb](../../commit/2447ecb) [added] formatPattern util method
v0.13.3 - Wed, 29 Apr 2015 01:47:08 GMT

@@ -2,0 +26,0 @@ ---------------------------------------

2

CONTRIBUTING.md

@@ -38,3 +38,3 @@ ### Tests

- `npm test` will fire up a karma test runner and watch for changes
- `npm run examples` fires up a webpack dev server that will watch
- `npm start` fires up a webpack dev server that will watch
for changes and build the examples

@@ -41,0 +41,0 @@

@@ -0,6 +1,7 @@

## Overview
To illustrate the problems React Router is going to solve for you, let’s build a
small application without it.
Without React Router
--------------------
### Without React Router

@@ -13,3 +14,3 @@ ```js

var App = React.createClass({
getInitialState () {
getInitialState() {
return {

@@ -20,3 +21,3 @@ route: window.location.hash.substr(1)

componentDidMount () {
componentDidMount() {
window.addEventListener('hashchange', () => {

@@ -29,3 +30,3 @@ this.setState({

render () {
render() {
var Child;

@@ -54,8 +55,5 @@ switch (this.state.route) {

As the hash portion of the URL changes, `App` will render a different
`<Child/>` by branching on `this.state.route`. Pretty straightforward
stuff. But it gets complicated fast.
As the hash portion of the URL changes, `App` will render a different `<Child/>` by branching on `this.state.route`. Pretty straightforward stuff. But it gets complicated fast.
Imagine now that `Inbox` has some nested UI at different URLs, maybe
something like this master detail view:
Imagine now that `Inbox` has some nested UI at different URLs, maybe something like this master detail view:

@@ -100,13 +98,7 @@ ```

We'd have to make our url parsing a lot more intelligent, and end up
with a lot of code to figure out which branch of nested components to be
rendered at any given url: `App -> About`, `App -> Inbox -> Messages ->
Message`, `App -> Inbox -> Messages -> Stats`, etc.
We'd have to make our URL parsing a lot more intelligently, and end up with a lot of code to figure out which branch of nested components to be rendered at any given URL: `App -> About`, `App -> Inbox -> Messages -> Message`, `App -> Inbox -> Messages -> Stats`, etc.
With React Router
-----------------
### With React Router
Nested URLs and nested component hierarchy are at the heart of React
Router's declarative API. Lots of people like to use JSX to define their
routes, but you can use plain objects if you want.
Nested URLs and nested component hierarchy are at the heart of React Router's declarative API. Lots of people like to use JSX to define their routes, but you can use plain objects if you want.

@@ -119,4 +111,6 @@ Let's refactor our app to use React Router.

// the histories are imported separately for smaller builds
import { history } from 'react-router/lib/HashHistory';
import createHistory from 'history/lib/createHashHistory';
var history = createHistory();
// ...

@@ -127,3 +121,3 @@

var App = React.createClass({
render () {
render() {
return (

@@ -148,9 +142,9 @@ <div>

// Finally we render a `Router` component with some `Route`s, it'll do all
// the fancy routing stuff for us.
// Finally we render a Router component with some Routes.
// It does all the fancy routing stuff for us.
React.render((
<Router history={history}>
<Route path="/" component={App}>
<Route path="about" component={About}/>
<Route path="inbox" component={Inbox}/>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>

@@ -176,4 +170,3 @@ </Router>

Adding more UI
--------------
### Adding more UI

@@ -185,3 +178,3 @@ Alright, now we're ready to nest the inbox messages inside the inbox UI.

var Message = React.createClass({
render () {
render() {
return <h3>Message</h3>;

@@ -192,3 +185,3 @@ }

var Inbox = React.createClass({
render () {
render() {
return (

@@ -217,16 +210,11 @@ <div>

Now visits to urls like `inbox/messages/Jkei3c32` will match the new
route and nest the UI branch of `App -> Inbox -> Message`.
Now visits to URLs like `inbox/messages/Jkei3c32` will match the new route and nest the UI branch of `App -> Inbox -> Message`.
Getting the url parameters
--------------------------
### Getting the URL parameters
We're going to need to know something about the message in order to
fetch it from the server. Route components get some useful properties
injected into them when you render, particularly the parameters from the
dynamic segment of your path. In our case, `:id`.
We're going to need to know something about the message in order to fetch it from the server. Route components get some useful properties injected into them when you render, particularly the parameters from the dynamic segment of your path. In our case, `:id`.
```js
var Message = React.createClass({
componentDidMount: function () {
componentDidMount() {
// from the path `/inbox/messages/:id`

@@ -233,0 +221,0 @@ var id = this.props.params.id;

@@ -6,3 +6,2 @@ "use strict";

exports.mapAsync = mapAsync;
exports.hashAsync = hashAsync;

@@ -22,4 +21,3 @@ function loopAsync(turns, work, callback) {

if (currentTurn < turns) {
currentTurn += 1;
work.call(this, currentTurn - 1, next, done);
work.call(this, currentTurn++, next, done);
} else {

@@ -62,21 +60,2 @@ done.apply(this, arguments);

});
}
function hashAsync(object, work, callback) {
var keys = Object.keys(object);
mapAsync(keys, function (key, index, callback) {
work(object[key], callback);
}, function (error, valuesArray) {
if (error) {
callback(error);
} else {
var values = valuesArray.reduce(function (memo, results, index) {
memo[keys[index]] = results;
return memo;
}, {});
callback(null, values);
}
});
}
'use strict';
exports.__esModule = true;
exports.addEventListener = addEventListener;
exports.removeEventListener = removeEventListener;
exports.getHashPath = getHashPath;

@@ -14,2 +16,18 @@ exports.replaceHashPath = replaceHashPath;

function addEventListener(node, type, listener) {
if (node.addEventListener) {
node.addEventListener(type, listener, false);
} else {
node.attachEvent('on' + type, listener);
}
}
function removeEventListener(node, type, listener) {
if (node.removeEventListener) {
node.removeEventListener(type, listener, false);
} else {
node.detachEvent('on' + type, listener);
}
}
function getHashPath() {

@@ -31,4 +49,4 @@ // We can't use window.location.hash here because it's not

return {
scrollX: window.pageXOffset || document.documentElement.scrollLeft,
scrollY: window.pageYOffset || document.documentElement.scrollTop
x: window.pageXOffset || document.documentElement.scrollLeft,
y: window.pageYOffset || document.documentElement.scrollTop
};

@@ -35,0 +53,0 @@ }

@@ -22,2 +22,8 @@ /* components */

var _IndexRoute2 = require('./IndexRoute');
var _IndexRoute3 = _interopRequireDefault(_IndexRoute2);
exports.IndexRoute = _IndexRoute3['default'];
var _Redirect2 = require('./Redirect');

@@ -37,2 +43,8 @@

var _Lifecycle2 = require('./Lifecycle');
var _Lifecycle3 = _interopRequireDefault(_Lifecycle2);
exports.Lifecycle = _Lifecycle3['default'];
var _Navigation2 = require('./Navigation');

@@ -44,7 +56,7 @@

var _TransitionHook2 = require('./TransitionHook');
var _RouteContext2 = require('./RouteContext');
var _TransitionHook3 = _interopRequireDefault(_TransitionHook2);
var _RouteContext3 = _interopRequireDefault(_RouteContext2);
exports.TransitionHook = _TransitionHook3['default'];
exports.RouteContext = _RouteContext3['default'];

@@ -59,2 +71,8 @@ var _State2 = require('./State');

var _useRoutes2 = require('./useRoutes');
var _useRoutes3 = _interopRequireDefault(_useRoutes2);
exports.useRoutes = _useRoutes3['default'];
var _RouteUtils = require('./RouteUtils');

@@ -61,0 +79,0 @@

@@ -13,3 +13,8 @@ 'use strict';

var _warning = require('warning');
var _warning2 = _interopRequireDefault(_warning);
var _React$PropTypes = _react2['default'].PropTypes;
var bool = _React$PropTypes.bool;
var object = _React$PropTypes.object;

@@ -28,9 +33,9 @@ var string = _React$PropTypes.string;

/**
* <Link> components are used to create an <a> element that links to a route.
* When that route is active, the link gets an "active" class name (or the
* value of its `activeClassName` prop).
* A <Link> is used to create an <a> element that links to a route.
* When that route is active, the link gets an "active" class name
* (or the value of its `activeClassName` prop).
*
* For example, assuming you have the following route:
*
* <Route name="showPost" path="/posts/:postID" handler={Post}/>
* <Route path="/posts/:postID" component={Post} />
*

@@ -41,6 +46,6 @@ * You could use the following component to link to that route:

*
* Links may pass along query string parameters
* using the `query` prop.
* Links may pass along location state and/or query string parameters
* in the state/query props, respectively.
*
* <Link to="/posts/123" query={{ show:true }}/>
* <Link ... query={{ show: true }} state={{ the: 'state' }} />
*/

@@ -51,3 +56,3 @@ var Link = _react2['default'].createClass({

contextTypes: {
router: object
history: object
},

@@ -58,2 +63,3 @@

activeClassName: string,
onlyActiveOnIndex: bool.isRequired,
to: string.isRequired,

@@ -69,2 +75,3 @@ query: object,

activeClassName: 'active',
onlyActiveOnIndex: false,
style: {}

@@ -86,21 +93,31 @@ };

if (allowTransition) this.context.router.transitionTo(this.props.to, this.props.query, this.props.state);
if (allowTransition) this.context.history.pushState(this.props.state, this.props.to, this.props.query);
},
componentWillMount: function componentWillMount() {
_warning2['default'](this.context.history, 'A <Link> should not be rendered outside the context of history; ' + 'some features including real hrefs, active styling, and navigation ' + 'will not function correctly');
},
render: function render() {
var router = this.context.router;
var _props = this.props;
var to = _props.to;
var query = _props.query;
var onlyActiveOnIndex = _props.onlyActiveOnIndex;
var props = _extends({}, this.props, {
href: router.makeHref(to, query),
onClick: this.handleClick
});
// ignore if rendered outside of the context of a router, simplifies unit testing
if (router && router.isActive(to, query)) {
if (props.activeClassName) props.className += props.className !== '' ? ' ' + props.activeClassName : props.activeClassName;
var history = this.context.history;
if (props.activeStyle) props.style = _extends({}, props.style, props.activeStyle);
// Ignore if rendered outside the context
// of history, simplifies unit testing.
if (history) {
props.href = history.createHref(to, query);
if (history.isActive(to, query, onlyActiveOnIndex)) {
if (props.activeClassName) props.className += props.className !== '' ? ' ' + props.activeClassName : props.activeClassName;
if (props.activeStyle) props.style = _extends({}, props.style, props.activeStyle);
}
}

@@ -113,3 +130,3 @@

exports.Link = Link;
exports['default'] = Link;
exports['default'] = Link;
module.exports = exports['default'];

@@ -14,3 +14,4 @@ 'use strict';

/**
* A mixin for components that modify the URL.
* The Navigation mixin provides methods for components
* that need to modify the URL.
*

@@ -25,3 +26,3 @@ * Example:

* event.preventDefault();
* this.transitionTo('aRoute', { the: 'params' }, { the: 'query' });
* this.transitionTo('/the/path', { the: 'query' });
* },

@@ -38,3 +39,11 @@ * render() {

contextTypes: {
router: object.isRequired
history: object.isRequired
},
transitionTo: function transitionTo(pathname, query, state) {
return this.context.history.pushState(state, pathname, query);
},
replaceWith: function replaceWith(pathname, query, state) {
return this.context.history.replaceState(state, pathname, query);
}

@@ -44,8 +53,9 @@

var RouterNavigationMethods = ['makePath', 'makeHref', 'transitionTo', 'replaceWith', 'go', 'goBack', 'goForward'];
var RouterNavigationMethods = ['createPath', 'createHref', 'go', 'goBack', 'goForward'];
RouterNavigationMethods.forEach(function (method) {
Navigation[method] = function () {
var router = this.context.router;
return router[method].apply(router, arguments);
var history = this.context.history;
return history[method].apply(history, arguments);
};

@@ -52,0 +62,0 @@ });

'use strict';
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
exports.__esModule = true;
exports.falsy = falsy;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var func = _react.PropTypes.func;
var object = _react.PropTypes.object;
var arrayOf = _react.PropTypes.arrayOf;
var oneOfType = _react.PropTypes.oneOfType;
var element = _react.PropTypes.element;
var shape = _react.PropTypes.shape;
var string = _react.PropTypes.string;
var _Location = require('./Location');
var _Location2 = _interopRequireDefault(_Location);
var _History = require('./History');
var _History2 = _interopRequireDefault(_History);
var _React$PropTypes = _react2['default'].PropTypes;
var func = _React$PropTypes.func;
var object = _React$PropTypes.object;
var arrayOf = _React$PropTypes.arrayOf;
var instanceOf = _React$PropTypes.instanceOf;
var oneOfType = _React$PropTypes.oneOfType;
var element = _React$PropTypes.element;
function falsy(props, propName, componentName) {

@@ -29,17 +20,26 @@ if (props[propName]) return new Error('<' + componentName + '> should not have a "' + propName + '" prop');

var component = func;
var history = shape({
listen: func.isRequired,
pushState: func.isRequired,
replaceState: func.isRequired,
go: func.isRequired
});
exports.history = history;
var location = shape({
pathname: string.isRequired,
search: string.isRequired,
state: object,
action: string.isRequired,
key: string
});
exports.location = location;
var component = oneOfType([func, string]);
exports.component = component;
var components = oneOfType([component, object]);
var history = instanceOf(_History2['default']);
var location = instanceOf(_Location2['default']);
exports.components = components;
var route = oneOfType([object, element]);
exports.route = route;
var routes = oneOfType([route, arrayOf(route)]);
module.exports = {
falsy: falsy,
component: component,
components: components,
history: history,
location: location,
route: route,
routes: routes
};
exports.routes = routes;

@@ -17,3 +17,3 @@ 'use strict';

var _URLUtils = require('./URLUtils');
var _PatternUtils = require('./PatternUtils');

@@ -25,2 +25,10 @@ var _PropTypes = require('./PropTypes');

var object = _React$PropTypes.object;
/**
* A <Redirect> is used to declare another URL path a client should be sent
* to when they request a given URL.
*
* Redirects are placed alongside routes in the route configuration and are
* traversed in the same manner.
*/
var Redirect = _react2['default'].createClass({

@@ -32,13 +40,16 @@ displayName: 'Redirect',

createRouteFromReactElement: function createRouteFromReactElement(element) {
var route = (0, _RouteUtils.createRouteFromReactElement)(element);
var route = _RouteUtils.createRouteFromReactElement(element);
if (route.from) route.path = route.from;
route.onEnter = function (nextState, transition) {
// TODO: Handle relative pathnames, see #1658
_invariant2['default'](route.to.charAt(0) === '/', '<Redirect to> must be an absolute path. This should be fixed in the future');
route.onEnter = function (nextState, redirectTo) {
var location = nextState.location;
var params = nextState.params;
var pathname = route.to ? (0, _URLUtils.formatPattern)(route.to, params) : location.pathname;
var pathname = route.to ? _PatternUtils.formatPattern(route.to, params) : location.pathname;
transition.to(pathname, route.query || location.query, route.state || location.state);
redirectTo(pathname, route.query || location.query, route.state || location.state);
};

@@ -62,3 +73,3 @@

render: function render() {
(0, _invariant2['default'])(false, '<Redirect> elements are for router configuration only and should not be rendered');
_invariant2['default'](false, '<Redirect> elements are for router configuration only and should not be rendered');
}

@@ -68,3 +79,3 @@

exports.Redirect = Redirect;
exports['default'] = Redirect;
exports['default'] = Redirect;
module.exports = exports['default'];

@@ -11,2 +11,6 @@ 'use strict';

var _warning = require('warning');
var _warning2 = _interopRequireDefault(_warning);
var _invariant = require('invariant');

@@ -20,6 +24,2 @@

var _warning = require('warning');
var _warning2 = _interopRequireDefault(_warning);
var _React$PropTypes = _react2['default'].PropTypes;

@@ -46,6 +46,7 @@ var string = _React$PropTypes.string;

createRouteFromReactElement: function createRouteFromReactElement(element) {
var route = (0, _RouteUtils.createRouteFromReactElement)(element);
var route = _RouteUtils.createRouteFromReactElement(element);
if (route.handler) {
(0, _warning2['default'])(false, '<Route handler> is deprecated, use <Route component> instead');
_warning2['default'](false, '<Route handler> is deprecated, use <Route component> instead');
route.component = route.handler;

@@ -63,4 +64,4 @@ delete route.handler;

ignoreScrollBehavior: bool,
handler: _PropTypes.component,
component: _PropTypes.component,
handler: // deprecated
_PropTypes.component, component: _PropTypes.component,
components: _PropTypes.components,

@@ -71,3 +72,3 @@ getComponents: func

render: function render() {
(0, _invariant2['default'])(false, '<Route> elements are for router configuration only and should not be rendered');
_invariant2['default'](false, '<Route> elements are for router configuration only and should not be rendered');
}

@@ -77,3 +78,3 @@

exports.Route = Route;
exports['default'] = Route;
exports['default'] = Route;
module.exports = exports['default'];

@@ -13,130 +13,45 @@ 'use strict';

var _warning = require('warning');
var _historyLibCreateHashHistory = require('history/lib/createHashHistory');
var _warning2 = _interopRequireDefault(_warning);
var _historyLibCreateHashHistory2 = _interopRequireDefault(_historyLibCreateHashHistory);
var _invariant = require('invariant');
var _RouteUtils = require('./RouteUtils');
var _invariant2 = _interopRequireDefault(_invariant);
var _RoutingContext = require('./RoutingContext');
var _AsyncUtils = require('./AsyncUtils');
var _RoutingContext2 = _interopRequireDefault(_RoutingContext);
var _RouteUtils = require('./RouteUtils');
var _useRoutes = require('./useRoutes');
var _RoutingUtils = require('./RoutingUtils');
var _useRoutes2 = _interopRequireDefault(_useRoutes);
var _PropTypes = require('./PropTypes');
var _RouterContextMixin = require('./RouterContextMixin');
var _RouterContextMixin2 = _interopRequireDefault(_RouterContextMixin);
var _ScrollManagementMixin = require('./ScrollManagementMixin');
var _ScrollManagementMixin2 = _interopRequireDefault(_ScrollManagementMixin);
var _Location = require('./Location');
var _Transition = require('./Transition');
var _Transition2 = _interopRequireDefault(_Transition);
var _React$PropTypes = _react2['default'].PropTypes;
var arrayOf = _React$PropTypes.arrayOf;
var func = _React$PropTypes.func;
var object = _React$PropTypes.object;
function runTransition(prevState, routes, location, hooks, callback) {
var transition = new _Transition2['default']();
(0, _RoutingUtils.getState)(routes, location, function (error, nextState) {
if (error || nextState == null || transition.isCancelled) {
callback(error, null, transition);
} else {
nextState.location = location;
var transitionHooks = (0, _RoutingUtils.getTransitionHooks)(prevState, nextState);
if (Array.isArray(hooks)) transitionHooks.unshift.apply(transitionHooks, hooks);
(0, _AsyncUtils.loopAsync)(transitionHooks.length, function (index, next, done) {
transitionHooks[index](nextState, transition, function (error) {
if (error || transition.isCancelled) {
done(error); // No need to continue.
} else {
next();
}
});
}, function (error) {
if (error || transition.isCancelled) {
callback(error, null, transition);
} else {
(0, _RoutingUtils.getComponents)(nextState.branch, function (error, components) {
if (error || transition.isCancelled) {
callback(error, null, transition);
} else {
nextState.components = components;
callback(null, nextState, transition);
}
});
}
});
}
});
}
/**
* A <Router> is a high-level API for automatically setting up
* a router that renders a <RoutingContext> with all the props
* it needs each time the URL changes.
*/
var Router = _react2['default'].createClass({
displayName: 'Router',
mixins: [_RouterContextMixin2['default'], _ScrollManagementMixin2['default']],
statics: {
/**
* Runs a transition to the given location using the given routes and
* transition hooks (optional) and calls callback(error, state, transition)
* when finished. This is primarily useful for server-side rendering.
*/
run: function run(routes, location, transitionHooks, callback) {
if (typeof transitionHooks === 'function') {
callback = transitionHooks;
transitionHooks = null;
}
(0, _invariant2['default'])(typeof callback === 'function', 'Router.run needs a callback');
runTransition(null, routes, location, transitionHooks, callback);
}
},
propTypes: {
createElement: func.isRequired,
onAbort: func,
history: object,
children: _PropTypes.routes,
routes: _PropTypes.routes, // alias for children
createElement: func,
onError: func,
onUpdate: func,
// Client-side
history: _PropTypes.history,
routes: _PropTypes.routes,
// Routes may also be given as children (JSX)
children: _PropTypes.routes,
// Server-side
location: _PropTypes.location,
branch: _PropTypes.routes,
params: object,
components: arrayOf(_PropTypes.components)
parseQueryString: func,
stringifyQuery: func
},
getDefaultProps: function getDefaultProps() {
return {
createElement: _react.createElement
};
},
getInitialState: function getInitialState() {
return {
isTransitioning: false,
location: null,
branch: null,
routes: null,
params: null,

@@ -147,71 +62,2 @@ components: null

_updateState: function _updateState(location) {
var _this = this;
(0, _invariant2['default'])((0, _Location.isLocation)(location), 'A <Router> needs a valid Location');
var hooks = this.transitionHooks;
if (hooks) hooks = hooks.map(function (hook) {
return (0, _RoutingUtils.createTransitionHook)(hook, _this);
});
this.setState({ isTransitioning: true });
runTransition(this.state, this.routes, location, hooks, function (error, state, transition) {
if (error) {
_this.handleError(error);
} else if (transition.isCancelled) {
if (transition.redirectInfo) {
var _transition$redirectInfo = transition.redirectInfo;
var pathname = _transition$redirectInfo.pathname;
var query = _transition$redirectInfo.query;
var state = _transition$redirectInfo.state;
_this.replaceWith(pathname, query, state);
} else {
(0, _invariant2['default'])(_this.state.location, 'You may not abort the initial transition');
_this.handleAbort(transition.abortReason);
}
} else if (state == null) {
(0, _warning2['default'])(false, 'Location "%s" did not match any routes', location.pathname);
} else {
_this.setState(state, _this.props.onUpdate);
}
_this.setState({ isTransitioning: false });
});
},
/**
* Adds a transition hook that runs before all route hooks in a
* transition. The signature is the same as route transition hooks.
*/
addTransitionHook: function addTransitionHook(hook) {
if (!this.transitionHooks) this.transitionHooks = [];
this.transitionHooks.push(hook);
},
/**
* Removes the given transition hook.
*/
removeTransitionHook: function removeTransitionHook(hook) {
if (this.transitionHooks) this.transitionHooks = this.transitionHooks.filter(function (h) {
return h !== hook;
});
},
handleAbort: function handleAbort(reason) {
if (this.props.onAbort) {
this.props.onAbort.call(this, reason);
} else {
// The best we can do here is goBack so the location state reverts
// to what it was. However, we also set a flag so that we know not
// to run through _updateState again since state did not change.
this._ignoreNextHistoryChange = true;
this.goBack();
}
},
handleError: function handleError(error) {

@@ -222,109 +68,44 @@ if (this.props.onError) {

// Throw errors by default so we don't silently swallow them!
throw error; // This error probably originated in getChildRoutes or getComponents.
throw error; // This error probably occurred in getChildRoutes or getComponents.
}
},
handleHistoryChange: function handleHistoryChange() {
if (this._ignoreNextHistoryChange) {
this._ignoreNextHistoryChange = false;
} else {
this._updateState(this.props.history.location);
}
},
componentWillMount: function componentWillMount() {
var _this = this;
componentWillMount: function componentWillMount() {
var _props = this.props;
var history = _props.history;
var children = _props.children;
var routes = _props.routes;
var children = _props.children;
var location = _props.location;
var branch = _props.branch;
var params = _props.params;
var components = _props.components;
var parseQueryString = _props.parseQueryString;
var stringifyQuery = _props.stringifyQuery;
if (history) {
(0, _invariant2['default'])(routes || children, 'Client-side <Router>s need routes. Try using <Router routes> or ' + 'passing your routes as nested <Route> children');
var createHistory = history ? function () {
return history;
} : _historyLibCreateHashHistory2['default'];
this.routes = (0, _RouteUtils.createRoutes)(routes || children);
this.history = _useRoutes2['default'](createHistory)({
routes: _RouteUtils.createRoutes(routes || children),
parseQueryString: parseQueryString,
stringifyQuery: stringifyQuery
});
if (typeof history.setup === 'function') history.setup();
// We need to listen first in case we redirect immediately.
if (history.addChangeListener) history.addChangeListener(this.handleHistoryChange);
this._updateState(history.location);
} else {
(0, _invariant2['default'])(location && branch && params && components, 'Server-side <Router>s need location, branch, params, and components ' + 'props. Try using Router.run to get all the props you need');
this.setState({ location: location, branch: branch, params: params, components: components });
}
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
(0, _invariant2['default'])(this.props.history === nextProps.history, '<Router history> may not be changed');
if (nextProps.history) {
var currentRoutes = this.props.routes || this.props.children;
var nextRoutes = nextProps.routes || nextProps.children;
if (currentRoutes !== nextRoutes) {
this.routes = (0, _RouteUtils.createRoutes)(nextRoutes);
// Call this here because _updateState
// uses this.routes to determine state.
if (nextProps.history.location) this._updateState(nextProps.history.location);
this._unlisten = this.history.listen(function (error, state) {
if (error) {
_this.handleError(error);
} else {
_this.setState(state, _this.props.onUpdate);
}
}
});
},
componentWillUnmount: function componentWillUnmount() {
var history = this.props.history;
if (history && history.removeChangeListener) history.removeChangeListener(this.handleHistoryChange);
if (this._unlisten) this._unlisten();
},
_createElement: function _createElement(component, props) {
return typeof component === 'function' ? this.props.createElement(component, props) : null;
},
render: function render() {
var _this2 = this;
var _state = this.state;
var branch = _state.branch;
var params = _state.params;
var components = _state.components;
var element = null;
if (components) {
element = components.reduceRight(function (element, components, index) {
if (components == null) return element; // Don't create new children; use the grandchildren.
var route = branch[index];
var routeParams = (0, _RoutingUtils.getRouteParams)(route, params);
var props = _extends({}, _this2.state, { route: route, routeParams: routeParams });
if ((0, _react.isValidElement)(element)) {
props.children = element;
} else if (element) {
// In render, do var { header, sidebar } = this.props;
_extends(props, element);
}
if (typeof components === 'object') {
var elements = {};
for (var key in components) if (components.hasOwnProperty(key)) elements[key] = _this2._createElement(components[key], props);
return elements;
}
return _this2._createElement(components, props);
}, element);
}
(0, _invariant2['default'])(element === null || element === false || (0, _react.isValidElement)(element), 'The root route must render a single element');
return element;
return _react2['default'].createElement(_RoutingContext2['default'], _extends({}, this.state, {
history: this.history,
createElement: this.props.createElement
}));
}

@@ -331,0 +112,0 @@

@@ -23,3 +23,3 @@ 'use strict';

function isValidChild(object) {
return object == null || (0, _react.isValidElement)(object);
return object == null || _react2['default'].isValidElement(object);
}

@@ -38,3 +38,3 @@

if (error instanceof Error) (0, _warning2['default'])(false, error.message);
if (error instanceof Error) _warning2['default'](false, error.message);
}

@@ -44,5 +44,9 @@ }

function createRoute(defaultProps, props) {
return _extends({}, defaultProps, props);
}
function createRouteFromReactElement(element) {
var type = element.type;
var route = _extends({}, type.defaultProps, element.props);
var route = createRoute(type.defaultProps, element.props);

@@ -52,3 +56,6 @@ if (type.propTypes) checkPropTypes(type.displayName || type.name, type.propTypes, route);

if (route.children) {
route.childRoutes = createRoutesFromReactChildren(route.children);
var childRoutes = createRoutesFromReactChildren(route.children, route);
if (childRoutes.length) route.childRoutes = childRoutes;
delete route.children;

@@ -78,10 +85,12 @@ }

function createRoutesFromReactChildren(children) {
function createRoutesFromReactChildren(children, parentRoute) {
var routes = [];
_react2['default'].Children.forEach(children, function (element) {
if ((0, _react.isValidElement)(element)) {
if (_react2['default'].isValidElement(element)) {
// Component classes may have a static create* method.
if (element.type.createRouteFromReactElement) {
routes.push(element.type.createRouteFromReactElement(element));
var route = element.type.createRouteFromReactElement(element, parentRoute);
if (route) routes.push(route);
} else {

@@ -88,0 +97,0 @@ routes.push(createRouteFromReactElement(element));

@@ -11,13 +11,11 @@ 'use strict';

var _history = require('history');
var _DOMUtils = require('./DOMUtils');
var _NavigationTypes = require('./NavigationTypes');
var _NavigationTypes2 = _interopRequireDefault(_NavigationTypes);
var func = _react2['default'].PropTypes.func;
function getCommonAncestors(branch, otherBranch) {
return branch.filter(function (route) {
return otherBranch.indexOf(route) !== -1;
function getCommonAncestors(routes, otherRoutes) {
return routes.filter(function (route) {
return otherRoutes.indexOf(route) !== -1;
});

@@ -28,5 +26,5 @@ }

var location = state.location;
var branch = state.branch;
var routes = state.routes;
var prevLocation = prevState.location;
var prevBranch = prevState.branch;
var prevRoutes = prevState.routes;

@@ -43,3 +41,3 @@ // When an onEnter hook uses transition.to to redirect

// has `ignoreScrollPosition` set to `true` on the route.
var sharedAncestors = getCommonAncestors(branch, prevBranch);
var sharedAncestors = getCommonAncestors(routes, prevRoutes);
if (sharedAncestors.some(function (route) {

@@ -52,8 +50,8 @@ return route.ignoreScrollBehavior;

function updateWindowScrollPosition(navigationType, scrollX, scrollY) {
function updateWindowScrollPosition(action, scrollX, scrollY) {
if (_DOMUtils.canUseDOM) {
if (navigationType === _NavigationTypes2['default'].POP) {
(0, _DOMUtils.setWindowScrollPosition)(scrollX, scrollY);
if (action === _history.Actions.POP) {
_DOMUtils.setWindowScrollPosition(scrollX, scrollY);
} else {
(0, _DOMUtils.setWindowScrollPosition)(0, 0);
_DOMUtils.setWindowScrollPosition(0, 0);
}

@@ -80,9 +78,8 @@ }

var locationState = location && location.state;
if (location && this.props.shouldUpdateScrollPosition(this.state, prevState)) {
var action = location.action;
var scrollX = location.scrollX;
var scrollY = location.scrollY;
if (locationState && this.props.shouldUpdateScrollPosition(this.state, prevState)) {
var scrollX = locationState.scrollX;
var scrollY = locationState.scrollY;
this.props.updateScrollPosition(location.navigationType, scrollX || 0, scrollY || 0);
this.props.updateScrollPosition(action, scrollX || 0, scrollY || 0);
}

@@ -89,0 +86,0 @@ }

@@ -14,4 +14,4 @@ 'use strict';

/**
* A mixin for components that need to know the path, routes, URL
* params and query that are currently active.
* The State mixin provides components with an isActive(pathname, query)
* method they can use to check if a given pathname/query are active.
*

@@ -27,6 +27,6 @@ * Example:

*
* if (this.isActive('about'))
* if (this.isActive('/about'))
* className += ' is-active';
*
* return React.createElement('a', { className: className }, this.props.children);
* return React.createElement('a', { className }, this.props.children);
* }

@@ -38,3 +38,7 @@ * });

contextTypes: {
router: object.isRequired
history: object.isRequired
},
isActive: function isActive(pathname, query, indexOnly) {
return this.context.history.isActive(pathname, query, indexOnly);
}

@@ -44,12 +48,3 @@

var RouterStateMethods = ['isActive'];
RouterStateMethods.forEach(function (method) {
State[method] = function () {
var router = this.context.router;
return router[method].apply(router, arguments);
};
});
exports['default'] = State;
module.exports = exports['default'];

@@ -15,4 +15,3 @@ export function loopAsync(turns, work, callback) {

if (currentTurn < turns) {
currentTurn += 1;
work.call(this, currentTurn - 1, next, done);
work.call(this, currentTurn++, next, done);
} else {

@@ -59,20 +58,1 @@ done.apply(this, arguments);

}
export function hashAsync(object, work, callback) {
var keys = Object.keys(object);
mapAsync(keys, function (key, index, callback) {
work(object[key], callback);
}, function (error, valuesArray) {
if (error) {
callback(error);
} else {
var values = valuesArray.reduce(function (memo, results, index) {
memo[keys[index]] = results;
return memo;
}, {});
callback(null, values);
}
});
}

@@ -5,2 +5,18 @@ export var canUseDOM = !!(

export function addEventListener(node, type, listener) {
if (node.addEventListener) {
node.addEventListener(type, listener, false);
} else {
node.attachEvent('on' + type, listener);
}
}
export function removeEventListener(node, type, listener) {
if (node.removeEventListener) {
node.removeEventListener(type, listener, false);
} else {
node.detachEvent('on' + type, listener);
}
}
export function getHashPath() {

@@ -24,4 +40,4 @@ // We can't use window.location.hash here because it's not

return {
scrollX: window.pageXOffset || document.documentElement.scrollLeft,
scrollY: window.pageYOffset || document.documentElement.scrollTop
x: window.pageXOffset || document.documentElement.scrollLeft,
y: window.pageYOffset || document.documentElement.scrollTop
};

@@ -28,0 +44,0 @@ }

@@ -6,2 +6,3 @@ /* components */

/* components (configuration) */
export IndexRoute from './IndexRoute';
export Redirect from './Redirect';

@@ -11,7 +12,9 @@ export Route from './Route';

/* mixins */
export Lifecycle from './Lifecycle';
export Navigation from './Navigation';
export TransitionHook from './TransitionHook';
export RouteContext from './RouteContext';
export State from './State';
/* utils */
export useRoutes from './useRoutes';
export { createRoutesFromReactChildren } from './RouteUtils';

@@ -18,0 +21,0 @@ export PropTypes from './PropTypes';

import React from 'react';
import warning from 'warning';
var { object, string, func } = React.PropTypes;
var { bool, object, string, func } = React.PropTypes;

@@ -14,9 +15,9 @@ function isLeftClickEvent(event) {

/**
* <Link> components are used to create an <a> element that links to a route.
* When that route is active, the link gets an "active" class name (or the
* value of its `activeClassName` prop).
* A <Link> is used to create an <a> element that links to a route.
* When that route is active, the link gets an "active" class name
* (or the value of its `activeClassName` prop).
*
* For example, assuming you have the following route:
*
* <Route name="showPost" path="/posts/:postID" handler={Post}/>
* <Route path="/posts/:postID" component={Post} />
*

@@ -27,11 +28,11 @@ * You could use the following component to link to that route:

*
* Links may pass along query string parameters
* using the `query` prop.
* Links may pass along location state and/or query string parameters
* in the state/query props, respectively.
*
* <Link to="/posts/123" query={{ show:true }}/>
* <Link ... query={{ show: true }} state={{ the: 'state' }} />
*/
export var Link = React.createClass({
var Link = React.createClass({
contextTypes: {
router: object
history: object
},

@@ -42,2 +43,3 @@

activeClassName: string,
onlyActiveOnIndex: bool.isRequired,
to: string.isRequired,

@@ -53,2 +55,3 @@ query: object,

activeClassName: 'active',
onlyActiveOnIndex: false,
style: {}

@@ -74,21 +77,36 @@ };

if (allowTransition)
this.context.router.transitionTo(this.props.to, this.props.query, this.props.state);
this.context.history.pushState(this.props.state, this.props.to, this.props.query);
},
componentWillMount() {
warning(
this.context.history,
'A <Link> should not be rendered outside the context of history; ' +
'some features including real hrefs, active styling, and navigation ' +
'will not function correctly'
);
},
render() {
var { router } = this.context;
var { to, query } = this.props;
var { to, query, onlyActiveOnIndex } = this.props;
var props = Object.assign({}, this.props, {
href: router.makeHref(to, query),
var props = {
...this.props,
onClick: this.handleClick
});
};
// ignore if rendered outside of the context of a router, simplifies unit testing
if (router && router.isActive(to, query)) {
if (props.activeClassName)
props.className += props.className !== '' ? ` ${props.activeClassName}` : props.activeClassName;
var { history } = this.context;
if (props.activeStyle)
props.style = Object.assign({}, props.style, props.activeStyle);
// Ignore if rendered outside the context
// of history, simplifies unit testing.
if (history) {
props.href = history.createHref(to, query);
if (history.isActive(to, query, onlyActiveOnIndex)) {
if (props.activeClassName)
props.className += props.className !== '' ? ` ${props.activeClassName}` : props.activeClassName;
if (props.activeStyle)
props.style = { ...props.style, ...props.activeStyle };
}
}

@@ -95,0 +113,0 @@

@@ -6,3 +6,4 @@ import React from 'react';

/**
* A mixin for components that modify the URL.
* The Navigation mixin provides methods for components
* that need to modify the URL.
*

@@ -17,3 +18,3 @@ * Example:

* event.preventDefault();
* this.transitionTo('aRoute', { the: 'params' }, { the: 'query' });
* this.transitionTo('/the/path', { the: 'query' });
* },

@@ -30,3 +31,11 @@ * render() {

contextTypes: {
router: object.isRequired
history: object.isRequired
},
transitionTo(pathname, query, state) {
return this.context.history.pushState(state, pathname, query);
},
replaceWith(pathname, query, state) {
return this.context.history.replaceState(state, pathname, query);
}

@@ -37,6 +46,4 @@

var RouterNavigationMethods = [
'makePath',
'makeHref',
'transitionTo',
'replaceWith',
'createPath',
'createHref',
'go',

@@ -49,4 +56,4 @@ 'goBack',

Navigation[method] = function () {
var router = this.context.router;
return router[method].apply(router, arguments);
var { history } = this.context;
return history[method].apply(history, arguments);
};

@@ -53,0 +60,0 @@ });

@@ -1,8 +0,6 @@

import React from 'react';
import Location from './Location';
import History from './History';
import { PropTypes } from 'react';
var { func, object, arrayOf, instanceOf, oneOfType, element } = React.PropTypes;
var { func, object, arrayOf, oneOfType, element, shape, string } = PropTypes;
function falsy(props, propName, componentName) {
export function falsy(props, propName, componentName) {
if (props[propName])

@@ -12,17 +10,20 @@ return new Error(`<${componentName}> should not have a "${propName}" prop`);

var component = func;
var components = oneOfType([ component, object ]);
var history = instanceOf(History);
var location = instanceOf(Location);
var route = oneOfType([ object, element ]);
var routes = oneOfType([ route, arrayOf(route) ]);
export var history = shape({
listen: func.isRequired,
pushState: func.isRequired,
replaceState: func.isRequired,
go: func.isRequired
});
module.exports = {
falsy,
component,
components,
history,
location,
route,
routes
};
export var location = shape({
pathname: string.isRequired,
search: string.isRequired,
state: object,
action: string.isRequired,
key: string
});
export var component = oneOfType([ func, string ]);
export var components = oneOfType([ component, object ]);
export var route = oneOfType([ object, element ]);
export var routes = oneOfType([ route, arrayOf(route) ]);
import React from 'react';
import invariant from 'invariant';
import { createRouteFromReactElement } from './RouteUtils';
import { formatPattern } from './URLUtils';
import { formatPattern } from './PatternUtils';
import { falsy } from './PropTypes';

@@ -9,3 +9,10 @@

export var Redirect = React.createClass({
/**
* A <Redirect> is used to declare another URL path a client should be sent
* to when they request a given URL.
*
* Redirects are placed alongside routes in the route configuration and are
* traversed in the same manner.
*/
var Redirect = React.createClass({

@@ -20,7 +27,13 @@ statics: {

route.onEnter = function (nextState, transition) {
// TODO: Handle relative pathnames, see #1658
invariant(
route.to.charAt(0) === '/',
'<Redirect to> must be an absolute path. This should be fixed in the future'
);
route.onEnter = function (nextState, redirectTo) {
var { location, params } = nextState;
var pathname = route.to ? formatPattern(route.to, params) : location.pathname;
transition.to(
redirectTo(
pathname,

@@ -27,0 +40,0 @@ route.query || location.query,

import React from 'react';
import warning from 'warning';
import invariant from 'invariant';
import { createRouteFromReactElement } from './RouteUtils';
import { component, components } from './PropTypes';
import warning from 'warning';

@@ -19,3 +19,3 @@ var { string, bool, func } = React.PropTypes;

*/
export var Route = React.createClass({
var Route = React.createClass({

@@ -28,3 +28,7 @@ statics: {

if (route.handler) {
warning(false, '<Route handler> is deprecated, use <Route component> instead');
warning(
false,
'<Route handler> is deprecated, use <Route component> instead'
);
route.component = route.handler;

@@ -42,3 +46,3 @@ delete route.handler;

ignoreScrollBehavior: bool,
handler: component,
handler: component, // deprecated
component,

@@ -45,0 +49,0 @@ components,

@@ -1,111 +0,32 @@

import React, { createElement, isValidElement } from 'react';
import warning from 'warning';
import invariant from 'invariant';
import { loopAsync } from './AsyncUtils';
import React from 'react';
import createHashHistory from 'history/lib/createHashHistory';
import { createRoutes } from './RouteUtils';
import { getState, getTransitionHooks, getComponents, getRouteParams, createTransitionHook } from './RoutingUtils';
import { routes, component, components, history, location } from './PropTypes';
import RouterContextMixin from './RouterContextMixin';
import ScrollManagementMixin from './ScrollManagementMixin';
import { isLocation } from './Location';
import Transition from './Transition';
import RoutingContext from './RoutingContext';
import useRoutes from './useRoutes';
import { routes } from './PropTypes';
var { arrayOf, func, object } = React.PropTypes;
var { func, object } = React.PropTypes;
function runTransition(prevState, routes, location, hooks, callback) {
var transition = new Transition;
getState(routes, location, function (error, nextState) {
if (error || nextState == null || transition.isCancelled) {
callback(error, null, transition);
} else {
nextState.location = location;
var transitionHooks = getTransitionHooks(prevState, nextState);
if (Array.isArray(hooks))
transitionHooks.unshift.apply(transitionHooks, hooks);
loopAsync(transitionHooks.length, (index, next, done) => {
transitionHooks[index](nextState, transition, (error) => {
if (error || transition.isCancelled) {
done(error); // No need to continue.
} else {
next();
}
});
}, function (error) {
if (error || transition.isCancelled) {
callback(error, null, transition);
} else {
getComponents(nextState.branch, function (error, components) {
if (error || transition.isCancelled) {
callback(error, null, transition);
} else {
nextState.components = components;
callback(null, nextState, transition);
}
});
}
});
}
});
}
/**
* A <Router> is a high-level API for automatically setting up
* a router that renders a <RoutingContext> with all the props
* it needs each time the URL changes.
*/
var Router = React.createClass({
mixins: [ RouterContextMixin, ScrollManagementMixin ],
statics: {
/**
* Runs a transition to the given location using the given routes and
* transition hooks (optional) and calls callback(error, state, transition)
* when finished. This is primarily useful for server-side rendering.
*/
run(routes, location, transitionHooks, callback) {
if (typeof transitionHooks === 'function') {
callback = transitionHooks;
transitionHooks = null;
}
invariant(
typeof callback === 'function',
'Router.run needs a callback'
);
runTransition(null, routes, location, transitionHooks, callback);
}
},
propTypes: {
createElement: func.isRequired,
onAbort: func,
history: object,
children: routes,
routes, // alias for children
createElement: func,
onError: func,
onUpdate: func,
// Client-side
history,
routes,
// Routes may also be given as children (JSX)
children: routes,
// Server-side
location,
branch: routes,
params: object,
components: arrayOf(components)
parseQueryString: func,
stringifyQuery: func
},
getDefaultProps() {
return {
createElement
};
},
getInitialState() {
return {
isTransitioning: false,
location: null,
branch: null,
routes: null,
params: null,

@@ -116,70 +37,2 @@ components: null

_updateState(location) {
invariant(
isLocation(location),
'A <Router> needs a valid Location'
);
var hooks = this.transitionHooks;
if (hooks)
hooks = hooks.map(hook => createTransitionHook(hook, this));
this.setState({ isTransitioning: true });
runTransition(this.state, this.routes, location, hooks, (error, state, transition) => {
if (error) {
this.handleError(error);
} else if (transition.isCancelled) {
if (transition.redirectInfo) {
var { pathname, query, state } = transition.redirectInfo;
this.replaceWith(pathname, query, state);
} else {
invariant(
this.state.location,
'You may not abort the initial transition'
);
this.handleAbort(transition.abortReason);
}
} else if (state == null) {
warning(false, 'Location "%s" did not match any routes', location.pathname);
} else {
this.setState(state, this.props.onUpdate);
}
this.setState({ isTransitioning: false });
});
},
/**
* Adds a transition hook that runs before all route hooks in a
* transition. The signature is the same as route transition hooks.
*/
addTransitionHook(hook) {
if (!this.transitionHooks)
this.transitionHooks = [];
this.transitionHooks.push(hook);
},
/**
* Removes the given transition hook.
*/
removeTransitionHook(hook) {
if (this.transitionHooks)
this.transitionHooks = this.transitionHooks.filter(h => h !== hook);
},
handleAbort(reason) {
if (this.props.onAbort) {
this.props.onAbort.call(this, reason);
} else {
// The best we can do here is goBack so the location state reverts
// to what it was. However, we also set a flag so that we know not
// to run through _updateState again since state did not change.
this._ignoreNextHistoryChange = true;
this.goBack();
}
},
handleError(error) {

@@ -190,117 +43,36 @@ if (this.props.onError) {

// Throw errors by default so we don't silently swallow them!
throw error; // This error probably originated in getChildRoutes or getComponents.
throw error; // This error probably occurred in getChildRoutes or getComponents.
}
},
handleHistoryChange() {
if (this._ignoreNextHistoryChange) {
this._ignoreNextHistoryChange = false;
} else {
this._updateState(this.props.history.location);
}
},
componentWillMount() {
var { history, routes, children, location, branch, params, components } = this.props;
var { history, children, routes, parseQueryString, stringifyQuery } = this.props;
var createHistory = history ? () => history : createHashHistory;
if (history) {
invariant(
routes || children,
'Client-side <Router>s need routes. Try using <Router routes> or ' +
'passing your routes as nested <Route> children'
);
this.history = useRoutes(createHistory)({
routes: createRoutes(routes || children),
parseQueryString,
stringifyQuery
});
this.routes = createRoutes(routes || children);
if (typeof history.setup === 'function')
history.setup();
// We need to listen first in case we redirect immediately.
if (history.addChangeListener)
history.addChangeListener(this.handleHistoryChange);
this._updateState(history.location);
} else {
invariant(
location && branch && params && components,
'Server-side <Router>s need location, branch, params, and components ' +
'props. Try using Router.run to get all the props you need'
);
this.setState({ location, branch, params, components });
}
},
componentWillReceiveProps(nextProps) {
invariant(
this.props.history === nextProps.history,
'<Router history> may not be changed'
);
if (nextProps.history) {
var currentRoutes = this.props.routes || this.props.children;
var nextRoutes = nextProps.routes || nextProps.children;
if (currentRoutes !== nextRoutes) {
this.routes = createRoutes(nextRoutes);
// Call this here because _updateState
// uses this.routes to determine state.
if (nextProps.history.location)
this._updateState(nextProps.history.location);
this._unlisten = this.history.listen((error, state) => {
if (error) {
this.handleError(error);
} else {
this.setState(state, this.props.onUpdate);
}
}
});
},
componentWillUnmount() {
var { history } = this.props;
if (history && history.removeChangeListener)
history.removeChangeListener(this.handleHistoryChange);
if (this._unlisten)
this._unlisten();
},
_createElement(component, props) {
return typeof component === 'function' ? this.props.createElement(component, props) : null;
},
render() {
var { branch, params, components } = this.state;
var element = null;
if (components) {
element = components.reduceRight((element, components, index) => {
if (components == null)
return element; // Don't create new children; use the grandchildren.
var route = branch[index];
var routeParams = getRouteParams(route, params);
var props = Object.assign({}, this.state, { route, routeParams });
if (isValidElement(element)) {
props.children = element;
} else if (element) {
// In render, do var { header, sidebar } = this.props;
Object.assign(props, element);
}
if (typeof components === 'object') {
var elements = {};
for (var key in components)
if (components.hasOwnProperty(key))
elements[key] = this._createElement(components[key], props);
return elements;
}
return this._createElement(components, props);
}, element);
}
invariant(
element === null || element === false || isValidElement(element),
'The root route must render a single element'
);
return element;
return React.createElement(RoutingContext, {
...this.state,
history: this.history,
createElement: this.props.createElement
});
}

@@ -307,0 +79,0 @@

@@ -1,6 +0,6 @@

import React, { isValidElement } from 'react';
import React from 'react';
import warning from 'warning';
function isValidChild(object) {
return object == null || isValidElement(object);
return object == null || React.isValidElement(object);
}

@@ -25,5 +25,9 @@

function createRoute(defaultProps, props) {
return { ...defaultProps, ...props };
}
export function createRouteFromReactElement(element) {
var type = element.type;
var route = Object.assign({}, type.defaultProps, element.props);
var route = createRoute(type.defaultProps, element.props);

@@ -34,3 +38,7 @@ if (type.propTypes)

if (route.children) {
route.childRoutes = createRoutesFromReactChildren(route.children);
var childRoutes = createRoutesFromReactChildren(route.children, route);
if (childRoutes.length)
route.childRoutes = childRoutes;
delete route.children;

@@ -59,10 +67,13 @@ }

*/
export function createRoutesFromReactChildren(children) {
export function createRoutesFromReactChildren(children, parentRoute) {
var routes = [];
React.Children.forEach(children, function (element) {
if (isValidElement(element)) {
if (React.isValidElement(element)) {
// Component classes may have a static create* method.
if (element.type.createRouteFromReactElement) {
routes.push(element.type.createRouteFromReactElement(element));
var route = element.type.createRouteFromReactElement(element, parentRoute);
if (route)
routes.push(route);
} else {

@@ -69,0 +80,0 @@ routes.push(createRouteFromReactElement(element));

import React from 'react';
import { Actions } from 'history';
import { canUseDOM, setWindowScrollPosition } from './DOMUtils';
import NavigationTypes from './NavigationTypes';
var { func } = React.PropTypes;
function getCommonAncestors(branch, otherBranch) {
return branch.filter(route => otherBranch.indexOf(route) !== -1);
function getCommonAncestors(routes, otherRoutes) {
return routes.filter(route => otherRoutes.indexOf(route) !== -1);
}
function shouldUpdateScrollPosition(state, prevState) {
var { location, branch } = state;
var { location: prevLocation, branch: prevBranch } = prevState;
var { location, routes } = state;
var { location: prevLocation, routes: prevRoutes } = prevState;

@@ -27,3 +27,3 @@ // When an onEnter hook uses transition.to to redirect

// has `ignoreScrollPosition` set to `true` on the route.
var sharedAncestors = getCommonAncestors(branch, prevBranch);
var sharedAncestors = getCommonAncestors(routes, prevRoutes);
if (sharedAncestors.some(route => route.ignoreScrollBehavior))

@@ -35,5 +35,5 @@ return false;

function updateWindowScrollPosition(navigationType, scrollX, scrollY) {
function updateWindowScrollPosition(action, scrollX, scrollY) {
if (canUseDOM) {
if (navigationType === NavigationTypes.POP) {
if (action === Actions.POP) {
setWindowScrollPosition(scrollX, scrollY);

@@ -62,7 +62,6 @@ } else {

var { location } = this.state;
var locationState = location && location.state;
if (locationState && this.props.shouldUpdateScrollPosition(this.state, prevState)) {
var { scrollX, scrollY } = locationState;
this.props.updateScrollPosition(location.navigationType, scrollX || 0, scrollY || 0);
if (location && this.props.shouldUpdateScrollPosition(this.state, prevState)) {
var { action, scrollX, scrollY } = location;
this.props.updateScrollPosition(action, scrollX || 0, scrollY || 0);
}

@@ -69,0 +68,0 @@ }

@@ -6,4 +6,4 @@ import React from 'react';

/**
* A mixin for components that need to know the path, routes, URL
* params and query that are currently active.
* The State mixin provides components with an isActive(pathname, query)
* method they can use to check if a given pathname/query are active.
*

@@ -19,6 +19,6 @@ * Example:

*
* if (this.isActive('about'))
* if (this.isActive('/about'))
* className += ' is-active';
*
* return React.createElement('a', { className: className }, this.props.children);
* return React.createElement('a', { className }, this.props.children);
* }

@@ -30,3 +30,7 @@ * });

contextTypes: {
router: object.isRequired
history: object.isRequired
},
isActive(pathname, query, indexOnly) {
return this.context.history.isActive(pathname, query, indexOnly);
}

@@ -36,13 +40,2 @@

var RouterStateMethods = [
'isActive'
];
RouterStateMethods.forEach(function (method) {
State[method] = function () {
var router = this.context.router;
return router[method].apply(router, arguments);
};
});
export default State;
{
"name": "react-router",
"version": "1.0.0-beta3",
"version": "1.0.0-beta4",
"description": "A complete routing library for React.js",

@@ -13,8 +13,9 @@ "main": "lib/index",

"scripts": {
"build": "scripts/build.sh",
"watch": "babel ./modules --watch -d lib",
"build": "babel ./modules -d lib --ignore '__tests__'",
"build-umd": "NODE_ENV=production webpack modules/index.js lib/umd/History.js",
"build-min": "NODE_ENV=production webpack -p modules/index.js lib/umd/History.min.js",
"build-website": "scripts/build-website.sh",
"examples": "webpack-dev-server --config examples/webpack.config.js --content-base examples --inline",
"prepublish": "npm run build",
"test": "jsxhint modules && karma start"
"start": "webpack-dev-server --config examples/webpack.config.js --content-base examples --inline",
"test": "eslint modules && karma start",
"prepublish": "npm run build"
},

@@ -27,6 +28,5 @@ "authors": [

"dependencies": {
"history": "^1.8.0",
"invariant": "^2.0.0",
"keymirror": "^0.1.1",
"qs": "2.4.1",
"warning": "^1.0.1"
"warning": "^2.0.0"
},

@@ -36,15 +36,17 @@ "devDependencies": {

"babel-core": "^5.4.7",
"babel-eslint": "^3.1.23",
"babel-loader": "^5.0.0",
"babel-plugin-object-assign": "^1.2.0",
"bundle-loader": "^0.5.2",
"eslint": "^1.0.0",
"events": "1.0.2",
"expect": "^1.6.0",
"jsxhint": "^0.12.1",
"karma": "^0.12.28",
"karma-chrome-launcher": "^0.1.7",
"karma-cli": "0.0.4",
"karma-firefox-launcher": "^0.1.3",
"karma-mocha": "^0.1.10",
"karma-sourcemap-loader": "^0.3.2",
"karma-webpack": "^1.3.1",
"karma": "^0.13.8",
"karma-browserstack-launcher": "^0.1.4",
"karma-chrome-launcher": "^0.2.0",
"karma-firefox-launcher": "^0.1.6",
"karma-mocha": "^0.2.0",
"karma-mocha-reporter": "^1.1.1",
"karma-sourcemap-loader": "^0.3.5",
"karma-webpack": "^1.7.0",
"marked": "0.3.3",

@@ -58,3 +60,3 @@ "mocha": "^2.0.1",

"webpack": "^1.4.13",
"webpack-dev-server": "^1.6.6"
"webpack-dev-server": "^1.10.1"
},

@@ -61,0 +63,0 @@ "tags": [

@@ -0,4 +1,4 @@

[![build status](https://img.shields.io/travis/rackt/react-router/master.svg?style=flat-square)](https://travis-ci.org/rackt/react-router)
[![npm package](https://img.shields.io/npm/v/react-router.svg?style=flat-square)](https://www.npmjs.org/package/react-router)
[![build status](https://img.shields.io/travis/rackt/react-router/master.svg?style=flat-square)](https://travis-ci.org/rackt/react-router)
[![dependency status](https://img.shields.io/david/rackt/react-router.svg?style=flat-square)](https://david-dm.org/rackt/react-router)
[![react-router channel on slack](https://img.shields.io/badge/slack-react--router@reactiflux-61DAFB.svg?style=flat-square)](http://www.reactiflux.com)

@@ -14,4 +14,3 @@ <img src="https://rackt.github.io/react-router/img/vertical.png" width="300"/>

Docs & Help
-----------
### Docs & Help

@@ -23,15 +22,14 @@ - [Guides and API Docs](https://rackt.github.io/react-router)

Browser Support
---------------
**Note: the docs and the examples in master refer to the 1.0 Beta and may be incomplete.**
**Browse [the website](http://rackt.github.io/react-router/) and [the 0.13.3 tag](https://github.com/rackt/react-router/tree/v0.13.3) for the information about the latest stable version.**
### Browser Support
We support all browsers and environments where React runs.
Installation
------------
### Installation
### npm + webpack/browserify
#### npm + webpack/browserify
```sh
npm install react-router
```
$ npm install react-router

@@ -53,21 +51,16 @@ Then with a module bundler or webpack, use as you would anything else:

### bower + who knows what
#### bower + who knows what
```sh
bower install react-router
```
$ bower install react-router
Find the UMD/global build in `lib/umd`, and the library on
`window.ReactRouter`. Best of luck to you. :)
Find the UMD/global build in `lib/umd`, and the library on `window.ReactRouter`. Best of luck to you. :)
### CDN
#### CDN
Available on cdnjs [here](https://cdnjs.com/libraries/react-router).
If you just want to drop a `<script>` tag in your page and be done with it, you can use the UMD/global build [hosted on cdnjs](https://cdnjs.com/libraries/react-router).
What's it look like?
--------------------
### What's it look like?
```js
import { Router, Route } from 'react-router';
import { history } from 'react-router/lib/BrowserHistory';

@@ -87,3 +80,3 @@ var App = React.createClass({/*...*/});

{this.state.users.map(user => (
<li><Link to={`/users/${users.id}`}>{user.name}</Link></li>
<li key={user.id}><Link to={`/user/${user.id}`}>{user.name}</Link></li>
))}

@@ -122,3 +115,3 @@ </ul>

React.render((
<Router history={history}>
<Router>
<Route path="/" component={App}>

@@ -138,11 +131,7 @@ <Route path="about" component={About}/>

Contributing
------------
### Thanks
Please see [CONTRIBUTING](CONTRIBUTING.md)
React Router was initially inspired by Ember's fantastic router. Many
thanks to the Ember team.
Thanks, Ember
-------------
React Router was initially inspired by Ember's fantastic Router. Many
thanks to the Ember team.
Also, thanks to [BrowserStack](https://www.browserstack.com/) for providing the infrastructure that allows us to run our build in real browsers.

@@ -469,3 +469,3 @@ Upgrade Guide

`.` used to be a delimiter like `/`, but now its a valid character in
`.` used to be a delimiter like `/`, but now it's a valid character in
your params.

@@ -472,0 +472,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc