@tanstack/react-router 0.0.1-beta.60 → 0.0.1-beta.62
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 +37 -29
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.js +37 -29
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +52 -52
- package/build/types/index.d.ts +16 -13
- package/build/umd/index.development.js +179 -163
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +3 -3
- package/build/umd/index.production.js.map +1 -1
- package/package.json +3 -3
- package/src/index.tsx +74 -54
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
const previous = this.state;
|
|
90
90
|
this.state = this.options?.updateFn ? this.options.updateFn(previous)(updater) : updater(previous);
|
|
91
91
|
if (this.state === previous) return;
|
|
92
|
+
this.options?.onUpdate?.(this.state, previous);
|
|
92
93
|
this.queue.push(() => {
|
|
93
94
|
this.listeners.forEach(listener => listener(this.state, previous));
|
|
94
|
-
this.options?.onUpdate?.(this.state, previous);
|
|
95
95
|
});
|
|
96
96
|
this.#flush();
|
|
97
97
|
};
|
|
@@ -577,7 +577,9 @@
|
|
|
577
577
|
this.options = options || {};
|
|
578
578
|
this.isRoot = !options?.getParentRoute;
|
|
579
579
|
}
|
|
580
|
-
init =
|
|
580
|
+
init = opts => {
|
|
581
|
+
this.originalIndex = opts.originalIndex;
|
|
582
|
+
this.router = opts.router;
|
|
581
583
|
const allOptions = this.options;
|
|
582
584
|
const isRoot = !allOptions?.path && !allOptions?.id;
|
|
583
585
|
const parent = this.options?.getParentRoute?.();
|
|
@@ -603,6 +605,7 @@
|
|
|
603
605
|
id = joinPaths(['/', id]);
|
|
604
606
|
}
|
|
605
607
|
const fullPath = id === rootRouteId ? '/' : trimPathRight(joinPaths([parent.fullPath, path]));
|
|
608
|
+
this.path = path;
|
|
606
609
|
this.id = id;
|
|
607
610
|
// this.customId = customId as TCustomId
|
|
608
611
|
this.fullPath = fullPath;
|
|
@@ -624,6 +627,9 @@
|
|
|
624
627
|
constructor(options) {
|
|
625
628
|
super(options);
|
|
626
629
|
}
|
|
630
|
+
static withRouterContext = () => {
|
|
631
|
+
return options => new RootRoute(options);
|
|
632
|
+
};
|
|
627
633
|
}
|
|
628
634
|
|
|
629
635
|
// const rootRoute = new RootRoute({
|
|
@@ -688,8 +694,13 @@
|
|
|
688
694
|
routeSearch: {},
|
|
689
695
|
search: {},
|
|
690
696
|
status: 'idle'
|
|
697
|
+
}, {
|
|
698
|
+
onUpdate: next => {
|
|
699
|
+
this.state = next;
|
|
700
|
+
}
|
|
691
701
|
})
|
|
692
702
|
});
|
|
703
|
+
this.state = this.store.state;
|
|
693
704
|
if (!this.#hasLoaders()) {
|
|
694
705
|
this.store.setState(s => ({
|
|
695
706
|
...s,
|
|
@@ -697,12 +708,66 @@
|
|
|
697
708
|
}));
|
|
698
709
|
}
|
|
699
710
|
}
|
|
711
|
+
#hasLoaders = () => {
|
|
712
|
+
return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload));
|
|
713
|
+
};
|
|
714
|
+
__init = opts => {
|
|
715
|
+
// Validate the search params and stabilize them
|
|
716
|
+
this.parentMatch = opts.parentMatch;
|
|
717
|
+
const parentSearch = this.parentMatch?.state.search ?? this.router.state.latestLocation.search;
|
|
718
|
+
try {
|
|
719
|
+
const validator = typeof this.route.options.validateSearch === 'object' ? this.route.options.validateSearch.parse : this.route.options.validateSearch;
|
|
720
|
+
let nextSearch = validator?.(parentSearch) ?? {};
|
|
721
|
+
this.store.setState(s => ({
|
|
722
|
+
...s,
|
|
723
|
+
routeSearch: nextSearch,
|
|
724
|
+
search: {
|
|
725
|
+
...parentSearch,
|
|
726
|
+
...nextSearch
|
|
727
|
+
}
|
|
728
|
+
}));
|
|
729
|
+
componentTypes.map(async type => {
|
|
730
|
+
const component = this.route.options[type];
|
|
731
|
+
if (typeof this[type] !== 'function') {
|
|
732
|
+
this[type] = component;
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
const parent = this.parentMatch;
|
|
736
|
+
this.routeContext = this.route.options.getContext?.({
|
|
737
|
+
parentContext: parent?.routeContext,
|
|
738
|
+
context: parent?.context,
|
|
739
|
+
params: this.params,
|
|
740
|
+
search: this.state.search
|
|
741
|
+
}) || {};
|
|
742
|
+
this.context = parent ? {
|
|
743
|
+
...parent.context,
|
|
744
|
+
...this.routeContext
|
|
745
|
+
} : {
|
|
746
|
+
...this.router?.options.context,
|
|
747
|
+
...this.routeContext
|
|
748
|
+
};
|
|
749
|
+
} catch (err) {
|
|
750
|
+
console.error(err);
|
|
751
|
+
const error = new Error('Invalid search params found', {
|
|
752
|
+
cause: err
|
|
753
|
+
});
|
|
754
|
+
error.code = 'INVALID_SEARCH_PARAMS';
|
|
755
|
+
this.store.setState(s => ({
|
|
756
|
+
...s,
|
|
757
|
+
status: 'error',
|
|
758
|
+
error: error
|
|
759
|
+
}));
|
|
760
|
+
|
|
761
|
+
// Do not proceed with loading the route
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
};
|
|
700
765
|
cancel = () => {
|
|
701
766
|
this.abortController?.abort();
|
|
702
767
|
};
|
|
703
768
|
load = async opts => {
|
|
704
769
|
// If the match is invalid, errored or idle, trigger it to load
|
|
705
|
-
if (this.
|
|
770
|
+
if (this.state.status !== 'pending') {
|
|
706
771
|
await this.fetch(opts);
|
|
707
772
|
}
|
|
708
773
|
};
|
|
@@ -719,7 +784,7 @@
|
|
|
719
784
|
// If the match was in an error state, set it
|
|
720
785
|
// to a loading state again. Otherwise, keep it
|
|
721
786
|
// as loading or resolved
|
|
722
|
-
if (this.
|
|
787
|
+
if (this.state.status === 'idle') {
|
|
723
788
|
this.store.setState(s => ({
|
|
724
789
|
...s,
|
|
725
790
|
status: 'pending'
|
|
@@ -741,9 +806,11 @@
|
|
|
741
806
|
if (this.route.options.onLoad) {
|
|
742
807
|
return this.route.options.onLoad({
|
|
743
808
|
params: this.params,
|
|
744
|
-
search: this.
|
|
809
|
+
search: this.state.search,
|
|
745
810
|
signal: this.abortController.signal,
|
|
746
|
-
preload: !!opts?.preload
|
|
811
|
+
preload: !!opts?.preload,
|
|
812
|
+
routeContext: this.routeContext,
|
|
813
|
+
context: this.context
|
|
747
814
|
});
|
|
748
815
|
}
|
|
749
816
|
return;
|
|
@@ -771,50 +838,6 @@
|
|
|
771
838
|
});
|
|
772
839
|
return this.__loadPromise;
|
|
773
840
|
};
|
|
774
|
-
#hasLoaders = () => {
|
|
775
|
-
return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload));
|
|
776
|
-
};
|
|
777
|
-
__setParentMatch = parentMatch => {
|
|
778
|
-
if (!this.parentMatch && parentMatch) {
|
|
779
|
-
this.parentMatch = parentMatch;
|
|
780
|
-
}
|
|
781
|
-
};
|
|
782
|
-
__validate = () => {
|
|
783
|
-
// Validate the search params and stabilize them
|
|
784
|
-
const parentSearch = this.parentMatch?.store.state.search ?? this.router.store.state.latestLocation.search;
|
|
785
|
-
try {
|
|
786
|
-
const validator = typeof this.route.options.validateSearch === 'object' ? this.route.options.validateSearch.parse : this.route.options.validateSearch;
|
|
787
|
-
let nextSearch = validator?.(parentSearch) ?? {};
|
|
788
|
-
this.store.setState(s => ({
|
|
789
|
-
...s,
|
|
790
|
-
routeSearch: nextSearch,
|
|
791
|
-
search: {
|
|
792
|
-
...parentSearch,
|
|
793
|
-
...nextSearch
|
|
794
|
-
}
|
|
795
|
-
}));
|
|
796
|
-
componentTypes.map(async type => {
|
|
797
|
-
const component = this.route.options[type];
|
|
798
|
-
if (typeof this[type] !== 'function') {
|
|
799
|
-
this[type] = component;
|
|
800
|
-
}
|
|
801
|
-
});
|
|
802
|
-
} catch (err) {
|
|
803
|
-
console.error(err);
|
|
804
|
-
const error = new Error('Invalid search params found', {
|
|
805
|
-
cause: err
|
|
806
|
-
});
|
|
807
|
-
error.code = 'INVALID_SEARCH_PARAMS';
|
|
808
|
-
this.store.setState(s => ({
|
|
809
|
-
...s,
|
|
810
|
-
status: 'error',
|
|
811
|
-
error: error
|
|
812
|
-
}));
|
|
813
|
-
|
|
814
|
-
// Do not proceed with loading the route
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
};
|
|
818
841
|
}
|
|
819
842
|
|
|
820
843
|
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
@@ -899,7 +922,12 @@
|
|
|
899
922
|
parseSearch: options?.parseSearch ?? defaultParseSearch,
|
|
900
923
|
fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn
|
|
901
924
|
};
|
|
902
|
-
this.store = new Store(getInitialRouterState()
|
|
925
|
+
this.store = new Store(getInitialRouterState(), {
|
|
926
|
+
onUpdate: state => {
|
|
927
|
+
this.state = state;
|
|
928
|
+
}
|
|
929
|
+
});
|
|
930
|
+
this.state = this.store.state;
|
|
903
931
|
this.basepath = '';
|
|
904
932
|
this.update(options);
|
|
905
933
|
|
|
@@ -913,7 +941,7 @@
|
|
|
913
941
|
// Mount only does anything on the client
|
|
914
942
|
if (!isServer) {
|
|
915
943
|
// If the router matches are empty, load the matches
|
|
916
|
-
if (!this.
|
|
944
|
+
if (!this.state.currentMatches.length) {
|
|
917
945
|
this.load();
|
|
918
946
|
}
|
|
919
947
|
const visibilityChangeEvent = 'visibilitychange';
|
|
@@ -952,7 +980,9 @@
|
|
|
952
980
|
currentLocation: parsedLocation
|
|
953
981
|
}));
|
|
954
982
|
this.#unsubHistory = this.history.listen(() => {
|
|
955
|
-
this.load(
|
|
983
|
+
this.load({
|
|
984
|
+
next: this.#parseLocation(this.state.latestLocation)
|
|
985
|
+
});
|
|
956
986
|
});
|
|
957
987
|
}
|
|
958
988
|
const {
|
|
@@ -978,11 +1008,11 @@
|
|
|
978
1008
|
});
|
|
979
1009
|
};
|
|
980
1010
|
cancelMatches = () => {
|
|
981
|
-
[...this.
|
|
1011
|
+
[...this.state.currentMatches, ...(this.state.pendingMatches || [])].forEach(match => {
|
|
982
1012
|
match.cancel();
|
|
983
1013
|
});
|
|
984
1014
|
};
|
|
985
|
-
load = async
|
|
1015
|
+
load = async opts => {
|
|
986
1016
|
let now = Date.now();
|
|
987
1017
|
const startedAt = now;
|
|
988
1018
|
this.startedLoadingAt = startedAt;
|
|
@@ -991,29 +1021,31 @@
|
|
|
991
1021
|
this.cancelMatches();
|
|
992
1022
|
let matches;
|
|
993
1023
|
this.store.batch(() => {
|
|
994
|
-
if (next) {
|
|
1024
|
+
if (opts?.next) {
|
|
995
1025
|
// Ingest the new location
|
|
996
1026
|
this.store.setState(s => ({
|
|
997
1027
|
...s,
|
|
998
|
-
latestLocation: next
|
|
1028
|
+
latestLocation: opts.next
|
|
999
1029
|
}));
|
|
1000
1030
|
}
|
|
1001
1031
|
|
|
1002
1032
|
// Match the routes
|
|
1003
|
-
matches = this.matchRoutes(this.
|
|
1033
|
+
matches = this.matchRoutes(this.state.latestLocation.pathname, {
|
|
1004
1034
|
strictParseParams: true
|
|
1005
1035
|
});
|
|
1006
1036
|
this.store.setState(s => ({
|
|
1007
1037
|
...s,
|
|
1008
1038
|
status: 'pending',
|
|
1009
1039
|
pendingMatches: matches,
|
|
1010
|
-
pendingLocation: this.
|
|
1040
|
+
pendingLocation: this.state.latestLocation
|
|
1011
1041
|
}));
|
|
1012
1042
|
});
|
|
1013
1043
|
|
|
1014
1044
|
// Load the matches
|
|
1015
1045
|
try {
|
|
1016
|
-
await this.loadMatches(matches
|
|
1046
|
+
await this.loadMatches(matches
|
|
1047
|
+
// opts
|
|
1048
|
+
);
|
|
1017
1049
|
} catch (err) {
|
|
1018
1050
|
console.warn(err);
|
|
1019
1051
|
invariant(false, 'Matches failed to load due to error above ☝️. Navigation cancelled!');
|
|
@@ -1022,7 +1054,7 @@
|
|
|
1022
1054
|
// Ignore side-effects of outdated side-effects
|
|
1023
1055
|
return this.navigationPromise;
|
|
1024
1056
|
}
|
|
1025
|
-
const previousMatches = this.
|
|
1057
|
+
const previousMatches = this.state.currentMatches;
|
|
1026
1058
|
const exiting = [],
|
|
1027
1059
|
staying = [];
|
|
1028
1060
|
previousMatches.forEach(d => {
|
|
@@ -1039,11 +1071,11 @@
|
|
|
1039
1071
|
exiting.forEach(d => {
|
|
1040
1072
|
d.__onExit?.({
|
|
1041
1073
|
params: d.params,
|
|
1042
|
-
search: d.
|
|
1074
|
+
search: d.state.routeSearch
|
|
1043
1075
|
});
|
|
1044
1076
|
|
|
1045
1077
|
// Clear non-loading error states when match leaves
|
|
1046
|
-
if (d.
|
|
1078
|
+
if (d.state.status === 'error') {
|
|
1047
1079
|
this.store.setState(s => ({
|
|
1048
1080
|
...s,
|
|
1049
1081
|
status: 'idle',
|
|
@@ -1054,21 +1086,19 @@
|
|
|
1054
1086
|
staying.forEach(d => {
|
|
1055
1087
|
d.route.options.onTransition?.({
|
|
1056
1088
|
params: d.params,
|
|
1057
|
-
search: d.
|
|
1089
|
+
search: d.state.routeSearch
|
|
1058
1090
|
});
|
|
1059
1091
|
});
|
|
1060
1092
|
entering.forEach(d => {
|
|
1061
1093
|
d.__onExit = d.route.options.onLoaded?.({
|
|
1062
1094
|
params: d.params,
|
|
1063
|
-
search: d.
|
|
1095
|
+
search: d.state.search
|
|
1064
1096
|
});
|
|
1065
|
-
// delete this.store.state.matchCache[d.id] // TODO:
|
|
1066
1097
|
});
|
|
1067
|
-
|
|
1068
1098
|
this.store.setState(s => ({
|
|
1069
1099
|
...s,
|
|
1070
1100
|
status: 'idle',
|
|
1071
|
-
currentLocation: this.
|
|
1101
|
+
currentLocation: this.state.latestLocation,
|
|
1072
1102
|
currentMatches: matches,
|
|
1073
1103
|
pendingLocation: undefined,
|
|
1074
1104
|
pendingMatches: undefined
|
|
@@ -1081,7 +1111,7 @@
|
|
|
1081
1111
|
invariant(route, `Route with id "${id}" not found`);
|
|
1082
1112
|
return route;
|
|
1083
1113
|
};
|
|
1084
|
-
loadRoute = async (navigateOpts = this.
|
|
1114
|
+
loadRoute = async (navigateOpts = this.state.latestLocation) => {
|
|
1085
1115
|
const next = this.buildNext(navigateOpts);
|
|
1086
1116
|
const matches = this.matchRoutes(next.pathname, {
|
|
1087
1117
|
strictParseParams: true
|
|
@@ -1089,7 +1119,7 @@
|
|
|
1089
1119
|
await this.loadMatches(matches);
|
|
1090
1120
|
return matches;
|
|
1091
1121
|
};
|
|
1092
|
-
preloadRoute = async (navigateOpts = this.
|
|
1122
|
+
preloadRoute = async (navigateOpts = this.state.latestLocation) => {
|
|
1093
1123
|
const next = this.buildNext(navigateOpts);
|
|
1094
1124
|
const matches = this.matchRoutes(next.pathname, {
|
|
1095
1125
|
strictParseParams: true
|
|
@@ -1104,7 +1134,7 @@
|
|
|
1104
1134
|
if (!this.routeTree) {
|
|
1105
1135
|
return matches;
|
|
1106
1136
|
}
|
|
1107
|
-
const existingMatches = [...this.
|
|
1137
|
+
const existingMatches = [...this.state.currentMatches, ...(this.state.pendingMatches ?? [])];
|
|
1108
1138
|
const findInRouteTree = async routes => {
|
|
1109
1139
|
const parentMatch = last(matches);
|
|
1110
1140
|
let params = parentMatch?.params ?? {};
|
|
@@ -1116,7 +1146,7 @@
|
|
|
1116
1146
|
if (!route.path && children?.length) {
|
|
1117
1147
|
return findMatchInRoutes([...matchingRoutes, route], children);
|
|
1118
1148
|
}
|
|
1119
|
-
const fuzzy = route.path
|
|
1149
|
+
const fuzzy = !!(route.path !== '/' || children?.length);
|
|
1120
1150
|
const matchParams = matchPathname(this.basepath, pathname, {
|
|
1121
1151
|
to: route.fullPath,
|
|
1122
1152
|
fuzzy,
|
|
@@ -1150,9 +1180,7 @@
|
|
|
1150
1180
|
matchingRoutes.forEach(foundRoute => {
|
|
1151
1181
|
const interpolatedPath = interpolatePath(foundRoute.path, params);
|
|
1152
1182
|
const matchId = interpolatePath(foundRoute.id, params, true);
|
|
1153
|
-
const match = existingMatches.find(d => d.id === matchId) ||
|
|
1154
|
-
// this.store.state.matchCache[matchId]?.match || // TODO:
|
|
1155
|
-
new RouteMatch(this, foundRoute, {
|
|
1183
|
+
const match = existingMatches.find(d => d.id === matchId) || new RouteMatch(this, foundRoute, {
|
|
1156
1184
|
id: matchId,
|
|
1157
1185
|
params,
|
|
1158
1186
|
pathname: joinPaths([this.basepath, interpolatedPath])
|
|
@@ -1166,15 +1194,10 @@
|
|
|
1166
1194
|
}
|
|
1167
1195
|
};
|
|
1168
1196
|
findInRouteTree([this.routeTree]);
|
|
1169
|
-
linkMatches(matches);
|
|
1170
1197
|
return matches;
|
|
1171
1198
|
};
|
|
1172
|
-
loadMatches = async (resolvedMatches,
|
|
1173
|
-
|
|
1174
|
-
resolvedMatches.forEach(async match => {
|
|
1175
|
-
// Validate the match (loads search params etc)
|
|
1176
|
-
match.__validate();
|
|
1177
|
-
});
|
|
1199
|
+
loadMatches = async (resolvedMatches, opts) => {
|
|
1200
|
+
initMatches(resolvedMatches);
|
|
1178
1201
|
|
|
1179
1202
|
// Check each match middleware to see if the route can be accessed
|
|
1180
1203
|
await Promise.all(resolvedMatches.map(async match => {
|
|
@@ -1184,7 +1207,7 @@
|
|
|
1184
1207
|
match
|
|
1185
1208
|
});
|
|
1186
1209
|
} catch (err) {
|
|
1187
|
-
if (!
|
|
1210
|
+
if (!opts?.preload) {
|
|
1188
1211
|
match.route.options.onLoadError?.(err);
|
|
1189
1212
|
}
|
|
1190
1213
|
throw err;
|
|
@@ -1192,14 +1215,16 @@
|
|
|
1192
1215
|
}));
|
|
1193
1216
|
const matchPromises = resolvedMatches.map(async (match, index) => {
|
|
1194
1217
|
const prevMatch = resolvedMatches[1];
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1218
|
+
match.state.search;
|
|
1219
|
+
|
|
1220
|
+
// if (opts?.filter && !opts.filter(match)) {
|
|
1221
|
+
// return
|
|
1222
|
+
// }
|
|
1223
|
+
|
|
1199
1224
|
match.load({
|
|
1200
|
-
preload:
|
|
1225
|
+
preload: opts?.preload
|
|
1201
1226
|
});
|
|
1202
|
-
if (match.
|
|
1227
|
+
if (match.state.status !== 'success' && match.__loadPromise) {
|
|
1203
1228
|
// Wait for the first sign of activity from the match
|
|
1204
1229
|
await match.__loadPromise;
|
|
1205
1230
|
}
|
|
@@ -1256,15 +1281,15 @@
|
|
|
1256
1281
|
};
|
|
1257
1282
|
const next = this.buildNext(location);
|
|
1258
1283
|
if (opts?.pending) {
|
|
1259
|
-
if (!this.
|
|
1284
|
+
if (!this.state.pendingLocation) {
|
|
1260
1285
|
return false;
|
|
1261
1286
|
}
|
|
1262
|
-
return matchPathname(this.basepath, this.
|
|
1287
|
+
return matchPathname(this.basepath, this.state.pendingLocation.pathname, {
|
|
1263
1288
|
...opts,
|
|
1264
1289
|
to: next.pathname
|
|
1265
1290
|
});
|
|
1266
1291
|
}
|
|
1267
|
-
return matchPathname(this.basepath, this.
|
|
1292
|
+
return matchPathname(this.basepath, this.state.currentLocation.pathname, {
|
|
1268
1293
|
...opts,
|
|
1269
1294
|
to: next.pathname
|
|
1270
1295
|
});
|
|
@@ -1310,11 +1335,11 @@
|
|
|
1310
1335
|
const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
|
|
1311
1336
|
|
|
1312
1337
|
// Compare path/hash for matches
|
|
1313
|
-
const pathIsEqual = this.
|
|
1314
|
-
const currentPathSplit = this.
|
|
1338
|
+
const pathIsEqual = this.state.currentLocation.pathname === next.pathname;
|
|
1339
|
+
const currentPathSplit = this.state.currentLocation.pathname.split('/');
|
|
1315
1340
|
const nextPathSplit = next.pathname.split('/');
|
|
1316
1341
|
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
1317
|
-
const hashIsEqual = this.
|
|
1342
|
+
const hashIsEqual = this.state.currentLocation.hash === next.hash;
|
|
1318
1343
|
// Combine the matches based on user options
|
|
1319
1344
|
const pathTest = activeOptions?.exact ? pathIsEqual : pathIsFuzzyEqual;
|
|
1320
1345
|
const hashTest = activeOptions?.includeHash ? hashIsEqual : true;
|
|
@@ -1377,21 +1402,18 @@
|
|
|
1377
1402
|
dehydrate = () => {
|
|
1378
1403
|
return {
|
|
1379
1404
|
state: {
|
|
1380
|
-
...pick(this.
|
|
1381
|
-
currentMatches: this.
|
|
1405
|
+
...pick(this.state, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
|
|
1406
|
+
currentMatches: this.state.currentMatches.map(match => ({
|
|
1382
1407
|
id: match.id,
|
|
1383
1408
|
state: {
|
|
1384
|
-
|
|
1409
|
+
status: match.state.status
|
|
1385
1410
|
}
|
|
1386
1411
|
}))
|
|
1387
|
-
}
|
|
1388
|
-
context: this.options.context
|
|
1412
|
+
}
|
|
1389
1413
|
};
|
|
1390
1414
|
};
|
|
1391
1415
|
hydrate = dehydratedRouter => {
|
|
1392
1416
|
this.store.setState(s => {
|
|
1393
|
-
this.options.context = dehydratedRouter.context;
|
|
1394
|
-
|
|
1395
1417
|
// Match the routes
|
|
1396
1418
|
const currentMatches = this.matchRoutes(dehydratedRouter.state.latestLocation.pathname, {
|
|
1397
1419
|
strictParseParams: true
|
|
@@ -1404,7 +1426,7 @@
|
|
|
1404
1426
|
...dehydratedMatch.state
|
|
1405
1427
|
}));
|
|
1406
1428
|
});
|
|
1407
|
-
currentMatches
|
|
1429
|
+
initMatches(currentMatches);
|
|
1408
1430
|
return {
|
|
1409
1431
|
...s,
|
|
1410
1432
|
...dehydratedRouter.state,
|
|
@@ -1415,9 +1437,10 @@
|
|
|
1415
1437
|
#buildRouteTree = routeTree => {
|
|
1416
1438
|
const recurseRoutes = routes => {
|
|
1417
1439
|
routes.forEach((route, i) => {
|
|
1418
|
-
route.init(
|
|
1419
|
-
|
|
1420
|
-
|
|
1440
|
+
route.init({
|
|
1441
|
+
originalIndex: i,
|
|
1442
|
+
router: this
|
|
1443
|
+
});
|
|
1421
1444
|
const existingRoute = this.routesById[route.id];
|
|
1422
1445
|
if (existingRoute) {
|
|
1423
1446
|
{
|
|
@@ -1455,9 +1478,9 @@
|
|
|
1455
1478
|
this.load();
|
|
1456
1479
|
};
|
|
1457
1480
|
#buildLocation = (dest = {}) => {
|
|
1458
|
-
const fromPathname = dest.fromCurrent ? this.
|
|
1481
|
+
const fromPathname = dest.fromCurrent ? this.state.latestLocation.pathname : dest.from ?? this.state.latestLocation.pathname;
|
|
1459
1482
|
let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
|
|
1460
|
-
const fromMatches = this.matchRoutes(this.
|
|
1483
|
+
const fromMatches = this.matchRoutes(this.state.latestLocation.pathname, {
|
|
1461
1484
|
strictParseParams: true
|
|
1462
1485
|
});
|
|
1463
1486
|
const toMatches = this.matchRoutes(pathname);
|
|
@@ -1473,7 +1496,7 @@
|
|
|
1473
1496
|
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
1474
1497
|
|
|
1475
1498
|
// Pre filters first
|
|
1476
|
-
const preFilteredSearch = dest.__preSearchFilters?.length ? dest.__preSearchFilters?.reduce((prev, next) => next(prev), this.
|
|
1499
|
+
const preFilteredSearch = dest.__preSearchFilters?.length ? dest.__preSearchFilters?.reduce((prev, next) => next(prev), this.state.latestLocation.search) : this.state.latestLocation.search;
|
|
1477
1500
|
|
|
1478
1501
|
// Then the link/navigate function
|
|
1479
1502
|
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
@@ -1483,15 +1506,15 @@
|
|
|
1483
1506
|
|
|
1484
1507
|
// Then post filters
|
|
1485
1508
|
const postFilteredSearch = dest.__postSearchFilters?.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
1486
|
-
const search = replaceEqualDeep(this.
|
|
1509
|
+
const search = replaceEqualDeep(this.state.latestLocation.search, postFilteredSearch);
|
|
1487
1510
|
const searchStr = this.options.stringifySearch(search);
|
|
1488
|
-
let hash = dest.hash === true ? this.
|
|
1511
|
+
let hash = dest.hash === true ? this.state.latestLocation.hash : functionalUpdate(dest.hash, this.state.latestLocation.hash);
|
|
1489
1512
|
hash = hash ? `#${hash}` : '';
|
|
1490
1513
|
return {
|
|
1491
1514
|
pathname,
|
|
1492
1515
|
search,
|
|
1493
1516
|
searchStr,
|
|
1494
|
-
state: this.
|
|
1517
|
+
state: this.state.latestLocation.state,
|
|
1495
1518
|
hash,
|
|
1496
1519
|
href: `${pathname}${searchStr}${hash}`,
|
|
1497
1520
|
key: dest.key
|
|
@@ -1505,7 +1528,7 @@
|
|
|
1505
1528
|
if (!location.replace) {
|
|
1506
1529
|
nextAction = 'push';
|
|
1507
1530
|
}
|
|
1508
|
-
const isSameUrl = this.
|
|
1531
|
+
const isSameUrl = this.state.latestLocation.href === next.href;
|
|
1509
1532
|
if (isSameUrl && !next.key) {
|
|
1510
1533
|
nextAction = 'replace';
|
|
1511
1534
|
}
|
|
@@ -1515,7 +1538,7 @@
|
|
|
1515
1538
|
...next.state
|
|
1516
1539
|
});
|
|
1517
1540
|
|
|
1518
|
-
// this.load(this.#parseLocation(this.
|
|
1541
|
+
// this.load(this.#parseLocation(this.state.latestLocation))
|
|
1519
1542
|
|
|
1520
1543
|
return this.navigationPromise = new Promise(resolve => {
|
|
1521
1544
|
const previousNavigationResolve = this.resolveNavigation;
|
|
@@ -1536,32 +1559,17 @@
|
|
|
1536
1559
|
currentLocation: null,
|
|
1537
1560
|
currentMatches: [],
|
|
1538
1561
|
lastUpdated: Date.now()
|
|
1539
|
-
// matchCache: {}, // TODO:
|
|
1540
|
-
// get isFetching() {
|
|
1541
|
-
// return (
|
|
1542
|
-
// this.status === 'loading' ||
|
|
1543
|
-
// this.currentMatches.some((d) => d.store.state.isFetching)
|
|
1544
|
-
// )
|
|
1545
|
-
// },
|
|
1546
|
-
// get isPreloading() {
|
|
1547
|
-
// return Object.values(this.matchCache).some(
|
|
1548
|
-
// (d) =>
|
|
1549
|
-
// d.match.store.state.isFetching &&
|
|
1550
|
-
// !this.currentMatches.find((dd) => dd.id === d.match.id),
|
|
1551
|
-
// )
|
|
1552
|
-
// },
|
|
1553
1562
|
};
|
|
1554
1563
|
}
|
|
1555
|
-
|
|
1556
1564
|
function isCtrlEvent(e) {
|
|
1557
1565
|
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
1558
1566
|
}
|
|
1559
|
-
function
|
|
1567
|
+
function initMatches(matches) {
|
|
1560
1568
|
matches.forEach((match, index) => {
|
|
1561
|
-
const
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
}
|
|
1569
|
+
const parentMatch = matches[index - 1];
|
|
1570
|
+
match.__init({
|
|
1571
|
+
parentMatch
|
|
1572
|
+
});
|
|
1565
1573
|
});
|
|
1566
1574
|
}
|
|
1567
1575
|
|
|
@@ -1637,7 +1645,7 @@
|
|
|
1637
1645
|
//
|
|
1638
1646
|
|
|
1639
1647
|
function useLinkProps(options) {
|
|
1640
|
-
const router =
|
|
1648
|
+
const router = useRouterContext();
|
|
1641
1649
|
const {
|
|
1642
1650
|
// custom props
|
|
1643
1651
|
type,
|
|
@@ -1762,7 +1770,7 @@
|
|
|
1762
1770
|
...rest
|
|
1763
1771
|
}) {
|
|
1764
1772
|
router.update(rest);
|
|
1765
|
-
const currentMatches = useStore(router.store, s => s.currentMatches
|
|
1773
|
+
const currentMatches = useStore(router.store, s => s.currentMatches);
|
|
1766
1774
|
React__namespace.useEffect(router.mount, [router]);
|
|
1767
1775
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
|
|
1768
1776
|
value: {
|
|
@@ -1772,22 +1780,24 @@
|
|
|
1772
1780
|
value: [undefined, ...currentMatches]
|
|
1773
1781
|
}, /*#__PURE__*/React__namespace.createElement(Outlet, null))));
|
|
1774
1782
|
}
|
|
1775
|
-
function
|
|
1783
|
+
function useRouterContext() {
|
|
1776
1784
|
const value = React__namespace.useContext(routerContext);
|
|
1777
1785
|
warning(!value, 'useRouter must be used inside a <Router> component!');
|
|
1786
|
+
useStore(value.router.store);
|
|
1778
1787
|
return value.router;
|
|
1779
1788
|
}
|
|
1780
|
-
function
|
|
1781
|
-
const router =
|
|
1782
|
-
|
|
1789
|
+
function useRouter(track, shallow) {
|
|
1790
|
+
const router = useRouterContext();
|
|
1791
|
+
useStore(router.store, track, shallow);
|
|
1792
|
+
return router;
|
|
1783
1793
|
}
|
|
1784
1794
|
function useMatches() {
|
|
1785
1795
|
return React__namespace.useContext(matchesContext);
|
|
1786
1796
|
}
|
|
1787
1797
|
function useMatch(opts) {
|
|
1788
|
-
const router =
|
|
1798
|
+
const router = useRouterContext();
|
|
1789
1799
|
const nearestMatch = useMatches()[0];
|
|
1790
|
-
const match = opts?.from ? router.
|
|
1800
|
+
const match = opts?.from ? router.state.currentMatches.find(d => d.route.id === opts?.from) : nearestMatch;
|
|
1791
1801
|
invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
|
|
1792
1802
|
if (opts?.strict ?? true) {
|
|
1793
1803
|
invariant(nearestMatch.route.id == match?.route.id, `useMatch("${match?.route.id}") is being called in a component that is meant to render the '${nearestMatch.route.id}' route. Did you mean to 'useMatch("${match?.route.id}", { strict: false })' or 'useRoute("${match?.route.id}")' instead?`);
|
|
@@ -1796,26 +1806,26 @@
|
|
|
1796
1806
|
return match;
|
|
1797
1807
|
}
|
|
1798
1808
|
function useRoute(routeId) {
|
|
1799
|
-
const router =
|
|
1809
|
+
const router = useRouterContext();
|
|
1800
1810
|
const resolvedRoute = router.getRoute(routeId);
|
|
1801
1811
|
invariant(resolvedRoute, `Could not find a route for route "${routeId}"! Did you forget to add it to your route config?`);
|
|
1802
1812
|
return resolvedRoute;
|
|
1803
1813
|
}
|
|
1804
1814
|
function useSearch(opts) {
|
|
1805
1815
|
const match = useMatch(opts);
|
|
1806
|
-
useStore(match.store, d => opts?.track?.(d.search) ?? d.search);
|
|
1807
|
-
return match.
|
|
1816
|
+
useStore(match.store, d => opts?.track?.(d.search) ?? d.search, true);
|
|
1817
|
+
return match.state.search;
|
|
1808
1818
|
}
|
|
1809
1819
|
function useParams(opts) {
|
|
1810
|
-
const router =
|
|
1820
|
+
const router = useRouterContext();
|
|
1811
1821
|
useStore(router.store, d => {
|
|
1812
1822
|
const params = last(d.currentMatches)?.params;
|
|
1813
1823
|
return opts?.track?.(params) ?? params;
|
|
1814
|
-
});
|
|
1815
|
-
return last(router.
|
|
1824
|
+
}, true);
|
|
1825
|
+
return last(router.state.currentMatches)?.params;
|
|
1816
1826
|
}
|
|
1817
1827
|
function useNavigate(defaultOpts) {
|
|
1818
|
-
const router =
|
|
1828
|
+
const router = useRouterContext();
|
|
1819
1829
|
return opts => {
|
|
1820
1830
|
return router.navigate({
|
|
1821
1831
|
...defaultOpts,
|
|
@@ -1824,7 +1834,7 @@
|
|
|
1824
1834
|
};
|
|
1825
1835
|
}
|
|
1826
1836
|
function useMatchRoute() {
|
|
1827
|
-
const router =
|
|
1837
|
+
const router = useRouterContext();
|
|
1828
1838
|
return opts => {
|
|
1829
1839
|
const {
|
|
1830
1840
|
pending,
|
|
@@ -1863,17 +1873,17 @@
|
|
|
1863
1873
|
matches,
|
|
1864
1874
|
match
|
|
1865
1875
|
}) {
|
|
1866
|
-
const router =
|
|
1867
|
-
useStore(match.store);
|
|
1876
|
+
const router = useRouterContext();
|
|
1877
|
+
useStore(match.store, store => [store.status, store.error], true);
|
|
1868
1878
|
const defaultPending = React__namespace.useCallback(() => null, []);
|
|
1869
1879
|
const Inner = React__namespace.useCallback(props => {
|
|
1870
|
-
if (props.match.
|
|
1871
|
-
throw props.match.
|
|
1880
|
+
if (props.match.state.status === 'error') {
|
|
1881
|
+
throw props.match.state.error;
|
|
1872
1882
|
}
|
|
1873
|
-
if (props.match.
|
|
1883
|
+
if (props.match.state.status === 'success') {
|
|
1874
1884
|
return /*#__PURE__*/React__namespace.createElement(props.match.component ?? router.options.defaultComponent ?? Outlet);
|
|
1875
1885
|
}
|
|
1876
|
-
if (props.match.
|
|
1886
|
+
if (props.match.state.status === 'pending') {
|
|
1877
1887
|
throw props.match.__loadPromise;
|
|
1878
1888
|
}
|
|
1879
1889
|
invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
|
|
@@ -1882,7 +1892,7 @@
|
|
|
1882
1892
|
const errorComponent = match.errorComponent ?? router.options.defaultErrorComponent;
|
|
1883
1893
|
return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
|
|
1884
1894
|
value: matches
|
|
1885
|
-
}, /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
|
|
1895
|
+
}, match.route.options.wrapInSuspense ?? true ? /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
|
|
1886
1896
|
fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, null)
|
|
1887
1897
|
}, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
1888
1898
|
key: match.route.id,
|
|
@@ -1890,7 +1900,13 @@
|
|
|
1890
1900
|
match: match
|
|
1891
1901
|
}, /*#__PURE__*/React__namespace.createElement(Inner, {
|
|
1892
1902
|
match: match
|
|
1893
|
-
})))
|
|
1903
|
+
}))) : /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
1904
|
+
key: match.route.id,
|
|
1905
|
+
errorComponent: errorComponent,
|
|
1906
|
+
match: match
|
|
1907
|
+
}, /*#__PURE__*/React__namespace.createElement(Inner, {
|
|
1908
|
+
match: match
|
|
1909
|
+
})));
|
|
1894
1910
|
}
|
|
1895
1911
|
|
|
1896
1912
|
// This is the messiest thing ever... I'm either seriously tired (likely) or
|
|
@@ -1919,17 +1935,17 @@
|
|
|
1919
1935
|
}
|
|
1920
1936
|
function CatchBoundaryInner(props) {
|
|
1921
1937
|
const [activeErrorState, setActiveErrorState] = React__namespace.useState(props.errorState);
|
|
1922
|
-
const router =
|
|
1938
|
+
const router = useRouterContext();
|
|
1923
1939
|
const errorComponent = props.errorComponent ?? DefaultErrorBoundary;
|
|
1924
1940
|
const prevKeyRef = React__namespace.useRef('');
|
|
1925
1941
|
React__namespace.useEffect(() => {
|
|
1926
1942
|
if (activeErrorState) {
|
|
1927
|
-
if (router.
|
|
1943
|
+
if (router.state.currentLocation.key !== prevKeyRef.current) {
|
|
1928
1944
|
setActiveErrorState({});
|
|
1929
1945
|
}
|
|
1930
1946
|
}
|
|
1931
|
-
prevKeyRef.current = router.
|
|
1932
|
-
}, [activeErrorState, router.
|
|
1947
|
+
prevKeyRef.current = router.state.currentLocation.key;
|
|
1948
|
+
}, [activeErrorState, router.state.currentLocation.key]);
|
|
1933
1949
|
React__namespace.useEffect(() => {
|
|
1934
1950
|
if (props.errorState.error) {
|
|
1935
1951
|
setActiveErrorState(props.errorState);
|
|
@@ -2043,7 +2059,7 @@
|
|
|
2043
2059
|
exports.useParams = useParams;
|
|
2044
2060
|
exports.useRoute = useRoute;
|
|
2045
2061
|
exports.useRouter = useRouter;
|
|
2046
|
-
exports.
|
|
2062
|
+
exports.useRouterContext = useRouterContext;
|
|
2047
2063
|
exports.useSearch = useSearch;
|
|
2048
2064
|
exports.useStore = useStore;
|
|
2049
2065
|
exports.warning = warning;
|