@tanstack/react-router 0.0.1-beta.227 → 0.0.1-beta.229
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/Matches.js +15 -13
- package/build/cjs/Matches.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +63 -34
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +78 -46
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +283 -289
- package/build/types/Matches.d.ts +1 -0
- package/build/types/fileRoute.d.ts +3 -1
- package/build/types/route.d.ts +3 -1
- package/build/types/router.d.ts +2 -7
- package/build/umd/index.development.js +78 -46
- 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/Matches.tsx +23 -15
- package/src/route.ts +3 -3
- package/src/router.ts +78 -36
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.229",
|
|
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.229"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "rollup --config rollup.config.js"
|
package/src/Matches.tsx
CHANGED
|
@@ -26,6 +26,7 @@ export interface RouteMatch<
|
|
|
26
26
|
params: RouteById<TRouteTree, TRouteId>['types']['allParams']
|
|
27
27
|
status: 'pending' | 'success' | 'error'
|
|
28
28
|
isFetching: boolean
|
|
29
|
+
showPending: boolean
|
|
29
30
|
invalid: boolean
|
|
30
31
|
error: unknown
|
|
31
32
|
paramsError: unknown
|
|
@@ -98,13 +99,22 @@ export function Match({ matches }: { matches: RouteMatch[] }) {
|
|
|
98
99
|
const PendingComponent = (route.options.pendingComponent ??
|
|
99
100
|
options.defaultPendingComponent) as any
|
|
100
101
|
|
|
102
|
+
const pendingElement = PendingComponent
|
|
103
|
+
? React.createElement(PendingComponent, {
|
|
104
|
+
useMatch: route.useMatch,
|
|
105
|
+
useRouteContext: route.useRouteContext,
|
|
106
|
+
useSearch: route.useSearch,
|
|
107
|
+
useParams: route.useParams,
|
|
108
|
+
})
|
|
109
|
+
: undefined
|
|
110
|
+
|
|
101
111
|
const routeErrorComponent =
|
|
102
112
|
route.options.errorComponent ??
|
|
103
113
|
options.defaultErrorComponent ??
|
|
104
114
|
ErrorComponent
|
|
105
115
|
|
|
106
116
|
const ResolvedSuspenseBoundary =
|
|
107
|
-
route.options.wrapInSuspense ??
|
|
117
|
+
route.options.wrapInSuspense ?? pendingElement
|
|
108
118
|
? React.Suspense
|
|
109
119
|
: SafeFragment
|
|
110
120
|
|
|
@@ -127,14 +137,7 @@ export function Match({ matches }: { matches: RouteMatch[] }) {
|
|
|
127
137
|
|
|
128
138
|
return (
|
|
129
139
|
<matchesContext.Provider value={matches}>
|
|
130
|
-
<ResolvedSuspenseBoundary
|
|
131
|
-
fallback={React.createElement(PendingComponent, {
|
|
132
|
-
useMatch: route.useMatch,
|
|
133
|
-
useRouteContext: route.useRouteContext,
|
|
134
|
-
useSearch: route.useSearch,
|
|
135
|
-
useParams: route.useParams,
|
|
136
|
-
})}
|
|
137
|
-
>
|
|
140
|
+
<ResolvedSuspenseBoundary fallback={pendingElement}>
|
|
138
141
|
<ResolvedCatchBoundary
|
|
139
142
|
resetKey={locationKey}
|
|
140
143
|
errorComponent={errorComponent}
|
|
@@ -142,25 +145,30 @@ export function Match({ matches }: { matches: RouteMatch[] }) {
|
|
|
142
145
|
warning(false, `Error in route match: ${match.id}`)
|
|
143
146
|
}}
|
|
144
147
|
>
|
|
145
|
-
<MatchInner match={match} />
|
|
148
|
+
<MatchInner match={match} pendingElement={pendingElement} />
|
|
146
149
|
</ResolvedCatchBoundary>
|
|
147
150
|
</ResolvedSuspenseBoundary>
|
|
148
151
|
</matchesContext.Provider>
|
|
149
152
|
)
|
|
150
153
|
}
|
|
151
|
-
function MatchInner({
|
|
154
|
+
function MatchInner({
|
|
155
|
+
match,
|
|
156
|
+
pendingElement,
|
|
157
|
+
}: {
|
|
158
|
+
match: RouteMatch
|
|
159
|
+
pendingElement: any
|
|
160
|
+
}): any {
|
|
152
161
|
const { options, routesById } = useRouter()
|
|
153
162
|
const route = routesById[match.routeId]!
|
|
154
163
|
|
|
155
|
-
if (match.id.split('/').length === 4) {
|
|
156
|
-
console.log(match.id, pick(match, ['status', 'cause', 'isFetching']))
|
|
157
|
-
}
|
|
158
|
-
|
|
159
164
|
if (match.status === 'error') {
|
|
160
165
|
throw match.error
|
|
161
166
|
}
|
|
162
167
|
|
|
163
168
|
if (match.status === 'pending') {
|
|
169
|
+
if (match.showPending) {
|
|
170
|
+
return pendingElement || null
|
|
171
|
+
}
|
|
164
172
|
throw match.loadPromise
|
|
165
173
|
}
|
|
166
174
|
|
package/src/route.ts
CHANGED
|
@@ -202,9 +202,7 @@ export type UpdatableRouteOptions<
|
|
|
202
202
|
errorComponent?: ErrorRouteComponent<
|
|
203
203
|
TFullSearchSchema,
|
|
204
204
|
TAllParams,
|
|
205
|
-
|
|
206
|
-
// TAllContext // TODO: I have no idea why this breaks the universe,
|
|
207
|
-
// so we'll come back to it later.
|
|
205
|
+
TAllContext // NOTE: This used to break the universe.... but it seems to work now?
|
|
208
206
|
> //
|
|
209
207
|
// If supported by your framework, the content to be rendered as the fallback content until the route is ready to render
|
|
210
208
|
pendingComponent?: PendingRouteComponent<
|
|
@@ -212,6 +210,8 @@ export type UpdatableRouteOptions<
|
|
|
212
210
|
TAllParams,
|
|
213
211
|
TAllContext
|
|
214
212
|
>
|
|
213
|
+
pendingMs?: number
|
|
214
|
+
pendingMinMs?: number
|
|
215
215
|
// Filter functions that can manipulate search params *before* they are passed to links and navigate
|
|
216
216
|
// calls that match this route.
|
|
217
217
|
preSearchFilters?: SearchFilter<TFullSearchSchema>[]
|
package/src/router.ts
CHANGED
|
@@ -119,13 +119,11 @@ export interface RouterOptions<
|
|
|
119
119
|
AnyPathParams,
|
|
120
120
|
AnyContext
|
|
121
121
|
>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
defaultPreloadMaxAge?: number
|
|
122
|
+
defaultPendingMs?: number
|
|
123
|
+
defaultPendingMinMs?: number
|
|
125
124
|
caseSensitive?: boolean
|
|
126
125
|
routeTree?: TRouteTree
|
|
127
126
|
basepath?: string
|
|
128
|
-
createRoute?: (opts: { route: AnyRoute; router: AnyRouter }) => void
|
|
129
127
|
context?: TRouteTree['types']['routerContext']
|
|
130
128
|
// dehydrate?: () => TDehydrated
|
|
131
129
|
// hydrate?: (dehydrated: TDehydrated) => void
|
|
@@ -253,6 +251,8 @@ export class Router<
|
|
|
253
251
|
constructor(options: RouterConstructorOptions<TRouteTree, TDehydrated>) {
|
|
254
252
|
this.updateOptions({
|
|
255
253
|
defaultPreloadDelay: 50,
|
|
254
|
+
defaultPendingMs: 1000,
|
|
255
|
+
defaultPendingMinMs: 500,
|
|
256
256
|
context: undefined!,
|
|
257
257
|
...options,
|
|
258
258
|
stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
|
|
@@ -631,6 +631,7 @@ export class Router<
|
|
|
631
631
|
search: {} as any,
|
|
632
632
|
searchError: undefined,
|
|
633
633
|
status: hasLoaders ? 'pending' : 'success',
|
|
634
|
+
showPending: false,
|
|
634
635
|
isFetching: false,
|
|
635
636
|
invalid: false,
|
|
636
637
|
error: undefined,
|
|
@@ -1061,8 +1062,11 @@ export class Router<
|
|
|
1061
1062
|
...match,
|
|
1062
1063
|
fetchedAt: Date.now(),
|
|
1063
1064
|
invalid: false,
|
|
1065
|
+
showPending: false,
|
|
1064
1066
|
}
|
|
1065
1067
|
|
|
1068
|
+
const pendingPromise = new Promise((r) => setTimeout(r, 1000))
|
|
1069
|
+
|
|
1066
1070
|
if (match.isFetching) {
|
|
1067
1071
|
loadPromise = getRouteMatch(this.state, match.id)?.loadPromise
|
|
1068
1072
|
} else {
|
|
@@ -1146,45 +1150,83 @@ export class Router<
|
|
|
1146
1150
|
}))
|
|
1147
1151
|
}
|
|
1148
1152
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1153
|
+
let didShowPending = false
|
|
1154
|
+
|
|
1155
|
+
await new Promise<void>(async (resolve) => {
|
|
1156
|
+
// If the route has a pending component and a pendingMs option,
|
|
1157
|
+
// forcefully show the pending component
|
|
1158
|
+
if (
|
|
1159
|
+
!preload &&
|
|
1160
|
+
(route.options.pendingComponent ??
|
|
1161
|
+
this.options.defaultPendingComponent) &&
|
|
1162
|
+
(route.options.pendingMs ?? this.options.defaultPendingMs)
|
|
1163
|
+
) {
|
|
1164
|
+
pendingPromise.then(() => {
|
|
1165
|
+
didShowPending = true
|
|
1166
|
+
matches[index] = match = {
|
|
1167
|
+
...match,
|
|
1168
|
+
showPending: true,
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
this.setState((s) => ({
|
|
1172
|
+
...s,
|
|
1173
|
+
matches: s.matches.map((d) =>
|
|
1174
|
+
d.id === match.id ? match : d,
|
|
1175
|
+
),
|
|
1176
|
+
}))
|
|
1177
|
+
resolve()
|
|
1178
|
+
})
|
|
1161
1179
|
}
|
|
1162
|
-
} catch (error) {
|
|
1163
|
-
if ((latestPromise = checkLatest())) return await latestPromise
|
|
1164
|
-
if (handleIfRedirect(error)) return
|
|
1165
1180
|
|
|
1166
1181
|
try {
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1182
|
+
const loaderData = await loadPromise
|
|
1183
|
+
if ((latestPromise = checkLatest())) return await latestPromise
|
|
1184
|
+
|
|
1185
|
+
const pendingMinMs =
|
|
1186
|
+
route.options.pendingMinMs ?? this.options.defaultPendingMinMs
|
|
1187
|
+
|
|
1188
|
+
if (didShowPending && pendingMinMs) {
|
|
1189
|
+
await new Promise((r) => setTimeout(r, pendingMinMs))
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
matches[index] = match = {
|
|
1193
|
+
...match,
|
|
1194
|
+
error: undefined,
|
|
1195
|
+
status: 'success',
|
|
1196
|
+
isFetching: false,
|
|
1197
|
+
updatedAt: Date.now(),
|
|
1198
|
+
loaderData,
|
|
1199
|
+
loadPromise: undefined,
|
|
1200
|
+
}
|
|
1201
|
+
} catch (error) {
|
|
1202
|
+
if ((latestPromise = checkLatest())) return await latestPromise
|
|
1203
|
+
if (handleIfRedirect(error)) return
|
|
1204
|
+
|
|
1205
|
+
try {
|
|
1206
|
+
route.options.onError?.(error)
|
|
1207
|
+
} catch (onErrorError) {
|
|
1208
|
+
error = onErrorError
|
|
1209
|
+
if (handleIfRedirect(onErrorError)) return
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
matches[index] = match = {
|
|
1213
|
+
...match,
|
|
1214
|
+
error,
|
|
1215
|
+
status: 'error',
|
|
1216
|
+
isFetching: false,
|
|
1217
|
+
updatedAt: Date.now(),
|
|
1218
|
+
}
|
|
1171
1219
|
}
|
|
1172
1220
|
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
updatedAt: Date.now(),
|
|
1221
|
+
if (!preload) {
|
|
1222
|
+
this.setState((s) => ({
|
|
1223
|
+
...s,
|
|
1224
|
+
matches: s.matches.map((d) => (d.id === match.id ? match : d)),
|
|
1225
|
+
}))
|
|
1179
1226
|
}
|
|
1180
|
-
}
|
|
1181
1227
|
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
...s,
|
|
1185
|
-
matches: s.matches.map((d) => (d.id === match.id ? match : d)),
|
|
1186
|
-
}))
|
|
1187
|
-
}
|
|
1228
|
+
resolve()
|
|
1229
|
+
})
|
|
1188
1230
|
})(),
|
|
1189
1231
|
)
|
|
1190
1232
|
})
|