@tanstack/react-router 0.0.1-beta.2 → 0.0.1-beta.21
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/react-router/src/index.js +117 -116
- package/build/cjs/react-router/src/index.js.map +1 -1
- package/build/cjs/router-core/build/esm/index.js +257 -227
- package/build/cjs/router-core/build/esm/index.js.map +1 -1
- package/build/esm/index.js +362 -342
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +29 -29
- package/build/types/index.d.ts +61 -31
- package/build/umd/index.development.js +373 -342
- 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 +3 -2
- package/src/index.tsx +260 -192
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-router",
|
|
3
3
|
"author": "Tanner Linsley",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.21",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router/",
|
|
@@ -34,13 +34,14 @@
|
|
|
34
34
|
"build/**",
|
|
35
35
|
"src"
|
|
36
36
|
],
|
|
37
|
+
"sideEffects": false,
|
|
37
38
|
"peerDependencies": {
|
|
38
39
|
"react": ">=16",
|
|
39
40
|
"react-dom": ">=16"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
42
43
|
"@babel/runtime": "^7.16.7",
|
|
43
|
-
"@tanstack/router-core": "0.0.1-beta.
|
|
44
|
+
"@tanstack/router-core": "0.0.1-beta.21",
|
|
44
45
|
"use-sync-external-store": "^1.2.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
package/src/index.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
AnyRoute,
|
|
7
7
|
CheckId,
|
|
8
8
|
rootRouteId,
|
|
9
|
-
|
|
9
|
+
Route,
|
|
10
10
|
RouterState,
|
|
11
11
|
ToIdOption,
|
|
12
12
|
} from '@tanstack/router-core'
|
|
@@ -31,15 +31,119 @@ import {
|
|
|
31
31
|
NoInfer,
|
|
32
32
|
ToOptions,
|
|
33
33
|
invariant,
|
|
34
|
+
Router,
|
|
34
35
|
} from '@tanstack/router-core'
|
|
35
36
|
|
|
36
37
|
export * from '@tanstack/router-core'
|
|
37
38
|
|
|
39
|
+
export interface RegisterRouter {
|
|
40
|
+
// router: Router
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type RegisteredRouter = RegisterRouter extends {
|
|
44
|
+
router: Router<infer TRouteConfig, infer TAllRouteInfo>
|
|
45
|
+
}
|
|
46
|
+
? Router<TRouteConfig, TAllRouteInfo>
|
|
47
|
+
: Router
|
|
48
|
+
|
|
49
|
+
export type RegisteredAllRouteInfo = RegisterRouter extends {
|
|
50
|
+
router: Router<infer TRouteConfig, infer TAllRouteInfo>
|
|
51
|
+
}
|
|
52
|
+
? TAllRouteInfo
|
|
53
|
+
: AnyAllRouteInfo
|
|
54
|
+
|
|
55
|
+
export type SyncRouteComponent = (props?: {}) => JSX.Element | React.ReactNode
|
|
56
|
+
|
|
57
|
+
export type RouteComponent = SyncRouteComponent & {
|
|
58
|
+
preload?: () => Promise<SyncRouteComponent>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function lazy(
|
|
62
|
+
importer: () => Promise<{ default: SyncRouteComponent }>,
|
|
63
|
+
): RouteComponent {
|
|
64
|
+
const lazyComp = React.lazy(importer as any)
|
|
65
|
+
let promise: Promise<SyncRouteComponent>
|
|
66
|
+
let resolvedComp: SyncRouteComponent
|
|
67
|
+
|
|
68
|
+
const forwardedComp = React.forwardRef((props, ref) => {
|
|
69
|
+
const resolvedCompRef = React.useRef(resolvedComp || lazyComp)
|
|
70
|
+
return React.createElement(
|
|
71
|
+
resolvedCompRef.current as any,
|
|
72
|
+
{ ...(ref ? { ref } : {}), ...props } as any,
|
|
73
|
+
)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const finalComp = forwardedComp as unknown as RouteComponent
|
|
77
|
+
|
|
78
|
+
finalComp.preload = () => {
|
|
79
|
+
if (!promise) {
|
|
80
|
+
promise = importer().then((module) => {
|
|
81
|
+
resolvedComp = module.default
|
|
82
|
+
return resolvedComp
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return promise
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return finalComp
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
type LinkPropsOptions<
|
|
93
|
+
TAllRouteInfo extends AnyAllRouteInfo,
|
|
94
|
+
TFrom extends ValidFromPath<TAllRouteInfo>,
|
|
95
|
+
TTo extends string,
|
|
96
|
+
> = LinkOptions<TAllRouteInfo, TFrom, TTo> & {
|
|
97
|
+
// A function that returns additional props for the `active` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
|
|
98
|
+
activeProps?:
|
|
99
|
+
| React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
100
|
+
| (() => React.AnchorHTMLAttributes<HTMLAnchorElement>)
|
|
101
|
+
// A function that returns additional props for the `inactive` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
|
|
102
|
+
inactiveProps?:
|
|
103
|
+
| React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
104
|
+
| (() => React.AnchorHTMLAttributes<HTMLAnchorElement>)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type MakeMatchRouteOptions<
|
|
108
|
+
TAllRouteInfo extends AnyAllRouteInfo,
|
|
109
|
+
TFrom extends ValidFromPath<TAllRouteInfo>,
|
|
110
|
+
TTo extends string,
|
|
111
|
+
> = ToOptions<TAllRouteInfo, TFrom, TTo> &
|
|
112
|
+
MatchRouteOptions & {
|
|
113
|
+
// If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
|
|
114
|
+
children?:
|
|
115
|
+
| React.ReactNode
|
|
116
|
+
| ((
|
|
117
|
+
params: RouteInfoByPath<
|
|
118
|
+
TAllRouteInfo,
|
|
119
|
+
ResolveRelativePath<TFrom, NoInfer<TTo>>
|
|
120
|
+
>['allParams'],
|
|
121
|
+
) => React.ReactNode)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
type MakeLinkPropsOptions<
|
|
125
|
+
TAllRouteInfo extends AnyAllRouteInfo,
|
|
126
|
+
TFrom extends ValidFromPath<TAllRouteInfo>,
|
|
127
|
+
TTo extends string,
|
|
128
|
+
> = LinkPropsOptions<TAllRouteInfo, TFrom, TTo> &
|
|
129
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
130
|
+
|
|
131
|
+
type MakeLinkOptions<
|
|
132
|
+
TAllRouteInfo extends AnyAllRouteInfo,
|
|
133
|
+
TFrom extends ValidFromPath<TAllRouteInfo>,
|
|
134
|
+
TTo extends string,
|
|
135
|
+
> = LinkPropsOptions<TAllRouteInfo, TFrom, TTo> &
|
|
136
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement> &
|
|
137
|
+
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> & {
|
|
138
|
+
// If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
|
|
139
|
+
children?:
|
|
140
|
+
| React.ReactNode
|
|
141
|
+
| ((state: { isActive: boolean }) => React.ReactNode)
|
|
142
|
+
}
|
|
143
|
+
|
|
38
144
|
declare module '@tanstack/router-core' {
|
|
39
145
|
interface FrameworkGenerics {
|
|
40
|
-
|
|
41
|
-
// Any is required here so import() will work without having to do import().then(d => d.default)
|
|
42
|
-
SyncOrAsyncElement: React.ReactNode | (() => Promise<any>)
|
|
146
|
+
Component: RouteComponent
|
|
43
147
|
}
|
|
44
148
|
|
|
45
149
|
interface Router<
|
|
@@ -50,36 +154,26 @@ declare module '@tanstack/router-core' {
|
|
|
50
154
|
useRoute: <TId extends keyof TAllRouteInfo['routeInfoById']>(
|
|
51
155
|
routeId: TId,
|
|
52
156
|
) => Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
53
|
-
|
|
157
|
+
useNearestMatch: () => RouteMatch<TAllRouteInfo, RouteInfo>
|
|
158
|
+
useMatch: <
|
|
159
|
+
TId extends keyof TAllRouteInfo['routeInfoById'],
|
|
160
|
+
TStrict extends boolean = true,
|
|
161
|
+
>(
|
|
54
162
|
routeId: TId,
|
|
55
|
-
|
|
163
|
+
opts?: { strict?: TStrict },
|
|
164
|
+
) => TStrict extends true
|
|
165
|
+
? RouteMatch<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
166
|
+
:
|
|
167
|
+
| RouteMatch<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
168
|
+
| undefined
|
|
56
169
|
linkProps: <TTo extends string = '.'>(
|
|
57
|
-
props:
|
|
58
|
-
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
170
|
+
props: MakeLinkPropsOptions<TAllRouteInfo, '/', TTo>,
|
|
59
171
|
) => React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
60
172
|
Link: <TTo extends string = '.'>(
|
|
61
|
-
props:
|
|
62
|
-
React.AnchorHTMLAttributes<HTMLAnchorElement> &
|
|
63
|
-
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> & {
|
|
64
|
-
// If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
|
|
65
|
-
children?:
|
|
66
|
-
| React.ReactNode
|
|
67
|
-
| ((state: { isActive: boolean }) => React.ReactNode)
|
|
68
|
-
},
|
|
173
|
+
props: MakeLinkOptions<TAllRouteInfo, '/', TTo>,
|
|
69
174
|
) => JSX.Element
|
|
70
175
|
MatchRoute: <TTo extends string = '.'>(
|
|
71
|
-
props:
|
|
72
|
-
MatchRouteOptions & {
|
|
73
|
-
// If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
|
|
74
|
-
children?:
|
|
75
|
-
| React.ReactNode
|
|
76
|
-
| ((
|
|
77
|
-
params: RouteInfoByPath<
|
|
78
|
-
TAllRouteInfo,
|
|
79
|
-
ResolveRelativePath<'/', NoInfer<TTo>>
|
|
80
|
-
>['allParams'],
|
|
81
|
-
) => React.ReactNode)
|
|
82
|
-
},
|
|
176
|
+
props: MakeMatchRouteOptions<TAllRouteInfo, '/', TTo>,
|
|
83
177
|
) => JSX.Element
|
|
84
178
|
}
|
|
85
179
|
|
|
@@ -99,53 +193,20 @@ declare module '@tanstack/router-core' {
|
|
|
99
193
|
TResolved,
|
|
100
194
|
ToIdOption<TAllRouteInfo, TRouteInfo['id'], TTo>
|
|
101
195
|
>,
|
|
196
|
+
opts?: { strict?: boolean },
|
|
102
197
|
) => Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TResolved]>
|
|
103
198
|
linkProps: <TTo extends string = '.'>(
|
|
104
|
-
props:
|
|
105
|
-
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
199
|
+
props: MakeLinkPropsOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
|
|
106
200
|
) => React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
107
201
|
Link: <TTo extends string = '.'>(
|
|
108
|
-
props:
|
|
109
|
-
React.AnchorHTMLAttributes<HTMLAnchorElement> &
|
|
110
|
-
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> & {
|
|
111
|
-
// If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
|
|
112
|
-
children?:
|
|
113
|
-
| React.ReactNode
|
|
114
|
-
| ((state: { isActive: boolean }) => React.ReactNode)
|
|
115
|
-
},
|
|
202
|
+
props: MakeLinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
|
|
116
203
|
) => JSX.Element
|
|
117
204
|
MatchRoute: <TTo extends string = '.'>(
|
|
118
|
-
props:
|
|
119
|
-
MatchRouteOptions & {
|
|
120
|
-
// If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
|
|
121
|
-
children?:
|
|
122
|
-
| React.ReactNode
|
|
123
|
-
| ((
|
|
124
|
-
params: RouteInfoByPath<
|
|
125
|
-
TAllRouteInfo,
|
|
126
|
-
ResolveRelativePath<TRouteInfo['fullPath'], NoInfer<TTo>>
|
|
127
|
-
>['allParams'],
|
|
128
|
-
) => React.ReactNode)
|
|
129
|
-
},
|
|
205
|
+
props: MakeMatchRouteOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
|
|
130
206
|
) => JSX.Element
|
|
131
207
|
}
|
|
132
208
|
}
|
|
133
209
|
|
|
134
|
-
type LinkPropsOptions<
|
|
135
|
-
TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
|
|
136
|
-
TFrom extends ValidFromPath<TAllRouteInfo> = '/',
|
|
137
|
-
TTo extends string = '.',
|
|
138
|
-
> = LinkOptions<TAllRouteInfo, TFrom, TTo> & {
|
|
139
|
-
// A function that returns additional props for the `active` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
|
|
140
|
-
activeProps?:
|
|
141
|
-
| React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
142
|
-
| (() => React.AnchorHTMLAttributes<HTMLAnchorElement>)
|
|
143
|
-
// A function that returns additional props for the `inactive` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
|
|
144
|
-
inactiveProps?:
|
|
145
|
-
| React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
146
|
-
| (() => React.AnchorHTMLAttributes<HTMLAnchorElement>)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
210
|
export type PromptProps = {
|
|
150
211
|
message: string
|
|
151
212
|
when?: boolean | any
|
|
@@ -154,18 +215,18 @@ export type PromptProps = {
|
|
|
154
215
|
|
|
155
216
|
//
|
|
156
217
|
|
|
157
|
-
|
|
158
|
-
|
|
218
|
+
export function Link<TTo extends string = '.'>(
|
|
219
|
+
props: MakeLinkOptions<RegisteredAllRouteInfo, '/', TTo>,
|
|
220
|
+
): JSX.Element {
|
|
221
|
+
const router = useRouter()
|
|
222
|
+
return <router.Link {...(props as any)} />
|
|
223
|
+
}
|
|
159
224
|
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
window.document &&
|
|
164
|
-
window.document.createElement,
|
|
225
|
+
export const matchesContext = React.createContext<RouteMatch[]>(null!)
|
|
226
|
+
export const routerContext = React.createContext<{ router: RegisteredRouter }>(
|
|
227
|
+
null!,
|
|
165
228
|
)
|
|
166
229
|
|
|
167
|
-
const useLayoutEffect = isDOM ? React.useLayoutEffect : React.useEffect
|
|
168
|
-
|
|
169
230
|
export type MatchesProviderProps = {
|
|
170
231
|
value: RouteMatch[]
|
|
171
232
|
children: React.ReactNode
|
|
@@ -237,7 +298,7 @@ export function createReactRouter<
|
|
|
237
298
|
...rest
|
|
238
299
|
} = options
|
|
239
300
|
|
|
240
|
-
const linkInfo = route.buildLink(options)
|
|
301
|
+
const linkInfo = route.buildLink(options as any)
|
|
241
302
|
|
|
242
303
|
if (linkInfo.type === 'external') {
|
|
243
304
|
const { href } = linkInfo
|
|
@@ -253,6 +314,12 @@ export function createReactRouter<
|
|
|
253
314
|
next,
|
|
254
315
|
} = linkInfo
|
|
255
316
|
|
|
317
|
+
const reactHandleClick = (e: Event) => {
|
|
318
|
+
React.startTransition(() => {
|
|
319
|
+
handleClick(e)
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
|
|
256
323
|
const composeHandlers =
|
|
257
324
|
(handlers: (undefined | ((e: any) => void))[]) =>
|
|
258
325
|
(e: React.SyntheticEvent) => {
|
|
@@ -275,7 +342,7 @@ export function createReactRouter<
|
|
|
275
342
|
...resolvedInactiveProps,
|
|
276
343
|
...rest,
|
|
277
344
|
href: disabled ? undefined : next.href,
|
|
278
|
-
onClick: composeHandlers([
|
|
345
|
+
onClick: composeHandlers([reactHandleClick, onClick]),
|
|
279
346
|
onFocus: composeHandlers([handleFocus, onFocus]),
|
|
280
347
|
onMouseEnter: composeHandlers([handleEnter, onMouseEnter]),
|
|
281
348
|
onMouseLeave: composeHandlers([handleLeave, onMouseLeave]),
|
|
@@ -349,7 +416,7 @@ export function createReactRouter<
|
|
|
349
416
|
useRouterSubscription(router)
|
|
350
417
|
return router.state
|
|
351
418
|
},
|
|
352
|
-
useMatch: (routeId) => {
|
|
419
|
+
useMatch: (routeId, opts) => {
|
|
353
420
|
useRouterSubscription(router)
|
|
354
421
|
|
|
355
422
|
invariant(
|
|
@@ -357,32 +424,30 @@ export function createReactRouter<
|
|
|
357
424
|
`"${rootRouteId}" cannot be used with useMatch! Did you mean to useRoute("${rootRouteId}")?`,
|
|
358
425
|
)
|
|
359
426
|
|
|
360
|
-
const runtimeMatch =
|
|
427
|
+
const runtimeMatch = useMatches()?.[0]!
|
|
361
428
|
const match = router.state.matches.find((d) => d.routeId === routeId)
|
|
362
429
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
routeId as string
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if (!match) {
|
|
382
|
-
invariant('Match not found!')
|
|
430
|
+
if (opts?.strict ?? true) {
|
|
431
|
+
invariant(
|
|
432
|
+
match,
|
|
433
|
+
`Could not find an active match for "${routeId as string}"!`,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
invariant(
|
|
437
|
+
runtimeMatch.routeId == match?.routeId,
|
|
438
|
+
`useMatch("${
|
|
439
|
+
match?.routeId as string
|
|
440
|
+
}") is being called in a component that is meant to render the '${
|
|
441
|
+
runtimeMatch.routeId
|
|
442
|
+
}' route. Did you mean to 'useMatch("${
|
|
443
|
+
match?.routeId as string
|
|
444
|
+
}", { strict: false })' or 'useRoute("${
|
|
445
|
+
match?.routeId as string
|
|
446
|
+
}")' instead?`,
|
|
447
|
+
)
|
|
383
448
|
}
|
|
384
449
|
|
|
385
|
-
return match
|
|
450
|
+
return match as any
|
|
386
451
|
},
|
|
387
452
|
}
|
|
388
453
|
|
|
@@ -395,19 +460,13 @@ export function createReactRouter<
|
|
|
395
460
|
|
|
396
461
|
Object.assign(route, routeExt)
|
|
397
462
|
},
|
|
398
|
-
|
|
399
|
-
if (typeof
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
// Support direct import() calls
|
|
403
|
-
if (typeof res === 'object' && res.default) {
|
|
404
|
-
return React.createElement(res.default)
|
|
405
|
-
} else {
|
|
406
|
-
return res
|
|
407
|
-
}
|
|
463
|
+
loadComponent: async (component) => {
|
|
464
|
+
if (component.preload && typeof document !== 'undefined') {
|
|
465
|
+
component.preload()
|
|
466
|
+
// return await component.preload()
|
|
408
467
|
}
|
|
409
468
|
|
|
410
|
-
return
|
|
469
|
+
return component as any
|
|
411
470
|
},
|
|
412
471
|
})
|
|
413
472
|
|
|
@@ -430,13 +489,13 @@ export function RouterProvider<
|
|
|
430
489
|
router.update(rest)
|
|
431
490
|
|
|
432
491
|
useRouterSubscription(router)
|
|
433
|
-
|
|
434
|
-
|
|
492
|
+
React.useEffect(() => {
|
|
493
|
+
console.log('hello')
|
|
435
494
|
return router.mount()
|
|
436
495
|
}, [router])
|
|
437
496
|
|
|
438
497
|
return (
|
|
439
|
-
<routerContext.Provider value={{ router }}>
|
|
498
|
+
<routerContext.Provider value={{ router: router as any }}>
|
|
440
499
|
<MatchesProvider value={router.state.matches}>
|
|
441
500
|
{children ?? <Outlet />}
|
|
442
501
|
</MatchesProvider>
|
|
@@ -444,93 +503,123 @@ export function RouterProvider<
|
|
|
444
503
|
)
|
|
445
504
|
}
|
|
446
505
|
|
|
447
|
-
function useRouter():
|
|
506
|
+
export function useRouter(): RegisteredRouter {
|
|
448
507
|
const value = React.useContext(routerContext)
|
|
449
508
|
warning(!value, 'useRouter must be used inside a <Router> component!')
|
|
450
509
|
|
|
451
510
|
useRouterSubscription(value.router)
|
|
452
511
|
|
|
453
|
-
return value.router
|
|
512
|
+
return value.router
|
|
454
513
|
}
|
|
455
514
|
|
|
456
|
-
function useMatches(): RouteMatch[] {
|
|
515
|
+
export function useMatches(): RouteMatch[] {
|
|
457
516
|
return React.useContext(matchesContext)
|
|
458
517
|
}
|
|
459
518
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
519
|
+
export function useMatch<
|
|
520
|
+
TId extends keyof RegisteredAllRouteInfo['routeInfoById'],
|
|
521
|
+
TStrict extends boolean = true,
|
|
522
|
+
>(
|
|
523
|
+
routeId: TId,
|
|
524
|
+
opts?: { strict?: TStrict },
|
|
525
|
+
): TStrict extends true
|
|
526
|
+
? RouteMatch<
|
|
527
|
+
RegisteredAllRouteInfo,
|
|
528
|
+
RegisteredAllRouteInfo['routeInfoById'][TId]
|
|
529
|
+
>
|
|
530
|
+
:
|
|
531
|
+
| RouteMatch<
|
|
532
|
+
RegisteredAllRouteInfo,
|
|
533
|
+
RegisteredAllRouteInfo['routeInfoById'][TId]
|
|
534
|
+
>
|
|
535
|
+
| undefined {
|
|
536
|
+
const router = useRouter()
|
|
537
|
+
return router.useMatch(routeId as any, opts) as any
|
|
472
538
|
}
|
|
473
539
|
|
|
474
|
-
export function
|
|
475
|
-
|
|
476
|
-
|
|
540
|
+
export function useNearestMatch(): RouteMatch<
|
|
541
|
+
RegisteredAllRouteInfo,
|
|
542
|
+
RouteInfo
|
|
543
|
+
> {
|
|
544
|
+
const runtimeMatch = useMatches()?.[0]!
|
|
477
545
|
|
|
478
|
-
|
|
546
|
+
invariant(runtimeMatch, `Could not find a nearest match!`)
|
|
479
547
|
|
|
480
|
-
|
|
548
|
+
return runtimeMatch as any
|
|
549
|
+
}
|
|
481
550
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
551
|
+
export function useRoute<
|
|
552
|
+
TId extends keyof RegisteredAllRouteInfo['routeInfoById'],
|
|
553
|
+
>(
|
|
554
|
+
routeId: TId,
|
|
555
|
+
): Route<RegisteredAllRouteInfo, RegisteredAllRouteInfo['routeInfoById'][TId]> {
|
|
556
|
+
const router = useRouter()
|
|
557
|
+
return router.useRoute(routeId as any) as any
|
|
558
|
+
}
|
|
486
559
|
|
|
487
|
-
|
|
488
|
-
|
|
560
|
+
export function linkProps<TTo extends string = '.'>(
|
|
561
|
+
props: MakeLinkPropsOptions<RegisteredAllRouteInfo, '/', TTo>,
|
|
562
|
+
): React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
563
|
+
const router = useRouter()
|
|
564
|
+
return router.linkProps(props as any)
|
|
565
|
+
}
|
|
489
566
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
567
|
+
export function MatchRoute<TTo extends string = '.'>(
|
|
568
|
+
props: MakeMatchRouteOptions<RegisteredAllRouteInfo, '/', TTo>,
|
|
569
|
+
): JSX.Element {
|
|
570
|
+
const router = useRouter()
|
|
571
|
+
return React.createElement(router.MatchRoute, props as any)
|
|
572
|
+
}
|
|
494
573
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
throw childMatch.error
|
|
500
|
-
}
|
|
574
|
+
export function Outlet() {
|
|
575
|
+
const router = useRouter()
|
|
576
|
+
const matches = useMatches().slice(1)
|
|
577
|
+
const match = matches[0]
|
|
501
578
|
|
|
502
|
-
|
|
503
|
-
}
|
|
579
|
+
const defaultPending = React.useCallback(() => null, [])
|
|
504
580
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
childMatch.__.pendingElement ?? router.options.defaultPendingElement
|
|
581
|
+
if (!match) {
|
|
582
|
+
return null
|
|
583
|
+
}
|
|
509
584
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
585
|
+
const PendingComponent = (match.__.pendingComponent ??
|
|
586
|
+
router.options.defaultPendingComponent ??
|
|
587
|
+
defaultPending) as any
|
|
514
588
|
|
|
515
|
-
|
|
516
|
-
|
|
589
|
+
const errorComponent =
|
|
590
|
+
match.__.errorComponent ?? router.options.defaultErrorComponent
|
|
517
591
|
|
|
518
|
-
|
|
519
|
-
|
|
592
|
+
return (
|
|
593
|
+
<MatchesProvider value={matches}>
|
|
594
|
+
<React.Suspense fallback={<PendingComponent />}>
|
|
595
|
+
<CatchBoundary errorComponent={errorComponent}>
|
|
596
|
+
{
|
|
597
|
+
((): React.ReactNode => {
|
|
598
|
+
if (match.status === 'error') {
|
|
599
|
+
throw match.error
|
|
600
|
+
}
|
|
520
601
|
|
|
521
|
-
|
|
522
|
-
|
|
602
|
+
if (match.status === 'success') {
|
|
603
|
+
return React.createElement(
|
|
604
|
+
(match.__.component as any) ??
|
|
605
|
+
router.options.defaultComponent ??
|
|
606
|
+
Outlet,
|
|
607
|
+
)
|
|
608
|
+
}
|
|
523
609
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
610
|
+
console.log(match.matchId, 'suspend')
|
|
611
|
+
throw match.__.loadPromise
|
|
612
|
+
})() as JSX.Element
|
|
613
|
+
}
|
|
614
|
+
</CatchBoundary>
|
|
615
|
+
</React.Suspense>
|
|
527
616
|
</MatchesProvider>
|
|
528
617
|
)
|
|
529
618
|
}
|
|
530
619
|
|
|
531
620
|
class CatchBoundary extends React.Component<{
|
|
532
621
|
children: any
|
|
533
|
-
|
|
622
|
+
errorComponent: any
|
|
534
623
|
}> {
|
|
535
624
|
state = {
|
|
536
625
|
error: false,
|
|
@@ -543,19 +632,11 @@ class CatchBoundary extends React.Component<{
|
|
|
543
632
|
info,
|
|
544
633
|
})
|
|
545
634
|
}
|
|
546
|
-
reset = () => {
|
|
547
|
-
this.setState({
|
|
548
|
-
error: false,
|
|
549
|
-
info: false,
|
|
550
|
-
})
|
|
551
|
-
}
|
|
552
635
|
render() {
|
|
553
|
-
const
|
|
636
|
+
const errorComponent = this.props.errorComponent ?? DefaultErrorBoundary
|
|
554
637
|
|
|
555
638
|
if (this.state.error) {
|
|
556
|
-
return
|
|
557
|
-
? catchElement(this.state)
|
|
558
|
-
: catchElement
|
|
639
|
+
return React.createElement(errorComponent, this.state)
|
|
559
640
|
}
|
|
560
641
|
|
|
561
642
|
return this.props.children
|
|
@@ -584,19 +665,6 @@ export function DefaultErrorBoundary({ error }: { error: any }) {
|
|
|
584
665
|
) : null}
|
|
585
666
|
</pre>
|
|
586
667
|
</div>
|
|
587
|
-
<div style={{ height: '1rem' }} />
|
|
588
|
-
<div
|
|
589
|
-
style={{
|
|
590
|
-
fontSize: '.8em',
|
|
591
|
-
borderLeft: '3px solid rgba(127, 127, 127, 1)',
|
|
592
|
-
paddingLeft: '.5rem',
|
|
593
|
-
opacity: 0.5,
|
|
594
|
-
}}
|
|
595
|
-
>
|
|
596
|
-
If you are the owner of this website, it's highly recommended that you
|
|
597
|
-
configure your own custom Catch/Error boundaries for the router. You can
|
|
598
|
-
optionally configure a boundary for each route.
|
|
599
|
-
</div>
|
|
600
668
|
</div>
|
|
601
669
|
)
|
|
602
670
|
}
|