Socket
Socket
Sign inDemoInstall

react-router

Package Overview
Dependencies
5
Maintainers
2
Versions
433
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0-beta4 to 1.0.0-rc1

docs/advanced/ComponentLifecycle.md

23

CHANGELOG.md

@@ -0,1 +1,24 @@

v1.0.0-rc1 - Fri, 11 Sep 2015 21:35:18 GMT
------------------------------------------
- [5fbe933](../../commit/5fbe933) [changed] Do not add "active" class by default
- [85c699c](../../commit/85c699c) [changed] State -> IsActive
- [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
v1.0.0-beta4 - Mon, 31 Aug 2015 06:19:34 GMT

@@ -2,0 +25,0 @@ --------------------------------------------

182

docs/Glossary.md

@@ -1,8 +0,10 @@

## Glossary
# Glossary
This is a glossary of common terms used in the React Router codebase and documentation listed in alphabetical order, along with their [type signatures](http://flowtype.org/docs/quick-reference.html).
### Action
## Action
type Action = 'PUSH' | 'REPLACE' | 'POP';
```js
type Action = 'PUSH' | 'REPLACE' | 'POP';
```

@@ -15,13 +17,17 @@ An *action* describes the type of change to a URL. Possible values are:

### Component
## Component
type Component = ReactClass | string;
```js
type Component = ReactClass | string;
```
A *component* is a React component class or a string (e.g. "div"). Basically, it's anything that can be used as the first argument to [`React.createElement`](https://facebook.github.io/react/docs/top-level-api.html#react.createelement).
### EnterHook
## EnterHook
type EnterHook = (nextState: RouterState, redirectTo: RedirectFunction, callback?: Function) => any;
```js
type EnterHook = (nextState: RouterState, replaceState: RedirectFunction, callback?: Function) => any;
```
An *enter hook* is a user-defined function that is called when a route is about to be rendered. It receives the next [router state](#routerstate) as its first argument. The [`redirectTo` function](#redirectfunction) may be used to trigger a transition to a different URL.
An *enter hook* is a user-defined function that is called when a route is about to be rendered. It receives the next [router state](#routerstate) as its first argument. The [`replaceState` function](#redirectfunction) may be used to trigger a transition to a different URL.

@@ -32,18 +38,22 @@ If an enter hook needs to execute asynchronously, it may list a 3rd `callback` argument that it must call in order to cause the transition to proceed.

### LeaveHook
## LeaveHook
type LeaveHook = () => any;
```js
type LeaveHook = () => any;
```
A *leave hook* is a user-defined function that is called when a route is about to be unmounted.
### Location
## Location
type Location = {
pathname: Pathname;
search: QueryString;
query: Query;
state: LocationState;
action: Action;
key: LocationKey;
};
```js
type Location = {
pathname: Pathname;
search: QueryString;
query: Query;
state: LocationState;
action: Action;
key: LocationKey;
};
```

@@ -57,11 +67,15 @@ A *location* answers two important (philosophical) questions:

### LocationKey
## LocationKey
type LocationKey = string;
```js
type LocationKey = string;
```
A *location key* is a string that is unique to a particular [`location`](#location). It is the one piece of data that most accurately answers the question "Where am I?".
### LocationState
## LocationState
type LocationState = ?Object;
```js
type LocationState = ?Object;
```

@@ -75,46 +89,60 @@ A *location state* is an arbitrary object of data associated with a particular [`location`](#location). This is basically a way to tie extra state to a location that is not contained in the URL.

### Path
## Path
type Path = Pathname + QueryString;
```js
type Path = Pathname + QueryString;
```
A *path* represents a URL path.
### Pathname
## Pathname
type Pathname = string;
```js
type Pathname = string;
```
A *pathname* is the portion of a URL that describes a hierarchical path, including the preceeding `/`. For example, in `http://example.com/the/path?the=query`, `/the/path` is the pathname. It is synonymous with `window.location.pathname` in web browsers.
### QueryString
## QueryString
type QueryString = string;
```js
type QueryString = string;
```
A *query string* is the portion of the URL that follows the [pathname](#pathname), including any preceeding `?`. For example, in `http://example.com/the/path?the=query`, `?the=query` is the query string. It is synonymous with `window.location.search` in web browsers.
### Query
## Query
type Query = Object;
```js
type Query = Object;
```
A *query* is the parsed version of a [query string](#querystring).
### Params
## Params
type Params = Object;
```js
type Params = Object;
```
The word *params* refers to an object of key/value pairs that were parsed out of the original URL's [pathname](#pathname). The values of this object are typically strings, unless there is more than one param with the same name in which case the value is an array.
### RedirectFunction
## RedirectFunction
type RedirectFunction = (pathname: Pathname | Path, query: ?Query, state: ?LocationState) => void;
```js
type RedirectFunction = (pathname: Pathname | Path, query: ?Query, state: ?LocationState) => void;
```
A *redirect function* is used in [`onEnter` hooks](#enterhook) to trigger a transition to a new URL.
### Route
## Route
type Route = {
component: RouteComponent;
path: ?RoutePattern;
onEnter: ?EnterHook;
onLeave: ?LeaveHook;
};
```js
type Route = {
component: RouteComponent;
path: ?RoutePattern;
onEnter: ?EnterHook;
onLeave: ?LeaveHook;
};
```

@@ -125,5 +153,7 @@ A *route* specifies a [component](#component) that is part of the user interface (UI). Routes should be nested in a tree-like structure that follows the hierarchy of your components.

### RouteComponent
## RouteComponent
type RouteComponent = Component;
```js
type RouteComponent = Component;
```

@@ -133,3 +163,3 @@ The term *route component* refers to a [component](#component) that is directly rendered by a [route](#route) (i.e. the `<Route component>`). The router creates elements from route components and provides them as `this.props.children` to route components further up the hierarchy. In addition to `children`, route components receive the following props:

- `router` – The [router](#router) instance
- `location` – The current [location](#location)
- `location` – The current [location](#location)
- `params` – The current [params](#params)

@@ -139,17 +169,23 @@ - `route` – The [route](#route) that declared this component

### RouteConfig
## RouteConfig
type RouteConfig = Array<Route>;
```js
type RouteConfig = Array<Route>;
```
A *route config* is an array of [route](#route)s that specifies the order in which routes should be tried when the router attempts to match a URL.
### RouteHook
## RouteHook
type RouteHook = (nextLocation?: Location) => any;
```js
type RouteHook = (nextLocation?: Location) => any;
```
A *route hook* is a function that is used to prevent the user from leaving a route. On normal transitions, it receives the next [location](#location) as an argument and must either `return false` to cancel the transition or `return` a prompt message to show the user. When invoked during the `beforeunload` event in web browsers, it does not receive any arguments and must `return` a prompt message to cancel the transition.
### RoutePattern
## RoutePattern
type RoutePattern = string;
```js
type RoutePattern = string;
```

@@ -164,12 +200,14 @@ A *route pattern* (or "path") is a string that describes a portion of a URL. Patterns are compiled into functions that are used to try and match a URL. Patterns may use the following special characters:

### Router
## Router
type Router = {
transitionTo: (location: Location) => void;
pushState: (state: ?LocationState, pathname: Pathname | Path, query?: Query) => void;
replaceState: (state: ?LocationState, pathname: Pathname | Path, query?: Query) => void;
go(n: Number) => void;
listen(listener: RouterListener) => Function;
match(location: Location, callback: RouterListener) => void;
};
```js
type Router = {
transitionTo: (location: Location) => void;
pushState: (state: ?LocationState, pathname: Pathname | Path, query?: Query) => void;
replaceState: (state: ?LocationState, pathname: Pathname | Path, query?: Query) => void;
go(n: Number) => void;
listen(listener: RouterListener) => Function;
match(location: Location, callback: RouterListener) => void;
};
```

@@ -183,16 +221,20 @@ A *router* is a [`history`](http://rackt.github.io/history) object (akin to `window.history` in web browsers) that is used to modify and listen for changes to the URL.

### RouterListener
## RouterListener
type RouterListener = (error: ?Error, nextState: RouterState) => void;
```js
type RouterListener = (error: ?Error, nextState: RouterState) => void;
```
A *router listener* is a function that is used to listen for changes to a [router](#router)'s [state](#routerstate).
### RouterState
## RouterState
type RouterState = {
location: Location;
routes: Array<Route>;
params: Params;
components: Array<Component>;
};
```js
type RouterState = {
location: Location;
routes: Array<Route>;
params: Params;
components: Array<Component>;
};
```

@@ -204,2 +246,2 @@ A *router state* represents the current state of a router. It contains:

- an object of [`params`](#params) that were parsed out of the URL, and
- an array of [`components`](#component) that will be rendered to the page in hierarchical order.
- an array of [`components`](#component) that will be rendered to the page in hierarchical order.
## Table of Contents
- [Introduction](Introduction.md)
- [Route Configuration](RouteConfiguration.md)
- [Route Matching](RouteMatching.md)
- [Dynamic Routing](DynamicRouting.md)
- [Confirming Navigation](ConfirmingNavigation.md)
- [Glossary](Glossary.md)
- [Route](Route.md)
- [Server Rendering](ServerRendering.md)
* [Read Me](/README.md)
* [Introduction](/docs/introduction/README.md)
* [Motivation](/docs/introduction/Motivation.md)
* [Principles](/docs/introduction/Principles.md)
* [Basics](/docs/basics/README.md)
* [Route Configuration](/docs/basics/RouteConfiguration.md)
* [Route Matching](/docs/basics/RouteMatching.md)
* [Histories](/docs/basics/Histories.md)
* [Advanced](/docs/advanced/README.md)
* [Dynamic Routing](/docs/advanced/DynamicRouting.md)
* [Confirming Navigation](/docs/advanced/ConfirmingNavigation.md)
* [Server Rendering](/docs/advanced/ServerRendering.md)
* [Component Lifecycle](/docs/advanced/ComponentLifecycle.md)
* [Recipes](/docs/recipes/README.md)
* [Upgrade Guide](/UPGRADE_GUIDE.md)
* [Troubleshooting](/docs/Troubleshooting.md)
* [Glossary](/docs/Glossary.md)
* [API Reference](/docs/api/README.md)
* [Components](/docs/api/README.md#components)
* [Router](/docs/api/Router.md)
* [Link](/docs/api/Link.md)
* [IndexLink](/docs/api/IndexLink.md)
* [RoutingContext](/docs/api/RoutingContext.md)
* [Configuration components](/docs/api/README.md#configuration-components)
* [Route](/docs/api/Route.md)
* [Redirect](/docs/api/Redirect.md)
* [IndexRoute](/docs/api/IndexRoute.md)
* [Mixins](/docs/api/README.md#mixins)
* [Lifecycle](/docs/api/Lifecycle.md)
* [Navigation](/docs/api/Navigation.md)
* [RouteContext](/docs/api/RouteContext.md)
* [IsActive](/docs/api/IsActive.md)
* [ScrollManagmentMixin](/docs/api/ScrollManagmentMixin.md)
* [Utilities](/docs/api/README.md#utilities)
* [useRoutes](/docs/api/useRoutes.md)
* [createRoutes](/docs/api/createRoutes.md)
* [PropTypes](/docs/api/PropTypes.md)

@@ -7,9 +7,9 @@ 'use strict';

function getComponentsForRoute(route, callback) {
function getComponentsForRoute(location, route, callback) {
if (route.component || route.components) {
callback(null, route.component || route.components);
} else if (route.getComponent) {
route.getComponent(callback);
route.getComponent(location, callback);
} else if (route.getComponents) {
route.getComponents(callback);
route.getComponents(location, callback);
} else {

@@ -27,5 +27,5 @@ callback();

*/
function getComponents(routes, callback) {
_AsyncUtils.mapAsync(routes, function (route, index, callback) {
getComponentsForRoute(route, callback);
function getComponents(nextState, callback) {
_AsyncUtils.mapAsync(nextState.routes, function (route, index, callback) {
getComponentsForRoute(nextState.location, route, callback);
}, callback);

@@ -32,0 +32,0 @@ }

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

var _History2 = require('./History');
var _History3 = _interopRequireDefault(_History2);
exports.History = _History3['default'];
var _Lifecycle2 = require('./Lifecycle');

@@ -49,8 +55,2 @@

var _Navigation2 = require('./Navigation');
var _Navigation3 = _interopRequireDefault(_Navigation2);
exports.Navigation = _Navigation3['default'];
var _RouteContext2 = require('./RouteContext');

@@ -62,8 +62,2 @@

var _State2 = require('./State');
var _State3 = _interopRequireDefault(_State2);
exports.State = _State3['default'];
/* utils */

@@ -79,4 +73,10 @@

exports.createRoutesFromReactChildren = _RouteUtils.createRoutesFromReactChildren;
exports.createRoutes = _RouteUtils.createRoutes;
var _RoutingContext2 = require('./RoutingContext');
var _RoutingContext3 = _interopRequireDefault(_RoutingContext2);
exports.RoutingContext = _RoutingContext3['default'];
var _PropTypes2 = require('./PropTypes');

@@ -88,4 +88,10 @@

var _match2 = require('./match');
var _match3 = _interopRequireDefault(_match2);
exports.match = _match3['default'];
var _Router4 = _interopRequireDefault(_Router2);
exports['default'] = _Router4['default'];

@@ -13,4 +13,2 @@ 'use strict';

var _PropTypes = require('./PropTypes');
var _Link = require('./Link');

@@ -17,0 +15,0 @@

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

var _warning = require('warning');
var _warning2 = _interopRequireDefault(_warning);
var _RouteUtils = require('./RouteUtils');

@@ -37,3 +41,3 @@

} else {
warning(false, 'An <IndexRoute> does not make sense at the root of your route config');
_warning2['default'](false, 'An <IndexRoute> does not make sense at the root of your route config');
}

@@ -40,0 +44,0 @@ }

@@ -18,2 +18,3 @@ 'use strict';

route = activeRoutes[i];
if (!route.path) return false;
pattern = route.path || '';

@@ -20,0 +21,0 @@

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

* the user for confirmation.
*
*
* On standard transitions, routerWillLeave receives a single argument: the

@@ -24,0 +24,0 @@ * location we're transitioning to. To cancel the transition, return false.

@@ -9,2 +9,4 @@ 'use strict';

function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var _react = require('react');

@@ -32,2 +34,8 @@

function isEmptyObject(object) {
for (var p in object) if (object.hasOwnProperty(p)) return false;
return true;
}
/**

@@ -70,5 +78,4 @@ * A <Link> is used to create an <a> element that links to a route.

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

@@ -98,12 +105,15 @@ };

render: function render() {
var history = this.context.history;
var _props = this.props;
var activeClassName = _props.activeClassName;
var activeStyle = _props.activeStyle;
var onlyActiveOnIndex = _props.onlyActiveOnIndex;
var to = _props.to;
var query = _props.query;
var onlyActiveOnIndex = _props.onlyActiveOnIndex;
var state = _props.state;
var onClick = _props.onClick;
var props = _extends({}, this.props, {
onClick: this.handleClick
});
var props = _objectWithoutProperties(_props, ['activeClassName', 'activeStyle', 'onlyActiveOnIndex', 'to', 'query', 'state', 'onClick']);
var history = this.context.history;
props.onClick = this.handleClick;

@@ -115,6 +125,8 @@ // Ignore if rendered outside the context

if (history.isActive(to, query, onlyActiveOnIndex)) {
if (props.activeClassName) props.className += props.className !== '' ? ' ' + props.activeClassName : props.activeClassName;
if (activeClassName || activeStyle != null && !isEmptyObject(activeStyle)) {
if (history.isActive(to, query, onlyActiveOnIndex)) {
if (activeClassName) props.className += props.className === '' ? activeClassName : ' ' + activeClassName;
if (props.activeStyle) props.style = _extends({}, props.style, props.activeStyle);
if (activeStyle) props.style = _extends({}, props.style, activeStyle);
}
}

@@ -121,0 +133,0 @@ }

@@ -9,2 +9,4 @@ 'use strict';

var _RouteUtils = require('./RouteUtils');
function getChildRoutes(route, location, callback) {

@@ -14,3 +16,5 @@ if (route.childRoutes) {

} else if (route.getChildRoutes) {
route.getChildRoutes(location, callback);
route.getChildRoutes(location, function (error, childRoutes) {
callback(error, !error && _RouteUtils.createRoutes(childRoutes));
});
} else {

@@ -25,3 +29,5 @@ callback();

} else if (route.getIndexRoute) {
route.getIndexRoute(location, callback);
route.getIndexRoute(location, function (error, indexRoute) {
callback(error, !error && _RouteUtils.createRoutes(indexRoute)[0]);
});
} else {

@@ -28,0 +34,0 @@ callback();

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

var routes = oneOfType([route, arrayOf(route)]);
exports.routes = routes;
exports.routes = routes;
exports['default'] = {
falsy: falsy,
history: history,
location: location,
component: component,
components: components,
route: route
};

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

route.onEnter = function (nextState, redirectTo) {
route.onEnter = function (nextState, replaceState) {
var location = nextState.location;

@@ -52,3 +52,3 @@ var params = nextState.params;

redirectTo(pathname, route.query || location.query, route.state || location.state);
replaceState(route.state || location.state, pathname, route.query || location.query);
};

@@ -55,0 +55,0 @@

@@ -5,4 +5,2 @@ 'use strict';

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

@@ -14,2 +12,6 @@

var _warning = require('warning');
var _warning2 = _interopRequireDefault(_warning);
var _historyLibCreateHashHistory = require('history/lib/createHashHistory');

@@ -101,2 +103,6 @@

componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
_warning2['default'](nextProps.history === this.props.history, "The `history` provided to <Router/> has changed, it will be ignored.");
},
componentWillUnmount: function componentWillUnmount() {

@@ -107,6 +113,19 @@ if (this._unlisten) this._unlisten();

render: function render() {
return _react2['default'].createElement(_RoutingContext2['default'], _extends({}, this.state, {
var _state = this.state;
var location = _state.location;
var routes = _state.routes;
var params = _state.params;
var components = _state.components;
var createElement = this.props.createElement;
if (location == null) return null; // Async match
return _react2['default'].createElement(_RoutingContext2['default'], {
history: this.history,
createElement: this.props.createElement
}));
createElement: createElement,
location: location,
routes: routes,
params: params,
components: components
});
}

@@ -113,0 +132,0 @@

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

* A <RoutingContext> renders the component tree for a given router state
* and sets the router object and the current location in context.
* and sets the history object and the current location in context.
*/

@@ -86,3 +86,4 @@ var RoutingContext = _react2['default'].createClass({

route: route,
routeParams: routeParams
routeParams: routeParams,
routes: routes
};

@@ -89,0 +90,0 @@

@@ -31,5 +31,5 @@ 'use strict';

* Runs all onEnter hooks in the given array of routes in order
* with onEnter(nextState, redirectTo, callback) and calls
* with onEnter(nextState, replaceState, callback) and calls
* callback(error, redirectInfo) when finished. The first hook
* to use redirectTo short-circuits the loop.
* to use replaceState short-circuits the loop.
*

@@ -50,3 +50,3 @@ * If a hook needs to run asynchronously, it may use the callback

var redirectInfo;
function redirectTo(pathname, query, state) {
function replaceState(state, pathname, query) {
redirectInfo = { pathname: pathname, query: query, state: state };

@@ -56,3 +56,3 @@ }

_AsyncUtils.loopAsync(hooks.length, function (index, next, done) {
hooks[index](nextState, redirectTo, function (error) {
hooks[index](nextState, replaceState, function (error) {
if (error || redirectInfo) {

@@ -59,0 +59,0 @@ done(error, redirectInfo); // No need to continue.

@@ -15,2 +15,4 @@ 'use strict';

var _historyLibActions = require('history/lib/Actions');
var _historyLibUseQueries = require('history/lib/useQueries');

@@ -20,2 +22,6 @@

var _historyLibCreateLocation = require('history/lib/createLocation');
var _historyLibCreateLocation2 = _interopRequireDefault(_historyLibCreateLocation);
var _computeChangedRoutes2 = require('./computeChangedRoutes');

@@ -39,4 +45,11 @@

function hasAnyProperties(object) {
for (var p in object) if (object.hasOwnProperty(p)) return true;
return false;
}
/**
* Enhances a history object with the following methods:
* Returns a new createHistory function that may be used to create
* history objects that know about routing.
*

@@ -46,4 +59,4 @@ * - isActive(pathname, query)

* - unregisterRouteHook(route, (location) => {})
* - listen((error, state) => {})
* - match(location, (error, state) => {})
* - match(location, (error, nextState, nextLocation) => {})
* - listen((error, nextState) => {})
*/

@@ -66,17 +79,4 @@ function useRoutes(createHistory) {

function matchRoutesWithGuaranteedState(routes, location, callback) {
_matchRoutes2['default'](routes, location, function (error, nextState) {
if (error || nextState) {
callback(error, nextState);
} else {
_warning2['default'](false, 'Location "%s" did not match any routes', location.pathname + location.search);
}
});
}
var partialNextState = undefined;
// TODO: If we had a way to uniquely identify a route,
// we could use a plain object here instead...
var routeHooks = new Map();
var partialNextState;
function match(location, callback) {

@@ -87,7 +87,12 @@ if (partialNextState && partialNextState.location === location) {

} else {
matchRoutesWithGuaranteedState(routes, location, function (error, nextState) {
_matchRoutes2['default'](routes, location, function (error, nextState) {
if (error) {
callback(error);
callback(error, null, null);
} else if (nextState) {
finishMatch(_extends({}, nextState, { location: location }), function (err, nextLocation, nextState) {
if (nextState) state = nextState;
callback(err, nextLocation, nextState);
});
} else {
finishMatch(_extends({}, nextState, { location: location }), callback);
callback(null, null, null);
}

@@ -98,2 +103,10 @@ });

function createLocationFromRedirectInfo(_ref) {
var pathname = _ref.pathname;
var query = _ref.query;
var state = _ref.state;
return _historyLibCreateLocation2['default'](history.createPath(pathname, query), state, _historyLibActions.REPLACE, history.createKey());
}
function finishMatch(nextState, callback) {

@@ -111,15 +124,10 @@ var _computeChangedRoutes = _computeChangedRoutes3['default'](state, nextState);

} else if (redirectInfo) {
var pathname = redirectInfo.pathname;
var query = redirectInfo.query;
var state = redirectInfo.state;
history.replaceState(state, pathname, query);
callback();
callback(null, createLocationFromRedirectInfo(redirectInfo), null);
} else {
// TODO: Fetch components after state is updated.
_getComponents2['default'](nextState.routes, function (error, components) {
_getComponents2['default'](nextState, function (error, components) {
if (error) {
callback(error);
} else {
callback(null, _extends({}, nextState, { components: components }));
callback(null, null, _extends({}, nextState, { components: components }));
}

@@ -131,5 +139,13 @@ });

var RouteHooks = {};
var RouteGuid = 1;
function getRouteID(route) {
return route.__id__ || (route.__id__ = RouteGuid++);
}
function getRouteHooksForRoutes(routes) {
return routes.reduce(function (hooks, route) {
hooks.push.apply(hooks, routeHooks.get(route));
hooks.push.apply(hooks, RouteHooks[getRouteID(route)]);
return hooks;

@@ -140,22 +156,25 @@ }, []);

function transitionHook(location, callback) {
matchRoutesWithGuaranteedState(routes, location, function (error, nextState) {
if (error) {
// TODO: Handle the error.
callback(false); // Cancel the transition.
} else {
// Cache some state here so we don't have to
// matchRoutes() again in the listen callback.
partialNextState = _extends({}, nextState, { location: location });
_matchRoutes2['default'](routes, location, function (error, nextState) {
if (nextState == null) {
// TODO: We didn't actually match anything, but hang
// onto error/nextState so we don't have to matchRoutes
// again in the listen callback.
callback();
return;
}
var hooks = getRouteHooksForRoutes(_computeChangedRoutes3['default'](state, nextState).leaveRoutes);
// Cache some state here so we don't have to
// matchRoutes() again in the listen callback.
partialNextState = _extends({}, nextState, { location: location });
var result;
for (var i = 0, len = hooks.length; result == null && i < len; ++i) {
// Passing the location arg here indicates to
// the user that this is a transition hook.
result = hooks[i](location);
}
var hooks = getRouteHooksForRoutes(_computeChangedRoutes3['default'](state, nextState).leaveRoutes);
callback(result);
}
var result = undefined;
for (var i = 0, len = hooks.length; result == null && i < len; ++i) {
// Passing the location arg here indicates to
// the user that this is a transition hook.
result = hooks[i](location);
}
callback(result);
});

@@ -167,6 +186,6 @@ }

// prevent the current window/tab from closing.
if (state && state.routes) {
if (state.routes) {
var hooks = getRouteHooksForRoutes(state.routes);
var message;
var message = undefined;
for (var i = 0, len = hooks.length; typeof message !== 'string' && i < len; ++i) {

@@ -186,8 +205,11 @@ // Passing no args indicates to the user that this is a

// route objects on every location change.
var hooks = routeHooks.get(route);
var routeID = getRouteID(route);
var hooks = RouteHooks[routeID];
if (hooks == null) {
routeHooks.set(route, hooks = [hook]);
var thereWereNoRouteHooks = !hasAnyProperties(RouteHooks);
if (routeHooks.size === 1) {
hooks = RouteHooks[routeID] = [hook];
if (thereWereNoRouteHooks) {
history.registerTransitionHook(transitionHook);

@@ -203,3 +225,4 @@

function unregisterRouteHook(route, hook) {
var hooks = routeHooks.get(route);
var routeID = getRouteID(route);
var hooks = RouteHooks[routeID];

@@ -212,5 +235,5 @@ if (hooks != null) {

if (newHooks.length === 0) {
routeHooks['delete'](route);
delete RouteHooks[routeID];
if (routeHooks.size === 0) {
if (!hasAnyProperties(RouteHooks)) {
history.unregisterTransitionHook(transitionHook);

@@ -221,3 +244,3 @@

} else {
routeHooks.set(route, newHooks);
RouteHooks[routeID] = newHooks;
}

@@ -227,20 +250,27 @@ }

function dispatch(location, callback) {
if (state && state.location === location) {
callback(null, state);
return;
}
match(location, function (error, nextState) {
if (error) {
callback(error);
} else if (nextState) {
callback(null, state = nextState);
}
});
}
/**
* This is the API for stateful environments. As the location changes,
* we update state and call the listener. Benefits of this API are:
*
* - We automatically manage state on the client
* - We automatically handle redirects on the client
* - We warn when the location doesn't match any routes
*/
function listen(listener) {
return history.listen(function (location) {
dispatch(location, listener);
if (state.location === location) {
listener(null, state);
} else {
match(location, function (error, nextLocation, nextState) {
if (error) {
listener(error);
} else if (nextState) {
listener(null, state); // match mutates state to nextState
} else if (nextLocation) {
history.transitionTo(nextLocation);
} else {
_warning2['default'](false, 'Location "%s" did not match any routes', location.pathname + location.search);
}
});
}
});

@@ -247,0 +277,0 @@ }

import { mapAsync } from './AsyncUtils';
function getComponentsForRoute(route, callback) {
function getComponentsForRoute(location, route, callback) {
if (route.component || route.components) {
callback(null, route.component || route.components);
} else if (route.getComponent) {
route.getComponent(callback);
route.getComponent(location, callback);
} else if (route.getComponents) {
route.getComponents(callback);
route.getComponents(location, callback);
} else {

@@ -22,5 +22,5 @@ callback();

*/
function getComponents(routes, callback) {
mapAsync(routes, function (route, index, callback) {
getComponentsForRoute(route, callback);
function getComponents(nextState, callback) {
mapAsync(nextState.routes, function (route, index, callback) {
getComponentsForRoute(nextState.location, route, callback);
}, callback);

@@ -27,0 +27,0 @@ }

@@ -11,12 +11,13 @@ /* components */

/* mixins */
export History from './History';
export Lifecycle from './Lifecycle';
export Navigation from './Navigation';
export RouteContext from './RouteContext';
export State from './State';
/* utils */
export useRoutes from './useRoutes';
export { createRoutesFromReactChildren } from './RouteUtils';
export { createRoutes } from './RouteUtils';
export RoutingContext from './RoutingContext';
export PropTypes from './PropTypes';
export match from './match';
export default from './Router';
import React from 'react';
import { component } from './PropTypes';
import Link from './Link';
var IndexLink = React.createClass({
render() {

@@ -8,0 +7,0 @@ return <Link {...this.props} onlyActiveOnIndex={true} />

import React from 'react';
import invariant from 'invariant';
import warning from 'warning';
import { createRouteFromReactElement } from './RouteUtils';

@@ -4,0 +5,0 @@ import { component, components, falsy } from './PropTypes';

@@ -15,2 +15,3 @@ import { matchPattern } from './PatternUtils';

route = activeRoutes[i];
if (!route.path) return false;
pattern = route.path || '';

@@ -17,0 +18,0 @@

@@ -10,3 +10,3 @@ import React from 'react';

* the user for confirmation.
*
*
* On standard transitions, routerWillLeave receives a single argument: the

@@ -48,3 +48,3 @@ * location we're transitioning to. To cancel the transition, return false.

},
componentWillMount() {

@@ -51,0 +51,0 @@ invariant(

@@ -14,2 +14,10 @@ import React from 'react';

function isEmptyObject(object) {
for (var p in object)
if (object.hasOwnProperty(p))
return false;
return true;
}
/**

@@ -51,5 +59,4 @@ * A <Link> is used to create an <a> element that links to a route.

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

@@ -88,11 +95,7 @@ };

render() {
var { to, query, onlyActiveOnIndex } = this.props;
var { history } = this.context;
var { activeClassName, activeStyle, onlyActiveOnIndex, to, query, state, onClick, ...props } = this.props;
var props = {
...this.props,
onClick: this.handleClick
};
props.onClick = this.handleClick;
var { history } = this.context;
// Ignore if rendered outside the context

@@ -103,8 +106,10 @@ // of history, simplifies unit testing.

if (history.isActive(to, query, onlyActiveOnIndex)) {
if (props.activeClassName)
props.className += props.className !== '' ? ` ${props.activeClassName}` : props.activeClassName;
if (activeClassName || (activeStyle != null && !isEmptyObject(activeStyle))) {
if (history.isActive(to, query, onlyActiveOnIndex)) {
if (activeClassName)
props.className += props.className === '' ? activeClassName : ` ${activeClassName}`;
if (props.activeStyle)
props.style = { ...props.style, ...props.activeStyle };
if (activeStyle)
props.style = { ...props.style, ...activeStyle };
}
}

@@ -111,0 +116,0 @@ }

import { loopAsync } from './AsyncUtils';
import { matchPattern } from './PatternUtils';
import { createRoutes } from './RouteUtils';

@@ -8,3 +9,5 @@ function getChildRoutes(route, location, callback) {

} else if (route.getChildRoutes) {
route.getChildRoutes(location, callback);
route.getChildRoutes(location, function(error, childRoutes) {
callback(error, !error && createRoutes(childRoutes));
});
} else {

@@ -19,3 +22,5 @@ callback();

} else if (route.getIndexRoute) {
route.getIndexRoute(location, callback);
route.getIndexRoute(location, function(error, indexRoute) {
callback(error, !error && createRoutes(indexRoute)[0]);
});
} else {

@@ -22,0 +27,0 @@ callback();

@@ -17,3 +17,3 @@ import invariant from 'invariant';

var match, lastIndex = 0, matcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|\*|\(|\)/g;
while (match = matcher.exec(pattern)) {
while ((match = matcher.exec(pattern))) {
if (match.index !== lastIndex) {

@@ -20,0 +20,0 @@ tokens.push(pattern.slice(lastIndex, match.index));

@@ -29,1 +29,10 @@ import { PropTypes } from 'react';

export var routes = oneOfType([ route, arrayOf(route) ]);
export default {
falsy,
history,
location,
component,
components,
route
};

@@ -32,10 +32,10 @@ import React from 'react';

route.onEnter = function (nextState, redirectTo) {
route.onEnter = function (nextState, replaceState) {
var { location, params } = nextState;
var pathname = route.to ? formatPattern(route.to, params) : location.pathname;
redirectTo(
replaceState(
route.state || location.state,
pathname,
route.query || location.query,
route.state || location.state
route.query || location.query
);

@@ -48,3 +48,3 @@ };

},
propTypes: {

@@ -66,5 +66,5 @@ path: string,

}
});
export default Redirect;

@@ -16,3 +16,3 @@ import React from 'react';

},
childContextTypes: {

@@ -19,0 +19,0 @@ route: object.isRequired

import React from 'react';
import warning from 'warning';
import createHashHistory from 'history/lib/createHashHistory';

@@ -8,3 +9,3 @@ import { createRoutes } from './RouteUtils';

var { func, object } = React.PropTypes;
const { func, object } = React.PropTypes;

@@ -16,4 +17,4 @@ /**

*/
var Router = React.createClass({
const Router = React.createClass({
propTypes: {

@@ -49,4 +50,4 @@ history: object,

componentWillMount() {
var { history, children, routes, parseQueryString, stringifyQuery } = this.props;
var createHistory = history ? () => history : createHashHistory;
let { history, children, routes, parseQueryString, stringifyQuery } = this.props;
let createHistory = history ? () => history : createHashHistory;

@@ -68,2 +69,9 @@ this.history = useRoutes(createHistory)({

componentWillReceiveProps(nextProps) {
warning(
nextProps.history === this.props.history,
"The `history` provided to <Router/> has changed, it will be ignored."
);
},
componentWillUnmount() {

@@ -75,6 +83,15 @@ if (this._unlisten)

render() {
let { location, routes, params, components } = this.state;
let { createElement } = this.props;
if (location == null)
return null; // Async match
return React.createElement(RoutingContext, {
...this.state,
history: this.history,
createElement: this.props.createElement
createElement,
location,
routes,
params,
components
});

@@ -81,0 +98,0 @@ }

@@ -9,3 +9,3 @@ import React from 'react';

* A <RoutingContext> renders the component tree for a given router state
* and sets the router object and the current location in context.
* and sets the history object and the current location in context.
*/

@@ -61,3 +61,4 @@ var RoutingContext = React.createClass({

route,
routeParams
routeParams,
routes
};

@@ -64,0 +65,0 @@

@@ -26,5 +26,5 @@ import { loopAsync } from './AsyncUtils';

* Runs all onEnter hooks in the given array of routes in order
* with onEnter(nextState, redirectTo, callback) and calls
* with onEnter(nextState, replaceState, callback) and calls
* callback(error, redirectInfo) when finished. The first hook
* to use redirectTo short-circuits the loop.
* to use replaceState short-circuits the loop.
*

@@ -44,3 +44,3 @@ * If a hook needs to run asynchronously, it may use the callback

var redirectInfo;
function redirectTo(pathname, query, state) {
function replaceState(state, pathname, query) {
redirectInfo = { pathname, query, state };

@@ -50,3 +50,3 @@ }

loopAsync(hooks.length, function (index, next, done) {
hooks[index](nextState, redirectTo, function (error) {
hooks[index](nextState, replaceState, function (error) {
if (error || redirectInfo) {

@@ -53,0 +53,0 @@ done(error, redirectInfo); // No need to continue.

import warning from 'warning';
import { REPLACE } from 'history/lib/Actions';
import useQueries from 'history/lib/useQueries';
import createLocation from 'history/lib/createLocation';
import computeChangedRoutes from './computeChangedRoutes';

@@ -9,4 +11,13 @@ import { runEnterHooks, runLeaveHooks } from './TransitionUtils';

function hasAnyProperties(object) {
for (var p in object)
if (object.hasOwnProperty(p))
return true;
return false;
}
/**
* Enhances a history object with the following methods:
* Returns a new createHistory function that may be used to create
* history objects that know about routing.
*

@@ -16,10 +27,10 @@ * - isActive(pathname, query)

* - unregisterRouteHook(route, (location) => {})
* - listen((error, state) => {})
* - match(location, (error, state) => {})
* - match(location, (error, nextState, nextLocation) => {})
* - listen((error, nextState) => {})
*/
function useRoutes(createHistory) {
return function (options={}) {
var { routes, ...historyOptions } = options;
var history = useQueries(createHistory)(historyOptions);
var state = {};
let { routes, ...historyOptions } = options;
let history = useQueries(createHistory)(historyOptions);
let state = {};

@@ -30,21 +41,4 @@ function isActive(pathname, query, indexOnly=false) {

function matchRoutesWithGuaranteedState(routes, location, callback) {
matchRoutes(routes, location, function (error, nextState) {
if (error || nextState) {
callback(error, nextState);
} else {
warning(
false,
'Location "%s" did not match any routes',
location.pathname + location.search
);
}
});
}
let partialNextState;
// TODO: If we had a way to uniquely identify a route,
// we could use a plain object here instead...
var routeHooks = new Map();
var partialNextState;
function match(location, callback) {

@@ -55,7 +49,13 @@ if (partialNextState && partialNextState.location === location) {

} else {
matchRoutesWithGuaranteedState(routes, location, function (error, nextState) {
matchRoutes(routes, location, function (error, nextState) {
if (error) {
callback(error);
callback(error, null, null);
} else if (nextState) {
finishMatch({ ...nextState, location }, function (err, nextLocation, nextState) {
if (nextState)
state = nextState;
callback(err, nextLocation, nextState);
});
} else {
finishMatch({ ...nextState, location }, callback);
callback(null, null, null);
}

@@ -66,4 +66,10 @@ });

function createLocationFromRedirectInfo({ pathname, query, state }) {
return createLocation(
history.createPath(pathname, query), state, REPLACE, history.createKey()
);
}
function finishMatch(nextState, callback) {
var { leaveRoutes, enterRoutes } = computeChangedRoutes(state, nextState);
let { leaveRoutes, enterRoutes } = computeChangedRoutes(state, nextState);

@@ -76,12 +82,10 @@ runLeaveHooks(leaveRoutes);

} else if (redirectInfo) {
var { pathname, query, state } = redirectInfo;
history.replaceState(state, pathname, query);
callback();
callback(null, createLocationFromRedirectInfo(redirectInfo), null);
} else {
// TODO: Fetch components after state is updated.
getComponents(nextState.routes, function (error, components) {
getComponents(nextState, function (error, components) {
if (error) {
callback(error);
} else {
callback(null, { ...nextState, components });
callback(null, null, { ...nextState, components });
}

@@ -93,5 +97,13 @@ });

const RouteHooks = {};
let RouteGuid = 1;
function getRouteID(route) {
return route.__id__ || (route.__id__ = RouteGuid++);
}
function getRouteHooksForRoutes(routes) {
return routes.reduce(function (hooks, route) {
hooks.push.apply(hooks, routeHooks.get(route));
hooks.push.apply(hooks, RouteHooks[getRouteID(route)]);
return hooks;

@@ -102,24 +114,27 @@ }, []);

function transitionHook(location, callback) {
matchRoutesWithGuaranteedState(routes, location, function (error, nextState) {
if (error) {
// TODO: Handle the error.
callback(false); // Cancel the transition.
} else {
// Cache some state here so we don't have to
// matchRoutes() again in the listen callback.
partialNextState = { ...nextState, location };
matchRoutes(routes, location, function (error, nextState) {
if (nextState == null) {
// TODO: We didn't actually match anything, but hang
// onto error/nextState so we don't have to matchRoutes
// again in the listen callback.
callback();
return;
}
var hooks = getRouteHooksForRoutes(
computeChangedRoutes(state, nextState).leaveRoutes
);
// Cache some state here so we don't have to
// matchRoutes() again in the listen callback.
partialNextState = { ...nextState, location };
var result;
for (var i = 0, len = hooks.length; result == null && i < len; ++i) {
// Passing the location arg here indicates to
// the user that this is a transition hook.
result = hooks[i](location);
}
let hooks = getRouteHooksForRoutes(
computeChangedRoutes(state, nextState).leaveRoutes
);
callback(result);
let result;
for (let i = 0, len = hooks.length; result == null && i < len; ++i) {
// Passing the location arg here indicates to
// the user that this is a transition hook.
result = hooks[i](location);
}
callback(result);
});

@@ -129,9 +144,9 @@ }

function beforeUnloadHook() {
// Synchronously check to see if any route hooks want to
// Synchronously check to see if any route hooks want to
// prevent the current window/tab from closing.
if (state && state.routes) {
var hooks = getRouteHooksForRoutes(state.routes);
if (state.routes) {
let hooks = getRouteHooksForRoutes(state.routes);
var message;
for (var i = 0, len = hooks.length; typeof message !== 'string' && i < len; ++i) {
let message;
for (let i = 0, len = hooks.length; typeof message !== 'string' && i < len; ++i) {
// Passing no args indicates to the user that this is a

@@ -150,10 +165,13 @@ // beforeunload hook. We don't know the next location.

// route objects on every location change.
var hooks = routeHooks.get(route);
let routeID = getRouteID(route);
let hooks = RouteHooks[routeID];
if (hooks == null) {
routeHooks.set(route, (hooks = [ hook ]));
let thereWereNoRouteHooks = !hasAnyProperties(RouteHooks);
if (routeHooks.size === 1) {
hooks = RouteHooks[routeID] = [ hook ];
if (thereWereNoRouteHooks) {
history.registerTransitionHook(transitionHook);
if (history.registerBeforeUnloadHook)

@@ -168,11 +186,12 @@ history.registerBeforeUnloadHook(beforeUnloadHook);

function unregisterRouteHook(route, hook) {
var hooks = routeHooks.get(route);
let routeID = getRouteID(route);
let hooks = RouteHooks[routeID];
if (hooks != null) {
var newHooks = hooks.filter(item => item !== hook);
let newHooks = hooks.filter(item => item !== hook);
if (newHooks.length === 0) {
routeHooks.delete(route);
delete RouteHooks[routeID];
if (routeHooks.size === 0) {
if (!hasAnyProperties(RouteHooks)) {
history.unregisterTransitionHook(transitionHook);

@@ -184,3 +203,3 @@

} else {
routeHooks.set(route, newHooks);
RouteHooks[routeID] = newHooks;
}

@@ -190,20 +209,31 @@ }

function dispatch(location, callback) {
if (state && state.location === location) {
callback(null, state);
return;
}
match(location, function (error, nextState) {
if (error) {
callback(error);
} else if (nextState) {
callback(null, (state = nextState));
}
});
}
/**
* This is the API for stateful environments. As the location changes,
* we update state and call the listener. Benefits of this API are:
*
* - We automatically manage state on the client
* - We automatically handle redirects on the client
* - We warn when the location doesn't match any routes
*/
function listen(listener) {
return history.listen(function (location) {
dispatch(location, listener);
if (state.location === location) {
listener(null, state);
} else {
match(location, function (error, nextLocation, nextState) {
if (error) {
listener(error);
} else if (nextState) {
listener(null, state); // match mutates state to nextState
} else if (nextLocation) {
history.transitionTo(nextLocation);
} else {
warning(
false,
'Location "%s" did not match any routes',
location.pathname + location.search
);
}
});
}
});

@@ -210,0 +240,0 @@ }

## Confirming Navigation
Sometimes you may want to prevent the user from going to a different page. For example, if they are halfway finished filling out a long form, and they click the back button, you may want to prompt them to confirm they actually want to leave the page before they lose the information they've already entered. For these cases, `history` lets you register transition hooks that return a prompt message you can show the user before the location changes. For example, you could do something like this:
Sometimes you may want to prevent the user from going to a different page. For example, if they are halfway finished filling out a long form, and they click the back button, you may want to prompt them to confirm they actually want to leave the page before they lose the information they've already entered. For these cases, `history` lets you register [transition hooks](Terms.md#transitionhook) that return a prompt message you can show the user before the [location](Terms.md#location) changes. For example, you could do something like this:

@@ -8,7 +8,7 @@ ```js

if (input.value !== '')
return 'Are you sure you want to leave this page?';
});
return 'Are you sure you want to leave this page?'
})
```
You can also simply `return false` to prevent a transition.
You can also simply `return false` to prevent a [transition](Terms.md#transition).

@@ -19,4 +19,4 @@ If your transition hook needs to execute asynchronously, you can provide a second `callback` argument to your transition hook function that you must call when you're done with async work.

history.registerTransitionHook(function (location, callback) {
doSomethingAsync().then(callback);
});
doSomethingAsync().then(callback)
})
```

@@ -29,7 +29,7 @@

```js
var history = createHistory({
let history = createHistory({
getUserConfirmation: function (message, callback) {
callback(window.confirm(message)); // The default behavior
callback(window.confirm(message)) // The default behavior
}
});
})
```

@@ -42,11 +42,11 @@

```js
import { createHistory, useBeforeUnload } from 'history';
import { createHistory, useBeforeUnload } from 'history'
var history = useBeforeUnload(createHistory)();
let history = useBeforeUnload(createHistory)()
history.registerBeforeUnloadHook(function () {
return 'Are you sure you want to leave this page?';
});
return 'Are you sure you want to leave this page?'
})
```
Note that because of the nature of the `beforeunload` event all hooks must `return` synchronously. `history` runs all hooks in the order they were registered and displays the first message that is returned.
## Getting Started
The first thing you'll need to do is create a history object. The main `history` module exports several different `create*` methods that you can use depending on your environment.
The first thing you'll need to do is create a [history object](Terms.md#history). The main `history` module exports several different [`create*` methods](Terms.md#createhistory) that you can use depending on your environment.

@@ -12,14 +12,14 @@ - `createHistory` is for use in modern web browsers that support the [HTML5 history API](http://diveintohtml5.info/history.html) (see [cross-browser compatibility](http://caniuse.com/#feat=history))

```js
import { createHistory } from 'history';
import { createHistory } from 'history'
var history = createHistory();
let history = createHistory()
// Listen for changes to the current location. The
// listener is called once immediately.
var unlisten = history.listen(function (location) {
console.log(location.pathname);
});
let unlisten = history.listen(function (location) {
console.log(location.pathname)
})
// When you're finished, stop the listener.
unlisten();
unlisten()
```

@@ -38,15 +38,15 @@

The `path` argument to `pushState` and `replaceState` represents a complete URL path, including the query string. The `state` argument should be a JSON-serializable object. In `setState`, the properties in `state` are shallowly merged into the current state.
The [`path`](Terms.md#path) argument to `pushState` and `replaceState` represents a complete URL path, including the [query string](Terms.md#querystring). The [`state`](Terms.md#locationstate) argument should be a JSON-serializable object. In `setState`, the properties in `state` are shallowly merged into the current state.
```js
// Push a new entry onto the history stack.
history.pushState({ some: 'state' }, '/home');
history.pushState({ some: 'state' }, '/home')
// Replace the current entry on the history stack.
history.replaceState({ some: 'other state' }, '/profile');
history.replaceState({ some: 'other state' }, '/profile')
// Go back to the previous history entry. The following
// two lines are synonymous.
history.go(-1);
history.goBack();
history.go(-1)
history.goBack()
```

@@ -61,3 +61,3 @@

```js
var href = history.createHref('/the/path');
let href = history.createHref('/the/path')
```

@@ -71,9 +71,9 @@

// Browser history
import createHistory from 'history/lib/createBrowserHistory';
import createHistory from 'history/lib/createBrowserHistory'
// Hash history
import createHistory from 'history/lib/createHashHistory';
import createHistory from 'history/lib/createHashHistory'
// Memory history
import createHistory from 'history/lib/createMemoryHistory';
import createHistory from 'history/lib/createMemoryHistory'
```

@@ -8,15 +8,15 @@ ## Caveats of Using Hash History

```js
import createHistory from 'history/lib/createHashHistory';
import createHistory from 'history/lib/createHashHistory'
// Use _key instead of _k.
var history = createHistory({
let history = createHistory({
queryKey: '_key'
});
})
// Opt-out of persistent state, not recommended.
var history = createHistory({
let history = createHistory({
queryKey: false
});
})
```
One other thing to keep in mind when using hash history is that you cannot also use `window.location.hash` as it was originally intended, to link an anchor point within your HTML document.
## Location
A `location` object is conceptually similar to [`document.location` in web browsers](https://developer.mozilla.org/en-US/docs/Web/API/Document/location), with a few extra goodies. `location` objects have the following properties:
A [`location` object](Terms.md#location) is conceptually similar to [`document.location` in web browsers](https://developer.mozilla.org/en-US/docs/Web/API/Document/location), with a few extra goodies. `location` objects have the following properties:

@@ -20,5 +20,5 @@ ```

```js
import createLocation from 'history/lib/createLocation';
import createLocation from 'history/lib/createLocation'
var location = createLocation('/a/path?a=query', { the: 'state' });
let location = createLocation('/a/path?a=query', { the: 'state' })
```
## Query Support
Support for parsing and serializing URL queries is provided by the `useQueries` enhancer function. Simply use a wrapped version of your `createHistory` function to create your `history` object and you'll have a parsed `location.query` object inside `listen`.
Support for parsing and serializing [URL queries](Terms.md#query) is provided by the `useQueries` [enhancer](Terms.md#createhistoryenhancer) function. Simply use a wrapped version of your `createHistory` function to create your `history` object and you'll have a parsed `location.query` object inside `listen`.
```js
import { createHistory, useQueries } from 'history';
import { createHistory, useQueries } from 'history'
// Use the built-in query parsing/serialization.
var history = useQueries(createHistory)();
let history = useQueries(createHistory)()
// Use custom query parsing/serialization.
var history = useQueries(createHistory)({
let history = useQueries(createHistory)({
parseQueryString: function (queryString) {
return qs.parse(queryString);
return qs.parse(queryString)
},
stringifyQuery: function (query) {
return qs.stringify(query, { arrayFormat: 'brackets' });
return qs.stringify(query, { arrayFormat: 'brackets' })
}
});
})
history.listen(function (location) {
console.log(location.query);
});
console.log(location.query)
})
```

@@ -29,4 +29,4 @@

```js
history.createPath('/the/path', { the: 'query' });
history.pushState(null, '/the/path', { the: 'query' });
history.createPath('/the/path', { the: 'query' })
history.pushState(null, '/the/path', { the: 'query' })
```

@@ -8,1 +8,2 @@ ## Table of Contents

- [Caveats of Using Hash History](HashHistoryCaveats.md)
- [Glossary](Terms.md)

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

var state;
var state = undefined;
if (key) {

@@ -57,3 +57,3 @@ state = _DOMStateStorage.readState(key);

key = history.createKey();
window.history.replaceState(_extends({}, historyState, { key: key }), path);
window.history.replaceState(_extends({}, historyState, { key: key }), null, path);
}

@@ -119,3 +119,3 @@

var listenerCount = 0,
stopPopStateListener;
stopPopStateListener = undefined;

@@ -122,0 +122,0 @@ function listen(listener) {

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

var key, state;
var key = undefined,
state = undefined;
if (queryKey) {

@@ -99,3 +100,3 @@ key = getQueryStringValueFromPath(path, queryKey);

transitionTo(getCurrentLocation());
};
}

@@ -149,3 +150,3 @@ ensureSlash();

var listenerCount = 0,
stopHashChangeListener;
stopHashChangeListener = undefined;

@@ -165,3 +166,3 @@ function listen(listener) {

function pushState(state, path) {
_warning2['default'](queryKey || state == null, 'You cannot use state without a queryKey; it will be dropped');
_warning2['default'](queryKey || state == null, 'You cannot use state without a queryKey it will be dropped');

@@ -172,3 +173,3 @@ history.pushState(state, path);

function replaceState(state, path) {
_warning2['default'](queryKey || state == null, 'You cannot use state without a queryKey; it will be dropped');
_warning2['default'](queryKey || state == null, 'You cannot use state without a queryKey it will be dropped');

@@ -175,0 +176,0 @@ history.replaceState(state, path);

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

var changeListeners = [];
var location;
var location = undefined;

@@ -101,5 +101,5 @@ var allKeys = [];

} else {
var location = getCurrentLocation();
allKeys = [location.key];
updateLocation(location);
var _location = getCurrentLocation();
allKeys = [_location.key];
updateLocation(_location);
}

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

} else {
_warning2['default'](result === undefined, 'You may not use `return` in a transition hook with a callback argument; call the callback instead');
_warning2['default'](result === undefined, 'You should not "return" in a transition hook with a callback argument call the callback instead');
}

@@ -155,3 +155,3 @@ }

var pendingLocation;
var pendingLocation = undefined;

@@ -158,0 +158,0 @@ function transitionTo(nextLocation) {

@@ -31,13 +31,18 @@ 'use strict';

var index = path.indexOf('?');
var pathname = path;
var search = '';
var hash = '';
var pathname, search;
if (index !== -1) {
pathname = path.substring(0, index);
search = path.substring(index);
} else {
pathname = path;
search = '';
var hashIndex = pathname.indexOf('#');
if (hashIndex !== -1) {
hash = pathname.substring(hashIndex);
pathname = pathname.substring(0, hashIndex);
}
var searchIndex = pathname.indexOf('?');
if (searchIndex !== -1) {
search = pathname.substring(searchIndex);
pathname = pathname.substring(0, searchIndex);
}
if (pathname === '') pathname = '/';

@@ -48,2 +53,3 @@

search: search,
hash: hash,
state: state,

@@ -50,0 +56,0 @@ action: action,

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

var state;
var state = undefined;
if (key) {

@@ -112,3 +112,3 @@ state = readState(key);

if (n) {
_invariant2['default'](canGo(n), 'Cannot go(%s); there is not enough history', n);
_invariant2['default'](canGo(n), 'Cannot go(%s) there is not enough history', n);

@@ -131,3 +131,3 @@ current += n;

// remove rest and push new
if (current < entries.length - 1) {
if (current < entries.length) {
entries.splice(current);

@@ -134,0 +134,0 @@ }

@@ -28,2 +28,7 @@ 'use strict';

/**
* Returns a new createHistory function that can be used to create
* history objects that know how to use the beforeunload event in web
* browsers to cancel navigation.
*/
function useBeforeUnload(createHistory) {

@@ -33,11 +38,11 @@ return function (options) {

var stopBeforeUnloadListener;
var stopBeforeUnloadListener = undefined;
var beforeUnloadHooks = [];
function getBeforeUnloadPromptMessage() {
var message;
var message = undefined;
for (var i = 0, len = beforeUnloadHooks.length; message == null && i < len; ++i) message = beforeUnloadHooks[i].call();
return message;
for (var i = 0, len = beforeUnloadHooks.length; message == null && i < len; ++i) {
message = beforeUnloadHooks[i].call();
}return message;
}

@@ -44,0 +49,0 @@

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

/**
* Returns a new createHistory function that may be used to create
* history objects that know how to handle URL queries.
*/
function useQueries(createHistory) {

@@ -55,3 +59,3 @@ return function () {

function createPath(pathname, query) {
var queryString;
var queryString = undefined;
if (query == null || (queryString = stringifyQuery(query)) === '') return pathname;

@@ -58,0 +62,0 @@

@@ -16,3 +16,3 @@ var pSlice = Array.prototype.slice;

// equivalence is determined by ==.
} else if (typeof actual != 'object' && typeof expected != 'object') {
} else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {
return opts.strict ? actual === expected : actual == expected;

@@ -19,0 +19,0 @@

{
"name": "deep-equal",
"version": "1.0.0",
"version": "1.0.1",
"description": "node's assert.deepEqual algorithm",

@@ -19,3 +19,3 @@ "main": "index.js",

"type": "git",
"url": "http://github.com/substack/node-deep-equal.git"
"url": "git+ssh://git@github.com/substack/node-deep-equal.git"
},

@@ -59,16 +59,20 @@ "keywords": [

},
"gitHead": "39c740ebdafed9443912a4ef1493b18693934daf",
"gitHead": "59c511f5aeae19e3dd1de054077a789d7302be34",
"bugs": {
"url": "https://github.com/substack/node-deep-equal/issues"
},
"homepage": "https://github.com/substack/node-deep-equal",
"_id": "deep-equal@1.0.0",
"_shasum": "d4564f07d2f0ab3e46110bec16592abd7dc2e326",
"_from": "deep-equal@>=1.0.0 <2.0.0",
"_npmVersion": "2.3.0",
"_nodeVersion": "0.10.35",
"homepage": "https://github.com/substack/node-deep-equal#readme",
"_id": "deep-equal@1.0.1",
"_shasum": "f5d260292b660e084eff4cdbc9f08ad3247448b5",
"_from": "deep-equal@>=1.0.1 <2.0.0",
"_npmVersion": "3.2.2",
"_nodeVersion": "2.4.0",
"_npmUser": {
"name": "substack",
"email": "mail@substack.net"
"email": "substack@gmail.com"
},
"dist": {
"shasum": "f5d260292b660e084eff4cdbc9f08ad3247448b5",
"tarball": "http://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz"
},
"maintainers": [

@@ -80,8 +84,4 @@ {

],
"dist": {
"shasum": "d4564f07d2f0ab3e46110bec16592abd7dc2e326",
"tarball": "http://registry.npmjs.org/deep-equal/-/deep-equal-1.0.0.tgz"
},
"_resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.0.tgz",
"_resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
"readme": "ERROR: No README data found!"
}

@@ -90,1 +90,7 @@ var test = require('tape');

})
test('null == undefined', function (t) {
t.ok(equal(null, undefined))
t.notOk(equal(null, undefined, { strict: true }))
t.end()
})
{
"name": "history",
"version": "1.8.1",
"version": "1.9.0",
"description": "A minimal, functional history implementation for JavaScript",

@@ -15,4 +15,4 @@ "main": "lib/index",

"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-umd": "NODE_ENV=production webpack modules/index.js umd/History.js",
"build-min": "NODE_ENV=production webpack -p modules/index.js umd/History.min.js",
"start": "webpack-dev-server -d --content-base ./ --history-api-fallback --inline modules/index.js",

@@ -30,3 +30,2 @@ "test": "eslint modules && karma start",

"qs": "^4.0.0",
"tough-cookie": "^2.0.0",
"warning": "^2.0.0"

@@ -62,12 +61,12 @@ },

],
"gitHead": "de1850f70b6674cc6445fae692660ae4208a293e",
"gitHead": "e9b16da106f1567f81c4f17a709ac287d1396735",
"homepage": "https://github.com/rackt/history",
"_id": "history@1.8.1",
"_shasum": "bb8155ce711db359cf0467e300eae9dc17306dfc",
"_from": "history@>=1.8.0 <2.0.0",
"_npmVersion": "2.7.5",
"_nodeVersion": "0.10.28",
"_id": "history@1.9.0",
"_shasum": "0527bc87de22e9f11ccf33e8bb8b1a9a89b2d6d7",
"_from": "history@>=1.9.0 <2.0.0",
"_npmVersion": "2.5.1",
"_nodeVersion": "0.12.0",
"_npmUser": {
"name": "mjackson",
"email": "mjijackson@gmail.com"
"name": "ryanflorence",
"email": "rpflorence@gmail.com"
},

@@ -78,11 +77,14 @@ "maintainers": [

"email": "mjijackson@gmail.com"
},
{
"name": "ryanflorence",
"email": "rpflorence@gmail.com"
}
],
"dist": {
"shasum": "bb8155ce711db359cf0467e300eae9dc17306dfc",
"tarball": "http://registry.npmjs.org/history/-/history-1.8.1.tgz"
"shasum": "0527bc87de22e9f11ccf33e8bb8b1a9a89b2d6d7",
"tarball": "http://registry.npmjs.org/history/-/history-1.9.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/history/-/history-1.8.1.tgz",
"readme": "ERROR: No README data found!"
"_resolved": "https://registry.npmjs.org/history/-/history-1.9.0.tgz"
}

@@ -18,16 +18,16 @@ [![build status](https://img.shields.io/travis/rackt/history/master.svg?style=flat-square)](https://travis-ci.org/rackt/history)

```js
import { createHistory } from 'history';
import { createHistory } from 'history'
var history = createHistory();
let history = createHistory()
// Listen for changes to the current location. The
// listener is called once immediately.
var unlisten = history.listen(function (location) {
console.log(location.pathname);
});
let unlisten = history.listen(function (location) {
console.log(location.pathname)
})
history.pushState({ the: 'state' }, '/the/path?a=query');
history.pushState({ the: 'state' }, '/the/path?a=query')
// When you're finished, stop the listener.
unlisten();
unlisten()
```

@@ -34,0 +34,0 @@

{
"name": "react-router",
"version": "1.0.0-beta4",
"version": "1.0.0-rc1",
"description": "A complete routing library for React.js",

@@ -14,7 +14,7 @@ "main": "lib/index",

"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",
"build-umd": "NODE_ENV=production webpack modules/index.js umd/ReactRouter.js",
"build-min": "NODE_ENV=production webpack -p modules/index.js umd/ReactRouter.min.js",
"start": "webpack-dev-server --config examples/webpack.config.js --content-base examples --inline",
"test": "eslint modules && karma start",
"lint": "eslint modules",
"prepublish": "npm run build"

@@ -28,3 +28,3 @@ },

"dependencies": {
"history": "^1.8.0",
"history": "^1.9.0",
"invariant": "^2.0.0",

@@ -40,3 +40,4 @@ "warning": "^2.0.0"

"bundle-loader": "^0.5.2",
"eslint": "^1.0.0",
"eslint": "1.4.0",
"eslint-plugin-react": "3.3.2",
"events": "1.0.2",

@@ -43,0 +44,0 @@ "expect": "^1.6.0",

@@ -7,3 +7,3 @@ [![build status](https://img.shields.io/travis/rackt/react-router/master.svg?style=flat-square)](https://travis-ci.org/rackt/react-router)

A complete routing library for React. https://rackt.github.io/react-router
A complete routing library for React

@@ -17,3 +17,3 @@ React Router keeps your UI in sync with the URL. It has a simple API

- [Guides and API Docs](https://rackt.github.io/react-router)
- [Guides and API Docs](/docs)
- [Upgrade Guide](/UPGRADE_GUIDE.md)

@@ -23,5 +23,2 @@ - [Changelog](/CHANGELOG.md)

**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

@@ -40,3 +37,3 @@

```js
// using an ES6 transpiler
// using an ES6 transpiler, like babel
import { Router, Route, Link } from 'react-router';

@@ -51,10 +48,16 @@

There's also a `lib/umd` folder containing a UMD version.
You can require only the pieces you need straight from the `lib` directory:
#### bower + who knows what
```js
import { Router } from 'react-router/lib/Router';
```
$ bower install react-router
There's also a UMD build in the `umd` directory:
Find the UMD/global build in `lib/umd`, and the library on `window.ReactRouter`. Best of luck to you. :)
```js
import ReactRouter from 'react-router/umd/ReactRouter';
```
If you're using globals, you can find the library on `window.ReactRouter`.
#### CDN

@@ -128,10 +131,9 @@

See more in the [overview guide](/doc/00 Guides/0 Overview.md) and [Advanced
Usage](/doc/00 Guides/Advanced Usage.md)
See more in the [Introduction](/docs/introduction/README.md) and [Advanced
Usage](/docs/advanced/README.md).
### Thanks
React Router was initially inspired by Ember's fantastic router. Many
thanks to the Ember team.
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.

@@ -8,2 +8,232 @@ Upgrade Guide

0.13.3 -> 1.0.0
---------------
Thanks for your patience :) Big changes. While on the surface a lot of
this just looks like shuffling around API, the entire codebase has been
rewritten to handle some really great use cases, like loading routes and
components on demand, session-based route matching, server rendering,
integration with libs like redux and relay, and lots more.
But for now, here's how to translate the old API to the new one.
### Rendering
```js
// v0.13.x
Router.run(routes, (Handler) => {
React.render(<Handler/>, el);
})
// v1.0
React.render(<Router>{routes}</Router>, el)
// looks more like this:
React.render((
<Router>
<Route path="/" component={App}/>
</Router>
), el);
// or if you'd rather
React.render(<Router routes={routes}/>, el)
```
### Route Config
You can still nest your routes as before, paths are inherited from
parents just like before but prop names have changed.
```js
// v0.13.x
<Route name="about" handler={About}/>
// v1.0
<Route path="about" component={About}/>
```
Named routes are gone (for now, [see discussion](https://github.com/rackt/react-router/issues/1840))
### NotFound route
Not found really confused people, mistaking not finding resources
from your API for not matching a route. We've removed it completely
since its simple with a `*` path.
```js
// v0.13.x
<NotFoundRoute handler={NoMatch}/>
// v1.0
<Route path="*" component={NoMatch}/>
```
### Redirect route
- no more params
- must have absolute "from" (for now)
```js
// v0.13.x
<Redirect from="some/where/:id" to="somewhere/else/:id" params={{id: 2}}/>
// v1.0
// Works the same as before, except no params, just put them in the path
<Redirect from="/some/where/:id" to="/somewhere/else/2"/>
```
### Links
#### path / params
```js
// v0.13.x
<Link to="user" params={{userId: user.id}}>Mateusz</Link>
// v1.0
// because named routes are gone, link to full paths, you no longer need
// to know the names of the parameters, and string templates are quite
// nice. Note that `query` has not changed.
<Link to={`/users/${user.id}`}>Mateusz</Link>
```
#### "active" class
In 0.13.x links added the "active" class by default which you could
override with `activeClassName`, or provide `activeStyles`. Most links
don't need this and the check is (currently) expensive.
Links no longer add the "active" class by default, you opt-in by
providing one; if no `activeClassName` or `activeStyles` are provided,
the link will not check if its active.
```js
// v0.13.x
<Link to="about">About</Link>
// v1.0
<Link to="/about" activeClassName="active">About</Link>
```
#### Linking to Default/Index routes
Because named routes are gone, a link to `/` with an index route at `/`
will always be active. So we've introduced `IndexLink` that is only
active when the index route is active.
```js
// v0.13.x
// with this route config
<Route path="/" handler={App}>
<DefaultRoute name="home" handler={Home}/>
<Route name="about" handler={About}/>
</Route>
// will be active only when home is active, not when about is active
<Link to="home">Home</Link>
// v1.0
<Route path="/" component={App}>
<IndexRoute handler={Home}/>
<Route path="about" handler={About}/>
</Route>
// will be active only when home is active, not when about is active
<IndexLink to="/">Home</Link>
```
### Navigation Mixin
If you were using the navigation, instead use the `History` mixin.
```js
// v0.13.x
var Assignment = React.createClass({
mixins: [ Navigation ],
navigateAfterSomethingHappened () {
this.transitionTo('/users', { userId: user.id }, query);
// this.replaceWith('/users', { userId: user.id }, query);
}
})
// v1.0
var Assignment = React.createClass({
mixins: [ History ],
navigateAfterSomethingHappened () {
// the router is not built on rackt/history, and it is a first class
// API in the router for navigating
this.history.pushState(null, `/users/${user.id}`, query);
// this.history.replaceState(null, `/users/${user.id}`, query);
}
})
```
The following `Navigation` methods are now also found on the history
object, main difference again is there are no params or route names,
just pathnames.
| v0.13 | v1.0 |
|--------------------------------------|-------------------------------|
| `go(n)` | `go(n)` |
| `goBack()` | `goBack()` |
| `goForward()` | `goForward()` |
| `makeHref(routeName, params, query)` | `createHref(pathname, query)` |
| `makePath(routeName, params, query)` | `createPath(pathname, query)` |
### State mixin
```js
// v0.13.x
var Assignment = React.createClass({
mixins: [ State ],
foo () {
this.getPath()
this.getParams()
// etc...
}
})
// v1.0
// if you are a route component...
<Route component={Assignment/>
var Assignment = React.createClass({
foo () {
this.props.location // contains path information
this.props.params // contains params
this.props.history.isActive
}
})
// if you're not a route component, you need to pass location down the
// tree or get the location from context, we will probably provide a
// higher order component that will do this for you but haven't yet
var Assignment = React.createClass({
contextTypes: {
location: React.PropTypes.object
},
foo () {
this.context.location
}
})
```
Here's a table of where you used to get stuff with the `State` mixin,
and where you get it now if you're a route component (`this.props`)
| v0.13 (this) | v1.0 (this.props) |
|-----------------|------------------------------------|
| `getPath()` | `location.pathname+location.query` |
| `getPathname()` | `location.pathname` |
| `getParams()` | `params` |
| `getQuery()` | `query` |
| `getRoutes()` | `routes` |
### We'll keep updating this
There's a lot of the old API we've missed, please give the [new
docs](/docs) a read and help us fill this guide in. Thansk!
0.13.2 -> 0.13.3

@@ -10,0 +240,0 @@ ----------------

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc