@tanstack/react-router 0.0.1-beta.228 → 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.
@@ -11,6 +11,7 @@ export interface RouteMatch<TRouteTree extends AnyRoute = AnyRoute, TRouteId ext
11
11
  params: RouteById<TRouteTree, TRouteId>['types']['allParams'];
12
12
  status: 'pending' | 'success' | 'error';
13
13
  isFetching: boolean;
14
+ showPending: boolean;
14
15
  invalid: boolean;
15
16
  error: unknown;
16
17
  paramsError: unknown;
@@ -19,8 +19,10 @@ export declare class FileRoute<TFilePath extends keyof FileRoutesByPath, TParent
19
19
  caseSensitive?: boolean | undefined;
20
20
  wrapInSuspense?: boolean | undefined;
21
21
  component?: import("./route").RouteComponent<TFullSearchSchema, TAllParams, TContext, TLoaderData> | undefined;
22
- errorComponent?: import("./route").ErrorRouteComponent<TFullSearchSchema, TAllParams, {}> | undefined;
22
+ errorComponent?: import("./route").ErrorRouteComponent<TFullSearchSchema, TAllParams, TContext> | undefined;
23
23
  pendingComponent?: import("./route").PendingRouteComponent<TFullSearchSchema, TAllParams, TContext> | undefined;
24
+ pendingMs?: number | undefined;
25
+ pendingMinMs?: number | undefined;
24
26
  preSearchFilters?: import("./route").SearchFilter<TFullSearchSchema, TFullSearchSchema>[] | undefined;
25
27
  postSearchFilters?: import("./route").SearchFilter<TFullSearchSchema, TFullSearchSchema>[] | undefined;
26
28
  onError?: ((err: any) => void) | undefined;
@@ -67,8 +67,10 @@ export type UpdatableRouteOptions<TFullSearchSchema extends Record<string, any>,
67
67
  caseSensitive?: boolean;
68
68
  wrapInSuspense?: boolean;
69
69
  component?: RouteComponent<TFullSearchSchema, TAllParams, TAllContext, TLoaderData>;
70
- errorComponent?: ErrorRouteComponent<TFullSearchSchema, TAllParams, {}>;
70
+ errorComponent?: ErrorRouteComponent<TFullSearchSchema, TAllParams, TAllContext>;
71
71
  pendingComponent?: PendingRouteComponent<TFullSearchSchema, TAllParams, TAllContext>;
72
+ pendingMs?: number;
73
+ pendingMinMs?: number;
72
74
  preSearchFilters?: SearchFilter<TFullSearchSchema>[];
73
75
  postSearchFilters?: SearchFilter<TFullSearchSchema>[];
74
76
  onError?: (err: any) => void;
@@ -40,16 +40,11 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TDehydrated extends
40
40
  defaultComponent?: RouteComponent<AnySearchSchema, AnyPathParams, AnyContext>;
41
41
  defaultErrorComponent?: ErrorRouteComponent<AnySearchSchema, AnyPathParams, AnyContext>;
42
42
  defaultPendingComponent?: PendingRouteComponent<AnySearchSchema, AnyPathParams, AnyContext>;
43
- defaultMaxAge?: number;
44
- defaultGcMaxAge?: number;
45
- defaultPreloadMaxAge?: number;
43
+ defaultPendingMs?: number;
44
+ defaultPendingMinMs?: number;
46
45
  caseSensitive?: boolean;
47
46
  routeTree?: TRouteTree;
48
47
  basepath?: string;
49
- createRoute?: (opts: {
50
- route: AnyRoute;
51
- router: AnyRouter;
52
- }) => void;
53
48
  context?: TRouteTree['types']['routerContext'];
54
49
  routeMasks?: RouteMask<TRouteTree>[];
55
50
  unmaskOnReload?: boolean;
@@ -978,8 +978,14 @@
978
978
  const route = routesById[routeId];
979
979
  const locationKey = useRouterState().location.state?.key;
980
980
  const PendingComponent = route.options.pendingComponent ?? options.defaultPendingComponent;
981
+ const pendingElement = PendingComponent ? /*#__PURE__*/React__namespace.createElement(PendingComponent, {
982
+ useMatch: route.useMatch,
983
+ useRouteContext: route.useRouteContext,
984
+ useSearch: route.useSearch,
985
+ useParams: route.useParams
986
+ }) : undefined;
981
987
  const routeErrorComponent = route.options.errorComponent ?? options.defaultErrorComponent ?? ErrorComponent;
982
- const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? PendingComponent ? React__namespace.Suspense : SafeFragment;
988
+ const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? pendingElement ? React__namespace.Suspense : SafeFragment;
983
989
  const errorComponent = routeErrorComponent ? React__namespace.useCallback(props => {
984
990
  return /*#__PURE__*/React__namespace.createElement(routeErrorComponent, {
985
991
  ...props,
@@ -993,12 +999,7 @@
993
999
  return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
994
1000
  value: matches
995
1001
  }, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
996
- fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, {
997
- useMatch: route.useMatch,
998
- useRouteContext: route.useRouteContext,
999
- useSearch: route.useSearch,
1000
- useParams: route.useParams
1001
- })
1002
+ fallback: pendingElement
1002
1003
  }, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
1003
1004
  resetKey: locationKey,
1004
1005
  errorComponent: errorComponent,
@@ -1006,11 +1007,13 @@
1006
1007
  warning(false, `Error in route match: ${match.id}`);
1007
1008
  }
1008
1009
  }, /*#__PURE__*/React__namespace.createElement(MatchInner, {
1009
- match: match
1010
+ match: match,
1011
+ pendingElement: pendingElement
1010
1012
  }))));
1011
1013
  }
1012
1014
  function MatchInner({
1013
- match
1015
+ match,
1016
+ pendingElement
1014
1017
  }) {
1015
1018
  const {
1016
1019
  options,
@@ -1021,6 +1024,9 @@
1021
1024
  throw match.error;
1022
1025
  }
1023
1026
  if (match.status === 'pending') {
1027
+ if (match.showPending) {
1028
+ return pendingElement || null;
1029
+ }
1024
1030
  throw match.loadPromise;
1025
1031
  }
1026
1032
  if (match.status === 'success') {
@@ -1563,6 +1569,8 @@
1563
1569
  constructor(options) {
1564
1570
  this.updateOptions({
1565
1571
  defaultPreloadDelay: 50,
1572
+ defaultPendingMs: 1000,
1573
+ defaultPendingMinMs: 500,
1566
1574
  context: undefined,
1567
1575
  ...options,
1568
1576
  stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
@@ -1839,6 +1847,7 @@
1839
1847
  search: {},
1840
1848
  searchError: undefined,
1841
1849
  status: hasLoaders ? 'pending' : 'success',
1850
+ showPending: false,
1842
1851
  isFetching: false,
1843
1852
  invalid: false,
1844
1853
  error: undefined,
@@ -2144,8 +2153,10 @@
2144
2153
  matches[index] = match = {
2145
2154
  ...match,
2146
2155
  fetchedAt: Date.now(),
2147
- invalid: false
2156
+ invalid: false,
2157
+ showPending: false
2148
2158
  };
2159
+ const pendingPromise = new Promise(r => setTimeout(r, 1000));
2149
2160
  if (match.isFetching) {
2150
2161
  loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
2151
2162
  } else {
@@ -2210,41 +2221,65 @@
2210
2221
  matches: s.matches.map(d => d.id === match.id ? match : d)
2211
2222
  }));
2212
2223
  }
2213
- try {
2214
- const loaderData = await loadPromise;
2215
- if (latestPromise = checkLatest()) return await latestPromise;
2216
- matches[index] = match = {
2217
- ...match,
2218
- error: undefined,
2219
- status: 'success',
2220
- isFetching: false,
2221
- updatedAt: Date.now(),
2222
- loaderData,
2223
- loadPromise: undefined
2224
- };
2225
- } catch (error) {
2226
- if (latestPromise = checkLatest()) return await latestPromise;
2227
- if (handleIfRedirect(error)) return;
2224
+ let didShowPending = false;
2225
+ await new Promise(async resolve => {
2226
+ // If the route has a pending component and a pendingMs option,
2227
+ // forcefully show the pending component
2228
+ if (!preload && (route.options.pendingComponent ?? this.options.defaultPendingComponent) && (route.options.pendingMs ?? this.options.defaultPendingMs)) {
2229
+ pendingPromise.then(() => {
2230
+ didShowPending = true;
2231
+ matches[index] = match = {
2232
+ ...match,
2233
+ showPending: true
2234
+ };
2235
+ this.setState(s => ({
2236
+ ...s,
2237
+ matches: s.matches.map(d => d.id === match.id ? match : d)
2238
+ }));
2239
+ resolve();
2240
+ });
2241
+ }
2228
2242
  try {
2229
- route.options.onError?.(error);
2230
- } catch (onErrorError) {
2231
- error = onErrorError;
2232
- if (handleIfRedirect(onErrorError)) return;
2243
+ const loaderData = await loadPromise;
2244
+ if (latestPromise = checkLatest()) return await latestPromise;
2245
+ const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
2246
+ if (didShowPending && pendingMinMs) {
2247
+ await new Promise(r => setTimeout(r, pendingMinMs));
2248
+ }
2249
+ matches[index] = match = {
2250
+ ...match,
2251
+ error: undefined,
2252
+ status: 'success',
2253
+ isFetching: false,
2254
+ updatedAt: Date.now(),
2255
+ loaderData,
2256
+ loadPromise: undefined
2257
+ };
2258
+ } catch (error) {
2259
+ if (latestPromise = checkLatest()) return await latestPromise;
2260
+ if (handleIfRedirect(error)) return;
2261
+ try {
2262
+ route.options.onError?.(error);
2263
+ } catch (onErrorError) {
2264
+ error = onErrorError;
2265
+ if (handleIfRedirect(onErrorError)) return;
2266
+ }
2267
+ matches[index] = match = {
2268
+ ...match,
2269
+ error,
2270
+ status: 'error',
2271
+ isFetching: false,
2272
+ updatedAt: Date.now()
2273
+ };
2233
2274
  }
2234
- matches[index] = match = {
2235
- ...match,
2236
- error,
2237
- status: 'error',
2238
- isFetching: false,
2239
- updatedAt: Date.now()
2240
- };
2241
- }
2242
- if (!preload) {
2243
- this.setState(s => ({
2244
- ...s,
2245
- matches: s.matches.map(d => d.id === match.id ? match : d)
2246
- }));
2247
- }
2275
+ if (!preload) {
2276
+ this.setState(s => ({
2277
+ ...s,
2278
+ matches: s.matches.map(d => d.id === match.id ? match : d)
2279
+ }));
2280
+ }
2281
+ resolve();
2282
+ });
2248
2283
  })());
2249
2284
  });
2250
2285
  await Promise.all(matchPromises);