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