Merge pull request #15170 from tkrotoff/react-router-v4

Update React Router to version 4.0
This commit is contained in:
Paul van Brenk
2017-03-21 15:26:31 -07:00
committed by GitHub
42 changed files with 1293 additions and 91 deletions
+3 -1
View File
@@ -15,7 +15,9 @@
],
"paths": {
"history": ["history/v3"],
"history/*": ["history/v3/*"]
"history/*": ["history/v3/*"],
"react-router": ["react-router/v3"],
"react-router/*": ["react-router/v3/*"]
},
"types": [],
"noEmit": true,
+81
View File
@@ -0,0 +1,81 @@
// Type definitions for React Router 4.0
// Project: https://github.com/ReactTraining/react-router
// Definitions by: Tanguy Krotoff <https://github.com/tkrotoff>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.2
declare module 'react-router-dom' {
import {
Prompt,
MemoryRouter,
Redirect,
RouteComponentProps,
PartialRouteComponentProps,
RouteProps,
Route,
Router,
StaticRouter,
Switch,
match,
matchPath,
withRouter
} from 'react-router';
import * as React from 'react';
import * as H from 'history';
interface BrowserRouterProps {
basename?: string;
getUserConfirmation?: () => void;
forceRefresh?: boolean;
keyLength?: number;
}
class BrowserRouter extends React.Component<BrowserRouterProps, void> {}
interface HashRouterProps {
basename?: string;
getUserConfirmation?: () => void;
hashType?: 'slash' | 'noslash' | 'hashbang';
}
class HashRouter extends React.Component<HashRouterProps, void> {}
interface LinkProps extends React.HTMLAttributes<HTMLAnchorElement> {
to: H.LocationDescriptor;
replace?: boolean;
}
class Link extends React.Component<LinkProps, void> {}
interface NavLinkProps extends LinkProps {
activeClassName?: string;
activeStyle?: React.CSSProperties;
exact?: boolean;
strict?: boolean;
isActive?: (location: H.Location, props: any) => boolean;
}
class NavLink extends React.Component<NavLinkProps, void> {}
export {
BrowserRouter,
HashRouter,
LinkProps, // TypeScript specific, not from React Router itself
Link,
NavLink,
Prompt,
MemoryRouter,
Redirect,
RouteComponentProps, // TypeScript specific, not from React Router itself
PartialRouteComponentProps, // TypeScript specific, not from React Router itself
RouteProps, // TypeScript specific, not from React Router itself
Route,
Router,
StaticRouter,
Switch,
match, // TypeScript specific, not from React Router itself
matchPath,
withRouter
}
}
+18
View File
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"baseUrl": "../",
"typeRoots": ["../"],
"types": [],
"module": "commonjs",
"lib": ["es6", "dom"],
"jsx": "react",
"strictNullChecks": true,
"noImplicitAny": true,
"noImplicitThis": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true
},
"files": [
"index.d.ts"
]
}
+6
View File
@@ -0,0 +1,6 @@
{
"extends": "../tslint.json",
"rules": {
"no-single-declare-module": false
}
}
+99 -47
View File
@@ -1,5 +1,5 @@
// Type definitions for react-router 3.0
// Project: https://github.com/rackt/react-router
// Type definitions for React Router 4.0
// Project: https://github.com/ReactTraining/react-router
// Definitions by: Sergey Buturlakin <https://github.com/sergey-buturlakin>
// Yuichi Murata <https://github.com/mrk21>
// Václav Ostrožlík <https://github.com/vasek17>
@@ -9,54 +9,106 @@
// John Reilly <https://github.com/johnnyreilly>
// Karol Janyst <https://github.com/LKay>
// Dovydas Navickas <https://github.com/DovydasNavickas>
// Tanguy Krotoff <https://github.com/tkrotoff>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.1
// TypeScript Version: 2.2
export {
ChangeHook,
EnterHook,
InjectedRouter,
LeaveHook,
ParseQueryString,
RouteComponent,
RouteComponents,
RouteComponentProps,
RouteConfig,
RoutePattern,
RouterProps,
RouterState,
RedirectFunction,
StringifyQuery
} from "react-router/lib/Router";
export { LinkProps } from "react-router/lib/Link";
export { IndexLinkProps } from "react-router/lib/IndexLink";
export { RouteProps, PlainRoute } from "react-router/lib/Route";
export { IndexRouteProps } from "react-router/lib/IndexRoute";
export { RedirectProps } from "react-router/lib/Redirect";
export { IndexRedirectProps } from "react-router/lib/IndexRedirect";
declare module 'react-router' {
import * as React from 'react';
import * as H from 'history';
/* components */
export { default as Router } from "react-router/lib/Router";
export { default as Link } from "react-router/lib/Link";
export { default as IndexLink } from "react-router/lib/IndexLink";
export { default as withRouter } from "react-router/lib/withRouter";
/* components (configuration) */
export { default as IndexRedirect } from "react-router/lib/IndexRedirect";
export { default as IndexRoute } from "react-router/lib/IndexRoute";
export { default as Redirect } from "react-router/lib/Redirect";
export { default as Route } from "react-router/lib/Route";
interface MemoryRouterProps {
initialEntries?: H.Location[];
initialIndex?: number;
getUserConfirmation?: () => void;
keyLength?: number;
}
class MemoryRouter extends React.Component<MemoryRouterProps, void> {}
/* utils */
export { createRoutes } from "react-router/lib/RouteUtils";
export { default as RouterContext } from "react-router/lib/RouterContext";
export { routerShape, locationShape } from "react-router/lib/PropTypes";
export { default as match } from "react-router/lib/match";
export { default as useRouterHistory } from "react-router/lib/useRouterHistory";
export { formatPattern } from "react-router/lib/PatternUtils";
export { default as applyRouterMiddleware } from "react-router/lib/applyRouterMiddleware";
/* histories */
export { default as browserHistory } from "react-router/lib/browserHistory";
export { default as hashHistory } from "react-router/lib/hashHistory";
export { default as createMemoryHistory } from "react-router/lib/createMemoryHistory";
interface PromptProps {
message: string | ((location: H.Location) => void);
when?: boolean;
}
class Prompt extends React.Component<PromptProps, void> {}
interface RedirectProps {
to: H.LocationDescriptor;
push?: boolean;
from?: string;
}
class Redirect extends React.Component<RedirectProps, void> {}
interface RouteComponentProps<P> {
match: match<P>;
location: H.Location;
history: H.History;
}
interface PartialRouteComponentProps<P> extends Partial<RouteComponentProps<P>> {
}
interface RouteProps {
location?: H.Location;
component?: React.SFC<PartialRouteComponentProps<any> | void> | React.ComponentClass<PartialRouteComponentProps<any> | void>;
render?: (props: RouteComponentProps<any>) => React.ReactNode;
children?: (props: RouteComponentProps<any>) => React.ReactNode | React.ReactNode;
path?: string;
exact?: boolean;
strict?: boolean;
}
class Route extends React.Component<RouteProps, void> {}
interface RouterProps {
history: any;
}
class Router extends React.Component<RouterProps, void> {}
interface StaticRouterProps extends RouterProps {
basename?: string;
location?: string | object;
context?: object;
}
class StaticRouter extends React.Component<StaticRouterProps, void> {}
interface SwitchProps extends RouteProps {
}
class Switch extends React.Component<SwitchProps, void> {}
interface match<P> {
params: P;
isExact?: boolean;
path?: string;
url?: string;
}
function matchPath<P>(pathname: string, props: RouteProps): match<P>;
function withRouter(component: React.SFC<RouteComponentProps<any>> | React.ComponentClass<RouteComponentProps<any>>): React.ComponentClass<any>;
export {
MemoryRouter,
Prompt,
Redirect,
RouteComponentProps, // TypeScript specific, not from React Router itself
PartialRouteComponentProps, // TypeScript specific, not from React Router itself
RouteProps, // TypeScript specific, not from React Router itself
Route,
Router,
StaticRouter,
Switch,
match, // TypeScript specific, not from React Router itself
matchPath,
withRouter
}
}
+50
View File
@@ -0,0 +1,50 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteComponentProps,
Route,
Link,
Switch
} from 'react-router-dom'
const AmbiguousExample = () => (
<Router>
<div>
<ul>
<li><Link to="/about">About Us (static)</Link></li>
<li><Link to="/company">Company (static)</Link></li>
<li><Link to="/kim">Kim (dynamic)</Link></li>
<li><Link to="/chris">Chris (dynamic)</Link></li>
</ul>
{/*
Sometimes you want to have a whitelist of static paths
like "/about" and "/company" but also allow for dynamic
patterns like "/:user". The problem is that "/about"
is ambiguous and will match both "/about" and "/:user".
Most routers have an algorithm to decide for you what
it will match since they only allow you to match one
"route". React Router lets you match in multiple places
on purpose (sidebars, breadcrumbs, etc). So, when you
want to clear up any ambiguous matching, and not match
"/about" to "/:user", just wrap your <Route>s in a
<Switch>. It will render the first one that matches.
*/}
<Switch>
<Route path="/about" component={About}/>
<Route path="/company" component={Company}/>
<Route path="/:user" component={User}/>
</Switch>
</div>
</Router>
)
const About = () => <h2>About</h2>
const Company = () => <h2>Company</h2>
const User: React.SFC<RouteComponentProps<{user: string}>> = ({ match }) => (
<div>
<h2>User: {match.params.user}</h2>
</div>
)
export default AmbiguousExample
+123
View File
@@ -0,0 +1,123 @@
import * as React from 'react'
import * as ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import {
BrowserRouter as Router,
RouteComponentProps,
Route,
LinkProps,
Link,
Redirect
} from 'react-router-dom'
/* you'll need this CSS somewhere
.fade-enter {
opacity: 0;
z-index: 1;
}
.fade-enter.fade-enter-active {
opacity: 1;
transition: opacity 250ms ease-in;
}
*/
const AnimationExample = () => (
<Router>
<Route render={({ location }) => (
<div style={styles.fill}>
<Route exact path="/" render={() => (
<Redirect to="/10/90/50"/>
)}/>
<ul style={styles.nav}>
<NavLink to="/10/90/50">Red</NavLink>
<NavLink to="/120/100/40">Green</NavLink>
<NavLink to="/200/100/40">Blue</NavLink>
<NavLink to="/310/100/50">Pink</NavLink>
</ul>
<div style={styles.content}>
<ReactCSSTransitionGroup
transitionName="fade"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}
>
{/* no different than other usage of
ReactCSSTransitionGroup, just make
sure to pass `location` to `Route`
so it can match the old location
as it animates out
*/}
<Route
location={location}
key={location.key}
path="/:h/:s/:l"
component={HSL}
/>
</ReactCSSTransitionGroup>
</div>
</div>
)}/>
</Router>
)
const NavLink: React.SFC<LinkProps> = (props) => (
<li style={styles.navItem}>
<Link {...props} style={{ color: 'inherit' }}/>
</li>
)
interface HSLParams {
h: number;
s: number;
l: number;
}
const HSL: React.SFC<RouteComponentProps<HSLParams>> = ({ match: { params } }) => (
<div style={{
...styles.fill,
...styles.hsl,
background: `hsl(${params.h}, ${params.s}%, ${params.l}%)`
}}>hsl({params.h}, {params.s}%, {params.l}%)</div>
)
const styles: any = {}
styles.fill = {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0
}
styles.content = {
...styles.fill,
top: '40px',
textAlign: 'center'
}
styles.nav = {
padding: 0,
margin: 0,
position: 'absolute',
top: 0,
height: '40px',
width: '100%',
display: 'flex'
}
styles.navItem = {
textAlign: 'center',
flex: 1,
listStyleType: 'none',
padding: '10px'
}
styles.hsl = {
...styles.fill,
color: 'white',
paddingTop: '20px',
fontSize: '30px'
}
export default AnimationExample
+101
View File
@@ -0,0 +1,101 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteComponentProps,
RouteProps,
Route,
Link,
Redirect,
withRouter
} from 'react-router-dom'
////////////////////////////////////////////////////////////
// 1. Click the public page
// 2. Click the protected page
// 3. Log in
// 4. Click the back button, note the URL each time
const AuthExample = () => (
<Router>
<div>
<AuthButton/>
<ul>
<li><Link to="/public">Public Page</Link></li>
<li><Link to="/protected">Protected Page</Link></li>
</ul>
<Route path="/public" component={Public}/>
<Route path="/login" component={Login}/>
<PrivateRoute path="/protected" component={Protected}/>
</div>
</Router>
)
const fakeAuth = {
isAuthenticated: false,
authenticate(this: any, cb: () => void) {
this.isAuthenticated = true
setTimeout(cb, 100) // fake async
},
signout(this: any, cb: () => void) {
this.isAuthenticated = false
setTimeout(cb, 100)
}
}
const AuthButton = withRouter(({ history }) => (
fakeAuth.isAuthenticated ? (
<p>
Welcome! <button onClick={() => {
fakeAuth.signout(() => history.push('/'))
}}>Sign out</button>
</p>
) : (
<p>You are not logged in.</p>
)
))
const PrivateRoute: React.SFC<RouteProps> = ({ component, ...rest }) => (
<Route {...rest} render={props => (
fakeAuth.isAuthenticated ? React.createElement(component! as React.SFC<any>, props) : (
<Redirect to={{
pathname: '/login',
state: { from: props.location }
}}/>
)
)}/>
)
const Public: React.SFC<RouteComponentProps<void>> = () => <h3>Public</h3>
const Protected: React.SFC<RouteComponentProps<void>> = () => <h3>Protected</h3>
class Login extends React.Component<RouteComponentProps<void>, {redirectToReferrer: boolean}> {
state = {
redirectToReferrer: false
}
login = () => {
fakeAuth.authenticate(() => {
this.setState({ redirectToReferrer: true })
})
}
render() {
const { from } = this.props.location.state || { from: { pathname: '/' } }
const { redirectToReferrer } = this.state
if (redirectToReferrer) {
return (
<Redirect to={from}/>
)
}
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={this.login}>Log in</button>
</div>
)
}
}
export default AuthExample
+73
View File
@@ -0,0 +1,73 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteComponentProps,
Route,
Link
} from 'react-router-dom'
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
)
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
const About = () => (
<div>
<h2>About</h2>
</div>
)
const Topics: React.SFC<RouteComponentProps<void>> = ({ match }) => (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/rendering`}>
Rendering with React
</Link>
</li>
<li>
<Link to={`${match.url}/components`}>
Components
</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<Route path={`${match.url}/:topicId`} component={Topic}/>
<Route exact path={match.url} render={() => (
<h3>Please select a topic.</h3>
)}/>
</div>
)
const Topic: React.SFC<RouteComponentProps<{topicId: string}>> = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
)
export default BasicExample
+45
View File
@@ -0,0 +1,45 @@
import * as React from 'react'
import {
BrowserRouter as Router,
Route,
LinkProps,
Link
} from 'react-router-dom'
const CustomLinkExample = () => (
<Router>
<div>
<OldSchoolMenuLink activeOnlyWhenExact={true} to="/" label="Home"/>
<OldSchoolMenuLink to="/about" label="About"/>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</div>
</Router>
)
interface OldSchoolMenuLinkProps extends LinkProps {
activeOnlyWhenExact?: boolean;
}
const OldSchoolMenuLink: React.SFC<OldSchoolMenuLinkProps> = ({ label, to, activeOnlyWhenExact }) => (
<Route path={to as string} exact={activeOnlyWhenExact} children={({ match }) => (
<div className={match ? 'active' : ''}>
{match ? '> ' : ''}<Link to={to}>{label}</Link>
</div>
)}/>
)
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
const About = () => (
<div>
<h2>About</h2>
</div>
)
export default CustomLinkExample
+177
View File
@@ -0,0 +1,177 @@
import * as React from 'react'
import {
BrowserRouter as Router,
Switch,
RouteComponentProps,
Route,
Link
} from 'react-router-dom'
// This example shows how to render two different screens
// (or the same screen in a different context) at the same url,
// depending on you got there.
//
// Click the colors and see them full screen, then "visit the
// gallery" and click on the colors. Note the URL and the component
// are the same as before but now we see them inside a modal
// on top of the old screen.
class ModalSwitch extends React.Component<RouteComponentProps<void>, void> {
// We can pass a location to <Switch/> that will tell it to
// ignore the router's current location and use the location
// prop instead.
//
// We can also use "location state" to tell the app the user
// wants to go to `/images/2` in a modal, rather than as the
// main page, keeping the gallery visible behind it.
//
// Normally, `/images/2` wouldn't match the gallery at `/`.
// So, to get both screens to render, we can save the old
// location and pass it to Switch, so it will think the location
// is still `/` even though its `/images/2`.
previousLocation = this.props.location
componentWillUpdate(nextProps: RouteComponentProps<void>) {
const { location } = this.props
// set previousLocation if props.location is not modal
if (
nextProps.history.action !== 'POP' &&
(!location.state || !location.state.modal)
) {
this.previousLocation = this.props.location
}
}
render() {
const { location } = this.props
const isModal = !!(
location.state &&
location.state.modal &&
this.previousLocation !== location // not initial render
)
return (
<div>
<Switch location={isModal ? this.previousLocation : location}>
<Route exact path='/' component={Home}/>
<Route path='/gallery' component={Gallery}/>
<Route path='/img/:id' component={ImageView}/>
</Switch>
{isModal ? <Route path='/img/:id' component={Modal} /> : null}
</div>
)
}
}
const IMAGES = [
{ id: 0, title: 'Dark Orchid', color: 'DarkOrchid' },
{ id: 1, title: 'Lime Green', color: 'LimeGreen' },
{ id: 2, title: 'Tomato', color: 'Tomato' },
{ id: 3, title: 'Seven Ate Nine', color: '#789' },
{ id: 4, title: 'Crimson', color: 'Crimson' }
]
const Thumbnail: React.SFC<{color: string}> = ({ color }) =>
<div style={{
width: 50,
height: 50,
background: color
}}/>
const Image: React.SFC<{color: string}> = ({ color }) =>
<div style={{
width: '100%',
height: 400,
background: color
}}></div>
const Home = () => (
<div>
<Link to='/gallery'>Visit the Gallery</Link>
<h2>Featured Images</h2>
<ul>
<li><Link to='/img/2'>Tomato</Link></li>
<li><Link to='/img/4'>Crimson</Link></li>
</ul>
</div>
)
const Gallery = () => (
<div>
{IMAGES.map(i => (
<Link
key={i.id}
to={{
pathname: `/img/${i.id}`,
// this is the trick!
state: { modal: true }
}}
>
<Thumbnail color={i.color} />
<p>{i.title}</p>
</Link>
))}
</div>
)
const ImageView: React.SFC<RouteComponentProps<{id: string}>> = ({ match }) => {
const image = IMAGES[parseInt(match.params.id, 10)]
if (!image) {
return <div>Image not found</div>
}
return (
<div>
<h1>{image.title}</h1>
<Image color={image.color} />
</div>
)
}
const Modal: React.SFC<RouteComponentProps<{id: string}>> = ({ match, history }) => {
const image = IMAGES[parseInt(match.params.id, 10)]
if (!image) {
return null!
}
const back = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation()
history.goBack()
}
return (
<div
onClick={back}
style={{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
background: 'rgba(0, 0, 0, 0.15)'
}}
>
<div className='modal' style={{
position: 'absolute',
background: '#fff',
top: 25,
left: '10%',
right: '10%',
padding: 15,
border: '2px solid #444'
}}>
<h1>{image.title}</h1>
<Image color={image.color} />
<button type='button' onClick={back}>
Close
</button>
</div>
</div>
)
}
const ModalGallery = () => (
<Router>
<Route component={ModalSwitch} />
</Router>
)
export default ModalGallery
+48
View File
@@ -0,0 +1,48 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteComponentProps,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom'
const NoMatchExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/old-match">Old Match, to be redirected</Link></li>
<li><Link to="/will-match">Will Match</Link></li>
<li><Link to="/will-not-match">Will Not Match</Link></li>
<li><Link to="/also/will/not/match">Also Will Not Match</Link></li>
</ul>
<Switch>
<Route path="/" exact component={Home}/>
<Redirect from="/old-match" to="/will-match"/>
<Route path="/will-match" component={WillMatch}/>
<Route component={NoMatch}/>
</Switch>
</div>
</Router>
)
const Home = () => (
<p>
A <code>&lt;Switch></code> renders the
first child <code>&lt;Route></code> that
matches. A <code>&lt;Route></code> with
no <code>path</code> always matches.
</p>
)
const WillMatch = () => <h3>Matched!</h3>
const NoMatch: React.SFC<RouteComponentProps<void>> = ({ location }) => (
<div>
<h3>No match for <code>{location.pathname}</code></h3>
</div>
)
export default NoMatchExample
+31
View File
@@ -0,0 +1,31 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteComponentProps,
Route,
Link
} from 'react-router-dom'
const ParamsExample = () => (
<Router>
<div>
<h2>Accounts</h2>
<ul>
<li><Link to="/netflix">Netflix</Link></li>
<li><Link to="/zillow-group">Zillow Group</Link></li>
<li><Link to="/yahoo">Yahoo</Link></li>
<li><Link to="/modus-create">Modus Create</Link></li>
</ul>
<Route path="/:id" component={Child}/>
</div>
</Router>
)
const Child: React.SFC<RouteComponentProps<{id: string}>> = ({ match }) => (
<div>
<h3>ID: {match.params.id}</h3>
</div>
)
export default ParamsExample
@@ -0,0 +1,74 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteComponentProps,
Route,
Link,
Prompt
} from 'react-router-dom'
const PreventingTransitionsExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Form</Link></li>
<li><Link to="/one">One</Link></li>
<li><Link to="/two">Two</Link></li>
</ul>
<Route path="/" exact component={Form}/>
<Route path="/one" render={() => <h3>One</h3>}/>
<Route path="/two" render={() => <h3>Two</h3>}/>
</div>
</Router>
)
class Form extends React.Component<void, {isBlocking: boolean}> {
state = {
isBlocking: false
}
render() {
const { isBlocking } = this.state
return (
<form
onSubmit={event => {
event.preventDefault();
(event.target as HTMLFormElement).reset();
this.setState({
isBlocking: false
})
}}
>
<Prompt
when={isBlocking}
message={location => (
`Are you sure you want to go to ${location.pathname}`
)}
/>
<p>
Blocking? {isBlocking ? 'Yes, click a link or the back button' : 'Nope'}
</p>
<p>
<input
size={50}
placeholder="type something to block transitions"
onChange={event => {
this.setState({
isBlocking: event.target.value.length > 0
})
}}
/>
</p>
<p>
<button>Submit to stop blocking</button>
</p>
</form>
)
}
}
export default PreventingTransitionsExample
+1
View File
@@ -0,0 +1 @@
Examples taken from https://github.com/ReactTraining/react-router/tree/22bd52c901ef0312348c2b02549c7102bd5653ae/packages/react-router-website/modules/examples
+50
View File
@@ -0,0 +1,50 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteComponentProps,
Route,
Link,
match
} from 'react-router-dom'
import * as H from 'history';
const PEEPS = [
{ id: 0, name: 'Michelle', friends: [ 1, 2, 3 ] },
{ id: 1, name: 'Sean', friends: [ 0, 3 ] },
{ id: 2, name: 'Kim', friends: [ 0, 1, 3 ], },
{ id: 3, name: 'David', friends: [ 1, 2 ] }
]
const find = (id: number) => PEEPS.find(p => p.id == id)
const RecursiveExample = () => (
<Router>
<Person match={{ params: { id: 0 }, url: '' }}/>
</Router>
)
interface PersonProps extends Partial<RouteComponentProps<{id: number}>> {
match: match<{id: number}>;
}
const Person: React.SFC<PersonProps> = ({ match }) => {
const person = find(match.params.id)
return (
<div>
<h3>{person!.name}’s Friends</h3>
<ul>
{person!.friends.map(id => (
<li key={id}>
<Link to={`${match.url}/${id}`}>
{find(id)!.name}
</Link>
</li>
))}
</ul>
<Route path={`${match.url}/:id`} component={Person}/>
</div>
)
}
export default RecursiveExample
+88
View File
@@ -0,0 +1,88 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteComponentProps,
RouteProps,
Route,
Link
} from 'react-router-dom'
// Some folks find value in a centralized route config.
// A route config is just data. React is great at mapping
// data into components, and <Route> is a component.
////////////////////////////////////////////////////////////
// first our route components
const Main = () => <h2>Main</h2>
const Sandwiches = () => <h2>Sandwiches</h2>
interface PropsWithRoutes extends RouteComponentProps<void> {
routes: Array<MyRouteProps>;
}
const Tacos: React.SFC<PropsWithRoutes> = ({ routes }) => (
<div>
<h2>Tacos</h2>
<ul>
<li><Link to="/tacos/bus">Bus</Link></li>
<li><Link to="/tacos/cart">Cart</Link></li>
</ul>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route}/>
))}
</div>
)
const Bus = () => <h3>Bus</h3>
const Cart = () => <h3>Cart</h3>
////////////////////////////////////////////////////////////
// then our route config
interface MyRouteProps extends RouteProps {
component: React.SFC<PropsWithRoutes>;
routes?: MyRouteProps[];
}
const routes: Array<MyRouteProps> = [
{ path: '/sandwiches',
component: Sandwiches
},
{ path: '/tacos',
component: Tacos,
routes: [
{ path: '/tacos/bus',
component: Bus
},
{ path: '/tacos/cart',
component: Cart
}
]
}
]
// wrap <Route> and use this everywhere instead, then when
// sub routes are added to any route it'll work
const RouteWithSubRoutes = (route: MyRouteProps) => (
<Route path={route.path} render={props => (
// pass the sub-routes down to keep nesting
<route.component {...props} routes={route.routes!}/>
)}/>
)
const RouteConfigExample = () => (
<Router>
<div>
<ul>
<li><Link to="/tacos">Tacos</Link></li>
<li><Link to="/sandwiches">Sandwiches</Link></li>
</ul>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route}/>
))}
</div>
</Router>
)
export default RouteConfigExample
+80
View File
@@ -0,0 +1,80 @@
import * as React from 'react'
import {
BrowserRouter as Router,
RouteProps,
Route,
Link
} from 'react-router-dom'
// Each logical "route" has two components, one for
// the sidebar and one for the main area. We want to
// render both of them in different places when the
// path matches the current URL.
interface MyRoute extends RouteProps {
sidebar: () => JSX.Element;
main: () => JSX.Element;
}
const routes: Array<MyRoute> = [
{ path: '/',
exact: true,
sidebar: () => <div>home!</div>,
main: () => <h2>Home</h2>
},
{ path: '/bubblegum',
sidebar: () => <div>bubblegum!</div>,
main: () => <h2>Bubblegum</h2>
},
{ path: '/shoelaces',
sidebar: () => <div>shoelaces!</div>,
main: () => <h2>Shoelaces</h2>
}
]
const SidebarExample = () => (
<Router>
<div style={{ display: 'flex' }}>
<div style={{
padding: '10px',
width: '40%',
background: '#f0f0f0'
}}>
<ul style={{ listStyleType: 'none', padding: 0 }}>
<li><Link to="/">Home</Link></li>
<li><Link to="/bubblegum">Bubblegum</Link></li>
<li><Link to="/shoelaces">Shoelaces</Link></li>
</ul>
{routes.map((route, index) => (
// You can render a <Route> in as many places
// as you want in your app. It will render along
// with any other <Route>s that also match the URL.
// So, a sidebar or breadcrumbs or anything else
// that requires you to render multiple things
// in multiple places at the same URL is nothing
// more than multiple <Route>s.
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.sidebar}
/>
))}
</div>
<div style={{ flex: 1, padding: '10px' }}>
{routes.map((route, index) => (
// Render more <Route>s with the same paths as
// above, but different components this time.
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.main}
/>
))}
</div>
</div>
</Router>
)
export default SidebarExample
+28 -42
View File
@@ -1,44 +1,30 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": false,
"jsx": "react",
"baseUrl": "../",
"typeRoots": ["../"],
"paths": {
"history": ["history/v3"],
"history/*": ["history/v3/*"]
},
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"lib/applyRouterMiddleware.d.ts",
"lib/browserHistory.d.ts",
"lib/createMemoryHistory.d.ts",
"lib/hashHistory.d.ts",
"lib/IndexLink.d.ts",
"lib/IndexRedirect.d.ts",
"lib/IndexRoute.d.ts",
"lib/Link.d.ts",
"lib/match.d.ts",
"lib/PatternUtils.d.ts",
"lib/PropTypes.d.ts",
"lib/Redirect.d.ts",
"lib/Route.d.ts",
"lib/Router.d.ts",
"lib/RouterContext.d.ts",
"lib/RouteUtils.d.ts",
"lib/useRouterHistory.d.ts",
"lib/withRouter.d.ts",
"react-router-tests.tsx"
]
"compilerOptions": {
"baseUrl": "../",
"typeRoots": ["../"],
"types": [],
"module": "commonjs",
"lib": ["es6", "dom"],
"jsx": "react",
"strictNullChecks": true,
"noImplicitAny": true,
"noImplicitThis": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true
},
"files": [
"index.d.ts",
"test/Ambiguous.tsx",
"test/Animation.tsx",
"test/Auth.tsx",
"test/Basic.tsx",
"test/CustomLink.tsx",
"test/ModalGallery.tsx",
"test/NoMatch.tsx",
"test/Params.tsx",
"test/PreventingTransitions.tsx",
"test/Recursive.tsx",
"test/RouteConfig.tsx",
"test/Sidebar.tsx"
]
}
+8 -1
View File
@@ -1 +1,8 @@
{ "extends": "../tslint.json" }
{
"extends": "../tslint.json",
"rules": {
"no-empty-interface": false,
"void-return": false,
"no-single-declare-module": false
}
}
+62
View File
@@ -0,0 +1,62 @@
// Type definitions for react-router 3.0
// Project: https://github.com/rackt/react-router
// Definitions by: Sergey Buturlakin <https://github.com/sergey-buturlakin>
// Yuichi Murata <https://github.com/mrk21>
// Václav Ostrožlík <https://github.com/vasek17>
// Nathan Brown <https://github.com/ngbrown>
// Alex Wendland <https://github.com/awendland>
// Kostya Esmukov <https://github.com/KostyaEsmukov>
// John Reilly <https://github.com/johnnyreilly>
// Karol Janyst <https://github.com/LKay>
// Dovydas Navickas <https://github.com/DovydasNavickas>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.1
export {
ChangeHook,
EnterHook,
InjectedRouter,
LeaveHook,
ParseQueryString,
RouteComponent,
RouteComponents,
RouteComponentProps,
RouteConfig,
RoutePattern,
RouterProps,
RouterState,
RedirectFunction,
StringifyQuery
} from "react-router/lib/Router";
export { LinkProps } from "react-router/lib/Link";
export { IndexLinkProps } from "react-router/lib/IndexLink";
export { RouteProps, PlainRoute } from "react-router/lib/Route";
export { IndexRouteProps } from "react-router/lib/IndexRoute";
export { RedirectProps } from "react-router/lib/Redirect";
export { IndexRedirectProps } from "react-router/lib/IndexRedirect";
/* components */
export { default as Router } from "react-router/lib/Router";
export { default as Link } from "react-router/lib/Link";
export { default as IndexLink } from "react-router/lib/IndexLink";
export { default as withRouter } from "react-router/lib/withRouter";
/* components (configuration) */
export { default as IndexRedirect } from "react-router/lib/IndexRedirect";
export { default as IndexRoute } from "react-router/lib/IndexRoute";
export { default as Redirect } from "react-router/lib/Redirect";
export { default as Route } from "react-router/lib/Route";
/* utils */
export { createRoutes } from "react-router/lib/RouteUtils";
export { default as RouterContext } from "react-router/lib/RouterContext";
export { routerShape, locationShape } from "react-router/lib/PropTypes";
export { default as match } from "react-router/lib/match";
export { default as useRouterHistory } from "react-router/lib/useRouterHistory";
export { formatPattern } from "react-router/lib/PatternUtils";
export { default as applyRouterMiddleware } from "react-router/lib/applyRouterMiddleware";
/* histories */
export { default as browserHistory } from "react-router/lib/browserHistory";
export { default as hashHistory } from "react-router/lib/hashHistory";
export { default as createMemoryHistory } from "react-router/lib/createMemoryHistory";
+46
View File
@@ -0,0 +1,46 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": false,
"jsx": "react",
"baseUrl": "../../",
"typeRoots": ["../../"],
"paths": {
"history": ["history/v3"],
"history/*": ["history/v3/*"],
"react-router": ["react-router/v3"],
"react-router/*": ["react-router/v3/*"]
},
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"lib/applyRouterMiddleware.d.ts",
"lib/browserHistory.d.ts",
"lib/createMemoryHistory.d.ts",
"lib/hashHistory.d.ts",
"lib/IndexLink.d.ts",
"lib/IndexRedirect.d.ts",
"lib/IndexRoute.d.ts",
"lib/Link.d.ts",
"lib/match.d.ts",
"lib/PatternUtils.d.ts",
"lib/PropTypes.d.ts",
"lib/Redirect.d.ts",
"lib/Route.d.ts",
"lib/Router.d.ts",
"lib/RouterContext.d.ts",
"lib/RouteUtils.d.ts",
"lib/useRouterHistory.d.ts",
"lib/withRouter.d.ts",
"react-router-tests.tsx"
]
}
+1
View File
@@ -0,0 +1 @@
{ "extends": "../tslint.json" }