@tanstack/react-router 0.0.1-alpha.1 → 0.0.1-alpha.10
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 +180 -146
- package/build/cjs/react-router/src/index.js.map +1 -1
- package/build/cjs/router-core/build/esm/index.js +1360 -1231
- package/build/cjs/router-core/build/esm/index.js.map +1 -1
- package/build/esm/index.js +1519 -1374
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +129 -0
- package/build/types/index.d.ts +76 -0
- package/build/umd/index.development.js +1506 -1356
- 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 -3
- package/src/index.tsx +258 -225
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-alpha.
|
|
4
|
+
"version": "0.0.1-alpha.10",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://react-router.tanstack.com/",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"node": ">=12"
|
|
32
32
|
},
|
|
33
33
|
"files": [
|
|
34
|
-
"build",
|
|
34
|
+
"build/**",
|
|
35
35
|
"src"
|
|
36
36
|
],
|
|
37
37
|
"peerDependencies": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@babel/runtime": "^7.16.7",
|
|
43
|
-
"@tanstack/router-core": "0.0.1-alpha.
|
|
43
|
+
"@tanstack/router-core": "0.0.1-alpha.10",
|
|
44
44
|
"use-sync-external-store": "^1.2.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
package/src/index.tsx
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
AnyRoute,
|
|
7
7
|
RootRouteId,
|
|
8
8
|
rootRouteId,
|
|
9
|
-
Route,
|
|
10
9
|
Router,
|
|
10
|
+
RouterState,
|
|
11
11
|
} from '@tanstack/router-core'
|
|
12
12
|
import {
|
|
13
13
|
warning,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
ResolveRelativePath,
|
|
30
30
|
NoInfer,
|
|
31
31
|
ToOptions,
|
|
32
|
+
invariant,
|
|
32
33
|
} from '@tanstack/router-core'
|
|
33
34
|
|
|
34
35
|
export * from '@tanstack/router-core'
|
|
@@ -49,40 +50,41 @@ declare module '@tanstack/router-core' {
|
|
|
49
50
|
Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][RootRouteId]>,
|
|
50
51
|
'linkProps' | 'Link' | 'MatchRoute'
|
|
51
52
|
> {
|
|
53
|
+
useState: () => RouterState
|
|
52
54
|
useRoute: <TId extends keyof TAllRouteInfo['routeInfoById']>(
|
|
53
55
|
routeId: TId,
|
|
54
56
|
) => Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
55
57
|
useMatch: <TId extends keyof TAllRouteInfo['routeInfoById']>(
|
|
56
58
|
routeId: TId,
|
|
57
59
|
) => RouteMatch<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
60
|
+
linkProps: <TTo extends string = '.'>(
|
|
61
|
+
props: LinkPropsOptions<TAllRouteInfo, '/', TTo> &
|
|
62
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
63
|
+
) => React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
64
|
+
Link: <TTo extends string = '.'>(
|
|
65
|
+
props: LinkPropsOptions<TAllRouteInfo, '/', TTo> &
|
|
66
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement> &
|
|
67
|
+
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> & {
|
|
68
|
+
// 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
|
|
69
|
+
children?:
|
|
70
|
+
| React.ReactNode
|
|
71
|
+
| ((state: { isActive: boolean }) => React.ReactNode)
|
|
72
|
+
},
|
|
73
|
+
) => JSX.Element
|
|
74
|
+
MatchRoute: <TTo extends string = '.'>(
|
|
75
|
+
props: ToOptions<TAllRouteInfo, '/', TTo> &
|
|
76
|
+
MatchRouteOptions & {
|
|
77
|
+
// 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
|
|
78
|
+
children?:
|
|
79
|
+
| React.ReactNode
|
|
80
|
+
| ((
|
|
81
|
+
params: RouteInfoByPath<
|
|
82
|
+
TAllRouteInfo,
|
|
83
|
+
ResolveRelativePath<'/', NoInfer<TTo>>
|
|
84
|
+
>['allParams'],
|
|
85
|
+
) => React.ReactNode)
|
|
86
|
+
},
|
|
87
|
+
) => JSX.Element
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
interface Route<
|
|
@@ -174,201 +176,211 @@ const useRouterSubscription = (router: Router<any, any>) => {
|
|
|
174
176
|
export function createReactRouter<
|
|
175
177
|
TRouteConfig extends AnyRouteConfig = RouteConfig,
|
|
176
178
|
>(opts: RouterOptions<TRouteConfig>): Router<TRouteConfig> {
|
|
179
|
+
const makeRouteExt = (
|
|
180
|
+
route: AnyRoute,
|
|
181
|
+
router: Router<any, any>,
|
|
182
|
+
): Pick<AnyRoute, 'linkProps' | 'Link' | 'MatchRoute'> => {
|
|
183
|
+
return {
|
|
184
|
+
linkProps: (options) => {
|
|
185
|
+
const {
|
|
186
|
+
// custom props
|
|
187
|
+
type,
|
|
188
|
+
children,
|
|
189
|
+
target,
|
|
190
|
+
activeProps = () => ({ className: 'active' }),
|
|
191
|
+
inactiveProps = () => ({}),
|
|
192
|
+
activeOptions,
|
|
193
|
+
disabled,
|
|
194
|
+
// fromCurrent,
|
|
195
|
+
hash,
|
|
196
|
+
search,
|
|
197
|
+
params,
|
|
198
|
+
to,
|
|
199
|
+
preload,
|
|
200
|
+
preloadDelay,
|
|
201
|
+
preloadMaxAge,
|
|
202
|
+
replace,
|
|
203
|
+
// element props
|
|
204
|
+
style,
|
|
205
|
+
className,
|
|
206
|
+
onClick,
|
|
207
|
+
onFocus,
|
|
208
|
+
onMouseEnter,
|
|
209
|
+
onMouseLeave,
|
|
210
|
+
onTouchStart,
|
|
211
|
+
onTouchEnd,
|
|
212
|
+
...rest
|
|
213
|
+
} = options
|
|
214
|
+
|
|
215
|
+
const linkInfo = route.buildLink(options)
|
|
216
|
+
|
|
217
|
+
if (linkInfo.type === 'external') {
|
|
218
|
+
const { href } = linkInfo
|
|
219
|
+
return { href }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const {
|
|
223
|
+
handleClick,
|
|
224
|
+
handleFocus,
|
|
225
|
+
handleEnter,
|
|
226
|
+
handleLeave,
|
|
227
|
+
isActive,
|
|
228
|
+
next,
|
|
229
|
+
} = linkInfo
|
|
230
|
+
|
|
231
|
+
const composeHandlers =
|
|
232
|
+
(handlers: (undefined | ((e: any) => void))[]) =>
|
|
233
|
+
(e: React.SyntheticEvent) => {
|
|
234
|
+
e.persist()
|
|
235
|
+
handlers.forEach((handler) => {
|
|
236
|
+
if (handler) handler(e)
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Get the active props
|
|
241
|
+
const resolvedActiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
242
|
+
isActive ? functionalUpdate(activeProps, {}) ?? {} : {}
|
|
243
|
+
|
|
244
|
+
// Get the inactive props
|
|
245
|
+
const resolvedInactiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
246
|
+
isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {}
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
...resolvedActiveProps,
|
|
250
|
+
...resolvedInactiveProps,
|
|
251
|
+
...rest,
|
|
252
|
+
href: disabled ? undefined : next.href,
|
|
253
|
+
onClick: composeHandlers([handleClick, onClick]),
|
|
254
|
+
onFocus: composeHandlers([handleFocus, onFocus]),
|
|
255
|
+
onMouseEnter: composeHandlers([handleEnter, onMouseEnter]),
|
|
256
|
+
onMouseLeave: composeHandlers([handleLeave, onMouseLeave]),
|
|
257
|
+
target,
|
|
258
|
+
style: {
|
|
259
|
+
...style,
|
|
260
|
+
...resolvedActiveProps.style,
|
|
261
|
+
...resolvedInactiveProps.style,
|
|
262
|
+
},
|
|
263
|
+
className:
|
|
264
|
+
[
|
|
265
|
+
className,
|
|
266
|
+
resolvedActiveProps.className,
|
|
267
|
+
resolvedInactiveProps.className,
|
|
268
|
+
]
|
|
269
|
+
.filter(Boolean)
|
|
270
|
+
.join(' ') || undefined,
|
|
271
|
+
...(disabled
|
|
272
|
+
? {
|
|
273
|
+
role: 'link',
|
|
274
|
+
'aria-disabled': true,
|
|
275
|
+
}
|
|
276
|
+
: undefined),
|
|
277
|
+
['data-status']: isActive ? 'active' : undefined,
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
Link: React.forwardRef((props: any, ref) => {
|
|
281
|
+
const linkProps = route.linkProps(props)
|
|
282
|
+
|
|
283
|
+
useRouterSubscription(router)
|
|
284
|
+
|
|
285
|
+
return (
|
|
286
|
+
<a
|
|
287
|
+
{...{
|
|
288
|
+
ref: ref as any,
|
|
289
|
+
...linkProps,
|
|
290
|
+
children:
|
|
291
|
+
typeof props.children === 'function'
|
|
292
|
+
? props.children({
|
|
293
|
+
isActive: (linkProps as any)['data-status'] === 'active',
|
|
294
|
+
})
|
|
295
|
+
: props.children,
|
|
296
|
+
}}
|
|
297
|
+
/>
|
|
298
|
+
)
|
|
299
|
+
}) as any,
|
|
300
|
+
MatchRoute: (opts) => {
|
|
301
|
+
const { pending, caseSensitive, children, ...rest } = opts
|
|
302
|
+
|
|
303
|
+
const params = route.matchRoute(rest as any, {
|
|
304
|
+
pending,
|
|
305
|
+
caseSensitive,
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
if (!params) {
|
|
309
|
+
return null
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return typeof opts.children === 'function'
|
|
313
|
+
? opts.children(params as any)
|
|
314
|
+
: (opts.children as any)
|
|
315
|
+
},
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
177
319
|
const coreRouter = createRouter<TRouteConfig>({
|
|
178
320
|
...opts,
|
|
179
321
|
createRouter: (router) => {
|
|
180
|
-
const routerExt: Pick<
|
|
322
|
+
const routerExt: Pick<
|
|
323
|
+
Router<any, any>,
|
|
324
|
+
'useRoute' | 'useMatch' | 'useState'
|
|
325
|
+
> = {
|
|
326
|
+
useState: () => {
|
|
327
|
+
useRouterSubscription(router)
|
|
328
|
+
return router.state
|
|
329
|
+
},
|
|
181
330
|
useRoute: (routeId) => {
|
|
182
331
|
const route = router.getRoute(routeId)
|
|
183
332
|
useRouterSubscription(router)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
333
|
+
invariant(
|
|
334
|
+
route,
|
|
335
|
+
`Could not find a route for route "${
|
|
336
|
+
routeId as string
|
|
337
|
+
}"! Did you forget to add it to your route config?`,
|
|
338
|
+
)
|
|
191
339
|
return route
|
|
192
340
|
},
|
|
193
341
|
useMatch: (routeId) => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
342
|
+
useRouterSubscription(router)
|
|
343
|
+
|
|
344
|
+
invariant(
|
|
345
|
+
routeId !== rootRouteId,
|
|
346
|
+
`"${rootRouteId}" cannot be used with useMatch! Did you mean to useRoute("${rootRouteId}")?`,
|
|
347
|
+
)
|
|
348
|
+
|
|
199
349
|
const runtimeMatch = useMatch()
|
|
200
350
|
const match = router.state.matches.find((d) => d.routeId === routeId)
|
|
201
351
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (runtimeMatch.routeId !== match?.routeId) {
|
|
211
|
-
throw new Error(
|
|
212
|
-
`useMatch('${
|
|
213
|
-
match?.routeId as string
|
|
214
|
-
}') is being called in a component that is meant to render the '${
|
|
215
|
-
runtimeMatch.routeId
|
|
216
|
-
}' route. Did you mean to 'useRoute(${
|
|
217
|
-
match?.routeId as string
|
|
218
|
-
})' instead?`,
|
|
219
|
-
)
|
|
220
|
-
}
|
|
352
|
+
invariant(
|
|
353
|
+
match,
|
|
354
|
+
`Could not find a match for route "${
|
|
355
|
+
routeId as string
|
|
356
|
+
}" being rendered in this component!`,
|
|
357
|
+
)
|
|
221
358
|
|
|
222
|
-
|
|
359
|
+
invariant(
|
|
360
|
+
runtimeMatch.routeId == match?.routeId,
|
|
361
|
+
`useMatch('${
|
|
362
|
+
match?.routeId as string
|
|
363
|
+
}') is being called in a component that is meant to render the '${
|
|
364
|
+
runtimeMatch.routeId
|
|
365
|
+
}' route. Did you mean to 'useRoute(${
|
|
366
|
+
match?.routeId as string
|
|
367
|
+
})' instead?`,
|
|
368
|
+
)
|
|
223
369
|
|
|
224
370
|
if (!match) {
|
|
225
|
-
|
|
371
|
+
invariant('Match not found!')
|
|
226
372
|
}
|
|
227
373
|
|
|
228
374
|
return match
|
|
229
375
|
},
|
|
230
376
|
}
|
|
231
377
|
|
|
232
|
-
|
|
378
|
+
const routeExt = makeRouteExt(router.getRoute('/'), router)
|
|
379
|
+
|
|
380
|
+
Object.assign(router, routerExt, routeExt)
|
|
233
381
|
},
|
|
234
382
|
createRoute: ({ router, route }) => {
|
|
235
|
-
const routeExt
|
|
236
|
-
linkProps: (options) => {
|
|
237
|
-
const {
|
|
238
|
-
// custom props
|
|
239
|
-
type,
|
|
240
|
-
children,
|
|
241
|
-
target,
|
|
242
|
-
activeProps = () => ({ className: 'active' }),
|
|
243
|
-
inactiveProps = () => ({}),
|
|
244
|
-
activeOptions,
|
|
245
|
-
disabled,
|
|
246
|
-
// fromCurrent,
|
|
247
|
-
hash,
|
|
248
|
-
search,
|
|
249
|
-
params,
|
|
250
|
-
to,
|
|
251
|
-
preload,
|
|
252
|
-
preloadDelay,
|
|
253
|
-
preloadMaxAge,
|
|
254
|
-
replace,
|
|
255
|
-
// element props
|
|
256
|
-
style,
|
|
257
|
-
className,
|
|
258
|
-
onClick,
|
|
259
|
-
onFocus,
|
|
260
|
-
onMouseEnter,
|
|
261
|
-
onMouseLeave,
|
|
262
|
-
onTouchStart,
|
|
263
|
-
onTouchEnd,
|
|
264
|
-
...rest
|
|
265
|
-
} = options
|
|
266
|
-
|
|
267
|
-
const linkInfo = route.buildLink(options)
|
|
268
|
-
|
|
269
|
-
if (linkInfo.type === 'external') {
|
|
270
|
-
const { href } = linkInfo
|
|
271
|
-
return { href }
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const {
|
|
275
|
-
handleClick,
|
|
276
|
-
handleFocus,
|
|
277
|
-
handleEnter,
|
|
278
|
-
handleLeave,
|
|
279
|
-
isActive,
|
|
280
|
-
next,
|
|
281
|
-
} = linkInfo
|
|
282
|
-
|
|
283
|
-
const composeHandlers =
|
|
284
|
-
(handlers: (undefined | ((e: any) => void))[]) =>
|
|
285
|
-
(e: React.SyntheticEvent) => {
|
|
286
|
-
e.persist()
|
|
287
|
-
handlers.forEach((handler) => {
|
|
288
|
-
if (handler) handler(e)
|
|
289
|
-
})
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Get the active props
|
|
293
|
-
const resolvedActiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
294
|
-
isActive ? functionalUpdate(activeProps) ?? {} : {}
|
|
295
|
-
|
|
296
|
-
// Get the inactive props
|
|
297
|
-
const resolvedInactiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
298
|
-
isActive ? {} : functionalUpdate(inactiveProps) ?? {}
|
|
299
|
-
|
|
300
|
-
return {
|
|
301
|
-
...resolvedActiveProps,
|
|
302
|
-
...resolvedInactiveProps,
|
|
303
|
-
...rest,
|
|
304
|
-
href: disabled ? undefined : next.href,
|
|
305
|
-
onClick: composeHandlers([handleClick, onClick]),
|
|
306
|
-
onFocus: composeHandlers([handleFocus, onFocus]),
|
|
307
|
-
onMouseEnter: composeHandlers([handleEnter, onMouseEnter]),
|
|
308
|
-
onMouseLeave: composeHandlers([handleLeave, onMouseLeave]),
|
|
309
|
-
target,
|
|
310
|
-
style: {
|
|
311
|
-
...style,
|
|
312
|
-
...resolvedActiveProps.style,
|
|
313
|
-
...resolvedInactiveProps.style,
|
|
314
|
-
},
|
|
315
|
-
className:
|
|
316
|
-
[
|
|
317
|
-
className,
|
|
318
|
-
resolvedActiveProps.className,
|
|
319
|
-
resolvedInactiveProps.className,
|
|
320
|
-
]
|
|
321
|
-
.filter(Boolean)
|
|
322
|
-
.join(' ') || undefined,
|
|
323
|
-
...(disabled
|
|
324
|
-
? {
|
|
325
|
-
role: 'link',
|
|
326
|
-
'aria-disabled': true,
|
|
327
|
-
}
|
|
328
|
-
: undefined),
|
|
329
|
-
['data-status']: isActive ? 'active' : undefined,
|
|
330
|
-
}
|
|
331
|
-
},
|
|
332
|
-
Link: React.forwardRef((props: any, ref) => {
|
|
333
|
-
const linkProps = route.linkProps(props)
|
|
334
|
-
|
|
335
|
-
useRouterSubscription(router)
|
|
336
|
-
|
|
337
|
-
return (
|
|
338
|
-
<a
|
|
339
|
-
{...{
|
|
340
|
-
ref: ref as any,
|
|
341
|
-
...linkProps,
|
|
342
|
-
children:
|
|
343
|
-
typeof props.children === 'function'
|
|
344
|
-
? props.children({
|
|
345
|
-
isActive:
|
|
346
|
-
(linkProps as any)['data-status'] === 'active',
|
|
347
|
-
})
|
|
348
|
-
: props.children,
|
|
349
|
-
}}
|
|
350
|
-
/>
|
|
351
|
-
)
|
|
352
|
-
}) as any,
|
|
353
|
-
MatchRoute: (opts) => {
|
|
354
|
-
const { pending, caseSensitive, children, ...rest } = opts
|
|
355
|
-
|
|
356
|
-
const params = route.matchRoute(rest as any, {
|
|
357
|
-
pending,
|
|
358
|
-
caseSensitive,
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
// useRouterSubscription(router)
|
|
362
|
-
|
|
363
|
-
if (!params) {
|
|
364
|
-
return null
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return typeof opts.children === 'function'
|
|
368
|
-
? opts.children(params as any)
|
|
369
|
-
: (opts.children as any)
|
|
370
|
-
},
|
|
371
|
-
}
|
|
383
|
+
const routeExt = makeRouteExt(route, router)
|
|
372
384
|
|
|
373
385
|
Object.assign(route, routeExt)
|
|
374
386
|
},
|
|
@@ -392,14 +404,11 @@ export function RouterProvider<
|
|
|
392
404
|
>({ children, router, ...rest }: RouterProps<TRouteConfig, TAllRouteInfo>) {
|
|
393
405
|
router.update(rest)
|
|
394
406
|
|
|
395
|
-
|
|
396
|
-
(cb) => router.subscribe(() => cb()),
|
|
397
|
-
() => router.state,
|
|
398
|
-
)
|
|
407
|
+
useRouterSubscription(router)
|
|
399
408
|
|
|
400
409
|
useLayoutEffect(() => {
|
|
401
|
-
router.mount()
|
|
402
|
-
}, [])
|
|
410
|
+
return router.mount()
|
|
411
|
+
}, [router])
|
|
403
412
|
|
|
404
413
|
return (
|
|
405
414
|
<routerContext.Provider value={{ router }}>
|
|
@@ -410,7 +419,7 @@ export function RouterProvider<
|
|
|
410
419
|
)
|
|
411
420
|
}
|
|
412
421
|
|
|
413
|
-
|
|
422
|
+
function useRouter(): Router {
|
|
414
423
|
const value = React.useContext(routerContext)
|
|
415
424
|
warning(!value, 'useRouter must be used inside a <Router> component!')
|
|
416
425
|
|
|
@@ -419,21 +428,21 @@ export function useRouter(): Router {
|
|
|
419
428
|
return value.router as Router
|
|
420
429
|
}
|
|
421
430
|
|
|
422
|
-
|
|
431
|
+
function useMatches(): RouteMatch[] {
|
|
423
432
|
return React.useContext(matchesContext)
|
|
424
433
|
}
|
|
425
434
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
|
|
435
|
+
// function useParentMatches(): RouteMatch[] {
|
|
436
|
+
// const router = useRouter()
|
|
437
|
+
// const match = useMatch()
|
|
438
|
+
// const matches = router.state.matches
|
|
439
|
+
// return matches.slice(
|
|
440
|
+
// 0,
|
|
441
|
+
// matches.findIndex((d) => d.matchId === match.matchId) - 1,
|
|
442
|
+
// )
|
|
443
|
+
// }
|
|
444
|
+
|
|
445
|
+
function useMatch<T>(): RouteMatch {
|
|
437
446
|
return useMatches()?.[0] as RouteMatch
|
|
438
447
|
}
|
|
439
448
|
|
|
@@ -445,7 +454,7 @@ export function Outlet() {
|
|
|
445
454
|
|
|
446
455
|
if (!childMatch) return null
|
|
447
456
|
|
|
448
|
-
const element = ((
|
|
457
|
+
const element = ((): React.ReactNode => {
|
|
449
458
|
if (!childMatch) {
|
|
450
459
|
return null
|
|
451
460
|
}
|
|
@@ -465,7 +474,7 @@ export function Outlet() {
|
|
|
465
474
|
throw childMatch.error
|
|
466
475
|
}
|
|
467
476
|
|
|
468
|
-
return <
|
|
477
|
+
return <DefaultErrorBoundary error={childMatch.error} />
|
|
469
478
|
}
|
|
470
479
|
|
|
471
480
|
if (childMatch.status === 'loading' || childMatch.status === 'idle') {
|
|
@@ -482,7 +491,7 @@ export function Outlet() {
|
|
|
482
491
|
}
|
|
483
492
|
|
|
484
493
|
return (childMatch.__.element as any) ?? router.options.defaultElement
|
|
485
|
-
})() as JSX.Element
|
|
494
|
+
})() as JSX.Element
|
|
486
495
|
|
|
487
496
|
const catchElement =
|
|
488
497
|
childMatch?.options.catchElement ?? router.options.defaultCatchElement
|
|
@@ -516,7 +525,7 @@ class CatchBoundary extends React.Component<{
|
|
|
516
525
|
})
|
|
517
526
|
}
|
|
518
527
|
render() {
|
|
519
|
-
const catchElement = this.props.catchElement ??
|
|
528
|
+
const catchElement = this.props.catchElement ?? DefaultErrorBoundary
|
|
520
529
|
|
|
521
530
|
if (this.state.error) {
|
|
522
531
|
return typeof catchElement === 'function'
|
|
@@ -528,7 +537,7 @@ class CatchBoundary extends React.Component<{
|
|
|
528
537
|
}
|
|
529
538
|
}
|
|
530
539
|
|
|
531
|
-
export function
|
|
540
|
+
export function DefaultErrorBoundary({ error }: { error: any }) {
|
|
532
541
|
return (
|
|
533
542
|
<div style={{ padding: '.5rem', maxWidth: '100%' }}>
|
|
534
543
|
<strong style={{ fontSize: '1.2rem' }}>Something went wrong!</strong>
|
|
@@ -566,3 +575,27 @@ export function DefaultCatchBoundary({ error }: { error: any }) {
|
|
|
566
575
|
</div>
|
|
567
576
|
)
|
|
568
577
|
}
|
|
578
|
+
|
|
579
|
+
export function usePrompt(message: string, when: boolean | any): void {
|
|
580
|
+
const router = useRouter()
|
|
581
|
+
|
|
582
|
+
React.useEffect(() => {
|
|
583
|
+
if (!when) return
|
|
584
|
+
|
|
585
|
+
let unblock = router.history.block((transition) => {
|
|
586
|
+
if (window.confirm(message)) {
|
|
587
|
+
unblock()
|
|
588
|
+
transition.retry()
|
|
589
|
+
} else {
|
|
590
|
+
router.location.pathname = window.location.pathname
|
|
591
|
+
}
|
|
592
|
+
})
|
|
593
|
+
|
|
594
|
+
return unblock
|
|
595
|
+
}, [when, location, message])
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
export function Prompt({ message, when, children }: PromptProps) {
|
|
599
|
+
usePrompt(message, when ?? true)
|
|
600
|
+
return (children ?? null) as React.ReactNode
|
|
601
|
+
}
|