narraleaf-react
Version:
A React visual novel player framework
639 lines (638 loc) • 21.8 kB
TypeScript
import { LiveGameEventToken } from "../../../../game/nlcore/types";
import React from "react";
export declare const RootPath = "/";
export declare class LayoutRouter {
/**
* Get current path
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* console.log(router.getCurrentPath()); // "/home"
*
* router.navigate("/about");
* console.log(router.getCurrentPath()); // "/about"
* ```
*/
getCurrentPath(): string;
/**
* Get pathname (path without query parameters)
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings?tab=general&theme=dark");
* console.log(router.getPathname()); // "/settings"
* ```
*/
getPathname(): string;
/**
* Get current query parameters
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings?tab=general&theme=dark");
* console.log(router.getCurrentQuery()); // { tab: "general", theme: "dark" }
* ```
*/
getCurrentQuery(): Record<string, string>;
/**
* Get query parameters (alias for getCurrentQuery)
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/profile?user=john&tab=info");
* console.log(router.getQueryParams()); // { user: "john", tab: "info" }
* ```
*/
getQueryParams(): Record<string, string>;
/**
* Get current full URL (path + query)
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings", { tab: "general", theme: "dark" });
* console.log(router.getCurrentUrl()); // "/settings?tab=general&theme=dark"
* ```
*/
getCurrentUrl(): string;
/**
* Parse URL into path and query parameters
* @param url URL string, e.g. "/me/settings?a=1&b=2"
* @returns Object with path and query
* @example
* ```typescript
* const router = new LayoutRouter(game);
* const result = router.parseUrl("/me/settings?tab=general&theme=dark");
* console.log(result.path); // "/me/settings"
* console.log(result.query); // { tab: "general", theme: "dark" }
*
* const simple = router.parseUrl("/about");
* console.log(simple.path); // "/about"
* console.log(simple.query); // {}
* ```
*/
parseUrl(url: string): {
path: string;
query: Record<string, string>;
};
/**
* Build URL from path and query parameters
* @param path Path string
* @param query Query parameters object
* @returns Full URL string
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* const url1 = router.buildUrl("/settings", { tab: "general", theme: "dark" });
* console.log(url1); // "/settings?tab=general&theme=dark"
*
* const url2 = router.buildUrl("/about", {});
* console.log(url2); // "/about"
*
* const url3 = router.buildUrl("/profile", { user: "john", tab: "info" });
* console.log(url3); // "/profile?user=john&tab=info"
* ```
*/
buildUrl(path: string, query: Record<string, string>): string;
/**
* Get query parameter value
* @param key Parameter key
* @returns Parameter value or undefined if not found
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings?tab=general&theme=dark");
*
* console.log(router.getQueryParam("tab")); // "general"
* console.log(router.getQueryParam("theme")); // "dark"
* console.log(router.getQueryParam("nonexistent")); // undefined
* ```
*/
getQueryParam(key: string): string | undefined;
/**
* Set query parameter
* @param key Parameter key
* @param value Parameter value
* @example
* ```typescript
* const router = new LayoutRouter(game, "/settings");
*
* router.setQueryParam("tab", "general");
* console.log(router.getCurrentUrl()); // "/settings?tab=general"
*
* router.setQueryParam("theme", "dark");
* console.log(router.getCurrentUrl()); // "/settings?tab=general&theme=dark"
* ```
*/
setQueryParam(key: string, value: string): this;
/**
* Set multiple query parameters
* @param params Object with key-value pairs
* @example
* ```typescript
* const router = new LayoutRouter(game, "/settings");
*
* router.setQueryParams({
* tab: "general",
* theme: "dark",
* lang: "en"
* });
* console.log(router.getCurrentUrl()); // "/settings?tab=general&theme=dark&lang=en"
* ```
*/
setQueryParams(params: Record<string, string>): this;
/**
* Remove query parameter
* @param key Parameter key to remove
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings?tab=general&theme=dark&lang=en");
*
* router.removeQueryParam("theme");
* console.log(router.getCurrentUrl()); // "/settings?tab=general&lang=en"
* ```
*/
removeQueryParam(key: string): this;
/**
* Clear all query parameters
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings?tab=general&theme=dark&lang=en");
*
* router.clearQueryParams();
* console.log(router.getCurrentUrl()); // "/settings"
* console.log(router.getCurrentQuery()); // {}
* ```
*/
clearQueryParams(): this;
/**
* Check if query parameter exists
* @param key Parameter key
* @returns Whether parameter exists
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings?tab=general&theme=dark");
*
* console.log(router.hasQueryParam("tab")); // true
* console.log(router.hasQueryParam("theme")); // true
* console.log(router.hasQueryParam("nonexistent")); // false
* ```
*/
hasQueryParam(key: string): boolean;
/**
* Get all query parameter keys
* @returns Array of parameter keys
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings?tab=general&theme=dark&lang=en");
*
* console.log(router.getQueryParamKeys()); // ["tab", "theme", "lang"]
* ```
*/
getQueryParamKeys(): string[];
/**
* Get query parameter count
* @returns Number of query parameters
* @example
* ```typescript
* const router = new LayoutRouter(game);
* router.navigate("/settings?tab=general&theme=dark&lang=en");
*
* console.log(router.getQueryParamCount()); // 3
*
* router.clearQueryParams();
* console.log(router.getQueryParamCount()); // 0
* ```
*/
getQueryParamCount(): number;
/**
* Get history records
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* router.navigate("/about");
* router.navigate("/contact");
*
* console.log(router.getHistory()); // ["/home", "/about", "/contact"]
* ```
*/
getHistory(): string[];
/**
* Get current history index
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* router.navigate("/about");
* router.navigate("/contact");
*
* console.log(router.getHistoryIndex()); // 2
*
* router.back();
* console.log(router.getHistoryIndex()); // 1
* ```
*/
getHistoryIndex(): number;
/**
* Check if can go back
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* console.log(router.canGoBack()); // false
*
* router.navigate("/about");
* console.log(router.canGoBack()); // true
*
* router.back();
* console.log(router.canGoBack()); // false
* ```
*/
canGoBack(): boolean;
/**
* Check if can go forward
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* router.navigate("/about");
* router.navigate("/contact");
*
* console.log(router.canGoForward()); // false
*
* router.back();
* console.log(router.canGoForward()); // true
*
* router.back();
* console.log(router.canGoForward()); // true
* ```
*/
canGoForward(): boolean;
/**
* Navigate to new path
* @param path Target path, e.g. "/me/settings?a=1&b=2" or "./settings" or "../parent"
* @param queryParams Optional query parameters to append to the path
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
*
* // Navigate to absolute path
* router.navigate("/about");
* console.log(router.getCurrentPath()); // "/about"
*
* // Navigate with query parameters
* router.navigate("/settings", { tab: "general", theme: "dark" });
* console.log(router.getCurrentUrl()); // "/settings?tab=general&theme=dark"
*
* // Navigate to relative path
* router.navigate("./profile");
* console.log(router.getCurrentPath()); // "/profile"
*
* // Navigate to parent directory
* router.navigate("../parent");
* console.log(router.getCurrentPath()); // "/parent"
* ```
*/
navigate(path: string, queryParams?: Record<string, string>): this;
/**
* Go back to previous path
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* router.navigate("/about");
* router.navigate("/contact");
*
* router.back();
* console.log(router.getCurrentPath()); // "/about"
*
* router.back();
* console.log(router.getCurrentPath()); // "/home"
*
* router.back(); // No effect, already at the beginning
* console.log(router.getCurrentPath()); // "/home"
* ```
*/
back(): this;
/**
* Go forward to next path
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* router.navigate("/about");
* router.navigate("/contact");
*
* router.back(); // Go to "/about"
* router.back(); // Go to "/home"
*
* router.forward(); // Go to "/about"
* console.log(router.getCurrentPath()); // "/about"
*
* router.forward(); // Go to "/contact"
* console.log(router.getCurrentPath()); // "/contact"
* ```
*/
forward(): this;
/**
* Replace current path (without adding to history)
* @param path New path, supports relative paths like "./settings" or "../parent"
* @param queryParams Optional query parameters to append to the path
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* router.navigate("/about");
* router.navigate("/contact");
*
* // Replace current path without affecting history
* router.replace("/settings", { tab: "general" });
* console.log(router.getCurrentPath()); // "/settings"
* console.log(router.getCurrentUrl()); // "/settings?tab=general"
*
* // Can still go back to previous paths
* router.back();
* console.log(router.getCurrentPath()); // "/about"
* ```
*/
replace(path: string, queryParams?: Record<string, string>): this;
/**
* Clear history records
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* router.navigate("/about");
* router.navigate("/contact");
*
* router.clear();
* console.log(router.getCurrentPath()); // ""
* console.log(router.getHistory()); // []
* console.log(router.isActive()); // false
* ```
*/
clear(): this;
/**
* Clean history records, keep only current path
* @example
* ```typescript
* const router = new LayoutRouter(game, "/home");
* router.navigate("/about");
* router.navigate("/contact");
*
* router.cleanHistory();
* console.log(router.getHistory()); // ["/contact"]
*
* // Cannot go back anymore
* console.log(router.canGoBack()); // false
* ```
*/
cleanHistory(): this;
/**
* Parse path into segments
* @param path Path string, e.g. "/me/settings/a"
* @returns Path segments array, e.g. ["me", "settings", "a"]
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* console.log(router.parsePath("/me/settings/a")); // ["me", "settings", "a"]
* console.log(router.parsePath("/about")); // ["about"]
* console.log(router.parsePath("/")); // []
* console.log(router.parsePath("")); // []
* ```
*/
parsePath(path: string): string[];
/**
* Build path string
* @param segments Path segments array
* @returns Path string
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* console.log(router.buildPath(["me", "settings", "a"])); // "/me/settings/a"
* console.log(router.buildPath(["about"])); // "/about"
* console.log(router.buildPath([])); // "/"
* ```
*/
buildPath(segments: string[]): string;
/**
* Get parent path of current path
* @param path Current path
* @returns Parent path, returns empty string if no parent
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* console.log(router.getParentPath("/me/settings/a")); // "/me/settings"
* console.log(router.getParentPath("/me/settings")); // "/me"
* console.log(router.getParentPath("/me")); // ""
* console.log(router.getParentPath("/")); // ""
* ```
*/
getParentPath(path: string): string;
/**
* Check if path matches pattern (supports prefix matching for nested layouts)
* @param path Path to check
* @param pattern Match pattern, supports wildcard * and parameters :param
* @returns Whether matches
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* // Exact match
* console.log(router.matchPath("/about", "/about")); // true
* console.log(router.matchPath("/about", "/contact")); // false
*
* // Prefix match (for nested layouts)
* console.log(router.matchPath("/settings/sound", "/settings")); // true
* console.log(router.matchPath("/settings/sound/char", "/settings")); // true
* console.log(router.matchPath("/settings/sound", "/settings/sound")); // true
*
* // Wildcard match
* console.log(router.matchPath("/user/123/profile", "/user/*" + "/profile")); // true
* console.log(router.matchPath("/user/123/settings", "/user/*" + "/profile")); // false
*
* // Parameter match
* console.log(router.matchPath("/user/123/profile", "/user/:id/profile")); // true
* console.log(router.matchPath("/user/abc/profile", "/user/:id/profile")); // true
*
* // Mixed pattern
* console.log(router.matchPath("/user/123/profile/edit", "/user/:id/*" + "/edit")); // true
* ```
*/
matchPath(path: string, pattern: string): boolean;
/**
* Check if path exactly matches pattern (requires exact segment count)
* @param path Path to check
* @param pattern Match pattern, supports wildcard * and parameters :param
* @returns Whether exactly matches
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* // Exact match
* console.log(router.exactMatch("/about", "/about")); // true
* console.log(router.exactMatch("/about", "/contact")); // false
*
* // No prefix matching (unlike matchPath)
* console.log(router.exactMatch("/settings/sound", "/settings")); // false
* console.log(router.exactMatch("/settings", "/settings")); // true
* console.log(router.exactMatch("/settings/sound", "/settings/sound")); // true
*
* // Wildcard match (exact segment count required)
* console.log(router.exactMatch("/user/123/profile", "/user/*" + "/profile")); // true
* console.log(router.exactMatch("/user/123/profile/edit", "/user/*" + "/profile")); // false
*
* // Parameter match (exact segment count required)
* console.log(router.exactMatch("/user/123/profile", "/user/:id/profile")); // true
* console.log(router.exactMatch("/user/123", "/user/:id/profile")); // false
* ```
*/
exactMatch(path: string, pattern: string): boolean;
/**
* Extract path parameters
* @param path Actual path
* @param pattern Pattern with parameters, e.g. "/user/:id/profile/:tab"
* @returns Parameter object
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* const params1 = router.extractParams("/user/123/profile", "/user/:id/profile");
* console.log(params1); // { id: "123" }
*
* const params2 = router.extractParams("/user/456/profile/settings", "/user/:id/profile/:tab");
* console.log(params2); // { id: "456", tab: "settings" }
*
* const params3 = router.extractParams("/about", "/user/:id/profile");
* console.log(params3); // {} (no match)
* ```
*/
extractParams(path: string, pattern: string): Record<string, string>;
/**
* Event listener for exit complete
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* const token = router.onExitComplete(() => {
* console.log("Page exit animation completed");
* // Clean up resources, show loading indicator, etc.
* });
*
* // Later, remove the listener
* token.off();
* ```
*/
onExitComplete(handler: () => void): LiveGameEventToken;
/**
* Event listener for exit complete (once)
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* router.onceExitComplete(() => {
* console.log("Page exit completed, this will only fire once");
* // Perform one-time cleanup
* });
* ```
*/
onceExitComplete(handler: () => void): LiveGameEventToken;
/**
* Event listener for page mount
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* const token = router.onPageMount(() => {
* console.log("New page mounted");
* // Initialize page-specific features, load data, etc.
* });
*
* // Later, remove the listener
* token.off();
* ```
*/
onPageMount(handler: () => void): LiveGameEventToken;
/**
* Event listener for page mount (once)
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* router.oncePageMount(() => {
* console.log("Page mounted, this will only fire once");
* // Perform one-time initialization
* });
* ```
*/
oncePageMount(handler: () => void): LiveGameEventToken;
/**
* Resolve relative path to absolute path
* @param path Path to resolve, can be absolute or relative
* @returns Resolved absolute path
* @example
* ```typescript
* const router = new LayoutRouter(game, "/user/settings");
*
* // Absolute paths
* console.log(router.resolvePath("/about")); // "/about"
* console.log(router.resolvePath("/user/profile")); // "/user/profile"
*
* // Relative paths
* console.log(router.resolvePath("./profile")); // "/user/profile"
* console.log(router.resolvePath("../admin")); // "/admin"
* console.log(router.resolvePath("../../home")); // "/home"
*
* // Complex relative paths
* console.log(router.resolvePath("./.././profile")); // "/profile"
* console.log(router.resolvePath("../../user/./settings")); // "/user/settings"
* ```
*/
resolvePath(path: string): string;
/**
* Normalize path by removing duplicate slashes and trailing slashes
* @param path Path to normalize
* @returns Normalized path
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* console.log(router.normalizePath("/home//about/")); // "/home/about"
* console.log(router.normalizePath("//home//about//")); // "/home/about"
* console.log(router.normalizePath("/home")); // "/home"
* console.log(router.normalizePath("home")); // "home"
* ```
*/
normalizePath(path: string): string;
/**
* Join multiple path segments into a single path
* @param path Base path
* @param paths Additional path segments to join
* @returns Joined and normalized path
* @example
* ```typescript
* const router = new LayoutRouter(game);
*
* // Basic path joining
* console.log(router.joinPath("/home", "about")); // "/home/about"
* console.log(router.joinPath("/user", "profile", "settings")); // "/user/profile/settings"
*
* // Handle paths without leading slash
* console.log(router.joinPath("home", "about")); // "/home/about"
*
* // Handle multiple segments
* console.log(router.joinPath("/api", "v1", "users", "123")); // "/api/v1/users/123"
*
* // Normalize duplicate slashes
* console.log(router.joinPath("/home//", "//about")); // "/home/about"
*
* // Handle empty segments
* console.log(router.joinPath("/home", "", "about")); // "/home/about"
* ```
*/
joinPath(path: string, ...paths: string[]): string;
}
export declare function RouterProvider({ children }: {
children: React.ReactNode;
}): React.JSX.Element;
export declare function useRouter(): LayoutRouter;