@tanstack/router-core 0.0.1-beta.161 → 0.0.1-beta.163
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/build/cjs/fileRoute.js.map +1 -1
- package/build/cjs/history.js +11 -11
- package/build/cjs/history.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +47 -29
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +58 -40
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +118 -118
- package/build/types/index.d.ts +46 -34
- package/build/umd/index.development.js +58 -40
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +2 -2
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/fileRoute.ts +5 -5
- package/src/history.ts +14 -14
- package/src/link.ts +8 -8
- package/src/route.ts +14 -23
- package/src/routeInfo.ts +2 -2
- package/src/router.ts +93 -50
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-core",
|
|
3
3
|
"author": "Tanner Linsley",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.163",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"tiny-invariant": "^1.3.1",
|
|
44
44
|
"tiny-warning": "^1.0.3",
|
|
45
45
|
"@gisatcz/cross-package-react-context": "^0.2.0",
|
|
46
|
-
"@tanstack/react-store": "0.0.1-beta.
|
|
46
|
+
"@tanstack/react-store": "0.0.1-beta.163"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "rollup --config rollup.config.js",
|
package/src/fileRoute.ts
CHANGED
|
@@ -59,7 +59,7 @@ export type ResolveFilePath<
|
|
|
59
59
|
? TrimPathLeft<TFilePath>
|
|
60
60
|
: Replace<
|
|
61
61
|
TrimPathLeft<TFilePath>,
|
|
62
|
-
TrimPathLeft<TParentRoute['
|
|
62
|
+
TrimPathLeft<TParentRoute['types']['customId']>,
|
|
63
63
|
''
|
|
64
64
|
>
|
|
65
65
|
|
|
@@ -96,14 +96,14 @@ export class FileRoute<
|
|
|
96
96
|
? AnyPathParams
|
|
97
97
|
: Record<ParsePathParams<TPath>, RouteConstraints['TPath']>,
|
|
98
98
|
TAllParams extends RouteConstraints['TAllParams'] = MergeParamsFromParent<
|
|
99
|
-
TParentRoute['
|
|
99
|
+
TParentRoute['types']['allParams'],
|
|
100
100
|
TParams
|
|
101
101
|
>,
|
|
102
|
-
TParentContext extends RouteConstraints['TParentContext'] = TParentRoute['
|
|
103
|
-
TAllParentContext extends RouteConstraints['TId'] = TParentRoute['
|
|
102
|
+
TParentContext extends RouteConstraints['TParentContext'] = TParentRoute['types']['routeContext'],
|
|
103
|
+
TAllParentContext extends RouteConstraints['TId'] = TParentRoute['types']['context'],
|
|
104
104
|
TRouteContext extends RouteConstraints['TRouteContext'] = RouteContext,
|
|
105
105
|
TContext extends RouteConstraints['TAllContext'] = MergeParamsFromParent<
|
|
106
|
-
TParentRoute['
|
|
106
|
+
TParentRoute['types']['context'],
|
|
107
107
|
TRouteContext
|
|
108
108
|
>,
|
|
109
109
|
TRouterContext extends RouteConstraints['TRouterContext'] = AnyContext,
|
package/src/history.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
export interface RouterHistory {
|
|
6
6
|
location: RouterLocation
|
|
7
|
-
|
|
7
|
+
subscribe: (cb: () => void) => () => void
|
|
8
8
|
push: (path: string, state?: any) => void
|
|
9
9
|
replace: (path: string, state?: any) => void
|
|
10
10
|
go: (index: number) => void
|
|
@@ -45,7 +45,7 @@ const stopBlocking = () => {
|
|
|
45
45
|
|
|
46
46
|
function createHistory(opts: {
|
|
47
47
|
getLocation: () => RouterLocation
|
|
48
|
-
|
|
48
|
+
subscriber: false | ((onUpdate: () => void) => () => void)
|
|
49
49
|
pushState: (path: string, state: any) => void
|
|
50
50
|
replaceState: (path: string, state: any) => void
|
|
51
51
|
go: (n: number) => void
|
|
@@ -55,7 +55,7 @@ function createHistory(opts: {
|
|
|
55
55
|
}): RouterHistory {
|
|
56
56
|
let location = opts.getLocation()
|
|
57
57
|
let unsub = () => {}
|
|
58
|
-
let
|
|
58
|
+
let subscribers = new Set<() => void>()
|
|
59
59
|
let blockers: BlockerFn[] = []
|
|
60
60
|
let queue: (() => void)[] = []
|
|
61
61
|
|
|
@@ -72,7 +72,7 @@ function createHistory(opts: {
|
|
|
72
72
|
queue.shift()?.()
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
if (!opts.
|
|
75
|
+
if (!opts.subscriber) {
|
|
76
76
|
onUpdate()
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -84,25 +84,25 @@ function createHistory(opts: {
|
|
|
84
84
|
|
|
85
85
|
const onUpdate = () => {
|
|
86
86
|
location = opts.getLocation()
|
|
87
|
-
|
|
87
|
+
subscribers.forEach((subscriber) => subscriber())
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
return {
|
|
91
91
|
get location() {
|
|
92
92
|
return location
|
|
93
93
|
},
|
|
94
|
-
|
|
95
|
-
if (
|
|
94
|
+
subscribe: (cb: () => void) => {
|
|
95
|
+
if (subscribers.size === 0) {
|
|
96
96
|
unsub =
|
|
97
|
-
typeof opts.
|
|
98
|
-
? opts.
|
|
97
|
+
typeof opts.subscriber === 'function'
|
|
98
|
+
? opts.subscriber(onUpdate)
|
|
99
99
|
: () => {}
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
subscribers.add(cb)
|
|
102
102
|
|
|
103
103
|
return () => {
|
|
104
|
-
|
|
105
|
-
if (
|
|
104
|
+
subscribers.delete(cb)
|
|
105
|
+
if (subscribers.size === 0) {
|
|
106
106
|
unsub()
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -166,7 +166,7 @@ export function createBrowserHistory(opts?: {
|
|
|
166
166
|
|
|
167
167
|
return createHistory({
|
|
168
168
|
getLocation,
|
|
169
|
-
|
|
169
|
+
subscriber: (onUpdate) => {
|
|
170
170
|
window.addEventListener(pushStateEvent, onUpdate)
|
|
171
171
|
window.addEventListener(popStateEvent, onUpdate)
|
|
172
172
|
|
|
@@ -234,7 +234,7 @@ export function createMemoryHistory(
|
|
|
234
234
|
|
|
235
235
|
return createHistory({
|
|
236
236
|
getLocation,
|
|
237
|
-
|
|
237
|
+
subscriber: false,
|
|
238
238
|
pushState: (path, state) => {
|
|
239
239
|
currentState = {
|
|
240
240
|
...state,
|
package/src/link.ts
CHANGED
|
@@ -152,17 +152,17 @@ export type SearchParamOptions<
|
|
|
152
152
|
TFromSchema = UnionToIntersection<
|
|
153
153
|
FullSearchSchema<TRouteTree> & RouteByPath<TRouteTree, TFrom> extends never
|
|
154
154
|
? {}
|
|
155
|
-
: RouteByPath<TRouteTree, TFrom>['
|
|
155
|
+
: RouteByPath<TRouteTree, TFrom>['types']['fullSearchSchema']
|
|
156
156
|
>,
|
|
157
157
|
// Find the schema for the new path, and make optional any keys
|
|
158
158
|
// that are already defined in the current schema
|
|
159
159
|
TToSchema = Partial<
|
|
160
|
-
RouteByPath<TRouteTree, TFrom>['
|
|
160
|
+
RouteByPath<TRouteTree, TFrom>['types']['fullSearchSchema']
|
|
161
161
|
> &
|
|
162
162
|
Omit<
|
|
163
|
-
RouteByPath<TRouteTree, TTo>['
|
|
163
|
+
RouteByPath<TRouteTree, TTo>['types']['fullSearchSchema'],
|
|
164
164
|
keyof PickRequired<
|
|
165
|
-
RouteByPath<TRouteTree, TFrom>['
|
|
165
|
+
RouteByPath<TRouteTree, TFrom>['types']['fullSearchSchema']
|
|
166
166
|
>
|
|
167
167
|
>,
|
|
168
168
|
TFromFullSchema = UnionToIntersection<
|
|
@@ -188,14 +188,14 @@ export type PathParamOptions<
|
|
|
188
188
|
TFromSchema = UnionToIntersection<
|
|
189
189
|
RouteByPath<TRouteTree, TFrom> extends never
|
|
190
190
|
? {}
|
|
191
|
-
: RouteByPath<TRouteTree, TFrom>['
|
|
191
|
+
: RouteByPath<TRouteTree, TFrom>['types']['allParams']
|
|
192
192
|
>,
|
|
193
193
|
// Find the schema for the new path, and make optional any keys
|
|
194
194
|
// that are already defined in the current schema
|
|
195
|
-
TToSchema = Partial<RouteByPath<TRouteTree, TFrom>['
|
|
195
|
+
TToSchema = Partial<RouteByPath<TRouteTree, TFrom>['types']['allParams']> &
|
|
196
196
|
Omit<
|
|
197
|
-
RouteByPath<TRouteTree, TTo>['
|
|
198
|
-
keyof PickRequired<RouteByPath<TRouteTree, TFrom>['
|
|
197
|
+
RouteByPath<TRouteTree, TTo>['types']['allParams'],
|
|
198
|
+
keyof PickRequired<RouteByPath<TRouteTree, TFrom>['types']['allParams']>
|
|
199
199
|
>,
|
|
200
200
|
TFromFullParams = UnionToIntersection<AllParams<TRouteTree> & TFromSchema>,
|
|
201
201
|
TToFullParams = UnionToIntersection<AllParams<TRouteTree> & TToSchema>,
|
package/src/route.ts
CHANGED
|
@@ -81,12 +81,12 @@ export type ComponentFromRoute<TRoute> = RegisteredRouteComponent<
|
|
|
81
81
|
>
|
|
82
82
|
|
|
83
83
|
export type RouteLoaderFromRoute<TRoute extends AnyRoute> = LoaderFn<
|
|
84
|
-
TRoute['
|
|
85
|
-
TRoute['
|
|
86
|
-
TRoute['
|
|
87
|
-
TRoute['
|
|
88
|
-
TRoute['
|
|
89
|
-
TRoute['
|
|
84
|
+
TRoute['types']['loader'],
|
|
85
|
+
TRoute['types']['searchSchema'],
|
|
86
|
+
TRoute['types']['fullSearchSchema'],
|
|
87
|
+
TRoute['types']['allParams'],
|
|
88
|
+
TRoute['types']['routeContext'],
|
|
89
|
+
TRoute['types']['context']
|
|
90
90
|
>
|
|
91
91
|
|
|
92
92
|
export type RouteProps<
|
|
@@ -312,7 +312,7 @@ export type UpdatableRouteOptions<
|
|
|
312
312
|
gcMaxAge?: number
|
|
313
313
|
// This async function is called before a route is loaded.
|
|
314
314
|
// If an error is thrown here, the route's loader will not be called.
|
|
315
|
-
// If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `
|
|
315
|
+
// If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onError` function.
|
|
316
316
|
// If thrown during a preload event, the error will be logged to the console.
|
|
317
317
|
beforeLoad?: (
|
|
318
318
|
opts: LoaderContext<
|
|
@@ -323,15 +323,6 @@ export type UpdatableRouteOptions<
|
|
|
323
323
|
TContext
|
|
324
324
|
>,
|
|
325
325
|
) => Promise<void> | void
|
|
326
|
-
// This function will be called if the route's loader throws an error **during an attempted navigation**.
|
|
327
|
-
// If you want to redirect due to an error, call `router.navigate()` from within this function.
|
|
328
|
-
onBeforeLoadError?: (err: any) => void
|
|
329
|
-
// This function will be called if the route's validateSearch option throws an error **during an attempted validation**.
|
|
330
|
-
// If you want to redirect due to an error, call `router.navigate()` from within this function.
|
|
331
|
-
// If you want to display the errorComponent, rethrow the error
|
|
332
|
-
onValidateSearchError?: (err: any) => void
|
|
333
|
-
onParseParamsError?: (err: any) => void
|
|
334
|
-
onLoadError?: (err: any) => void
|
|
335
326
|
onError?: (err: any) => void
|
|
336
327
|
// This function is called
|
|
337
328
|
// when moving from an inactive state to an active one. Likewise, when moving from
|
|
@@ -443,13 +434,13 @@ export type ResolveId<
|
|
|
443
434
|
|
|
444
435
|
export type InferFullSearchSchema<TRoute> = TRoute extends {
|
|
445
436
|
isRoot: true
|
|
446
|
-
|
|
437
|
+
types: {
|
|
447
438
|
searchSchema: infer TSearchSchema
|
|
448
439
|
}
|
|
449
440
|
}
|
|
450
441
|
? TSearchSchema
|
|
451
442
|
: TRoute extends {
|
|
452
|
-
|
|
443
|
+
types: {
|
|
453
444
|
fullSearchSchema: infer TFullSearchSchema
|
|
454
445
|
}
|
|
455
446
|
}
|
|
@@ -542,21 +533,21 @@ export class Route<
|
|
|
542
533
|
string
|
|
543
534
|
>,
|
|
544
535
|
TAllParams extends RouteConstraints['TAllParams'] = MergeParamsFromParent<
|
|
545
|
-
TParentRoute['
|
|
536
|
+
TParentRoute['types']['allParams'],
|
|
546
537
|
TParams
|
|
547
538
|
>,
|
|
548
|
-
TParentContext extends RouteConstraints['TParentContext'] = TParentRoute['
|
|
549
|
-
TAllParentContext extends RouteConstraints['TAllParentContext'] = TParentRoute['
|
|
539
|
+
TParentContext extends RouteConstraints['TParentContext'] = TParentRoute['types']['routeContext'],
|
|
540
|
+
TAllParentContext extends RouteConstraints['TAllParentContext'] = TParentRoute['types']['context'],
|
|
550
541
|
TRouteContext extends RouteConstraints['TRouteContext'] = RouteContext,
|
|
551
542
|
TAllContext extends RouteConstraints['TAllContext'] = MergeParamsFromParent<
|
|
552
|
-
TParentRoute['
|
|
543
|
+
TParentRoute['types']['context'],
|
|
553
544
|
TRouteContext
|
|
554
545
|
>,
|
|
555
546
|
TRouterContext extends RouteConstraints['TRouterContext'] = AnyContext,
|
|
556
547
|
TChildren extends RouteConstraints['TChildren'] = unknown,
|
|
557
548
|
TRouteTree extends RouteConstraints['TRouteTree'] = AnyRoute,
|
|
558
549
|
> {
|
|
559
|
-
|
|
550
|
+
types!: {
|
|
560
551
|
parentRoute: TParentRoute
|
|
561
552
|
path: TPath
|
|
562
553
|
to: TrimPathRight<TFullPath>
|
package/src/routeInfo.ts
CHANGED
|
@@ -63,9 +63,9 @@ export type RoutePaths<TRouteTree extends AnyRoute> =
|
|
|
63
63
|
| '/'
|
|
64
64
|
|
|
65
65
|
export type FullSearchSchema<TRouteTree extends AnyRoute> = MergeUnion<
|
|
66
|
-
ParseRoute<TRouteTree>['
|
|
66
|
+
ParseRoute<TRouteTree>['types']['fullSearchSchema']
|
|
67
67
|
> & {}
|
|
68
68
|
|
|
69
69
|
export type AllParams<TRouteTree extends AnyRoute> = MergeUnion<
|
|
70
|
-
ParseRoute<TRouteTree>['
|
|
70
|
+
ParseRoute<TRouteTree>['types']['allParams']
|
|
71
71
|
>
|
package/src/router.ts
CHANGED
|
@@ -114,7 +114,7 @@ export interface RouteMatch<
|
|
|
114
114
|
key?: string
|
|
115
115
|
routeId: string
|
|
116
116
|
pathname: string
|
|
117
|
-
params: TRoute['
|
|
117
|
+
params: TRoute['types']['allParams']
|
|
118
118
|
status: 'pending' | 'success' | 'error'
|
|
119
119
|
isFetching: boolean
|
|
120
120
|
invalid: boolean
|
|
@@ -124,13 +124,13 @@ export interface RouteMatch<
|
|
|
124
124
|
updatedAt: number
|
|
125
125
|
invalidAt: number
|
|
126
126
|
preloadInvalidAt: number
|
|
127
|
-
loaderData: TRoute['
|
|
127
|
+
loaderData: TRoute['types']['loader']
|
|
128
128
|
loadPromise?: Promise<void>
|
|
129
129
|
__resolveLoadPromise?: () => void
|
|
130
|
-
routeContext: TRoute['
|
|
131
|
-
context: TRoute['
|
|
132
|
-
routeSearch: TRoute['
|
|
133
|
-
search: FullSearchSchema<TRouteTree> & TRoute['
|
|
130
|
+
routeContext: TRoute['types']['routeContext']
|
|
131
|
+
context: TRoute['types']['context']
|
|
132
|
+
routeSearch: TRoute['types']['searchSchema']
|
|
133
|
+
search: FullSearchSchema<TRouteTree> & TRoute['types']['fullSearchSchema']
|
|
134
134
|
fetchedAt: number
|
|
135
135
|
abortController: AbortController
|
|
136
136
|
}
|
|
@@ -138,12 +138,12 @@ export interface RouteMatch<
|
|
|
138
138
|
export type AnyRouteMatch = RouteMatch<AnyRoute, AnyRoute>
|
|
139
139
|
|
|
140
140
|
export type RouterContextOptions<TRouteTree extends AnyRoute> =
|
|
141
|
-
AnyContext extends TRouteTree['
|
|
141
|
+
AnyContext extends TRouteTree['types']['routerContext']
|
|
142
142
|
? {
|
|
143
|
-
context?: TRouteTree['
|
|
143
|
+
context?: TRouteTree['types']['routerContext']
|
|
144
144
|
}
|
|
145
145
|
: {
|
|
146
|
-
context: TRouteTree['
|
|
146
|
+
context: TRouteTree['types']['routerContext']
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
export interface RouterOptions<
|
|
@@ -171,8 +171,7 @@ export interface RouterOptions<
|
|
|
171
171
|
routeTree?: TRouteTree
|
|
172
172
|
basepath?: string
|
|
173
173
|
createRoute?: (opts: { route: AnyRoute; router: AnyRouter }) => void
|
|
174
|
-
|
|
175
|
-
context?: TRouteTree['__types']['routerContext']
|
|
174
|
+
context?: TRouteTree['types']['routerContext']
|
|
176
175
|
Wrap?: React.ComponentType<{
|
|
177
176
|
children: React.ReactNode
|
|
178
177
|
dehydratedState?: TDehydrated
|
|
@@ -197,7 +196,7 @@ export interface RouterState<
|
|
|
197
196
|
lastUpdated: number
|
|
198
197
|
}
|
|
199
198
|
|
|
200
|
-
export type ListenerFn = () => void
|
|
199
|
+
export type ListenerFn<TEvent extends RouterEvent> = (event: TEvent) => void
|
|
201
200
|
|
|
202
201
|
export interface BuildNextOptions {
|
|
203
202
|
to?: string | number | null
|
|
@@ -249,6 +248,28 @@ export const componentTypes = [
|
|
|
249
248
|
'pendingComponent',
|
|
250
249
|
] as const
|
|
251
250
|
|
|
251
|
+
export type RouterEvents = {
|
|
252
|
+
onBeforeLoad: {
|
|
253
|
+
type: 'onBeforeLoad'
|
|
254
|
+
from: ParsedLocation
|
|
255
|
+
to: ParsedLocation
|
|
256
|
+
pathChanged: boolean
|
|
257
|
+
}
|
|
258
|
+
onLoad: {
|
|
259
|
+
type: 'onLoad'
|
|
260
|
+
from: ParsedLocation
|
|
261
|
+
to: ParsedLocation
|
|
262
|
+
pathChanged: boolean
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export type RouterEvent = RouterEvents[keyof RouterEvents]
|
|
267
|
+
|
|
268
|
+
export type RouterListener<TRouterEvent extends RouterEvent> = {
|
|
269
|
+
eventType: TRouterEvent['type']
|
|
270
|
+
fn: ListenerFn<TRouterEvent>
|
|
271
|
+
}
|
|
272
|
+
|
|
252
273
|
export class Router<
|
|
253
274
|
TRouteTree extends AnyRoute = AnyRoute,
|
|
254
275
|
TDehydrated extends Record<string, any> = Record<string, any>,
|
|
@@ -343,6 +364,32 @@ export class Router<
|
|
|
343
364
|
}
|
|
344
365
|
}
|
|
345
366
|
|
|
367
|
+
subscribers = new Set<RouterListener<RouterEvent>>()
|
|
368
|
+
|
|
369
|
+
subscribe = <TType extends keyof RouterEvents>(
|
|
370
|
+
eventType: TType,
|
|
371
|
+
fn: ListenerFn<RouterEvents[TType]>,
|
|
372
|
+
) => {
|
|
373
|
+
const listener: RouterListener<any> = {
|
|
374
|
+
eventType,
|
|
375
|
+
fn,
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
this.subscribers.add(listener)
|
|
379
|
+
|
|
380
|
+
return () => {
|
|
381
|
+
this.subscribers.delete(listener)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
#emit = (routerEvent: RouterEvent) => {
|
|
386
|
+
this.subscribers.forEach((listener) => {
|
|
387
|
+
if (listener.eventType === routerEvent.type) {
|
|
388
|
+
listener.fn(routerEvent)
|
|
389
|
+
}
|
|
390
|
+
})
|
|
391
|
+
}
|
|
392
|
+
|
|
346
393
|
reset = () => {
|
|
347
394
|
this.__store.setState((s) => Object.assign(s, getInitialRouterState()))
|
|
348
395
|
}
|
|
@@ -384,7 +431,7 @@ export class Router<
|
|
|
384
431
|
location: parsedLocation as any,
|
|
385
432
|
}))
|
|
386
433
|
|
|
387
|
-
this.#unsubHistory = this.history.
|
|
434
|
+
this.#unsubHistory = this.history.subscribe(() => {
|
|
388
435
|
this.safeLoad({
|
|
389
436
|
next: this.#parseLocation(this.state.location),
|
|
390
437
|
})
|
|
@@ -435,6 +482,11 @@ export class Router<
|
|
|
435
482
|
|
|
436
483
|
load = async (opts?: { next?: ParsedLocation; throwOnError?: boolean }) => {
|
|
437
484
|
const promise = new Promise<void>(async (resolve, reject) => {
|
|
485
|
+
const prevLocation = this.state.resolvedLocation
|
|
486
|
+
const pathDidChange = !!(
|
|
487
|
+
opts?.next && prevLocation!.href !== opts.next.href
|
|
488
|
+
)
|
|
489
|
+
|
|
438
490
|
let latestPromise: Promise<void> | undefined | null
|
|
439
491
|
|
|
440
492
|
const checkLatest = (): undefined | Promise<void> | null => {
|
|
@@ -448,6 +500,13 @@ export class Router<
|
|
|
448
500
|
|
|
449
501
|
let pendingMatches!: RouteMatch<any, any>[]
|
|
450
502
|
|
|
503
|
+
this.#emit({
|
|
504
|
+
type: 'onBeforeLoad',
|
|
505
|
+
from: prevLocation,
|
|
506
|
+
to: opts?.next ?? this.state.location,
|
|
507
|
+
pathChanged: pathDidChange,
|
|
508
|
+
})
|
|
509
|
+
|
|
451
510
|
this.__store.batch(() => {
|
|
452
511
|
if (opts?.next) {
|
|
453
512
|
// Ingest the new location
|
|
@@ -489,8 +548,6 @@ export class Router<
|
|
|
489
548
|
return latestPromise
|
|
490
549
|
}
|
|
491
550
|
|
|
492
|
-
const prevLocation = this.state.resolvedLocation
|
|
493
|
-
|
|
494
551
|
this.__store.setState((s) => ({
|
|
495
552
|
...s,
|
|
496
553
|
status: 'idle',
|
|
@@ -499,9 +556,12 @@ export class Router<
|
|
|
499
556
|
pendingMatchIds: [],
|
|
500
557
|
}))
|
|
501
558
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
559
|
+
this.#emit({
|
|
560
|
+
type: 'onLoad',
|
|
561
|
+
from: prevLocation,
|
|
562
|
+
to: this.state.location,
|
|
563
|
+
pathChanged: pathDidChange,
|
|
564
|
+
})
|
|
505
565
|
|
|
506
566
|
resolve()
|
|
507
567
|
} catch (err) {
|
|
@@ -844,19 +904,16 @@ export class Router<
|
|
|
844
904
|
for (const [index, match] of resolvedMatches.entries()) {
|
|
845
905
|
const route = this.getRoute(match.routeId)
|
|
846
906
|
|
|
847
|
-
const handleError = (
|
|
848
|
-
err
|
|
849
|
-
handler: undefined | ((err: any) => void),
|
|
850
|
-
) => {
|
|
907
|
+
const handleError = (err: any, code: string) => {
|
|
908
|
+
err.routerCode = code
|
|
851
909
|
firstBadMatchIndex = firstBadMatchIndex ?? index
|
|
852
|
-
handler = handler || route.options.onError
|
|
853
910
|
|
|
854
911
|
if (isRedirect(err)) {
|
|
855
912
|
throw err
|
|
856
913
|
}
|
|
857
914
|
|
|
858
915
|
try {
|
|
859
|
-
|
|
916
|
+
route.options.onError?.(err)
|
|
860
917
|
} catch (errorHandlerErr) {
|
|
861
918
|
err = errorHandlerErr
|
|
862
919
|
|
|
@@ -874,11 +931,11 @@ export class Router<
|
|
|
874
931
|
}
|
|
875
932
|
|
|
876
933
|
if (match.paramsError) {
|
|
877
|
-
handleError(match.paramsError,
|
|
934
|
+
handleError(match.paramsError, 'PARSE_PARAMS')
|
|
878
935
|
}
|
|
879
936
|
|
|
880
937
|
if (match.searchError) {
|
|
881
|
-
handleError(match.searchError,
|
|
938
|
+
handleError(match.searchError, 'VALIDATE_SEARCH')
|
|
882
939
|
}
|
|
883
940
|
|
|
884
941
|
let didError = false
|
|
@@ -889,7 +946,7 @@ export class Router<
|
|
|
889
946
|
preload: !!opts?.preload,
|
|
890
947
|
})
|
|
891
948
|
} catch (err) {
|
|
892
|
-
handleError(err,
|
|
949
|
+
handleError(err, 'BEFORE_LOAD')
|
|
893
950
|
didError = true
|
|
894
951
|
}
|
|
895
952
|
|
|
@@ -968,34 +1025,20 @@ export class Router<
|
|
|
968
1025
|
if ((latestPromise = checkLatest())) return await latestPromise
|
|
969
1026
|
|
|
970
1027
|
this.setRouteMatchData(match.id, () => loader, opts)
|
|
971
|
-
} catch (
|
|
972
|
-
let latestError = loaderError
|
|
1028
|
+
} catch (error) {
|
|
973
1029
|
if ((latestPromise = checkLatest())) return await latestPromise
|
|
974
|
-
if (handleIfRedirect(
|
|
975
|
-
|
|
976
|
-
if (route.options.onLoadError) {
|
|
977
|
-
try {
|
|
978
|
-
route.options.onLoadError(loaderError)
|
|
979
|
-
} catch (onLoadError) {
|
|
980
|
-
latestError = onLoadError
|
|
981
|
-
if (handleIfRedirect(onLoadError)) return
|
|
982
|
-
}
|
|
983
|
-
}
|
|
1030
|
+
if (handleIfRedirect(error)) return
|
|
984
1031
|
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
route.options.onError(latestError)
|
|
991
|
-
} catch (onErrorError) {
|
|
992
|
-
if (handleIfRedirect(onErrorError)) return
|
|
993
|
-
}
|
|
1032
|
+
try {
|
|
1033
|
+
route.options.onError?.(error)
|
|
1034
|
+
} catch (onErrorError) {
|
|
1035
|
+
error = onErrorError
|
|
1036
|
+
if (handleIfRedirect(onErrorError)) return
|
|
994
1037
|
}
|
|
995
1038
|
|
|
996
1039
|
this.setRouteMatch(match.id, (s) => ({
|
|
997
1040
|
...s,
|
|
998
|
-
error
|
|
1041
|
+
error,
|
|
999
1042
|
status: 'error',
|
|
1000
1043
|
isFetching: false,
|
|
1001
1044
|
updatedAt: Date.now(),
|
|
@@ -1089,7 +1132,7 @@ export class Router<
|
|
|
1089
1132
|
>(
|
|
1090
1133
|
location: ToOptions<TRouteTree, TFrom, TTo>,
|
|
1091
1134
|
opts?: MatchRouteOptions,
|
|
1092
|
-
): false | RouteById<TRouteTree, TResolved>['
|
|
1135
|
+
): false | RouteById<TRouteTree, TResolved>['types']['allParams'] => {
|
|
1093
1136
|
location = {
|
|
1094
1137
|
...location,
|
|
1095
1138
|
to: location.to
|