Skip to content

v5 #751

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 133 commits into from
Jun 12, 2020
Merged

v5 #751

Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
4b8a816
Remove deprecated files from v4
mjackson Nov 4, 2019
c013f2f
Update ESLint config
mjackson Nov 4, 2019
5416474
Main v5 rewrite
mjackson Nov 5, 2019
d51e9b7
Use ES6 ESLint env
mjackson Nov 5, 2019
7496807
Tweak test function format
mjackson Nov 5, 2019
824ed29
Consolidate push/replace => navigate
mjackson Nov 6, 2019
3cc181f
Add beforeunload fixture
mjackson Nov 6, 2019
4bf15b1
Add location.index + fix blocking POP actions
mjackson Nov 6, 2019
0831aae
Add history.retry for retrying transitions
mjackson Nov 6, 2019
c1702ab
Run all tests in parallel
mjackson Nov 6, 2019
67f6aea
Remove location.index, use history.push/replace
mjackson Nov 7, 2019
87a042e
Update block fixtures
mjackson Nov 7, 2019
bb91b28
Skip failing tests
mjackson Nov 7, 2019
d9013e4
Fix hash history test reset
mjackson Nov 7, 2019
dc947ec
Remove encoding tests
mjackson Nov 7, 2019
8b3be6f
Add back missing pathname support
mjackson Nov 7, 2019
2acce39
Remove Safari from testing, hopefully temporary
mjackson Nov 7, 2019
50997b3
Small tweaks
mjackson Nov 7, 2019
c647e9c
Rename to avoid collision with browser globals
mjackson Nov 8, 2019
02b43fd
Update docs
mjackson Nov 8, 2019
105b64a
5.0.0-beta.0
mjackson Nov 8, 2019
f1ba1cd
No need to return push/replace values from retry
mjackson Nov 15, 2019
a9825bd
Only use Object.freeze in dev
mjackson Nov 15, 2019
da24367
Small tweaks
mjackson Nov 15, 2019
d09f4fe
Use Closure Compiler with Advanced Mode (#753)
kristoferbaxter Nov 20, 2019
59c5d5d
Remove CommonJS builds
mjackson Nov 20, 2019
9338571
Change global name from History => HistoryLib
mjackson Nov 20, 2019
0b350a3
Remove BUILD_ENV var
mjackson Nov 20, 2019
2058791
Add is*History functions for type checking
mjackson Nov 20, 2019
dd4f4be
More explicit externals
mjackson Nov 20, 2019
dbb8900
Remove transform-object-assign Babel plugin
mjackson Nov 20, 2019
ad95d95
Move mem history to last
mjackson Nov 20, 2019
d0011ed
Generate sourcemaps
mjackson Nov 22, 2019
ec6aa85
Update global UMD name
mjackson Nov 22, 2019
4083639
Update global UMD name to "HistoryLibrary"
mjackson Nov 22, 2019
11b295b
Update ignore paths
mjackson Dec 2, 2019
9b90395
Fix CommonJS entry point
mjackson Dec 2, 2019
211bb9f
Use simple optimizations instead of advanced
mjackson Dec 3, 2019
4c2a05a
Remove is*History functions
mjackson Dec 3, 2019
0ada9c2
Update size check paths
mjackson Dec 3, 2019
434fe90
Remove TEST_ENV variable
mjackson Dec 3, 2019
65dd4be
Version 5.0.0-beta.1
mjackson Dec 3, 2019
39c4af9
Explicitly include index.js
mjackson Dec 3, 2019
e2833f7
Use simple optimizations
mjackson Dec 3, 2019
5f19f4b
Rework builds
mjackson Dec 7, 2019
a6abd69
Fine-tuning the build
mjackson Dec 7, 2019
6d901ec
Use PRETTY env var to run prettier on builds
mjackson Dec 7, 2019
30951b7
Run the build before tests on Travis
mjackson Dec 7, 2019
7367169
Fix loading tests in IE11
mjackson Dec 7, 2019
b6bbdce
Run build before size check
mjackson Dec 7, 2019
4b149df
Run CommonJS entry point through CC
mjackson Dec 7, 2019
969a267
Fix deploy script
mjackson Dec 7, 2019
643e666
Version 5.0.0-beta.2
mjackson Dec 7, 2019
c43d1a4
Remove loose-envify dep
mjackson Dec 7, 2019
d2db803
Add browser module builds
mjackson Dec 10, 2019
0e43e72
Output ES8 in browser modules
mjackson Dec 11, 2019
9ffbead
Version 5.0.0-beta.3
mjackson Dec 11, 2019
e6c94da
Upgrade Rollup
mjackson Dec 11, 2019
88163eb
Rename some source files
mjackson Dec 18, 2019
e6df3da
Update build scripts
mjackson Dec 19, 2019
f81c90a
Also accept a string in createHref
mjackson Dec 19, 2019
bcb89a3
Remove unnecessary "use strict"
mjackson Dec 19, 2019
18dff0b
Clearer blocking description and typo fix
pshrmn Jan 5, 2020
85b134c
console.warn instead of throwing warnings in dev
mjackson Jan 22, 2020
2d74ea5
Export parsePath and createPath helpers
mjackson Jan 22, 2020
34f405b
Increase size limit for UMD bundle
mjackson Jan 22, 2020
97c3163
Version 5.0.0-beta.4
mjackson Jan 22, 2020
9532fb2
Reformat some docs files
mjackson Feb 3, 2020
5c56e90
Upgrade filesize dep
mjackson Feb 4, 2020
5f72346
Update cc rollup plugin
mjackson Feb 4, 2020
b266c94
Move files out of modules dir
mjackson Feb 6, 2020
e181153
Rename node-main.js to main.js in package output
mjackson Feb 7, 2020
4bfb134
Remove TODO about using hashchange
mjackson Feb 7, 2020
083400c
Add TypeScript declaration files
mjackson Feb 7, 2020
e25626f
Version 5.0.0-beta.5
mjackson Feb 7, 2020
a8a056b
Fix TS linting issues
mjackson Feb 7, 2020
aba0c9f
Fix no-unused-vars lint errors in TS files
mjackson Feb 14, 2020
fd866b2
Add version + publish scripts
mjackson Feb 18, 2020
007b42d
Configure CircleCI
mjackson Mar 24, 2020
1bb5554
Update BrowserStack config
mjackson Mar 25, 2020
a62364a
Update CircleCI config
mjackson Mar 25, 2020
44f6662
Remove Travis config
mjackson Mar 25, 2020
fc00d36
Use annotated git tags
mjackson Mar 25, 2020
21e6b8c
Use separate workflows for build + deploy
mjackson Mar 25, 2020
6695288
Trying out a different config for CircleCI
mjackson Mar 26, 2020
501d3f1
Use cleaned version from command prompt
mjackson Mar 26, 2020
374c0e0
Try again, yay
mjackson Mar 26, 2020
e91dbcf
Another try, weeee!!
mjackson Mar 26, 2020
820d032
Version 5.0.0-beta.6
mjackson Mar 26, 2020
0c5d004
Use Travis CI
mjackson Mar 26, 2020
2d91489
Version 5.0.0-beta.7
mjackson Mar 26, 2020
cb3897c
Use explicit install step
mjackson Mar 26, 2020
7904e45
Consolidate test utils
mjackson Mar 27, 2020
1e91a64
Convert to TypeScript
mjackson Apr 15, 2020
72e513e
Update doc comment
mjackson Apr 17, 2020
6ad66e3
Version 5.0.0-beta.8
mjackson Apr 17, 2020
59e7e6c
Add generics for events collections
mjackson Apr 22, 2020
10c36a6
location.state should be `null` by default
mjackson Apr 22, 2020
b2ccfd5
Some types tweaks
mjackson Apr 22, 2020
9bf1254
More types tweaks
mjackson Apr 24, 2020
2153e3e
Add LocationPieces interface
mjackson Apr 24, 2020
f210445
State type union with null
mjackson Apr 24, 2020
e282eba
Comment formatting
mjackson Apr 24, 2020
3a9cc2b
Add more details + links to doc comments
mjackson Apr 24, 2020
943f377
Use ... instead of Object.assign
mjackson Apr 29, 2020
2145ce3
Fix working directory clean check
mjackson Apr 29, 2020
c692ca5
Version 5.0.0-beta.9
mjackson Apr 29, 2020
513edad
Ran yarn upgrade
mjackson Apr 29, 2020
46eaaad
Add type aliases for some primitives
mjackson May 1, 2020
6996dd7
Re-formatting
mjackson May 12, 2020
fca4907
Add a generic type to readOnly
mjackson May 15, 2020
0f99273
Memory history initial index defaults to last
mjackson May 15, 2020
0b066ba
Update some docs
mjackson May 15, 2020
5a5d611
Rename n => delta
mjackson May 15, 2020
8402b31
Added API reference doc
mjackson May 15, 2020
fc0c588
Update docs README
mjackson May 15, 2020
35d1b3f
Update API reference links
mjackson May 15, 2020
3a32a36
Update docs
mjackson May 15, 2020
700f019
Use cleaner anchors
mjackson May 15, 2020
d1b2808
Add API docs for state
mjackson May 15, 2020
79bb32a
Update API reference intro
mjackson May 15, 2020
313f1c2
Minor docs tweaks
mjackson May 15, 2020
742a3a4
Add script for generating API docs
mjackson Jun 3, 2020
90144a7
Some scripts tweaks
mjackson Jun 3, 2020
da807d5
Export types for options objects
mjackson Jun 7, 2020
138ba28
Remove typeParam docs
mjackson Jun 7, 2020
f88b174
Small tweaks to api reference
mjackson Jun 7, 2020
0f95d29
More tweaks to API docs
mjackson Jun 8, 2020
1babffe
Update API docs
mjackson Jun 10, 2020
a7ae54c
More docs + IntelliSense doc comments
mjackson Jun 12, 2020
41bacf0
Add more links to doc comments
mjackson Jun 12, 2020
4ab6a42
Restore syntax highlights in declaration blocks
mjackson Jun 12, 2020
987ff43
Add some more type declarations
mjackson Jun 12, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/build
/fixtures
20 changes: 14 additions & 6 deletions modules/.eslintrc → .eslintrc
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
{
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"plugins": ["import"],
"env": {
"browser": true
"node": true
},
"extends": ["eslint:recommended", "plugin:import/errors"],
"rules": {
"prefer-arrow-callback": 2
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
"prefer-arrow-callback": "error",
"no-unused-vars": [
"warn",
{
"args": "after-used",
"ignoreRestSiblings": true,
"argsIgnorePattern": "event"
}
]
}
}
9 changes: 4 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/node_modules/
/esm/
/cjs/
/umd/
/local.log
/build/
/fixtures/*/history.js

node_modules/
26 changes: 0 additions & 26 deletions .size-snapshot.json

This file was deleted.

24 changes: 12 additions & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
language: node_js
node_js: node
cache: yarn
env:
- TEST_ENV=cjs BUILD_ENV=cjs
- TEST_ENV=umd BUILD_ENV=umd
- TEST_ENV=source
before_script:
- ([[ -z "$BUILD_ENV" ]] || yarn build)
script:
- yarn lint
- yarn test
jobs:
include:
- stage: Test
before_script: yarn build
script: yarn test
- stage: Size
before_script: yarn build
script: yarn size
- stage: Release
if: tag =~ ^v[0-9]
env: NPM_TAG=$([[ "$TRAVIS_TAG" == *-* ]] && echo "next" || echo "latest")
before_script: yarn build
script: echo "Releasing $TRAVIS_TAG to npm with tag \"$NPM_TAG\" ..."
deploy:
provider: npm
skip_cleanup: true
tag: "$NPM_TAG"
edge: true
cleanup: false
email: [email protected]
api_key: "$NPM_TOKEN"
api_token: "$NPM_TOKEN"
src: "./build/history"
tag: "$NPM_TAG"
on:
tags: true
3 changes: 0 additions & 3 deletions DOMUtils.js

This file was deleted.

3 changes: 0 additions & 3 deletions ExecutionEnvironment.js

This file was deleted.

3 changes: 0 additions & 3 deletions LocationUtils.js

This file was deleted.

3 changes: 0 additions & 3 deletions PathUtils.js

This file was deleted.

3 changes: 0 additions & 3 deletions createBrowserHistory.js

This file was deleted.

3 changes: 0 additions & 3 deletions createHashHistory.js

This file was deleted.

3 changes: 0 additions & 3 deletions createMemoryHistory.js

This file was deleted.

3 changes: 0 additions & 3 deletions createTransitionManager.js

This file was deleted.

49 changes: 21 additions & 28 deletions docs/Blocking.md
Original file line number Diff line number Diff line change
@@ -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).
87 changes: 46 additions & 41 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
@@ -1,84 +1,84 @@
# Intro

The history library is a lightweight layer over browsers' built-in [History](https://developer.mozilla.org/en-US/docs/Web/API/History) and [Location](https://developer.mozilla.org/en-US/docs/Web/API/Location) APIs. The goal is not to provide a full implementation of these APIs, but rather to make it easy for users to opt-in to different methods of navigation.
The history library provides history tracking and navigation primitives for JavaScript applications that run in browsers and other stateful environments.

We provide 3 different methods for creating a `history` object, depending on the needs of your environment:
We provide 3 different methods for working with history, depending on 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
- `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
- A "browser history" 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))
- A "hash history" is for use in web browsers 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
- A "memory history" is used as a reference implementation that may be used in non-browser 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.
Since you'll only ever need to use one in a given app, we provide environment-specific bundles. You'll need to `import` one of these bundles:

- `history/browser`
- `history/hash`
- `history/memory`

Each bundle exports a `createHistory` method you can use to create your own history object. In addition, `history/browser` and `history/hash` export a singleton instance you can use which reflects the state of [the current `document`](https://developer.mozilla.org/en-US/docs/Web/API/Window/document).

## Basic Usage

Basic usage looks like this:

```js
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();
// Import the browser history singleton instance.
import history from 'history/browser';
// Alternatively, if you're using hash history import
// the hash history singleton instance.
// import history from 'history/hash';

// 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) => {
// location is an object like window.location
let unlisten = history.listen(({ location, action }) => {
console.log(action, location.pathname, location.state);
});

// Use push, replace, and go to navigate around.
// Use push to push a new entry onto the history stack.
history.push('/home', { some: 'state' });

// Use replace to replace the current entry in the stack.
history.replace('/logged-in');

// Use back/forward to navigate one entry back or forward.
history.back();

// To stop listening, call the function returned from listen().
unlisten();
```

The options that each `create` method takes, along with its default values, are:
If you're using `history/memory` you'll need to create your own `history` object before you can use it.

```js
createBrowserHistory({
basename: '', // The base URL of the app (see below)
forceRefresh: false, // Set true to force full page refreshes
keyLength: 6, // The length of location.key
// A function to use to confirm navigation with the user (see below)
getUserConfirmation: (message, callback) => callback(window.confirm(message))
});
import { createHistory } from 'history/memory';
let history = createHistory();
```

createHashHistory({
basename: '', // The base URL of the app (see below)
hashType: 'slash', // The hash type to use (see below)
// A function to use to confirm navigation with the user (see below)
getUserConfirmation: (message, callback) => callback(window.confirm(message))
});
If you're using browser or hash history with a `window` other than that of the current `document` (like an iframe), you'll need to create your own browser/hash history:

createMemoryHistory({
initialEntries: ['/'], // The initial URLs in the history stack
initialIndex: 0, // The starting index in the history stack
keyLength: 6, // The length of location.key
// A function to use to confirm navigation with the user. Required
// if you return string prompts from transition hooks (see below)
getUserConfirmation: null
```js
import { createHistory } from 'history/browser';
let history = createHistory({
window: iframe.contentWindow
});
```

## Properties

Each `history` object has the following properties:

- `history.length` - The number of entries in the history stack
- `history.location` - The current location (see below)
- `history.action` - The current navigation action (see below)

Additionally, `createMemoryHistory` provides `history.index` and `history.entries` properties that let you inspect the history stack.
Additionally, memory history provides `history.index` that tells you the current index in the history stack.

## Listening

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}`
);
Expand All @@ -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();
```
Loading