@tanstack/react-router 0.0.1-alpha.9 → 0.0.1-beta.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 +88 -74
- package/build/cjs/react-router/src/index.js.map +1 -1
- package/build/cjs/router-core/build/esm/index.js +379 -324
- package/build/cjs/router-core/build/esm/index.js.map +1 -1
- package/build/esm/index.js +464 -397
- 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 +12 -8
- package/build/umd/index.development.js +467 -398
- 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 +130 -95
- package/src/qss.ts +0 -53
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-router",
|
|
3
3
|
"author": "Tanner Linsley",
|
|
4
|
-
"version": "0.0.1-
|
|
4
|
+
"version": "0.0.1-beta.10",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
|
-
"homepage": "https://
|
|
7
|
+
"homepage": "https://tanstack.com/router/",
|
|
8
8
|
"description": "",
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@babel/runtime": "^7.16.7",
|
|
43
|
-
"@tanstack/router-core": "0.0.1-
|
|
43
|
+
"@tanstack/router-core": "0.0.1-beta.10",
|
|
44
44
|
"use-sync-external-store": "^1.2.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
package/src/index.tsx
CHANGED
|
@@ -4,10 +4,11 @@ import { useSyncExternalStore } from 'use-sync-external-store/shim'
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
AnyRoute,
|
|
7
|
-
|
|
7
|
+
CheckId,
|
|
8
8
|
rootRouteId,
|
|
9
9
|
Router,
|
|
10
10
|
RouterState,
|
|
11
|
+
ToIdOption,
|
|
11
12
|
} from '@tanstack/router-core'
|
|
12
13
|
import {
|
|
13
14
|
warning,
|
|
@@ -37,26 +38,29 @@ export * from '@tanstack/router-core'
|
|
|
37
38
|
declare module '@tanstack/router-core' {
|
|
38
39
|
interface FrameworkGenerics {
|
|
39
40
|
Element: React.ReactNode
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}) => Promise<React.ReactNode>
|
|
43
|
-
SyncOrAsyncElement: React.ReactNode | FrameworkGenerics['AsyncElement']
|
|
41
|
+
// Any is required here so import() will work without having to do import().then(d => d.default)
|
|
42
|
+
SyncOrAsyncElement: React.ReactNode | (() => Promise<any>)
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
interface Router<
|
|
47
46
|
TRouteConfig extends AnyRouteConfig = RouteConfig,
|
|
48
47
|
TAllRouteInfo extends AnyAllRouteInfo = AllRouteInfo<TRouteConfig>,
|
|
49
|
-
>
|
|
50
|
-
Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][RootRouteId]>,
|
|
51
|
-
'linkProps' | 'Link' | 'MatchRoute'
|
|
52
|
-
> {
|
|
48
|
+
> {
|
|
53
49
|
useState: () => RouterState
|
|
54
50
|
useRoute: <TId extends keyof TAllRouteInfo['routeInfoById']>(
|
|
55
51
|
routeId: TId,
|
|
56
52
|
) => Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
57
|
-
useMatch: <
|
|
53
|
+
useMatch: <
|
|
54
|
+
TId extends keyof TAllRouteInfo['routeInfoById'],
|
|
55
|
+
TStrict extends true | false = true,
|
|
56
|
+
>(
|
|
58
57
|
routeId: TId,
|
|
59
|
-
|
|
58
|
+
opts?: { strict?: TStrict },
|
|
59
|
+
) => TStrict extends true
|
|
60
|
+
? RouteMatch<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
61
|
+
:
|
|
62
|
+
| RouteMatch<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
63
|
+
| undefined
|
|
60
64
|
linkProps: <TTo extends string = '.'>(
|
|
61
65
|
props: LinkPropsOptions<TAllRouteInfo, '/', TTo> &
|
|
62
66
|
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
@@ -91,6 +95,20 @@ declare module '@tanstack/router-core' {
|
|
|
91
95
|
TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
|
|
92
96
|
TRouteInfo extends AnyRouteInfo = RouteInfo,
|
|
93
97
|
> {
|
|
98
|
+
useRoute: <
|
|
99
|
+
TTo extends string = '.',
|
|
100
|
+
TResolved extends string = ResolveRelativePath<
|
|
101
|
+
TRouteInfo['id'],
|
|
102
|
+
NoInfer<TTo>
|
|
103
|
+
>,
|
|
104
|
+
>(
|
|
105
|
+
routeId: CheckId<
|
|
106
|
+
TAllRouteInfo,
|
|
107
|
+
TResolved,
|
|
108
|
+
ToIdOption<TAllRouteInfo, TRouteInfo['id'], TTo>
|
|
109
|
+
>,
|
|
110
|
+
opts?: { strict?: boolean },
|
|
111
|
+
) => Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TResolved]>
|
|
94
112
|
linkProps: <TTo extends string = '.'>(
|
|
95
113
|
props: LinkPropsOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo> &
|
|
96
114
|
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
@@ -170,6 +188,7 @@ const useRouterSubscription = (router: Router<any, any>) => {
|
|
|
170
188
|
useSyncExternalStore(
|
|
171
189
|
(cb) => router.subscribe(() => cb()),
|
|
172
190
|
() => router.state,
|
|
191
|
+
() => router.state,
|
|
173
192
|
)
|
|
174
193
|
}
|
|
175
194
|
|
|
@@ -179,8 +198,23 @@ export function createReactRouter<
|
|
|
179
198
|
const makeRouteExt = (
|
|
180
199
|
route: AnyRoute,
|
|
181
200
|
router: Router<any, any>,
|
|
182
|
-
): Pick<AnyRoute, 'linkProps' | 'Link' | 'MatchRoute'> => {
|
|
201
|
+
): Pick<AnyRoute, 'useRoute' | 'linkProps' | 'Link' | 'MatchRoute'> => {
|
|
183
202
|
return {
|
|
203
|
+
useRoute: (subRouteId = '.' as any) => {
|
|
204
|
+
const resolvedRouteId = router.resolvePath(
|
|
205
|
+
route.routeId,
|
|
206
|
+
subRouteId as string,
|
|
207
|
+
)
|
|
208
|
+
const resolvedRoute = router.getRoute(resolvedRouteId)
|
|
209
|
+
useRouterSubscription(router)
|
|
210
|
+
invariant(
|
|
211
|
+
resolvedRoute,
|
|
212
|
+
`Could not find a route for route "${
|
|
213
|
+
resolvedRouteId as string
|
|
214
|
+
}"! Did you forget to add it to your route config?`,
|
|
215
|
+
)
|
|
216
|
+
return resolvedRoute
|
|
217
|
+
},
|
|
184
218
|
linkProps: (options) => {
|
|
185
219
|
const {
|
|
186
220
|
// custom props
|
|
@@ -319,26 +353,12 @@ export function createReactRouter<
|
|
|
319
353
|
const coreRouter = createRouter<TRouteConfig>({
|
|
320
354
|
...opts,
|
|
321
355
|
createRouter: (router) => {
|
|
322
|
-
const routerExt: Pick<
|
|
323
|
-
Router<any, any>,
|
|
324
|
-
'useRoute' | 'useMatch' | 'useState'
|
|
325
|
-
> = {
|
|
356
|
+
const routerExt: Pick<Router<any, any>, 'useMatch' | 'useState'> = {
|
|
326
357
|
useState: () => {
|
|
327
358
|
useRouterSubscription(router)
|
|
328
359
|
return router.state
|
|
329
360
|
},
|
|
330
|
-
|
|
331
|
-
const route = router.getRoute(routeId)
|
|
332
|
-
useRouterSubscription(router)
|
|
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
|
-
)
|
|
339
|
-
return route
|
|
340
|
-
},
|
|
341
|
-
useMatch: (routeId) => {
|
|
361
|
+
useMatch: (routeId, opts) => {
|
|
342
362
|
useRouterSubscription(router)
|
|
343
363
|
|
|
344
364
|
invariant(
|
|
@@ -346,32 +366,30 @@ export function createReactRouter<
|
|
|
346
366
|
`"${rootRouteId}" cannot be used with useMatch! Did you mean to useRoute("${rootRouteId}")?`,
|
|
347
367
|
)
|
|
348
368
|
|
|
349
|
-
const runtimeMatch =
|
|
369
|
+
const runtimeMatch = useMatches()?.[0]!
|
|
350
370
|
const match = router.state.matches.find((d) => d.routeId === routeId)
|
|
351
371
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
routeId as string
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
if (!match) {
|
|
371
|
-
invariant('Match not found!')
|
|
372
|
+
if (opts?.strict ?? true) {
|
|
373
|
+
invariant(
|
|
374
|
+
match,
|
|
375
|
+
`Could not find an active match for "${routeId as string}"!`,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
invariant(
|
|
379
|
+
runtimeMatch.routeId == match?.routeId,
|
|
380
|
+
`useMatch('${
|
|
381
|
+
match?.routeId as string
|
|
382
|
+
}') is being called in a component that is meant to render the '${
|
|
383
|
+
runtimeMatch.routeId
|
|
384
|
+
}' route. Did you mean to 'useMatch(${
|
|
385
|
+
match?.routeId as string
|
|
386
|
+
}, { strict: false })' or 'useRoute(${
|
|
387
|
+
match?.routeId as string
|
|
388
|
+
})' instead?`,
|
|
389
|
+
)
|
|
372
390
|
}
|
|
373
391
|
|
|
374
|
-
return match
|
|
392
|
+
return match as any
|
|
375
393
|
},
|
|
376
394
|
}
|
|
377
395
|
|
|
@@ -384,6 +402,20 @@ export function createReactRouter<
|
|
|
384
402
|
|
|
385
403
|
Object.assign(route, routeExt)
|
|
386
404
|
},
|
|
405
|
+
createElement: async (element) => {
|
|
406
|
+
if (typeof element === 'function') {
|
|
407
|
+
const res = (await element()) as any
|
|
408
|
+
|
|
409
|
+
// Support direct import() calls
|
|
410
|
+
if (typeof res === 'object' && res.default) {
|
|
411
|
+
return React.createElement(res.default)
|
|
412
|
+
} else {
|
|
413
|
+
return res
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return element
|
|
418
|
+
},
|
|
387
419
|
})
|
|
388
420
|
|
|
389
421
|
return coreRouter as any
|
|
@@ -405,9 +437,10 @@ export function RouterProvider<
|
|
|
405
437
|
router.update(rest)
|
|
406
438
|
|
|
407
439
|
useRouterSubscription(router)
|
|
408
|
-
|
|
409
440
|
useLayoutEffect(() => {
|
|
410
|
-
|
|
441
|
+
const unsub = router.mount()
|
|
442
|
+
router.load()
|
|
443
|
+
return unsub
|
|
411
444
|
}, [router])
|
|
412
445
|
|
|
413
446
|
return (
|
|
@@ -432,57 +465,41 @@ function useMatches(): RouteMatch[] {
|
|
|
432
465
|
return React.useContext(matchesContext)
|
|
433
466
|
}
|
|
434
467
|
|
|
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 {
|
|
446
|
-
return useMatches()?.[0] as RouteMatch
|
|
447
|
-
}
|
|
448
|
-
|
|
449
468
|
export function Outlet() {
|
|
450
469
|
const router = useRouter()
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
const childMatch = matches[0]
|
|
470
|
+
const matches = useMatches().slice(1)
|
|
471
|
+
const match = matches[0]
|
|
454
472
|
|
|
455
|
-
if (!
|
|
473
|
+
if (!match) {
|
|
474
|
+
return null
|
|
475
|
+
}
|
|
456
476
|
|
|
457
477
|
const element = ((): React.ReactNode => {
|
|
458
|
-
if (!
|
|
478
|
+
if (!match) {
|
|
459
479
|
return null
|
|
460
480
|
}
|
|
461
481
|
|
|
462
482
|
const errorElement =
|
|
463
|
-
|
|
483
|
+
match.__.errorElement ?? router.options.defaultErrorElement
|
|
464
484
|
|
|
465
|
-
if (
|
|
485
|
+
if (match.status === 'error') {
|
|
466
486
|
if (errorElement) {
|
|
467
487
|
return errorElement as any
|
|
468
488
|
}
|
|
469
489
|
|
|
470
|
-
if (
|
|
471
|
-
|
|
472
|
-
router.options.useErrorBoundary
|
|
473
|
-
) {
|
|
474
|
-
throw childMatch.error
|
|
490
|
+
if (match.options.useErrorBoundary || router.options.useErrorBoundary) {
|
|
491
|
+
throw match.error
|
|
475
492
|
}
|
|
476
493
|
|
|
477
|
-
return <DefaultErrorBoundary error={
|
|
494
|
+
return <DefaultErrorBoundary error={match.error} />
|
|
478
495
|
}
|
|
479
496
|
|
|
480
|
-
if (
|
|
481
|
-
if (
|
|
497
|
+
if (match.status === 'loading' || match.status === 'idle') {
|
|
498
|
+
if (match.isPending) {
|
|
482
499
|
const pendingElement =
|
|
483
|
-
|
|
500
|
+
match.__.pendingElement ?? router.options.defaultPendingElement
|
|
484
501
|
|
|
485
|
-
if (
|
|
502
|
+
if (match.options.pendingMs || pendingElement) {
|
|
486
503
|
return (pendingElement as any) ?? null
|
|
487
504
|
}
|
|
488
505
|
}
|
|
@@ -490,14 +507,16 @@ export function Outlet() {
|
|
|
490
507
|
return null
|
|
491
508
|
}
|
|
492
509
|
|
|
493
|
-
return (
|
|
510
|
+
return (
|
|
511
|
+
(match.__.element as any) ?? router.options.defaultElement ?? <Outlet />
|
|
512
|
+
)
|
|
494
513
|
})() as JSX.Element
|
|
495
514
|
|
|
496
515
|
const catchElement =
|
|
497
|
-
|
|
516
|
+
match?.options.catchElement ?? router.options.defaultCatchElement
|
|
498
517
|
|
|
499
518
|
return (
|
|
500
|
-
<MatchesProvider value={matches}
|
|
519
|
+
<MatchesProvider value={matches}>
|
|
501
520
|
<CatchBoundary catchElement={catchElement}>{element}</CatchBoundary>
|
|
502
521
|
</MatchesProvider>
|
|
503
522
|
)
|
|
@@ -518,12 +537,6 @@ class CatchBoundary extends React.Component<{
|
|
|
518
537
|
info,
|
|
519
538
|
})
|
|
520
539
|
}
|
|
521
|
-
reset = () => {
|
|
522
|
-
this.setState({
|
|
523
|
-
error: false,
|
|
524
|
-
info: false,
|
|
525
|
-
})
|
|
526
|
-
}
|
|
527
540
|
render() {
|
|
528
541
|
const catchElement = this.props.catchElement ?? DefaultErrorBoundary
|
|
529
542
|
|
|
@@ -559,7 +572,7 @@ export function DefaultErrorBoundary({ error }: { error: any }) {
|
|
|
559
572
|
) : null}
|
|
560
573
|
</pre>
|
|
561
574
|
</div>
|
|
562
|
-
<div style={{ height: '1rem' }} />
|
|
575
|
+
{/* <div style={{ height: '1rem' }} />
|
|
563
576
|
<div
|
|
564
577
|
style={{
|
|
565
578
|
fontSize: '.8em',
|
|
@@ -571,9 +584,31 @@ export function DefaultErrorBoundary({ error }: { error: any }) {
|
|
|
571
584
|
If you are the owner of this website, it's highly recommended that you
|
|
572
585
|
configure your own custom Catch/Error boundaries for the router. You can
|
|
573
586
|
optionally configure a boundary for each route.
|
|
574
|
-
</div>
|
|
587
|
+
</div> */}
|
|
575
588
|
</div>
|
|
576
589
|
)
|
|
577
590
|
}
|
|
578
591
|
|
|
579
|
-
|
|
592
|
+
export function usePrompt(message: string, when: boolean | any): void {
|
|
593
|
+
const router = useRouter()
|
|
594
|
+
|
|
595
|
+
React.useEffect(() => {
|
|
596
|
+
if (!when) return
|
|
597
|
+
|
|
598
|
+
let unblock = router.history.block((transition) => {
|
|
599
|
+
if (window.confirm(message)) {
|
|
600
|
+
unblock()
|
|
601
|
+
transition.retry()
|
|
602
|
+
} else {
|
|
603
|
+
router.location.pathname = window.location.pathname
|
|
604
|
+
}
|
|
605
|
+
})
|
|
606
|
+
|
|
607
|
+
return unblock
|
|
608
|
+
}, [when, location, message])
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
export function Prompt({ message, when, children }: PromptProps) {
|
|
612
|
+
usePrompt(message, when ?? true)
|
|
613
|
+
return (children ?? null) as React.ReactNode
|
|
614
|
+
}
|
package/src/qss.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
|
|
3
|
-
// We're inlining qss here for compression's sake, but we've included it as a hard dependency for the MIT license it requires.
|
|
4
|
-
|
|
5
|
-
export function encode(obj, pfx?: string) {
|
|
6
|
-
var k,
|
|
7
|
-
i,
|
|
8
|
-
tmp,
|
|
9
|
-
str = ''
|
|
10
|
-
|
|
11
|
-
for (k in obj) {
|
|
12
|
-
if ((tmp = obj[k]) !== void 0) {
|
|
13
|
-
if (Array.isArray(tmp)) {
|
|
14
|
-
for (i = 0; i < tmp.length; i++) {
|
|
15
|
-
str && (str += '&')
|
|
16
|
-
str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i])
|
|
17
|
-
}
|
|
18
|
-
} else {
|
|
19
|
-
str && (str += '&')
|
|
20
|
-
str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return (pfx || '') + str
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function toValue(mix) {
|
|
29
|
-
if (!mix) return ''
|
|
30
|
-
var str = decodeURIComponent(mix)
|
|
31
|
-
if (str === 'false') return false
|
|
32
|
-
if (str === 'true') return true
|
|
33
|
-
return +str * 0 === 0 ? +str : str
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function decode(str) {
|
|
37
|
-
var tmp,
|
|
38
|
-
k,
|
|
39
|
-
out = {},
|
|
40
|
-
arr = str.split('&')
|
|
41
|
-
|
|
42
|
-
while ((tmp = arr.shift())) {
|
|
43
|
-
tmp = tmp.split('=')
|
|
44
|
-
k = tmp.shift()
|
|
45
|
-
if (out[k] !== void 0) {
|
|
46
|
-
out[k] = [].concat(out[k], toValue(tmp.shift()))
|
|
47
|
-
} else {
|
|
48
|
-
out[k] = toValue(tmp.shift())
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return out
|
|
53
|
-
}
|