@tanstack/router-core 0.0.1-beta.173 → 0.0.1-beta.175
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 +60 -36
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +59 -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 +60 -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 +122 -79
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type NoInfer<T> = [T][T extends any ? 0 : never];
|
|
2
|
+
export type IsAny<T, Y, N> = 1 extends 0 & T ? Y : N;
|
|
3
|
+
export type IsAnyBoolean<T> = 1 extends 0 & T ? true : false;
|
|
4
|
+
export type IsKnown<T, Y, N> = unknown extends T ? N : Y;
|
|
5
|
+
export type PickAsRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
6
|
+
export type PickAsPartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
7
|
+
export type PickUnsafe<T, K> = K extends keyof T ? Pick<T, K> : never;
|
|
8
|
+
export type PickExtra<T, K> = {
|
|
9
|
+
[TKey in keyof K as string extends TKey ? never : TKey extends keyof T ? never : TKey]: K[TKey];
|
|
10
|
+
};
|
|
11
|
+
export type PickRequired<T> = {
|
|
12
|
+
[K in keyof T as undefined extends T[K] ? never : K]: T[K];
|
|
13
|
+
};
|
|
14
|
+
export type Expand<T> = T extends object ? T extends infer O ? {
|
|
15
|
+
[K in keyof O]: O[K];
|
|
16
|
+
} : never : T;
|
|
17
|
+
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => any ? I : never;
|
|
18
|
+
type Compute<T> = {
|
|
19
|
+
[K in keyof T]: T[K];
|
|
20
|
+
} | never;
|
|
21
|
+
type AllKeys<T> = T extends any ? keyof T : never;
|
|
22
|
+
export type MergeUnion<T, Keys extends keyof T = keyof T> = Compute<{
|
|
23
|
+
[K in Keys]: T[Keys];
|
|
24
|
+
} & {
|
|
25
|
+
[K in AllKeys<T>]?: T extends any ? K extends keyof T ? T[K] : never : never;
|
|
26
|
+
}>;
|
|
27
|
+
export type Values<O> = O[ValueKeys<O>];
|
|
28
|
+
export type ValueKeys<O> = Extract<keyof O, PropertyKey>;
|
|
29
|
+
export type DeepAwaited<T> = T extends Promise<infer A> ? DeepAwaited<A> : T extends Record<infer A, Promise<infer B>> ? {
|
|
30
|
+
[K in A]: DeepAwaited<B>;
|
|
31
|
+
} : T;
|
|
32
|
+
export type PathParamMask<TRoutePath extends string> = TRoutePath extends `${infer L}/$${infer C}/${infer R}` ? PathParamMask<`${L}/${string}/${R}`> : TRoutePath extends `${infer L}/$${infer C}` ? PathParamMask<`${L}/${string}`> : TRoutePath;
|
|
33
|
+
export type Timeout = ReturnType<typeof setTimeout>;
|
|
34
|
+
export type Updater<TPrevious, TResult = TPrevious> = TResult | ((prev?: TPrevious) => TResult);
|
|
35
|
+
export type PickExtract<T, U> = {
|
|
36
|
+
[K in keyof T as T[K] extends U ? K : never]: T[K];
|
|
37
|
+
};
|
|
38
|
+
export type PickExclude<T, U> = {
|
|
39
|
+
[K in keyof T as T[K] extends U ? never : K]: T[K];
|
|
40
|
+
};
|
|
41
|
+
export declare function last<T>(arr: T[]): T | undefined;
|
|
42
|
+
export declare function functionalUpdate<TResult>(updater: Updater<TResult>, previous: TResult): TResult;
|
|
43
|
+
export declare function pick<T, K extends keyof T>(parent: T, keys: K[]): Pick<T, K>;
|
|
44
|
+
/**
|
|
45
|
+
* This function returns `a` if `b` is deeply equal.
|
|
46
|
+
* If not, it will replace any deeply equal children of `b` with those of `a`.
|
|
47
|
+
* This can be used for structural sharing between immutable JSON values for example.
|
|
48
|
+
* Do not use this with signals
|
|
49
|
+
*/
|
|
50
|
+
export declare function replaceEqualDeep<T>(prev: any, _next: T): T;
|
|
51
|
+
export declare function isPlainObject(o: any): boolean;
|
|
52
|
+
export declare function partialDeepEqual(a: any, b: any): boolean;
|
|
53
|
+
export {};
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
(function (global, factory) {
|
|
12
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports
|
|
13
|
-
typeof define === 'function' && define.amd ? define(['exports'
|
|
12
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
13
|
+
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
14
14
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.RouterCore = {}));
|
|
15
15
|
})(this, (function (exports) { 'use strict';
|
|
16
16
|
|
|
@@ -804,6 +804,8 @@
|
|
|
804
804
|
//
|
|
805
805
|
|
|
806
806
|
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
807
|
+
const visibilityChangeEvent = 'visibilitychange';
|
|
808
|
+
const focusEvent = 'focus';
|
|
807
809
|
class Router {
|
|
808
810
|
#unsubHistory;
|
|
809
811
|
resetNextScroll = false;
|
|
@@ -880,12 +882,26 @@
|
|
|
880
882
|
this.__store.setState(s => Object.assign(s, getInitialRouterState()));
|
|
881
883
|
};
|
|
882
884
|
mount = () => {
|
|
883
|
-
//
|
|
884
|
-
//
|
|
885
|
+
// addEventListener does not exist in React Native, but window does
|
|
886
|
+
// In the future, we might need to invert control here for more adapters
|
|
887
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
888
|
+
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
889
|
+
window.addEventListener(visibilityChangeEvent, this.#onFocus, false);
|
|
890
|
+
window.addEventListener(focusEvent, this.#onFocus, false);
|
|
891
|
+
}
|
|
885
892
|
this.safeLoad();
|
|
886
|
-
|
|
893
|
+
return () => {
|
|
894
|
+
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
895
|
+
window.removeEventListener(visibilityChangeEvent, this.#onFocus);
|
|
896
|
+
window.removeEventListener(focusEvent, this.#onFocus);
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
};
|
|
900
|
+
#onFocus = () => {
|
|
901
|
+
if (this.options.refetchOnWindowFocus ?? true) {
|
|
902
|
+
this.reload();
|
|
903
|
+
}
|
|
887
904
|
};
|
|
888
|
-
|
|
889
905
|
update = opts => {
|
|
890
906
|
this.options = {
|
|
891
907
|
...this.options,
|
|
@@ -956,7 +972,6 @@
|
|
|
956
972
|
};
|
|
957
973
|
|
|
958
974
|
// Cancel any pending matches
|
|
959
|
-
// this.cancelMatches()
|
|
960
975
|
|
|
961
976
|
let pendingMatches;
|
|
962
977
|
this.#emit({
|
|
@@ -999,6 +1014,9 @@
|
|
|
999
1014
|
if (latestPromise = checkLatest()) {
|
|
1000
1015
|
return latestPromise;
|
|
1001
1016
|
}
|
|
1017
|
+
const exitingMatchIds = this.state.matchIds.filter(id => !this.state.pendingMatchIds.includes(id));
|
|
1018
|
+
const enteringMatchIds = this.state.pendingMatchIds.filter(id => !this.state.matchIds.includes(id));
|
|
1019
|
+
const stayingMatchIds = this.state.matchIds.filter(id => this.state.pendingMatchIds.includes(id));
|
|
1002
1020
|
this.__store.setState(s => ({
|
|
1003
1021
|
...s,
|
|
1004
1022
|
status: 'idle',
|
|
@@ -1006,6 +1024,13 @@
|
|
|
1006
1024
|
matchIds: s.pendingMatchIds,
|
|
1007
1025
|
pendingMatchIds: []
|
|
1008
1026
|
}));
|
|
1027
|
+
[[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matchIds, hook]) => {
|
|
1028
|
+
matchIds.forEach(id => {
|
|
1029
|
+
const match = this.getRouteMatch(id);
|
|
1030
|
+
const route = this.getRoute(match.routeId);
|
|
1031
|
+
route.options[hook]?.(match);
|
|
1032
|
+
});
|
|
1033
|
+
});
|
|
1009
1034
|
this.#emit({
|
|
1010
1035
|
type: 'onLoad',
|
|
1011
1036
|
from: prevLocation,
|
|
@@ -1022,6 +1047,9 @@
|
|
|
1022
1047
|
}
|
|
1023
1048
|
});
|
|
1024
1049
|
this.latestLoadPromise = promise;
|
|
1050
|
+
this.latestLoadPromise.then(() => {
|
|
1051
|
+
this.cleanMatches();
|
|
1052
|
+
});
|
|
1025
1053
|
return this.latestLoadPromise;
|
|
1026
1054
|
};
|
|
1027
1055
|
#mergeMatches = (prevMatchesById, nextMatches) => {
|
|
@@ -1066,7 +1094,7 @@
|
|
|
1066
1094
|
const now = Date.now();
|
|
1067
1095
|
const outdatedMatchIds = Object.values(this.state.matchesById).filter(match => {
|
|
1068
1096
|
const route = this.getRoute(match.routeId);
|
|
1069
|
-
return !this.state.matchIds.includes(match.id) && !this.state.pendingMatchIds.includes(match.id) && match.
|
|
1097
|
+
return !this.state.matchIds.includes(match.id) && !this.state.pendingMatchIds.includes(match.id) && (match.preloadMaxAge > -1 ? match.updatedAt + match.preloadMaxAge < now : true) && (route.options.gcMaxAge ? match.updatedAt + route.options.gcMaxAge < now : true);
|
|
1070
1098
|
}).map(d => d.id);
|
|
1071
1099
|
if (outdatedMatchIds.length) {
|
|
1072
1100
|
this.__store.setState(s => {
|
|
@@ -1154,8 +1182,8 @@
|
|
|
1154
1182
|
params: routeParams,
|
|
1155
1183
|
pathname: joinPaths([this.basepath, interpolatedPath]),
|
|
1156
1184
|
updatedAt: Date.now(),
|
|
1157
|
-
|
|
1158
|
-
|
|
1185
|
+
maxAge: -1,
|
|
1186
|
+
preloadMaxAge: -1,
|
|
1159
1187
|
routeSearch: {},
|
|
1160
1188
|
search: {},
|
|
1161
1189
|
status: hasLoaders ? 'pending' : 'success',
|
|
@@ -1251,11 +1279,13 @@
|
|
|
1251
1279
|
paramsError: match.paramsError,
|
|
1252
1280
|
searchError: match.searchError,
|
|
1253
1281
|
params: match.params,
|
|
1254
|
-
|
|
1282
|
+
preloadMaxAge: 0
|
|
1255
1283
|
}));
|
|
1256
1284
|
});
|
|
1285
|
+
} else {
|
|
1286
|
+
// If we're preloading, clean preload matches before we try and use them
|
|
1287
|
+
this.cleanMatches();
|
|
1257
1288
|
}
|
|
1258
|
-
this.cleanMatches();
|
|
1259
1289
|
let firstBadMatchIndex;
|
|
1260
1290
|
|
|
1261
1291
|
// Check each match middleware to see if the route can be accessed
|
|
@@ -1317,8 +1347,7 @@
|
|
|
1317
1347
|
matchPromises.push((async () => {
|
|
1318
1348
|
const parentMatchPromise = matchPromises[index - 1];
|
|
1319
1349
|
const route = this.getRoute(match.routeId);
|
|
1320
|
-
if (match.isFetching || match.status === 'success' && !
|
|
1321
|
-
matchId: match.id,
|
|
1350
|
+
if (match.isFetching || match.status === 'success' && !isMatchInvalid(match, {
|
|
1322
1351
|
preload: opts?.preload
|
|
1323
1352
|
})) {
|
|
1324
1353
|
return this.getRouteMatch(match.id)?.loadPromise;
|
|
@@ -1391,7 +1420,6 @@
|
|
|
1391
1420
|
})());
|
|
1392
1421
|
});
|
|
1393
1422
|
await Promise.all(matchPromises);
|
|
1394
|
-
this.cleanMatches();
|
|
1395
1423
|
};
|
|
1396
1424
|
reload = () => {
|
|
1397
1425
|
return this.navigate({
|
|
@@ -1576,7 +1604,7 @@
|
|
|
1576
1604
|
dehydrate = () => {
|
|
1577
1605
|
return {
|
|
1578
1606
|
state: {
|
|
1579
|
-
dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', '
|
|
1607
|
+
dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', 'preloadMaxAge', 'maxAge', 'id', 'loaderData', 'status', 'updatedAt']))
|
|
1580
1608
|
}
|
|
1581
1609
|
};
|
|
1582
1610
|
};
|
|
@@ -1815,7 +1843,6 @@
|
|
|
1815
1843
|
...next.state
|
|
1816
1844
|
});
|
|
1817
1845
|
this.resetNextScroll = location.resetScroll ?? true;
|
|
1818
|
-
console.log('resetScroll', this.resetNextScroll);
|
|
1819
1846
|
return this.latestLoadPromise;
|
|
1820
1847
|
};
|
|
1821
1848
|
getRouteMatch = id => {
|
|
@@ -1840,17 +1867,17 @@
|
|
|
1840
1867
|
if (!match) return;
|
|
1841
1868
|
const route = this.getRoute(match.routeId);
|
|
1842
1869
|
const updatedAt = opts?.updatedAt ?? Date.now();
|
|
1843
|
-
const
|
|
1844
|
-
const
|
|
1870
|
+
const preloadMaxAge = opts?.maxAge ?? route.options.preloadMaxAge ?? this.options.defaultPreloadMaxAge ?? 5000;
|
|
1871
|
+
const maxAge = opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? -1;
|
|
1845
1872
|
this.setRouteMatch(id, s => ({
|
|
1846
1873
|
...s,
|
|
1847
1874
|
error: undefined,
|
|
1848
1875
|
status: 'success',
|
|
1849
1876
|
isFetching: false,
|
|
1850
|
-
updatedAt:
|
|
1877
|
+
updatedAt: updatedAt,
|
|
1851
1878
|
loaderData: functionalUpdate(updater, s.loaderData),
|
|
1852
|
-
|
|
1853
|
-
|
|
1879
|
+
preloadMaxAge,
|
|
1880
|
+
maxAge
|
|
1854
1881
|
}));
|
|
1855
1882
|
};
|
|
1856
1883
|
invalidate = async opts => {
|
|
@@ -1881,20 +1908,6 @@
|
|
|
1881
1908
|
return this.reload();
|
|
1882
1909
|
}
|
|
1883
1910
|
};
|
|
1884
|
-
getIsInvalid = opts => {
|
|
1885
|
-
if (!opts?.matchId) {
|
|
1886
|
-
return !!this.state.matches.find(d => this.getIsInvalid({
|
|
1887
|
-
matchId: d.id,
|
|
1888
|
-
preload: opts?.preload
|
|
1889
|
-
}));
|
|
1890
|
-
}
|
|
1891
|
-
const match = this.getRouteMatch(opts?.matchId);
|
|
1892
|
-
if (!match) {
|
|
1893
|
-
return false;
|
|
1894
|
-
}
|
|
1895
|
-
const now = Date.now();
|
|
1896
|
-
return match.invalid || (opts?.preload ? match.preloadInvalidAt : match.invalidAt) < now;
|
|
1897
|
-
};
|
|
1898
1911
|
}
|
|
1899
1912
|
|
|
1900
1913
|
// Detect if we're in the DOM
|
|
@@ -1940,6 +1953,16 @@
|
|
|
1940
1953
|
return imported[key || 'default'](...args);
|
|
1941
1954
|
};
|
|
1942
1955
|
}
|
|
1956
|
+
function isMatchInvalid(match, opts) {
|
|
1957
|
+
const now = Date.now();
|
|
1958
|
+
if (match.invalid) {
|
|
1959
|
+
return true;
|
|
1960
|
+
}
|
|
1961
|
+
if (opts?.preload) {
|
|
1962
|
+
return match.preloadMaxAge < 0 ? false : match.updatedAt + match.preloadMaxAge < now;
|
|
1963
|
+
}
|
|
1964
|
+
return match.maxAge < 0 ? false : match.updatedAt + match.maxAge < now;
|
|
1965
|
+
}
|
|
1943
1966
|
|
|
1944
1967
|
const windowKey = 'window';
|
|
1945
1968
|
const delimiter = '___';
|
|
@@ -2106,6 +2129,7 @@
|
|
|
2106
2129
|
exports.interpolatePath = interpolatePath;
|
|
2107
2130
|
exports.invariant = invariant;
|
|
2108
2131
|
exports.isDehydratedDeferred = isDehydratedDeferred;
|
|
2132
|
+
exports.isMatchInvalid = isMatchInvalid;
|
|
2109
2133
|
exports.isPlainObject = isPlainObject;
|
|
2110
2134
|
exports.isRedirect = isRedirect;
|
|
2111
2135
|
exports.joinPaths = joinPaths;
|