From d89fabadf4f7c556fecefa01d8c6a6b63be136a0 Mon Sep 17 00:00:00 2001 From: Nathan Brown Date: Thu, 25 Feb 2016 16:08:20 -0700 Subject: [PATCH 1/4] Update history to v2.0.0 and add tests. --- react-router/history-tests.ts | 132 ++++++++++++++++++++++++++++++++++ react-router/history.d.ts | 71 ++++++++++++++---- 2 files changed, 188 insertions(+), 15 deletions(-) create mode 100644 react-router/history-tests.ts diff --git a/react-router/history-tests.ts b/react-router/history-tests.ts new file mode 100644 index 000000000..92b3794e1 --- /dev/null +++ b/react-router/history-tests.ts @@ -0,0 +1,132 @@ +/// + +import { createHistory, createLocation, useBeforeUnload, useQueries, useBasename } from 'history' +import { getUserConfirmation } from 'history/lib/DOMUtils' + +interface Promise { + then(onfulfilled?: (value: T) => TResult): Promise; +} + +let doSomethingAsync: () => Promise; +let input = { value: "" }; + +{ + let history = createHistory() + + // Listen for changes to the current location. The + // listener is called once immediately. + let unlisten = history.listen(function(location) { + console.log(location.pathname) + }) + + // When you're finished, stop the listener. + unlisten() + + // Push a new entry onto the history stack. + history.push('/home') + + // Replace the current entry on the history stack. + history.replace('/profile') + + // Push a new entry with state onto the history stack. + history.push({ + pathname: '/about', + search: '?the=search', + state: { some: 'state' } + }); + + // Change just the search on an existing location. + //history.push({ ...location, search: '?the=other+search' }) + + // Go back to the previous history entry. The following + // two lines are synonymous. + history.go(-1) + history.goBack() + + let href = history.createHref('/the/path') +} + +{ + let history = createHistory() + + // Pushing a path string. + history.push('/the/path') + + // Omitting location state when pushing a location descriptor. + history.push({ pathname: '/the/path', search: '?the=search' }) + + // Extending an existing location object. + //history.push({ ...location, search: '?other=search' }) + + let location = createLocation('/a/path?a=query', { the: 'state' }) + + location = history.createLocation('/a/path?a=query', { the: 'state' }) +} + +{ + let history = createHistory() + history.listenBefore(function(location) { + if (input.value !== '') + return 'Are you sure you want to leave this page?' + }) + + history.listenBefore(function(location, callback) { + doSomethingAsync().then(callback) + }) +} + +{ + let history = createHistory({ + getUserConfirmation(message, callback) { + callback(window.confirm(message)) // The default behavior + } + }) +} + +{ + let history = useBeforeUnload(createHistory)() + + history.listenBeforeUnload(function() { + return 'Are you sure you want to leave this page?' + }) +} + +{ + let history = useQueries(createHistory)() + + history.listen(function(location) { + console.log(location.query) + }) +} + +{ + let history = useQueries(createHistory)({ + parseQueryString: function(queryString) { + // TODO: return a parsed version of queryString + return {}; + }, + stringifyQuery: function(query) { + // TODO: return a query string created from query + return ""; + } + }) + + history.createPath({ pathname: '/the/path', query: { the: 'query' } }) + history.push({ pathname: '/the/path', query: { the: 'query' } }) +} + +{ + // Run our app under the /base URL. + let history = useBasename(createHistory)({ + basename: '/base' + }) + + // At the /base/hello/world URL: + history.listen(function(location) { + console.log(location.pathname) // /hello/world + console.log(location.basename) // /base + }) + + history.createPath('/the/path') // /base/the/path + history.push('/the/path') // push /base/the/path +} \ No newline at end of file diff --git a/react-router/history.d.ts b/react-router/history.d.ts index 1b5c6dfad..e22dbb757 100644 --- a/react-router/history.d.ts +++ b/react-router/history.d.ts @@ -1,6 +1,6 @@ -// Type definitions for history v1.13.1 +// Type definitions for history v2.0.0 // Project: https://github.com/rackt/history -// Definitions by: Sergey Buturlakin +// Definitions by: Sergey Buturlakin , Nathan Brown // Definitions: https://github.com/borisyankov/DefinitelyTyped @@ -17,21 +17,25 @@ declare namespace HistoryModule { type CreateHistoryEnhancer = (createHistory: CreateHistory) => CreateHistory interface History { - listenBefore(hook: TransitionHook): Function - listen(listener: LocationListener): Function + listenBefore(hook: TransitionHook): () => void + listen(listener: LocationListener): () => void transitionTo(location: Location): void - pushState(state: LocationState, path: Path): void - replaceState(state: LocationState, path: Path): void - push(path: Path): void - replace(path: Path): void + push(path: LocationDescriptor): void + replace(path: LocationDescriptor): void go(n: number): void goBack(): void goForward(): void createKey(): LocationKey - createPath(path: Path): Path - createHref(path: Path): Href - createLocation(path?: Path, state?: LocationState, action?: Action, key?: LocationKey): Location + createPath(path: LocationDescriptor): Path + createHref(path: LocationDescriptor): Href + createLocation(path?: LocationDescriptor, action?: Action, key?: LocationKey): Location + /** @deprecated use a location descriptor instead */ + createLocation(path?: Path, state?: LocationState, action?: Action, key?: LocationKey): Location + /** @deprecated use location.key to save state instead */ + pushState(state: LocationState, path: Path): void + /** @deprecated use location.key to save state instead */ + replaceState(state: LocationState, path: Path): void /** @deprecated use location.key to save state instead */ setState(state: LocationState): void /** @deprecated use listenBefore instead */ @@ -40,19 +44,42 @@ declare namespace HistoryModule { unregisterTransitionHook(hook: TransitionHook): void } - type HistoryOptions = Object + type HistoryOptions = { + getCurrentLocation?: () => Location + finishTransition?: (nextLocation: Location) => boolean + saveState?: (key: LocationKey, state: LocationState) => void + go?: (n: number) => void + getUserConfirmation?: (message: string, callback: (result: boolean) => void) => void + keyLength?: number + queryKey?: string | boolean + stringifyQuery?: (obj: any) => string + parseQueryString?: (str: string) => any + basename?: string + entries?: string | [any] + current?: number + } type Href = string type Location = { pathname: Pathname - search: QueryString + search: Search query: Query state: LocationState action: Action key: LocationKey + basename?: string } + type LocationDescriptorObject = { + pathname?: Pathname + search?: Search + query?: Query + state?: LocationState + } + + type LocationDescriptor = LocationDescriptorObject | Path + type LocationKey = string type LocationListener = (location: Location) => void @@ -67,11 +94,13 @@ declare namespace HistoryModule { type QueryString = string - type TransitionHook = (location: Location, callback: Function) => any + type Search = string + + type TransitionHook = (location: Location, callback: (result: any) => void) => any interface HistoryBeforeUnload { - listenBeforeUnload(hook: BeforeUnloadHook): Function + listenBeforeUnload(hook: BeforeUnloadHook): () => void } interface HistoryQueries { @@ -168,6 +197,18 @@ declare module "history/lib/actions" { } +declare module "history/lib/DOMUtils" { + export function addEventListener(node: EventTarget, event: string, listener: EventListenerOrEventListenerObject): void; + export function removeEventListener(node: EventTarget, event: string, listener: EventListenerOrEventListenerObject): void; + export function getHashPath(): string; + export function replaceHashPath(path: string): void; + export function getWindowPath(): string; + export function go(n: number): void; + export function getUserConfirmation(message: string, callback: (result: boolean) => void): void; + export function supportsHistory(): boolean; + export function supportsGoWithoutReloadUsingHash(): boolean; +} + declare module "history" { From 156aee9c2e092b6e06609a05a900d57aa8da4a55 Mon Sep 17 00:00:00 2001 From: Nathan Brown Date: Thu, 25 Feb 2016 16:10:52 -0700 Subject: [PATCH 2/4] react-router has a new context type in v2.0.0, so added that. Updated tests. --- react-router/react-router-tests.tsx | 14 ++++++++++++++ react-router/react-router.d.ts | 8 ++++++-- react/react.d.ts | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/react-router/react-router-tests.tsx b/react-router/react-router-tests.tsx index ab32451a0..a079d49fb 100644 --- a/react-router/react-router-tests.tsx +++ b/react-router/react-router-tests.tsx @@ -12,6 +12,16 @@ import { browserHistory, hashHistory, Router, Route, IndexRoute, Link } from "re class Master extends React.Component, {}> { + navigate() { + var router = this.context["router"] as ReactRouter.RouterOnContext; + router.push("/users"); + router.push({ + pathname: "/users/12", + query: { modal: true }, + state: { fromDashboard: true } + }); + } + render() { return

Master

@@ -22,6 +32,10 @@ class Master extends React.Component, {}> { } +(Master as React.ComponentClass<{}>).contextTypes = { + router: React.PropTypes.object, +}; + class Dashboard extends React.Component<{}, {}> { diff --git a/react-router/react-router.d.ts b/react-router/react-router.d.ts index abed5eb65..76fd7209d 100644 --- a/react-router/react-router.d.ts +++ b/react-router/react-router.d.ts @@ -1,6 +1,6 @@ -// Type definitions for react-router v2.0.0-rc5 +// Type definitions for react-router v2.0.0 // Project: https://github.com/rackt/react-router -// Definitions by: Sergey Buturlakin , Yuichi Murata , Václav Ostrožlík +// Definitions by: Sergey Buturlakin , Yuichi Murata , Václav Ostrožlík , Nathan Brown // Definitions: https://github.com/borisyankov/DefinitelyTyped @@ -195,6 +195,10 @@ declare namespace ReactRouter { interface IndexRedirectElement extends React.ReactElement {} const IndexRedirect: IndexRedirect + interface RouterOnContext extends H.History { + setRouteLeaveHook(route: PlainRoute, hook?: RouteHook): () => void; + isActive(pathOrLoc: H.LocationDescriptor, indexOnly?: boolean): boolean; + } /* mixins */ diff --git a/react/react.d.ts b/react/react.d.ts index 5753731b1..f60fba4b1 100644 --- a/react/react.d.ts +++ b/react/react.d.ts @@ -124,7 +124,7 @@ declare namespace __React { render(): JSX.Element; props: P; state: S; - context: {}; + context: { [key: string]: any }; refs: { [key: string]: ReactInstance }; From 647734d25203feb6f4bd94cf7919e887c347d6b2 Mon Sep 17 00:00:00 2001 From: Nathan Brown Date: Fri, 26 Feb 2016 11:44:03 -0700 Subject: [PATCH 3/4] Undo changes to react.d.ts. Update test to use static contextTypes and retype context. --- react-router/react-router-tests.tsx | 15 ++++++++++----- react/react.d.ts | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/react-router/react-router-tests.tsx b/react-router/react-router-tests.tsx index a079d49fb..703ce4a9f 100644 --- a/react-router/react-router-tests.tsx +++ b/react-router/react-router-tests.tsx @@ -10,10 +10,19 @@ import * as ReactDOM from "react-dom" import { browserHistory, hashHistory, Router, Route, IndexRoute, Link } from "react-router" +interface MasterContext { + router: ReactRouter.RouterOnContext; +} + class Master extends React.Component, {}> { + static contextTypes: React.ValidationMap = { + router: React.PropTypes.object + }; + context: MasterContext; + navigate() { - var router = this.context["router"] as ReactRouter.RouterOnContext; + var router = this.context.router; router.push("/users"); router.push({ pathname: "/users/12", @@ -32,10 +41,6 @@ class Master extends React.Component, {}> { } -(Master as React.ComponentClass<{}>).contextTypes = { - router: React.PropTypes.object, -}; - class Dashboard extends React.Component<{}, {}> { diff --git a/react/react.d.ts b/react/react.d.ts index f60fba4b1..5753731b1 100644 --- a/react/react.d.ts +++ b/react/react.d.ts @@ -124,7 +124,7 @@ declare namespace __React { render(): JSX.Element; props: P; state: S; - context: { [key: string]: any }; + context: {}; refs: { [key: string]: ReactInstance }; From b3a2b981341b7ff0b1cec5047bebe13ceed944da Mon Sep 17 00:00:00 2001 From: Nathan Brown Date: Sun, 28 Feb 2016 12:24:19 -0700 Subject: [PATCH 4/4] Export RouterOnContext from "react-router" module. --- react-router/react-router.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/react-router/react-router.d.ts b/react-router/react-router.d.ts index 76fd7209d..846c186d8 100644 --- a/react-router/react-router.d.ts +++ b/react-router/react-router.d.ts @@ -451,6 +451,7 @@ declare module "react-router" { export type RouterListener = ReactRouter.RouterListener export type RouterState = ReactRouter.RouterState export type HistoryBase = ReactRouter.HistoryBase + export type RouterOnContext = ReactRouter.RouterOnContext export { Router,