waymark 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1404 -7
- package/dist/index.d.ts +196 -4
- package/dist/index.js +1 -4
- package/package.json +27 -15
- package/tsdown.config.ts +8 -0
- package/dist/react/components.d.ts +0 -20
- package/dist/react/components.js +0 -107
- package/dist/react/contexts.d.ts +0 -4
- package/dist/react/contexts.js +0 -3
- package/dist/react/hooks.d.ts +0 -13
- package/dist/react/hooks.js +0 -54
- package/dist/react/index.d.ts +0 -3
- package/dist/react/index.js +0 -3
- package/dist/route.d.ts +0 -27
- package/dist/route.js +0 -57
- package/dist/router/browser-history.d.ts +0 -11
- package/dist/router/browser-history.js +0 -48
- package/dist/router/index.d.ts +0 -3
- package/dist/router/index.js +0 -3
- package/dist/router/memory-history.d.ts +0 -18
- package/dist/router/memory-history.js +0 -39
- package/dist/router/router.d.ts +0 -31
- package/dist/router/router.js +0 -64
- package/dist/utils/index.d.ts +0 -5
- package/dist/utils/index.js +0 -5
- package/dist/utils/misc.d.ts +0 -17
- package/dist/utils/misc.js +0 -27
- package/dist/utils/path.d.ts +0 -9
- package/dist/utils/path.js +0 -19
- package/dist/utils/react.d.ts +0 -10
- package/dist/utils/react.js +0 -50
- package/dist/utils/router.d.ts +0 -37
- package/dist/utils/router.js +0 -1
- package/dist/utils/search.d.ts +0 -3
- package/dist/utils/search.js +0 -31
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,196 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import * as react2 from "react";
|
|
2
|
+
import { AnchorHTMLAttributes, CSSProperties, ComponentType, ReactNode, RefAttributes } from "react";
|
|
3
|
+
import * as regexparam0 from "regexparam";
|
|
4
|
+
import * as type_fest0 from "type-fest";
|
|
5
|
+
import { EmptyObject } from "type-fest";
|
|
6
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
|
+
|
|
8
|
+
//#region src/utils/types.d.ts
|
|
9
|
+
type NormalizePath<P extends string> = RemoveTrailingSlash<DedupSlashes<`/${P}`>>;
|
|
10
|
+
type DedupSlashes<P extends string> = P extends `${infer Prefix}//${infer Rest}` ? `${Prefix}${DedupSlashes<`/${Rest}`>}` : P;
|
|
11
|
+
type RemoveTrailingSlash<P extends string> = P extends `${infer Prefix}/` ? Prefix extends "" ? "/" : Prefix : P;
|
|
12
|
+
type MaybeKey<K extends string, T> = T extends EmptyObject ? { [P in K]?: EmptyObject } : {} extends T ? { [P in K]?: T } : { [P in K]: T };
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/types.d.ts
|
|
15
|
+
interface Register {}
|
|
16
|
+
type RouteList = Register extends {
|
|
17
|
+
routes: infer RouteList extends ReadonlyArray<Route>;
|
|
18
|
+
} ? RouteList : ReadonlyArray<Route>;
|
|
19
|
+
type Handle = Register extends {
|
|
20
|
+
handle: infer Handle;
|
|
21
|
+
} ? Handle : any;
|
|
22
|
+
type Pattern = RouteList[number]["pattern"];
|
|
23
|
+
type GetRoute<P extends Pattern> = Extract<RouteList[number], {
|
|
24
|
+
pattern: P;
|
|
25
|
+
}>;
|
|
26
|
+
type Params<P extends Pattern> = NonNullable<GetRoute<P>["_"]["_params"]>;
|
|
27
|
+
type Search<P extends Pattern> = NonNullable<GetRoute<P>["_"]["_search"]>;
|
|
28
|
+
type MatchOptions<P extends Pattern> = {
|
|
29
|
+
from: P | GetRoute<P>;
|
|
30
|
+
strict?: boolean;
|
|
31
|
+
params?: Partial<Params<P>>;
|
|
32
|
+
};
|
|
33
|
+
type Match<P extends Pattern = Pattern> = {
|
|
34
|
+
route: GetRoute<P>;
|
|
35
|
+
params: Params<P>;
|
|
36
|
+
};
|
|
37
|
+
type NavigateOptions<P extends Pattern> = {
|
|
38
|
+
to: P | GetRoute<P>;
|
|
39
|
+
replace?: boolean;
|
|
40
|
+
state?: any;
|
|
41
|
+
} & MaybeKey<"params", Params<P>> & MaybeKey<"search", Search<P>>;
|
|
42
|
+
interface HistoryPushOptions {
|
|
43
|
+
url: string;
|
|
44
|
+
replace?: boolean;
|
|
45
|
+
state?: any;
|
|
46
|
+
}
|
|
47
|
+
interface HistoryLike {
|
|
48
|
+
getPath: () => string;
|
|
49
|
+
getSearch: () => string;
|
|
50
|
+
getState: () => any;
|
|
51
|
+
go: (delta: number) => void;
|
|
52
|
+
push: (options: HistoryPushOptions) => void;
|
|
53
|
+
subscribe: (listener: () => void) => () => void;
|
|
54
|
+
}
|
|
55
|
+
type Updater<T extends object> = Partial<T> | ((prev: T) => Partial<T>);
|
|
56
|
+
type ComponentLoader = () => Promise<ComponentType | {
|
|
57
|
+
default: ComponentType;
|
|
58
|
+
}>;
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/route.d.ts
|
|
61
|
+
declare function route<P extends string>(pattern: P): Route<NormalizePath<P>, regexparam0.RouteParams<NormalizePath<P>> extends infer T ? { [KeyType in keyof T]: T[KeyType] } : never, {}>;
|
|
62
|
+
declare class Route<P extends string = string, Ps extends {} = any, S extends {} = any> {
|
|
63
|
+
readonly pattern: P;
|
|
64
|
+
readonly _: {
|
|
65
|
+
_params?: Ps;
|
|
66
|
+
_search?: S;
|
|
67
|
+
keys: string[];
|
|
68
|
+
regex: RegExp;
|
|
69
|
+
looseRegex: RegExp;
|
|
70
|
+
weights: number[];
|
|
71
|
+
mapSearch: (search: Record<string, unknown>) => S;
|
|
72
|
+
handles: Handle[];
|
|
73
|
+
components: ComponentType[];
|
|
74
|
+
preloaded: boolean;
|
|
75
|
+
preloaders: (() => Promise<any>)[];
|
|
76
|
+
};
|
|
77
|
+
constructor(pattern: P, mapSearch: (search: Record<string, unknown>) => S, handles: Handle[], components: ComponentType[], preloaders: (() => Promise<any>)[]);
|
|
78
|
+
route<P2 extends string>(subPattern: P2): Route<NormalizePath<`${P}/${P2}`>, regexparam0.RouteParams<NormalizePath<`${P}/${P2}`>> extends infer T ? { [KeyType in keyof T]: T[KeyType] } : never, S>;
|
|
79
|
+
search<S2 extends {}>(mapper: ((search: S & Record<string, unknown>) => S2) | StandardSchemaV1<S & Record<string, unknown>, S2>): Route<P, Ps, (type_fest0.PickIndexSignature<S> extends infer T_1 ? { [Key in keyof T_1 as Key extends keyof type_fest0.PickIndexSignature<{ [K in keyof S2 as undefined extends S2[K] ? never : K]: S2[K] } & { [K_1 in keyof S2 as undefined extends S2[K_1] ? K_1 : never]?: S2[K_1] | undefined } extends infer T_2 ? { [KeyType_1 in keyof T_2]: T_2[KeyType_1] } : never> ? never : Key]: T_1[Key] } : never) & type_fest0.PickIndexSignature<{ [K in keyof S2 as undefined extends S2[K] ? never : K]: S2[K] } & { [K_1 in keyof S2 as undefined extends S2[K_1] ? K_1 : never]?: S2[K_1] | undefined } extends infer T_2 ? { [KeyType_1 in keyof T_2]: T_2[KeyType_1] } : never> & (type_fest0.OmitIndexSignature<S> extends infer T_3 ? { [Key_1 in keyof T_3 as Key_1 extends keyof type_fest0.OmitIndexSignature<{ [K in keyof S2 as undefined extends S2[K] ? never : K]: S2[K] } & { [K_1 in keyof S2 as undefined extends S2[K_1] ? K_1 : never]?: S2[K_1] | undefined } extends infer T_4 ? { [KeyType_1 in keyof T_4]: T_4[KeyType_1] } : never> ? never : Key_1]: T_3[Key_1] } : never) & type_fest0.OmitIndexSignature<{ [K in keyof S2 as undefined extends S2[K] ? never : K]: S2[K] } & { [K_1 in keyof S2 as undefined extends S2[K_1] ? K_1 : never]?: S2[K_1] | undefined } extends infer T_4 ? { [KeyType_1 in keyof T_4]: T_4[KeyType_1] } : never> extends infer T ? { [KeyType in keyof T]: T[KeyType] } : never>;
|
|
80
|
+
handle(handle: Handle): Route<P, Ps, S>;
|
|
81
|
+
preloader(preloader: () => Promise<any>): Route<P, Ps, S>;
|
|
82
|
+
component(component: ComponentType): Route<P, Ps, S>;
|
|
83
|
+
lazy(loader: ComponentLoader): Route<P, Ps, S>;
|
|
84
|
+
suspense(fallback: ComponentType): Route<P, Ps, S>;
|
|
85
|
+
error(fallback: ComponentType<{
|
|
86
|
+
error: unknown;
|
|
87
|
+
}>): Route<P, Ps, S>;
|
|
88
|
+
preload(): Promise<void>;
|
|
89
|
+
toString(): P;
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/react/components.d.ts
|
|
93
|
+
type RouterRootProps = RouterOptions | {
|
|
94
|
+
router: Router;
|
|
95
|
+
};
|
|
96
|
+
declare function RouterRoot(props: RouterRootProps): ReactNode;
|
|
97
|
+
declare function Outlet(): ReactNode;
|
|
98
|
+
type NavigateProps<P extends Pattern> = NavigateOptions<P>;
|
|
99
|
+
declare function Navigate<P extends Pattern>(props: NavigateProps<P>): null;
|
|
100
|
+
type LinkProps<P extends Pattern> = NavigateOptions<P> & LinkOptions & AnchorHTMLAttributes<HTMLAnchorElement> & RefAttributes<HTMLAnchorElement> & {
|
|
101
|
+
asChild?: boolean;
|
|
102
|
+
};
|
|
103
|
+
interface LinkOptions {
|
|
104
|
+
strict?: boolean;
|
|
105
|
+
preload?: "intent" | "render" | "viewport" | false;
|
|
106
|
+
style?: CSSProperties;
|
|
107
|
+
className?: string;
|
|
108
|
+
activeStyle?: CSSProperties;
|
|
109
|
+
activeClassName?: string;
|
|
110
|
+
}
|
|
111
|
+
declare function Link<P extends Pattern>(props: LinkProps<P>): ReactNode;
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/react/hooks.d.ts
|
|
114
|
+
declare function useRouter(): Router;
|
|
115
|
+
declare function useHandles(): Handle[];
|
|
116
|
+
declare function useOutlet(): react2.ReactNode;
|
|
117
|
+
declare function useSubscribe<T>(router: Router, getSnapshot: () => T): T;
|
|
118
|
+
declare function useNavigate(): <P extends Pattern>(options: number | HistoryPushOptions | NavigateOptions<P>) => void;
|
|
119
|
+
declare function useLocation(): {
|
|
120
|
+
path: string;
|
|
121
|
+
search: Record<string, unknown>;
|
|
122
|
+
state: any;
|
|
123
|
+
};
|
|
124
|
+
declare function useMatch<P extends Pattern>(options: MatchOptions<P>): Match<P> | null;
|
|
125
|
+
declare function useParams<P extends Pattern>(from: P | GetRoute<P>): Params<P>;
|
|
126
|
+
declare function useSearch<P extends Pattern>(from: P | GetRoute<P>): readonly [Search<P>, (update: Updater<Search<P>>, replace?: boolean) => void];
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/react/contexts.d.ts
|
|
129
|
+
declare const RouterContext: react2.Context<Router | null>;
|
|
130
|
+
declare const MatchContext: react2.Context<Match | null>;
|
|
131
|
+
declare const OutletContext: react2.Context<ReactNode>;
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/router/router.d.ts
|
|
134
|
+
interface RouterOptions {
|
|
135
|
+
basePath?: string;
|
|
136
|
+
routes: RouteList;
|
|
137
|
+
history?: HistoryLike;
|
|
138
|
+
defaultLinkOptions?: LinkOptions;
|
|
139
|
+
}
|
|
140
|
+
declare class Router {
|
|
141
|
+
readonly basePath: string;
|
|
142
|
+
readonly routes: RouteList;
|
|
143
|
+
readonly history: HistoryLike;
|
|
144
|
+
readonly defaultLinkOptions?: LinkOptions;
|
|
145
|
+
readonly _: {
|
|
146
|
+
routeMap: Map<string, Route>;
|
|
147
|
+
};
|
|
148
|
+
constructor(options: RouterOptions);
|
|
149
|
+
getRoute<P extends Pattern>(pattern: P | GetRoute<P>): GetRoute<P>;
|
|
150
|
+
match<P extends Pattern>(path: string, options: MatchOptions<P>): Match<P> | null;
|
|
151
|
+
matchAll(path: string): Match | null;
|
|
152
|
+
createUrl<P extends Pattern>(options: NavigateOptions<P>): string;
|
|
153
|
+
navigate<P extends Pattern>(options: NavigateOptions<P> | HistoryPushOptions | number): void;
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/router/browser-history.d.ts
|
|
157
|
+
declare class BrowserHistory implements HistoryLike {
|
|
158
|
+
private static patchKey;
|
|
159
|
+
constructor();
|
|
160
|
+
getPath: () => string;
|
|
161
|
+
getSearch: () => string;
|
|
162
|
+
getState: () => any;
|
|
163
|
+
go: (delta: number) => void;
|
|
164
|
+
push: (options: HistoryPushOptions) => void;
|
|
165
|
+
subscribe: (listener: () => void) => () => void;
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/router/memory-history.d.ts
|
|
169
|
+
interface MemoryLocation {
|
|
170
|
+
path: string;
|
|
171
|
+
search: string;
|
|
172
|
+
state: any;
|
|
173
|
+
}
|
|
174
|
+
declare class MemoryHistory implements HistoryLike {
|
|
175
|
+
private stack;
|
|
176
|
+
private index;
|
|
177
|
+
private listeners;
|
|
178
|
+
constructor(url?: string);
|
|
179
|
+
private getCurrent;
|
|
180
|
+
getPath: () => string;
|
|
181
|
+
getSearch: () => string;
|
|
182
|
+
getState: () => any;
|
|
183
|
+
go: (delta: number) => void;
|
|
184
|
+
push: (options: HistoryPushOptions) => void;
|
|
185
|
+
subscribe: (listener: () => void) => () => void;
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
188
|
+
//#region src/router/hash-history.d.ts
|
|
189
|
+
declare class HashHistory extends BrowserHistory {
|
|
190
|
+
private getHashUrl;
|
|
191
|
+
getPath: () => string;
|
|
192
|
+
getSearch: () => string;
|
|
193
|
+
push: (options: HistoryPushOptions) => void;
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
export { BrowserHistory, ComponentLoader, GetRoute, Handle, HashHistory, HistoryLike, HistoryPushOptions, Link, LinkOptions, LinkProps, Match, MatchContext, MatchOptions, MemoryHistory, MemoryLocation, Navigate, NavigateOptions, NavigateProps, Outlet, OutletContext, Params, Pattern, Register, Route, RouteList, Router, RouterContext, RouterOptions, RouterRoot, RouterRootProps, Search, Updater, route, useHandles, useLocation, useMatch, useNavigate, useOutlet, useParams, useRouter, useSearch, useSubscribe };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export * from "./router";
|
|
3
|
-
export * from "./react";
|
|
4
|
-
export * from "./utils/router";
|
|
1
|
+
import{Component as e,Suspense as t,cloneElement as n,createContext as r,isValidElement as i,lazy as a,memo as o,useCallback as s,useContext as c,useEffect as l,useLayoutEffect as u,useMemo as d,useRef as ee,useState as f,useSyncExternalStore as p}from"react";import{inject as m,parse as h}from"regexparam";import{jsx as g}from"react/jsx-runtime";function _(e){return`/${e}`.replaceAll(/\/+/g,`/`).replace(/(.+)\/$/,`$1`)}function v(e){return e.split(`/`).slice(1).map(e=>e.includes(`*`)?0:e.includes(`:`)?1:2)}function y(e){return typeof e==`function`?e:t=>{let n=e[`~standard`].validate(t);if(n instanceof Promise)throw Error(`[Waymark] Validation must be synchronous`);if(n.issues)throw Error(`[Waymark] Validation failed`,{cause:n.issues});return n.value}}function b(e){return e.startsWith(`?`)?e.slice(1):e}function x(e){return Object.entries(e).filter(([e,t])=>t!==void 0).map(([e,t])=>`${e}=${encodeURIComponent(C(t))}`).join(`&`)}function S(e){let t=new URLSearchParams(e);return Object.fromEntries([...t.entries()].map(([e,t])=>(t=decodeURIComponent(t),[e,w(t)?JSON.parse(t):t])))}function C(e){return typeof e==`string`&&!w(e)?e:JSON.stringify(e)}function w(e){try{return JSON.parse(e),!0}catch{return!1}}function T(e,t){return _(`${t}/${e}`)}function E(e,t){return(e===t||e.startsWith(`${t}/`))&&(e=e.slice(t.length)||`/`),e}function D(e,t){return[e,x(t)].filter(Boolean).join(`?`)}function O(e){let{pathname:t,search:n}=new URL(e,`http://w`);return{path:t,search:b(n)}}function k(e,t,n,r){let i=e.exec(E(n,r));if(!i)return null;let a={};return t.forEach((e,t)=>{let n=i[t+1];n&&(a[e]=n)}),a}function A(e){return[...e].sort((e,t)=>{let n=e.route._.weights,r=t.route._.weights,i=Math.max(n.length,r.length);for(let e=0;e<i;e++){let t=n[e]??-1,i=r[e]??-1;if(t!==i)return i-t}return 0})}const j=r(null),M=r(null),N=r(null);function P(){let e=c(j);if(!e)throw Error(`[Waymark] useRouter must be used within a router context`);return e}function F(){let e=c(M);return d(()=>e?.route._.handles??[],[e])}function I(){return c(N)}function L(e,t){return p(e.history.subscribe,t,t)}function R(){let e=P();return d(()=>e.navigate.bind(e),[e])}function z(){let e=P(),t=L(e,e.history.getPath),n=L(e,e.history.getSearch),r=L(e,e.history.getState);return d(()=>({path:t,search:S(n),state:r}),[t,n,r])}function B(e){let t=P(),n=L(t,t.history.getPath);return d(()=>t.match(n,e),[t,n,e])}function te(e){let t=B({from:e});if(!t)throw Error(`[Waymark] Can't read params for non-matching route: ${e}`);return t.params}function ne(e){let t=B({from:e});if(!t)throw Error(`[Waymark] Can't read search for non-matching route: ${e}`);let n=s(e=>t.route._.mapSearch(S(e)),[t.route]),r=P(),i=L(r,r.history.getSearch);return[d(()=>n(i),[n,i]),s((e,t)=>{let i=n(r.history.getSearch());e=typeof e==`function`?e(i):e;let a=D(r.history.getPath(),{...i,...e});r.navigate({url:a,replace:t})},[r,n])]}var V=class e{static patchKey=Symbol.for(`waymark_history_patch_v01`);constructor(){if(typeof history<`u`&&!Object.hasOwn(window,e.patchKey)){for(let e of[H,U]){let t=history[e];history[e]=function(...n){let r=t.apply(this,n),i=new Event(e);return i.arguments=n,dispatchEvent(i),r}}Object.assign(window,{[e.patchKey]:!0})}}getPath=()=>location.pathname;getSearch=()=>b(location.search);getState=()=>history.state;go=e=>history.go(e);push=e=>{let{url:t,replace:n,state:r}=e;history[n?U:H](r,``,t)};subscribe=e=>(W.forEach(t=>window.addEventListener(t,e)),()=>{W.forEach(t=>window.removeEventListener(t,e))})};const H=`pushState`,U=`replaceState`,W=[`popstate`,H,U,`hashchange`];var G=class{basePath;routes;history;defaultLinkOptions;_;constructor(e){let{basePath:t=`/`,routes:n,history:r,defaultLinkOptions:i}=e;this.basePath=_(t),this.routes=n,this.history=r??new V,this.defaultLinkOptions=i,this._={routeMap:new Map(n.map(e=>[e.pattern,e]))}}getRoute(e){if(typeof e!=`string`)return e;let t=this._.routeMap.get(e);if(!t)throw Error(`[Waymark] Route not found for pattern: ${e}`);return t}match(e,t){let{from:n,strict:r,params:i}=t,a=this.getRoute(n),o=k(r?a._.regex:a._.looseRegex,a._.keys,e,this.basePath);return!o||i&&Object.keys(i).some(e=>i[e]!==o[e])?null:{route:a,params:o}}matchAll(e){return A(this.routes.map(t=>this.match(e,{from:t,strict:!0})).filter(e=>!!e))[0]??null}createUrl(e){let{to:t,params:n={},search:r={}}=e,{pattern:i}=this.getRoute(t);return D(T(m(i,n),this.basePath),r)}navigate(e){if(typeof e==`number`)this.history.go(e);else if(`url`in e)this.history.push(e);else{let{replace:t,state:n}=e;this.history.push({url:this.createUrl(e),replace:t,state:n})}}},K=class{stack=[];index=0;listeners=new Set;constructor(e=`/`){this.stack.push({...O(e),state:void 0})}getCurrent=()=>this.stack[this.index];getPath=()=>this.getCurrent().path;getSearch=()=>this.getCurrent().search;getState=()=>this.getCurrent().state;go=e=>{let t=this.index+e;this.stack[t]&&(this.index=t,this.listeners.forEach(e=>e()))};push=e=>{let{url:t,replace:n,state:r}=e,i={...O(t),state:r};this.stack=this.stack.slice(0,this.index+1),n?this.stack[this.index]=i:this.index=this.stack.push(i)-1,this.listeners.forEach(e=>e())};subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)})},q=class extends V{getHashUrl=()=>location.hash.slice(1)||`/`;getPath=()=>O(this.getHashUrl()).path;getSearch=()=>O(this.getHashUrl()).search;push=e=>{let{url:t,replace:n,state:r}=e;history[n?`replaceState`:`pushState`](r,``,`#${t}`)}};function J(e){let[t]=f(()=>`router`in e?e.router:new G(e)),n=L(t,t.history.getPath),r=d(()=>t.matchAll(n),[t,n]);return r||console.error(`[Waymark] No matching route found for path:`,n),d(()=>g(j.Provider,{value:t,children:g(M.Provider,{value:r,children:r?.route._.components.reduceRight((e,t)=>g(N.Provider,{value:e,children:g(t,{})}),null)})}),[t,r])}function Y(){return I()}function X(e){let t=R();return u(()=>t(e),[]),null}function Z(e){let t=P(),{to:r,replace:a,state:o,params:s,search:c,strict:u,preload:f,style:p,className:m,activeStyle:h,activeClassName:_,asChild:v,children:y,...b}={...t.defaultLinkOptions,...e},x=ee(null),S=t.createUrl(e),C=d(()=>t.getRoute(e.to),[t,e.to]),w=!!B({from:C,strict:u,params:s}),T=d(()=>({"data-active":w,style:{...p,...w&&h},className:[m,w&&_].filter(Boolean).join(` `)||void 0}),[w,p,m,h,_]);l(()=>{if(f===`render`)C.preload();else if(f===`viewport`&&x.current){let e=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting&&(C.preload(),e.disconnect())})});return e.observe(x.current),()=>e.disconnect()}},[f,C]);let E=e=>{b.onClick?.(e),!(e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||e.button!==0||e.defaultPrevented)&&(e.preventDefault(),t.navigate({url:S,replace:a,state:o}))},D=e=>{b.onFocus?.(e),f===`intent`&&!e.defaultPrevented&&C.preload()},O=e=>{b.onPointerEnter?.(e),f===`intent`&&!e.defaultPrevented&&C.preload()},k={...b,...T,ref:re(b.ref,x),href:S,onClick:E,onFocus:D,onPointerEnter:O};return v&&i(y)?n(y,k):g(`a`,{...k,children:y})}function re(...e){let t=e.filter(e=>!!e);return t.length<=1?t[0]??null:e=>{let n=[];for(let r of t){let t=Q(r,e);n.push(t??(()=>Q(r,null)))}return()=>n.forEach(e=>e())}}function Q(e,t){if(typeof e==`function`)return e(t);e&&(e.current=t)}function ie(e){return()=>g(t,{fallback:g(e,{}),children:I()})}function ae(t){class n extends e{constructor(e){super(e),this.state={children:e.children,error:null}}static getDerivedStateFromError(e){return{error:[e]}}static getDerivedStateFromProps(e,t){return e.children===t.children?t:{children:e.children,error:null}}render(){return this.state.error?g(t,{error:this.state.error[0]}):this.props.children}}return()=>g(n,{children:I()})}function oe(e){return new $(_(e),e=>e,[],[],[])}var $=class e{pattern;_;constructor(e,t,n,r,i){let{keys:a,pattern:o}=h(e),s=h(e,!0).pattern,c=v(e);this.pattern=e,this._={keys:a,regex:o,looseRegex:s,weights:c,mapSearch:t,handles:n,components:r,preloaded:!1,preloaders:i}}route(t){let{mapSearch:n,handles:r,components:i,preloaders:a}=this._;return new e(_(`${this.pattern}/${t}`),n,r,i,a)}search(t){let{mapSearch:n,handles:r,components:i,preloaders:a}=this._;return t=y(t),new e(this.pattern,e=>{let r=n(e);return{...r,...t(r)}},r,i,a)}handle(t){let{mapSearch:n,handles:r,components:i,preloaders:a}=this._;return new e(this.pattern,n,[...r,t],i,a)}preloader(t){let{mapSearch:n,handles:r,components:i,preloaders:a}=this._;return new e(this.pattern,n,r,i,[...a,t])}component(t){let{mapSearch:n,handles:r,components:i,preloaders:a}=this._;return new e(this.pattern,n,r,[...i,o(t)],a)}lazy(e){let t=a(async()=>{let t=await e();return{default:o(`default`in t?t.default:t)}});return this.preloader(e).component(t)}suspense(e){return this.component(ie(e))}error(e){return this.component(ae(e))}async preload(){let{preloaded:e,preloaders:t}=this._;e||(this._.preloaded=!0,await Promise.all(t.map(e=>e())))}toString(){return this.pattern}};export{V as BrowserHistory,q as HashHistory,Z as Link,M as MatchContext,K as MemoryHistory,X as Navigate,Y as Outlet,N as OutletContext,$ as Route,G as Router,j as RouterContext,J as RouterRoot,oe as route,F as useHandles,z as useLocation,B as useMatch,R as useNavigate,I as useOutlet,te as useParams,P as useRouter,ne as useSearch,L as useSubscribe};
|
package/package.json
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waymark",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"author": "strblr",
|
|
6
|
+
"description": "Lightweight type-safe router for React",
|
|
5
7
|
"type": "module",
|
|
6
8
|
"main": "dist/index.js",
|
|
7
9
|
"types": "dist/index.d.ts",
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"default": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
10
16
|
"repository": {
|
|
11
17
|
"type": "git",
|
|
12
18
|
"url": "https://github.com/strblr/waymark"
|
|
@@ -16,33 +22,39 @@
|
|
|
16
22
|
"keywords": [
|
|
17
23
|
"react",
|
|
18
24
|
"router",
|
|
19
|
-
"wouter",
|
|
20
25
|
"typescript",
|
|
21
26
|
"type",
|
|
22
27
|
"typed",
|
|
28
|
+
"strongly-typed",
|
|
29
|
+
"type-safe",
|
|
23
30
|
"navigate",
|
|
24
31
|
"navigation",
|
|
32
|
+
"route",
|
|
33
|
+
"history",
|
|
25
34
|
"search",
|
|
26
35
|
"params",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
36
|
+
"simple",
|
|
37
|
+
"tiny",
|
|
38
|
+
"lightweight",
|
|
39
|
+
"minimal"
|
|
30
40
|
],
|
|
31
41
|
"scripts": {
|
|
32
|
-
"build": "
|
|
33
|
-
"
|
|
42
|
+
"build": "tsdown --minify --platform browser",
|
|
43
|
+
"copy-readme": "cp ../../README.md README.md",
|
|
44
|
+
"prepublishOnly": "bun run build && bun run copy-readme"
|
|
34
45
|
},
|
|
35
46
|
"devDependencies": {
|
|
36
|
-
"@
|
|
37
|
-
"@types/
|
|
38
|
-
"
|
|
39
|
-
"type-fest": "^5.4.1",
|
|
47
|
+
"@types/bun": "^1.3.6",
|
|
48
|
+
"@types/react": "^19.2.9",
|
|
49
|
+
"tsdown": "^0.20.1",
|
|
40
50
|
"typescript": "^5.9.3"
|
|
41
51
|
},
|
|
42
52
|
"peerDependencies": {
|
|
43
53
|
"react": ">=18"
|
|
44
54
|
},
|
|
45
55
|
"dependencies": {
|
|
46
|
-
"
|
|
56
|
+
"@standard-schema/spec": "^1.1.0",
|
|
57
|
+
"regexparam": "^3.0.0",
|
|
58
|
+
"type-fest": "^5.4.1"
|
|
47
59
|
}
|
|
48
60
|
}
|
package/tsdown.config.ts
ADDED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type ReactNode, type AnchorHTMLAttributes, type CSSProperties, type RefAttributes } from "react";
|
|
2
|
-
import { Router, type RouterOptions } from "../router";
|
|
3
|
-
import { type Patterns, type NavigateOptions } from "../utils";
|
|
4
|
-
export type RouterRootProps = RouterOptions | {
|
|
5
|
-
router: Router;
|
|
6
|
-
};
|
|
7
|
-
export declare function RouterRoot(props: RouterRootProps): ReactNode;
|
|
8
|
-
export declare function Outlet(): ReactNode;
|
|
9
|
-
export type NavigateProps<P extends Patterns> = NavigateOptions<P>;
|
|
10
|
-
export declare function Navigate<P extends Patterns>(props: NavigateProps<P>): null;
|
|
11
|
-
export type LinkProps<P extends Patterns> = NavigateOptions<P> & LinkOptions & AnchorHTMLAttributes<HTMLAnchorElement> & RefAttributes<HTMLAnchorElement> & {
|
|
12
|
-
asChild?: boolean;
|
|
13
|
-
};
|
|
14
|
-
export interface LinkOptions {
|
|
15
|
-
preload?: "intent" | "render" | "viewport" | false;
|
|
16
|
-
active?: (currentPath: string, targetPath: string) => boolean;
|
|
17
|
-
activeStyle?: CSSProperties;
|
|
18
|
-
activeClassName?: string;
|
|
19
|
-
}
|
|
20
|
-
export declare function Link<P extends Patterns>(props: LinkProps<P>): ReactNode;
|
package/dist/react/components.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { useMemo, useState, useLayoutEffect, useRef, useEffect, createElement, isValidElement, cloneElement } from "react";
|
|
2
|
-
import { routerContext, outletContext } from "./contexts";
|
|
3
|
-
import { useRouter, useOutlet, _useSubscribe } from "./hooks";
|
|
4
|
-
import { Router } from "../router";
|
|
5
|
-
import { getHref, mergeRefs, defaultLinkActive } from "../utils";
|
|
6
|
-
export function RouterRoot(props) {
|
|
7
|
-
const [router] = useState(() => "router" in props ? props.router : new Router(props));
|
|
8
|
-
const path = _useSubscribe(router, router.history.getPath);
|
|
9
|
-
const route = useMemo(() => router.matchPath(path), [router, path]);
|
|
10
|
-
if (!route) {
|
|
11
|
-
console.error("[Waymark] No route found for path:", path);
|
|
12
|
-
}
|
|
13
|
-
return useMemo(() => {
|
|
14
|
-
return createElement(routerContext.Provider, { value: router }, route?._.components.reduceRight((acc, comp) => createElement(outletContext.Provider, { value: acc }, createElement(comp)), null));
|
|
15
|
-
}, [router, route]);
|
|
16
|
-
}
|
|
17
|
-
// Outlet
|
|
18
|
-
export function Outlet() {
|
|
19
|
-
return useOutlet();
|
|
20
|
-
}
|
|
21
|
-
export function Navigate(props) {
|
|
22
|
-
const router = useRouter();
|
|
23
|
-
useLayoutEffect(() => router.navigate(props), []);
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
export function Link(props) {
|
|
27
|
-
const ref = useRef(null);
|
|
28
|
-
const router = useRouter();
|
|
29
|
-
const { path, search } = router.composePath(props);
|
|
30
|
-
const currentPath = _useSubscribe(router, router.history.getPath);
|
|
31
|
-
const route = useMemo(() => router.matchPath(path), [router, path]);
|
|
32
|
-
const { to, replace, state, params, search: search_, preload, active, activeStyle, activeClassName, asChild, style, className, children, ...rest } = {
|
|
33
|
-
active: defaultLinkActive,
|
|
34
|
-
...router.defaultLinkOptions,
|
|
35
|
-
...props
|
|
36
|
-
};
|
|
37
|
-
const activeProps = useMemo(() => {
|
|
38
|
-
const isActive = active(currentPath, path);
|
|
39
|
-
return {
|
|
40
|
-
["data-active"]: isActive,
|
|
41
|
-
style: { ...style, ...(isActive && activeStyle) },
|
|
42
|
-
className: [className, isActive && activeClassName].filter(Boolean).join(" ") ||
|
|
43
|
-
undefined
|
|
44
|
-
};
|
|
45
|
-
}, [
|
|
46
|
-
active,
|
|
47
|
-
path,
|
|
48
|
-
currentPath,
|
|
49
|
-
style,
|
|
50
|
-
className,
|
|
51
|
-
activeStyle,
|
|
52
|
-
activeClassName
|
|
53
|
-
]);
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
if (preload === "render") {
|
|
56
|
-
route?.preload();
|
|
57
|
-
}
|
|
58
|
-
else if (preload === "viewport" && ref.current) {
|
|
59
|
-
const observer = new IntersectionObserver(entries => {
|
|
60
|
-
entries.forEach(entry => {
|
|
61
|
-
if (entry.isIntersecting) {
|
|
62
|
-
route?.preload();
|
|
63
|
-
observer.disconnect();
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
observer.observe(ref.current);
|
|
68
|
-
return () => observer.disconnect();
|
|
69
|
-
}
|
|
70
|
-
}, [preload, route]);
|
|
71
|
-
const onClick = (event) => {
|
|
72
|
-
rest.onClick?.(event);
|
|
73
|
-
if (event.ctrlKey ||
|
|
74
|
-
event.metaKey ||
|
|
75
|
-
event.shiftKey ||
|
|
76
|
-
event.altKey ||
|
|
77
|
-
event.button !== 0 ||
|
|
78
|
-
event.defaultPrevented)
|
|
79
|
-
return;
|
|
80
|
-
event.preventDefault();
|
|
81
|
-
router.history.push({ path, search, replace, state });
|
|
82
|
-
};
|
|
83
|
-
const onFocus = (event) => {
|
|
84
|
-
rest.onFocus?.(event);
|
|
85
|
-
if (preload === "intent" && !event.defaultPrevented) {
|
|
86
|
-
route?.preload();
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
const onPointerEnter = (event) => {
|
|
90
|
-
rest.onPointerEnter?.(event);
|
|
91
|
-
if (preload === "intent" && !event.defaultPrevented) {
|
|
92
|
-
route?.preload();
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
const anchorProps = {
|
|
96
|
-
...rest,
|
|
97
|
-
...activeProps,
|
|
98
|
-
ref: mergeRefs(rest.ref, ref),
|
|
99
|
-
href: getHref(path, search),
|
|
100
|
-
onClick,
|
|
101
|
-
onFocus,
|
|
102
|
-
onPointerEnter
|
|
103
|
-
};
|
|
104
|
-
return asChild && isValidElement(children)
|
|
105
|
-
? cloneElement(children, anchorProps)
|
|
106
|
-
: createElement("a", { ...anchorProps, children });
|
|
107
|
-
}
|
package/dist/react/contexts.d.ts
DELETED
package/dist/react/contexts.js
DELETED
package/dist/react/hooks.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Router } from "../router";
|
|
2
|
-
import type { Routes, RouteSearch, Updater } from "../utils";
|
|
3
|
-
export declare function useRouter(): Router;
|
|
4
|
-
export declare function useOutlet(): import("react").ReactNode;
|
|
5
|
-
export declare function useLocation(): {
|
|
6
|
-
path: string;
|
|
7
|
-
search: URLSearchParams;
|
|
8
|
-
state: any;
|
|
9
|
-
};
|
|
10
|
-
export declare function useNavigate(): <P extends import("..").Patterns>(options: number | import("..").NavigateOptions<P>) => void;
|
|
11
|
-
export declare function useParams<R extends Routes>(route: R): import("..").RouteParams<R>;
|
|
12
|
-
export declare function useSearch<R extends Routes>(route: R): readonly [RouteSearch<R>, (update: Updater<RouteSearch<R>>, replace?: boolean) => void];
|
|
13
|
-
export declare function _useSubscribe<T>(router: Router, getSnapshot: () => T): T;
|
package/dist/react/hooks.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { useCallback, useContext, useMemo, useSyncExternalStore } from "react";
|
|
2
|
-
import { outletContext, routerContext } from "./contexts";
|
|
3
|
-
// useRouter
|
|
4
|
-
export function useRouter() {
|
|
5
|
-
const router = useContext(routerContext);
|
|
6
|
-
if (!router) {
|
|
7
|
-
throw new Error("[Waymark] useRouter must be used within a router context");
|
|
8
|
-
}
|
|
9
|
-
return router;
|
|
10
|
-
}
|
|
11
|
-
// useOutlet
|
|
12
|
-
export function useOutlet() {
|
|
13
|
-
return useContext(outletContext);
|
|
14
|
-
}
|
|
15
|
-
// useLocation
|
|
16
|
-
export function useLocation() {
|
|
17
|
-
const router = useRouter();
|
|
18
|
-
const path = _useSubscribe(router, router.history.getPath);
|
|
19
|
-
const search = _useSubscribe(router, router.history.getSearch);
|
|
20
|
-
const state = _useSubscribe(router, router.history.getState);
|
|
21
|
-
return useMemo(() => ({ path, search: new URLSearchParams(search), state }), [path, search, state]);
|
|
22
|
-
}
|
|
23
|
-
// useNavigate
|
|
24
|
-
export function useNavigate() {
|
|
25
|
-
const router = useRouter();
|
|
26
|
-
return useMemo(() => router.navigate.bind(router), [router]);
|
|
27
|
-
}
|
|
28
|
-
// useParams
|
|
29
|
-
export function useParams(route) {
|
|
30
|
-
const router = useRouter();
|
|
31
|
-
const path = _useSubscribe(router, router.history.getPath);
|
|
32
|
-
return useMemo(() => router.decomposePath(route, path, router.history.getSearch()).params, [router, route, path]);
|
|
33
|
-
}
|
|
34
|
-
// useSearch
|
|
35
|
-
export function useSearch(route) {
|
|
36
|
-
const router = useRouter();
|
|
37
|
-
const search = _useSubscribe(router, router.history.getSearch);
|
|
38
|
-
const parsed = useMemo(() => router.decomposePath(route, router.history.getPath(), search).search, [router, route, search]);
|
|
39
|
-
const setSearch = useCallback((update, replace) => {
|
|
40
|
-
const { params, search } = router.decomposePath(route, router.history.getPath(), router.history.getSearch());
|
|
41
|
-
update = typeof update === "function" ? update(search) : update;
|
|
42
|
-
router.navigate({
|
|
43
|
-
to: route._.pattern,
|
|
44
|
-
params,
|
|
45
|
-
search: { ...search, ...update },
|
|
46
|
-
replace
|
|
47
|
-
});
|
|
48
|
-
}, [router, route]);
|
|
49
|
-
return [parsed, setSearch];
|
|
50
|
-
}
|
|
51
|
-
// _useSubscribe
|
|
52
|
-
export function _useSubscribe(router, getSnapshot) {
|
|
53
|
-
return useSyncExternalStore(router.history.subscribe, getSnapshot, getSnapshot);
|
|
54
|
-
}
|
package/dist/react/index.d.ts
DELETED
package/dist/react/index.js
DELETED
package/dist/route.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { type ComponentType } from "react";
|
|
2
|
-
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
-
import { type NormalizePath, type ComponentLoader } from "./utils";
|
|
4
|
-
export declare class Route<P extends string, Ps extends {}, S extends {}> {
|
|
5
|
-
_: {
|
|
6
|
-
pattern: P;
|
|
7
|
-
_params?: Ps;
|
|
8
|
-
_search?: S;
|
|
9
|
-
keys: string[];
|
|
10
|
-
regex: RegExp;
|
|
11
|
-
looseRegex: RegExp;
|
|
12
|
-
mapSearch: (search: Record<string, unknown>) => S;
|
|
13
|
-
components: ComponentType[];
|
|
14
|
-
preloaded: boolean;
|
|
15
|
-
preloaders: (() => Promise<any>)[];
|
|
16
|
-
};
|
|
17
|
-
constructor(pattern: P, mapSearch: (search: Record<string, unknown>) => S, components: ComponentType[], preloaders: (() => Promise<any>)[]);
|
|
18
|
-
route<P2 extends string>(subPattern: P2): Route<NormalizePath<`${P}/${P2}`>, import("regexparam").RouteParams<NormalizePath<`${P}/${P2}`>> extends infer T ? { [KeyType in keyof T]: T[KeyType]; } : never, S>;
|
|
19
|
-
search<S2 extends {}>(mapper: ((search: S & Record<string, unknown>) => S2) | StandardSchemaV1<S & Record<string, unknown>, S2>): Route<P, Ps, (import("type-fest").PickIndexSignature<S> extends infer T_1 ? { [Key in keyof T_1 as Key extends keyof import("type-fest").PickIndexSignature<{ [K in keyof S2 as undefined extends S2[K] ? never : K]: S2[K]; } & { [K_1 in keyof S2 as undefined extends S2[K_1] ? K_1 : never]?: S2[K_1] | undefined; } extends infer T_2 ? { [KeyType_1 in keyof T_2]: T_2[KeyType_1]; } : never> ? never : Key]: T_1[Key]; } : never) & import("type-fest").PickIndexSignature<{ [K in keyof S2 as undefined extends S2[K] ? never : K]: S2[K]; } & { [K_1 in keyof S2 as undefined extends S2[K_1] ? K_1 : never]?: S2[K_1] | undefined; } extends infer T_2 ? { [KeyType_1 in keyof T_2]: T_2[KeyType_1]; } : never> & (import("type-fest").OmitIndexSignature<S> extends infer T_3 ? { [Key_1 in keyof T_3 as Key_1 extends keyof import("type-fest").OmitIndexSignature<{ [K in keyof S2 as undefined extends S2[K] ? never : K]: S2[K]; } & { [K_1 in keyof S2 as undefined extends S2[K_1] ? K_1 : never]?: S2[K_1] | undefined; } extends infer T_4 ? { [KeyType_1 in keyof T_4]: T_4[KeyType_1]; } : never> ? never : Key_1]: T_3[Key_1]; } : never) & import("type-fest").OmitIndexSignature<{ [K in keyof S2 as undefined extends S2[K] ? never : K]: S2[K]; } & { [K_1 in keyof S2 as undefined extends S2[K_1] ? K_1 : never]?: S2[K_1] | undefined; } extends infer T_4 ? { [KeyType_1 in keyof T_4]: T_4[KeyType_1]; } : never> extends infer T ? { [KeyType in keyof T]: T[KeyType]; } : never>;
|
|
20
|
-
component(component: ComponentType): Route<P, Ps, S>;
|
|
21
|
-
lazy(loader: ComponentLoader): Route<P, Ps, S>;
|
|
22
|
-
error(component: ComponentType<{
|
|
23
|
-
error: unknown;
|
|
24
|
-
}>): Route<P, Ps, S>;
|
|
25
|
-
preload(): Promise<void>;
|
|
26
|
-
}
|
|
27
|
-
export declare function route<P extends string>(pattern: P): Route<NormalizePath<P>, import("regexparam").RouteParams<NormalizePath<P>> extends infer T ? { [KeyType in keyof T]: T[KeyType]; } : never, {}>;
|
package/dist/route.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { lazy } from "react";
|
|
2
|
-
import { parse } from "regexparam";
|
|
3
|
-
import { normalizePath, validator, errorBoundary } from "./utils";
|
|
4
|
-
export class Route {
|
|
5
|
-
_;
|
|
6
|
-
constructor(pattern, mapSearch, components, preloaders) {
|
|
7
|
-
const { keys, pattern: regex } = parse(pattern);
|
|
8
|
-
const looseRegex = parse(pattern, true).pattern;
|
|
9
|
-
this._ = {
|
|
10
|
-
pattern,
|
|
11
|
-
keys,
|
|
12
|
-
regex,
|
|
13
|
-
looseRegex,
|
|
14
|
-
mapSearch,
|
|
15
|
-
components,
|
|
16
|
-
preloaded: false,
|
|
17
|
-
preloaders
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
route(subPattern) {
|
|
21
|
-
const { pattern, mapSearch, components, preloaders } = this._;
|
|
22
|
-
return new Route(normalizePath(`${pattern}/${subPattern}`), mapSearch, components, preloaders);
|
|
23
|
-
}
|
|
24
|
-
search(mapper) {
|
|
25
|
-
const { pattern, mapSearch, components, preloaders } = this._;
|
|
26
|
-
mapper = validator(mapper);
|
|
27
|
-
return new Route(pattern, search => {
|
|
28
|
-
const mapped = mapSearch(search);
|
|
29
|
-
return { ...mapped, ...mapper(mapped) };
|
|
30
|
-
}, components, preloaders);
|
|
31
|
-
}
|
|
32
|
-
component(component) {
|
|
33
|
-
const { pattern, mapSearch, components, preloaders } = this._;
|
|
34
|
-
return new Route(pattern, mapSearch, [...components, component], preloaders);
|
|
35
|
-
}
|
|
36
|
-
lazy(loader) {
|
|
37
|
-
const { pattern, mapSearch, components, preloaders } = this._;
|
|
38
|
-
const lazyLoader = async () => {
|
|
39
|
-
const result = await loader();
|
|
40
|
-
return "default" in result ? result : { default: result };
|
|
41
|
-
};
|
|
42
|
-
return new Route(pattern, mapSearch, [...components, lazy(lazyLoader)], [...preloaders, loader]);
|
|
43
|
-
}
|
|
44
|
-
error(component) {
|
|
45
|
-
return this.component(errorBoundary(component));
|
|
46
|
-
}
|
|
47
|
-
async preload() {
|
|
48
|
-
const { preloaded, preloaders } = this._;
|
|
49
|
-
if (preloaded)
|
|
50
|
-
return;
|
|
51
|
-
this._.preloaded = true;
|
|
52
|
-
await Promise.all(preloaders.map(loader => loader()));
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
export function route(pattern) {
|
|
56
|
-
return new Route(normalizePath(pattern), search => search, [], []);
|
|
57
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type HistoryLike, type HistoryPushOptions } from "../utils";
|
|
2
|
-
export declare class BrowserHistory implements HistoryLike {
|
|
3
|
-
private static patchKey;
|
|
4
|
-
constructor();
|
|
5
|
-
getPath: () => string;
|
|
6
|
-
getSearch: () => string;
|
|
7
|
-
getState: () => any;
|
|
8
|
-
go: (delta: number) => void;
|
|
9
|
-
push: (options: HistoryPushOptions) => void;
|
|
10
|
-
subscribe: (listener: () => void) => () => void;
|
|
11
|
-
}
|