@tanstack/router-core 0.0.1-beta.159 → 0.0.1-beta.160
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/route.js +0 -2
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +65 -48
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +65 -50
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +118 -118
- package/build/types/index.d.ts +13 -14
- package/build/umd/index.development.js +65 -50
- 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 +2 -2
- package/src/route.ts +18 -38
- package/src/router.ts +87 -71
package/build/types/index.d.ts
CHANGED
|
@@ -151,7 +151,7 @@ type HydrationCtx = {
|
|
|
151
151
|
router: DehydratedRouter;
|
|
152
152
|
payload: Record<string, any>;
|
|
153
153
|
};
|
|
154
|
-
interface RouteMatch<TRouteTree extends AnyRoute =
|
|
154
|
+
interface RouteMatch<TRouteTree extends AnyRoute = AnyRoute, TRoute extends AnyRoute = AnyRoute> {
|
|
155
155
|
id: string;
|
|
156
156
|
key?: string;
|
|
157
157
|
routeId: string;
|
|
@@ -210,7 +210,7 @@ interface RouterOptions<TRouteTree extends AnyRoute, TDehydrated extends Record<
|
|
|
210
210
|
dehydrate?: () => TDehydrated;
|
|
211
211
|
hydrate?: (dehydrated: TDehydrated) => void;
|
|
212
212
|
}
|
|
213
|
-
interface RouterState<TRouteTree extends AnyRoute =
|
|
213
|
+
interface RouterState<TRouteTree extends AnyRoute = AnyRoute> {
|
|
214
214
|
status: 'idle' | 'pending';
|
|
215
215
|
isFetching: boolean;
|
|
216
216
|
matchesById: Record<string, RouteMatch<TRouteTree, AnyRoute>>;
|
|
@@ -254,7 +254,7 @@ interface DehydratedRouter {
|
|
|
254
254
|
}
|
|
255
255
|
type RouterConstructorOptions<TRouteTree extends AnyRoute, TDehydrated extends Record<string, any>> = Omit<RouterOptions<TRouteTree, TDehydrated>, 'context'> & RouterContextOptions<TRouteTree>;
|
|
256
256
|
declare const componentTypes: readonly ["component", "errorComponent", "pendingComponent"];
|
|
257
|
-
declare class Router<TRouteTree extends AnyRoute =
|
|
257
|
+
declare class Router<TRouteTree extends AnyRoute = AnyRoute, TDehydrated extends Record<string, any> = Record<string, any>> {
|
|
258
258
|
#private;
|
|
259
259
|
types: {
|
|
260
260
|
RootRoute: TRouteTree;
|
|
@@ -375,7 +375,7 @@ type AnyRouteProps = RouteProps<any, any, any, any, any>;
|
|
|
375
375
|
type ComponentPropsFromRoute<TRoute> = TRoute extends Route<infer TParentRoute, infer TPath, infer TFullPath, infer TCustomId, infer TId, infer TLoader, infer TSearchSchema, infer TFullSearchSchema, infer TParams, infer TAllParams, infer TParentContext, infer TAllParentContext, infer TRouteContext, infer TContext, infer TRouterContext, infer TChildren, infer TRouteTree> ? RouteProps<TLoader, TFullSearchSchema, TAllParams, TRouteContext, TContext> : never;
|
|
376
376
|
type ComponentFromRoute<TRoute> = RegisteredRouteComponent<ComponentPropsFromRoute<TRoute>>;
|
|
377
377
|
type RouteLoaderFromRoute<TRoute extends AnyRoute> = LoaderFn<TRoute['__types']['loader'], TRoute['__types']['searchSchema'], TRoute['__types']['fullSearchSchema'], TRoute['__types']['allParams'], TRoute['__types']['routeContext'], TRoute['__types']['context']>;
|
|
378
|
-
type RouteProps<TLoader = unknown, TFullSearchSchema extends AnySearchSchema = AnySearchSchema, TAllParams extends AnyPathParams = AnyPathParams, TRouteContext extends AnyContext = AnyContext, TContext extends AnyContext = AnyContext> = {
|
|
378
|
+
type RouteProps<TLoader extends any = unknown, TFullSearchSchema extends AnySearchSchema = AnySearchSchema, TAllParams extends AnyPathParams = AnyPathParams, TRouteContext extends AnyContext = AnyContext, TContext extends AnyContext = AnyContext> = {
|
|
379
379
|
useMatch: () => RouteMatch<any, any>;
|
|
380
380
|
useLoader: () => UseLoaderResult<TLoader>;
|
|
381
381
|
useSearch: <TStrict extends boolean = true, TSearch = TFullSearchSchema, TSelected = TSearch>(opts?: {
|
|
@@ -394,12 +394,14 @@ type RouteProps<TLoader = unknown, TFullSearchSchema extends AnySearchSchema = A
|
|
|
394
394
|
};
|
|
395
395
|
type RouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TLoader = unknown, TParentSearchSchema extends AnySearchSchema = {}, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = TSearchSchema, TParams extends AnyPathParams = AnyPathParams, TAllParams extends AnyPathParams = TParams, TParentContext extends AnyContext = AnyContext, TAllParentContext extends AnyContext = AnyContext, TRouteContext extends RouteContext = RouteContext, TAllContext extends AnyContext = AnyContext> = BaseRouteOptions<TParentRoute, TCustomId, TPath, TLoader, TParentSearchSchema, TSearchSchema, TFullSearchSchema, TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TAllContext> & UpdatableRouteOptions<TLoader, TSearchSchema, TFullSearchSchema, TAllParams, TRouteContext, TAllContext>;
|
|
396
396
|
type ParamsFallback<TPath extends string, TParams> = unknown extends TParams ? Record<ParsePathParams<TPath>, string> : TParams;
|
|
397
|
-
type BaseRouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TLoader = unknown, TParentSearchSchema extends AnySearchSchema = {}, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = TSearchSchema, TParams =
|
|
397
|
+
type BaseRouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TLoader = unknown, TParentSearchSchema extends AnySearchSchema = {}, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = TSearchSchema, TParams extends AnyPathParams = {}, TAllParams = ParamsFallback<TPath, TParams>, TParentContext extends AnyContext = AnyContext, TAllParentContext extends AnyContext = AnyContext, TRouteContext extends RouteContext = RouteContext, TAllContext extends AnyContext = AnyContext> = RoutePathOptions<TCustomId, TPath> & {
|
|
398
398
|
layoutLimit?: string;
|
|
399
399
|
getParentRoute: () => TParentRoute;
|
|
400
|
-
validateSearch?: SearchSchemaValidator<TSearchSchema
|
|
400
|
+
validateSearch?: SearchSchemaValidator<TSearchSchema>;
|
|
401
401
|
loader?: LoaderFn<TLoader, TSearchSchema, TFullSearchSchema, TAllParams, NoInfer<TRouteContext>, TAllContext>;
|
|
402
|
-
} & ({
|
|
402
|
+
} & ([TLoader] extends [never] ? {
|
|
403
|
+
loader: 'Loaders must return a type other than never. If you are throwing a redirect() and not returning anything, return a redirect() instead.';
|
|
404
|
+
} : {}) & ({
|
|
403
405
|
parseParams?: (rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>) => TParams extends Record<ParsePathParams<TPath>, any> ? TParams : 'parseParams must return an object';
|
|
404
406
|
stringifyParams?: (params: NoInfer<ParamsFallback<TPath, TParams>>) => Record<ParsePathParams<TPath>, string>;
|
|
405
407
|
} | {
|
|
@@ -457,14 +459,11 @@ type ParseParamsFn<TPath extends string, TParams> = (rawParams: IsAny<TPath, any
|
|
|
457
459
|
type ParseParamsObj<TPath extends string, TParams> = {
|
|
458
460
|
parse?: ParseParamsFn<TPath, TParams>;
|
|
459
461
|
};
|
|
460
|
-
type SearchSchemaValidator<TReturn
|
|
461
|
-
type SearchSchemaValidatorObj<TReturn
|
|
462
|
-
parse?: SearchSchemaValidatorFn<TReturn
|
|
462
|
+
type SearchSchemaValidator<TReturn> = SearchSchemaValidatorObj<TReturn> | SearchSchemaValidatorFn<TReturn>;
|
|
463
|
+
type SearchSchemaValidatorObj<TReturn> = {
|
|
464
|
+
parse?: SearchSchemaValidatorFn<TReturn>;
|
|
463
465
|
};
|
|
464
|
-
type SearchSchemaValidatorFn<TReturn
|
|
465
|
-
error: 'Top level search params cannot be redefined by child routes!';
|
|
466
|
-
keys: keyof TReturn & keyof TParentSchema;
|
|
467
|
-
} : TReturn;
|
|
466
|
+
type SearchSchemaValidatorFn<TReturn> = (searchObj: Record<string, unknown>) => TReturn;
|
|
468
467
|
type DefinedPathParamWarning = 'Path params cannot be redefined by child routes!';
|
|
469
468
|
type ParentParams<TParentParams> = AnyPathParams extends TParentParams ? {} : {
|
|
470
469
|
[Key in keyof TParentParams]?: DefinedPathParamWarning;
|
|
@@ -578,8 +578,6 @@
|
|
|
578
578
|
|
|
579
579
|
const rootRouteId = '__root__';
|
|
580
580
|
|
|
581
|
-
// | ParseParamsObj<TPath, TParams>
|
|
582
|
-
|
|
583
581
|
// The parse type here allows a zod schema to be passed directly to the validator
|
|
584
582
|
|
|
585
583
|
class Route {
|
|
@@ -812,25 +810,27 @@
|
|
|
812
810
|
this.__store = new Store(getInitialRouterState(), {
|
|
813
811
|
onUpdate: () => {
|
|
814
812
|
const prev = this.state;
|
|
815
|
-
|
|
816
|
-
|
|
813
|
+
const next = this.__store.state;
|
|
814
|
+
console.log(Object.values(next.matchesById).find(d => d.status === 'error'));
|
|
815
|
+
const matchesByIdChanged = prev.matchesById !== next.matchesById;
|
|
817
816
|
let matchesChanged;
|
|
818
817
|
let pendingMatchesChanged;
|
|
819
818
|
if (!matchesByIdChanged) {
|
|
820
|
-
matchesChanged = prev.matchIds.length !==
|
|
821
|
-
pendingMatchesChanged = prev.pendingMatchIds.length !==
|
|
819
|
+
matchesChanged = prev.matchIds.length !== next.matchIds.length || prev.matchIds.some((d, i) => d !== next.matchIds[i]);
|
|
820
|
+
pendingMatchesChanged = prev.pendingMatchIds.length !== next.pendingMatchIds.length || prev.pendingMatchIds.some((d, i) => d !== next.pendingMatchIds[i]);
|
|
822
821
|
}
|
|
823
822
|
if (matchesByIdChanged || matchesChanged) {
|
|
824
|
-
|
|
825
|
-
return
|
|
823
|
+
next.matches = next.matchIds.map(id => {
|
|
824
|
+
return next.matchesById[id];
|
|
826
825
|
});
|
|
827
826
|
}
|
|
828
827
|
if (matchesByIdChanged || pendingMatchesChanged) {
|
|
829
|
-
|
|
830
|
-
return
|
|
828
|
+
next.pendingMatches = next.pendingMatchIds.map(id => {
|
|
829
|
+
return next.matchesById[id];
|
|
831
830
|
});
|
|
832
831
|
}
|
|
833
|
-
|
|
832
|
+
next.isFetching = [...next.matches, ...next.pendingMatches].some(d => d.isFetching);
|
|
833
|
+
this.state = next;
|
|
834
834
|
},
|
|
835
835
|
defaultPriority: 'low'
|
|
836
836
|
});
|
|
@@ -911,11 +911,12 @@
|
|
|
911
911
|
cancelMatch = id => {
|
|
912
912
|
this.getRouteMatch(id)?.abortController?.abort();
|
|
913
913
|
};
|
|
914
|
-
safeLoad = opts => {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
914
|
+
safeLoad = async opts => {
|
|
915
|
+
try {
|
|
916
|
+
return this.load(opts);
|
|
917
|
+
} catch (err) {
|
|
918
|
+
// Don't do anything
|
|
919
|
+
}
|
|
919
920
|
};
|
|
920
921
|
latestLoadPromise = Promise.resolve();
|
|
921
922
|
load = async opts => {
|
|
@@ -952,11 +953,16 @@
|
|
|
952
953
|
});
|
|
953
954
|
try {
|
|
954
955
|
// Load the matches
|
|
955
|
-
|
|
956
|
+
try {
|
|
957
|
+
await this.loadMatches(pendingMatches);
|
|
958
|
+
} catch (err) {
|
|
959
|
+
// swallow this error, since we'll display the
|
|
960
|
+
// errors on the route components
|
|
961
|
+
}
|
|
956
962
|
|
|
957
963
|
// Only apply the latest transition
|
|
958
964
|
if (latestPromise = checkLatest()) {
|
|
959
|
-
return
|
|
965
|
+
return latestPromise;
|
|
960
966
|
}
|
|
961
967
|
const prevLocation = this.state.resolvedLocation;
|
|
962
968
|
this.__store.setState(s => ({
|
|
@@ -973,7 +979,7 @@
|
|
|
973
979
|
} catch (err) {
|
|
974
980
|
// Only apply the latest transition
|
|
975
981
|
if (latestPromise = checkLatest()) {
|
|
976
|
-
return
|
|
982
|
+
return latestPromise;
|
|
977
983
|
}
|
|
978
984
|
reject(err);
|
|
979
985
|
}
|
|
@@ -1232,6 +1238,7 @@
|
|
|
1232
1238
|
throw errorHandlerErr;
|
|
1233
1239
|
}
|
|
1234
1240
|
}
|
|
1241
|
+
console.log('set error');
|
|
1235
1242
|
this.setRouteMatch(match.id, s => ({
|
|
1236
1243
|
...s,
|
|
1237
1244
|
error: err,
|
|
@@ -1284,19 +1291,8 @@
|
|
|
1284
1291
|
const latest = this.getRouteMatch(match.id);
|
|
1285
1292
|
return latest && latest.fetchedAt !== fetchedAt ? latest.loadPromise : undefined;
|
|
1286
1293
|
};
|
|
1287
|
-
const
|
|
1294
|
+
const load = async () => {
|
|
1288
1295
|
let latestPromise;
|
|
1289
|
-
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
1290
|
-
const component = route.options[type];
|
|
1291
|
-
if (component?.preload) {
|
|
1292
|
-
await component.preload();
|
|
1293
|
-
}
|
|
1294
|
-
}));
|
|
1295
|
-
const loaderPromise = route.options.loader?.({
|
|
1296
|
-
...match,
|
|
1297
|
-
preload: !!opts?.preload,
|
|
1298
|
-
parentMatchPromise
|
|
1299
|
-
});
|
|
1300
1296
|
const handleError = err => {
|
|
1301
1297
|
if (isRedirect(err)) {
|
|
1302
1298
|
if (!opts?.preload) {
|
|
@@ -1307,33 +1303,46 @@
|
|
|
1307
1303
|
return false;
|
|
1308
1304
|
};
|
|
1309
1305
|
try {
|
|
1306
|
+
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
1307
|
+
const component = route.options[type];
|
|
1308
|
+
if (component?.preload) {
|
|
1309
|
+
await component.preload();
|
|
1310
|
+
}
|
|
1311
|
+
}));
|
|
1312
|
+
const loaderPromise = route.options.loader?.({
|
|
1313
|
+
...match,
|
|
1314
|
+
preload: !!opts?.preload,
|
|
1315
|
+
parentMatchPromise
|
|
1316
|
+
});
|
|
1310
1317
|
const [_, loader] = await Promise.all([componentsPromise, loaderPromise]);
|
|
1311
1318
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1312
1319
|
this.setRouteMatchData(match.id, () => loader, opts);
|
|
1313
|
-
} catch (
|
|
1320
|
+
} catch (loaderError) {
|
|
1314
1321
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
}
|
|
1318
|
-
const errorHandler = route.options.onLoadError ?? route.options.onError;
|
|
1319
|
-
let caughtError = err;
|
|
1322
|
+
handleError(loaderError);
|
|
1323
|
+
let error = loaderError;
|
|
1320
1324
|
try {
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
return;
|
|
1325
|
+
if (route.options.onLoadError) {
|
|
1326
|
+
route.options.onLoadError?.(loaderError);
|
|
1327
|
+
} else {
|
|
1328
|
+
route.options.onError?.(loaderError);
|
|
1326
1329
|
}
|
|
1330
|
+
} catch (errorHandlerErr) {
|
|
1331
|
+
error = errorHandlerErr;
|
|
1332
|
+
handleError(error);
|
|
1327
1333
|
}
|
|
1334
|
+
console.log('set error');
|
|
1328
1335
|
this.setRouteMatch(match.id, s => ({
|
|
1329
1336
|
...s,
|
|
1330
|
-
error:
|
|
1337
|
+
error: error,
|
|
1331
1338
|
status: 'error',
|
|
1332
1339
|
isFetching: false,
|
|
1333
1340
|
updatedAt: Date.now()
|
|
1334
1341
|
}));
|
|
1342
|
+
console.log(this.getRouteMatch(match.id)?.status);
|
|
1335
1343
|
}
|
|
1336
|
-
}
|
|
1344
|
+
};
|
|
1345
|
+
const loadPromise = load();
|
|
1337
1346
|
this.setRouteMatch(match.id, s => ({
|
|
1338
1347
|
...s,
|
|
1339
1348
|
status: s.status !== 'success' ? 'pending' : s.status,
|
|
@@ -1757,13 +1766,18 @@
|
|
|
1757
1766
|
return this.state.matchesById[id];
|
|
1758
1767
|
};
|
|
1759
1768
|
setRouteMatch = (id, updater) => {
|
|
1760
|
-
this.__store.setState(prev =>
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
...prev.matchesById,
|
|
1764
|
-
[id]: updater(prev.matchesById[id])
|
|
1769
|
+
this.__store.setState(prev => {
|
|
1770
|
+
if (!prev.matchesById[id]) {
|
|
1771
|
+
console.warn(`No match found with id: ${id}`);
|
|
1765
1772
|
}
|
|
1766
|
-
|
|
1773
|
+
return {
|
|
1774
|
+
...prev,
|
|
1775
|
+
matchesById: {
|
|
1776
|
+
...prev.matchesById,
|
|
1777
|
+
[id]: updater(prev.matchesById[id])
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
});
|
|
1767
1781
|
};
|
|
1768
1782
|
setRouteMatchData = (id, updater, opts) => {
|
|
1769
1783
|
const match = this.getRouteMatch(id);
|
|
@@ -1772,6 +1786,7 @@
|
|
|
1772
1786
|
const updatedAt = opts?.updatedAt ?? Date.now();
|
|
1773
1787
|
const preloadInvalidAt = updatedAt + (opts?.maxAge ?? route.options.preloadMaxAge ?? this.options.defaultPreloadMaxAge ?? 5000);
|
|
1774
1788
|
const invalidAt = updatedAt + (opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? Infinity);
|
|
1789
|
+
console.log('set success');
|
|
1775
1790
|
this.setRouteMatch(id, s => ({
|
|
1776
1791
|
...s,
|
|
1777
1792
|
error: undefined,
|