@tanstack/react-router 0.0.1-beta.206 → 0.0.1-beta.208
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/RouterProvider.js +61 -49
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/index.js +1 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/react.js +6 -1
- package/build/cjs/react.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +67 -51
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +167 -167
- package/build/types/react.d.ts +1 -0
- package/build/types/route.d.ts +4 -1
- package/build/types/router.d.ts +3 -0
- package/build/umd/index.development.js +67 -50
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/RouterProvider.tsx +62 -61
- package/src/react.tsx +16 -1
- package/src/route.ts +4 -1
- package/src/router.ts +2 -0
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.208",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@babel/runtime": "^7.16.7",
|
|
43
43
|
"tiny-invariant": "^1.3.1",
|
|
44
44
|
"tiny-warning": "^1.0.3",
|
|
45
|
-
"@tanstack/history": "0.0.1-beta.
|
|
45
|
+
"@tanstack/history": "0.0.1-beta.208"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "rollup --config rollup.config.js"
|
package/src/RouterProvider.tsx
CHANGED
|
@@ -134,6 +134,10 @@ export type RouterContext<
|
|
|
134
134
|
|
|
135
135
|
export const routerContext = React.createContext<RouterContext<any>>(null!)
|
|
136
136
|
|
|
137
|
+
if (typeof document !== 'undefined') {
|
|
138
|
+
window.__TSR_ROUTER_CONTEXT__ = routerContext as any
|
|
139
|
+
}
|
|
140
|
+
|
|
137
141
|
export function getInitialRouterState(
|
|
138
142
|
location: ParsedLocation,
|
|
139
143
|
): RouterState<any> {
|
|
@@ -175,6 +179,14 @@ export function RouterProvider<
|
|
|
175
179
|
|
|
176
180
|
const navigateTimeoutRef = React.useRef<NodeJS.Timeout | null>(null)
|
|
177
181
|
|
|
182
|
+
const latestLoadPromiseRef = React.useRef<Promise<void>>(Promise.resolve())
|
|
183
|
+
|
|
184
|
+
const checkLatest = (promise: Promise<void>): undefined | Promise<void> => {
|
|
185
|
+
return latestLoadPromiseRef.current !== promise
|
|
186
|
+
? latestLoadPromiseRef.current
|
|
187
|
+
: undefined
|
|
188
|
+
}
|
|
189
|
+
|
|
178
190
|
const parseLocation = useStableCallback(
|
|
179
191
|
(
|
|
180
192
|
previousLocation?: ParsedLocation,
|
|
@@ -346,8 +358,6 @@ export function RouterProvider<
|
|
|
346
358
|
[routesByPath],
|
|
347
359
|
)
|
|
348
360
|
|
|
349
|
-
const latestLoadPromiseRef = React.useRef<Promise<void>>(Promise.resolve())
|
|
350
|
-
|
|
351
361
|
const matchRoutes = useStableCallback(
|
|
352
362
|
<TRouteTree extends AnyRoute>(
|
|
353
363
|
pathname: string,
|
|
@@ -786,12 +796,15 @@ export function RouterProvider<
|
|
|
786
796
|
|
|
787
797
|
const loadMatches = useStableCallback(
|
|
788
798
|
async ({
|
|
799
|
+
checkLatest,
|
|
789
800
|
matches,
|
|
790
801
|
preload,
|
|
791
802
|
}: {
|
|
803
|
+
checkLatest: () => Promise<void> | undefined
|
|
792
804
|
matches: AnyRouteMatch[]
|
|
793
805
|
preload?: boolean
|
|
794
|
-
}) => {
|
|
806
|
+
}): Promise<RouteMatch[]> => {
|
|
807
|
+
let latestPromise
|
|
795
808
|
let firstBadMatchIndex: number | undefined
|
|
796
809
|
|
|
797
810
|
// Check each match middleware to see if the route can be accessed
|
|
@@ -845,6 +858,7 @@ export function RouterProvider<
|
|
|
845
858
|
preload: !!preload,
|
|
846
859
|
meta: parentMeta,
|
|
847
860
|
location: state.location, // TODO: This might need to be latestLocationRef.current...?
|
|
861
|
+
navigate: (opts) => navigate({ ...opts, from: match.pathname }),
|
|
848
862
|
})) ?? ({} as any)
|
|
849
863
|
|
|
850
864
|
const meta = {
|
|
@@ -864,7 +878,7 @@ export function RouterProvider<
|
|
|
864
878
|
} catch (err) {
|
|
865
879
|
if (isRedirect(err)) {
|
|
866
880
|
if (!preload) navigate(err as any)
|
|
867
|
-
return
|
|
881
|
+
return matches
|
|
868
882
|
}
|
|
869
883
|
|
|
870
884
|
throw err
|
|
@@ -883,14 +897,6 @@ export function RouterProvider<
|
|
|
883
897
|
return getRouteMatch(state, match.id)?.loadPromise
|
|
884
898
|
}
|
|
885
899
|
|
|
886
|
-
const fetchedAt = Date.now()
|
|
887
|
-
const checkLatest = () => {
|
|
888
|
-
const latest = getRouteMatch(state, match.id)
|
|
889
|
-
return latest && latest.fetchedAt !== fetchedAt
|
|
890
|
-
? latest.loadPromise
|
|
891
|
-
: undefined
|
|
892
|
-
}
|
|
893
|
-
|
|
894
900
|
const handleIfRedirect = (err: any) => {
|
|
895
901
|
if (isRedirect(err)) {
|
|
896
902
|
if (!preload) {
|
|
@@ -902,8 +908,6 @@ export function RouterProvider<
|
|
|
902
908
|
}
|
|
903
909
|
|
|
904
910
|
const load = async () => {
|
|
905
|
-
let latestPromise
|
|
906
|
-
|
|
907
911
|
try {
|
|
908
912
|
const componentsPromise = Promise.all(
|
|
909
913
|
componentTypes.map(async (type) => {
|
|
@@ -922,6 +926,9 @@ export function RouterProvider<
|
|
|
922
926
|
parentMatchPromise,
|
|
923
927
|
abortController: match.abortController,
|
|
924
928
|
meta: match.meta,
|
|
929
|
+
location: state.location,
|
|
930
|
+
navigate: (opts) =>
|
|
931
|
+
navigate({ ...opts, from: match.pathname }),
|
|
925
932
|
})
|
|
926
933
|
|
|
927
934
|
await Promise.all([componentsPromise, loaderPromise])
|
|
@@ -953,6 +960,15 @@ export function RouterProvider<
|
|
|
953
960
|
updatedAt: Date.now(),
|
|
954
961
|
}
|
|
955
962
|
}
|
|
963
|
+
|
|
964
|
+
if (!preload) {
|
|
965
|
+
setState((s) => ({
|
|
966
|
+
...s,
|
|
967
|
+
matches: s.matches.map((d) =>
|
|
968
|
+
d.id === match.id ? match : d,
|
|
969
|
+
),
|
|
970
|
+
}))
|
|
971
|
+
}
|
|
956
972
|
}
|
|
957
973
|
|
|
958
974
|
let loadPromise: Promise<void> | undefined
|
|
@@ -960,7 +976,7 @@ export function RouterProvider<
|
|
|
960
976
|
matches[index] = match = {
|
|
961
977
|
...match,
|
|
962
978
|
isFetching: true,
|
|
963
|
-
fetchedAt,
|
|
979
|
+
fetchedAt: Date.now(),
|
|
964
980
|
invalid: false,
|
|
965
981
|
}
|
|
966
982
|
|
|
@@ -977,48 +993,38 @@ export function RouterProvider<
|
|
|
977
993
|
})
|
|
978
994
|
|
|
979
995
|
await Promise.all(matchPromises)
|
|
996
|
+
return matches
|
|
980
997
|
},
|
|
981
998
|
)
|
|
982
999
|
|
|
983
|
-
const load = useStableCallback<LoadFn>(async (
|
|
1000
|
+
const load = useStableCallback<LoadFn>(async () => {
|
|
984
1001
|
const promise = new Promise<void>(async (resolve, reject) => {
|
|
1002
|
+
const next = latestLocationRef.current
|
|
985
1003
|
const prevLocation = state.resolvedLocation
|
|
986
|
-
const pathDidChange = !!(
|
|
987
|
-
opts?.next && prevLocation!.href !== opts.next.href
|
|
988
|
-
)
|
|
989
|
-
|
|
1004
|
+
const pathDidChange = !!(next && prevLocation!.href !== next.href)
|
|
990
1005
|
let latestPromise: Promise<void> | undefined | null
|
|
991
1006
|
|
|
992
|
-
const checkLatest = (): undefined | Promise<void> | null => {
|
|
993
|
-
return latestLoadPromiseRef.current !== promise
|
|
994
|
-
? latestLoadPromiseRef.current
|
|
995
|
-
: undefined
|
|
996
|
-
}
|
|
997
|
-
|
|
998
1007
|
// Cancel any pending matches
|
|
999
1008
|
cancelMatches(state)
|
|
1000
1009
|
|
|
1001
1010
|
router.emit({
|
|
1002
1011
|
type: 'onBeforeLoad',
|
|
1003
1012
|
from: prevLocation,
|
|
1004
|
-
to:
|
|
1013
|
+
to: next ?? state.location,
|
|
1005
1014
|
pathChanged: pathDidChange,
|
|
1006
1015
|
})
|
|
1007
1016
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
}))
|
|
1014
|
-
}
|
|
1017
|
+
// Ingest the new location
|
|
1018
|
+
setState((s) => ({
|
|
1019
|
+
...s,
|
|
1020
|
+
location: next,
|
|
1021
|
+
}))
|
|
1015
1022
|
|
|
1016
1023
|
// Match the routes
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1024
|
+
let matches: RouteMatch<any, any>[] = matchRoutes(
|
|
1025
|
+
next.pathname,
|
|
1026
|
+
next.search,
|
|
1020
1027
|
{
|
|
1021
|
-
throwOnError: opts?.throwOnError,
|
|
1022
1028
|
debug: true,
|
|
1023
1029
|
},
|
|
1024
1030
|
)
|
|
@@ -1030,10 +1036,11 @@ export function RouterProvider<
|
|
|
1030
1036
|
}))
|
|
1031
1037
|
|
|
1032
1038
|
try {
|
|
1033
|
-
// Load the matches
|
|
1034
1039
|
try {
|
|
1040
|
+
// Load the matches
|
|
1035
1041
|
await loadMatches({
|
|
1036
1042
|
matches,
|
|
1043
|
+
checkLatest: () => checkLatest(promise),
|
|
1037
1044
|
})
|
|
1038
1045
|
} catch (err) {
|
|
1039
1046
|
// swallow this error, since we'll display the
|
|
@@ -1041,7 +1048,7 @@ export function RouterProvider<
|
|
|
1041
1048
|
}
|
|
1042
1049
|
|
|
1043
1050
|
// Only apply the latest transition
|
|
1044
|
-
if ((latestPromise = checkLatest())) {
|
|
1051
|
+
if ((latestPromise = checkLatest(promise))) {
|
|
1045
1052
|
return latestPromise
|
|
1046
1053
|
}
|
|
1047
1054
|
|
|
@@ -1078,14 +1085,14 @@ export function RouterProvider<
|
|
|
1078
1085
|
router.emit({
|
|
1079
1086
|
type: 'onLoad',
|
|
1080
1087
|
from: prevLocation,
|
|
1081
|
-
to:
|
|
1088
|
+
to: next,
|
|
1082
1089
|
pathChanged: pathDidChange,
|
|
1083
1090
|
})
|
|
1084
1091
|
|
|
1085
1092
|
resolve()
|
|
1086
1093
|
} catch (err) {
|
|
1087
1094
|
// Only apply the latest transition
|
|
1088
|
-
if ((latestPromise = checkLatest())) {
|
|
1095
|
+
if ((latestPromise = checkLatest(promise))) {
|
|
1089
1096
|
return latestPromise
|
|
1090
1097
|
}
|
|
1091
1098
|
|
|
@@ -1098,14 +1105,6 @@ export function RouterProvider<
|
|
|
1098
1105
|
return latestLoadPromiseRef.current
|
|
1099
1106
|
})
|
|
1100
1107
|
|
|
1101
|
-
const safeLoad = React.useCallback(async () => {
|
|
1102
|
-
try {
|
|
1103
|
-
return load()
|
|
1104
|
-
} catch (err) {
|
|
1105
|
-
// Don't do anything
|
|
1106
|
-
}
|
|
1107
|
-
}, [])
|
|
1108
|
-
|
|
1109
1108
|
const preloadRoute = useStableCallback(
|
|
1110
1109
|
async (navigateOpts: BuildNextOptions = state.location) => {
|
|
1111
1110
|
let next = buildLocation(navigateOpts)
|
|
@@ -1117,6 +1116,7 @@ export function RouterProvider<
|
|
|
1117
1116
|
await loadMatches({
|
|
1118
1117
|
matches,
|
|
1119
1118
|
preload: true,
|
|
1119
|
+
checkLatest: () => undefined,
|
|
1120
1120
|
})
|
|
1121
1121
|
|
|
1122
1122
|
return [last(matches)!, matches] as const
|
|
@@ -1259,10 +1259,13 @@ export function RouterProvider<
|
|
|
1259
1259
|
latestLocationRef.current = parseLocation(latestLocationRef.current)
|
|
1260
1260
|
|
|
1261
1261
|
React.startTransition(() => {
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1262
|
+
if (state.location !== latestLocationRef.current) {
|
|
1263
|
+
try {
|
|
1264
|
+
load()
|
|
1265
|
+
} catch (err) {
|
|
1266
|
+
console.error(err)
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1266
1269
|
})
|
|
1267
1270
|
})
|
|
1268
1271
|
|
|
@@ -1286,14 +1289,12 @@ export function RouterProvider<
|
|
|
1286
1289
|
|
|
1287
1290
|
if (initialLoad.current) {
|
|
1288
1291
|
initialLoad.current = false
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
if (state.resolvedLocation !== state.location) {
|
|
1294
|
-
safeLoad()
|
|
1292
|
+
try {
|
|
1293
|
+
load()
|
|
1294
|
+
} catch (err) {
|
|
1295
|
+
console.error(err)
|
|
1295
1296
|
}
|
|
1296
|
-
}
|
|
1297
|
+
}
|
|
1297
1298
|
|
|
1298
1299
|
const isFetching = React.useMemo(
|
|
1299
1300
|
() => [...state.matches, ...state.pendingMatches].some((d) => d.isFetching),
|
package/src/react.tsx
CHANGED
|
@@ -404,7 +404,8 @@ export type RouterProps<
|
|
|
404
404
|
export function useRouter<
|
|
405
405
|
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
|
|
406
406
|
>(): RouterContext<TRouteTree> {
|
|
407
|
-
const
|
|
407
|
+
const resolvedContext = window.__TSR_ROUTER_CONTEXT__ || routerContext
|
|
408
|
+
const value = React.useContext(resolvedContext)
|
|
408
409
|
warning(value, 'useRouter must be used inside a <RouterProvider> component!')
|
|
409
410
|
return value as any
|
|
410
411
|
}
|
|
@@ -597,6 +598,20 @@ export function useNavigate<
|
|
|
597
598
|
)
|
|
598
599
|
}
|
|
599
600
|
|
|
601
|
+
export function typedNavigate<
|
|
602
|
+
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
|
|
603
|
+
TDefaultFrom extends RoutePaths<TRouteTree> = '/',
|
|
604
|
+
>(navigate: (opts: NavigateOptions<any>) => Promise<void>) {
|
|
605
|
+
return navigate as <
|
|
606
|
+
TFrom extends RoutePaths<TRouteTree> = TDefaultFrom,
|
|
607
|
+
TTo extends string = '',
|
|
608
|
+
TMaskFrom extends RoutePaths<TRouteTree> = '/',
|
|
609
|
+
TMaskTo extends string = '',
|
|
610
|
+
>(
|
|
611
|
+
opts?: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,
|
|
612
|
+
) => Promise<void>
|
|
613
|
+
}
|
|
614
|
+
|
|
600
615
|
export function useMatchRoute<
|
|
601
616
|
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
|
|
602
617
|
>() {
|
package/src/route.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
UnionToIntersection,
|
|
12
12
|
Assign,
|
|
13
13
|
} from './utils'
|
|
14
|
-
import { ParsePathParams, ToSubOptions } from './link'
|
|
14
|
+
import { NavigateOptions, ParsePathParams, ToSubOptions } from './link'
|
|
15
15
|
import {
|
|
16
16
|
ErrorRouteComponent,
|
|
17
17
|
PendingRouteComponent,
|
|
@@ -154,6 +154,7 @@ type BeforeLoadFn<
|
|
|
154
154
|
params: TAllParams
|
|
155
155
|
meta: TParentRoute['types']['allMeta']
|
|
156
156
|
location: ParsedLocation
|
|
157
|
+
navigate: (opts: NavigateOptions<AnyRoute>) => Promise<void>
|
|
157
158
|
}) => Promise<TRouteMeta> | TRouteMeta | void
|
|
158
159
|
|
|
159
160
|
export type UpdatableRouteOptions<
|
|
@@ -265,6 +266,8 @@ export interface LoadFnContext<
|
|
|
265
266
|
params: TAllParams
|
|
266
267
|
search: TFullSearchSchema
|
|
267
268
|
meta: Expand<Assign<TAllContext, TRouteMeta>>
|
|
269
|
+
location: ParsedLocation<TFullSearchSchema>
|
|
270
|
+
navigate: (opts: NavigateOptions<AnyRoute>) => Promise<void>
|
|
268
271
|
}
|
|
269
272
|
|
|
270
273
|
export type SearchFilter<T, U = T> = (prev: T) => U
|
package/src/router.ts
CHANGED
|
@@ -21,12 +21,14 @@ import { RouteMatch } from './RouteMatch'
|
|
|
21
21
|
import { ParsedLocation } from './location'
|
|
22
22
|
import { LocationState } from './location'
|
|
23
23
|
import { SearchSerializer, SearchParser } from './searchParams'
|
|
24
|
+
import { RouterContext } from './RouterProvider'
|
|
24
25
|
|
|
25
26
|
//
|
|
26
27
|
|
|
27
28
|
declare global {
|
|
28
29
|
interface Window {
|
|
29
30
|
__TSR_DEHYDRATED__?: HydrationCtx
|
|
31
|
+
__TSR_ROUTER_CONTEXT__?: React.Context<RouterContext<any>>
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
|