# @gyral/router

> Gyral router: typed route tables, navigation as commands, History API baseline with Navigation API enhancement.

Source: https://gyral.dev/docs/api/router/

Gyral router: typed route tables, navigation as commands, History API baseline with Navigation API enhancement.

```sh
npm install @gyral/router
```

> **Writing code? Start from working code, not from this page.** [Routing](https://gyral.dev/docs/routing/). Adapt the closest example and check it, then look a name up here when you are about to call it.

Generated from the package's type declarations. Entry points: [`@gyral/router`](#gyralrouter).

## `@gyral/router`

### Functions

| Name | Summary |
| --- | --- |
| [`listen`](#router-listen) | Streams the current location, then every URL change, as messages until the component disconnects (a streaming command, ADR 0006/0009). |
| [`makeRouter`](#router-makerouter) | A router driver. |
| [`navigate`](#router-navigate) | Navigates in-app (pushes a history entry, or replaces the current one). |
| [`routes`](#router-routes) |  |
| [`setHead`](#router-sethead) | Makes the document's head this `Head` (ADR 0019): the title, `lang`/`dir`, and every managed element (description, robots, canonical, meta, links, JSON-LD). |

#### `listen`

```ts
function listen<M>(toMsg: (location: RouteLocation) => M | undefined): Command<M>;
```

Streams the current location, then every URL change, as messages until the component
disconnects (a streaming command, ADR 0006/0009). Start it from `subscriptions`, which restarts
it when a moved or re-attached component connects again (a command from `init` is not):


```ts
subscriptions: () => [listen((location) => ({ _tag: 'Routed', location }))]
```


#### `makeRouter`

```ts
function makeRouter(options?: RouterOptions): RouterDriver;
```

A router driver. Listeners are installed on first use, never at import time.

#### `navigate`

```ts
function navigate(url: string, options?: NavigateOptions): Command<never>;
```

Navigates in-app (pushes a history entry, or replaces the current one). In the browser, once
the new page has rendered, a push scrolls to the `#fragment` target or the top and resets
focus, as the browser does for a page load (ADR 0009 "Scroll and focus"); `scroll: false` or
`focusReset: false` leaves that to the app. A `replace` (keeping the query in sync with a
search box) leaves scroll and focus alone unless `scroll: true` / `focusReset: true`.

#### `routes`

```ts
function routes<const T extends RouteTable>(table: T, options?: {
    readonly matcher?: Matcher;
}): Routes<T>;
```


#### `setHead`

```ts
function setHead(head: Head): Command<never>;
```

Makes the document's head this `Head` (ADR 0019): the title, `lang`/`dir`, and every managed
element (description, robots, canonical, meta, links, JSON-LD). Managed elements the new head
doesn't name are removed; unchanged ones are not written; content from `renderPage({ extraHead })`
is never touched. The memory history records it instead. Build the head with one pure
function and pass the same function's result to the server's `renderPage()`:


```ts
Routed: (s, m) => [next, [setHead(pageHead(site.match(m.location.href), origin))]]
```


### Constants

| Name | Summary |
| --- | --- |
| [`router`](#router-router) | The default router (global window, Navigation API when available). |

#### `router`

```ts
const router: RouterDriver
```

The default router (global window, Navigation API when available).

### Types and interfaces

You rarely write most of these yourself: TypeScript infers them from the functions above. Look one up when an example or a compiler error names it.

| Name | Summary |
| --- | --- |
| [`AfterNavigation`](#router-afternavigation) | What the browser history does once a navigation's render has committed (ADR 0009). |
| [`LocationLike`](#router-locationlike) | What link capture and URL resolution need from a location (a `URL` qualifies). |
| [`Matcher`](#router-matcher) |  |
| [`MemoryOptions`](#router-memoryoptions) |  |
| [`NavigateOptions`](#router-navigateoptions) | Options of `navigate()`. |
| [`Params`](#router-params) | Named required strings, optional strings and trailing catch-all arrays, inferred by path. |
| [`RouteLocation`](#router-routelocation) | The document location, numbered in the order this router saw changes. |
| [`RouteMatch`](#router-routematch) | The route name discriminates its params. |
| [`RouterDriver`](#router-routerdriver) |  |
| [`RouterInput`](#router-routerinput) |  |
| [`RouterOptions`](#router-routeroptions) |  |
| [`RouterSnapshot`](#router-routersnapshot) | The router's current URL and last head, for tests and server-side assertions. |
| [`Routes`](#router-routes) |  |
| [`RouteTable`](#router-routetable) |  |

#### `AfterNavigation`

```ts
interface AfterNavigation {
    /** Scroll to the `#fragment` target or the top (push), or restore (back/forward). */
    readonly scroll: boolean;
    /** Move focus to the first `[autofocus]` element, or reset it to the page start. */
    readonly focusReset: boolean;
}
```

What the browser history does once a navigation's render has committed (ADR 0009).

#### `LocationLike`

```ts
type LocationLike = Pick<Location, 'href' | 'origin' | 'pathname' | 'search'>;
```

What link capture and URL resolution need from a location (a `URL` qualifies).

#### `Matcher`

```ts
type Matcher = 'auto' | 'urlpattern' | 'fallback';
```


#### `MemoryOptions`

```ts
interface MemoryOptions {
    /** Starting URL, absolute or relative to `origin`. Default `'/'`. */
    readonly initial?: string;
    /** Origin that relative URLs resolve against. Default `'http://localhost'`. */
    readonly origin?: string;
    /**
     * Intercept same-origin link clicks. **Default `false`** (opt in): a router that captures
     * every link on the page breaks multi-page apps where only one component routes (ADR 0009).
     */
    readonly captureLinks?: boolean;
    /**
     * Where to capture link clicks when `captureLinks` is on. Default: the (global, or the
     * browser history's) `document`. Passing an element also turns capture on and limits it to
     * that subtree; `null` turns it off. Capture is only active while a component listens.
     */
    readonly linkRoot?: EventTarget | null;
}
```


#### `NavigateOptions`

```ts
interface NavigateOptions extends Partial<AfterNavigation> {
    /** Replace the current history entry instead of pushing one. Default `false`. */
    readonly replace?: boolean;
}
```

Options of `navigate()`.

#### `Params`

```ts
type Params<Path extends string> = Path extends `${infer Head}/${infer Rest}` ? Param<Head> & Params<Rest> : Param<Path>;
```

Named required strings, optional strings and trailing catch-all arrays, inferred by path.

#### `RouteLocation`

```ts
interface RouteLocation {
    readonly href: string;
    readonly pathname: string;
    readonly search: string;
    readonly hash: string;
    /** Increases on every URL change seen by this router. */
    readonly seq: number;
}
```

The document location, numbered in the order this router saw changes.

#### `RouteMatch`

```ts
type RouteMatch<T extends RouteTable> = {
    [N in keyof T & string]: {
        readonly name: N;
        readonly params: Params<T[N]>;
        readonly path: string;
    };
}[keyof T & string];
```

The route name discriminates its params. `path` is the canonical href for those captures.

#### `RouterDriver`

```ts
interface RouterDriver extends Driver<RouterInput, RouteLocation | undefined> {
    /** The current URL and last head as this router sees them. */
    readonly snapshot: () => RouterSnapshot;
    /** Removes document listeners and ends running `listen` commands. */
    readonly dispose: () => void;
}
```


#### `RouterInput`

```ts
type RouterInput = ({
    readonly _tag: 'Navigate';
    readonly url: string;
    readonly replace: boolean;
} & Partial<AfterNavigation>) | {
    readonly _tag: 'Traverse';
    readonly delta: number;
} | {
    readonly _tag: 'Head';
    readonly head: Head;
} | {
    readonly _tag: 'Listen';
};
```


#### `RouterOptions`

```ts
interface RouterOptions extends MemoryOptions {
    /** Driver name used for substitution (`el.drivers`). Default `'router'`. */
    readonly name?: string;
    /**
     * `'browser'` (default) drives the real document. `'memory'` keeps entries in memory: no
     * global URL changes, no `window` needed (tests, servers). See `initial` and `origin`.
     * `captureLinks`/`linkRoot` apply to both histories.
     */
    readonly history?: 'browser' | 'memory';
    /** Browser history: default the global window, resolved on first use (safe on a server). */
    readonly window?: Window;
    /** Browser history: use the Navigation API when present. Default `true`. */
    readonly navigationApi?: boolean;
    /**
     * Browser history, once a navigation has rendered: scroll to the `#fragment` target or the
     * top (push) and restore the position on back/forward. Default `true`; `false` for apps that
     * manage scroll themselves. A replace never scrolls unless `navigate(url, { scroll: true })`;
     * `navigate(url, { scroll })` overrides it per call.
     */
    readonly scroll?: boolean;
    /**
     * Browser history, once a navigation has rendered: move focus to the first `[autofocus]`
     * element, or reset it to the page start, unless something took focus during the navigation
     * (a `focus('main h1')` command). Default `true` (a replace: only with `focusReset: true`).
     * `navigate(url, { focusReset })` per call.
     */
    readonly focusReset?: boolean;
}
```


#### `RouterSnapshot`

```ts
interface RouterSnapshot {
    readonly href: string;
    /** The last `setHead()` head, if any (the browser applies it to the document too). */
    readonly head: Head | undefined;
    /** Number of history entries (memory history; `history.length` in a browser). */
    readonly length: number;
}
```

The router's current URL and last head, for tests and server-side assertions.

#### `Routes`

```ts
interface Routes<T extends RouteTable> {
    readonly table: T;
    /** First route in table order matching the pathname. A string beginning with / is a path. */
    match(url: string | URL): RouteMatch<T> | undefined;
    /** Percent-encode each parameter or catch-all segment; omit absent optional parameters. */
    href<N extends keyof T & string>(name: N, params: Params<T[N]>): string;
}
```


#### `RouteTable`

```ts
type RouteTable = Readonly<Record<string, string>>;
```
