@jayalfredprufrock/mobx-toolbox 0.6.5 → 0.7.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/dist/router.d.mts +159 -59
- package/dist/router.d.mts.map +1 -1
- package/dist/router.mjs +226 -49
- package/dist/router.mjs.map +1 -1
- package/package.json +1 -1
package/dist/router.d.mts
CHANGED
|
@@ -1,50 +1,6 @@
|
|
|
1
1
|
import React$1 from "react";
|
|
2
2
|
import { History, Location } from "history";
|
|
3
3
|
|
|
4
|
-
//#region src/router/outlet.d.ts
|
|
5
|
-
interface OutletConfig {
|
|
6
|
-
component?: Component | LazyComponent;
|
|
7
|
-
loader?: Loader;
|
|
8
|
-
}
|
|
9
|
-
type RouteSegmentState = "preloading" | "loading" | "error" | "ready";
|
|
10
|
-
declare const DefaultOutlet: Component;
|
|
11
|
-
declare class Outlet {
|
|
12
|
-
readonly config: OutletConfig;
|
|
13
|
-
state: RouteSegmentState;
|
|
14
|
-
promise: Promise<unknown> | undefined;
|
|
15
|
-
data: unknown;
|
|
16
|
-
component: Component | undefined;
|
|
17
|
-
get Component(): Component | undefined;
|
|
18
|
-
constructor(config: OutletConfig);
|
|
19
|
-
load(route: Route): Promise<void>;
|
|
20
|
-
setData(data: unknown): void;
|
|
21
|
-
setState(state: RouteSegmentState): void;
|
|
22
|
-
private loadData;
|
|
23
|
-
private loadComponent;
|
|
24
|
-
}
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region src/router/route.d.ts
|
|
27
|
-
interface RouteConfig$1 {
|
|
28
|
-
path: string;
|
|
29
|
-
outlets: Outlet[];
|
|
30
|
-
guards: Guard[];
|
|
31
|
-
context?: Obj;
|
|
32
|
-
layout?: Component;
|
|
33
|
-
params: Obj;
|
|
34
|
-
}
|
|
35
|
-
declare class Route {
|
|
36
|
-
readonly path: string;
|
|
37
|
-
readonly outlets: Outlet[];
|
|
38
|
-
readonly guards: Guard[];
|
|
39
|
-
readonly context: Obj;
|
|
40
|
-
readonly params: Obj;
|
|
41
|
-
readonly layout?: Component;
|
|
42
|
-
get data(): Obj;
|
|
43
|
-
constructor(def: RouteConfig$1);
|
|
44
|
-
guard(): Promise<void>;
|
|
45
|
-
load(): Promise<void>;
|
|
46
|
-
}
|
|
47
|
-
//#endregion
|
|
48
4
|
//#region src/router/symbols.d.ts
|
|
49
5
|
declare const CONTEXT: unique symbol;
|
|
50
6
|
declare const LAYOUT: unique symbol;
|
|
@@ -52,6 +8,7 @@ declare const WRAPPER: unique symbol;
|
|
|
52
8
|
declare const LOAD: unique symbol;
|
|
53
9
|
declare const GUARD: unique symbol;
|
|
54
10
|
declare const PAGE: unique symbol;
|
|
11
|
+
declare const ERROR: unique symbol;
|
|
55
12
|
declare const REDIRECT: unique symbol;
|
|
56
13
|
//#endregion
|
|
57
14
|
//#region src/router/types.d.ts
|
|
@@ -60,12 +17,29 @@ type LazyComponent = () => Promise<any>;
|
|
|
60
17
|
type Obj<T = any> = Record<string, T>;
|
|
61
18
|
type Loader = (route: Route) => Promise<any>;
|
|
62
19
|
type Guard = (route: Route) => Promise<void>;
|
|
20
|
+
/** The props every `[ERROR]` component receives. */
|
|
21
|
+
interface ErrorComponentProps {
|
|
22
|
+
route: Route;
|
|
23
|
+
error: RouterError;
|
|
24
|
+
}
|
|
25
|
+
/** @internal a guard together with the route level that declared it */
|
|
26
|
+
interface GuardEntry {
|
|
27
|
+
guard: Guard;
|
|
28
|
+
depth: number;
|
|
29
|
+
}
|
|
30
|
+
/** @internal per-level snapshot used to build synthetic error routes */
|
|
31
|
+
interface MatchLevel {
|
|
32
|
+
wrapper?: Component;
|
|
33
|
+
layout?: Component;
|
|
34
|
+
errorComponent?: Component;
|
|
35
|
+
}
|
|
63
36
|
interface RouteConfig {
|
|
64
37
|
[CONTEXT]?: Obj;
|
|
65
38
|
[LAYOUT]?: Component;
|
|
66
39
|
[WRAPPER]?: Component;
|
|
67
40
|
[GUARD]?: Guard;
|
|
68
41
|
[LOAD]?: Loader;
|
|
42
|
+
[ERROR]?: Component;
|
|
69
43
|
}
|
|
70
44
|
/**
|
|
71
45
|
* A route page definition.
|
|
@@ -134,9 +108,148 @@ type DynamicRoutePath = Extract<RoutePath, `${string}:${string}`>;
|
|
|
134
108
|
type StaticRoutePath = Exclude<RoutePath, `${string}:${string}`>;
|
|
135
109
|
/********************************************************************************* */
|
|
136
110
|
type JoinSegments<S1, S2> = `/${S1 extends string ? S1 : ""}${S2 extends string ? S2 : ""}`;
|
|
111
|
+
type SegmentName<S> = S extends `$${infer Param}` ? `:${Param}` : S;
|
|
137
112
|
type ExtractParam<P, NextPart> = P extends `:${infer Param}` ? Record<Param, string> & NextPart : NextPart;
|
|
138
113
|
type ExtractParams<P> = P extends `${infer S1}/${infer Rest}` ? ExtractParam<S1, ExtractParams<Rest>> : ExtractParam<P, {}>;
|
|
139
|
-
type ExtractPaths<R> = { [S in keyof R]: S extends string ? S extends "index" ? "/" : R[S] extends Leaf ? `/${S}` : JoinSegments<S
|
|
114
|
+
type ExtractPaths<R> = { [S in keyof R]: S extends string ? S extends "index" ? "/" : R[S] extends Leaf ? `/${SegmentName<S> extends string ? SegmentName<S> : ""}` : JoinSegments<SegmentName<S>, ExtractPaths<R[S]>> : never }[keyof R];
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/router/route.d.ts
|
|
117
|
+
interface RouteConfig$1 {
|
|
118
|
+
path: string;
|
|
119
|
+
outlets: Outlet[];
|
|
120
|
+
guards: GuardEntry[];
|
|
121
|
+
levels: MatchLevel[];
|
|
122
|
+
context?: Obj;
|
|
123
|
+
layout?: Component;
|
|
124
|
+
params: Obj;
|
|
125
|
+
error?: RouterError;
|
|
126
|
+
}
|
|
127
|
+
declare class Route {
|
|
128
|
+
readonly path: string;
|
|
129
|
+
readonly outlets: Outlet[];
|
|
130
|
+
readonly guards: Guard[];
|
|
131
|
+
readonly context: Obj;
|
|
132
|
+
readonly params: Obj;
|
|
133
|
+
readonly layout?: Component;
|
|
134
|
+
/** set on synthetic error routes; the error being rendered */
|
|
135
|
+
readonly error?: RouterError;
|
|
136
|
+
/** @internal */
|
|
137
|
+
readonly guardEntries: GuardEntry[];
|
|
138
|
+
/** @internal */
|
|
139
|
+
readonly levels: MatchLevel[];
|
|
140
|
+
get data(): Obj;
|
|
141
|
+
constructor(def: RouteConfig$1);
|
|
142
|
+
guard(): Promise<void>;
|
|
143
|
+
load(): Promise<void>;
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region src/router/outlet.d.ts
|
|
147
|
+
interface OutletConfig {
|
|
148
|
+
component?: Component | LazyComponent;
|
|
149
|
+
loader?: Loader;
|
|
150
|
+
errorComponent?: Component;
|
|
151
|
+
}
|
|
152
|
+
type RouteSegmentState = "preloading" | "loading" | "error" | "ready";
|
|
153
|
+
declare const DefaultOutlet: Component;
|
|
154
|
+
declare class Outlet {
|
|
155
|
+
readonly config: OutletConfig;
|
|
156
|
+
state: RouteSegmentState;
|
|
157
|
+
promise: Promise<unknown> | undefined;
|
|
158
|
+
data: unknown;
|
|
159
|
+
error: RouterError | undefined;
|
|
160
|
+
component: Component | undefined;
|
|
161
|
+
get Component(): Component | undefined;
|
|
162
|
+
constructor(config: OutletConfig);
|
|
163
|
+
load(route: Route): Promise<void>;
|
|
164
|
+
setData(data: unknown): void;
|
|
165
|
+
setError(error: RouterError): void;
|
|
166
|
+
setState(state: RouteSegmentState): void;
|
|
167
|
+
private loadData;
|
|
168
|
+
private loadComponent;
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/router/make-routes.d.ts
|
|
172
|
+
interface MatchState {
|
|
173
|
+
segments: string[];
|
|
174
|
+
context: Obj;
|
|
175
|
+
params: Obj;
|
|
176
|
+
outlets: (Outlet | undefined)[];
|
|
177
|
+
guards: GuardEntry[];
|
|
178
|
+
levels: MatchLevel[];
|
|
179
|
+
layout?: Component;
|
|
180
|
+
errorComponent?: Component;
|
|
181
|
+
}
|
|
182
|
+
declare const makeRoute: (matchState: MatchState) => Route;
|
|
183
|
+
/**
|
|
184
|
+
* Builds the synthetic route rendered when navigation fails. Bubbles
|
|
185
|
+
* from the failing level (`error.depth`, defaulting to the deepest
|
|
186
|
+
* matched level) to the nearest `[ERROR]` component, preserving the
|
|
187
|
+
* `[LAYOUT]` and `[WRAPPER]`s accumulated up to that level. Ancestor
|
|
188
|
+
* `[LOAD]` loaders are intentionally not run — error routes never
|
|
189
|
+
* fetch data.
|
|
190
|
+
*/
|
|
191
|
+
declare const makeErrorRoute: (error: RouterError, pathname: string, source?: {
|
|
192
|
+
levels: MatchLevel[];
|
|
193
|
+
params: Obj;
|
|
194
|
+
context: Obj;
|
|
195
|
+
}) => Route;
|
|
196
|
+
declare const matchRoute: (path: string, routeDef: Routes, matchState?: MatchState) => Route;
|
|
197
|
+
declare const makeRoutes: () => <R extends Routes>(routes: R) => R;
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region src/router/errors.d.ts
|
|
200
|
+
type RouterErrorType = "NOT_FOUND" | "GUARD" | "LOAD" | "RENDER";
|
|
201
|
+
interface RouterErrorOptions {
|
|
202
|
+
message?: string;
|
|
203
|
+
cause?: unknown;
|
|
204
|
+
path?: string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The single error type surfaced to `[ERROR]` components. `type`
|
|
208
|
+
* discriminates the failure source; when the router wraps an
|
|
209
|
+
* application-level error (thrown by a guard or loader), the original
|
|
210
|
+
* is preserved on the standard `cause` property.
|
|
211
|
+
*
|
|
212
|
+
* Guards and loaders may also throw `RouterError` directly — e.g.
|
|
213
|
+
* `throw new RouterError("NOT_FOUND")` from a loader when an entity
|
|
214
|
+
* doesn't exist — and it passes through unwrapped.
|
|
215
|
+
*/
|
|
216
|
+
declare class RouterError extends Error {
|
|
217
|
+
readonly type: RouterErrorType;
|
|
218
|
+
readonly path?: string;
|
|
219
|
+
/** @internal matched-prefix state captured when the matcher throws NOT_FOUND */
|
|
220
|
+
state?: MatchState;
|
|
221
|
+
/** @internal level index of the failing guard, for depth-aware bubbling */
|
|
222
|
+
depth?: number;
|
|
223
|
+
constructor(type: RouterErrorType, options?: RouterErrorOptions);
|
|
224
|
+
}
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/router/components/error.d.ts
|
|
227
|
+
/**
|
|
228
|
+
* Rendered when an error occurs and no `[ERROR]` component is defined
|
|
229
|
+
* on the matched prefix. Deliberately minimal and dependency-free —
|
|
230
|
+
* define a root-level `[ERROR]` to replace it.
|
|
231
|
+
*/
|
|
232
|
+
declare const DefaultErrorPage: Component;
|
|
233
|
+
interface RouteErrorBoundaryProps {
|
|
234
|
+
route: Route;
|
|
235
|
+
fallback: Component;
|
|
236
|
+
children?: React$1.ReactNode;
|
|
237
|
+
}
|
|
238
|
+
interface RouteErrorBoundaryState {
|
|
239
|
+
error?: RouterError;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Catches render-time crashes in page and `[WRAPPER]` components and
|
|
243
|
+
* renders the nearest `[ERROR]` component with `type: "RENDER"`. Mounted
|
|
244
|
+
* inside the `[LAYOUT]` so the layout survives page crashes; crashes in
|
|
245
|
+
* the layout itself (or in the fallback) propagate out of `<Router>` by
|
|
246
|
+
* design — those are developer bugs that should stay loud.
|
|
247
|
+
*/
|
|
248
|
+
declare class RouteErrorBoundary extends React$1.Component<RouteErrorBoundaryProps, RouteErrorBoundaryState> {
|
|
249
|
+
state: RouteErrorBoundaryState;
|
|
250
|
+
static getDerivedStateFromError(cause: unknown): RouteErrorBoundaryState;
|
|
251
|
+
render(): React$1.ReactNode;
|
|
252
|
+
}
|
|
140
253
|
//#endregion
|
|
141
254
|
//#region src/router/components/link.d.ts
|
|
142
255
|
type LinkComponentProps<C extends React$1.ElementType> = Omit<React$1.ComponentProps<C>, "ref" | "exact" | "to" | "params" | "onClick" | "asChild">;
|
|
@@ -204,19 +317,6 @@ declare const Router: (({
|
|
|
204
317
|
displayName: string;
|
|
205
318
|
};
|
|
206
319
|
//#endregion
|
|
207
|
-
//#region src/router/make-routes.d.ts
|
|
208
|
-
interface MatchState {
|
|
209
|
-
segments: string[];
|
|
210
|
-
context: Obj;
|
|
211
|
-
params: Obj;
|
|
212
|
-
outlets: (Outlet | undefined)[];
|
|
213
|
-
guards: (Guard | undefined)[];
|
|
214
|
-
layout?: Component;
|
|
215
|
-
}
|
|
216
|
-
declare const makeRoute: (matchState: MatchState) => Route;
|
|
217
|
-
declare const matchRoute: (path: string, routeDef: Routes, matchState?: MatchState) => Route;
|
|
218
|
-
declare const makeRoutes: () => <R extends Routes>(routes: R) => R;
|
|
219
|
-
//#endregion
|
|
220
320
|
//#region src/router/redirect.d.ts
|
|
221
321
|
declare class Redirect<P extends RoutePath> {
|
|
222
322
|
readonly options: NavigateOptions<P>;
|
|
@@ -232,5 +332,5 @@ declare const isRedirect: (data: any) => data is Redirector;
|
|
|
232
332
|
declare const isLeaf: (data: any) => data is Leaf;
|
|
233
333
|
declare const isLazyComponent: (data: any) => data is LazyComponent;
|
|
234
334
|
//#endregion
|
|
235
|
-
export { CONTEXT, Component, DefaultOutlet, DynamicRoutePath, ExtractParam, ExtractParams, ExtractPaths, GUARD, Guard, HasParam, JoinSegments, LAYOUT, LOAD, LazyComponent, Leaf, LinkComponent, LinkPropsBase, Loader, MatchState, MobxRenderSegment, MobxRouter, MobxRouterConfig, MobxRouterRoutes, Navigate, NavigateOptions, Obj, Outlet, OutletConfig, PAGE, Page, PassThrough, REDIRECT, Redirect, Redirector, Route, RouteConfig, RoutePath, RouteSegmentState, Router, RouterOutlet, RouterProps, RouterStore, Routes, StaticRoutePath, WRAPPER, WithToAndParams, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
|
|
335
|
+
export { CONTEXT, Component, DefaultErrorPage, DefaultOutlet, DynamicRoutePath, ERROR, ErrorComponentProps, ExtractParam, ExtractParams, ExtractPaths, GUARD, Guard, GuardEntry, HasParam, JoinSegments, LAYOUT, LOAD, LazyComponent, Leaf, LinkComponent, LinkPropsBase, Loader, MatchLevel, MatchState, MobxRenderSegment, MobxRouter, MobxRouterConfig, MobxRouterRoutes, Navigate, NavigateOptions, Obj, Outlet, OutletConfig, PAGE, Page, PassThrough, REDIRECT, Redirect, Redirector, Route, RouteConfig, RouteErrorBoundary, RouteErrorBoundaryProps, RoutePath, RouteSegmentState, Router, RouterError, RouterErrorOptions, RouterErrorType, RouterOutlet, RouterProps, RouterStore, Routes, SegmentName, StaticRoutePath, WRAPPER, WithToAndParams, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeErrorRoute, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
|
|
236
336
|
//# sourceMappingURL=router.d.mts.map
|
package/dist/router.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.mts","names":[],"sources":["../src/router/outlet.tsx","../src/router/
|
|
1
|
+
{"version":3,"file":"router.d.mts","names":[],"sources":["../src/router/symbols.ts","../src/router/types.ts","../src/router/route.tsx","../src/router/outlet.tsx","../src/router/make-routes.tsx","../src/router/errors.ts","../src/router/components/error.tsx","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/router.store.ts","../src/router/components/router.tsx","../src/router/redirect.ts","../src/router/util.ts"],"mappings":";;;;cAAa,OAAA;AAAA,cACA,MAAA;AAAA,cACA,OAAA;AAAA,cACA,IAAA;AAAA,cACA,KAAA;AAAA,cACA,IAAA;AAAA,cACA,KAAA;AAAA,cACA,QAAA;;;KCFD,SAAA,GAAY,KAAA,CAAM,EAAE;AAAA,KACpB,aAAA,SAAsB,OAAO;AAAA,KAC7B,GAAA,YAAe,MAAM,SAAS,CAAA;AAAA,KAC9B,MAAA,IAAU,KAAA,EAAO,KAAA,KAAU,OAAO;AAAA,KAClC,KAAA,IAAS,KAAA,EAAO,KAAA,KAAU,OAAO;ADR7C;AAAA,UCWiB,mBAAA;EACf,KAAA,EAAO,KAAA;EACP,KAAA,EAAO,WAAW;AAAA;ADZpB;AAAA,UCgBiB,UAAA;EACf,KAAA,EAAO,KAAK;EACZ,KAAA;AAAA;ADjBF;AAAA,UCqBiB,UAAA;EACf,OAAA,GAAU,SAAA;EACV,MAAA,GAAS,SAAA;EACT,cAAA,GAAiB,SAAA;AAAA;AAAA,UAGF,WAAA;EAAA,CACd,OAAA,IAAW,GAAA;EAAA,CACX,MAAA,IAAU,SAAA;EAAA,CACV,OAAA,IAAW,SAAA;EAAA,CACX,KAAA,IAAS,KAAA;EAAA,CACT,IAAA,IAAQ,MAAA;EAAA,CACR,KAAA,IAAS,SAAA;AAAA;AD/BqD;AACjE;;;;AAAmE;AACnE;;;;AAAyE;;;;ACFzE;;;;AAAgC;AAChC;;;;AAAyC;AACzC;ADFiE,UC2DhD,IAAA,SAAa,IAAA,CAAK,WAAA,SAAoB,OAAA;EAAA,CACpD,IAAA,GAAO,SAAA,GAAY,aAAA;AAAA;AAAA,UAGL,UAAA;EAAA,CACd,QAAQ,YAAY,eAAA;AAAA;AAAA,KAGX,IAAA,GAAO,IAAA,GAAO,UAAA,GAAa,SAAA,GAAY,aAAA;AAAA,UAElC,MAAA,SAAe,WAAA;EAAA,CAC7B,OAAA,WAAkB,IAAA,GAAO,MAAA;AAAA;AAAA,KAGhB,QAAA,MAAc,CAAC;AAAA,KAEf,eAAA,WAA0B,SAAA,uBACzB,aAAA,CAAc,CAAA;EACnB,EAAA,EAAI,CAAA;EAAG,MAAA;AAAA,IAAuB,IAAA,CAAK,CAAA;EACnC,EAAA,EAAI,CAAA;EAAG,MAAA,EAAQ,aAAA,CAAc,CAAA;AAAA,IAAO,IAAA,CAAK,CAAA;AAAA,KAErC,eAAA;EACV,EAAA,EAAI,CAAA;EACJ,OAAA;EACA,KAAA;EACA,MAAA,GAAS,MAAA,mBAAyB,eAAA;EAClC,cAAA;AAAA,KACG,QAAA,CAAS,CAAA;EAAoB,MAAA,EAAQ,aAAA,CAAc,CAAA;AAAA;EAAS,MAAA;AAAA;;UAMhD,UAAA;AAAA,KAEL,gBAAA,GAAmB,UAAA;EAAqB,MAAA;AAAA,IAAoB,CAAA,GAAI,MAAM;AAAA,UAEjE,gBAAA;EACf,OAAA,GAAU,OAAO;AAAA;AAAA,KAGP,SAAA,GACV,YAAA,CAAa,gBAAA,+BAA+C,YAAA,CAAa,gBAAA;AAAA,KAE/D,gBAAA,GAAmB,OAAO,CAAC,SAAA;AAAA,KAC3B,eAAA,GAAkB,OAAO,CAAC,SAAA;;KAK1B,YAAA,eAA2B,EAAA,kBAAoB,EAAA,QAAU,EAAA,kBAAoB,EAAA;AAAA,KAK7E,WAAA,MAAiB,CAAA,iCAAkC,KAAA,KAAU,CAAA;AAAA,KAE7D,YAAA,gBAA4B,CAAA,6BACpC,MAAA,CAAO,KAAA,YAAiB,QAAA,GACxB,QAAA;AAAA,KACQ,aAAA,MAAmB,CAAA,uCAC3B,YAAA,CAAa,EAAA,EAAI,aAAA,CAAc,IAAA,KAC/B,YAAA,CAAa,CAAA;AAAA,KAEL,YAAA,oBACE,CAAA,GAAI,CAAA,kBACZ,CAAA,yBAEE,CAAA,CAAE,CAAA,UAAW,IAAA,OACP,WAAA,CAAY,CAAA,mBAAoB,WAAA,CAAY,CAAA,WAChD,YAAA,CAAa,WAAA,CAAY,CAAA,GAAI,YAAA,CAAa,CAAA,CAAE,CAAA,oBAE9C,CAAA;;;UClIS,aAAA;EACf,IAAA;EACA,OAAA,EAAS,MAAA;EACT,MAAA,EAAQ,UAAA;EACR,MAAA,EAAQ,UAAA;EACR,OAAA,GAAU,GAAA;EACV,MAAA,GAAS,SAAA;EACT,MAAA,EAAQ,GAAA;EACR,KAAA,GAAQ,WAAA;AAAA;AAAA,cAGG,KAAA;EAAA,SACF,IAAA;EAAA,SACA,OAAA,EAAS,MAAA;EAAA,SACT,MAAA,EAAQ,KAAA;EAAA,SACR,OAAA,EAAS,GAAA;EAAA,SACT,MAAA,EAAQ,GAAA;EAAA,SACR,MAAA,GAAS,SAAA;EFpB6C;EAAA,SEsBtD,KAAA,GAAQ,WAAA;EFtB8C;EAAA,SEwBtD,YAAA,EAAc,UAAA;EFvBZ;EAAA,SEyBF,MAAA,EAAQ,UAAA;EAAA,IAEb,IAAA,IAAQ,GAAA;EAIZ,WAAA,CAAY,GAAA,EAAK,aAAA;EAgBX,KAAA,IAAS,OAAA;EAaT,IAAA,IAAQ,OAAA;AAAA;;;UCxDC,YAAA;EACf,SAAA,GAAY,SAAA,GAAY,aAAA;EACxB,MAAA,GAAS,MAAA;EACT,cAAA,GAAiB,SAAA;AAAA;AAAA,KAGP,iBAAA;AAAA,cAEC,aAAA,EAAe,SAAsC;AAAA,cAIrD,MAAA;EAAA,SA+BU,MAAA,EAAQ,YAAA;EA9B7B,KAAA,EAAO,iBAAA;EACP,OAAA,EAAS,OAAA;EACT,IAAA;EACA,KAAA,EAAO,WAAA;EAOP,SAAA,EAAW,SAAA;EAAA,IAEP,SAAA,IAAa,SAAA;EAkBjB,WAAA,CAAqB,MAAA,EAAQ,YAAA;EAcvB,IAAA,CAAK,KAAA,EAAO,KAAA,GAAQ,OAAA;EAmD1B,OAAA,CAAQ,IAAA;EAIR,QAAA,CAAS,KAAA,EAAO,WAAA;EAIhB,QAAA,CAAS,KAAA,EAAO,iBAAA;EAAA,QAIF,QAAA;EAAA,QAIA,aAAA;AAAA;;;UCvHC,UAAA;EACf,QAAA;EACA,OAAA,EAAS,GAAA;EACT,MAAA,EAAQ,GAAA;EACR,OAAA,GAAU,MAAA;EACV,MAAA,EAAQ,UAAA;EACR,MAAA,EAAQ,UAAA;EACR,MAAA,GAAS,SAAA;EACT,cAAA,GAAiB,SAAA;AAAA;AAAA,cAGN,SAAA,GAAS,UAAA,EAAgB,UAAA,KAAa,KAIlD;;;;AJ1BsE;AACvE;;;;cImCa,cAAA,GAAc,KAAA,EAClB,WAAA,EAAW,QAAA,UACF,MAAA;EACL,MAAA,EAAQ,UAAA;EAAc,MAAA,EAAQ,GAAA;EAAK,OAAA,EAAS,GAAA;AAAA,MACtD,KAAA;AAAA,cAiCU,UAAA,GAAU,IAAA,UAAgB,QAAA,EAAY,MAAA,EAAM,UAAA,GAAe,UAAA,KAAa,KAAA;AAAA,cAmGxE,UAAA,mBAEA,MAAA,EAAM,MAAA,EAAU,CAAA,KAAI,CAAA;;;KC9KrB,eAAA;AAAA,UAEK,kBAAA;EACf,OAAA;EACA,KAAA;EACA,IAAA;AAAA;;ALPqE;AACvE;;;;AAAqE;AACrE;;;cK+Ba,WAAA,SAAoB,KAAA;EAAA,SACtB,IAAA,EAAM,eAAA;EAAA,SACN,IAAA;ELhCsD;EKmC/D,KAAA,GAAQ,UAAA;ELnCuD;EKqC/D,KAAA;EAEA,WAAA,CAAY,IAAA,EAAM,eAAA,EAAiB,OAAA,GAAU,kBAAA;AAAA;;;AL1C/C;;;;AAAuE;AAAvE,cMUa,gBAAA,EAAkB,SAK9B;AAAA,UAEgB,uBAAA;EACf,KAAA,EAAO,KAAA;EACP,QAAA,EAAU,SAAA;EACV,QAAA,GAAW,OAAA,CAAM,SAAA;AAAA;AAAA,UAGT,uBAAA;EACR,KAAA,GAAQ,WAAW;AAAA;ANtBkD;AACvE;;;;AAAiE;AACjE;AAFuE,cMgC1D,kBAAA,SAA2B,OAAA,CAAM,SAAA,CAC5C,uBAAA,EACA,uBAAA;EAES,KAAA,EAAO,uBAAA;EAAA,OAET,wBAAA,CAAyB,KAAA,YAAiB,uBAAA;EAIxC,MAAA,IAAU,OAAA,CAAM,SAAA;AAAA;;;KChCtB,kBAAA,WAA6B,OAAA,CAAM,WAAA,IAAe,IAAA,CACrD,OAAA,CAAM,cAAA,CAAe,CAAA;AAAA,KAIX,aAAA,WACA,OAAA,CAAM,WAAA,YACN,OAAA,CAAM,WAAA,GAAc,CAAA,IAC5B,kBAAA,CAAmB,CAAA;EACrB,KAAA;EACA,cAAA;EACA,GAAA,GAAM,OAAA,CAAM,GAAA,CAAI,OAAA,CAAM,YAAA,CAAa,CAAA;AAAA;AAAA,UAOpB,aAAA,WAAwB,OAAA,CAAM,WAAA,YAAuB,OAAA,CAAM,WAAA,GAAc,CAAA;EAAA,WAC7E,eAAA,EACT,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA;IAAO,EAAA,EAAI,CAAA;IAAG,MAAA;EAAA,IACrC,OAAA,CAAM,SAAA;EAAA,WACE,gBAAA,EACT,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA;IAAO,EAAA,EAAI,CAAA;IAAG,MAAA,EAAQ,aAAA,CAAc,CAAA;EAAA,IAC3D,OAAA,CAAM,SAAA;AAAA;AAAA,cAME,iBAAA,aAA+B,OAAA,CAAM,WAAA,YAAuB,OAAA,CAAM,WAAA,GAAc,CAAA,EAAC,CAAA,EACzF,CAAA,EAAC,SAAA,GACQ,OAAA,CAAQ,kBAAA,CAAmB,CAAA;EAAQ,EAAA,GAAK,CAAA;AAAA,MAwB9C,aAAA,CAAc,CAAA,EAAG,CAAA;;;cChEZ,QAAA,aAAsB,SAAA,EAAS,KAAA,EAAS,eAAA,CAAgB,CAAA;;;UCKpD,iBAAA;EACf,OAAA;EACA,SAAA,EAAW,SAAA;EACX,KAAA,GAAQ,GAAG;AAAA;AAAA,cAGA,WAAA;EAAA,SACF,OAAA,EAAS,OAAA;EAElB,SAAA,GAAY,MAAA;EAEZ,QAAA,EAAW,QAAA;EACX,WAAA,EAAa,KAAA;EAAA,IAET,MAAA,IAAU,eAAA;EAAA,IAIV,KAAA,IAAS,MAAA;EAAA,IAIT,UAAA,IAAc,MAAA;EAAA,IAId,cAAA;EAIJ,WAAA,CAAY,MAAA,GAAS,gBAAA;EAerB,UAAA,CAAW,SAAA,EAAW,MAAA;EAStB,aAAA,WAAwB,SAAA,EAAW,IAAA,EAAM,CAAA,EAAG,KAAA;EAa5C,QAAA,WAAmB,SAAA,EAAW,OAAA,EAAS,eAAA,CAAgB,CAAA;EASvD,SAAA,WAAoB,SAAA,EAAW,OAAA,EAAS,eAAA,CAAgB,CAAA;EAyBxD,aAAA,CAAc,KAAA,UAAe,KAAA;EAM7B,gBAAA,CAAiB,KAAA;EAUX,WAAA,CAAY,QAAA,EAAU,QAAA,GAAW,OAAA;AAAA;;;cCvH5B,WAAA,EAAa,SAAsC;AAAA,cAMnD,YAAA,EAAc,KAAA,CAAM,EAAA;EAAK,KAAA,EAAO,KAAA;EAAO,UAAA,GAAa,SAAA;AAAA;AAAA,cAepD,aAAA,kBAAa,OAAA,CAAA,WAAA;AAAA,cACb,SAAA,QAAS,WAAkC;AAAA,UAEvC,WAAA;EACf,KAAA,EAAO,WAAW;AAAA;AAAA,cAGP,MAAA;EAAM;AAAA,GAAwB,WAAW,iCAAA,GAAA,CAAA,OAAA;;;;;cCjCzC,QAAA,WAAmB,SAAA;EAAA,SACT,OAAA,EAAS,eAAA,CAAgB,CAAA;EAA9C,WAAA,CAAqB,OAAA,EAAS,eAAA,CAAgB,CAAA;AAAA;AAAA,cAGnC,QAAA,aAAsB,SAAA,EAAS,OAAA,EAAW,eAAA,CAAgB,CAAA,MAAK,QAAA,CAAS,CAAA;;;cCHxE,WAAA,GAAW,EAAA,UAAc,MAAA,GAAW,GAAG;AAAA,cASvC,WAAA,GAAW,IAAA,UAAgB,IAAA,IAAQ,SAM/C;AAAA,cAEY,MAAA,GAAM,IAAA,UAAgB,IAAA,IAAQ,IAI1C;AAAA,cAEY,UAAA,GAAU,IAAA,UAAgB,IAAA,IAAQ,UAI9C;AAAA,cAEY,MAAA,GAAM,IAAA,UAAgB,IAAA,IAAQ,IAE1C;AAAA,cAEY,eAAA,GAAe,IAAA,UAAgB,IAAA,IAAQ,aAEnD"}
|
package/dist/router.mjs
CHANGED
|
@@ -1,9 +1,77 @@
|
|
|
1
1
|
import { observer } from "mobx-react-lite";
|
|
2
2
|
import React, { createContext, useCallback, useContext, useLayoutEffect } from "react";
|
|
3
3
|
import { action, computed, makeAutoObservable, makeObservable, observable, runInAction } from "mobx";
|
|
4
|
-
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { createBrowserHistory } from "history";
|
|
6
6
|
|
|
7
|
+
//#region src/router/errors.ts
|
|
8
|
+
const defaultMessage = (type, path) => {
|
|
9
|
+
switch (type) {
|
|
10
|
+
case "NOT_FOUND": return path ? `No route matches '${path}'.` : "No matching route.";
|
|
11
|
+
case "GUARD": return "A route guard rejected the navigation.";
|
|
12
|
+
case "LOAD": return "A route loader or lazy component failed.";
|
|
13
|
+
case "RENDER": return "A route component failed to render.";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The single error type surfaced to `[ERROR]` components. `type`
|
|
18
|
+
* discriminates the failure source; when the router wraps an
|
|
19
|
+
* application-level error (thrown by a guard or loader), the original
|
|
20
|
+
* is preserved on the standard `cause` property.
|
|
21
|
+
*
|
|
22
|
+
* Guards and loaders may also throw `RouterError` directly — e.g.
|
|
23
|
+
* `throw new RouterError("NOT_FOUND")` from a loader when an entity
|
|
24
|
+
* doesn't exist — and it passes through unwrapped.
|
|
25
|
+
*/
|
|
26
|
+
var RouterError = class extends Error {
|
|
27
|
+
type;
|
|
28
|
+
path;
|
|
29
|
+
/** @internal matched-prefix state captured when the matcher throws NOT_FOUND */
|
|
30
|
+
state;
|
|
31
|
+
/** @internal level index of the failing guard, for depth-aware bubbling */
|
|
32
|
+
depth;
|
|
33
|
+
constructor(type, options) {
|
|
34
|
+
super(options?.message ?? defaultMessage(type, options?.path), { cause: options?.cause });
|
|
35
|
+
this.name = "RouterError";
|
|
36
|
+
this.type = type;
|
|
37
|
+
this.path = options?.path;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/router/components/error.tsx
|
|
43
|
+
/**
|
|
44
|
+
* Rendered when an error occurs and no `[ERROR]` component is defined
|
|
45
|
+
* on the matched prefix. Deliberately minimal and dependency-free —
|
|
46
|
+
* define a root-level `[ERROR]` to replace it.
|
|
47
|
+
*/
|
|
48
|
+
const DefaultErrorPage = ({ error }) => /* @__PURE__ */ jsxs("div", {
|
|
49
|
+
role: "alert",
|
|
50
|
+
children: [/* @__PURE__ */ jsx("h1", { children: error.type === "NOT_FOUND" ? "Page Not Found" : "Something Went Wrong" }), /* @__PURE__ */ jsx("p", { children: error.message })]
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Catches render-time crashes in page and `[WRAPPER]` components and
|
|
54
|
+
* renders the nearest `[ERROR]` component with `type: "RENDER"`. Mounted
|
|
55
|
+
* inside the `[LAYOUT]` so the layout survives page crashes; crashes in
|
|
56
|
+
* the layout itself (or in the fallback) propagate out of `<Router>` by
|
|
57
|
+
* design — those are developer bugs that should stay loud.
|
|
58
|
+
*/
|
|
59
|
+
var RouteErrorBoundary = class extends React.Component {
|
|
60
|
+
state = {};
|
|
61
|
+
static getDerivedStateFromError(cause) {
|
|
62
|
+
return { error: cause instanceof RouterError ? cause : new RouterError("RENDER", { cause }) };
|
|
63
|
+
}
|
|
64
|
+
render() {
|
|
65
|
+
if (!this.state.error) return this.props.children;
|
|
66
|
+
const Fallback = this.props.fallback;
|
|
67
|
+
return /* @__PURE__ */ jsx(Fallback, {
|
|
68
|
+
route: this.props.route,
|
|
69
|
+
error: this.state.error
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
7
75
|
//#region src/router/symbols.ts
|
|
8
76
|
const CONTEXT = Symbol.for("MOBX_ROUTER_CONTEXT");
|
|
9
77
|
const LAYOUT = Symbol.for("MOBX_ROUTER_LAYOUT");
|
|
@@ -11,6 +79,7 @@ const WRAPPER = Symbol.for("MOBX_ROUTER_WRAPPER");
|
|
|
11
79
|
const LOAD = Symbol.for("MOBX_ROUTER_LOAD");
|
|
12
80
|
const GUARD = Symbol.for("MOBX_ROUTER_GUARD");
|
|
13
81
|
const PAGE = Symbol.for("MOBX_ROUTER_PAGE");
|
|
82
|
+
const ERROR = Symbol.for("MOBX_ROUTER_ERROR");
|
|
14
83
|
const REDIRECT = Symbol.for("MOBX_ROUTER_REDIRECT");
|
|
15
84
|
|
|
16
85
|
//#endregion
|
|
@@ -18,7 +87,7 @@ const REDIRECT = Symbol.for("MOBX_ROUTER_REDIRECT");
|
|
|
18
87
|
const resolvePath = (to, params) => {
|
|
19
88
|
return to.replaceAll(/:[^/]*/g, (segment) => {
|
|
20
89
|
const value = params?.[segment.slice(1)];
|
|
21
|
-
if (!value) throw new Error(`Unable to resolve route '${to}.
|
|
90
|
+
if (!value) throw new Error(`Unable to resolve route '${to}'. Parameter '${segment}' not specified.`);
|
|
22
91
|
return value;
|
|
23
92
|
});
|
|
24
93
|
};
|
|
@@ -58,17 +127,23 @@ const RouterOutlet = ({ route, components }) => {
|
|
|
58
127
|
const routerContext = createContext(null);
|
|
59
128
|
const useRouter = () => useContext(routerContext);
|
|
60
129
|
const Router = observer(({ store }) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
130
|
+
const route = store.activeRoute;
|
|
131
|
+
if (!route) return null;
|
|
132
|
+
const Layout = route.layout ?? PassThrough;
|
|
133
|
+
const outlet = /* @__PURE__ */ jsx(RouterOutlet, {
|
|
134
|
+
route,
|
|
135
|
+
components: route.outlets.map((o) => o.Component)
|
|
136
|
+
});
|
|
137
|
+
const fallback = route.levels.at(-1)?.errorComponent ?? DefaultErrorPage;
|
|
64
138
|
return /* @__PURE__ */ jsx(routerContext.Provider, {
|
|
65
139
|
value: store,
|
|
66
140
|
children: /* @__PURE__ */ jsx(Layout, {
|
|
67
|
-
route
|
|
68
|
-
children: /* @__PURE__ */ jsx(
|
|
69
|
-
route
|
|
70
|
-
|
|
71
|
-
|
|
141
|
+
route,
|
|
142
|
+
children: route.error ? outlet : /* @__PURE__ */ jsx(RouteErrorBoundary, {
|
|
143
|
+
route,
|
|
144
|
+
fallback,
|
|
145
|
+
children: outlet
|
|
146
|
+
}, store.location.key)
|
|
72
147
|
})
|
|
73
148
|
});
|
|
74
149
|
});
|
|
@@ -90,7 +165,7 @@ const makeLinkComponent = (C, baseProps) => {
|
|
|
90
165
|
router.navigate({
|
|
91
166
|
to,
|
|
92
167
|
preserveSearch,
|
|
93
|
-
|
|
168
|
+
params
|
|
94
169
|
});
|
|
95
170
|
}, [
|
|
96
171
|
router,
|
|
@@ -112,6 +187,16 @@ const Navigate = (props) => {
|
|
|
112
187
|
return null;
|
|
113
188
|
};
|
|
114
189
|
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/router/redirect.ts
|
|
192
|
+
var Redirect = class {
|
|
193
|
+
options;
|
|
194
|
+
constructor(options) {
|
|
195
|
+
this.options = options;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
const redirect = (options) => new Redirect(options);
|
|
199
|
+
|
|
115
200
|
//#endregion
|
|
116
201
|
//#region src/router/outlet.tsx
|
|
117
202
|
const DefaultOutlet = ({ children }) => children;
|
|
@@ -121,11 +206,20 @@ var Outlet = class {
|
|
|
121
206
|
state = "preloading";
|
|
122
207
|
promise;
|
|
123
208
|
data;
|
|
209
|
+
error;
|
|
124
210
|
component;
|
|
125
211
|
get Component() {
|
|
126
212
|
switch (this.state) {
|
|
127
213
|
case "loading": return LoadingPlaceholder;
|
|
128
214
|
case "ready": return this.component ?? DefaultOutlet;
|
|
215
|
+
case "error": {
|
|
216
|
+
const ErrorComponent = this.config.errorComponent ?? DefaultErrorPage;
|
|
217
|
+
const error = this.error ?? new RouterError("LOAD");
|
|
218
|
+
return (props) => /* @__PURE__ */ jsx(ErrorComponent, {
|
|
219
|
+
...props,
|
|
220
|
+
error
|
|
221
|
+
});
|
|
222
|
+
}
|
|
129
223
|
default: return;
|
|
130
224
|
}
|
|
131
225
|
}
|
|
@@ -135,6 +229,7 @@ var Outlet = class {
|
|
|
135
229
|
makeAutoObservable(this, {
|
|
136
230
|
promise: observable.ref,
|
|
137
231
|
data: observable.ref,
|
|
232
|
+
error: observable.ref,
|
|
138
233
|
component: false,
|
|
139
234
|
config: false
|
|
140
235
|
});
|
|
@@ -156,15 +251,20 @@ var Outlet = class {
|
|
|
156
251
|
this.setState("ready");
|
|
157
252
|
}, 300);
|
|
158
253
|
else this.setState("ready");
|
|
159
|
-
}).catch(() => {
|
|
254
|
+
}).catch((e) => {
|
|
160
255
|
clearTimeout(preloadingTimer);
|
|
161
256
|
this.setState("error");
|
|
257
|
+
if (e instanceof Redirect) throw e;
|
|
258
|
+
this.setError(e instanceof RouterError ? e : new RouterError("LOAD", { cause: e }));
|
|
162
259
|
});
|
|
163
260
|
await this.promise;
|
|
164
261
|
}
|
|
165
262
|
setData(data) {
|
|
166
263
|
this.data = data;
|
|
167
264
|
}
|
|
265
|
+
setError(error) {
|
|
266
|
+
this.error = error;
|
|
267
|
+
}
|
|
168
268
|
setState(state) {
|
|
169
269
|
this.state = state;
|
|
170
270
|
}
|
|
@@ -182,16 +282,6 @@ var Outlet = class {
|
|
|
182
282
|
}
|
|
183
283
|
};
|
|
184
284
|
|
|
185
|
-
//#endregion
|
|
186
|
-
//#region src/router/redirect.ts
|
|
187
|
-
var Redirect = class {
|
|
188
|
-
options;
|
|
189
|
-
constructor(options) {
|
|
190
|
-
this.options = options;
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
const redirect = (options) => new Redirect(options);
|
|
194
|
-
|
|
195
285
|
//#endregion
|
|
196
286
|
//#region src/router/route.tsx
|
|
197
287
|
var Route = class {
|
|
@@ -201,20 +291,36 @@ var Route = class {
|
|
|
201
291
|
context;
|
|
202
292
|
params;
|
|
203
293
|
layout;
|
|
294
|
+
/** set on synthetic error routes; the error being rendered */
|
|
295
|
+
error;
|
|
296
|
+
/** @internal */
|
|
297
|
+
guardEntries;
|
|
298
|
+
/** @internal */
|
|
299
|
+
levels;
|
|
204
300
|
get data() {
|
|
205
301
|
return Object.assign({}, ...this.outlets.map((o) => o.data));
|
|
206
302
|
}
|
|
207
303
|
constructor(def) {
|
|
208
304
|
this.path = def.path;
|
|
209
|
-
this.
|
|
305
|
+
this.guardEntries = def.guards;
|
|
306
|
+
this.guards = def.guards.map((entry) => entry.guard);
|
|
307
|
+
this.levels = def.levels;
|
|
210
308
|
this.context = def.context ?? {};
|
|
211
309
|
this.outlets = def.outlets;
|
|
212
310
|
this.params = def.params;
|
|
213
311
|
this.layout = def.layout;
|
|
312
|
+
this.error = def.error;
|
|
214
313
|
makeObservable(this, { data: computed });
|
|
215
314
|
}
|
|
216
315
|
async guard() {
|
|
217
|
-
for (const guard of this.
|
|
316
|
+
for (const { guard, depth } of this.guardEntries) try {
|
|
317
|
+
await guard(this);
|
|
318
|
+
} catch (e) {
|
|
319
|
+
if (e instanceof Redirect) throw e;
|
|
320
|
+
const error = e instanceof RouterError ? e : new RouterError("GUARD", { cause: e });
|
|
321
|
+
error.depth ??= depth;
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
218
324
|
}
|
|
219
325
|
async load() {
|
|
220
326
|
await Promise.all(this.outlets.map((outlet) => outlet.load(this)));
|
|
@@ -228,59 +334,126 @@ const pathToSegments = (path) => {
|
|
|
228
334
|
};
|
|
229
335
|
const makeRoute = (matchState) => {
|
|
230
336
|
const outlets = matchState.outlets.filter((o) => o !== void 0);
|
|
231
|
-
const guards = matchState.guards.filter((g) => g !== void 0);
|
|
232
337
|
return new Route({
|
|
233
338
|
...matchState,
|
|
234
339
|
outlets,
|
|
235
|
-
guards,
|
|
236
340
|
path: matchState.segments.join("/")
|
|
237
341
|
});
|
|
238
342
|
};
|
|
343
|
+
/**
|
|
344
|
+
* Builds the synthetic route rendered when navigation fails. Bubbles
|
|
345
|
+
* from the failing level (`error.depth`, defaulting to the deepest
|
|
346
|
+
* matched level) to the nearest `[ERROR]` component, preserving the
|
|
347
|
+
* `[LAYOUT]` and `[WRAPPER]`s accumulated up to that level. Ancestor
|
|
348
|
+
* `[LOAD]` loaders are intentionally not run — error routes never
|
|
349
|
+
* fetch data.
|
|
350
|
+
*/
|
|
351
|
+
const makeErrorRoute = (error, pathname, source) => {
|
|
352
|
+
const levels = error.state?.levels ?? source?.levels ?? [];
|
|
353
|
+
const depth = Math.min(error.depth ?? levels.length - 1, levels.length - 1);
|
|
354
|
+
const level = depth >= 0 ? levels[depth] : void 0;
|
|
355
|
+
const ErrorComponent = level?.errorComponent ?? DefaultErrorPage;
|
|
356
|
+
const outlets = levels.slice(0, depth + 1).flatMap((l) => l.wrapper ? [new Outlet({ component: l.wrapper })] : []);
|
|
357
|
+
outlets.push(new Outlet({ component: (props) => /* @__PURE__ */ jsx(ErrorComponent, {
|
|
358
|
+
...props,
|
|
359
|
+
error
|
|
360
|
+
}) }));
|
|
361
|
+
return new Route({
|
|
362
|
+
path: pathname.replace(/^\/+/, ""),
|
|
363
|
+
outlets,
|
|
364
|
+
guards: [],
|
|
365
|
+
levels: [],
|
|
366
|
+
params: error.state?.params ?? source?.params ?? {},
|
|
367
|
+
context: error.state?.context ?? source?.context ?? {},
|
|
368
|
+
layout: level?.layout,
|
|
369
|
+
error
|
|
370
|
+
});
|
|
371
|
+
};
|
|
372
|
+
const notFound = (state, attemptedSegments) => {
|
|
373
|
+
const error = new RouterError("NOT_FOUND", { path: `/${attemptedSegments.filter((s) => s !== "").join("/")}` });
|
|
374
|
+
error.state = state;
|
|
375
|
+
return error;
|
|
376
|
+
};
|
|
239
377
|
const matchRoute = (path, routeDef, matchState) => {
|
|
378
|
+
const depth = matchState?.levels.length ?? 0;
|
|
379
|
+
const layout = routeDef[LAYOUT] ?? matchState?.layout;
|
|
380
|
+
const errorComponent = routeDef[ERROR] ?? matchState?.errorComponent;
|
|
240
381
|
const state = {
|
|
241
382
|
segments: [],
|
|
242
383
|
params: {},
|
|
243
384
|
...matchState,
|
|
244
|
-
layout
|
|
385
|
+
layout,
|
|
386
|
+
errorComponent,
|
|
245
387
|
context: {
|
|
246
388
|
...matchState?.context,
|
|
247
389
|
...routeDef[CONTEXT]
|
|
248
390
|
},
|
|
249
|
-
guards: [...matchState?.guards ?? [], routeDef[GUARD]
|
|
391
|
+
guards: [...matchState?.guards ?? [], ...routeDef[GUARD] ? [{
|
|
392
|
+
guard: routeDef[GUARD],
|
|
393
|
+
depth
|
|
394
|
+
}] : []],
|
|
250
395
|
outlets: [
|
|
251
396
|
...matchState?.outlets ?? [],
|
|
252
|
-
routeDef[WRAPPER] ? new Outlet({
|
|
253
|
-
|
|
254
|
-
|
|
397
|
+
routeDef[WRAPPER] ? new Outlet({
|
|
398
|
+
component: routeDef[WRAPPER],
|
|
399
|
+
errorComponent
|
|
400
|
+
}) : void 0,
|
|
401
|
+
routeDef[LOAD] ? new Outlet({
|
|
402
|
+
loader: routeDef[LOAD],
|
|
403
|
+
errorComponent
|
|
404
|
+
}) : void 0
|
|
405
|
+
],
|
|
406
|
+
levels: [...matchState?.levels ?? [], {
|
|
407
|
+
wrapper: routeDef[WRAPPER],
|
|
408
|
+
layout,
|
|
409
|
+
errorComponent
|
|
410
|
+
}]
|
|
255
411
|
};
|
|
256
412
|
const [segment, ...remainingSegments] = pathToSegments(path);
|
|
257
413
|
const remainingPath = remainingSegments.join("/");
|
|
258
414
|
let defAtSegment = routeDef[segment || "index"];
|
|
259
415
|
if (!defAtSegment) {
|
|
260
|
-
const matchedSegment = Object.keys(routeDef).find((segment) => segment.startsWith("$"));
|
|
416
|
+
const matchedSegment = Object.keys(routeDef).find((segment) => segment.startsWith("$") || segment.startsWith(":"));
|
|
261
417
|
if (matchedSegment) {
|
|
262
418
|
defAtSegment = routeDef[matchedSegment];
|
|
263
419
|
state.params[matchedSegment.slice(1)] = segment;
|
|
264
420
|
}
|
|
265
421
|
}
|
|
266
|
-
if (!defAtSegment) throw
|
|
422
|
+
if (!defAtSegment) throw notFound(state, [
|
|
423
|
+
...state.segments,
|
|
424
|
+
segment ?? "",
|
|
425
|
+
...remainingSegments
|
|
426
|
+
]);
|
|
267
427
|
state.segments.push(segment ?? "index");
|
|
268
428
|
if (isLeaf(defAtSegment)) {
|
|
269
|
-
if (remainingPath) throw
|
|
429
|
+
if (remainingPath) throw notFound(state, [...state.segments, ...remainingSegments]);
|
|
270
430
|
if (isRedirect(defAtSegment)) throw new Redirect(typeof defAtSegment[REDIRECT] === "string" ? { to: defAtSegment[REDIRECT] } : defAtSegment[REDIRECT]);
|
|
271
431
|
if (isComponent(defAtSegment) || isLazyComponent(defAtSegment)) {
|
|
272
|
-
state.outlets.push(new Outlet({
|
|
432
|
+
state.outlets.push(new Outlet({
|
|
433
|
+
component: defAtSegment,
|
|
434
|
+
errorComponent
|
|
435
|
+
}));
|
|
273
436
|
return makeRoute(state);
|
|
274
437
|
}
|
|
275
438
|
}
|
|
276
439
|
if (isPage(defAtSegment)) {
|
|
277
440
|
state.layout = defAtSegment[LAYOUT] ?? state.layout;
|
|
441
|
+
state.errorComponent = defAtSegment[ERROR] ?? state.errorComponent;
|
|
278
442
|
Object.assign(state.context, defAtSegment[CONTEXT]);
|
|
279
|
-
state.guards.push(
|
|
443
|
+
if (defAtSegment[GUARD]) state.guards.push({
|
|
444
|
+
guard: defAtSegment[GUARD],
|
|
445
|
+
depth
|
|
446
|
+
});
|
|
280
447
|
state.outlets.push(new Outlet({
|
|
281
448
|
component: defAtSegment[PAGE],
|
|
282
|
-
loader: defAtSegment[LOAD]
|
|
449
|
+
loader: defAtSegment[LOAD],
|
|
450
|
+
errorComponent: state.errorComponent
|
|
283
451
|
}));
|
|
452
|
+
state.levels[state.levels.length - 1] = {
|
|
453
|
+
...state.levels[state.levels.length - 1],
|
|
454
|
+
layout: state.layout,
|
|
455
|
+
errorComponent: state.errorComponent
|
|
456
|
+
};
|
|
284
457
|
return makeRoute(state);
|
|
285
458
|
}
|
|
286
459
|
return matchRoute(remainingPath, defAtSegment, state);
|
|
@@ -303,14 +476,7 @@ var RouterStore = class {
|
|
|
303
476
|
return Object.fromEntries(this.search);
|
|
304
477
|
}
|
|
305
478
|
get pathParams() {
|
|
306
|
-
|
|
307
|
-
const paramSegments = this.activeSegments.filter((segment) => segment.startsWith("$"));
|
|
308
|
-
const pathValues = this.location.pathname.split("/").slice(1);
|
|
309
|
-
paramSegments.forEach((segment, index) => {
|
|
310
|
-
const value = pathValues[index + 1];
|
|
311
|
-
if (value) params[segment] = value;
|
|
312
|
-
});
|
|
313
|
-
return params;
|
|
479
|
+
return { ...this.activeRoute?.params };
|
|
314
480
|
}
|
|
315
481
|
get activeSegments() {
|
|
316
482
|
return this.activeRoute?.path.split("/") ?? [];
|
|
@@ -335,7 +501,7 @@ var RouterStore = class {
|
|
|
335
501
|
}
|
|
336
502
|
doesPathMatch(path, exact) {
|
|
337
503
|
const segments = path.slice(1).split("/");
|
|
338
|
-
return segments.every((segment, i) => segment === this.activeSegments[i] || segment.startsWith("
|
|
504
|
+
return segments.every((segment, i) => segment === this.activeSegments[i] || segment.startsWith(":")) && this.activeSegments.length >= segments.length && (!exact || segments.length === this.activeSegments.length);
|
|
339
505
|
}
|
|
340
506
|
navigate(options) {
|
|
341
507
|
if (!document.startViewTransition) this._navigate(options);
|
|
@@ -378,8 +544,9 @@ var RouterStore = class {
|
|
|
378
544
|
return;
|
|
379
545
|
}
|
|
380
546
|
this.location = location;
|
|
547
|
+
let matchedRoute;
|
|
381
548
|
try {
|
|
382
|
-
|
|
549
|
+
matchedRoute = matchRoute(location.pathname, this.routesDef);
|
|
383
550
|
await matchedRoute.guard();
|
|
384
551
|
if (this.location !== location) return;
|
|
385
552
|
runInAction(() => {
|
|
@@ -391,11 +558,21 @@ var RouterStore = class {
|
|
|
391
558
|
this.navigate(e.options);
|
|
392
559
|
return;
|
|
393
560
|
}
|
|
394
|
-
|
|
561
|
+
if (this.location !== location) return;
|
|
562
|
+
const error = e instanceof RouterError ? e : new RouterError("RENDER", {
|
|
563
|
+
cause: e,
|
|
564
|
+
path: location.pathname
|
|
565
|
+
});
|
|
566
|
+
console.error(error);
|
|
567
|
+
const errorRoute = makeErrorRoute(error, location.pathname, matchedRoute);
|
|
568
|
+
runInAction(() => {
|
|
569
|
+
this.activeRoute = errorRoute;
|
|
570
|
+
});
|
|
571
|
+
await errorRoute.load();
|
|
395
572
|
}
|
|
396
573
|
}
|
|
397
574
|
};
|
|
398
575
|
|
|
399
576
|
//#endregion
|
|
400
|
-
export { CONTEXT, DefaultOutlet, GUARD, LAYOUT, LOAD, Navigate, Outlet, PAGE, PassThrough, REDIRECT, Redirect, Route, Router, RouterOutlet, RouterStore, WRAPPER, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
|
|
577
|
+
export { CONTEXT, DefaultErrorPage, DefaultOutlet, ERROR, GUARD, LAYOUT, LOAD, Navigate, Outlet, PAGE, PassThrough, REDIRECT, Redirect, Route, RouteErrorBoundary, Router, RouterError, RouterOutlet, RouterStore, WRAPPER, isComponent, isLazyComponent, isLeaf, isPage, isRedirect, makeErrorRoute, makeLinkComponent, makeRoute, makeRoutes, matchRoute, redirect, resolvePath, routerContext, useRouter };
|
|
401
578
|
//# sourceMappingURL=router.mjs.map
|
package/dist/router.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.mjs","names":[],"sources":["../src/router/symbols.ts","../src/router/util.ts","../src/router/components/router.tsx","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/outlet.tsx","../src/router/redirect.ts","../src/router/route.tsx","../src/router/make-routes.tsx","../src/router/router.store.ts"],"sourcesContent":["export const CONTEXT: unique symbol = Symbol.for(\"MOBX_ROUTER_CONTEXT\");\nexport const LAYOUT: unique symbol = Symbol.for(\"MOBX_ROUTER_LAYOUT\");\nexport const WRAPPER: unique symbol = Symbol.for(\"MOBX_ROUTER_WRAPPER\");\nexport const LOAD: unique symbol = Symbol.for(\"MOBX_ROUTER_LOAD\");\nexport const GUARD: unique symbol = Symbol.for(\"MOBX_ROUTER_GUARD\");\nexport const PAGE: unique symbol = Symbol.for(\"MOBX_ROUTER_PAGE\");\nexport const REDIRECT: unique symbol = Symbol.for(\"MOBX_ROUTER_REDIRECT\");\n","import { PAGE, REDIRECT } from \"./symbols\";\nimport type { Component, LazyComponent, Leaf, Obj, Page, Redirector } from \"./types\";\n\nexport const resolvePath = (to: string, params?: Obj): string => {\n return to.replaceAll(/:[^/]*/g, (segment) => {\n const value = params?.[segment.slice(1)];\n if (!value)\n throw new Error(`Unable to resolve route '${to}. Paramater '${segment}' not specified.`);\n return value;\n });\n};\n\nexport const isComponent = (data: any): data is Component => {\n if (!data) return false;\n return (\n typeof data === \"function\" ||\n (typeof data === \"object\" && data[\"$$typeof\"] === Symbol.for(\"react.memo\"))\n );\n};\n\nexport const isPage = (data: any): data is Page => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(PAGE);\n};\n\nexport const isRedirect = (data: any): data is Redirector => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(REDIRECT);\n};\n\nexport const isLeaf = (data: any): data is Leaf => {\n return isComponent(data) || isPage(data) || isRedirect(data);\n};\n\nexport const isLazyComponent = (data: any): data is LazyComponent => {\n return typeof data === \"function\" && data.toString().startsWith(\"() => import(\");\n};\n","import { observer } from \"mobx-react-lite\";\nimport { createContext, useContext } from \"react\";\nimport type { Route } from \"../route\";\nimport type { RouterStore } from \"../router.store\";\nimport type { Component } from \"../types\";\n\nexport const PassThrough: Component = ({ children }) => children;\n\n// Plain (non-observer) renderer. State observation lives one level up\n// in `Router`, so the page component renders as a child of a plain\n// FunctionComponent — no memo wrapper in the parent chain to interact\n// with React Refresh's family-update propagation.\nexport const RouterOutlet: React.FC<{ route: Route; components: (Component | undefined)[] }> = ({\n route,\n components,\n}) => {\n const [C, ...remaining] = components;\n\n if (!C) return null;\n\n return (\n <C route={route}>\n {remaining.length > 0 && <RouterOutlet route={route} components={remaining} />}\n </C>\n );\n};\n\nexport const routerContext = createContext<RouterStore>(null as any);\nexport const useRouter = () => useContext(routerContext);\n\nexport interface RouterProps {\n store: RouterStore;\n}\n\nexport const Router = observer(({ store }: RouterProps) => {\n if (!store.activeRoute) {\n return null;\n }\n\n const Layout = store.activeRoute.layout ?? PassThrough;\n const components = store.activeRoute.outlets.map((o) => o.Component);\n\n return (\n <routerContext.Provider value={store}>\n <Layout route={store.activeRoute}>\n <RouterOutlet route={store.activeRoute} components={components} />\n </Layout>\n </routerContext.Provider>\n );\n});\n","import { observer } from \"mobx-react-lite\";\nimport React, { useCallback } from \"react\";\nimport type {\n DynamicRoutePath,\n ExtractParams,\n NavigateOptions,\n RoutePath,\n StaticRoutePath,\n} from \"../types\";\nimport { resolvePath } from \"../util\";\nimport { useRouter } from \"./router\";\n\ntype LinkComponentProps<C extends React.ElementType> = Omit<\n React.ComponentProps<C>,\n \"ref\" | \"exact\" | \"to\" | \"params\" | \"onClick\" | \"asChild\"\n>;\n\nexport type LinkPropsBase<\n C extends React.ElementType,\n I extends React.ElementType = C,\n> = LinkComponentProps<C> & {\n exact?: boolean;\n preserveSearch?: boolean;\n ref?: React.Ref<React.ComponentRef<I>>;\n};\n\n// function overloading is much faster than leveraging conditional types\n// but once the typescript go compiler is released and performance is no\n// longer an issue, it might make sense to simplify this a bit so it can\n// be more easily consumed by users\nexport interface LinkComponent<C extends React.ElementType, I extends React.ElementType = C> {\n <P extends StaticRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params?: undefined },\n ): React.ReactNode;\n <P extends DynamicRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params: ExtractParams<P> },\n ): React.ReactNode;\n}\n\n// final thing to do is make sure refs still work in React 19\n\n// this smooths over some of the awkwardness when extending this component\nexport const makeLinkComponent = <C extends React.ElementType, I extends React.ElementType = C>(\n C: C,\n baseProps?: Partial<LinkComponentProps<C>> & { as?: I },\n) => {\n return observer(({ to, params, exact, preserveSearch, children, ...props }: any) => {\n const router = useRouter();\n const mergedProps = { ...baseProps, ...props };\n\n if (props.role !== \"link\") {\n mergedProps.href = resolvePath(to, params);\n }\n\n if (router.doesPathMatch(to, exact)) {\n mergedProps[\"aria-current\"] = \"page\";\n }\n\n mergedProps.onClick = useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n event.preventDefault();\n if (props.disabled) return;\n router.navigate({ to, preserveSearch, ...(params as any) } as NavigateOptions<RoutePath>);\n },\n [router, params, to, props.disabled],\n );\n\n return React.createElement(C, mergedProps, children);\n }) as LinkComponent<C, I>;\n};\n\n//export const Link = makeLinkComponent('a');\n","import { useLayoutEffect } from \"react\";\nimport type { NavigateOptions, RoutePath } from \"../types\";\nimport { useRouter } from \"./router\";\n\nexport const Navigate = <P extends RoutePath>(props: NavigateOptions<P>) => {\n const router = useRouter();\n\n useLayoutEffect(() => {\n router.navigate(props);\n }, [router, props]);\n\n return null;\n};\n","import { makeAutoObservable, observable } from \"mobx\";\nimport type { Route } from \"./route\";\nimport type { Component, LazyComponent, Loader } from \"./types\";\nimport { isLazyComponent } from \"./util\";\n\nexport interface OutletConfig {\n component?: Component | LazyComponent;\n loader?: Loader;\n}\n\nexport type RouteSegmentState = \"preloading\" | \"loading\" | \"error\" | \"ready\";\n\nexport const DefaultOutlet: Component = ({ children }) => children;\n\nconst LoadingPlaceholder: Component = () => <p>Loading...</p>;\n\nexport class Outlet {\n state: RouteSegmentState = \"preloading\";\n promise: Promise<unknown> | undefined;\n data: unknown;\n\n // Plain (non-observable) reference. The page component must reach\n // React unmediated by MobX — once MobX deep-observes the holder,\n // React Refresh can no longer swap the page identity via family\n // lookup on the original function. This mirrors how Route holds\n // `layout` as a plain field under makeObservable.\n component: Component | undefined;\n\n get Component(): Component | undefined {\n switch (this.state) {\n case \"loading\":\n return LoadingPlaceholder;\n case \"ready\":\n return this.component ?? DefaultOutlet;\n default:\n return undefined;\n }\n }\n\n constructor(readonly config: OutletConfig) {\n if (!isLazyComponent(config.component)) {\n this.component = config.component;\n }\n\n makeAutoObservable<Outlet, \"component\" | \"config\">(this, {\n promise: observable.ref,\n data: observable.ref,\n component: false,\n config: false,\n });\n }\n\n async load(route: Route): Promise<void> {\n const promises: Promise<void>[] = [];\n\n if (isLazyComponent(this.config.component) && !this.component) {\n promises.push(this.loadComponent());\n }\n\n if (this.config.loader) {\n promises.push(this.loadData(route));\n }\n\n if (!promises.length) {\n this.setState(\"ready\");\n return;\n }\n\n // wait to transition to loading to avoid\n // screen flashes when the loader function\n // executes quickly\n const preloadingTimer = setTimeout(() => {\n if (this.state === \"preloading\") {\n this.setState(\"loading\");\n }\n }, 300);\n\n this.promise = Promise.all(promises)\n .then(() => {\n clearTimeout(preloadingTimer);\n if (this.state === \"loading\") {\n // if we had to transition to regular loading because\n // the loader was taking too long, force an additional\n // timeout to prevent a loading flash\n setTimeout(() => {\n this.setState(\"ready\");\n }, 300);\n } else {\n this.setState(\"ready\");\n }\n })\n .catch(() => {\n clearTimeout(preloadingTimer);\n // TODO: check for type of error\n // handle access denied and redirects\n this.setState(\"error\");\n });\n\n await this.promise;\n }\n\n setData(data: unknown) {\n this.data = data;\n }\n\n setState(state: RouteSegmentState) {\n this.state = state;\n }\n\n private async loadData(route: Route): Promise<void> {\n await this.config.loader?.(route).then((data) => this.setData(data));\n }\n\n private async loadComponent(): Promise<void> {\n if (!isLazyComponent(this.config.component)) return;\n const module = await this.config.component();\n for (const exportName in module) {\n if (exportName === \"default\" || exportName.endsWith(\"Page\")) {\n this.component = module[exportName];\n return;\n }\n }\n throw new Error(\n \"Lazy route component module did not export `default` or a `*Page` named export\",\n );\n }\n}\n","import type { NavigateOptions, RoutePath } from \"./types\";\n\nexport class Redirect<P extends RoutePath> {\n constructor(readonly options: NavigateOptions<P>) {}\n}\n\nexport const redirect = <P extends RoutePath>(options: NavigateOptions<P>): Redirect<P> =>\n new Redirect(options);\n","import { computed, makeObservable } from \"mobx\";\nimport type { Outlet } from \"./outlet\";\nimport type { Component, Guard, Obj } from \"./types\";\n\nexport interface RouteConfig {\n path: string;\n outlets: Outlet[];\n guards: Guard[];\n context?: Obj;\n layout?: Component;\n params: Obj;\n}\n\nexport class Route {\n readonly path: string;\n readonly outlets: Outlet[];\n readonly guards: Guard[];\n readonly context: Obj;\n readonly params: Obj;\n readonly layout?: Component;\n\n get data(): Obj {\n return Object.assign({}, ...this.outlets.map((o) => o.data));\n }\n\n constructor(def: RouteConfig) {\n this.path = def.path;\n this.guards = def.guards;\n this.context = def.context ?? {};\n this.outlets = def.outlets;\n this.params = def.params;\n this.layout = def.layout;\n\n makeObservable(this, {\n data: computed,\n });\n }\n\n async guard(): Promise<void> {\n for (const guard of this.guards) {\n await guard(this);\n }\n }\n\n async load(): Promise<void> {\n await Promise.all(this.outlets.map((outlet) => outlet.load(this)));\n }\n}\n","import { Outlet } from \"./outlet\";\nimport { Redirect } from \"./redirect\";\nimport { Route } from \"./route\";\nimport { CONTEXT, GUARD, LAYOUT, LOAD, PAGE, REDIRECT, WRAPPER } from \"./symbols\";\nimport type { Component, Guard, Obj, Routes } from \"./types\";\nimport { isComponent, isLazyComponent, isLeaf, isPage, isRedirect } from \"./util\";\n\nconst pathToSegments = (path: string): string[] => {\n return path.replace(/^\\/+|\\/+$/g, \"\").split(\"/\");\n};\n\nexport interface MatchState {\n segments: string[];\n context: Obj;\n params: Obj;\n outlets: (Outlet | undefined)[];\n guards: (Guard | undefined)[];\n layout?: Component;\n}\n\nexport const makeRoute = (matchState: MatchState): Route => {\n const outlets = matchState.outlets.filter((o) => o !== undefined);\n const guards = matchState.guards.filter((g) => g !== undefined);\n\n return new Route({ ...matchState, outlets, guards, path: matchState.segments.join(\"/\") });\n};\n\nexport const matchRoute = (path: string, routeDef: Routes, matchState?: MatchState): Route => {\n const state: MatchState = {\n segments: [],\n params: {},\n ...matchState,\n layout: routeDef[LAYOUT] ?? matchState?.layout,\n context: { ...matchState?.context, ...routeDef[CONTEXT] },\n guards: [...(matchState?.guards ?? []), routeDef[GUARD]],\n outlets: [\n ...(matchState?.outlets ?? []),\n routeDef[WRAPPER] ? new Outlet({ component: routeDef[WRAPPER] }) : undefined,\n routeDef[LOAD] ? new Outlet({ loader: routeDef[LOAD] }) : undefined,\n ],\n };\n\n const [segment, ...remainingSegments] = pathToSegments(path);\n const remainingPath = remainingSegments.join(\"/\");\n\n let defAtSegment = routeDef[segment || \"index\"];\n\n if (!defAtSegment) {\n const matchedSegment = Object.keys(routeDef).find((segment) => segment.startsWith(\"$\"));\n if (matchedSegment) {\n defAtSegment = routeDef[matchedSegment];\n state.params[matchedSegment.slice(1)] = segment;\n }\n }\n\n if (!defAtSegment) {\n throw new Error(\"Not Found.\");\n }\n\n state.segments.push(segment ?? \"index\");\n\n if (isLeaf(defAtSegment)) {\n if (remainingPath) {\n throw new Error(\"Not Found.\");\n }\n\n if (isRedirect(defAtSegment)) {\n const redirect =\n typeof defAtSegment[REDIRECT] === \"string\"\n ? { to: defAtSegment[REDIRECT] }\n : defAtSegment[REDIRECT];\n throw new Redirect(redirect as any);\n }\n\n if (isComponent(defAtSegment) || isLazyComponent(defAtSegment)) {\n state.outlets.push(new Outlet({ component: defAtSegment }));\n return makeRoute(state);\n }\n }\n\n // at this point we have a nested route or a [Page] definition\n\n if (isPage(defAtSegment)) {\n state.layout = defAtSegment[LAYOUT] ?? state.layout;\n Object.assign(state.context, defAtSegment[CONTEXT]);\n state.guards.push(defAtSegment[GUARD]);\n state.outlets.push(\n new Outlet({\n component: defAtSegment[PAGE],\n loader: defAtSegment[LOAD],\n }),\n );\n\n return makeRoute(state);\n }\n\n // now we know we have a nested route\n return matchRoute(remainingPath, defAtSegment, state);\n};\n\n// TODO: ideally this could resolve to something less than R,\n// but specific enough to infer all paths as a literal union.\n// As it stands, there are certain things we can't access reliably\n// without the compiler complaining about circular references\n// try \"as const satisfies\" approach which would allow us to\n// exchange a less specific version of MobxRoutesRoot for this\nexport const makeRoutes =\n () =>\n <R extends Routes>(routes: R): R => {\n // todo: perform some validation here\n // - no forward slashes in keys\n // - at most one variable segment per level\n // - only lowercase letters (except variables)\n // - paths/variables cannot contain $ that aren't at the beginning\n // - path variables must be unique across a path\n\n return routes;\n };\n","import { createBrowserHistory, type History, type Location } from \"history\";\nimport { action, computed, makeObservable, observable, runInAction } from \"mobx\";\nimport { matchRoute } from \"./make-routes\";\nimport { Redirect } from \"./redirect\";\nimport type { Route } from \"./route\";\nimport type { Component, MobxRouterConfig, NavigateOptions, Obj, RoutePath, Routes } from \"./types\";\nimport { resolvePath } from \"./util\";\n\nexport interface MobxRenderSegment {\n segment: string;\n component: Component;\n props?: Obj;\n}\n\nexport class RouterStore {\n readonly history: History;\n\n routesDef?: Routes;\n\n location!: Location;\n activeRoute: Route | undefined;\n\n get search(): URLSearchParams {\n return new URLSearchParams(this.location?.search);\n }\n\n get query(): Record<string, string> {\n return Object.fromEntries(this.search);\n }\n\n get pathParams(): Record<string, string> {\n const params = {} as Record<string, string>;\n\n const paramSegments = this.activeSegments.filter((segment) => segment.startsWith(\"$\"));\n const pathValues = this.location.pathname.split(\"/\").slice(1);\n\n paramSegments.forEach((segment, index) => {\n const value = pathValues[index + 1];\n if (value) {\n params[segment] = value;\n }\n });\n\n return params as Record<string, string>;\n }\n\n get activeSegments(): string[] {\n return this.activeRoute?.path.split(\"/\") ?? [];\n }\n\n constructor(config?: MobxRouterConfig) {\n makeObservable(this, {\n location: observable.ref,\n activeRoute: observable.ref,\n\n search: computed,\n pathParams: computed,\n activeSegments: computed,\n\n setLocation: action,\n });\n\n this.history = config?.history ?? createBrowserHistory();\n }\n\n initialize(routesDef: Routes): void {\n this.routesDef = routesDef;\n this.history.listen((data) => {\n void this.setLocation(data.location);\n });\n\n void this.setLocation(this.history.location);\n }\n\n doesPathMatch<P extends RoutePath>(path: P, exact?: boolean): boolean {\n const segments = path.slice(1).split(\"/\");\n const segmentsMatch = segments.every(\n (segment, i) => segment === this.activeSegments[i] || segment.startsWith(\"$\"),\n );\n\n return (\n segmentsMatch &&\n this.activeSegments.length >= segments.length &&\n (!exact || segments.length === this.activeSegments.length)\n );\n }\n\n navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n if (!document.startViewTransition) {\n this._navigate(options);\n } else {\n const transition = document.startViewTransition(() => this._navigate(options));\n transition.ready.catch((e) => console.log(e, typeof e));\n }\n }\n\n _navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n const { to, replace, state, search = {}, preserveSearch, params } = options;\n\n const searchParams = search instanceof URLSearchParams ? search : new URLSearchParams(search);\n\n if (preserveSearch) {\n for (const [name, value] of this.search) {\n if (!searchParams.has(name)) {\n searchParams.set(name, value);\n }\n }\n }\n\n const location = {\n pathname: resolvePath(to, params),\n search: searchParams.size ? `?${searchParams.toString()}` : undefined,\n };\n\n if (replace) {\n this.history.replace(location, state);\n } else {\n this.history.push(location, state);\n }\n }\n\n setQueryParam(param: string, value: string): void {\n const params = new URLSearchParams(this.location.search);\n params.set(param, value);\n this.history.replace({ search: params.toString() });\n }\n\n removeQueryParam(param: string): string | undefined {\n const params = new URLSearchParams(this.location.search);\n const value = params.get(param) ?? undefined;\n if (value !== undefined) {\n params.delete(param);\n this.history.replace({ search: params.toString() });\n }\n return value;\n }\n\n async setLocation(location: Location): Promise<void> {\n if (!this.routesDef) return;\n\n // TODO: this should not be the responsibility of mobx-router\n // and should really be handled server-side\n if (location.pathname !== \"/\" && location.pathname.endsWith(\"/\")) {\n this.history.replace({ ...location, pathname: location.pathname.slice(0, -1) });\n return;\n }\n\n this.location = location;\n\n try {\n const matchedRoute = matchRoute(location.pathname, this.routesDef);\n\n await matchedRoute.guard();\n\n // navigating within a guard function\n // is essentially a redirect\n if (this.location !== location) {\n return;\n }\n\n runInAction(() => {\n this.activeRoute = matchedRoute;\n });\n\n await this.activeRoute?.load();\n } catch (e) {\n if (e instanceof Redirect) {\n this.navigate(e.options);\n return;\n }\n throw e;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.mjs","names":[],"sources":["../src/router/errors.ts","../src/router/components/error.tsx","../src/router/symbols.ts","../src/router/util.ts","../src/router/components/router.tsx","../src/router/components/link.tsx","../src/router/components/navigate.tsx","../src/router/redirect.ts","../src/router/outlet.tsx","../src/router/route.tsx","../src/router/make-routes.tsx","../src/router/router.store.ts"],"sourcesContent":["import type { MatchState } from \"./make-routes\";\n\nexport type RouterErrorType = \"NOT_FOUND\" | \"GUARD\" | \"LOAD\" | \"RENDER\";\n\nexport interface RouterErrorOptions {\n message?: string;\n cause?: unknown;\n path?: string;\n}\n\nconst defaultMessage = (type: RouterErrorType, path?: string): string => {\n switch (type) {\n case \"NOT_FOUND\":\n return path ? `No route matches '${path}'.` : \"No matching route.\";\n case \"GUARD\":\n return \"A route guard rejected the navigation.\";\n case \"LOAD\":\n return \"A route loader or lazy component failed.\";\n case \"RENDER\":\n return \"A route component failed to render.\";\n }\n};\n\n/**\n * The single error type surfaced to `[ERROR]` components. `type`\n * discriminates the failure source; when the router wraps an\n * application-level error (thrown by a guard or loader), the original\n * is preserved on the standard `cause` property.\n *\n * Guards and loaders may also throw `RouterError` directly — e.g.\n * `throw new RouterError(\"NOT_FOUND\")` from a loader when an entity\n * doesn't exist — and it passes through unwrapped.\n */\nexport class RouterError extends Error {\n readonly type: RouterErrorType;\n readonly path?: string;\n\n /** @internal matched-prefix state captured when the matcher throws NOT_FOUND */\n state?: MatchState;\n /** @internal level index of the failing guard, for depth-aware bubbling */\n depth?: number;\n\n constructor(type: RouterErrorType, options?: RouterErrorOptions) {\n super(options?.message ?? defaultMessage(type, options?.path), { cause: options?.cause });\n this.name = \"RouterError\";\n this.type = type;\n this.path = options?.path;\n }\n}\n","import React from \"react\";\nimport { RouterError } from \"../errors\";\nimport type { Route } from \"../route\";\nimport type { Component, ErrorComponentProps } from \"../types\";\n\n/**\n * Rendered when an error occurs and no `[ERROR]` component is defined\n * on the matched prefix. Deliberately minimal and dependency-free —\n * define a root-level `[ERROR]` to replace it.\n */\nexport const DefaultErrorPage: Component = ({ error }: ErrorComponentProps) => (\n <div role=\"alert\">\n <h1>{error.type === \"NOT_FOUND\" ? \"Page Not Found\" : \"Something Went Wrong\"}</h1>\n <p>{error.message}</p>\n </div>\n);\n\nexport interface RouteErrorBoundaryProps {\n route: Route;\n fallback: Component;\n children?: React.ReactNode;\n}\n\ninterface RouteErrorBoundaryState {\n error?: RouterError;\n}\n\n/**\n * Catches render-time crashes in page and `[WRAPPER]` components and\n * renders the nearest `[ERROR]` component with `type: \"RENDER\"`. Mounted\n * inside the `[LAYOUT]` so the layout survives page crashes; crashes in\n * the layout itself (or in the fallback) propagate out of `<Router>` by\n * design — those are developer bugs that should stay loud.\n */\nexport class RouteErrorBoundary extends React.Component<\n RouteErrorBoundaryProps,\n RouteErrorBoundaryState\n> {\n override state: RouteErrorBoundaryState = {};\n\n static getDerivedStateFromError(cause: unknown): RouteErrorBoundaryState {\n return { error: cause instanceof RouterError ? cause : new RouterError(\"RENDER\", { cause }) };\n }\n\n override render(): React.ReactNode {\n if (!this.state.error) return this.props.children;\n\n const Fallback = this.props.fallback;\n return <Fallback route={this.props.route} error={this.state.error} />;\n }\n}\n","export const CONTEXT: unique symbol = Symbol.for(\"MOBX_ROUTER_CONTEXT\");\nexport const LAYOUT: unique symbol = Symbol.for(\"MOBX_ROUTER_LAYOUT\");\nexport const WRAPPER: unique symbol = Symbol.for(\"MOBX_ROUTER_WRAPPER\");\nexport const LOAD: unique symbol = Symbol.for(\"MOBX_ROUTER_LOAD\");\nexport const GUARD: unique symbol = Symbol.for(\"MOBX_ROUTER_GUARD\");\nexport const PAGE: unique symbol = Symbol.for(\"MOBX_ROUTER_PAGE\");\nexport const ERROR: unique symbol = Symbol.for(\"MOBX_ROUTER_ERROR\");\nexport const REDIRECT: unique symbol = Symbol.for(\"MOBX_ROUTER_REDIRECT\");\n","import { PAGE, REDIRECT } from \"./symbols\";\nimport type { Component, LazyComponent, Leaf, Obj, Page, Redirector } from \"./types\";\n\nexport const resolvePath = (to: string, params?: Obj): string => {\n return to.replaceAll(/:[^/]*/g, (segment) => {\n const value = params?.[segment.slice(1)];\n if (!value)\n throw new Error(`Unable to resolve route '${to}'. Parameter '${segment}' not specified.`);\n return value;\n });\n};\n\nexport const isComponent = (data: any): data is Component => {\n if (!data) return false;\n return (\n typeof data === \"function\" ||\n (typeof data === \"object\" && data[\"$$typeof\"] === Symbol.for(\"react.memo\"))\n );\n};\n\nexport const isPage = (data: any): data is Page => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(PAGE);\n};\n\nexport const isRedirect = (data: any): data is Redirector => {\n if (typeof data !== \"object\") return false;\n const symbols = Object.getOwnPropertySymbols(data);\n return symbols.includes(REDIRECT);\n};\n\nexport const isLeaf = (data: any): data is Leaf => {\n return isComponent(data) || isPage(data) || isRedirect(data);\n};\n\nexport const isLazyComponent = (data: any): data is LazyComponent => {\n return typeof data === \"function\" && data.toString().startsWith(\"() => import(\");\n};\n","import { observer } from \"mobx-react-lite\";\nimport { createContext, useContext } from \"react\";\nimport type { Route } from \"../route\";\nimport type { RouterStore } from \"../router.store\";\nimport type { Component } from \"../types\";\nimport { DefaultErrorPage, RouteErrorBoundary } from \"./error\";\n\nexport const PassThrough: Component = ({ children }) => children;\n\n// Plain (non-observer) renderer. State observation lives one level up\n// in `Router`, so the page component renders as a child of a plain\n// FunctionComponent — no memo wrapper in the parent chain to interact\n// with React Refresh's family-update propagation.\nexport const RouterOutlet: React.FC<{ route: Route; components: (Component | undefined)[] }> = ({\n route,\n components,\n}) => {\n const [C, ...remaining] = components;\n\n if (!C) return null;\n\n return (\n <C route={route}>\n {remaining.length > 0 && <RouterOutlet route={route} components={remaining} />}\n </C>\n );\n};\n\nexport const routerContext = createContext<RouterStore>(null as any);\nexport const useRouter = () => useContext(routerContext);\n\nexport interface RouterProps {\n store: RouterStore;\n}\n\nexport const Router = observer(({ store }: RouterProps) => {\n const route = store.activeRoute;\n if (!route) {\n return null;\n }\n\n const Layout = route.layout ?? PassThrough;\n const components = route.outlets.map((o) => o.Component);\n const outlet = <RouterOutlet route={route} components={components} />;\n\n // Render crashes in pages/wrappers funnel to the nearest [ERROR]\n // component; the layout survives. On synthetic error routes the\n // boundary is omitted so a crashing [ERROR] component propagates\n // out of <Router> — a developer bug that should stay loud. Layout\n // crashes propagate for the same reason.\n const fallback = route.levels.at(-1)?.errorComponent ?? DefaultErrorPage;\n\n return (\n <routerContext.Provider value={store}>\n <Layout route={route}>\n {route.error ? (\n outlet\n ) : (\n <RouteErrorBoundary key={store.location.key} route={route} fallback={fallback}>\n {outlet}\n </RouteErrorBoundary>\n )}\n </Layout>\n </routerContext.Provider>\n );\n});\n","import { observer } from \"mobx-react-lite\";\nimport React, { useCallback } from \"react\";\nimport type {\n DynamicRoutePath,\n ExtractParams,\n NavigateOptions,\n RoutePath,\n StaticRoutePath,\n} from \"../types\";\nimport { resolvePath } from \"../util\";\nimport { useRouter } from \"./router\";\n\ntype LinkComponentProps<C extends React.ElementType> = Omit<\n React.ComponentProps<C>,\n \"ref\" | \"exact\" | \"to\" | \"params\" | \"onClick\" | \"asChild\"\n>;\n\nexport type LinkPropsBase<\n C extends React.ElementType,\n I extends React.ElementType = C,\n> = LinkComponentProps<C> & {\n exact?: boolean;\n preserveSearch?: boolean;\n ref?: React.Ref<React.ComponentRef<I>>;\n};\n\n// function overloading is much faster than leveraging conditional types\n// but once the typescript go compiler is released and performance is no\n// longer an issue, it might make sense to simplify this a bit so it can\n// be more easily consumed by users\nexport interface LinkComponent<C extends React.ElementType, I extends React.ElementType = C> {\n <P extends StaticRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params?: undefined },\n ): React.ReactNode;\n <P extends DynamicRoutePath>(\n props: LinkPropsBase<C, I> & { to: P; params: ExtractParams<P> },\n ): React.ReactNode;\n}\n\n// final thing to do is make sure refs still work in React 19\n\n// this smooths over some of the awkwardness when extending this component\nexport const makeLinkComponent = <C extends React.ElementType, I extends React.ElementType = C>(\n C: C,\n baseProps?: Partial<LinkComponentProps<C>> & { as?: I },\n) => {\n return observer(({ to, params, exact, preserveSearch, children, ...props }: any) => {\n const router = useRouter();\n const mergedProps = { ...baseProps, ...props };\n\n if (props.role !== \"link\") {\n mergedProps.href = resolvePath(to, params);\n }\n\n if (router.doesPathMatch(to, exact)) {\n mergedProps[\"aria-current\"] = \"page\";\n }\n\n mergedProps.onClick = useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n event.preventDefault();\n if (props.disabled) return;\n router.navigate({ to, preserveSearch, params } as NavigateOptions<RoutePath>);\n },\n [router, params, to, props.disabled],\n );\n\n return React.createElement(C, mergedProps, children);\n }) as LinkComponent<C, I>;\n};\n\n//export const Link = makeLinkComponent('a');\n","import { useLayoutEffect } from \"react\";\nimport type { NavigateOptions, RoutePath } from \"../types\";\nimport { useRouter } from \"./router\";\n\nexport const Navigate = <P extends RoutePath>(props: NavigateOptions<P>) => {\n const router = useRouter();\n\n useLayoutEffect(() => {\n router.navigate(props);\n }, [router, props]);\n\n return null;\n};\n","import type { NavigateOptions, RoutePath } from \"./types\";\n\nexport class Redirect<P extends RoutePath> {\n constructor(readonly options: NavigateOptions<P>) {}\n}\n\nexport const redirect = <P extends RoutePath>(options: NavigateOptions<P>): Redirect<P> =>\n new Redirect(options);\n","import { makeAutoObservable, observable } from \"mobx\";\nimport { DefaultErrorPage } from \"./components/error\";\nimport { RouterError } from \"./errors\";\nimport { Redirect } from \"./redirect\";\nimport type { Route } from \"./route\";\nimport type { Component, LazyComponent, Loader, Obj } from \"./types\";\nimport { isLazyComponent } from \"./util\";\n\nexport interface OutletConfig {\n component?: Component | LazyComponent;\n loader?: Loader;\n errorComponent?: Component;\n}\n\nexport type RouteSegmentState = \"preloading\" | \"loading\" | \"error\" | \"ready\";\n\nexport const DefaultOutlet: Component = ({ children }) => children;\n\nconst LoadingPlaceholder: Component = () => <p>Loading...</p>;\n\nexport class Outlet {\n state: RouteSegmentState = \"preloading\";\n promise: Promise<unknown> | undefined;\n data: unknown;\n error: RouterError | undefined;\n\n // Plain (non-observable) reference. The page component must reach\n // React unmediated by MobX — once MobX deep-observes the holder,\n // React Refresh can no longer swap the page identity via family\n // lookup on the original function. This mirrors how Route holds\n // `layout` as a plain field under makeObservable.\n component: Component | undefined;\n\n get Component(): Component | undefined {\n switch (this.state) {\n case \"loading\":\n return LoadingPlaceholder;\n case \"ready\":\n return this.component ?? DefaultOutlet;\n case \"error\": {\n // render the nearest [ERROR] component in this outlet's slot,\n // leaving the rest of the page intact\n const ErrorComponent = this.config.errorComponent ?? DefaultErrorPage;\n const error = this.error ?? new RouterError(\"LOAD\");\n return (props: Obj) => <ErrorComponent {...props} error={error} />;\n }\n default:\n return undefined;\n }\n }\n\n constructor(readonly config: OutletConfig) {\n if (!isLazyComponent(config.component)) {\n this.component = config.component;\n }\n\n makeAutoObservable<Outlet, \"component\" | \"config\">(this, {\n promise: observable.ref,\n data: observable.ref,\n error: observable.ref,\n component: false,\n config: false,\n });\n }\n\n async load(route: Route): Promise<void> {\n const promises: Promise<void>[] = [];\n\n if (isLazyComponent(this.config.component) && !this.component) {\n promises.push(this.loadComponent());\n }\n\n if (this.config.loader) {\n promises.push(this.loadData(route));\n }\n\n if (!promises.length) {\n this.setState(\"ready\");\n return;\n }\n\n // wait to transition to loading to avoid\n // screen flashes when the loader function\n // executes quickly\n const preloadingTimer = setTimeout(() => {\n if (this.state === \"preloading\") {\n this.setState(\"loading\");\n }\n }, 300);\n\n this.promise = Promise.all(promises)\n .then(() => {\n clearTimeout(preloadingTimer);\n if (this.state === \"loading\") {\n // if we had to transition to regular loading because\n // the loader was taking too long, force an additional\n // timeout to prevent a loading flash\n setTimeout(() => {\n this.setState(\"ready\");\n }, 300);\n } else {\n this.setState(\"ready\");\n }\n })\n .catch((e) => {\n clearTimeout(preloadingTimer);\n this.setState(\"error\");\n // a Redirect thrown by a loader propagates so the router\n // navigates; everything else renders in-slot error UI\n if (e instanceof Redirect) throw e;\n this.setError(e instanceof RouterError ? e : new RouterError(\"LOAD\", { cause: e }));\n });\n\n await this.promise;\n }\n\n setData(data: unknown) {\n this.data = data;\n }\n\n setError(error: RouterError) {\n this.error = error;\n }\n\n setState(state: RouteSegmentState) {\n this.state = state;\n }\n\n private async loadData(route: Route): Promise<void> {\n await this.config.loader?.(route).then((data) => this.setData(data));\n }\n\n private async loadComponent(): Promise<void> {\n if (!isLazyComponent(this.config.component)) return;\n const module = await this.config.component();\n for (const exportName in module) {\n if (exportName === \"default\" || exportName.endsWith(\"Page\")) {\n this.component = module[exportName];\n return;\n }\n }\n throw new Error(\n \"Lazy route component module did not export `default` or a `*Page` named export\",\n );\n }\n}\n","import { computed, makeObservable } from \"mobx\";\nimport { RouterError } from \"./errors\";\nimport type { Outlet } from \"./outlet\";\nimport { Redirect } from \"./redirect\";\nimport type { Component, Guard, GuardEntry, MatchLevel, Obj } from \"./types\";\n\nexport interface RouteConfig {\n path: string;\n outlets: Outlet[];\n guards: GuardEntry[];\n levels: MatchLevel[];\n context?: Obj;\n layout?: Component;\n params: Obj;\n error?: RouterError;\n}\n\nexport class Route {\n readonly path: string;\n readonly outlets: Outlet[];\n readonly guards: Guard[];\n readonly context: Obj;\n readonly params: Obj;\n readonly layout?: Component;\n /** set on synthetic error routes; the error being rendered */\n readonly error?: RouterError;\n /** @internal */\n readonly guardEntries: GuardEntry[];\n /** @internal */\n readonly levels: MatchLevel[];\n\n get data(): Obj {\n return Object.assign({}, ...this.outlets.map((o) => o.data));\n }\n\n constructor(def: RouteConfig) {\n this.path = def.path;\n this.guardEntries = def.guards;\n this.guards = def.guards.map((entry) => entry.guard);\n this.levels = def.levels;\n this.context = def.context ?? {};\n this.outlets = def.outlets;\n this.params = def.params;\n this.layout = def.layout;\n this.error = def.error;\n\n makeObservable(this, {\n data: computed,\n });\n }\n\n async guard(): Promise<void> {\n for (const { guard, depth } of this.guardEntries) {\n try {\n await guard(this);\n } catch (e) {\n if (e instanceof Redirect) throw e;\n const error = e instanceof RouterError ? e : new RouterError(\"GUARD\", { cause: e });\n error.depth ??= depth;\n throw error;\n }\n }\n }\n\n async load(): Promise<void> {\n await Promise.all(this.outlets.map((outlet) => outlet.load(this)));\n }\n}\n","import { DefaultErrorPage } from \"./components/error\";\nimport { RouterError } from \"./errors\";\nimport { Outlet } from \"./outlet\";\nimport { Redirect } from \"./redirect\";\nimport { Route } from \"./route\";\nimport { CONTEXT, ERROR, GUARD, LAYOUT, LOAD, PAGE, REDIRECT, WRAPPER } from \"./symbols\";\nimport type { Component, GuardEntry, MatchLevel, Obj, Routes } from \"./types\";\nimport { isComponent, isLazyComponent, isLeaf, isPage, isRedirect } from \"./util\";\n\nconst pathToSegments = (path: string): string[] => {\n return path.replace(/^\\/+|\\/+$/g, \"\").split(\"/\");\n};\n\nexport interface MatchState {\n segments: string[];\n context: Obj;\n params: Obj;\n outlets: (Outlet | undefined)[];\n guards: GuardEntry[];\n levels: MatchLevel[];\n layout?: Component;\n errorComponent?: Component;\n}\n\nexport const makeRoute = (matchState: MatchState): Route => {\n const outlets = matchState.outlets.filter((o) => o !== undefined);\n\n return new Route({ ...matchState, outlets, path: matchState.segments.join(\"/\") });\n};\n\n/**\n * Builds the synthetic route rendered when navigation fails. Bubbles\n * from the failing level (`error.depth`, defaulting to the deepest\n * matched level) to the nearest `[ERROR]` component, preserving the\n * `[LAYOUT]` and `[WRAPPER]`s accumulated up to that level. Ancestor\n * `[LOAD]` loaders are intentionally not run — error routes never\n * fetch data.\n */\nexport const makeErrorRoute = (\n error: RouterError,\n pathname: string,\n source?: { levels: MatchLevel[]; params: Obj; context: Obj },\n): Route => {\n const levels = error.state?.levels ?? source?.levels ?? [];\n const depth = Math.min(error.depth ?? levels.length - 1, levels.length - 1);\n const level = depth >= 0 ? levels[depth] : undefined;\n\n const ErrorComponent = level?.errorComponent ?? DefaultErrorPage;\n const outlets = levels\n .slice(0, depth + 1)\n .flatMap((l) => (l.wrapper ? [new Outlet({ component: l.wrapper })] : []));\n outlets.push(\n new Outlet({ component: (props: Obj) => <ErrorComponent {...props} error={error} /> }),\n );\n\n return new Route({\n path: pathname.replace(/^\\/+/, \"\"),\n outlets,\n guards: [],\n levels: [],\n params: error.state?.params ?? source?.params ?? {},\n context: error.state?.context ?? source?.context ?? {},\n layout: level?.layout,\n error,\n });\n};\n\nconst notFound = (state: MatchState, attemptedSegments: string[]): RouterError => {\n const error = new RouterError(\"NOT_FOUND\", {\n path: `/${attemptedSegments.filter((s) => s !== \"\").join(\"/\")}`,\n });\n error.state = state;\n return error;\n};\n\nexport const matchRoute = (path: string, routeDef: Routes, matchState?: MatchState): Route => {\n const depth = matchState?.levels.length ?? 0;\n const layout = routeDef[LAYOUT] ?? matchState?.layout;\n const errorComponent = routeDef[ERROR] ?? matchState?.errorComponent;\n\n const state: MatchState = {\n segments: [],\n params: {},\n ...matchState,\n layout,\n errorComponent,\n context: { ...matchState?.context, ...routeDef[CONTEXT] },\n guards: [\n ...(matchState?.guards ?? []),\n ...(routeDef[GUARD] ? [{ guard: routeDef[GUARD], depth }] : []),\n ],\n outlets: [\n ...(matchState?.outlets ?? []),\n routeDef[WRAPPER] ? new Outlet({ component: routeDef[WRAPPER], errorComponent }) : undefined,\n routeDef[LOAD] ? new Outlet({ loader: routeDef[LOAD], errorComponent }) : undefined,\n ],\n levels: [...(matchState?.levels ?? []), { wrapper: routeDef[WRAPPER], layout, errorComponent }],\n };\n\n const [segment, ...remainingSegments] = pathToSegments(path);\n const remainingPath = remainingSegments.join(\"/\");\n\n let defAtSegment = routeDef[segment || \"index\"];\n\n if (!defAtSegment) {\n const matchedSegment = Object.keys(routeDef).find(\n (segment) => segment.startsWith(\"$\") || segment.startsWith(\":\"),\n );\n if (matchedSegment) {\n defAtSegment = routeDef[matchedSegment];\n state.params[matchedSegment.slice(1)] = segment;\n }\n }\n\n if (!defAtSegment) {\n throw notFound(state, [...state.segments, segment ?? \"\", ...remainingSegments]);\n }\n\n state.segments.push(segment ?? \"index\");\n\n if (isLeaf(defAtSegment)) {\n if (remainingPath) {\n throw notFound(state, [...state.segments, ...remainingSegments]);\n }\n\n if (isRedirect(defAtSegment)) {\n const redirect =\n typeof defAtSegment[REDIRECT] === \"string\"\n ? { to: defAtSegment[REDIRECT] }\n : defAtSegment[REDIRECT];\n throw new Redirect(redirect as any);\n }\n\n if (isComponent(defAtSegment) || isLazyComponent(defAtSegment)) {\n state.outlets.push(new Outlet({ component: defAtSegment, errorComponent }));\n return makeRoute(state);\n }\n }\n\n // at this point we have a nested route or a [Page] definition\n\n if (isPage(defAtSegment)) {\n state.layout = defAtSegment[LAYOUT] ?? state.layout;\n state.errorComponent = defAtSegment[ERROR] ?? state.errorComponent;\n Object.assign(state.context, defAtSegment[CONTEXT]);\n if (defAtSegment[GUARD]) {\n state.guards.push({ guard: defAtSegment[GUARD], depth });\n }\n state.outlets.push(\n new Outlet({\n component: defAtSegment[PAGE],\n loader: defAtSegment[LOAD],\n errorComponent: state.errorComponent,\n }),\n );\n state.levels[state.levels.length - 1] = {\n ...state.levels[state.levels.length - 1],\n layout: state.layout,\n errorComponent: state.errorComponent,\n };\n\n return makeRoute(state);\n }\n\n // now we know we have a nested route\n return matchRoute(remainingPath, defAtSegment, state);\n};\n\n// TODO: ideally this could resolve to something less than R,\n// but specific enough to infer all paths as a literal union.\n// As it stands, there are certain things we can't access reliably\n// without the compiler complaining about circular references\n// try \"as const satisfies\" approach which would allow us to\n// exchange a less specific version of MobxRoutesRoot for this\nexport const makeRoutes =\n () =>\n <R extends Routes>(routes: R): R => {\n // todo: perform some validation here\n // - no forward slashes in keys\n // - at most one variable segment per level\n // - only lowercase letters (except variables)\n // - paths/variables cannot contain $ or : that aren't at the beginning\n // - path variables must be unique across a path\n return routes;\n };\n","import { createBrowserHistory, type History, type Location } from \"history\";\nimport { action, computed, makeObservable, observable, runInAction } from \"mobx\";\nimport { RouterError } from \"./errors\";\nimport { makeErrorRoute, matchRoute } from \"./make-routes\";\nimport { Redirect } from \"./redirect\";\nimport type { Route } from \"./route\";\nimport type { Component, MobxRouterConfig, NavigateOptions, Obj, RoutePath, Routes } from \"./types\";\nimport { resolvePath } from \"./util\";\n\nexport interface MobxRenderSegment {\n segment: string;\n component: Component;\n props?: Obj;\n}\n\nexport class RouterStore {\n readonly history: History;\n\n routesDef?: Routes;\n\n location!: Location;\n activeRoute: Route | undefined;\n\n get search(): URLSearchParams {\n return new URLSearchParams(this.location?.search);\n }\n\n get query(): Record<string, string> {\n return Object.fromEntries(this.search);\n }\n\n get pathParams(): Record<string, string> {\n return { ...this.activeRoute?.params };\n }\n\n get activeSegments(): string[] {\n return this.activeRoute?.path.split(\"/\") ?? [];\n }\n\n constructor(config?: MobxRouterConfig) {\n makeObservable(this, {\n location: observable.ref,\n activeRoute: observable.ref,\n\n search: computed,\n pathParams: computed,\n activeSegments: computed,\n\n setLocation: action,\n });\n\n this.history = config?.history ?? createBrowserHistory();\n }\n\n initialize(routesDef: Routes): void {\n this.routesDef = routesDef;\n this.history.listen((data) => {\n void this.setLocation(data.location);\n });\n\n void this.setLocation(this.history.location);\n }\n\n doesPathMatch<P extends RoutePath>(path: P, exact?: boolean): boolean {\n const segments = path.slice(1).split(\"/\");\n const segmentsMatch = segments.every(\n (segment, i) => segment === this.activeSegments[i] || segment.startsWith(\":\"),\n );\n\n return (\n segmentsMatch &&\n this.activeSegments.length >= segments.length &&\n (!exact || segments.length === this.activeSegments.length)\n );\n }\n\n navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n if (!document.startViewTransition) {\n this._navigate(options);\n } else {\n const transition = document.startViewTransition(() => this._navigate(options));\n transition.ready.catch((e) => console.log(e, typeof e));\n }\n }\n\n _navigate<P extends RoutePath>(options: NavigateOptions<P>): void {\n const { to, replace, state, search = {}, preserveSearch, params } = options;\n\n const searchParams = search instanceof URLSearchParams ? search : new URLSearchParams(search);\n\n if (preserveSearch) {\n for (const [name, value] of this.search) {\n if (!searchParams.has(name)) {\n searchParams.set(name, value);\n }\n }\n }\n\n const location = {\n pathname: resolvePath(to, params),\n search: searchParams.size ? `?${searchParams.toString()}` : undefined,\n };\n\n if (replace) {\n this.history.replace(location, state);\n } else {\n this.history.push(location, state);\n }\n }\n\n setQueryParam(param: string, value: string): void {\n const params = new URLSearchParams(this.location.search);\n params.set(param, value);\n this.history.replace({ search: params.toString() });\n }\n\n removeQueryParam(param: string): string | undefined {\n const params = new URLSearchParams(this.location.search);\n const value = params.get(param) ?? undefined;\n if (value !== undefined) {\n params.delete(param);\n this.history.replace({ search: params.toString() });\n }\n return value;\n }\n\n async setLocation(location: Location): Promise<void> {\n if (!this.routesDef) return;\n\n // TODO: this should not be the responsibility of mobx-router\n // and should really be handled server-side\n if (location.pathname !== \"/\" && location.pathname.endsWith(\"/\")) {\n this.history.replace({ ...location, pathname: location.pathname.slice(0, -1) });\n return;\n }\n\n this.location = location;\n\n let matchedRoute: Route | undefined;\n try {\n matchedRoute = matchRoute(location.pathname, this.routesDef);\n\n await matchedRoute.guard();\n\n // navigating within a guard function\n // is essentially a redirect\n if (this.location !== location) {\n return;\n }\n\n runInAction(() => {\n this.activeRoute = matchedRoute;\n });\n\n await this.activeRoute?.load();\n } catch (e) {\n if (e instanceof Redirect) {\n this.navigate(e.options);\n return;\n }\n\n // navigating within a guard before it threw — treat as a redirect\n if (this.location !== location) {\n return;\n }\n\n const error =\n e instanceof RouterError\n ? e\n : new RouterError(\"RENDER\", { cause: e, path: location.pathname });\n console.error(error);\n\n const errorRoute = makeErrorRoute(error, location.pathname, matchedRoute);\n runInAction(() => {\n this.activeRoute = errorRoute;\n });\n await errorRoute.load();\n }\n }\n}\n"],"mappings":"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"}
|