diff --git a/.size-snapshot.json b/.size-snapshot.json index a0f2fef90..44b07fbf1 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,8 +1,8 @@ { "esm/history.js": { - "bundled": 21157, - "minified": 7812, - "gzipped": 2248, + "bundled": 21197, + "minified": 7852, + "gzipped": 2251, "treeshaked": { "rollup": { "code": 43, @@ -14,12 +14,12 @@ } }, "umd/history.js": { - "bundled": 22878, + "bundled": 22918, "minified": 7173, "gzipped": 2201 }, "umd/history.min.js": { - "bundled": 20184, + "bundled": 20224, "minified": 5778, "gzipped": 1867 } diff --git a/docs/Blocking.md b/docs/Blocking.md index b3c1aabaa..d1db8c260 100644 --- a/docs/Blocking.md +++ b/docs/Blocking.md @@ -1,38 +1,31 @@ # Blocking Transitions -`history` lets you register a prompt message that will be shown to the user before location listeners are notified. This allows you to make sure the user wants to leave the current page before they navigate away. +`history` lets you block navigation away from the current page so you can make sure e.g. the user wants to leave before they go to another page and possibly lose some changes they've made in the current page. ```js -// Register a simple prompt message that will be shown the -// user before they navigate away from the current page. -const unblock = history.block('Are you sure you want to leave this page?'); - -// Or use a function that returns the message when it's needed. -history.block((location, action) => { - // The location and action arguments indicate the location - // we're transitioning to and how we're getting there. - - // A common use case is to prevent the user from leaving the - // page if there's a form they haven't submitted yet. - if (input.value !== '') return 'Are you sure you want to leave this page?'; +// Block navigation and register a callback that +// fires when a navigation attempt is blocked. +let unblock = history.block(tx => { + // Navigation was blocked! Let's show a confirmation dialog + // so the user can decide if they actually want to navigate + // away and discard changes they've made in the current page. + let url = tx.location.pathnanme; + if (window.confirm(`Are you sure you want to go to ${url}?`)) { + // Unblock the navigation. + unblock(); + + // Retry the transition. + tx.retry(); + } }); - -// To stop blocking transitions, call the function returned from block(). -unblock(); ``` -**Note:** You'll need to provide a `getUserConfirmation` function to use this feature with `createMemoryHistory` (see below). +This example uses `window.confirm`, but you could also use your own custom confirm dialog if you'd rather. -## Customizing the Confirm Dialog +## Caveats -By default, [`window.confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) is used to show prompt messages to the user. If you need to override this behavior (or if you're using `createMemoryHistory`, which doesn't assume a DOM environment), provide a `getUserConfirmation` function when you create your history object. +`history.block` will call your callback for all in-page navigation attempts, but for navigation that reloads the page (e.g. the refresh button or a link that doesn't use `history.push`) it registers [a `beforeunload` handler](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event) to prevent the navigation. In modern browsers you are not able to customize this dialog. Instead, you'll see something like this (Chrome): -```js -const history = createHistory({ - getUserConfirmation(message, callback) { - // Show some custom dialog to the user and call - // callback(true) to continue the transiton, or - // callback(false) to abort it. - } -}); -``` +![Chrome navigation confirm dialog](images/block.png) + +One subtle side effect of registering a `beforeunload` handler is that the page will not be [salvageable](https://html.spec.whatwg.org/#unloading-documents) in [the `pagehide` event](https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event). diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index f7e965685..c0e78d4ce 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -5,7 +5,7 @@ The history library is a lightweight layer over browsers' built-in [History](htt We provide 3 different methods for creating a `history` object, depending on the needs of your environment: - `createBrowserHistory` 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)) -- `createHashHistory` is for use in situations where you want to store the location in the [hash](https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/hash) of the current URL to avoid sending it to the server when the page reloads +- `createHashHistory` is for use in situations where you want to store the location in the [hash](https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/hash) portion of the current URL to avoid sending it to the server when the page reloads - `createMemoryHistory` is used as a reference implementation and may also be used in non-DOM environments, like [React Native](https://facebook.github.io/react-native/) or tests Depending on the method you want to use to keep track of history, you'll `import` (or `require`, if you're using CommonJS) only one of these methods. @@ -17,13 +17,13 @@ Basic usage looks like this: ```js import { createBrowserHistory } from 'history'; -const history = createBrowserHistory(); +let history = createBrowserHistory(); // Get the current location. -const location = history.location; +let location = history.location; // Listen for changes to the current location. -const unlisten = history.listen((location, action) => { +let unlisten = history.listen((location, action) => { // location is an object like window.location console.log(action, location.pathname, location.state); }); @@ -78,7 +78,7 @@ Additionally, `createMemoryHistory` provides `history.index` and `history.entrie You can listen for changes to the current location using `history.listen`: ```js -history.listen((location, action) => { +history.listen(({ action, location }) => { console.log( `The current URL is ${location.pathname}${location.search}${location.hash}` ); @@ -94,17 +94,22 @@ The `location` object implements a subset of [the `window.location` interface](h Locations may also have the following properties: -- `location.state` - Some extra state for this location that does not reside in the URL (supported in `createBrowserHistory` and `createMemoryHistory`) -- `location.key` - A unique string representing this location (supported in `createBrowserHistory` and `createMemoryHistory`) +- `location.state` - Some extra state for this location that does not reside in the URL +- `location.key` - A unique string representing this location The `action` is one of `PUSH`, `REPLACE`, or `POP` depending on how the user got to the current URL. +- A `PUSH` means one more entry was added to the history stack +- A `REPLACE` means the current entry in the stack was replaced +- A `POP` means we went to some other location already in the stack + ## Cleaning up When you attach a listener using `history.listen`, it returns a function that can be used to remove the listener, which can then be invoked in cleanup logic: ```js -const unlisten = history.listen(myListener); -// ... +let unlisten = history.listen(myListener); + +// Later, when you're done... unlisten(); ``` diff --git a/docs/Misc.md b/docs/Misc.md deleted file mode 100644 index cff65e471..000000000 --- a/docs/Misc.md +++ /dev/null @@ -1,51 +0,0 @@ -## Using a Base URL - -If all the URLs in your app are relative to some other "base" URL, use the `basename` option. This option transparently adds the given string to the front of all URLs you use. - -```js -const history = createHistory({ - basename: '/the/base' -}); - -history.listen(location => { - console.log(location.pathname); // /home -}); - -history.push('/home'); // URL is now /the/base/home -``` - -**Note:** `basename` is not supported in `createMemoryHistory`. - -## Forcing Full Page Refreshes in createBrowserHistory - -By default `createBrowserHistory` uses HTML5 `pushState` and `replaceState` to prevent reloading the entire page from the server while navigating around. If instead you would like to reload as the URL changes, use the `forceRefresh` option. - -```js -const history = createBrowserHistory({ - forceRefresh: true -}); -``` - -## Modifying the Hash Type in createHashHistory - -By default `createHashHistory` uses a leading slash in hash-based URLs. You can use the `hashType` option to use a different hash formatting. - -```js -const history = createHashHistory({ - hashType: 'slash' // the default -}); - -history.push('/home'); // window.location.hash is #/home - -const history = createHashHistory({ - hashType: 'noslash' // Omit the leading slash -}); - -history.push('/home'); // window.location.hash is #home - -const history = createHashHistory({ - hashType: 'hashbang' // Google's legacy AJAX URL format -}); - -history.push('/home'); // window.location.hash is #!/home -``` diff --git a/docs/Navigation.md b/docs/Navigation.md index bc3804eda..f8fbcf62e 100644 --- a/docs/Navigation.md +++ b/docs/Navigation.md @@ -5,9 +5,8 @@ - `history.push(path, [state])` - `history.replace(path, [state])` - `history.go(n)` -- `history.goBack()` -- `history.goForward()` -- `history.canGo(n)` (only in `createMemoryHistory`) +- `history.back()` +- `history.forward()` When using `push` or `replace` you can either specify both the URL path and state as separate arguments or include everything in a single location-like object as the first argument. @@ -33,7 +32,5 @@ history.push({ // Go back to the previous history entry. The following // two lines are synonymous. history.go(-1); -history.goBack(); +history.back(); ``` - -**Note:** Location state is only supported in `createBrowserHistory` and `createMemoryHistory`. diff --git a/docs/README.md b/docs/README.md index e9c6f955e..6169ea83e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,11 +1,7 @@ -Welcome to the history docs! The library isn't huge, so there are really just a few files here for you to browse. +Welcome to the history docs! The library is very small, so there are really just a few files here for you to browse. -If this is your first time here, I'd recommend you first [install](Installation.md) the library and then read both: +If this is your first time here, we'd recommend you first [install](Installation.md) the library and then read: - [Getting Started](GettingStarted.md) - [Navigation](Navigation.md) - -For more advanced usage, check out: - -- [Blocking](Blocking.md) - Details about how to block navigation attempts -- [Misc](Misc.md) - Miscellaneous topics about several API details +- [Blocking Navigation](Blocking.md) diff --git a/docs/images/block.png b/docs/images/block.png new file mode 100644 index 000000000..6dd81e8b7 Binary files /dev/null and b/docs/images/block.png differ