rvx
Version:
A signal based rendering library
330 lines (318 loc) • 9.48 kB
TypeScript
/*!
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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;
parent?: Router;
}
/**
* A router that keeps its state in memory instead of the 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;
}
/**
* Match a route against the specified path.
*
* @param path The {@link normalize normalized} path to match against. Non normalized paths result in undefined behavior.
* @param route The route to match.
* @returns A match or undefined if the route doesn't match.
*/
declare function matchRoute<T extends Route>(path: string, route: 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 provided 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 provided 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;
/**
* Check if the specified pattern matches the current router's rest path.
*/
declare function isCurrent(match: Route["match"], router?: Router): boolean;
export { ChildRouter, HashRouter, HistoryRouter, MemoryRouter, Query, ROUTER, Routes, formatQuery, isCurrent, join, matchRoute, normalize, relative, routes, watchRoutes };
export type { ComponentRoute, HashRouterOptions, HistoryRouterOptions, MemoryRouterOptions, ParentRouteMatch, QueryInit, Route, RouteMatch, RouteMatchFn, RouteMatchResult, RouteProps, Router, WatchedRoutes };