@gyral/router
Gyral router: typed route tables, navigation as commands, History API baseline with Navigation API enhancement.
npm install @gyral/routerWriting code? Start from working code, not from this page. 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.
@gyral/router
Functions
| Name | Summary |
|---|---|
listen |
Streams the current location, then every URL change, as messages until the component disconnects (a streaming command, ADR 0006/0009). |
makeRouter |
A router driver. |
navigate |
Navigates in-app (pushes a history entry, or replaces the current one). |
routes |
|
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
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):
subscriptions: () => [listen((location) => ({ _tag: 'Routed', location }))]makeRouter
function makeRouter(options?: RouterOptions): RouterDriver;A router driver. Listeners are installed on first use, never at import time.
navigate
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
function routes<const T extends RouteTable>(table: T, options?: {
readonly matcher?: Matcher;
}): Routes<T>;setHead
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():
Routed: (s, m) => [next, [setHead(pageHead(site.match(m.location.href), origin))]]Constants
| Name | Summary |
|---|---|
router |
The default router (global window, Navigation API when available). |
router
const router: RouterDriverThe 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 |
What the browser history does once a navigation's render has committed (ADR 0009). |
LocationLike |
What link capture and URL resolution need from a location (a URL qualifies). |
Matcher |
|
MemoryOptions |
|
NavigateOptions |
Options of navigate(). |
Params |
Named required strings, optional strings and trailing catch-all arrays, inferred by path. |
RouteLocation |
The document location, numbered in the order this router saw changes. |
RouteMatch |
The route name discriminates its params. |
RouterDriver |
|
RouterInput |
|
RouterOptions |
|
RouterSnapshot |
The router's current URL and last head, for tests and server-side assertions. |
Routes |
|
RouteTable |
AfterNavigation
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
type LocationLike = Pick<Location, 'href' | 'origin' | 'pathname' | 'search'>;What link capture and URL resolution need from a location (a URL qualifies).
Matcher
type Matcher = 'auto' | 'urlpattern' | 'fallback';MemoryOptions
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
interface NavigateOptions extends Partial<AfterNavigation> {
/** Replace the current history entry instead of pushing one. Default `false`. */
readonly replace?: boolean;
}Options of navigate().
Params
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
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
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
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
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
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
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
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
type RouteTable = Readonly<Record<string, string>>;