@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.
Files changed (65) hide show
  1. package/build/cjs/CatchBoundary.js +3 -6
  2. package/build/cjs/CatchBoundary.js.map +1 -1
  3. package/build/cjs/Matches.js +8 -15
  4. package/build/cjs/Matches.js.map +1 -1
  5. package/build/cjs/RouterProvider.js +61 -968
  6. package/build/cjs/RouterProvider.js.map +1 -1
  7. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +1 -3
  8. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
  9. package/build/cjs/awaited.js +0 -2
  10. package/build/cjs/awaited.js.map +1 -1
  11. package/build/cjs/defer.js +0 -2
  12. package/build/cjs/defer.js.map +1 -1
  13. package/build/cjs/fileRoute.js +0 -2
  14. package/build/cjs/fileRoute.js.map +1 -1
  15. package/build/cjs/index.js +3 -16
  16. package/build/cjs/index.js.map +1 -1
  17. package/build/cjs/lazyRouteComponent.js +3 -6
  18. package/build/cjs/lazyRouteComponent.js.map +1 -1
  19. package/build/cjs/link.js +4 -7
  20. package/build/cjs/link.js.map +1 -1
  21. package/build/cjs/path.js +0 -2
  22. package/build/cjs/path.js.map +1 -1
  23. package/build/cjs/qss.js +0 -2
  24. package/build/cjs/qss.js.map +1 -1
  25. package/build/cjs/redirects.js +0 -2
  26. package/build/cjs/redirects.js.map +1 -1
  27. package/build/cjs/route.js +2 -7
  28. package/build/cjs/route.js.map +1 -1
  29. package/build/cjs/router.js +949 -42
  30. package/build/cjs/router.js.map +1 -1
  31. package/build/cjs/scroll-restoration.js +8 -15
  32. package/build/cjs/scroll-restoration.js.map +1 -1
  33. package/build/cjs/searchParams.js +0 -2
  34. package/build/cjs/searchParams.js.map +1 -1
  35. package/build/cjs/useBlocker.js +3 -6
  36. package/build/cjs/useBlocker.js.map +1 -1
  37. package/build/cjs/useNavigate.js +3 -6
  38. package/build/cjs/useNavigate.js.map +1 -1
  39. package/build/cjs/useParams.js +0 -2
  40. package/build/cjs/useParams.js.map +1 -1
  41. package/build/cjs/useSearch.js +0 -2
  42. package/build/cjs/useSearch.js.map +1 -1
  43. package/build/cjs/utils.js +9 -6
  44. package/build/cjs/utils.js.map +1 -1
  45. package/build/esm/index.js +889 -878
  46. package/build/esm/index.js.map +1 -1
  47. package/build/stats-html.html +3494 -2700
  48. package/build/stats-react.json +374 -368
  49. package/build/types/CatchBoundary.d.ts +2 -2
  50. package/build/types/Matches.d.ts +3 -3
  51. package/build/types/RouterProvider.d.ts +4 -23
  52. package/build/types/awaited.d.ts +1 -0
  53. package/build/types/fileRoute.d.ts +4 -3
  54. package/build/types/route.d.ts +1 -0
  55. package/build/types/router.d.ts +50 -5
  56. package/build/umd/index.development.js +865 -857
  57. package/build/umd/index.development.js.map +1 -1
  58. package/build/umd/index.production.js +2 -2
  59. package/build/umd/index.production.js.map +1 -1
  60. package/package.json +2 -2
  61. package/src/RouterProvider.tsx +57 -1314
  62. package/src/fileRoute.ts +1 -1
  63. package/src/route.ts +23 -0
  64. package/src/router.ts +1320 -45
  65. package/src/scroll-restoration.tsx +5 -5
@@ -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
- // Detect if we're in the DOM
783
-
784
- function redirect(opts) {
785
- opts.isRedirect = true;
786
- return opts;
787
- }
788
- function isRedirect(obj) {
789
- return !!obj?.isRedirect;
790
- }
791
-
792
- // @ts-nocheck
793
-
794
- // 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.
795
-
796
- function encode(obj, pfx) {
797
- var k,
798
- i,
799
- tmp,
800
- str = '';
801
- for (k in obj) {
802
- if ((tmp = obj[k]) !== void 0) {
803
- if (Array.isArray(tmp)) {
804
- for (i = 0; i < tmp.length; i++) {
805
- str && (str += '&');
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
- const options = {
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 latestLocationRef = React.useRef(parseLocation());
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 ? latestLocationRef.current : preState.location,
1124
- pendingMatches: pendingMatchesRef.current
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
- pendingMatchesRef.current = [];
891
+ router.pendingMatches = [];
1135
892
  setState(s => ({
1136
893
  ...s,
1137
894
  resolvedLocation: s.location
1138
895
  }));
1139
896
  }
1140
897
  });
1141
- const basepath = `/${trimPath(options.basepath ?? '') ?? ''}`;
1142
- const resolvePathWithBase = useStableCallback((from, path) => {
1143
- return resolvePath(basepath, from, cleanPath(path));
1144
- });
1145
- const [routesById, routesByPath] = React.useMemo(() => {
1146
- const routesById = {};
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
- return {
1188
- child: d,
1189
- trimmed,
1190
- parsed,
1191
- index: i,
1192
- score
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
- }).sort((a, b) => {
1195
- let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
1196
- if (isIndex !== 0) return isIndex;
1197
- const length = Math.min(a.score.length, b.score.length);
1198
-
1199
- // Sort by length of score
1200
- if (a.score.length !== b.score.length) {
1201
- return b.score.length - a.score.length;
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
- // Sort by min available score
1205
- for (let i = 0; i < length; i++) {
1206
- if (a.score[i] !== b.score[i]) {
1207
- return b.score[i] - a.score[i];
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
- // Sort by min available parsed value
1212
- for (let i = 0; i < length; i++) {
1213
- if (a.parsed[i].value !== b.parsed[i].value) {
1214
- return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
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
- // Sort by length of trimmed full path
1219
- if (a.trimmed !== b.trimmed) {
1220
- return a.trimmed > b.trimmed ? 1 : -1;
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
- // Sort by original index
1224
- return a.index - b.index;
1225
- }).map((d, i) => {
1226
- d.child.rank = i;
1227
- return d.child;
1228
- }), [routesByPath]);
1229
- const matchRoutes = useStableCallback((pathname, locationSearch, opts) => {
1230
- let routeParams = {};
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
- // Existing matches are matches that are already loaded along with
1252
- // pending matches that are still loading
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
- const parseErrors = matchedRoutes.map(route => {
1255
- let parsedParamsError;
1256
- if (route.options.parseParams) {
1257
- try {
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
- const cancelMatch = useStableCallback(id => {
1356
- getRouteMatch(state, id)?.abortController?.abort();
1357
- });
1358
- const cancelMatches = useStableCallback(state => {
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
- const buildLocation = useStableCallback(opts => {
1576
+ };
1577
+ buildLocation = opts => {
1364
1578
  const build = (dest = {}, matches) => {
1365
- const from = latestLocationRef.current;
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
- const commitLocation = useStableCallback(async ({
1669
+ };
1670
+ commitLocation = async ({
1457
1671
  startTransition,
1458
1672
  ...next
1459
1673
  }) => {
1460
- if (navigateTimeoutRef.current) clearTimeout(navigateTimeoutRef.current);
1461
- const isSameUrl = latestLocationRef.current.href === next.href;
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 = tempLocationKeyRef.current;
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
- resetNextScrollRef.current = next.resetScroll ?? true;
1502
- return latestLoadPromiseRef.current;
1503
- });
1504
- const buildAndCommitLocation = useStableCallback(({
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
- const navigate = useStableCallback(({
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
- const loadMatches = useStableCallback(async ({
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
- navigate: opts => navigate({
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
- const load = useStableCallback(async () => {
1957
+ };
1958
+ load = async () => {
1744
1959
  const promise = new Promise(async (resolve, reject) => {
1745
- const next = latestLocationRef.current;
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(state);
1752
- router.emit({
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
- pendingMatchesRef.current = matches;
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 => !pendingMatchesRef.current.includes(id));
1790
- const enteringMatchIds = pendingMatchesRef.current.filter(id => !previousMatches.includes(id));
1791
- const stayingMatchIds = previousMatches.filter(id => pendingMatchesRef.current.includes(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
- router.emit({
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
- latestLoadPromiseRef.current = promise;
1822
- return latestLoadPromiseRef.current;
1823
- });
1824
- const preloadRoute = useStableCallback(async (navigateOpts = state.location) => {
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
- const buildLink = useStableCallback(dest => {
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 = latestLocationRef.current.pathname.split('/');
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 ? latestLocationRef.current.pathname === next.pathname : pathIsFuzzyEqual;
1872
- const hashTest = activeOptions?.includeHash ? latestLocationRef.current.hash === next.hash : true;
1873
- const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(latestLocationRef.current.search, next.search, true) : true;
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
- return target;
2163
- };
2164
- return _extends.apply(this, arguments);
2165
- }
2166
-
2167
- function useLinkProps(options) {
2168
- const {
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
- href
2146
+ type: 'internal',
2147
+ next,
2148
+ handleFocus,
2149
+ handleClick,
2150
+ handleEnter,
2151
+ handleLeave,
2152
+ handleTouchStart,
2153
+ isActive,
2154
+ disabled
2216
2155
  };
2217
- }
2218
- const {
2219
- handleClick,
2220
- handleFocus,
2221
- handleEnter,
2222
- handleLeave,
2223
- handleTouchStart,
2224
- isActive,
2225
- next
2226
- } = linkInfo;
2227
- const composeHandlers = handlers => e => {
2228
- if (e.persist) e.persist();
2229
- handlers.filter(Boolean).forEach(handler => {
2230
- if (e.defaultPrevented) return;
2231
- handler(e);
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
- // Get the active props
2236
- const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {};
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
- // Get the inactive props
2239
- const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
2240
- return {
2241
- ...resolvedActiveProps,
2242
- ...resolvedInactiveProps,
2243
- ...rest,
2244
- href: disabled ? undefined : next.maskedLocation ? next.maskedLocation.href : next.href,
2245
- onClick: composeHandlers([onClick, handleClick]),
2246
- onFocus: composeHandlers([onFocus, handleFocus]),
2247
- onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
2248
- onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
2249
- onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
2250
- target,
2251
- style: {
2252
- ...style,
2253
- ...resolvedActiveProps.style,
2254
- ...resolvedInactiveProps.style
2255
- },
2256
- className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
2257
- ...(disabled ? {
2258
- role: 'link',
2259
- 'aria-disabled': true
2260
- } : undefined),
2261
- ['data-status']: isActive ? 'active' : undefined
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
- const Link = /*#__PURE__*/React.forwardRef((props, ref) => {
2265
- const linkProps = useLinkProps(props);
2266
- return /*#__PURE__*/React.createElement("a", _extends({
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 (!resetNextScrollRef.current) {
2386
+ if (!router.resetNextScroll) {
2376
2387
  return;
2377
2388
  }
2378
- resetNextScrollRef.current = true;
2389
+ router.resetNextScroll = true;
2379
2390
  const getKey = options?.getKey || defaultGetKey;
2380
2391
  const restoreKey = getKey(event.toLocation);
2381
2392
  let windowRestored = false;