virtualstate / navigation

Native JavaScript navigation [web api] implementation
MIT License
77 stars 5 forks source link
browser deno navigation typescript

@virtualstate/navigation

Native JavaScript navigation implementation

Support

Node.js supported Deno supported Bun supported Chromium supported Webkit supported Firefox supported

Test Coverage ![Web Platform Tests 140/277](https://img.shields.io/badge/Web%20Platform%20Tests-140%2F277-brightgreen) ![92.86%25 lines covered](https://img.shields.io/badge/lines-92.86%25-brightgreen) ![92.86%25 statements covered](https://img.shields.io/badge/statements-92.86%25-brightgreen) ![83.11%25 functions covered](https://img.shields.io/badge/functions-83.11%25-brightgreen) ![83.02%25 branches covered](https://img.shields.io/badge/branches-83.02%25-brightgreen)

Install

npm / yarn / GitHub - [Package Registry Link - GitHub](https://github.com/virtualstate/navigation/packages) - [Package Registry Link - npm](https://www.npmjs.com/package/@virtualstate/navigation) ``` npm i --save @virtualstate/navigation ``` _Or_ ``` yarn add @virtualstate/navigation ``` Then ```typescript import { Navigation } from "@virtualstate/navigation"; ```
Skypack - [Package Registry Link - Skypack](https://www.skypack.dev/view/@virtualstate/navigation) ```typescript const { Navigation } = await import("https://cdn.skypack.dev/@virtualstate/navigation"); ``` _Or_ ```typescript import { Navigation } from "https://cdn.skypack.dev/@virtualstate/navigation"; ```
importmap [`importmap` documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) ```html ```

Usage

See the MDN documentation for the Navigation API for in depth information on usage.

Examples ## Navigation ```typescript import { Navigation } from "@virtualstate/navigation"; const navigation = new Navigation(); // Set initial url navigation.navigate("/"); navigation.navigate("/skipped"); // Use .finished to wait for the transition to complete await navigation.navigate("/awaited").finished; ``` ## Waiting for events ```typescript import { Navigation } from "@virtualstate/navigation"; const navigation = new Navigation(); navigation.addEventListener("navigate", async ({ destination, preventDefault }) => { if (new URL(destination.url).pathname === "/disallow") { preventDefault(); } }); await navigation.navigate("/allowed").finished; // Resolves await navigation.navigate("/disallow").finished; // Rejects ``` ## Transitions ```typescript import { Navigation } from "@virtualstate/navigation"; import { loadPhotoIntoCache } from "./cache"; const navigation = new Navigation(); navigation.addEventListener("navigate", async ({ destination, intercept }) => { intercept(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 {Navigation} from "@virtualstate/navigation"; import {URLPattern} from "urlpattern-polyfill"; const navigation = new Navigation(); navigation.addEventListener("navigate", async ({destination, intercept}) => { const pattern = new URLPattern({ pathname: "/books/:id" }); const match = pattern.exec(destination.url); if (match) { intercept(transition()); } async function transition() { console.log("load book", match.pathname.groups.id) } }); navigation.navigate("/book/1"); ``` ## State ```typescript import { Navigation } from "@virtualstate/navigation"; const navigation = new Navigation(); navigation.addEventListener("currententrychange", () => { console.log({ updatedState: navigation.currentEntry?.getState() }); }); await navigation.updateCurrentEntry({ state: { items: [ "first", "second" ], index: 0 } }).finished; await navigation.updateCurrentEntry({ state: { ...navigation.currentEntry.getState(), index: 1 } }).finished; ```

Polyfill

If a global instance of the navigation API is not available, this will provide one, integrated into the History API if available.

import "@virtualstate/navigation/polyfill";

await window.navigation.navigate("/").finished;

// Or if within a window global scope, aka in a browser:
await navigation.navigate("/").finished;
Polyfill Global Window Types See [`@types/dom-navigation`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/dom-navigation/package.json) for a standardised type definition for the Navigation API which can be utilised alongside this polyfill. ```bash yarn add --dev @types/dom-navigation ``` This should then be included as a type in your `tsconfig.json`: ```json { "compilerOptions": { "types": [ "dom-navigation" ] } } ```