@tanstack/router-core 0.0.1-beta.174 → 0.0.1-beta.176
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 +57 -36
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +56 -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 +57 -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 +100 -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.176",
|
|
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,11 @@ 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
|
})
|
|
923
977
|
}
|
|
924
978
|
|
|
925
|
-
this.cleanMatches()
|
|
926
|
-
|
|
927
979
|
let firstBadMatchIndex: number | undefined
|
|
928
980
|
|
|
929
981
|
// Check each match middleware to see if the route can be accessed
|
|
@@ -1002,7 +1054,9 @@ export class Router<
|
|
|
1002
1054
|
if (
|
|
1003
1055
|
match.isFetching ||
|
|
1004
1056
|
(match.status === 'success' &&
|
|
1005
|
-
!
|
|
1057
|
+
!isMatchInvalid(match, {
|
|
1058
|
+
preload: opts?.preload,
|
|
1059
|
+
}))
|
|
1006
1060
|
) {
|
|
1007
1061
|
return this.getRouteMatch(match.id)?.loadPromise
|
|
1008
1062
|
}
|
|
@@ -1098,8 +1152,6 @@ export class Router<
|
|
|
1098
1152
|
})
|
|
1099
1153
|
|
|
1100
1154
|
await Promise.all(matchPromises)
|
|
1101
|
-
|
|
1102
|
-
this.cleanMatches()
|
|
1103
1155
|
}
|
|
1104
1156
|
|
|
1105
1157
|
reload = () => {
|
|
@@ -1350,7 +1402,8 @@ export class Router<
|
|
|
1350
1402
|
pick(d, [
|
|
1351
1403
|
'fetchedAt',
|
|
1352
1404
|
'invalid',
|
|
1353
|
-
'
|
|
1405
|
+
'preloadMaxAge',
|
|
1406
|
+
'maxAge',
|
|
1354
1407
|
'id',
|
|
1355
1408
|
'loaderData',
|
|
1356
1409
|
'status',
|
|
@@ -1709,7 +1762,6 @@ export class Router<
|
|
|
1709
1762
|
})
|
|
1710
1763
|
|
|
1711
1764
|
this.resetNextScroll = location.resetScroll ?? true
|
|
1712
|
-
console.log('resetScroll', this.resetNextScroll)
|
|
1713
1765
|
|
|
1714
1766
|
return this.latestLoadPromise
|
|
1715
1767
|
}
|
|
@@ -1752,29 +1804,24 @@ export class Router<
|
|
|
1752
1804
|
const route = this.getRoute(match.routeId)
|
|
1753
1805
|
const updatedAt = opts?.updatedAt ?? Date.now()
|
|
1754
1806
|
|
|
1755
|
-
const
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
5000)
|
|
1807
|
+
const preloadMaxAge =
|
|
1808
|
+
opts?.maxAge ??
|
|
1809
|
+
route.options.preloadMaxAge ??
|
|
1810
|
+
this.options.defaultPreloadMaxAge ??
|
|
1811
|
+
5000
|
|
1761
1812
|
|
|
1762
|
-
const
|
|
1763
|
-
|
|
1764
|
-
(opts?.maxAge ??
|
|
1765
|
-
route.options.maxAge ??
|
|
1766
|
-
this.options.defaultMaxAge ??
|
|
1767
|
-
Infinity)
|
|
1813
|
+
const maxAge =
|
|
1814
|
+
opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? -1
|
|
1768
1815
|
|
|
1769
1816
|
this.setRouteMatch(id, (s) => ({
|
|
1770
1817
|
...s,
|
|
1771
1818
|
error: undefined,
|
|
1772
1819
|
status: 'success',
|
|
1773
1820
|
isFetching: false,
|
|
1774
|
-
updatedAt:
|
|
1821
|
+
updatedAt: updatedAt,
|
|
1775
1822
|
loaderData: functionalUpdate(updater, s.loaderData),
|
|
1776
|
-
|
|
1777
|
-
|
|
1823
|
+
preloadMaxAge,
|
|
1824
|
+
maxAge,
|
|
1778
1825
|
}))
|
|
1779
1826
|
}
|
|
1780
1827
|
|
|
@@ -1810,27 +1857,6 @@ export class Router<
|
|
|
1810
1857
|
return this.reload()
|
|
1811
1858
|
}
|
|
1812
1859
|
}
|
|
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
1860
|
}
|
|
1835
1861
|
|
|
1836
1862
|
// Detect if we're in the DOM
|
|
@@ -1900,3 +1926,22 @@ export function lazyFn<
|
|
|
1900
1926
|
return imported[key || 'default'](...args)
|
|
1901
1927
|
}
|
|
1902
1928
|
}
|
|
1929
|
+
|
|
1930
|
+
export function isMatchInvalid(
|
|
1931
|
+
match: AnyRouteMatch,
|
|
1932
|
+
opts?: { preload?: boolean },
|
|
1933
|
+
) {
|
|
1934
|
+
const now = Date.now()
|
|
1935
|
+
|
|
1936
|
+
if (match.invalid) {
|
|
1937
|
+
return true
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
if (opts?.preload) {
|
|
1941
|
+
return match.preloadMaxAge < 0
|
|
1942
|
+
? false
|
|
1943
|
+
: match.updatedAt + match.preloadMaxAge < now
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
return match.maxAge < 0 ? false : match.updatedAt + match.maxAge < now
|
|
1947
|
+
}
|