@tanstack/react-router 0.0.1-beta.223 → 0.0.1-beta.224
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/RouterProvider.js +56 -958
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/fileRoute.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +953 -39
- package/build/cjs/router.js.map +1 -1
- package/build/cjs/scroll-restoration.js +5 -9
- package/build/cjs/scroll-restoration.js.map +1 -1
- package/build/esm/index.js +887 -884
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +369 -363
- package/build/types/RouterProvider.d.ts +3 -22
- package/build/types/fileRoute.d.ts +2 -2
- package/build/types/route.d.ts +1 -0
- package/build/types/router.d.ts +50 -5
- package/build/umd/index.development.js +887 -884
- 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/RouterProvider.tsx +57 -1314
- package/src/fileRoute.ts +1 -1
- package/src/route.ts +22 -0
- package/src/router.ts +1320 -45
- package/src/scroll-restoration.tsx +5 -5
package/build/esm/index.js
CHANGED
|
@@ -779,274 +779,34 @@ function useLoaderData(opts) {
|
|
|
779
779
|
return typeof opts.select === 'function' ? opts.select(match?.loaderData) : match?.loaderData;
|
|
780
780
|
}
|
|
781
781
|
|
|
782
|
-
//
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
//
|
|
793
|
-
|
|
794
|
-
//
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i]);
|
|
807
|
-
}
|
|
808
|
-
} else {
|
|
809
|
-
str && (str += '&');
|
|
810
|
-
str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
return (pfx || '') + str;
|
|
815
|
-
}
|
|
816
|
-
function toValue(mix) {
|
|
817
|
-
if (!mix) return '';
|
|
818
|
-
var str = decodeURIComponent(mix);
|
|
819
|
-
if (str === 'false') return false;
|
|
820
|
-
if (str === 'true') return true;
|
|
821
|
-
return +str * 0 === 0 && +str + '' === str ? +str : str;
|
|
822
|
-
}
|
|
823
|
-
function decode(str) {
|
|
824
|
-
var tmp,
|
|
825
|
-
k,
|
|
826
|
-
out = {},
|
|
827
|
-
arr = str.split('&');
|
|
828
|
-
while (tmp = arr.shift()) {
|
|
829
|
-
tmp = tmp.split('=');
|
|
830
|
-
k = tmp.shift();
|
|
831
|
-
if (out[k] !== void 0) {
|
|
832
|
-
out[k] = [].concat(out[k], toValue(tmp.shift()));
|
|
833
|
-
} else {
|
|
834
|
-
out[k] = toValue(tmp.shift());
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
return out;
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
841
|
-
const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
|
|
842
|
-
function parseSearchWith(parser) {
|
|
843
|
-
return searchStr => {
|
|
844
|
-
if (searchStr.substring(0, 1) === '?') {
|
|
845
|
-
searchStr = searchStr.substring(1);
|
|
846
|
-
}
|
|
847
|
-
let query = decode(searchStr);
|
|
848
|
-
|
|
849
|
-
// Try to parse any query params that might be json
|
|
850
|
-
for (let key in query) {
|
|
851
|
-
const value = query[key];
|
|
852
|
-
if (typeof value === 'string') {
|
|
853
|
-
try {
|
|
854
|
-
query[key] = parser(value);
|
|
855
|
-
} catch (err) {
|
|
856
|
-
//
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
return query;
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
function stringifySearchWith(stringify, parser) {
|
|
864
|
-
function stringifyValue(val) {
|
|
865
|
-
if (typeof val === 'object' && val !== null) {
|
|
866
|
-
try {
|
|
867
|
-
return stringify(val);
|
|
868
|
-
} catch (err) {
|
|
869
|
-
// silent
|
|
870
|
-
}
|
|
871
|
-
} else if (typeof val === 'string' && typeof parser === 'function') {
|
|
872
|
-
try {
|
|
873
|
-
// Check if it's a valid parseable string.
|
|
874
|
-
// If it is, then stringify it again.
|
|
875
|
-
parser(val);
|
|
876
|
-
return stringify(val);
|
|
877
|
-
} catch (err) {
|
|
878
|
-
// silent
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
return val;
|
|
882
|
-
}
|
|
883
|
-
return search => {
|
|
884
|
-
search = {
|
|
885
|
-
...search
|
|
886
|
-
};
|
|
887
|
-
if (search) {
|
|
888
|
-
Object.keys(search).forEach(key => {
|
|
889
|
-
const val = search[key];
|
|
890
|
-
if (typeof val === 'undefined' || val === undefined) {
|
|
891
|
-
delete search[key];
|
|
892
|
-
} else {
|
|
893
|
-
search[key] = stringifyValue(val);
|
|
894
|
-
}
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
const searchStr = encode(search).toString();
|
|
898
|
-
return searchStr ? `?${searchStr}` : '';
|
|
899
|
-
};
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
//
|
|
903
|
-
|
|
904
|
-
//
|
|
905
|
-
|
|
906
|
-
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
907
|
-
class Router {
|
|
908
|
-
// dehydratedData?: TDehydrated
|
|
909
|
-
// resetNextScroll = false
|
|
910
|
-
// tempLocationKey = `${Math.round(Math.random() * 10000000)}`
|
|
911
|
-
constructor(options) {
|
|
912
|
-
this.options = {
|
|
913
|
-
defaultPreloadDelay: 50,
|
|
914
|
-
context: undefined,
|
|
915
|
-
...options,
|
|
916
|
-
stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
|
|
917
|
-
parseSearch: options?.parseSearch ?? defaultParseSearch
|
|
918
|
-
};
|
|
919
|
-
this.routeTree = this.options.routeTree;
|
|
920
|
-
}
|
|
921
|
-
subscribers = new Set();
|
|
922
|
-
subscribe = (eventType, fn) => {
|
|
923
|
-
const listener = {
|
|
924
|
-
eventType,
|
|
925
|
-
fn
|
|
926
|
-
};
|
|
927
|
-
this.subscribers.add(listener);
|
|
928
|
-
return () => {
|
|
929
|
-
this.subscribers.delete(listener);
|
|
930
|
-
};
|
|
931
|
-
};
|
|
932
|
-
emit = routerEvent => {
|
|
933
|
-
this.subscribers.forEach(listener => {
|
|
934
|
-
if (listener.eventType === routerEvent.type) {
|
|
935
|
-
listener.fn(routerEvent);
|
|
936
|
-
}
|
|
937
|
-
});
|
|
938
|
-
};
|
|
939
|
-
|
|
940
|
-
// dehydrate = (): DehydratedRouter => {
|
|
941
|
-
// return {
|
|
942
|
-
// state: {
|
|
943
|
-
// dehydratedMatches: state.matches.map((d) =>
|
|
944
|
-
// pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt']),
|
|
945
|
-
// ),
|
|
946
|
-
// },
|
|
947
|
-
// }
|
|
948
|
-
// }
|
|
949
|
-
|
|
950
|
-
// hydrate = async (__do_not_use_server_ctx?: HydrationCtx) => {
|
|
951
|
-
// let _ctx = __do_not_use_server_ctx
|
|
952
|
-
// // Client hydrates from window
|
|
953
|
-
// if (typeof document !== 'undefined') {
|
|
954
|
-
// _ctx = window.__TSR_DEHYDRATED__
|
|
955
|
-
// }
|
|
956
|
-
|
|
957
|
-
// invariant(
|
|
958
|
-
// _ctx,
|
|
959
|
-
// 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?',
|
|
960
|
-
// )
|
|
961
|
-
|
|
962
|
-
// const ctx = _ctx
|
|
963
|
-
// this.dehydratedData = ctx.payload as any
|
|
964
|
-
// this.options.hydrate?.(ctx.payload as any)
|
|
965
|
-
// const dehydratedState = ctx.router.state
|
|
966
|
-
|
|
967
|
-
// let matches = this.matchRoutes(
|
|
968
|
-
// state.location.pathname,
|
|
969
|
-
// state.location.search,
|
|
970
|
-
// ).map((match) => {
|
|
971
|
-
// const dehydratedMatch = dehydratedState.dehydratedMatches.find(
|
|
972
|
-
// (d) => d.id === match.id,
|
|
973
|
-
// )
|
|
974
|
-
|
|
975
|
-
// invariant(
|
|
976
|
-
// dehydratedMatch,
|
|
977
|
-
// `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
|
|
978
|
-
// )
|
|
979
|
-
|
|
980
|
-
// if (dehydratedMatch) {
|
|
981
|
-
// return {
|
|
982
|
-
// ...match,
|
|
983
|
-
// ...dehydratedMatch,
|
|
984
|
-
// }
|
|
985
|
-
// }
|
|
986
|
-
// return match
|
|
987
|
-
// })
|
|
988
|
-
|
|
989
|
-
// this.setState((s) => {
|
|
990
|
-
// return {
|
|
991
|
-
// ...s,
|
|
992
|
-
// matches: dehydratedState.dehydratedMatches as any,
|
|
993
|
-
// }
|
|
994
|
-
// })
|
|
995
|
-
// }
|
|
996
|
-
|
|
997
|
-
// resolveMatchPromise = (matchId: string, key: string, value: any) => {
|
|
998
|
-
// state.matches
|
|
999
|
-
// .find((d) => d.id === matchId)
|
|
1000
|
-
// ?.__promisesByKey[key]?.resolve(value)
|
|
1001
|
-
// }
|
|
1002
|
-
|
|
1003
|
-
// setRouteMatch = (
|
|
1004
|
-
// id: string,
|
|
1005
|
-
// pending: boolean,
|
|
1006
|
-
// updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
|
|
1007
|
-
// ) => {
|
|
1008
|
-
// const key = pending ? 'pendingMatches' : 'matches'
|
|
1009
|
-
|
|
1010
|
-
// this.setState((prev) => {
|
|
1011
|
-
// return {
|
|
1012
|
-
// ...prev,
|
|
1013
|
-
// [key]: prev[key].map((d) => {
|
|
1014
|
-
// if (d.id === id) {
|
|
1015
|
-
// return functionalUpdate(updater, d)
|
|
1016
|
-
// }
|
|
1017
|
-
|
|
1018
|
-
// return d
|
|
1019
|
-
// }),
|
|
1020
|
-
// }
|
|
1021
|
-
// })
|
|
1022
|
-
// }
|
|
1023
|
-
|
|
1024
|
-
// setPendingRouteMatch = (
|
|
1025
|
-
// id: string,
|
|
1026
|
-
// updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
|
|
1027
|
-
// ) => {
|
|
1028
|
-
// this.setRouteMatch(id, true, updater)
|
|
1029
|
-
// }
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
// A function that takes an import() argument which is a function and returns a new function that will
|
|
1033
|
-
// proxy arguments from the caller to the imported function, retaining all type
|
|
1034
|
-
// information along the way
|
|
1035
|
-
function lazyFn(fn, key) {
|
|
1036
|
-
return async (...args) => {
|
|
1037
|
-
const imported = await fn();
|
|
1038
|
-
return imported[key || 'default'](...args);
|
|
1039
|
-
};
|
|
1040
|
-
}
|
|
1041
|
-
|
|
782
|
+
// export type RouterContext<
|
|
783
|
+
// TRouteTree extends AnyRoute,
|
|
784
|
+
// // TDehydrated extends Record<string, any>,
|
|
785
|
+
// > = {
|
|
786
|
+
// buildLink: BuildLinkFn<TRouteTree>
|
|
787
|
+
// state: RouterState<TRouteTree>
|
|
788
|
+
// navigate: NavigateFn<TRouteTree>
|
|
789
|
+
// matchRoute: MatchRouteFn<TRouteTree>
|
|
790
|
+
// routeTree: TRouteTree
|
|
791
|
+
// routesById: RoutesById<TRouteTree>
|
|
792
|
+
// options: RouterOptions<TRouteTree>
|
|
793
|
+
// history: RouterHistory
|
|
794
|
+
// load: LoadFn
|
|
795
|
+
// buildLocation: BuildLocationFn<TRouteTree>
|
|
796
|
+
// subscribe: Router<TRouteTree>['subscribe']
|
|
797
|
+
// resetNextScrollRef: React.MutableRefObject<boolean>
|
|
798
|
+
// injectedHtmlRef: React.MutableRefObject<InjectedHtmlEntry[]>
|
|
799
|
+
// injectHtml: (entry: InjectedHtmlEntry) => void
|
|
800
|
+
// dehydrateData: <T>(
|
|
801
|
+
// key: any,
|
|
802
|
+
// getData: T | (() => Promise<T> | T),
|
|
803
|
+
// ) => () => void
|
|
804
|
+
// hydrateData: <T>(key: any) => T | undefined
|
|
805
|
+
// }
|
|
1042
806
|
const routerContext = /*#__PURE__*/React.createContext(null);
|
|
1043
807
|
if (typeof document !== 'undefined') {
|
|
1044
808
|
window.__TSR_ROUTER_CONTEXT__ = routerContext;
|
|
1045
809
|
}
|
|
1046
|
-
const preloadWarning = 'Error preloading route! ☝️';
|
|
1047
|
-
function isCtrlEvent(e) {
|
|
1048
|
-
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
1049
|
-
}
|
|
1050
810
|
class SearchParamError extends Error {}
|
|
1051
811
|
class PathParamError extends Error {}
|
|
1052
812
|
function getInitialRouterState(location) {
|
|
@@ -1063,66 +823,55 @@ function RouterProvider({
|
|
|
1063
823
|
router,
|
|
1064
824
|
...rest
|
|
1065
825
|
}) {
|
|
1066
|
-
|
|
826
|
+
// Allow the router to update options on the router instance
|
|
827
|
+
router.updateOptions({
|
|
1067
828
|
...router.options,
|
|
1068
829
|
...rest,
|
|
1069
830
|
context: {
|
|
1070
831
|
...router.options.context,
|
|
1071
832
|
...rest?.context
|
|
1072
833
|
}
|
|
1073
|
-
};
|
|
1074
|
-
const history = React.useState(() => options.history ?? createBrowserHistory())[0];
|
|
1075
|
-
const tempLocationKeyRef = React.useRef(`${Math.round(Math.random() * 10000000)}`);
|
|
1076
|
-
const resetNextScrollRef = React.useRef(true);
|
|
1077
|
-
const navigateTimeoutRef = React.useRef(null);
|
|
1078
|
-
const latestLoadPromiseRef = React.useRef(Promise.resolve());
|
|
1079
|
-
const checkLatest = promise => {
|
|
1080
|
-
return latestLoadPromiseRef.current !== promise ? latestLoadPromiseRef.current : undefined;
|
|
1081
|
-
};
|
|
1082
|
-
const parseLocation = useStableCallback(previousLocation => {
|
|
1083
|
-
const parse = ({
|
|
1084
|
-
pathname,
|
|
1085
|
-
search,
|
|
1086
|
-
hash,
|
|
1087
|
-
state
|
|
1088
|
-
}) => {
|
|
1089
|
-
const parsedSearch = options.parseSearch(search);
|
|
1090
|
-
return {
|
|
1091
|
-
pathname: pathname,
|
|
1092
|
-
searchStr: search,
|
|
1093
|
-
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
1094
|
-
hash: hash.split('#').reverse()[0] ?? '',
|
|
1095
|
-
href: `${pathname}${search}${hash}`,
|
|
1096
|
-
state: replaceEqualDeep(previousLocation?.state, state)
|
|
1097
|
-
};
|
|
1098
|
-
};
|
|
1099
|
-
const location = parse(history.location);
|
|
1100
|
-
let {
|
|
1101
|
-
__tempLocation,
|
|
1102
|
-
__tempKey
|
|
1103
|
-
} = location.state;
|
|
1104
|
-
if (__tempLocation && (!__tempKey || __tempKey === tempLocationKeyRef.current)) {
|
|
1105
|
-
// Sync up the location keys
|
|
1106
|
-
const parsedTempLocation = parse(__tempLocation);
|
|
1107
|
-
parsedTempLocation.state.key = location.state.key;
|
|
1108
|
-
delete parsedTempLocation.state.__tempLocation;
|
|
1109
|
-
return {
|
|
1110
|
-
...parsedTempLocation,
|
|
1111
|
-
maskedLocation: location
|
|
1112
|
-
};
|
|
1113
|
-
}
|
|
1114
|
-
return location;
|
|
1115
834
|
});
|
|
1116
|
-
const
|
|
1117
|
-
const [preState, setState] = React.useState(() => getInitialRouterState(latestLocationRef.current));
|
|
835
|
+
const [preState, setState] = React.useState(() => router.state);
|
|
1118
836
|
const [isTransitioning, startReactTransition] = React.useTransition();
|
|
1119
|
-
const pendingMatchesRef = React.useRef([]);
|
|
1120
837
|
const state = React.useMemo(() => ({
|
|
1121
838
|
...preState,
|
|
1122
839
|
status: isTransitioning ? 'pending' : 'idle',
|
|
1123
|
-
location: isTransitioning ?
|
|
1124
|
-
pendingMatches:
|
|
840
|
+
location: isTransitioning ? router.latestLocation : preState.location,
|
|
841
|
+
pendingMatches: router.pendingMatches
|
|
1125
842
|
}), [preState, isTransitioning]);
|
|
843
|
+
router.setState = setState;
|
|
844
|
+
router.state = state;
|
|
845
|
+
router.startReactTransition = startReactTransition;
|
|
846
|
+
React.useLayoutEffect(() => {
|
|
847
|
+
const unsub = router.history.subscribe(() => {
|
|
848
|
+
router.latestLocation = router.parseLocation(router.latestLocation);
|
|
849
|
+
if (state.location !== router.latestLocation) {
|
|
850
|
+
startReactTransition(() => {
|
|
851
|
+
try {
|
|
852
|
+
router.load();
|
|
853
|
+
} catch (err) {
|
|
854
|
+
console.error(err);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
const nextLocation = router.buildLocation({
|
|
860
|
+
search: true,
|
|
861
|
+
params: true,
|
|
862
|
+
hash: true,
|
|
863
|
+
state: true
|
|
864
|
+
});
|
|
865
|
+
if (state.location.href !== nextLocation.href) {
|
|
866
|
+
router.commitLocation({
|
|
867
|
+
...nextLocation,
|
|
868
|
+
replace: true
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
return () => {
|
|
872
|
+
unsub();
|
|
873
|
+
};
|
|
874
|
+
}, [history]);
|
|
1126
875
|
React.useLayoutEffect(() => {
|
|
1127
876
|
if (!isTransitioning && state.resolvedLocation !== state.location) {
|
|
1128
877
|
router.emit({
|
|
@@ -1131,135 +880,592 @@ function RouterProvider({
|
|
|
1131
880
|
toLocation: state.location,
|
|
1132
881
|
pathChanged: state.location.href !== state.resolvedLocation?.href
|
|
1133
882
|
});
|
|
1134
|
-
|
|
883
|
+
router.pendingMatches = [];
|
|
1135
884
|
setState(s => ({
|
|
1136
885
|
...s,
|
|
1137
886
|
resolvedLocation: s.location
|
|
1138
887
|
}));
|
|
1139
888
|
}
|
|
1140
889
|
});
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
const routesByPath = {};
|
|
1148
|
-
const recurseRoutes = routes => {
|
|
1149
|
-
routes.forEach((route, i) => {
|
|
1150
|
-
route.init({
|
|
1151
|
-
originalIndex: i
|
|
1152
|
-
});
|
|
1153
|
-
const existingRoute = routesById[route.id];
|
|
1154
|
-
invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
|
|
1155
|
-
routesById[route.id] = route;
|
|
1156
|
-
if (!route.isRoot && route.path) {
|
|
1157
|
-
const trimmedFullPath = trimPathRight(route.fullPath);
|
|
1158
|
-
if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
|
|
1159
|
-
routesByPath[trimmedFullPath] = route;
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
const children = route.children;
|
|
1163
|
-
if (children?.length) {
|
|
1164
|
-
recurseRoutes(children);
|
|
1165
|
-
}
|
|
1166
|
-
});
|
|
1167
|
-
};
|
|
1168
|
-
recurseRoutes([router.routeTree]);
|
|
1169
|
-
return [routesById, routesByPath];
|
|
1170
|
-
}, []);
|
|
1171
|
-
const looseRoutesById = routesById;
|
|
1172
|
-
const flatRoutes = React.useMemo(() => Object.values(routesByPath).map((d, i) => {
|
|
1173
|
-
const trimmed = trimPath(d.fullPath);
|
|
1174
|
-
const parsed = parsePathname(trimmed);
|
|
1175
|
-
while (parsed.length > 1 && parsed[0]?.value === '/') {
|
|
1176
|
-
parsed.shift();
|
|
1177
|
-
}
|
|
1178
|
-
const score = parsed.map(d => {
|
|
1179
|
-
if (d.type === 'param') {
|
|
1180
|
-
return 0.5;
|
|
1181
|
-
}
|
|
1182
|
-
if (d.type === 'wildcard') {
|
|
1183
|
-
return 0.25;
|
|
890
|
+
React.useLayoutEffect(() => {
|
|
891
|
+
startReactTransition(() => {
|
|
892
|
+
try {
|
|
893
|
+
router.load();
|
|
894
|
+
} catch (err) {
|
|
895
|
+
console.error(err);
|
|
1184
896
|
}
|
|
1185
|
-
return 1;
|
|
1186
897
|
});
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
898
|
+
}, []);
|
|
899
|
+
return /*#__PURE__*/React.createElement(routerContext.Provider, {
|
|
900
|
+
value: router
|
|
901
|
+
}, /*#__PURE__*/React.createElement(Matches, null));
|
|
902
|
+
}
|
|
903
|
+
function getRouteMatch(state, id) {
|
|
904
|
+
return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
|
|
905
|
+
}
|
|
906
|
+
function useRouterState(opts) {
|
|
907
|
+
const {
|
|
908
|
+
state
|
|
909
|
+
} = useRouter();
|
|
910
|
+
// return useStore(router.__store, opts?.select as any)
|
|
911
|
+
return opts?.select ? opts.select(state) : state;
|
|
912
|
+
}
|
|
913
|
+
function useRouter() {
|
|
914
|
+
const resolvedContext = window.__TSR_ROUTER_CONTEXT__ || routerContext;
|
|
915
|
+
const value = React.useContext(resolvedContext);
|
|
916
|
+
warning(value, 'useRouter must be used inside a <RouterProvider> component!');
|
|
917
|
+
return value;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
function defer(_promise) {
|
|
921
|
+
const promise = _promise;
|
|
922
|
+
if (!promise.__deferredState) {
|
|
923
|
+
promise.__deferredState = {
|
|
924
|
+
uid: Math.random().toString(36).slice(2),
|
|
925
|
+
status: 'pending'
|
|
1193
926
|
};
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
927
|
+
const state = promise.__deferredState;
|
|
928
|
+
promise.then(data => {
|
|
929
|
+
state.status = 'success';
|
|
930
|
+
state.data = data;
|
|
931
|
+
}).catch(error => {
|
|
932
|
+
state.status = 'error';
|
|
933
|
+
state.error = error;
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
return promise;
|
|
937
|
+
}
|
|
938
|
+
function isDehydratedDeferred(obj) {
|
|
939
|
+
return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
|
|
940
|
+
}
|
|
1203
941
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
942
|
+
function useAwaited({
|
|
943
|
+
promise
|
|
944
|
+
}) {
|
|
945
|
+
const router = useRouter();
|
|
946
|
+
let state = promise.__deferredState;
|
|
947
|
+
const key = `__TSR__DEFERRED__${state.uid}`;
|
|
948
|
+
if (isDehydratedDeferred(promise)) {
|
|
949
|
+
state = router.hydrateData(key);
|
|
950
|
+
promise = Promise.resolve(state.data);
|
|
951
|
+
promise.__deferredState = state;
|
|
952
|
+
}
|
|
953
|
+
if (state.status === 'pending') {
|
|
954
|
+
throw promise;
|
|
955
|
+
}
|
|
956
|
+
if (state.status === 'error') {
|
|
957
|
+
throw state.error;
|
|
958
|
+
}
|
|
959
|
+
router.dehydrateData(key, state);
|
|
960
|
+
return [state.data];
|
|
961
|
+
}
|
|
962
|
+
function Await(props) {
|
|
963
|
+
const awaited = useAwaited(props);
|
|
964
|
+
return props.children(...awaited);
|
|
965
|
+
}
|
|
1210
966
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
967
|
+
class FileRoute {
|
|
968
|
+
constructor(path) {
|
|
969
|
+
this.path = path;
|
|
970
|
+
}
|
|
971
|
+
createRoute = options => {
|
|
972
|
+
const route = new Route(options);
|
|
973
|
+
route.isRoot = false;
|
|
974
|
+
return route;
|
|
975
|
+
};
|
|
976
|
+
}
|
|
1217
977
|
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
978
|
+
function lazyRouteComponent(importer, exportName) {
|
|
979
|
+
let loadPromise;
|
|
980
|
+
const load = () => {
|
|
981
|
+
if (!loadPromise) {
|
|
982
|
+
loadPromise = importer();
|
|
1221
983
|
}
|
|
984
|
+
return loadPromise;
|
|
985
|
+
};
|
|
986
|
+
const lazyComp = /*#__PURE__*/React.lazy(async () => {
|
|
987
|
+
const moduleExports = await load();
|
|
988
|
+
const comp = moduleExports[exportName ?? 'default'];
|
|
989
|
+
return {
|
|
990
|
+
default: comp
|
|
991
|
+
};
|
|
992
|
+
});
|
|
993
|
+
lazyComp.preload = load;
|
|
994
|
+
return lazyComp;
|
|
995
|
+
}
|
|
1222
996
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
let foundRoute = flatRoutes.find(route => {
|
|
1232
|
-
const matchedParams = matchPathname(basepath, trimPathRight(pathname), {
|
|
1233
|
-
to: route.fullPath,
|
|
1234
|
-
caseSensitive: route.options.caseSensitive ?? options.caseSensitive,
|
|
1235
|
-
fuzzy: false
|
|
1236
|
-
});
|
|
1237
|
-
if (matchedParams) {
|
|
1238
|
-
routeParams = matchedParams;
|
|
1239
|
-
return true;
|
|
997
|
+
function _extends() {
|
|
998
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
999
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
1000
|
+
var source = arguments[i];
|
|
1001
|
+
for (var key in source) {
|
|
1002
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1003
|
+
target[key] = source[key];
|
|
1004
|
+
}
|
|
1240
1005
|
}
|
|
1241
|
-
return false;
|
|
1242
|
-
});
|
|
1243
|
-
let routeCursor = foundRoute || routesById['__root__'];
|
|
1244
|
-
let matchedRoutes = [routeCursor];
|
|
1245
|
-
// let includingLayouts = true
|
|
1246
|
-
while (routeCursor?.parentRoute) {
|
|
1247
|
-
routeCursor = routeCursor.parentRoute;
|
|
1248
|
-
if (routeCursor) matchedRoutes.unshift(routeCursor);
|
|
1249
1006
|
}
|
|
1007
|
+
return target;
|
|
1008
|
+
};
|
|
1009
|
+
return _extends.apply(this, arguments);
|
|
1010
|
+
}
|
|
1250
1011
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1012
|
+
function useLinkProps(options) {
|
|
1013
|
+
const {
|
|
1014
|
+
buildLink
|
|
1015
|
+
} = useRouter();
|
|
1016
|
+
const match = useMatch({
|
|
1017
|
+
strict: false
|
|
1018
|
+
});
|
|
1019
|
+
const {
|
|
1020
|
+
// custom props
|
|
1021
|
+
type,
|
|
1022
|
+
children,
|
|
1023
|
+
target,
|
|
1024
|
+
activeProps = () => ({
|
|
1025
|
+
className: 'active'
|
|
1026
|
+
}),
|
|
1027
|
+
inactiveProps = () => ({}),
|
|
1028
|
+
activeOptions,
|
|
1029
|
+
disabled,
|
|
1030
|
+
hash,
|
|
1031
|
+
search,
|
|
1032
|
+
params,
|
|
1033
|
+
to,
|
|
1034
|
+
state,
|
|
1035
|
+
mask,
|
|
1036
|
+
preload,
|
|
1037
|
+
preloadDelay,
|
|
1038
|
+
replace,
|
|
1039
|
+
startTransition,
|
|
1040
|
+
resetScroll,
|
|
1041
|
+
// element props
|
|
1042
|
+
style,
|
|
1043
|
+
className,
|
|
1044
|
+
onClick,
|
|
1045
|
+
onFocus,
|
|
1046
|
+
onMouseEnter,
|
|
1047
|
+
onMouseLeave,
|
|
1048
|
+
onTouchStart,
|
|
1049
|
+
...rest
|
|
1050
|
+
} = options;
|
|
1051
|
+
const linkInfo = buildLink({
|
|
1052
|
+
from: options.to ? match.pathname : undefined,
|
|
1053
|
+
...options
|
|
1054
|
+
});
|
|
1055
|
+
if (linkInfo.type === 'external') {
|
|
1056
|
+
const {
|
|
1057
|
+
href
|
|
1058
|
+
} = linkInfo;
|
|
1059
|
+
return {
|
|
1060
|
+
href
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
const {
|
|
1064
|
+
handleClick,
|
|
1065
|
+
handleFocus,
|
|
1066
|
+
handleEnter,
|
|
1067
|
+
handleLeave,
|
|
1068
|
+
handleTouchStart,
|
|
1069
|
+
isActive,
|
|
1070
|
+
next
|
|
1071
|
+
} = linkInfo;
|
|
1072
|
+
const composeHandlers = handlers => e => {
|
|
1073
|
+
if (e.persist) e.persist();
|
|
1074
|
+
handlers.filter(Boolean).forEach(handler => {
|
|
1075
|
+
if (e.defaultPrevented) return;
|
|
1076
|
+
handler(e);
|
|
1077
|
+
});
|
|
1078
|
+
};
|
|
1253
1079
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1080
|
+
// Get the active props
|
|
1081
|
+
const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {};
|
|
1082
|
+
|
|
1083
|
+
// Get the inactive props
|
|
1084
|
+
const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
|
|
1085
|
+
return {
|
|
1086
|
+
...resolvedActiveProps,
|
|
1087
|
+
...resolvedInactiveProps,
|
|
1088
|
+
...rest,
|
|
1089
|
+
href: disabled ? undefined : next.maskedLocation ? next.maskedLocation.href : next.href,
|
|
1090
|
+
onClick: composeHandlers([onClick, handleClick]),
|
|
1091
|
+
onFocus: composeHandlers([onFocus, handleFocus]),
|
|
1092
|
+
onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
|
|
1093
|
+
onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
|
|
1094
|
+
onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
|
|
1095
|
+
target,
|
|
1096
|
+
style: {
|
|
1097
|
+
...style,
|
|
1098
|
+
...resolvedActiveProps.style,
|
|
1099
|
+
...resolvedInactiveProps.style
|
|
1100
|
+
},
|
|
1101
|
+
className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
|
|
1102
|
+
...(disabled ? {
|
|
1103
|
+
role: 'link',
|
|
1104
|
+
'aria-disabled': true
|
|
1105
|
+
} : undefined),
|
|
1106
|
+
['data-status']: isActive ? 'active' : undefined
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
const Link = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
1110
|
+
const linkProps = useLinkProps(props);
|
|
1111
|
+
return /*#__PURE__*/React.createElement("a", _extends({
|
|
1112
|
+
ref: ref
|
|
1113
|
+
}, linkProps, {
|
|
1114
|
+
children: typeof props.children === 'function' ? props.children({
|
|
1115
|
+
isActive: linkProps['data-status'] === 'active'
|
|
1116
|
+
}) : props.children
|
|
1117
|
+
}));
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
// @ts-nocheck
|
|
1121
|
+
|
|
1122
|
+
// qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
|
|
1123
|
+
|
|
1124
|
+
function encode(obj, pfx) {
|
|
1125
|
+
var k,
|
|
1126
|
+
i,
|
|
1127
|
+
tmp,
|
|
1128
|
+
str = '';
|
|
1129
|
+
for (k in obj) {
|
|
1130
|
+
if ((tmp = obj[k]) !== void 0) {
|
|
1131
|
+
if (Array.isArray(tmp)) {
|
|
1132
|
+
for (i = 0; i < tmp.length; i++) {
|
|
1133
|
+
str && (str += '&');
|
|
1134
|
+
str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i]);
|
|
1135
|
+
}
|
|
1136
|
+
} else {
|
|
1137
|
+
str && (str += '&');
|
|
1138
|
+
str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
return (pfx || '') + str;
|
|
1143
|
+
}
|
|
1144
|
+
function toValue(mix) {
|
|
1145
|
+
if (!mix) return '';
|
|
1146
|
+
var str = decodeURIComponent(mix);
|
|
1147
|
+
if (str === 'false') return false;
|
|
1148
|
+
if (str === 'true') return true;
|
|
1149
|
+
return +str * 0 === 0 && +str + '' === str ? +str : str;
|
|
1150
|
+
}
|
|
1151
|
+
function decode(str) {
|
|
1152
|
+
var tmp,
|
|
1153
|
+
k,
|
|
1154
|
+
out = {},
|
|
1155
|
+
arr = str.split('&');
|
|
1156
|
+
while (tmp = arr.shift()) {
|
|
1157
|
+
tmp = tmp.split('=');
|
|
1158
|
+
k = tmp.shift();
|
|
1159
|
+
if (out[k] !== void 0) {
|
|
1160
|
+
out[k] = [].concat(out[k], toValue(tmp.shift()));
|
|
1161
|
+
} else {
|
|
1162
|
+
out[k] = toValue(tmp.shift());
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
return out;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// Detect if we're in the DOM
|
|
1169
|
+
|
|
1170
|
+
function redirect(opts) {
|
|
1171
|
+
opts.isRedirect = true;
|
|
1172
|
+
return opts;
|
|
1173
|
+
}
|
|
1174
|
+
function isRedirect(obj) {
|
|
1175
|
+
return !!obj?.isRedirect;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
1179
|
+
const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
|
|
1180
|
+
function parseSearchWith(parser) {
|
|
1181
|
+
return searchStr => {
|
|
1182
|
+
if (searchStr.substring(0, 1) === '?') {
|
|
1183
|
+
searchStr = searchStr.substring(1);
|
|
1184
|
+
}
|
|
1185
|
+
let query = decode(searchStr);
|
|
1186
|
+
|
|
1187
|
+
// Try to parse any query params that might be json
|
|
1188
|
+
for (let key in query) {
|
|
1189
|
+
const value = query[key];
|
|
1190
|
+
if (typeof value === 'string') {
|
|
1191
|
+
try {
|
|
1192
|
+
query[key] = parser(value);
|
|
1193
|
+
} catch (err) {
|
|
1194
|
+
//
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
return query;
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
function stringifySearchWith(stringify, parser) {
|
|
1202
|
+
function stringifyValue(val) {
|
|
1203
|
+
if (typeof val === 'object' && val !== null) {
|
|
1204
|
+
try {
|
|
1205
|
+
return stringify(val);
|
|
1206
|
+
} catch (err) {
|
|
1207
|
+
// silent
|
|
1208
|
+
}
|
|
1209
|
+
} else if (typeof val === 'string' && typeof parser === 'function') {
|
|
1210
|
+
try {
|
|
1211
|
+
// Check if it's a valid parseable string.
|
|
1212
|
+
// If it is, then stringify it again.
|
|
1213
|
+
parser(val);
|
|
1214
|
+
return stringify(val);
|
|
1215
|
+
} catch (err) {
|
|
1216
|
+
// silent
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
return val;
|
|
1220
|
+
}
|
|
1221
|
+
return search => {
|
|
1222
|
+
search = {
|
|
1223
|
+
...search
|
|
1224
|
+
};
|
|
1225
|
+
if (search) {
|
|
1226
|
+
Object.keys(search).forEach(key => {
|
|
1227
|
+
const val = search[key];
|
|
1228
|
+
if (typeof val === 'undefined' || val === undefined) {
|
|
1229
|
+
delete search[key];
|
|
1230
|
+
} else {
|
|
1231
|
+
search[key] = stringifyValue(val);
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
const searchStr = encode(search).toString();
|
|
1236
|
+
return searchStr ? `?${searchStr}` : '';
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
//
|
|
1241
|
+
|
|
1242
|
+
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
1243
|
+
const preloadWarning = 'Error preloading route! ☝️';
|
|
1244
|
+
class Router {
|
|
1245
|
+
// Option-independent properties
|
|
1246
|
+
tempLocationKey = `${Math.round(Math.random() * 10000000)}`;
|
|
1247
|
+
resetNextScroll = true;
|
|
1248
|
+
navigateTimeout = null;
|
|
1249
|
+
latestLoadPromise = Promise.resolve();
|
|
1250
|
+
subscribers = new Set();
|
|
1251
|
+
pendingMatches = [];
|
|
1252
|
+
injectedHtml = [];
|
|
1253
|
+
|
|
1254
|
+
// Must build in constructor
|
|
1255
|
+
|
|
1256
|
+
constructor(options) {
|
|
1257
|
+
this.updateOptions({
|
|
1258
|
+
defaultPreloadDelay: 50,
|
|
1259
|
+
context: undefined,
|
|
1260
|
+
...options,
|
|
1261
|
+
stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
|
|
1262
|
+
parseSearch: options?.parseSearch ?? defaultParseSearch
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
startReactTransition = () => {
|
|
1266
|
+
warning(false, 'startReactTransition implementation is missing. If you see this, please file an issue.');
|
|
1267
|
+
};
|
|
1268
|
+
setState = () => {
|
|
1269
|
+
warning(false, 'setState implementation is missing. If you see this, please file an issue.');
|
|
1270
|
+
};
|
|
1271
|
+
updateOptions = newOptions => {
|
|
1272
|
+
this.options;
|
|
1273
|
+
this.options = {
|
|
1274
|
+
...this.options,
|
|
1275
|
+
...newOptions
|
|
1276
|
+
};
|
|
1277
|
+
this.basepath = `/${trimPath(newOptions.basepath ?? '') ?? ''}`;
|
|
1278
|
+
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
1279
|
+
this.history = this.options.history ?? createBrowserHistory();
|
|
1280
|
+
this.latestLocation = this.parseLocation();
|
|
1281
|
+
}
|
|
1282
|
+
if (this.options.routeTree !== this.routeTree) {
|
|
1283
|
+
this.routeTree = this.options.routeTree;
|
|
1284
|
+
this.buildRouteTree();
|
|
1285
|
+
}
|
|
1286
|
+
if (!this.state) {
|
|
1287
|
+
this.state = getInitialRouterState(this.latestLocation);
|
|
1288
|
+
}
|
|
1289
|
+
};
|
|
1290
|
+
buildRouteTree = () => {
|
|
1291
|
+
this.routesById = {};
|
|
1292
|
+
this.routesByPath = {};
|
|
1293
|
+
const recurseRoutes = childRoutes => {
|
|
1294
|
+
childRoutes.forEach((childRoute, i) => {
|
|
1295
|
+
// if (typeof childRoute === 'function') {
|
|
1296
|
+
// childRoute = (childRoute as any)()
|
|
1297
|
+
// }
|
|
1298
|
+
childRoute.init({
|
|
1299
|
+
originalIndex: i
|
|
1300
|
+
});
|
|
1301
|
+
const existingRoute = this.routesById[childRoute.id];
|
|
1302
|
+
invariant(!existingRoute, `Duplicate routes found with id: ${String(childRoute.id)}`);
|
|
1303
|
+
this.routesById[childRoute.id] = childRoute;
|
|
1304
|
+
if (!childRoute.isRoot && childRoute.path) {
|
|
1305
|
+
const trimmedFullPath = trimPathRight(childRoute.fullPath);
|
|
1306
|
+
if (!this.routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith('/')) {
|
|
1307
|
+
this.routesByPath[trimmedFullPath] = childRoute;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
const children = childRoute.children;
|
|
1311
|
+
if (children?.length) {
|
|
1312
|
+
recurseRoutes(children);
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
};
|
|
1316
|
+
recurseRoutes([this.routeTree]);
|
|
1317
|
+
this.flatRoutes = Object.values(this.routesByPath).map((d, i) => {
|
|
1318
|
+
const trimmed = trimPath(d.fullPath);
|
|
1319
|
+
const parsed = parsePathname(trimmed);
|
|
1320
|
+
while (parsed.length > 1 && parsed[0]?.value === '/') {
|
|
1321
|
+
parsed.shift();
|
|
1322
|
+
}
|
|
1323
|
+
const score = parsed.map(d => {
|
|
1324
|
+
if (d.type === 'param') {
|
|
1325
|
+
return 0.5;
|
|
1326
|
+
}
|
|
1327
|
+
if (d.type === 'wildcard') {
|
|
1328
|
+
return 0.25;
|
|
1329
|
+
}
|
|
1330
|
+
return 1;
|
|
1331
|
+
});
|
|
1332
|
+
return {
|
|
1333
|
+
child: d,
|
|
1334
|
+
trimmed,
|
|
1335
|
+
parsed,
|
|
1336
|
+
index: i,
|
|
1337
|
+
score
|
|
1338
|
+
};
|
|
1339
|
+
}).sort((a, b) => {
|
|
1340
|
+
let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
|
|
1341
|
+
if (isIndex !== 0) return isIndex;
|
|
1342
|
+
const length = Math.min(a.score.length, b.score.length);
|
|
1343
|
+
|
|
1344
|
+
// Sort by length of score
|
|
1345
|
+
if (a.score.length !== b.score.length) {
|
|
1346
|
+
return b.score.length - a.score.length;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// Sort by min available score
|
|
1350
|
+
for (let i = 0; i < length; i++) {
|
|
1351
|
+
if (a.score[i] !== b.score[i]) {
|
|
1352
|
+
return b.score[i] - a.score[i];
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
// Sort by min available parsed value
|
|
1357
|
+
for (let i = 0; i < length; i++) {
|
|
1358
|
+
if (a.parsed[i].value !== b.parsed[i].value) {
|
|
1359
|
+
return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// Sort by length of trimmed full path
|
|
1364
|
+
if (a.trimmed !== b.trimmed) {
|
|
1365
|
+
return a.trimmed > b.trimmed ? 1 : -1;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
// Sort by original index
|
|
1369
|
+
return a.index - b.index;
|
|
1370
|
+
}).map((d, i) => {
|
|
1371
|
+
d.child.rank = i;
|
|
1372
|
+
return d.child;
|
|
1373
|
+
});
|
|
1374
|
+
};
|
|
1375
|
+
subscribe = (eventType, fn) => {
|
|
1376
|
+
const listener = {
|
|
1377
|
+
eventType,
|
|
1378
|
+
fn
|
|
1379
|
+
};
|
|
1380
|
+
this.subscribers.add(listener);
|
|
1381
|
+
return () => {
|
|
1382
|
+
this.subscribers.delete(listener);
|
|
1383
|
+
};
|
|
1384
|
+
};
|
|
1385
|
+
emit = routerEvent => {
|
|
1386
|
+
this.subscribers.forEach(listener => {
|
|
1387
|
+
if (listener.eventType === routerEvent.type) {
|
|
1388
|
+
listener.fn(routerEvent);
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
};
|
|
1392
|
+
checkLatest = promise => {
|
|
1393
|
+
return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
|
|
1394
|
+
};
|
|
1395
|
+
parseLocation = previousLocation => {
|
|
1396
|
+
const parse = ({
|
|
1397
|
+
pathname,
|
|
1398
|
+
search,
|
|
1399
|
+
hash,
|
|
1400
|
+
state
|
|
1401
|
+
}) => {
|
|
1402
|
+
const parsedSearch = this.options.parseSearch(search);
|
|
1403
|
+
return {
|
|
1404
|
+
pathname: pathname,
|
|
1405
|
+
searchStr: search,
|
|
1406
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
1407
|
+
hash: hash.split('#').reverse()[0] ?? '',
|
|
1408
|
+
href: `${pathname}${search}${hash}`,
|
|
1409
|
+
state: replaceEqualDeep(previousLocation?.state, state)
|
|
1410
|
+
};
|
|
1411
|
+
};
|
|
1412
|
+
const location = parse(this.history.location);
|
|
1413
|
+
let {
|
|
1414
|
+
__tempLocation,
|
|
1415
|
+
__tempKey
|
|
1416
|
+
} = location.state;
|
|
1417
|
+
if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
|
|
1418
|
+
// Sync up the location keys
|
|
1419
|
+
const parsedTempLocation = parse(__tempLocation);
|
|
1420
|
+
parsedTempLocation.state.key = location.state.key;
|
|
1421
|
+
delete parsedTempLocation.state.__tempLocation;
|
|
1422
|
+
return {
|
|
1423
|
+
...parsedTempLocation,
|
|
1424
|
+
maskedLocation: location
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
return location;
|
|
1428
|
+
};
|
|
1429
|
+
resolvePathWithBase = (from, path) => {
|
|
1430
|
+
return resolvePath(this.basepath, from, cleanPath(path));
|
|
1431
|
+
};
|
|
1432
|
+
get looseRoutesById() {
|
|
1433
|
+
return this.routesById;
|
|
1434
|
+
}
|
|
1435
|
+
matchRoutes = (pathname, locationSearch, opts) => {
|
|
1436
|
+
let routeParams = {};
|
|
1437
|
+
let foundRoute = this.flatRoutes.find(route => {
|
|
1438
|
+
const matchedParams = matchPathname(this.basepath, trimPathRight(pathname), {
|
|
1439
|
+
to: route.fullPath,
|
|
1440
|
+
caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
|
|
1441
|
+
fuzzy: false
|
|
1442
|
+
});
|
|
1443
|
+
if (matchedParams) {
|
|
1444
|
+
routeParams = matchedParams;
|
|
1445
|
+
return true;
|
|
1446
|
+
}
|
|
1447
|
+
return false;
|
|
1448
|
+
});
|
|
1449
|
+
let routeCursor = foundRoute || this.routesById['__root__'];
|
|
1450
|
+
let matchedRoutes = [routeCursor];
|
|
1451
|
+
// let includingLayouts = true
|
|
1452
|
+
while (routeCursor?.parentRoute) {
|
|
1453
|
+
routeCursor = routeCursor.parentRoute;
|
|
1454
|
+
if (routeCursor) matchedRoutes.unshift(routeCursor);
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
// Existing matches are matches that are already loaded along with
|
|
1458
|
+
// pending matches that are still loading
|
|
1459
|
+
|
|
1460
|
+
const parseErrors = matchedRoutes.map(route => {
|
|
1461
|
+
let parsedParamsError;
|
|
1462
|
+
if (route.options.parseParams) {
|
|
1463
|
+
try {
|
|
1464
|
+
const parsedParams = route.options.parseParams(routeParams);
|
|
1465
|
+
// Add the parsed params to the accumulated params bag
|
|
1466
|
+
Object.assign(routeParams, parsedParams);
|
|
1467
|
+
} catch (err) {
|
|
1468
|
+
parsedParamsError = new PathParamError(err.message, {
|
|
1263
1469
|
cause: err
|
|
1264
1470
|
});
|
|
1265
1471
|
if (opts?.throwOnError) {
|
|
@@ -1277,8 +1483,8 @@ function RouterProvider({
|
|
|
1277
1483
|
// Waste not, want not. If we already have a match for this route,
|
|
1278
1484
|
// reuse it. This is important for layout routes, which might stick
|
|
1279
1485
|
// around between navigation actions that only change leaf routes.
|
|
1280
|
-
const existingMatch = getRouteMatch(state, matchId);
|
|
1281
|
-
const cause = state.matches.find(d => d.id === matchId) ? 'stay' : 'enter';
|
|
1486
|
+
const existingMatch = getRouteMatch(this.state, matchId);
|
|
1487
|
+
const cause = this.state.matches.find(d => d.id === matchId) ? 'stay' : 'enter';
|
|
1282
1488
|
if (existingMatch) {
|
|
1283
1489
|
return {
|
|
1284
1490
|
...existingMatch,
|
|
@@ -1292,7 +1498,7 @@ function RouterProvider({
|
|
|
1292
1498
|
id: matchId,
|
|
1293
1499
|
routeId: route.id,
|
|
1294
1500
|
params: routeParams,
|
|
1295
|
-
pathname: joinPaths([basepath, interpolatedPath]),
|
|
1501
|
+
pathname: joinPaths([this.basepath, interpolatedPath]),
|
|
1296
1502
|
updatedAt: Date.now(),
|
|
1297
1503
|
routeSearch: {},
|
|
1298
1504
|
search: {},
|
|
@@ -1317,7 +1523,7 @@ function RouterProvider({
|
|
|
1317
1523
|
// so that we can use the parent match's search params and context
|
|
1318
1524
|
matches.forEach((match, i) => {
|
|
1319
1525
|
const parentMatch = matches[i - 1];
|
|
1320
|
-
const route = looseRoutesById[match.routeId];
|
|
1526
|
+
const route = this.looseRoutesById[match.routeId];
|
|
1321
1527
|
const searchInfo = (() => {
|
|
1322
1528
|
// Validate the search params and stabilize them
|
|
1323
1529
|
const parentSearchInfo = {
|
|
@@ -1351,28 +1557,28 @@ function RouterProvider({
|
|
|
1351
1557
|
Object.assign(match, searchInfo);
|
|
1352
1558
|
});
|
|
1353
1559
|
return matches;
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
getRouteMatch(state, id)?.abortController?.abort();
|
|
1357
|
-
}
|
|
1358
|
-
|
|
1359
|
-
state.matches.forEach(match => {
|
|
1360
|
-
cancelMatch(match.id);
|
|
1560
|
+
};
|
|
1561
|
+
cancelMatch = id => {
|
|
1562
|
+
getRouteMatch(this.state, id)?.abortController?.abort();
|
|
1563
|
+
};
|
|
1564
|
+
cancelMatches = () => {
|
|
1565
|
+
this.state.matches.forEach(match => {
|
|
1566
|
+
this.cancelMatch(match.id);
|
|
1361
1567
|
});
|
|
1362
|
-
}
|
|
1363
|
-
|
|
1568
|
+
};
|
|
1569
|
+
buildLocation = opts => {
|
|
1364
1570
|
const build = (dest = {}, matches) => {
|
|
1365
|
-
const from =
|
|
1571
|
+
const from = this.latestLocation;
|
|
1366
1572
|
const fromPathname = dest.from ?? from.pathname;
|
|
1367
|
-
let pathname = resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
|
|
1368
|
-
const fromMatches = matchRoutes(fromPathname, from.search);
|
|
1573
|
+
let pathname = this.resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
|
|
1574
|
+
const fromMatches = this.matchRoutes(fromPathname, from.search);
|
|
1369
1575
|
const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
|
|
1370
1576
|
const prevParams = {
|
|
1371
1577
|
...last(fromMatches)?.params
|
|
1372
1578
|
};
|
|
1373
1579
|
let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
1374
1580
|
if (nextParams) {
|
|
1375
|
-
matches?.map(d => looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
1581
|
+
matches?.map(d => this.looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
1376
1582
|
nextParams = {
|
|
1377
1583
|
...nextParams,
|
|
1378
1584
|
...fn(nextParams)
|
|
@@ -1380,8 +1586,8 @@ function RouterProvider({
|
|
|
1380
1586
|
});
|
|
1381
1587
|
}
|
|
1382
1588
|
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
1383
|
-
const preSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1384
|
-
const postSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1589
|
+
const preSearchFilters = stayingMatches?.map(match => this.looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1590
|
+
const postSearchFilters = stayingMatches?.map(match => this.looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1385
1591
|
|
|
1386
1592
|
// Pre filters first
|
|
1387
1593
|
const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
|
|
@@ -1395,7 +1601,7 @@ function RouterProvider({
|
|
|
1395
1601
|
// Then post filters
|
|
1396
1602
|
const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
1397
1603
|
const search = replaceEqualDeep(from.search, postFilteredSearch);
|
|
1398
|
-
const searchStr = options.stringifySearch(search);
|
|
1604
|
+
const searchStr = this.options.stringifySearch(search);
|
|
1399
1605
|
const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
|
|
1400
1606
|
const hashStr = hash ? `#${hash}` : '';
|
|
1401
1607
|
let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
|
|
@@ -1406,7 +1612,7 @@ function RouterProvider({
|
|
|
1406
1612
|
searchStr,
|
|
1407
1613
|
state: nextState,
|
|
1408
1614
|
hash,
|
|
1409
|
-
href: history.createHref(`${pathname}${searchStr}${hashStr}`),
|
|
1615
|
+
href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
|
|
1410
1616
|
unmaskOnReload: dest.unmaskOnReload
|
|
1411
1617
|
};
|
|
1412
1618
|
};
|
|
@@ -1415,8 +1621,8 @@ function RouterProvider({
|
|
|
1415
1621
|
let maskedNext = maskedDest ? build(maskedDest) : undefined;
|
|
1416
1622
|
if (!maskedNext) {
|
|
1417
1623
|
let params = {};
|
|
1418
|
-
let foundMask = options.routeMasks?.find(d => {
|
|
1419
|
-
const match = matchPathname(basepath, next.pathname, {
|
|
1624
|
+
let foundMask = this.options.routeMasks?.find(d => {
|
|
1625
|
+
const match = matchPathname(this.basepath, next.pathname, {
|
|
1420
1626
|
to: d.from,
|
|
1421
1627
|
caseSensitive: false,
|
|
1422
1628
|
fuzzy: false
|
|
@@ -1436,8 +1642,8 @@ function RouterProvider({
|
|
|
1436
1642
|
maskedNext = build(maskedDest);
|
|
1437
1643
|
}
|
|
1438
1644
|
}
|
|
1439
|
-
const nextMatches = matchRoutes(next.pathname, next.search);
|
|
1440
|
-
const maskedMatches = maskedNext ? matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
|
|
1645
|
+
const nextMatches = this.matchRoutes(next.pathname, next.search);
|
|
1646
|
+
const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
|
|
1441
1647
|
const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
|
|
1442
1648
|
const final = build(dest, nextMatches);
|
|
1443
1649
|
if (maskedFinal) {
|
|
@@ -1452,13 +1658,13 @@ function RouterProvider({
|
|
|
1452
1658
|
});
|
|
1453
1659
|
}
|
|
1454
1660
|
return buildWithMatches(opts);
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1661
|
+
};
|
|
1662
|
+
commitLocation = async ({
|
|
1457
1663
|
startTransition,
|
|
1458
1664
|
...next
|
|
1459
1665
|
}) => {
|
|
1460
|
-
if (
|
|
1461
|
-
const isSameUrl =
|
|
1666
|
+
if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
|
|
1667
|
+
const isSameUrl = this.latestLocation.href === next.href;
|
|
1462
1668
|
|
|
1463
1669
|
// If the next urls are the same and we're not replacing,
|
|
1464
1670
|
// do nothing
|
|
@@ -1485,37 +1691,37 @@ function RouterProvider({
|
|
|
1485
1691
|
}
|
|
1486
1692
|
}
|
|
1487
1693
|
};
|
|
1488
|
-
if (nextHistory.unmaskOnReload ?? options.unmaskOnReload ?? false) {
|
|
1489
|
-
nextHistory.state.__tempKey =
|
|
1694
|
+
if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
|
|
1695
|
+
nextHistory.state.__tempKey = this.tempLocationKey;
|
|
1490
1696
|
}
|
|
1491
1697
|
}
|
|
1492
1698
|
const apply = () => {
|
|
1493
|
-
history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
|
|
1699
|
+
this.history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
|
|
1494
1700
|
};
|
|
1495
1701
|
if (startTransition ?? true) {
|
|
1496
|
-
startReactTransition(apply);
|
|
1702
|
+
this.startReactTransition(apply);
|
|
1497
1703
|
} else {
|
|
1498
1704
|
apply();
|
|
1499
1705
|
}
|
|
1500
1706
|
}
|
|
1501
|
-
|
|
1502
|
-
return
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1707
|
+
this.resetNextScroll = next.resetScroll ?? true;
|
|
1708
|
+
return this.latestLoadPromise;
|
|
1709
|
+
};
|
|
1710
|
+
buildAndCommitLocation = ({
|
|
1505
1711
|
replace,
|
|
1506
1712
|
resetScroll,
|
|
1507
1713
|
startTransition,
|
|
1508
1714
|
...rest
|
|
1509
1715
|
} = {}) => {
|
|
1510
|
-
const location = buildLocation(rest);
|
|
1511
|
-
return commitLocation({
|
|
1716
|
+
const location = this.buildLocation(rest);
|
|
1717
|
+
return this.commitLocation({
|
|
1512
1718
|
...location,
|
|
1513
1719
|
startTransition,
|
|
1514
1720
|
replace,
|
|
1515
1721
|
resetScroll
|
|
1516
1722
|
});
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1723
|
+
};
|
|
1724
|
+
navigate = ({
|
|
1519
1725
|
from,
|
|
1520
1726
|
to = '',
|
|
1521
1727
|
...rest
|
|
@@ -1533,13 +1739,13 @@ function RouterProvider({
|
|
|
1533
1739
|
isExternal = true;
|
|
1534
1740
|
} catch (e) {}
|
|
1535
1741
|
invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
|
|
1536
|
-
return buildAndCommitLocation({
|
|
1742
|
+
return this.buildAndCommitLocation({
|
|
1537
1743
|
...rest,
|
|
1538
1744
|
from: fromString,
|
|
1539
1745
|
to: toString
|
|
1540
1746
|
});
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1747
|
+
};
|
|
1748
|
+
loadMatches = async ({
|
|
1543
1749
|
checkLatest,
|
|
1544
1750
|
matches,
|
|
1545
1751
|
preload
|
|
@@ -1551,7 +1757,7 @@ function RouterProvider({
|
|
|
1551
1757
|
try {
|
|
1552
1758
|
for (let [index, match] of matches.entries()) {
|
|
1553
1759
|
const parentMatch = matches[index - 1];
|
|
1554
|
-
const route = looseRoutesById[match.routeId];
|
|
1760
|
+
const route = this.looseRoutesById[match.routeId];
|
|
1555
1761
|
const handleError = (err, code) => {
|
|
1556
1762
|
err.routerCode = code;
|
|
1557
1763
|
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
@@ -1580,19 +1786,20 @@ function RouterProvider({
|
|
|
1580
1786
|
if (match.searchError) {
|
|
1581
1787
|
handleError(match.searchError, 'VALIDATE_SEARCH');
|
|
1582
1788
|
}
|
|
1583
|
-
const parentContext = parentMatch?.context ?? options.context ?? {};
|
|
1789
|
+
const parentContext = parentMatch?.context ?? this.options.context ?? {};
|
|
1584
1790
|
const beforeLoadContext = (await route.options.beforeLoad?.({
|
|
1585
1791
|
search: match.search,
|
|
1586
1792
|
abortController: match.abortController,
|
|
1587
1793
|
params: match.params,
|
|
1588
1794
|
preload: !!preload,
|
|
1589
1795
|
context: parentContext,
|
|
1590
|
-
location: state.location,
|
|
1591
|
-
|
|
1796
|
+
location: this.state.location,
|
|
1797
|
+
// TOOD: just expose state and router, etc
|
|
1798
|
+
navigate: opts => this.navigate({
|
|
1592
1799
|
...opts,
|
|
1593
1800
|
from: match.pathname
|
|
1594
1801
|
}),
|
|
1595
|
-
buildLocation,
|
|
1802
|
+
buildLocation: this.buildLocation,
|
|
1596
1803
|
cause: match.cause
|
|
1597
1804
|
})) ?? {};
|
|
1598
1805
|
const context = {
|
|
@@ -1610,7 +1817,7 @@ function RouterProvider({
|
|
|
1610
1817
|
}
|
|
1611
1818
|
} catch (err) {
|
|
1612
1819
|
if (isRedirect(err)) {
|
|
1613
|
-
if (!preload) navigate(err);
|
|
1820
|
+
if (!preload) this.navigate(err);
|
|
1614
1821
|
return matches;
|
|
1615
1822
|
}
|
|
1616
1823
|
throw err;
|
|
@@ -1620,11 +1827,11 @@ function RouterProvider({
|
|
|
1620
1827
|
validResolvedMatches.forEach((match, index) => {
|
|
1621
1828
|
matchPromises.push((async () => {
|
|
1622
1829
|
const parentMatchPromise = matchPromises[index - 1];
|
|
1623
|
-
const route = looseRoutesById[match.routeId];
|
|
1830
|
+
const route = this.looseRoutesById[match.routeId];
|
|
1624
1831
|
const handleIfRedirect = err => {
|
|
1625
1832
|
if (isRedirect(err)) {
|
|
1626
1833
|
if (!preload) {
|
|
1627
|
-
navigate(err);
|
|
1834
|
+
this.navigate(err);
|
|
1628
1835
|
}
|
|
1629
1836
|
return true;
|
|
1630
1837
|
}
|
|
@@ -1637,7 +1844,7 @@ function RouterProvider({
|
|
|
1637
1844
|
invalid: false
|
|
1638
1845
|
};
|
|
1639
1846
|
if (match.isFetching) {
|
|
1640
|
-
loadPromise = getRouteMatch(state, match.id)?.loadPromise;
|
|
1847
|
+
loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
|
|
1641
1848
|
} else {
|
|
1642
1849
|
const loaderContext = {
|
|
1643
1850
|
params: match.params,
|
|
@@ -1646,8 +1853,8 @@ function RouterProvider({
|
|
|
1646
1853
|
parentMatchPromise,
|
|
1647
1854
|
abortController: match.abortController,
|
|
1648
1855
|
context: match.context,
|
|
1649
|
-
location: state.location,
|
|
1650
|
-
navigate: opts => navigate({
|
|
1856
|
+
location: this.state.location,
|
|
1857
|
+
navigate: opts => this.navigate({
|
|
1651
1858
|
...opts,
|
|
1652
1859
|
from: match.pathname
|
|
1653
1860
|
}),
|
|
@@ -1695,7 +1902,7 @@ function RouterProvider({
|
|
|
1695
1902
|
loadPromise
|
|
1696
1903
|
};
|
|
1697
1904
|
if (!preload) {
|
|
1698
|
-
setState(s => ({
|
|
1905
|
+
this.setState(s => ({
|
|
1699
1906
|
...s,
|
|
1700
1907
|
matches: s.matches.map(d => d.id === match.id ? match : d)
|
|
1701
1908
|
}));
|
|
@@ -1730,7 +1937,7 @@ function RouterProvider({
|
|
|
1730
1937
|
};
|
|
1731
1938
|
}
|
|
1732
1939
|
if (!preload) {
|
|
1733
|
-
setState(s => ({
|
|
1940
|
+
this.setState(s => ({
|
|
1734
1941
|
...s,
|
|
1735
1942
|
matches: s.matches.map(d => d.id === match.id ? match : d)
|
|
1736
1943
|
}));
|
|
@@ -1739,17 +1946,17 @@ function RouterProvider({
|
|
|
1739
1946
|
});
|
|
1740
1947
|
await Promise.all(matchPromises);
|
|
1741
1948
|
return matches;
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1949
|
+
};
|
|
1950
|
+
load = async () => {
|
|
1744
1951
|
const promise = new Promise(async (resolve, reject) => {
|
|
1745
|
-
const next =
|
|
1746
|
-
const prevLocation = state.resolvedLocation;
|
|
1952
|
+
const next = this.latestLocation;
|
|
1953
|
+
const prevLocation = this.state.resolvedLocation;
|
|
1747
1954
|
const pathDidChange = prevLocation.href !== next.href;
|
|
1748
1955
|
let latestPromise;
|
|
1749
1956
|
|
|
1750
1957
|
// Cancel any pending matches
|
|
1751
|
-
cancelMatches(
|
|
1752
|
-
|
|
1958
|
+
this.cancelMatches();
|
|
1959
|
+
this.emit({
|
|
1753
1960
|
type: 'onBeforeLoad',
|
|
1754
1961
|
fromLocation: prevLocation,
|
|
1755
1962
|
toLocation: next,
|
|
@@ -1757,14 +1964,14 @@ function RouterProvider({
|
|
|
1757
1964
|
});
|
|
1758
1965
|
|
|
1759
1966
|
// Match the routes
|
|
1760
|
-
let matches = matchRoutes(next.pathname, next.search, {
|
|
1967
|
+
let matches = this.matchRoutes(next.pathname, next.search, {
|
|
1761
1968
|
debug: true
|
|
1762
1969
|
});
|
|
1763
|
-
|
|
1764
|
-
const previousMatches = state.matches;
|
|
1970
|
+
this.pendingMatches = matches;
|
|
1971
|
+
const previousMatches = this.state.matches;
|
|
1765
1972
|
|
|
1766
1973
|
// Ingest the new matches
|
|
1767
|
-
setState(s => ({
|
|
1974
|
+
this.setState(s => ({
|
|
1768
1975
|
...s,
|
|
1769
1976
|
status: 'pending',
|
|
1770
1977
|
location: next,
|
|
@@ -1773,9 +1980,9 @@ function RouterProvider({
|
|
|
1773
1980
|
try {
|
|
1774
1981
|
try {
|
|
1775
1982
|
// Load the matches
|
|
1776
|
-
await loadMatches({
|
|
1983
|
+
await this.loadMatches({
|
|
1777
1984
|
matches,
|
|
1778
|
-
checkLatest: () => checkLatest(promise)
|
|
1985
|
+
checkLatest: () => this.checkLatest(promise)
|
|
1779
1986
|
});
|
|
1780
1987
|
} catch (err) {
|
|
1781
1988
|
// swallow this error, since we'll display the
|
|
@@ -1783,12 +1990,12 @@ function RouterProvider({
|
|
|
1783
1990
|
}
|
|
1784
1991
|
|
|
1785
1992
|
// Only apply the latest transition
|
|
1786
|
-
if (latestPromise = checkLatest(promise)) {
|
|
1993
|
+
if (latestPromise = this.checkLatest(promise)) {
|
|
1787
1994
|
return latestPromise;
|
|
1788
1995
|
}
|
|
1789
|
-
const exitingMatchIds = previousMatches.filter(id => !
|
|
1790
|
-
const enteringMatchIds =
|
|
1791
|
-
const stayingMatchIds = previousMatches.filter(id =>
|
|
1996
|
+
const exitingMatchIds = previousMatches.filter(id => !this.pendingMatches.includes(id));
|
|
1997
|
+
const enteringMatchIds = this.pendingMatches.filter(id => !previousMatches.includes(id));
|
|
1998
|
+
const stayingMatchIds = previousMatches.filter(id => this.pendingMatches.includes(id))
|
|
1792
1999
|
|
|
1793
2000
|
// setState((s) => ({
|
|
1794
2001
|
// ...s,
|
|
@@ -1800,10 +2007,10 @@ function RouterProvider({
|
|
|
1800
2007
|
;
|
|
1801
2008
|
[[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matches, hook]) => {
|
|
1802
2009
|
matches.forEach(match => {
|
|
1803
|
-
looseRoutesById[match.routeId].options[hook]?.(match);
|
|
2010
|
+
this.looseRoutesById[match.routeId].options[hook]?.(match);
|
|
1804
2011
|
});
|
|
1805
2012
|
});
|
|
1806
|
-
|
|
2013
|
+
this.emit({
|
|
1807
2014
|
type: 'onLoad',
|
|
1808
2015
|
fromLocation: prevLocation,
|
|
1809
2016
|
toLocation: next,
|
|
@@ -1812,28 +2019,28 @@ function RouterProvider({
|
|
|
1812
2019
|
resolve();
|
|
1813
2020
|
} catch (err) {
|
|
1814
2021
|
// Only apply the latest transition
|
|
1815
|
-
if (latestPromise = checkLatest(promise)) {
|
|
2022
|
+
if (latestPromise = this.checkLatest(promise)) {
|
|
1816
2023
|
return latestPromise;
|
|
1817
2024
|
}
|
|
1818
2025
|
reject(err);
|
|
1819
2026
|
}
|
|
1820
2027
|
});
|
|
1821
|
-
|
|
1822
|
-
return
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
let next = buildLocation(navigateOpts);
|
|
1826
|
-
let matches = matchRoutes(next.pathname, next.search, {
|
|
2028
|
+
this.latestLoadPromise = promise;
|
|
2029
|
+
return this.latestLoadPromise;
|
|
2030
|
+
};
|
|
2031
|
+
preloadRoute = async (navigateOpts = this.state.location) => {
|
|
2032
|
+
let next = this.buildLocation(navigateOpts);
|
|
2033
|
+
let matches = this.matchRoutes(next.pathname, next.search, {
|
|
1827
2034
|
throwOnError: true
|
|
1828
2035
|
});
|
|
1829
|
-
await loadMatches({
|
|
2036
|
+
await this.loadMatches({
|
|
1830
2037
|
matches,
|
|
1831
2038
|
preload: true,
|
|
1832
2039
|
checkLatest: () => undefined
|
|
1833
2040
|
});
|
|
1834
2041
|
return [last(matches), matches];
|
|
1835
|
-
}
|
|
1836
|
-
|
|
2042
|
+
};
|
|
2043
|
+
buildLink = dest => {
|
|
1837
2044
|
// If this link simply reloads the current route,
|
|
1838
2045
|
// make sure it has a new key so it will trigger a data refresh
|
|
1839
2046
|
|
|
@@ -1859,18 +2066,18 @@ function RouterProvider({
|
|
|
1859
2066
|
};
|
|
1860
2067
|
} catch (e) {}
|
|
1861
2068
|
const nextOpts = dest;
|
|
1862
|
-
const next = buildLocation(nextOpts);
|
|
1863
|
-
const preload = userPreload ?? options.defaultPreload;
|
|
1864
|
-
const preloadDelay = userPreloadDelay ?? options.defaultPreloadDelay ?? 0;
|
|
2069
|
+
const next = this.buildLocation(nextOpts);
|
|
2070
|
+
const preload = userPreload ?? this.options.defaultPreload;
|
|
2071
|
+
const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
|
|
1865
2072
|
|
|
1866
2073
|
// Compare path/hash for matches
|
|
1867
|
-
const currentPathSplit =
|
|
2074
|
+
const currentPathSplit = this.latestLocation.pathname.split('/');
|
|
1868
2075
|
const nextPathSplit = next.pathname.split('/');
|
|
1869
2076
|
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
1870
|
-
// Combine the matches based on user options
|
|
1871
|
-
const pathTest = activeOptions?.exact ?
|
|
1872
|
-
const hashTest = activeOptions?.includeHash ?
|
|
1873
|
-
const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(
|
|
2077
|
+
// Combine the matches based on user this.options
|
|
2078
|
+
const pathTest = activeOptions?.exact ? this.latestLocation.pathname === next.pathname : pathIsFuzzyEqual;
|
|
2079
|
+
const hashTest = activeOptions?.includeHash ? this.latestLocation.hash === next.hash : true;
|
|
2080
|
+
const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(this.latestLocation.search, next.search, true) : true;
|
|
1874
2081
|
|
|
1875
2082
|
// The final "active" test
|
|
1876
2083
|
const isActive = pathTest && hashTest && searchTest;
|
|
@@ -1881,7 +2088,7 @@ function RouterProvider({
|
|
|
1881
2088
|
e.preventDefault();
|
|
1882
2089
|
|
|
1883
2090
|
// All is well? Navigate!
|
|
1884
|
-
commitLocation({
|
|
2091
|
+
this.commitLocation({
|
|
1885
2092
|
...next,
|
|
1886
2093
|
replace,
|
|
1887
2094
|
resetScroll,
|
|
@@ -1893,384 +2100,184 @@ function RouterProvider({
|
|
|
1893
2100
|
// The click handler
|
|
1894
2101
|
const handleFocus = e => {
|
|
1895
2102
|
if (preload) {
|
|
1896
|
-
preloadRoute(nextOpts).catch(err => {
|
|
2103
|
+
this.preloadRoute(nextOpts).catch(err => {
|
|
1897
2104
|
console.warn(err);
|
|
1898
2105
|
console.warn(preloadWarning);
|
|
1899
2106
|
});
|
|
1900
2107
|
}
|
|
1901
2108
|
};
|
|
1902
2109
|
const handleTouchStart = e => {
|
|
1903
|
-
preloadRoute(nextOpts).catch(err => {
|
|
2110
|
+
this.preloadRoute(nextOpts).catch(err => {
|
|
1904
2111
|
console.warn(err);
|
|
1905
2112
|
console.warn(preloadWarning);
|
|
1906
2113
|
});
|
|
1907
2114
|
};
|
|
1908
|
-
const handleEnter = e => {
|
|
1909
|
-
const target = e.target || {};
|
|
1910
|
-
if (preload) {
|
|
1911
|
-
if (target.preloadTimeout) {
|
|
1912
|
-
return;
|
|
1913
|
-
}
|
|
1914
|
-
target.preloadTimeout = setTimeout(() => {
|
|
1915
|
-
target.preloadTimeout = null;
|
|
1916
|
-
preloadRoute(nextOpts).catch(err => {
|
|
1917
|
-
console.warn(err);
|
|
1918
|
-
console.warn(preloadWarning);
|
|
1919
|
-
});
|
|
1920
|
-
}, preloadDelay);
|
|
1921
|
-
}
|
|
1922
|
-
};
|
|
1923
|
-
const handleLeave = e => {
|
|
1924
|
-
const target = e.target || {};
|
|
1925
|
-
if (target.preloadTimeout) {
|
|
1926
|
-
clearTimeout(target.preloadTimeout);
|
|
1927
|
-
target.preloadTimeout = null;
|
|
1928
|
-
}
|
|
1929
|
-
};
|
|
1930
|
-
return {
|
|
1931
|
-
type: 'internal',
|
|
1932
|
-
next,
|
|
1933
|
-
handleFocus,
|
|
1934
|
-
handleClick,
|
|
1935
|
-
handleEnter,
|
|
1936
|
-
handleLeave,
|
|
1937
|
-
handleTouchStart,
|
|
1938
|
-
isActive,
|
|
1939
|
-
disabled
|
|
1940
|
-
};
|
|
1941
|
-
});
|
|
1942
|
-
React.useLayoutEffect(() => {
|
|
1943
|
-
const unsub = history.subscribe(() => {
|
|
1944
|
-
latestLocationRef.current = parseLocation(latestLocationRef.current);
|
|
1945
|
-
if (state.location !== latestLocationRef.current) {
|
|
1946
|
-
startReactTransition(() => {
|
|
1947
|
-
try {
|
|
1948
|
-
load();
|
|
1949
|
-
} catch (err) {
|
|
1950
|
-
console.error(err);
|
|
1951
|
-
}
|
|
1952
|
-
});
|
|
1953
|
-
}
|
|
1954
|
-
});
|
|
1955
|
-
const nextLocation = buildLocation({
|
|
1956
|
-
search: true,
|
|
1957
|
-
params: true,
|
|
1958
|
-
hash: true,
|
|
1959
|
-
state: true
|
|
1960
|
-
});
|
|
1961
|
-
if (state.location.href !== nextLocation.href) {
|
|
1962
|
-
commitLocation({
|
|
1963
|
-
...nextLocation,
|
|
1964
|
-
replace: true
|
|
1965
|
-
});
|
|
1966
|
-
}
|
|
1967
|
-
return () => {
|
|
1968
|
-
unsub();
|
|
1969
|
-
};
|
|
1970
|
-
}, [history]);
|
|
1971
|
-
const matchRoute = useStableCallback((location, opts) => {
|
|
1972
|
-
location = {
|
|
1973
|
-
...location,
|
|
1974
|
-
to: location.to ? resolvePathWithBase(location.from || '', location.to) : undefined
|
|
1975
|
-
};
|
|
1976
|
-
const next = buildLocation(location);
|
|
1977
|
-
if (opts?.pending && state.status !== 'pending') {
|
|
1978
|
-
return false;
|
|
1979
|
-
}
|
|
1980
|
-
const baseLocation = opts?.pending ? latestLocationRef.current : state.resolvedLocation;
|
|
1981
|
-
|
|
1982
|
-
// const baseLocation = state.resolvedLocation
|
|
1983
|
-
|
|
1984
|
-
if (!baseLocation) {
|
|
1985
|
-
return false;
|
|
1986
|
-
}
|
|
1987
|
-
const match = matchPathname(basepath, baseLocation.pathname, {
|
|
1988
|
-
...opts,
|
|
1989
|
-
to: next.pathname
|
|
1990
|
-
});
|
|
1991
|
-
if (!match) {
|
|
1992
|
-
return false;
|
|
1993
|
-
}
|
|
1994
|
-
if (match && (opts?.includeSearch ?? true)) {
|
|
1995
|
-
return deepEqual(baseLocation.search, next.search, true) ? match : false;
|
|
1996
|
-
}
|
|
1997
|
-
return match;
|
|
1998
|
-
});
|
|
1999
|
-
const injectedHtmlRef = React.useRef([]);
|
|
2000
|
-
const injectHtml = useStableCallback(async html => {
|
|
2001
|
-
injectedHtmlRef.current.push(html);
|
|
2002
|
-
});
|
|
2003
|
-
const dehydrateData = useStableCallback((key, getData) => {
|
|
2004
|
-
if (typeof document === 'undefined') {
|
|
2005
|
-
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
2006
|
-
injectHtml(async () => {
|
|
2007
|
-
const id = `__TSR_DEHYDRATED__${strKey}`;
|
|
2008
|
-
const data = typeof getData === 'function' ? await getData() : getData;
|
|
2009
|
-
return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
|
|
2010
|
-
;(() => {
|
|
2011
|
-
var el = document.getElementById('${id}')
|
|
2012
|
-
el.parentElement.removeChild(el)
|
|
2013
|
-
})()
|
|
2014
|
-
</script>`;
|
|
2015
|
-
});
|
|
2016
|
-
return () => hydrateData(key);
|
|
2017
|
-
}
|
|
2018
|
-
return () => undefined;
|
|
2019
|
-
});
|
|
2020
|
-
const hydrateData = useStableCallback(key => {
|
|
2021
|
-
if (typeof document !== 'undefined') {
|
|
2022
|
-
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
2023
|
-
return window[`__TSR_DEHYDRATED__${strKey}`];
|
|
2024
|
-
}
|
|
2025
|
-
return undefined;
|
|
2026
|
-
});
|
|
2027
|
-
React.useLayoutEffect(() => {
|
|
2028
|
-
startReactTransition(() => {
|
|
2029
|
-
try {
|
|
2030
|
-
load();
|
|
2031
|
-
} catch (err) {
|
|
2032
|
-
console.error(err);
|
|
2033
|
-
}
|
|
2034
|
-
});
|
|
2035
|
-
}, []);
|
|
2036
|
-
const routerContextValue = {
|
|
2037
|
-
routeTree: router.routeTree,
|
|
2038
|
-
navigate,
|
|
2039
|
-
buildLink,
|
|
2040
|
-
state,
|
|
2041
|
-
matchRoute,
|
|
2042
|
-
routesById,
|
|
2043
|
-
options,
|
|
2044
|
-
history,
|
|
2045
|
-
load,
|
|
2046
|
-
buildLocation,
|
|
2047
|
-
subscribe: router.subscribe,
|
|
2048
|
-
resetNextScrollRef,
|
|
2049
|
-
injectedHtmlRef,
|
|
2050
|
-
injectHtml,
|
|
2051
|
-
dehydrateData,
|
|
2052
|
-
hydrateData
|
|
2053
|
-
};
|
|
2054
|
-
return /*#__PURE__*/React.createElement(routerContext.Provider, {
|
|
2055
|
-
value: routerContextValue
|
|
2056
|
-
}, /*#__PURE__*/React.createElement(Matches, null));
|
|
2057
|
-
}
|
|
2058
|
-
function getRouteMatch(state, id) {
|
|
2059
|
-
return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
|
|
2060
|
-
}
|
|
2061
|
-
function useRouterState(opts) {
|
|
2062
|
-
const {
|
|
2063
|
-
state
|
|
2064
|
-
} = useRouter();
|
|
2065
|
-
// return useStore(router.__store, opts?.select as any)
|
|
2066
|
-
return opts?.select ? opts.select(state) : state;
|
|
2067
|
-
}
|
|
2068
|
-
function useRouter() {
|
|
2069
|
-
const resolvedContext = window.__TSR_ROUTER_CONTEXT__ || routerContext;
|
|
2070
|
-
const value = React.useContext(resolvedContext);
|
|
2071
|
-
warning(value, 'useRouter must be used inside a <RouterProvider> component!');
|
|
2072
|
-
return value;
|
|
2073
|
-
}
|
|
2074
|
-
|
|
2075
|
-
function defer(_promise) {
|
|
2076
|
-
const promise = _promise;
|
|
2077
|
-
if (!promise.__deferredState) {
|
|
2078
|
-
promise.__deferredState = {
|
|
2079
|
-
uid: Math.random().toString(36).slice(2),
|
|
2080
|
-
status: 'pending'
|
|
2081
|
-
};
|
|
2082
|
-
const state = promise.__deferredState;
|
|
2083
|
-
promise.then(data => {
|
|
2084
|
-
state.status = 'success';
|
|
2085
|
-
state.data = data;
|
|
2086
|
-
}).catch(error => {
|
|
2087
|
-
state.status = 'error';
|
|
2088
|
-
state.error = error;
|
|
2089
|
-
});
|
|
2090
|
-
}
|
|
2091
|
-
return promise;
|
|
2092
|
-
}
|
|
2093
|
-
function isDehydratedDeferred(obj) {
|
|
2094
|
-
return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
|
-
function useAwaited({
|
|
2098
|
-
promise
|
|
2099
|
-
}) {
|
|
2100
|
-
const router = useRouter();
|
|
2101
|
-
let state = promise.__deferredState;
|
|
2102
|
-
const key = `__TSR__DEFERRED__${state.uid}`;
|
|
2103
|
-
if (isDehydratedDeferred(promise)) {
|
|
2104
|
-
state = router.hydrateData(key);
|
|
2105
|
-
promise = Promise.resolve(state.data);
|
|
2106
|
-
promise.__deferredState = state;
|
|
2107
|
-
}
|
|
2108
|
-
if (state.status === 'pending') {
|
|
2109
|
-
throw promise;
|
|
2110
|
-
}
|
|
2111
|
-
if (state.status === 'error') {
|
|
2112
|
-
throw state.error;
|
|
2113
|
-
}
|
|
2114
|
-
router.dehydrateData(key, state);
|
|
2115
|
-
return [state.data];
|
|
2116
|
-
}
|
|
2117
|
-
function Await(props) {
|
|
2118
|
-
const awaited = useAwaited(props);
|
|
2119
|
-
return props.children(...awaited);
|
|
2120
|
-
}
|
|
2121
|
-
|
|
2122
|
-
class FileRoute {
|
|
2123
|
-
constructor(path) {
|
|
2124
|
-
this.path = path;
|
|
2125
|
-
}
|
|
2126
|
-
createRoute = options => {
|
|
2127
|
-
const route = new Route(options);
|
|
2128
|
-
route.isRoot = false;
|
|
2129
|
-
return route;
|
|
2130
|
-
};
|
|
2131
|
-
}
|
|
2132
|
-
|
|
2133
|
-
function lazyRouteComponent(importer, exportName) {
|
|
2134
|
-
let loadPromise;
|
|
2135
|
-
const load = () => {
|
|
2136
|
-
if (!loadPromise) {
|
|
2137
|
-
loadPromise = importer();
|
|
2138
|
-
}
|
|
2139
|
-
return loadPromise;
|
|
2140
|
-
};
|
|
2141
|
-
const lazyComp = /*#__PURE__*/React.lazy(async () => {
|
|
2142
|
-
const moduleExports = await load();
|
|
2143
|
-
const comp = moduleExports[exportName ?? 'default'];
|
|
2144
|
-
return {
|
|
2145
|
-
default: comp
|
|
2146
|
-
};
|
|
2147
|
-
});
|
|
2148
|
-
lazyComp.preload = load;
|
|
2149
|
-
return lazyComp;
|
|
2150
|
-
}
|
|
2151
|
-
|
|
2152
|
-
function _extends() {
|
|
2153
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
2154
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
2155
|
-
var source = arguments[i];
|
|
2156
|
-
for (var key in source) {
|
|
2157
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
2158
|
-
target[key] = source[key];
|
|
2115
|
+
const handleEnter = e => {
|
|
2116
|
+
const target = e.target || {};
|
|
2117
|
+
if (preload) {
|
|
2118
|
+
if (target.preloadTimeout) {
|
|
2119
|
+
return;
|
|
2159
2120
|
}
|
|
2121
|
+
target.preloadTimeout = setTimeout(() => {
|
|
2122
|
+
target.preloadTimeout = null;
|
|
2123
|
+
this.preloadRoute(nextOpts).catch(err => {
|
|
2124
|
+
console.warn(err);
|
|
2125
|
+
console.warn(preloadWarning);
|
|
2126
|
+
});
|
|
2127
|
+
}, preloadDelay);
|
|
2160
2128
|
}
|
|
2161
|
-
}
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
buildLink
|
|
2170
|
-
} = useRouter();
|
|
2171
|
-
const match = useMatch({
|
|
2172
|
-
strict: false
|
|
2173
|
-
});
|
|
2174
|
-
const {
|
|
2175
|
-
// custom props
|
|
2176
|
-
type,
|
|
2177
|
-
children,
|
|
2178
|
-
target,
|
|
2179
|
-
activeProps = () => ({
|
|
2180
|
-
className: 'active'
|
|
2181
|
-
}),
|
|
2182
|
-
inactiveProps = () => ({}),
|
|
2183
|
-
activeOptions,
|
|
2184
|
-
disabled,
|
|
2185
|
-
hash,
|
|
2186
|
-
search,
|
|
2187
|
-
params,
|
|
2188
|
-
to,
|
|
2189
|
-
state,
|
|
2190
|
-
mask,
|
|
2191
|
-
preload,
|
|
2192
|
-
preloadDelay,
|
|
2193
|
-
replace,
|
|
2194
|
-
startTransition,
|
|
2195
|
-
resetScroll,
|
|
2196
|
-
// element props
|
|
2197
|
-
style,
|
|
2198
|
-
className,
|
|
2199
|
-
onClick,
|
|
2200
|
-
onFocus,
|
|
2201
|
-
onMouseEnter,
|
|
2202
|
-
onMouseLeave,
|
|
2203
|
-
onTouchStart,
|
|
2204
|
-
...rest
|
|
2205
|
-
} = options;
|
|
2206
|
-
const linkInfo = buildLink({
|
|
2207
|
-
from: options.to ? match.pathname : undefined,
|
|
2208
|
-
...options
|
|
2209
|
-
});
|
|
2210
|
-
if (linkInfo.type === 'external') {
|
|
2211
|
-
const {
|
|
2212
|
-
href
|
|
2213
|
-
} = linkInfo;
|
|
2129
|
+
};
|
|
2130
|
+
const handleLeave = e => {
|
|
2131
|
+
const target = e.target || {};
|
|
2132
|
+
if (target.preloadTimeout) {
|
|
2133
|
+
clearTimeout(target.preloadTimeout);
|
|
2134
|
+
target.preloadTimeout = null;
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2214
2137
|
return {
|
|
2215
|
-
|
|
2138
|
+
type: 'internal',
|
|
2139
|
+
next,
|
|
2140
|
+
handleFocus,
|
|
2141
|
+
handleClick,
|
|
2142
|
+
handleEnter,
|
|
2143
|
+
handleLeave,
|
|
2144
|
+
handleTouchStart,
|
|
2145
|
+
isActive,
|
|
2146
|
+
disabled
|
|
2216
2147
|
};
|
|
2217
|
-
}
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2148
|
+
};
|
|
2149
|
+
matchRoute = (location, opts) => {
|
|
2150
|
+
location = {
|
|
2151
|
+
...location,
|
|
2152
|
+
to: location.to ? this.resolvePathWithBase(location.from || '', location.to) : undefined
|
|
2153
|
+
};
|
|
2154
|
+
const next = this.buildLocation(location);
|
|
2155
|
+
if (opts?.pending && this.state.status !== 'pending') {
|
|
2156
|
+
return false;
|
|
2157
|
+
}
|
|
2158
|
+
const baseLocation = opts?.pending ? this.latestLocation : this.state.resolvedLocation;
|
|
2159
|
+
|
|
2160
|
+
// const baseLocation = state.resolvedLocation
|
|
2161
|
+
|
|
2162
|
+
if (!baseLocation) {
|
|
2163
|
+
return false;
|
|
2164
|
+
}
|
|
2165
|
+
const match = matchPathname(this.basepath, baseLocation.pathname, {
|
|
2166
|
+
...opts,
|
|
2167
|
+
to: next.pathname
|
|
2232
2168
|
});
|
|
2169
|
+
if (!match) {
|
|
2170
|
+
return false;
|
|
2171
|
+
}
|
|
2172
|
+
if (match && (opts?.includeSearch ?? true)) {
|
|
2173
|
+
return deepEqual(baseLocation.search, next.search, true) ? match : false;
|
|
2174
|
+
}
|
|
2175
|
+
return match;
|
|
2176
|
+
};
|
|
2177
|
+
injectHtml = async html => {
|
|
2178
|
+
this.injectedHtml.push(html);
|
|
2179
|
+
};
|
|
2180
|
+
dehydrateData = (key, getData) => {
|
|
2181
|
+
if (typeof document === 'undefined') {
|
|
2182
|
+
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
2183
|
+
this.injectHtml(async () => {
|
|
2184
|
+
const id = `__TSR_DEHYDRATED__${strKey}`;
|
|
2185
|
+
const data = typeof getData === 'function' ? await getData() : getData;
|
|
2186
|
+
return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
|
|
2187
|
+
;(() => {
|
|
2188
|
+
var el = document.getElementById('${id}')
|
|
2189
|
+
el.parentElement.removeChild(el)
|
|
2190
|
+
})()
|
|
2191
|
+
</script>`;
|
|
2192
|
+
});
|
|
2193
|
+
return () => this.hydrateData(key);
|
|
2194
|
+
}
|
|
2195
|
+
return () => undefined;
|
|
2196
|
+
};
|
|
2197
|
+
hydrateData = key => {
|
|
2198
|
+
if (typeof document !== 'undefined') {
|
|
2199
|
+
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
2200
|
+
return window[`__TSR_DEHYDRATED__${strKey}`];
|
|
2201
|
+
}
|
|
2202
|
+
return undefined;
|
|
2233
2203
|
};
|
|
2234
2204
|
|
|
2235
|
-
//
|
|
2236
|
-
|
|
2205
|
+
// dehydrate = (): DehydratedRouter => {
|
|
2206
|
+
// return {
|
|
2207
|
+
// state: {
|
|
2208
|
+
// dehydratedMatches: this.state.matches.map((d) =>
|
|
2209
|
+
// pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt']),
|
|
2210
|
+
// ),
|
|
2211
|
+
// },
|
|
2212
|
+
// }
|
|
2213
|
+
// }
|
|
2237
2214
|
|
|
2238
|
-
//
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2215
|
+
// hydrate = async (__do_not_use_server_ctx?: HydrationCtx) => {
|
|
2216
|
+
// let _ctx = __do_not_use_server_ctx
|
|
2217
|
+
// // Client hydrates from window
|
|
2218
|
+
// if (typeof document !== 'undefined') {
|
|
2219
|
+
// _ctx = window.__TSR_DEHYDRATED__
|
|
2220
|
+
// }
|
|
2221
|
+
|
|
2222
|
+
// invariant(
|
|
2223
|
+
// _ctx,
|
|
2224
|
+
// 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?',
|
|
2225
|
+
// )
|
|
2226
|
+
|
|
2227
|
+
// const ctx = _ctx
|
|
2228
|
+
// this.dehydratedData = ctx.payload as any
|
|
2229
|
+
// this.options.hydrate?.(ctx.payload as any)
|
|
2230
|
+
// const dehydratedState = ctx.router.state
|
|
2231
|
+
|
|
2232
|
+
// let matches = this.matchRoutes(
|
|
2233
|
+
// this.state.location.pathname,
|
|
2234
|
+
// this.state.location.search,
|
|
2235
|
+
// ).map((match) => {
|
|
2236
|
+
// const dehydratedMatch = dehydratedState.dehydratedMatches.find(
|
|
2237
|
+
// (d) => d.id === match.id,
|
|
2238
|
+
// )
|
|
2239
|
+
|
|
2240
|
+
// invariant(
|
|
2241
|
+
// dehydratedMatch,
|
|
2242
|
+
// `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
|
|
2243
|
+
// )
|
|
2244
|
+
|
|
2245
|
+
// if (dehydratedMatch) {
|
|
2246
|
+
// return {
|
|
2247
|
+
// ...match,
|
|
2248
|
+
// ...dehydratedMatch,
|
|
2249
|
+
// }
|
|
2250
|
+
// }
|
|
2251
|
+
// return match
|
|
2252
|
+
// })
|
|
2253
|
+
|
|
2254
|
+
// this.setState((s) => {
|
|
2255
|
+
// return {
|
|
2256
|
+
// ...s,
|
|
2257
|
+
// matches: dehydratedState.dehydratedMatches as any,
|
|
2258
|
+
// }
|
|
2259
|
+
// })
|
|
2260
|
+
// }
|
|
2261
|
+
|
|
2262
|
+
// resolveMatchPromise = (matchId: string, key: string, value: any) => {
|
|
2263
|
+
// state.matches
|
|
2264
|
+
// .find((d) => d.id === matchId)
|
|
2265
|
+
// ?.__promisesByKey[key]?.resolve(value)
|
|
2266
|
+
// }
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
// A function that takes an import() argument which is a function and returns a new function that will
|
|
2270
|
+
// proxy arguments from the caller to the imported function, retaining all type
|
|
2271
|
+
// information along the way
|
|
2272
|
+
function lazyFn(fn, key) {
|
|
2273
|
+
return async (...args) => {
|
|
2274
|
+
const imported = await fn();
|
|
2275
|
+
return imported[key || 'default'](...args);
|
|
2262
2276
|
};
|
|
2263
2277
|
}
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
ref: ref
|
|
2268
|
-
}, linkProps, {
|
|
2269
|
-
children: typeof props.children === 'function' ? props.children({
|
|
2270
|
-
isActive: linkProps['data-status'] === 'active'
|
|
2271
|
-
}) : props.children
|
|
2272
|
-
}));
|
|
2273
|
-
});
|
|
2278
|
+
function isCtrlEvent(e) {
|
|
2279
|
+
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
2280
|
+
}
|
|
2274
2281
|
|
|
2275
2282
|
const useLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
|
|
2276
2283
|
const windowKey = 'window';
|
|
@@ -2280,11 +2287,7 @@ let cache;
|
|
|
2280
2287
|
const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
|
|
2281
2288
|
const defaultGetKey = location => location.state.key;
|
|
2282
2289
|
function useScrollRestoration(options) {
|
|
2283
|
-
const
|
|
2284
|
-
state,
|
|
2285
|
-
subscribe,
|
|
2286
|
-
resetNextScrollRef
|
|
2287
|
-
} = useRouter();
|
|
2290
|
+
const router = useRouter();
|
|
2288
2291
|
useLayoutEffect(() => {
|
|
2289
2292
|
const getKey = options?.getKey || defaultGetKey;
|
|
2290
2293
|
if (sessionsStorage) {
|
|
@@ -2340,7 +2343,7 @@ function useScrollRestoration(options) {
|
|
|
2340
2343
|
if (typeof document !== 'undefined') {
|
|
2341
2344
|
document.addEventListener('scroll', onScroll, true);
|
|
2342
2345
|
}
|
|
2343
|
-
const unsubOnBeforeLoad = subscribe('onBeforeLoad', event => {
|
|
2346
|
+
const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
|
|
2344
2347
|
if (event.pathChanged) {
|
|
2345
2348
|
const restoreKey = getKey(event.fromLocation);
|
|
2346
2349
|
for (const elementSelector in cache.state.next) {
|
|
@@ -2370,12 +2373,12 @@ function useScrollRestoration(options) {
|
|
|
2370
2373
|
}
|
|
2371
2374
|
}
|
|
2372
2375
|
});
|
|
2373
|
-
const unsubOnResolved = subscribe('onResolved', event => {
|
|
2376
|
+
const unsubOnResolved = router.subscribe('onResolved', event => {
|
|
2374
2377
|
if (event.pathChanged) {
|
|
2375
|
-
if (!
|
|
2378
|
+
if (!router.resetNextScroll) {
|
|
2376
2379
|
return;
|
|
2377
2380
|
}
|
|
2378
|
-
|
|
2381
|
+
router.resetNextScroll = true;
|
|
2379
2382
|
const getKey = options?.getKey || defaultGetKey;
|
|
2380
2383
|
const restoreKey = getKey(event.toLocation);
|
|
2381
2384
|
let windowRestored = false;
|