@virtualstate/app-history
Version:
Native JavaScript [app-history](https://github.com/WICG/app-history) implementation
187 lines (126 loc) • 5.02 kB
Markdown
# `@virtualstate/app-history`
Native JavaScript [app-history](https://github.com/WICG/app-history) implementation
[//]: # (badges)
### Support
    
### Test Coverage
    
[//]: # (badges)
## Install
### Skypack
- [Package Registry Link - Skypack](https://www.skypack.dev/view/@virtualstate/app-history)
```typescript
const { AppHistory } = await import("https://cdn.skypack.dev/@virtualstate/app-history");
```
_Or_
```typescript
import { AppHistory } from "https://cdn.skypack.dev/@virtualstate/app-history";
```
### npm / yarn / GitHub
- [Package Registry Link - GitHub](https://github.com/virtualstate/app-history/packages)
- [Package Registry Link - npm](https://www.npmjs.com/package/@virtualstate/app-history)
```
npm i --save @virtualstate/app-history
```
_Or_
```
yarn add @virtualstate/app-history
```
Then
```typescript
import { AppHistory } from "@virtualstate/app-history";
```
## Navigation
```typescript
import { AppHistory } from "@virtualstate/app-history";
const appHistory = new AppHistory();
// Set initial url
appHistory.navigate("/");
appHistory.navigate("/skipped");
// Use .finished to wait for the transition to complete
await appHistory.navigate("/awaited").finished;
```
## Waiting for events
```typescript
import { AppHistory } from "@virtualstate/app-history";
const appHistory = new AppHistory();
appHistory.addEventListener("navigate", async ({ destination }) => {
if (destination.url === "/disallow") {
throw new Error("No!");
}
});
await appHistory.navigate("/allowed").finished; // Resolves
await appHistory.navigate("/disallow").finished; // Rejects
```
## Transitions
```typescript
import { AppHistory } from "@virtualstate/app-history";
import { loadPhotoIntoCache } from "./cache";
const appHistory = new AppHistory();
appHistory.addEventListener("navigate", async ({ destination, transitionWhile }) => {
transitionWhile(loadPhotoIntoCache(destination.url));
});
```
## URLPattern
You can match `destination.url` using [`URLPattern`](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API)
```typescript
import {AppHistory} from "@virtualstate/app-history";
import {URLPattern} from "urlpattern-polyfill";
const appHistory = new AppHistory();
appHistory.addEventListener("navigate", async ({destination, transitionWhile}) => {
const pattern = new URLPattern({ pathname: "/books/:id" });
const match = pattern.exec(destination.url);
if (match) {
transitionWhile(transition());
}
async function transition() {
console.log("load book", match.pathname.groups.id)
}
});
appHistory.navigate("/book/1");
```
## State
```typescript
import { AppHistory } from "@virtualstate/app-history";
const appHistory = new AppHistory();
appHistory.addEventListener("currentchange", () => {
console.log({ updatedState: appHistory.current?.getState() });
});
await appHistory.updateCurrent({
state: {
items: [
"first",
"second"
],
index: 0
}
}).finished;
await appHistory.updateCurrent({
state: {
...appHistory.current.getState(),
index: 1
}
}).finished;
```
## Updating browser url
> This is a pending development task.
> The below code will help visually update the window
This can be achieved various ways, but if your application completely utilises
the app history interface, then you can directly use `pushState` to immediately
update the window's url.
This does not take into account the browser's native back/forward functionality,
which would need to be investigated further.
```typescript
import { AppHistory } from "@virtualstate/app-history";
const appHistory = new AppHistory();
const origin = typeof location === "undefined" ? "https://example.com" : location.origin;
appHistory.addEventListener("currentchange", () => {
const { current } = appHistory;
if (!current || !current.sameDocument) return;
const state = current.getState() ?? {};
const { pathname } = new URL(current.url, origin);
if (typeof window !== "undefined" && window.history) {
window.history.pushState(state, state.title, origin)
}
})
```