@tanstack/router-core 0.0.1-beta.174 → 0.0.1-beta.175
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/index.js +1 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +60 -36
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +59 -36
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +158 -191
- package/build/types/defer.d.ts +19 -0
- package/build/types/fileRoute.d.ts +35 -0
- package/build/types/history.d.ts +31 -0
- package/build/types/index.d.ts +12 -780
- package/build/types/link.d.ts +92 -0
- package/build/types/path.d.ts +16 -0
- package/build/types/qss.d.ts +2 -0
- package/build/types/route.d.ts +234 -0
- package/build/types/routeInfo.d.ts +22 -0
- package/build/types/router.d.ts +251 -0
- package/build/types/scroll-restoration.d.ts +6 -0
- package/build/types/searchParams.d.ts +5 -0
- package/build/types/utils.d.ts +53 -0
- package/build/umd/index.development.js +60 -36
- 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/route.ts +12 -16
- package/src/router.ts +103 -55
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.175",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"@babel/runtime": "^7.16.7",
|
|
43
43
|
"tiny-invariant": "^1.3.1",
|
|
44
44
|
"tiny-warning": "^1.0.3",
|
|
45
|
-
"@
|
|
46
|
-
"@
|
|
45
|
+
"@tanstack/store": "^0.0.1",
|
|
46
|
+
"@gisatcz/cross-package-react-context": "^0.2.0"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "rollup --config rollup.config.js",
|
package/src/route.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { ParsePathParams } from './link'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AnyRouter,
|
|
4
|
+
Router,
|
|
5
|
+
RouteMatch,
|
|
6
|
+
RegisteredRouter,
|
|
7
|
+
AnyRouteMatch,
|
|
8
|
+
} from './router'
|
|
3
9
|
import { IsAny, NoInfer, PickRequired, UnionToIntersection } from './utils'
|
|
4
10
|
import invariant from 'tiny-invariant'
|
|
5
11
|
import { joinPaths, trimPath } from './path'
|
|
@@ -386,21 +392,11 @@ export type UpdatableRouteOptions<
|
|
|
386
392
|
>,
|
|
387
393
|
) => Promise<void> | void
|
|
388
394
|
onError?: (err: any) => void
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
search: TFullSearchSchema
|
|
395
|
-
}) =>
|
|
396
|
-
| void
|
|
397
|
-
| undefined
|
|
398
|
-
| ((match: { params: TAllParams; search: TFullSearchSchema }) => void)
|
|
399
|
-
// This function is called when the route remains active from one transition to the next.
|
|
400
|
-
onTransition?: (match: {
|
|
401
|
-
params: TAllParams
|
|
402
|
-
search: TFullSearchSchema
|
|
403
|
-
}) => void
|
|
395
|
+
// These functions are called as route matches are loaded, stick around and leave the active
|
|
396
|
+
// matches
|
|
397
|
+
onEnter?: (match: AnyRouteMatch) => void
|
|
398
|
+
onTransition?: (match: AnyRouteMatch) => void
|
|
399
|
+
onLeave?: (match: AnyRouteMatch) => void
|
|
404
400
|
}
|
|
405
401
|
|
|
406
402
|
export type ParseParamsOption<TPath extends string, TParams> = ParseParamsFn<
|
package/src/router.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Store } from '@tanstack/
|
|
1
|
+
import { Store } from '@tanstack/store'
|
|
2
2
|
import invariant from 'tiny-invariant'
|
|
3
3
|
|
|
4
4
|
//
|
|
@@ -123,8 +123,8 @@ export interface RouteMatch<
|
|
|
123
123
|
paramsError: unknown
|
|
124
124
|
searchError: unknown
|
|
125
125
|
updatedAt: number
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
maxAge: number
|
|
127
|
+
preloadMaxAge: number
|
|
128
128
|
loaderData: RouteById<TRouteTree, TRouteId>['types']['loader']
|
|
129
129
|
loadPromise?: Promise<void>
|
|
130
130
|
__resolveLoadPromise?: () => void
|
|
@@ -157,6 +157,7 @@ export interface RouterOptions<
|
|
|
157
157
|
parseSearch?: SearchParser
|
|
158
158
|
defaultPreload?: false | 'intent'
|
|
159
159
|
defaultPreloadDelay?: number
|
|
160
|
+
refetchOnWindowFocus?: boolean
|
|
160
161
|
defaultComponent?: RegisteredRouteComponent<
|
|
161
162
|
unknown,
|
|
162
163
|
AnySearchSchema,
|
|
@@ -249,7 +250,8 @@ export type DehydratedRouteMatch = Pick<
|
|
|
249
250
|
RouteMatch,
|
|
250
251
|
| 'fetchedAt'
|
|
251
252
|
| 'invalid'
|
|
252
|
-
| '
|
|
253
|
+
| 'maxAge'
|
|
254
|
+
| 'preloadMaxAge'
|
|
253
255
|
| 'id'
|
|
254
256
|
| 'loaderData'
|
|
255
257
|
| 'status'
|
|
@@ -294,6 +296,9 @@ export type RouterListener<TRouterEvent extends RouterEvent> = {
|
|
|
294
296
|
fn: ListenerFn<TRouterEvent>
|
|
295
297
|
}
|
|
296
298
|
|
|
299
|
+
const visibilityChangeEvent = 'visibilitychange'
|
|
300
|
+
const focusEvent = 'focus'
|
|
301
|
+
|
|
297
302
|
export class Router<
|
|
298
303
|
TRouteTree extends AnyRoute = AnyRoute,
|
|
299
304
|
TDehydrated extends Record<string, any> = Record<string, any>,
|
|
@@ -420,10 +425,28 @@ export class Router<
|
|
|
420
425
|
}
|
|
421
426
|
|
|
422
427
|
mount = () => {
|
|
423
|
-
//
|
|
424
|
-
//
|
|
428
|
+
// addEventListener does not exist in React Native, but window does
|
|
429
|
+
// In the future, we might need to invert control here for more adapters
|
|
430
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
431
|
+
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
432
|
+
window.addEventListener(visibilityChangeEvent, this.#onFocus, false)
|
|
433
|
+
window.addEventListener(focusEvent, this.#onFocus, false)
|
|
434
|
+
}
|
|
435
|
+
|
|
425
436
|
this.safeLoad()
|
|
426
|
-
|
|
437
|
+
|
|
438
|
+
return () => {
|
|
439
|
+
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
440
|
+
window.removeEventListener(visibilityChangeEvent, this.#onFocus)
|
|
441
|
+
window.removeEventListener(focusEvent, this.#onFocus)
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
#onFocus = () => {
|
|
447
|
+
if (this.options.refetchOnWindowFocus ?? true) {
|
|
448
|
+
this.reload()
|
|
449
|
+
}
|
|
427
450
|
}
|
|
428
451
|
|
|
429
452
|
update = (opts?: RouterOptions<any, any>): this => {
|
|
@@ -525,7 +548,6 @@ export class Router<
|
|
|
525
548
|
}
|
|
526
549
|
|
|
527
550
|
// Cancel any pending matches
|
|
528
|
-
// this.cancelMatches()
|
|
529
551
|
|
|
530
552
|
let pendingMatches!: RouteMatch<any, any>[]
|
|
531
553
|
|
|
@@ -577,6 +599,18 @@ export class Router<
|
|
|
577
599
|
return latestPromise
|
|
578
600
|
}
|
|
579
601
|
|
|
602
|
+
const exitingMatchIds = this.state.matchIds.filter(
|
|
603
|
+
(id) => !this.state.pendingMatchIds.includes(id),
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
const enteringMatchIds = this.state.pendingMatchIds.filter(
|
|
607
|
+
(id) => !this.state.matchIds.includes(id),
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
const stayingMatchIds = this.state.matchIds.filter((id) =>
|
|
611
|
+
this.state.pendingMatchIds.includes(id),
|
|
612
|
+
)
|
|
613
|
+
|
|
580
614
|
this.__store.setState((s) => ({
|
|
581
615
|
...s,
|
|
582
616
|
status: 'idle',
|
|
@@ -584,6 +618,19 @@ export class Router<
|
|
|
584
618
|
matchIds: s.pendingMatchIds,
|
|
585
619
|
pendingMatchIds: [],
|
|
586
620
|
}))
|
|
621
|
+
;(
|
|
622
|
+
[
|
|
623
|
+
[exitingMatchIds, 'onLeave'],
|
|
624
|
+
[enteringMatchIds, 'onEnter'],
|
|
625
|
+
[stayingMatchIds, 'onTransition'],
|
|
626
|
+
] as const
|
|
627
|
+
).forEach(([matchIds, hook]) => {
|
|
628
|
+
matchIds.forEach((id) => {
|
|
629
|
+
const match = this.getRouteMatch(id)!
|
|
630
|
+
const route = this.getRoute(match.routeId)
|
|
631
|
+
route.options[hook]?.(match)
|
|
632
|
+
})
|
|
633
|
+
})
|
|
587
634
|
|
|
588
635
|
this.#emit({
|
|
589
636
|
type: 'onLoad',
|
|
@@ -605,6 +652,10 @@ export class Router<
|
|
|
605
652
|
|
|
606
653
|
this.latestLoadPromise = promise
|
|
607
654
|
|
|
655
|
+
this.latestLoadPromise.then(() => {
|
|
656
|
+
this.cleanMatches()
|
|
657
|
+
})
|
|
658
|
+
|
|
608
659
|
return this.latestLoadPromise
|
|
609
660
|
}
|
|
610
661
|
|
|
@@ -671,10 +722,13 @@ export class Router<
|
|
|
671
722
|
const outdatedMatchIds = Object.values(this.state.matchesById)
|
|
672
723
|
.filter((match) => {
|
|
673
724
|
const route = this.getRoute(match.routeId)
|
|
725
|
+
|
|
674
726
|
return (
|
|
675
727
|
!this.state.matchIds.includes(match.id) &&
|
|
676
728
|
!this.state.pendingMatchIds.includes(match.id) &&
|
|
677
|
-
match.
|
|
729
|
+
(match.preloadMaxAge > -1
|
|
730
|
+
? match.updatedAt + match.preloadMaxAge < now
|
|
731
|
+
: true) &&
|
|
678
732
|
(route.options.gcMaxAge
|
|
679
733
|
? match.updatedAt + route.options.gcMaxAge < now
|
|
680
734
|
: true)
|
|
@@ -795,8 +849,8 @@ export class Router<
|
|
|
795
849
|
params: routeParams,
|
|
796
850
|
pathname: joinPaths([this.basepath, interpolatedPath]),
|
|
797
851
|
updatedAt: Date.now(),
|
|
798
|
-
|
|
799
|
-
|
|
852
|
+
maxAge: -1,
|
|
853
|
+
preloadMaxAge: -1,
|
|
800
854
|
routeSearch: {},
|
|
801
855
|
search: {} as any,
|
|
802
856
|
status: hasLoaders ? 'pending' : 'success',
|
|
@@ -917,13 +971,14 @@ export class Router<
|
|
|
917
971
|
paramsError: match.paramsError,
|
|
918
972
|
searchError: match.searchError,
|
|
919
973
|
params: match.params,
|
|
920
|
-
|
|
974
|
+
preloadMaxAge: 0,
|
|
921
975
|
}))
|
|
922
976
|
})
|
|
977
|
+
} else {
|
|
978
|
+
// If we're preloading, clean preload matches before we try and use them
|
|
979
|
+
this.cleanMatches()
|
|
923
980
|
}
|
|
924
981
|
|
|
925
|
-
this.cleanMatches()
|
|
926
|
-
|
|
927
982
|
let firstBadMatchIndex: number | undefined
|
|
928
983
|
|
|
929
984
|
// Check each match middleware to see if the route can be accessed
|
|
@@ -1002,7 +1057,9 @@ export class Router<
|
|
|
1002
1057
|
if (
|
|
1003
1058
|
match.isFetching ||
|
|
1004
1059
|
(match.status === 'success' &&
|
|
1005
|
-
!
|
|
1060
|
+
!isMatchInvalid(match, {
|
|
1061
|
+
preload: opts?.preload,
|
|
1062
|
+
}))
|
|
1006
1063
|
) {
|
|
1007
1064
|
return this.getRouteMatch(match.id)?.loadPromise
|
|
1008
1065
|
}
|
|
@@ -1098,8 +1155,6 @@ export class Router<
|
|
|
1098
1155
|
})
|
|
1099
1156
|
|
|
1100
1157
|
await Promise.all(matchPromises)
|
|
1101
|
-
|
|
1102
|
-
this.cleanMatches()
|
|
1103
1158
|
}
|
|
1104
1159
|
|
|
1105
1160
|
reload = () => {
|
|
@@ -1350,7 +1405,8 @@ export class Router<
|
|
|
1350
1405
|
pick(d, [
|
|
1351
1406
|
'fetchedAt',
|
|
1352
1407
|
'invalid',
|
|
1353
|
-
'
|
|
1408
|
+
'preloadMaxAge',
|
|
1409
|
+
'maxAge',
|
|
1354
1410
|
'id',
|
|
1355
1411
|
'loaderData',
|
|
1356
1412
|
'status',
|
|
@@ -1709,7 +1765,6 @@ export class Router<
|
|
|
1709
1765
|
})
|
|
1710
1766
|
|
|
1711
1767
|
this.resetNextScroll = location.resetScroll ?? true
|
|
1712
|
-
console.log('resetScroll', this.resetNextScroll)
|
|
1713
1768
|
|
|
1714
1769
|
return this.latestLoadPromise
|
|
1715
1770
|
}
|
|
@@ -1752,29 +1807,24 @@ export class Router<
|
|
|
1752
1807
|
const route = this.getRoute(match.routeId)
|
|
1753
1808
|
const updatedAt = opts?.updatedAt ?? Date.now()
|
|
1754
1809
|
|
|
1755
|
-
const
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
5000)
|
|
1810
|
+
const preloadMaxAge =
|
|
1811
|
+
opts?.maxAge ??
|
|
1812
|
+
route.options.preloadMaxAge ??
|
|
1813
|
+
this.options.defaultPreloadMaxAge ??
|
|
1814
|
+
5000
|
|
1761
1815
|
|
|
1762
|
-
const
|
|
1763
|
-
|
|
1764
|
-
(opts?.maxAge ??
|
|
1765
|
-
route.options.maxAge ??
|
|
1766
|
-
this.options.defaultMaxAge ??
|
|
1767
|
-
Infinity)
|
|
1816
|
+
const maxAge =
|
|
1817
|
+
opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? -1
|
|
1768
1818
|
|
|
1769
1819
|
this.setRouteMatch(id, (s) => ({
|
|
1770
1820
|
...s,
|
|
1771
1821
|
error: undefined,
|
|
1772
1822
|
status: 'success',
|
|
1773
1823
|
isFetching: false,
|
|
1774
|
-
updatedAt:
|
|
1824
|
+
updatedAt: updatedAt,
|
|
1775
1825
|
loaderData: functionalUpdate(updater, s.loaderData),
|
|
1776
|
-
|
|
1777
|
-
|
|
1826
|
+
preloadMaxAge,
|
|
1827
|
+
maxAge,
|
|
1778
1828
|
}))
|
|
1779
1829
|
}
|
|
1780
1830
|
|
|
@@ -1810,27 +1860,6 @@ export class Router<
|
|
|
1810
1860
|
return this.reload()
|
|
1811
1861
|
}
|
|
1812
1862
|
}
|
|
1813
|
-
|
|
1814
|
-
getIsInvalid = (opts?: { matchId: string; preload?: boolean }): boolean => {
|
|
1815
|
-
if (!opts?.matchId) {
|
|
1816
|
-
return !!this.state.matches.find((d) =>
|
|
1817
|
-
this.getIsInvalid({ matchId: d.id, preload: opts?.preload }),
|
|
1818
|
-
)
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
const match = this.getRouteMatch(opts?.matchId)
|
|
1822
|
-
|
|
1823
|
-
if (!match) {
|
|
1824
|
-
return false
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
const now = Date.now()
|
|
1828
|
-
|
|
1829
|
-
return (
|
|
1830
|
-
match.invalid ||
|
|
1831
|
-
(opts?.preload ? match.preloadInvalidAt : match.invalidAt) < now
|
|
1832
|
-
)
|
|
1833
|
-
}
|
|
1834
1863
|
}
|
|
1835
1864
|
|
|
1836
1865
|
// Detect if we're in the DOM
|
|
@@ -1900,3 +1929,22 @@ export function lazyFn<
|
|
|
1900
1929
|
return imported[key || 'default'](...args)
|
|
1901
1930
|
}
|
|
1902
1931
|
}
|
|
1932
|
+
|
|
1933
|
+
export function isMatchInvalid(
|
|
1934
|
+
match: AnyRouteMatch,
|
|
1935
|
+
opts?: { preload?: boolean },
|
|
1936
|
+
) {
|
|
1937
|
+
const now = Date.now()
|
|
1938
|
+
|
|
1939
|
+
if (match.invalid) {
|
|
1940
|
+
return true
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
if (opts?.preload) {
|
|
1944
|
+
return match.preloadMaxAge < 0
|
|
1945
|
+
? false
|
|
1946
|
+
: match.updatedAt + match.preloadMaxAge < now
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
return match.maxAge < 0 ? false : match.updatedAt + match.maxAge < now
|
|
1950
|
+
}
|