rvx
Version:
A signal based rendering library
335 lines (320 loc) • 9.75 kB
TypeScript
/*!
MIT License
Copyright (c) 2025 Max J. Polster
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import { Expression } from './rvx.js';
import { Context } from './rvx.js';
import { Component } from './rvx.js';
import { View } from './rvx.js';
/**
* Represents URL search parameters.
*/
declare class Query {
#private;
constructor(raw: string, params?: URLSearchParams);
static from(init: QueryInit): Query | undefined;
get raw(): string;
get params(): URLSearchParams;
}
type QueryInit = ConstructorParameters<typeof URLSearchParams>[0];
/**
* Format the specified query for use in a URL.
*
* Strings are returned as is.
*/
declare function formatQuery(value: QueryInit): string;
/**
* Represents a path with optional query parameters that may change over time.
*/
interface Router {
/**
* The root router.
*/
get root(): Router;
/**
* The parent of this router if any.
*/
get parent(): Router | undefined;
/**
* Reactively get the remaining normalized path in this context.
*/
get path(): string;
/**
* Reactively get the search parameters in this context.
*/
get query(): Query | undefined;
/**
* Navigate to the specified path within the path this router is mounted in.
*
* @param path The path. This may not be normalized.
* @param query The query part.
*
* @example
* ```tsx
* import { ROUTER } from "rvx/router";
*
* ROUTER.current!.root.push("/home");
* ```
*/
push(path: string, query?: QueryInit): void;
/**
* Same as {@link push}, but replaces the URL in history if possible.
*
* @example
* ```tsx
* import { ROUTER } from "rvx/router";
*
* ROUTER.current!.root.replace("/home");
* ```
*/
replace(path: string, query?: QueryInit): void;
}
/**
* Context for the current router.
*/
declare const ROUTER: Context<Router | undefined>;
/**
* A router that is located at a specific path and navigates within that path.
*/
declare class ChildRouter implements Router {
#private;
/**
* Create a new child router.
*
* @param parent The parent router.
* @param mountPath The path this router is mounted at.
* @param path An expression to get the normalized rest path.
*/
constructor(parent: Router, mountPath: string, path: Expression<string>);
get root(): Router;
get parent(): Router | undefined;
get path(): string;
get query(): Query | undefined;
push(path: string, query?: QueryInit): void;
replace(path: string, query?: QueryInit): void;
}
interface HashRouterOptions {
/**
* The current location is parsed when one of these events occur.
*
* @default ["hashchange"]
*/
parseEvents?: string[];
}
/**
* A router that uses `location.hash` as the path ignoring the leading `"#"`.
*
* Everything after the first `"?"` is treated as query parameters.
*/
declare class HashRouter implements Router {
#private;
constructor(options?: HashRouterOptions);
/**
* Called to parse & update this router's state from the current browser location.
*/
parse(): void;
get root(): Router;
get parent(): Router | undefined;
get path(): string;
get query(): Query | undefined;
push(path: string, query?: QueryInit): void;
replace(path: string, query?: QueryInit): void;
}
interface HistoryRouterOptions {
/**
* The current location is parsed when one of these events occur.
*
* @default ["popstate", "rvx:router:update"]
*/
parseEvents?: string[];
/**
* The leading base path to ignore when matching routes.
*
* @default ""
*/
basePath?: string;
}
/**
* A router that uses the history API.
*/
declare class HistoryRouter implements Router {
#private;
constructor(options?: HistoryRouterOptions);
/**
* Called to parse & update this router's state from the current browser location.
*/
parse(): void;
get root(): Router;
get parent(): Router | undefined;
get path(): string;
get query(): Query | undefined;
push(path: string, query?: QueryInit): void;
replace(path: string, query?: QueryInit): void;
}
interface MemoryRouterOptions {
/**
* The initial path.
*/
path?: string;
/**
* The initial query.
*/
query?: QueryInit;
}
/**
* A router that keeps it's state in memory instead of the actual browser location.
*/
declare class MemoryRouter implements Router {
#private;
constructor(options?: MemoryRouterOptions);
get root(): Router;
get parent(): Router | undefined;
get path(): string;
get query(): Query | undefined;
push(path: string, query?: QueryInit): void;
replace(path: string, query?: QueryInit): void;
}
/**
* Normalize a path:
* + Empty paths are represented as an empty string.
* + Non-empty paths start with a slash.
*
* @param path The path to normalize.
* @param preserveDir True to keep trailing slashes in non-empty paths. Default is `true`.
* @returns The normalized path.
*/
declare function normalize(path: string, preserveDir?: boolean): string;
/**
* Join two paths.
*
* Note, that this dosn't handle empty, ".." or "." parts.
*
* @param parent The parent path.
* @param child The child path.
* @param preserveDir True to keep trailing slashes. Default is `true`.
* @returns A {@link normalize normalized} path.
*/
declare function join(parent: string, child: string, preserveDir?: boolean): string;
/**
* Get a normalized relative path.
*
* Note, that this dosn't handle empty, ".." or "." parts, but inserts ".." parts if necessary.
*
* @param from The path from which the relative path starts.
* @param to The path to which the relative path points.
* @param preserveDir True to keep trailing slashes from the `to` path. Trailing slashes from the `from` path are always discarded. Default is `true`.
* @returns A {@link normalize normalized} path.
*/
declare function relative(from: string, to: string, preserveDir?: boolean): string;
interface RouteMatchResult {
/**
* The normalized matched path.
*/
path: string;
/**
* The parameters extracted from the matched path.
*/
params?: unknown;
}
interface RouteMatchFn {
/**
* Check if this route matches the specified path.
*
* @param path The path to match against.
* @returns The match result or undefined if the path doesn't match.
*/
(path: string): RouteMatchResult | undefined;
}
interface Route {
/**
* The paths this route matches.
*/
match?: string | RegExp | RouteMatchFn;
}
interface ParentRouteMatch<T extends Route> {
/**
* The route that has been matched.
*/
route: T;
/**
* The normalized matched path.
*/
path: string;
/**
* The parameters extracted from the matched path.
*/
params?: unknown;
}
interface RouteMatch<T extends Route> extends ParentRouteMatch<T> {
/**
* The normalized remaining rest path.
*/
rest: string;
}
/**
* Find the first matching route.
*
* @param path The {@link normalize normalized} path to match against. Non normalized paths result in undefined behavior.
* @param routes The routes to test in order.
* @returns A match or undefined if none of the routes matched.
*/
declare function matchRoute<T extends Route>(path: string, routes: Iterable<T>): RouteMatch<T> | undefined;
interface WatchedRoutes<T extends Route> {
match: () => ParentRouteMatch<T> | undefined;
rest: () => string;
}
/**
* Watch and match routes against an expression.
*
* @param path The normalized path.
* @param routes The routes to watch.
* @returns An object with individually watchable route match and the unmatched rest path.
*/
declare function watchRoutes<T extends Route>(path: Expression<string>, routes: Expression<Iterable<T>>): WatchedRoutes<T>;
/**
* Props passed to the root component of a {@link ComponentRoute}.
*/
interface RouteProps<P = unknown> {
/** Matched route parameters. */
params: P;
}
/**
* A route where the content is a component to render.
*/
interface ComponentRoute<P = unknown> extends Route {
content: Component<RouteProps<P>>;
}
/**
* Match and render routes in the current context.
*
* A {@link ChildRouter} is injected as a replacement for the current router when rendering route content.
*/
declare function routes(routes: Expression<Iterable<ComponentRoute<any>>>): View;
/**
* Match and render routes in the current context.
*
* A {@link ChildRouter} is injected as a replacement for the current router when rendering route content.
*/
declare function Routes(props: {
/**
* The routes to match.
*/
routes: Expression<Iterable<ComponentRoute<any>>>;
}): View;
export { ChildRouter, HashRouter, HistoryRouter, MemoryRouter, Query, ROUTER, Routes, formatQuery, join, matchRoute, normalize, relative, routes, watchRoutes };
export type { ComponentRoute, HashRouterOptions, HistoryRouterOptions, MemoryRouterOptions, ParentRouteMatch, QueryInit, Route, RouteMatch, RouteMatchFn, RouteMatchResult, RouteProps, Router, WatchedRoutes };