@tanstack/react-router 0.0.1-beta.2 → 0.0.1-beta.20
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 +95 -117
- 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 +344 -343
- 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 +42 -10
- package/build/umd/index.development.js +351 -343
- 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 +172 -136
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.20",
|
|
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.19",
|
|
44
45
|
"use-sync-external-store": "^1.2.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
package/src/index.tsx
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
AnyRoute,
|
|
7
7
|
CheckId,
|
|
8
8
|
rootRouteId,
|
|
9
|
-
Router,
|
|
10
9
|
RouterState,
|
|
11
10
|
ToIdOption,
|
|
12
11
|
} from '@tanstack/router-core'
|
|
@@ -31,15 +30,67 @@ import {
|
|
|
31
30
|
NoInfer,
|
|
32
31
|
ToOptions,
|
|
33
32
|
invariant,
|
|
33
|
+
Router,
|
|
34
34
|
} from '@tanstack/router-core'
|
|
35
35
|
|
|
36
36
|
export * from '@tanstack/router-core'
|
|
37
37
|
|
|
38
|
+
export interface RegisterRouter {
|
|
39
|
+
// router: Router
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type ResolvedRouter = RegisterRouter extends {
|
|
43
|
+
router: Router<infer TRouteConfig, infer TAllRouteInfo>
|
|
44
|
+
}
|
|
45
|
+
? Router<TRouteConfig, TAllRouteInfo>
|
|
46
|
+
: Router
|
|
47
|
+
|
|
48
|
+
export type ResolvedAllRouteInfo = RegisterRouter extends {
|
|
49
|
+
router: Router<infer TRouteConfig, infer TAllRouteInfo>
|
|
50
|
+
}
|
|
51
|
+
? TAllRouteInfo
|
|
52
|
+
: AnyAllRouteInfo
|
|
53
|
+
|
|
54
|
+
export type SyncRouteComponent = (props?: {}) => JSX.Element | React.ReactNode
|
|
55
|
+
|
|
56
|
+
export type RouteComponent = SyncRouteComponent & {
|
|
57
|
+
preload?: () => Promise<SyncRouteComponent>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function lazy(
|
|
61
|
+
importer: () => Promise<{ default: SyncRouteComponent }>,
|
|
62
|
+
): RouteComponent {
|
|
63
|
+
const lazyComp = React.lazy(importer as any)
|
|
64
|
+
let promise: Promise<SyncRouteComponent>
|
|
65
|
+
let resolvedComp: SyncRouteComponent
|
|
66
|
+
|
|
67
|
+
const forwardedComp = React.forwardRef((props, ref) => {
|
|
68
|
+
const resolvedCompRef = React.useRef(resolvedComp || lazyComp)
|
|
69
|
+
return React.createElement(
|
|
70
|
+
resolvedCompRef.current as any,
|
|
71
|
+
{ ...(ref ? { ref } : {}), ...props } as any,
|
|
72
|
+
)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const finalComp = forwardedComp as unknown as RouteComponent
|
|
76
|
+
|
|
77
|
+
finalComp.preload = () => {
|
|
78
|
+
if (!promise) {
|
|
79
|
+
promise = importer().then((module) => {
|
|
80
|
+
resolvedComp = module.default
|
|
81
|
+
return resolvedComp
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return promise
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return finalComp
|
|
89
|
+
}
|
|
90
|
+
|
|
38
91
|
declare module '@tanstack/router-core' {
|
|
39
92
|
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>)
|
|
93
|
+
Component: RouteComponent
|
|
43
94
|
}
|
|
44
95
|
|
|
45
96
|
interface Router<
|
|
@@ -50,9 +101,17 @@ declare module '@tanstack/router-core' {
|
|
|
50
101
|
useRoute: <TId extends keyof TAllRouteInfo['routeInfoById']>(
|
|
51
102
|
routeId: TId,
|
|
52
103
|
) => Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
53
|
-
useMatch: <
|
|
104
|
+
useMatch: <
|
|
105
|
+
TId extends keyof TAllRouteInfo['routeInfoById'],
|
|
106
|
+
TStrict extends true | false = true,
|
|
107
|
+
>(
|
|
54
108
|
routeId: TId,
|
|
55
|
-
|
|
109
|
+
opts?: { strict?: TStrict },
|
|
110
|
+
) => TStrict extends true
|
|
111
|
+
? RouteMatch<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
112
|
+
:
|
|
113
|
+
| RouteMatch<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
114
|
+
| undefined
|
|
56
115
|
linkProps: <TTo extends string = '.'>(
|
|
57
116
|
props: LinkPropsOptions<TAllRouteInfo, '/', TTo> &
|
|
58
117
|
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
@@ -99,6 +158,7 @@ declare module '@tanstack/router-core' {
|
|
|
99
158
|
TResolved,
|
|
100
159
|
ToIdOption<TAllRouteInfo, TRouteInfo['id'], TTo>
|
|
101
160
|
>,
|
|
161
|
+
opts?: { strict?: boolean },
|
|
102
162
|
) => Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TResolved]>
|
|
103
163
|
linkProps: <TTo extends string = '.'>(
|
|
104
164
|
props: LinkPropsOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo> &
|
|
@@ -154,18 +214,24 @@ export type PromptProps = {
|
|
|
154
214
|
|
|
155
215
|
//
|
|
156
216
|
|
|
157
|
-
|
|
158
|
-
|
|
217
|
+
export function Link<TTo extends string = '.'>(
|
|
218
|
+
props: LinkPropsOptions<ResolvedAllRouteInfo, '/', TTo> &
|
|
219
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement> &
|
|
220
|
+
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> & {
|
|
221
|
+
children?:
|
|
222
|
+
| React.ReactNode
|
|
223
|
+
| ((state: { isActive: boolean }) => React.ReactNode)
|
|
224
|
+
},
|
|
225
|
+
): JSX.Element {
|
|
226
|
+
const router = useRouter()
|
|
227
|
+
return <router.Link {...(props as any)} />
|
|
228
|
+
}
|
|
159
229
|
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
window.document &&
|
|
164
|
-
window.document.createElement,
|
|
230
|
+
export const matchesContext = React.createContext<RouteMatch[]>(null!)
|
|
231
|
+
export const routerContext = React.createContext<{ router: ResolvedRouter }>(
|
|
232
|
+
null!,
|
|
165
233
|
)
|
|
166
234
|
|
|
167
|
-
const useLayoutEffect = isDOM ? React.useLayoutEffect : React.useEffect
|
|
168
|
-
|
|
169
235
|
export type MatchesProviderProps = {
|
|
170
236
|
value: RouteMatch[]
|
|
171
237
|
children: React.ReactNode
|
|
@@ -253,6 +319,12 @@ export function createReactRouter<
|
|
|
253
319
|
next,
|
|
254
320
|
} = linkInfo
|
|
255
321
|
|
|
322
|
+
const reactHandleClick = (e: Event) => {
|
|
323
|
+
React.startTransition(() => {
|
|
324
|
+
handleClick(e)
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
|
|
256
328
|
const composeHandlers =
|
|
257
329
|
(handlers: (undefined | ((e: any) => void))[]) =>
|
|
258
330
|
(e: React.SyntheticEvent) => {
|
|
@@ -275,7 +347,7 @@ export function createReactRouter<
|
|
|
275
347
|
...resolvedInactiveProps,
|
|
276
348
|
...rest,
|
|
277
349
|
href: disabled ? undefined : next.href,
|
|
278
|
-
onClick: composeHandlers([
|
|
350
|
+
onClick: composeHandlers([reactHandleClick, onClick]),
|
|
279
351
|
onFocus: composeHandlers([handleFocus, onFocus]),
|
|
280
352
|
onMouseEnter: composeHandlers([handleEnter, onMouseEnter]),
|
|
281
353
|
onMouseLeave: composeHandlers([handleLeave, onMouseLeave]),
|
|
@@ -349,7 +421,7 @@ export function createReactRouter<
|
|
|
349
421
|
useRouterSubscription(router)
|
|
350
422
|
return router.state
|
|
351
423
|
},
|
|
352
|
-
useMatch: (routeId) => {
|
|
424
|
+
useMatch: (routeId, opts) => {
|
|
353
425
|
useRouterSubscription(router)
|
|
354
426
|
|
|
355
427
|
invariant(
|
|
@@ -357,32 +429,30 @@ export function createReactRouter<
|
|
|
357
429
|
`"${rootRouteId}" cannot be used with useMatch! Did you mean to useRoute("${rootRouteId}")?`,
|
|
358
430
|
)
|
|
359
431
|
|
|
360
|
-
const runtimeMatch =
|
|
432
|
+
const runtimeMatch = useMatches()?.[0]!
|
|
361
433
|
const match = router.state.matches.find((d) => d.routeId === routeId)
|
|
362
434
|
|
|
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!')
|
|
435
|
+
if (opts?.strict ?? true) {
|
|
436
|
+
invariant(
|
|
437
|
+
match,
|
|
438
|
+
`Could not find an active match for "${routeId as string}"!`,
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
invariant(
|
|
442
|
+
runtimeMatch.routeId == match?.routeId,
|
|
443
|
+
`useMatch("${
|
|
444
|
+
match?.routeId as string
|
|
445
|
+
}") is being called in a component that is meant to render the '${
|
|
446
|
+
runtimeMatch.routeId
|
|
447
|
+
}' route. Did you mean to 'useMatch("${
|
|
448
|
+
match?.routeId as string
|
|
449
|
+
}", { strict: false })' or 'useRoute("${
|
|
450
|
+
match?.routeId as string
|
|
451
|
+
}")' instead?`,
|
|
452
|
+
)
|
|
383
453
|
}
|
|
384
454
|
|
|
385
|
-
return match
|
|
455
|
+
return match as any
|
|
386
456
|
},
|
|
387
457
|
}
|
|
388
458
|
|
|
@@ -395,19 +465,13 @@ export function createReactRouter<
|
|
|
395
465
|
|
|
396
466
|
Object.assign(route, routeExt)
|
|
397
467
|
},
|
|
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
|
-
}
|
|
468
|
+
loadComponent: async (component) => {
|
|
469
|
+
if (component.preload && typeof document !== 'undefined') {
|
|
470
|
+
component.preload()
|
|
471
|
+
// return await component.preload()
|
|
408
472
|
}
|
|
409
473
|
|
|
410
|
-
return
|
|
474
|
+
return component as any
|
|
411
475
|
},
|
|
412
476
|
})
|
|
413
477
|
|
|
@@ -430,13 +494,13 @@ export function RouterProvider<
|
|
|
430
494
|
router.update(rest)
|
|
431
495
|
|
|
432
496
|
useRouterSubscription(router)
|
|
433
|
-
|
|
434
|
-
|
|
497
|
+
React.useEffect(() => {
|
|
498
|
+
console.log('hello')
|
|
435
499
|
return router.mount()
|
|
436
500
|
}, [router])
|
|
437
501
|
|
|
438
502
|
return (
|
|
439
|
-
<routerContext.Provider value={{ router }}>
|
|
503
|
+
<routerContext.Provider value={{ router: router as any }}>
|
|
440
504
|
<MatchesProvider value={router.state.matches}>
|
|
441
505
|
{children ?? <Outlet />}
|
|
442
506
|
</MatchesProvider>
|
|
@@ -444,93 +508,86 @@ export function RouterProvider<
|
|
|
444
508
|
)
|
|
445
509
|
}
|
|
446
510
|
|
|
447
|
-
function useRouter():
|
|
511
|
+
export function useRouter(): ResolvedRouter {
|
|
448
512
|
const value = React.useContext(routerContext)
|
|
449
513
|
warning(!value, 'useRouter must be used inside a <Router> component!')
|
|
450
514
|
|
|
451
515
|
useRouterSubscription(value.router)
|
|
452
516
|
|
|
453
|
-
return value.router
|
|
517
|
+
return value.router
|
|
454
518
|
}
|
|
455
519
|
|
|
456
|
-
function useMatches(): RouteMatch[] {
|
|
520
|
+
export function useMatches(): RouteMatch[] {
|
|
457
521
|
return React.useContext(matchesContext)
|
|
458
522
|
}
|
|
459
523
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
524
|
+
export function useMatch<
|
|
525
|
+
TId extends keyof ResolvedAllRouteInfo['routeInfoById'],
|
|
526
|
+
TStrict extends true | false = true,
|
|
527
|
+
>(
|
|
528
|
+
routeId: TId,
|
|
529
|
+
opts?: { strict?: TStrict },
|
|
530
|
+
): TStrict extends true
|
|
531
|
+
? RouteMatch<ResolvedAllRouteInfo, ResolvedAllRouteInfo['routeInfoById'][TId]>
|
|
532
|
+
:
|
|
533
|
+
| RouteMatch<
|
|
534
|
+
ResolvedAllRouteInfo,
|
|
535
|
+
ResolvedAllRouteInfo['routeInfoById'][TId]
|
|
536
|
+
>
|
|
537
|
+
| undefined {
|
|
538
|
+
const router = useRouter()
|
|
539
|
+
return router.useMatch(routeId as any, opts) as any
|
|
472
540
|
}
|
|
473
541
|
|
|
474
542
|
export function Outlet() {
|
|
475
543
|
const router = useRouter()
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
const childMatch = matches[0]
|
|
479
|
-
|
|
480
|
-
if (!childMatch) return null
|
|
481
|
-
|
|
482
|
-
const element = ((): React.ReactNode => {
|
|
483
|
-
if (!childMatch) {
|
|
484
|
-
return null
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
const errorElement =
|
|
488
|
-
childMatch.__.errorElement ?? router.options.defaultErrorElement
|
|
489
|
-
|
|
490
|
-
if (childMatch.status === 'error') {
|
|
491
|
-
if (errorElement) {
|
|
492
|
-
return errorElement as any
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
if (
|
|
496
|
-
childMatch.options.useErrorBoundary ||
|
|
497
|
-
router.options.useErrorBoundary
|
|
498
|
-
) {
|
|
499
|
-
throw childMatch.error
|
|
500
|
-
}
|
|
544
|
+
const matches = useMatches().slice(1)
|
|
545
|
+
const match = matches[0]
|
|
501
546
|
|
|
502
|
-
|
|
503
|
-
}
|
|
547
|
+
const defaultPending = React.useCallback(() => null, [])
|
|
504
548
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
childMatch.__.pendingElement ?? router.options.defaultPendingElement
|
|
549
|
+
if (!match) {
|
|
550
|
+
return null
|
|
551
|
+
}
|
|
509
552
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
553
|
+
const PendingComponent = (match.__.pendingComponent ??
|
|
554
|
+
router.options.defaultPendingComponent ??
|
|
555
|
+
defaultPending) as any
|
|
514
556
|
|
|
515
|
-
|
|
516
|
-
|
|
557
|
+
const errorComponent =
|
|
558
|
+
match.__.errorComponent ?? router.options.defaultErrorComponent
|
|
517
559
|
|
|
518
|
-
|
|
519
|
-
|
|
560
|
+
return (
|
|
561
|
+
<MatchesProvider value={matches}>
|
|
562
|
+
<React.Suspense fallback={<PendingComponent />}>
|
|
563
|
+
<CatchBoundary errorComponent={errorComponent}>
|
|
564
|
+
{
|
|
565
|
+
((): React.ReactNode => {
|
|
566
|
+
if (match.status === 'error') {
|
|
567
|
+
throw match.error
|
|
568
|
+
}
|
|
520
569
|
|
|
521
|
-
|
|
522
|
-
|
|
570
|
+
if (match.status === 'success') {
|
|
571
|
+
return React.createElement(
|
|
572
|
+
(match.__.component as any) ??
|
|
573
|
+
router.options.defaultComponent ??
|
|
574
|
+
Outlet,
|
|
575
|
+
)
|
|
576
|
+
}
|
|
523
577
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
578
|
+
console.log(match.matchId, 'suspend')
|
|
579
|
+
throw match.__.loadPromise
|
|
580
|
+
})() as JSX.Element
|
|
581
|
+
}
|
|
582
|
+
</CatchBoundary>
|
|
583
|
+
</React.Suspense>
|
|
527
584
|
</MatchesProvider>
|
|
528
585
|
)
|
|
529
586
|
}
|
|
530
587
|
|
|
531
588
|
class CatchBoundary extends React.Component<{
|
|
532
589
|
children: any
|
|
533
|
-
|
|
590
|
+
errorComponent: any
|
|
534
591
|
}> {
|
|
535
592
|
state = {
|
|
536
593
|
error: false,
|
|
@@ -543,19 +600,11 @@ class CatchBoundary extends React.Component<{
|
|
|
543
600
|
info,
|
|
544
601
|
})
|
|
545
602
|
}
|
|
546
|
-
reset = () => {
|
|
547
|
-
this.setState({
|
|
548
|
-
error: false,
|
|
549
|
-
info: false,
|
|
550
|
-
})
|
|
551
|
-
}
|
|
552
603
|
render() {
|
|
553
|
-
const
|
|
604
|
+
const errorComponent = this.props.errorComponent ?? DefaultErrorBoundary
|
|
554
605
|
|
|
555
606
|
if (this.state.error) {
|
|
556
|
-
return
|
|
557
|
-
? catchElement(this.state)
|
|
558
|
-
: catchElement
|
|
607
|
+
return React.createElement(errorComponent, this.state)
|
|
559
608
|
}
|
|
560
609
|
|
|
561
610
|
return this.props.children
|
|
@@ -584,19 +633,6 @@ export function DefaultErrorBoundary({ error }: { error: any }) {
|
|
|
584
633
|
) : null}
|
|
585
634
|
</pre>
|
|
586
635
|
</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
636
|
</div>
|
|
601
637
|
)
|
|
602
638
|
}
|