@tanstack/react-router 0.0.1-beta.204 → 0.0.1-beta.206

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 (73) hide show
  1. package/build/cjs/RouterProvider.js +963 -0
  2. package/build/cjs/RouterProvider.js.map +1 -0
  3. package/build/cjs/fileRoute.js +29 -0
  4. package/build/cjs/fileRoute.js.map +1 -0
  5. package/build/cjs/index.js +69 -21
  6. package/build/cjs/index.js.map +1 -1
  7. package/build/cjs/path.js +211 -0
  8. package/build/cjs/path.js.map +1 -0
  9. package/build/cjs/qss.js +65 -0
  10. package/build/cjs/qss.js.map +1 -0
  11. package/build/cjs/react.js +148 -190
  12. package/build/cjs/react.js.map +1 -1
  13. package/build/cjs/redirects.js +27 -0
  14. package/build/cjs/redirects.js.map +1 -0
  15. package/build/cjs/route.js +136 -0
  16. package/build/cjs/route.js.map +1 -0
  17. package/build/cjs/router.js +203 -0
  18. package/build/cjs/router.js.map +1 -0
  19. package/build/cjs/searchParams.js +83 -0
  20. package/build/cjs/searchParams.js.map +1 -0
  21. package/build/cjs/utils.js +196 -0
  22. package/build/cjs/utils.js.map +1 -0
  23. package/build/esm/index.js +1801 -211
  24. package/build/esm/index.js.map +1 -1
  25. package/build/stats-html.html +1 -1
  26. package/build/stats-react.json +385 -164
  27. package/build/types/RouteMatch.d.ts +23 -0
  28. package/build/types/RouterProvider.d.ts +54 -0
  29. package/build/types/awaited.d.ts +0 -8
  30. package/build/types/defer.d.ts +0 -0
  31. package/build/types/fileRoute.d.ts +17 -0
  32. package/build/types/history.d.ts +7 -0
  33. package/build/types/index.d.ts +17 -4
  34. package/build/types/link.d.ts +98 -0
  35. package/build/types/location.d.ts +14 -0
  36. package/build/types/path.d.ts +16 -0
  37. package/build/types/qss.d.ts +2 -0
  38. package/build/types/react.d.ts +23 -83
  39. package/build/types/redirects.d.ts +10 -0
  40. package/build/types/route.d.ts +222 -0
  41. package/build/types/routeInfo.d.ts +22 -0
  42. package/build/types/router.d.ts +115 -0
  43. package/build/types/scroll-restoration.d.ts +0 -3
  44. package/build/types/searchParams.d.ts +7 -0
  45. package/build/types/utils.d.ts +48 -0
  46. package/build/umd/index.development.js +1118 -1540
  47. package/build/umd/index.development.js.map +1 -1
  48. package/build/umd/index.production.js +2 -33
  49. package/build/umd/index.production.js.map +1 -1
  50. package/package.json +2 -4
  51. package/src/RouteMatch.ts +28 -0
  52. package/src/RouterProvider.tsx +1390 -0
  53. package/src/awaited.tsx +40 -40
  54. package/src/defer.ts +55 -0
  55. package/src/fileRoute.ts +143 -0
  56. package/src/history.ts +8 -0
  57. package/src/index.tsx +18 -5
  58. package/src/link.ts +347 -0
  59. package/src/location.ts +14 -0
  60. package/src/path.ts +256 -0
  61. package/src/qss.ts +53 -0
  62. package/src/react.tsx +174 -422
  63. package/src/redirects.ts +31 -0
  64. package/src/route.ts +710 -0
  65. package/src/routeInfo.ts +68 -0
  66. package/src/router.ts +373 -0
  67. package/src/scroll-restoration.tsx +205 -27
  68. package/src/searchParams.ts +78 -0
  69. package/src/utils.ts +257 -0
  70. package/build/cjs/awaited.js +0 -45
  71. package/build/cjs/awaited.js.map +0 -1
  72. package/build/cjs/scroll-restoration.js +0 -56
  73. package/build/cjs/scroll-restoration.js.map +0 -1
@@ -9,10 +9,10 @@
9
9
  * @license MIT
10
10
  */
11
11
  (function (global, factory) {
12
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('use-sync-external-store/shim/with-selector'), require('react')) :
13
- typeof define === 'function' && define.amd ? define(['exports', 'use-sync-external-store/shim/with-selector', 'react'], factory) :
14
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.withSelector, global.React));
15
- })(this, (function (exports, withSelector, React) { 'use strict';
12
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
13
+ typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
14
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.React));
15
+ })(this, (function (exports, React) { 'use strict';
16
16
 
17
17
  function _interopNamespace(e) {
18
18
  if (e && e.__esModule) return e;
@@ -34,106 +34,6 @@
34
34
 
35
35
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
36
36
 
37
- /**
38
- * @tanstack/store/src/index.ts
39
- *
40
- * Copyright (c) TanStack
41
- *
42
- * This source code is licensed under the MIT license found in the
43
- * LICENSE.md file in the root directory of this source tree.
44
- *
45
- * @license MIT
46
- */
47
- class Store {
48
- listeners = new Set();
49
- _batching = false;
50
- _flushing = 0;
51
- _nextPriority = null;
52
- constructor(initialState, options) {
53
- this.state = initialState;
54
- this.options = options;
55
- }
56
- subscribe = listener => {
57
- this.listeners.add(listener);
58
- const unsub = this.options?.onSubscribe?.(listener, this);
59
- return () => {
60
- this.listeners.delete(listener);
61
- unsub?.();
62
- };
63
- };
64
- setState = (updater, opts) => {
65
- const previous = this.state;
66
- this.state = this.options?.updateFn ? this.options.updateFn(previous)(updater) : updater(previous);
67
- const priority = opts?.priority ?? this.options?.defaultPriority ?? 'high';
68
- if (this._nextPriority === null) {
69
- this._nextPriority = priority;
70
- } else if (this._nextPriority === 'high') {
71
- this._nextPriority = priority;
72
- } else {
73
- this._nextPriority = this.options?.defaultPriority ?? 'high';
74
- }
75
-
76
- // Always run onUpdate, regardless of batching
77
- this.options?.onUpdate?.({
78
- priority: this._nextPriority
79
- });
80
-
81
- // Attempt to flush
82
- this._flush();
83
- };
84
- _flush = () => {
85
- if (this._batching) return;
86
- const flushId = ++this._flushing;
87
- this.listeners.forEach(listener => {
88
- if (this._flushing !== flushId) return;
89
- listener({
90
- priority: this._nextPriority ?? 'high'
91
- });
92
- });
93
- };
94
- batch = cb => {
95
- if (this._batching) return cb();
96
- this._batching = true;
97
- cb();
98
- this._batching = false;
99
- this._flush();
100
- };
101
- }
102
-
103
- /**
104
- * @tanstack/react-store/src/index.tsx
105
- *
106
- * Copyright (c) TanStack
107
- *
108
- * This source code is licensed under the MIT license found in the
109
- * LICENSE.md file in the root directory of this source tree.
110
- *
111
- * @license MIT
112
- */
113
-
114
- function useStore(store, selector = d => d) {
115
- const slice = withSelector.useSyncExternalStoreWithSelector(store.subscribe, () => store.state, () => store.state, selector, shallow$1);
116
- return slice;
117
- }
118
- function shallow$1(objA, objB) {
119
- if (Object.is(objA, objB)) {
120
- return true;
121
- }
122
- if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
123
- return false;
124
- }
125
- const keysA = Object.keys(objA);
126
- if (keysA.length !== Object.keys(objB).length) {
127
- return false;
128
- }
129
- for (let i = 0; i < keysA.length; i++) {
130
- if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
131
- return false;
132
- }
133
- }
134
- return true;
135
- }
136
-
137
37
  /**
138
38
  * @tanstack/history/src/index.ts
139
39
  *
@@ -181,7 +81,6 @@
181
81
  while (queue.length) {
182
82
  queue.shift()?.();
183
83
  }
184
- onUpdate();
185
84
  };
186
85
  const queueTask = task => {
187
86
  queue.push(task);
@@ -241,7 +140,7 @@
241
140
  },
242
141
  flush: () => opts.flush?.(),
243
142
  destroy: () => opts.destroy?.(),
244
- update: onUpdate
143
+ notify: onUpdate
245
144
  };
246
145
  }
247
146
  function assignKey(state) {
@@ -327,7 +226,7 @@
327
226
  };
328
227
  const onPushPop = () => {
329
228
  currentLocation = parseLocation(getHref(), window.history.state);
330
- history.update();
229
+ history.notify();
331
230
  };
332
231
  var originalPushState = window.history.pushState;
333
232
  var originalReplaceState = window.history.replaceState;
@@ -351,12 +250,12 @@
351
250
  window.addEventListener(popStateEvent, onPushPop);
352
251
  window.history.pushState = function () {
353
252
  let res = originalPushState.apply(window.history, arguments);
354
- if (tracking) history.update();
253
+ if (tracking) history.notify();
355
254
  return res;
356
255
  };
357
256
  window.history.replaceState = function () {
358
257
  let res = originalReplaceState.apply(window.history, arguments);
359
- if (tracking) history.update();
258
+ if (tracking) history.notify();
360
259
  return res;
361
260
  };
362
261
  return history;
@@ -442,17 +341,6 @@
442
341
  }
443
342
  }
444
343
 
445
- /**
446
- * @tanstack/router-core/src/index.ts
447
- *
448
- * Copyright (c) TanStack
449
- *
450
- * This source code is licensed under the MIT license found in the
451
- * LICENSE.md file in the root directory of this source tree.
452
- *
453
- * @license MIT
454
- */
455
-
456
344
  // export type Expand<T> = T
457
345
 
458
346
  // type Compute<T> = { [K in keyof T]: T[K] } | never
@@ -470,6 +358,40 @@
470
358
  // : never
471
359
  // }
472
360
  // >
361
+ // // Sample types to merge
362
+ // type TypeA = {
363
+ // shared: string
364
+ // onlyInA: string
365
+ // nested: {
366
+ // shared: string
367
+ // aProp: string
368
+ // }
369
+ // array: string[]
370
+ // }
371
+ // type TypeB = {
372
+ // shared: number
373
+ // onlyInB: number
374
+ // nested: {
375
+ // shared: number
376
+ // bProp: number
377
+ // }
378
+ // array: number[]
379
+ // }
380
+ // type TypeC = {
381
+ // shared: boolean
382
+ // onlyInC: boolean
383
+ // nested: {
384
+ // shared: boolean
385
+ // cProp: boolean
386
+ // }
387
+ // array: boolean[]
388
+ // }
389
+ // type Test = Expand<Assign<TypeA, TypeB>>
390
+ // // Using DeepMerge to merge TypeA and TypeB
391
+ // type MergedType = Expand<AssignAll<[TypeA, TypeB, TypeC]>>
392
+ //
393
+
394
+ const isServer = typeof document === 'undefined';
473
395
  function last(arr) {
474
396
  return arr[arr.length - 1];
475
397
  }
@@ -563,6 +485,12 @@
563
485
  }
564
486
  return false;
565
487
  }
488
+ function useStableCallback(fn) {
489
+ const fnRef = React__namespace.useRef(fn);
490
+ fnRef.current = fn;
491
+ const ref = React__namespace.useRef((...args) => fnRef.current(...args));
492
+ return ref.current;
493
+ }
566
494
 
567
495
  function joinPaths(paths) {
568
496
  return cleanPath(paths.filter(Boolean).join('/'));
@@ -796,102 +724,19 @@
796
724
  return out;
797
725
  }
798
726
 
799
- const rootRouteId = '__root__';
800
-
801
- // The parse type here allows a zod schema to be passed directly to the validator
802
-
803
- // T extends Record<PropertyKey, infer U>
804
- // ? {
805
- // [K in keyof T]: UseLoaderResultPromise<T[K]>
806
- // }
807
- // : UseLoaderResultPromise<T>
808
-
809
- // export type UseLoaderResultPromise<T> = T extends Promise<infer U>
810
- // ? StreamedPromise<U>
811
- // : T
812
- class Route {
813
- // Set up in this.init()
814
-
815
- // customId!: TCustomId
816
-
817
- // Optional
818
-
819
- constructor(options) {
820
- this.options = options || {};
821
- this.isRoot = !options?.getParentRoute;
822
- Route.__onInit(this);
823
- }
824
- init = opts => {
825
- this.originalIndex = opts.originalIndex;
826
- this.router = opts.router;
827
- const options = this.options;
828
- const isRoot = !options?.path && !options?.id;
829
- this.parentRoute = this.options?.getParentRoute?.();
830
- if (isRoot) {
831
- this.path = rootRouteId;
832
- } else {
833
- invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
834
- }
835
- let path = isRoot ? rootRouteId : options.path;
836
-
837
- // If the path is anything other than an index path, trim it up
838
- if (path && path !== '/') {
839
- path = trimPath(path);
840
- }
841
- const customId = options?.id || path;
842
-
843
- // Strip the parentId prefix from the first level of children
844
- let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
845
- if (path === rootRouteId) {
846
- path = '/';
847
- }
848
- if (id !== rootRouteId) {
849
- id = joinPaths(['/', id]);
727
+ function _extends() {
728
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
729
+ for (var i = 1; i < arguments.length; i++) {
730
+ var source = arguments[i];
731
+ for (var key in source) {
732
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
733
+ target[key] = source[key];
734
+ }
735
+ }
850
736
  }
851
- const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
852
- this.path = path;
853
- this.id = id;
854
- // this.customId = customId as TCustomId
855
- this.fullPath = fullPath;
856
- this.to = fullPath;
857
- };
858
- addChildren = children => {
859
- this.children = children;
860
- return this;
861
- };
862
- update = options => {
863
- Object.assign(this.options, options);
864
- return this;
865
- };
866
- static __onInit = route => {
867
- // This is a dummy static method that should get
868
- // replaced by a framework specific implementation if necessary
869
- };
870
- }
871
- class RouterContext {
872
- constructor() {}
873
- createRootRoute = options => {
874
- return new RootRoute(options);
875
- };
876
- }
877
- class RootRoute extends Route {
878
- constructor(options) {
879
- super(options);
880
- }
881
- }
882
- function createRouteMask(opts) {
883
- return opts;
884
- }
885
-
886
- class FileRoute {
887
- constructor(path) {
888
- this.path = path;
889
- }
890
- createRoute = options => {
891
- const route = new Route(options);
892
- route.isRoot = false;
893
- return route;
737
+ return target;
894
738
  };
739
+ return _extends.apply(this, arguments);
895
740
  }
896
741
 
897
742
  const defaultParseSearch = parseSearchWith(JSON.parse);
@@ -958,76 +803,22 @@
958
803
 
959
804
  //
960
805
 
806
+ //
807
+
961
808
  const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
962
- const visibilityChangeEvent = 'visibilitychange';
963
- const focusEvent = 'focus';
964
- const preloadWarning = 'Error preloading route! ☝️';
965
809
  class Router {
966
- #unsubHistory;
967
- resetNextScroll = false;
968
- tempLocationKey = `${Math.round(Math.random() * 10000000)}`;
969
- // nextTemporaryLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>
970
-
810
+ // dehydratedData?: TDehydrated
811
+ // resetNextScroll = false
812
+ // tempLocationKey = `${Math.round(Math.random() * 10000000)}`
971
813
  constructor(options) {
972
814
  this.options = {
973
815
  defaultPreloadDelay: 50,
974
- context: undefined,
816
+ meta: undefined,
975
817
  ...options,
976
818
  stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
977
819
  parseSearch: options?.parseSearch ?? defaultParseSearch
978
- // fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn,
979
820
  };
980
-
981
- this.__store = new Store(getInitialRouterState(), {
982
- onUpdate: () => {
983
- const prev = this.state;
984
- const next = this.__store.state;
985
- const matchesByIdChanged = prev.matchesById !== next.matchesById;
986
- let matchesChanged;
987
- let pendingMatchesChanged;
988
- if (!matchesByIdChanged) {
989
- matchesChanged = prev.matchIds.length !== next.matchIds.length || prev.matchIds.some((d, i) => d !== next.matchIds[i]);
990
- pendingMatchesChanged = prev.pendingMatchIds.length !== next.pendingMatchIds.length || prev.pendingMatchIds.some((d, i) => d !== next.pendingMatchIds[i]);
991
- }
992
- if (matchesByIdChanged || matchesChanged) {
993
- next.matches = next.matchIds.map(id => {
994
- return next.matchesById[id];
995
- });
996
- }
997
- if (matchesByIdChanged || pendingMatchesChanged) {
998
- next.pendingMatches = next.pendingMatchIds.map(id => {
999
- return next.matchesById[id];
1000
- });
1001
- }
1002
- if (matchesByIdChanged || matchesChanged || pendingMatchesChanged) {
1003
- const hasPendingComponent = next.pendingMatches.some(d => {
1004
- const route = this.getRoute(d.routeId);
1005
- return !!route?.options.pendingComponent;
1006
- });
1007
- next.renderedMatchIds = hasPendingComponent ? next.pendingMatchIds : next.matchIds;
1008
- next.renderedMatches = next.renderedMatchIds.map(id => {
1009
- return next.matchesById[id];
1010
- });
1011
- }
1012
- next.isFetching = [...next.matches, ...next.pendingMatches].some(d => d.isFetching);
1013
- this.state = next;
1014
- },
1015
- defaultPriority: 'low'
1016
- });
1017
- this.state = this.__store.state;
1018
- this.update(options);
1019
- const nextLocation = this.buildLocation({
1020
- search: true,
1021
- params: true,
1022
- hash: true,
1023
- state: true
1024
- });
1025
- if (this.state.location.href !== nextLocation.href) {
1026
- this.#commitLocation({
1027
- ...nextLocation,
1028
- replace: true
1029
- });
1030
- }
821
+ this.routeTree = this.options.routeTree;
1031
822
  }
1032
823
  subscribers = new Set();
1033
824
  subscribe = (eventType, fn) => {
@@ -1040,245 +831,329 @@
1040
831
  this.subscribers.delete(listener);
1041
832
  };
1042
833
  };
1043
- #emit = routerEvent => {
834
+ emit = routerEvent => {
1044
835
  this.subscribers.forEach(listener => {
1045
836
  if (listener.eventType === routerEvent.type) {
1046
837
  listener.fn(routerEvent);
1047
838
  }
1048
839
  });
1049
840
  };
1050
- reset = () => {
1051
- this.__store.setState(s => Object.assign(s, getInitialRouterState()));
1052
- };
1053
- mount = () => {
1054
- // addEventListener does not exist in React Native, but window does
1055
- // In the future, we might need to invert control here for more adapters
1056
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1057
- if (typeof window !== 'undefined' && window.addEventListener) {
1058
- window.addEventListener(visibilityChangeEvent, this.#onFocus, false);
1059
- window.addEventListener(focusEvent, this.#onFocus, false);
1060
- }
1061
- this.safeLoad();
1062
- return () => {
1063
- if (typeof window !== 'undefined' && window.removeEventListener) {
1064
- window.removeEventListener(visibilityChangeEvent, this.#onFocus);
1065
- window.removeEventListener(focusEvent, this.#onFocus);
1066
- }
1067
- };
1068
- };
1069
- #onFocus = () => {
1070
- if (this.options.reloadOnWindowFocus ?? true) {
1071
- this.invalidate({
1072
- __fromFocus: true
1073
- });
1074
- }
1075
- };
1076
- update = opts => {
1077
- this.options = {
1078
- ...this.options,
1079
- ...opts,
1080
- context: {
1081
- ...this.options.context,
1082
- ...opts?.context
1083
- }
1084
- };
1085
- if (!this.history || this.options.history && this.options.history !== this.history) {
1086
- if (this.#unsubHistory) {
1087
- this.#unsubHistory();
1088
- }
1089
- this.history = this.options.history ?? (isServer ? createMemoryHistory() : createBrowserHistory());
1090
- const parsedLocation = this.#parseLocation();
1091
- this.__store.setState(s => ({
1092
- ...s,
1093
- resolvedLocation: parsedLocation,
1094
- location: parsedLocation
1095
- }));
1096
- this.#unsubHistory = this.history.subscribe(() => {
1097
- this.safeLoad({
1098
- next: this.#parseLocation(this.state.location)
1099
- });
1100
- });
1101
- }
1102
- const {
1103
- basepath,
1104
- routeTree
1105
- } = this.options;
1106
- this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
1107
- if (routeTree && routeTree !== this.routeTree) {
1108
- this.#processRoutes(routeTree);
1109
- }
1110
- return this;
1111
- };
1112
- cancelMatches = () => {
1113
- this.state.matches.forEach(match => {
1114
- this.cancelMatch(match.id);
1115
- });
1116
- };
1117
- cancelMatch = id => {
1118
- this.getRouteMatch(id)?.abortController?.abort();
1119
- };
1120
- safeLoad = async opts => {
1121
- try {
1122
- return this.load(opts);
1123
- } catch (err) {
1124
- // Don't do anything
1125
- }
1126
- };
1127
- latestLoadPromise = Promise.resolve();
1128
- load = async opts => {
1129
- const promise = new Promise(async (resolve, reject) => {
1130
- const prevLocation = this.state.resolvedLocation;
1131
- const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
1132
- let latestPromise;
1133
- const checkLatest = () => {
1134
- return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
1135
- };
1136
841
 
1137
- // Cancel any pending matches
842
+ // dehydrate = (): DehydratedRouter => {
843
+ // return {
844
+ // state: {
845
+ // dehydratedMatches: state.matches.map((d) =>
846
+ // pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt']),
847
+ // ),
848
+ // },
849
+ // }
850
+ // }
1138
851
 
1139
- let pendingMatches;
1140
- this.#emit({
1141
- type: 'onBeforeLoad',
1142
- from: prevLocation,
1143
- to: opts?.next ?? this.state.location,
1144
- pathChanged: pathDidChange
1145
- });
1146
- this.__store.batch(() => {
1147
- if (opts?.next) {
1148
- // Ingest the new location
1149
- this.__store.setState(s => ({
1150
- ...s,
1151
- location: opts.next
1152
- }));
1153
- }
852
+ // hydrate = async (__do_not_use_server_ctx?: HydrationCtx) => {
853
+ // let _ctx = __do_not_use_server_ctx
854
+ // // Client hydrates from window
855
+ // if (typeof document !== 'undefined') {
856
+ // _ctx = window.__TSR_DEHYDRATED__
857
+ // }
858
+
859
+ // invariant(
860
+ // _ctx,
861
+ // 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?',
862
+ // )
863
+
864
+ // const ctx = _ctx
865
+ // this.dehydratedData = ctx.payload as any
866
+ // this.options.hydrate?.(ctx.payload as any)
867
+ // const dehydratedState = ctx.router.state
868
+
869
+ // let matches = this.matchRoutes(
870
+ // state.location.pathname,
871
+ // state.location.search,
872
+ // ).map((match) => {
873
+ // const dehydratedMatch = dehydratedState.dehydratedMatches.find(
874
+ // (d) => d.id === match.id,
875
+ // )
876
+
877
+ // invariant(
878
+ // dehydratedMatch,
879
+ // `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
880
+ // )
881
+
882
+ // if (dehydratedMatch) {
883
+ // return {
884
+ // ...match,
885
+ // ...dehydratedMatch,
886
+ // }
887
+ // }
888
+ // return match
889
+ // })
890
+
891
+ // this.setState((s) => {
892
+ // return {
893
+ // ...s,
894
+ // matches: dehydratedState.dehydratedMatches as any,
895
+ // }
896
+ // })
897
+ // }
1154
898
 
1155
- // Match the routes
1156
- pendingMatches = this.matchRoutes(this.state.location.pathname, this.state.location.search, {
1157
- throwOnError: opts?.throwOnError,
1158
- debug: true
1159
- });
1160
- this.__store.setState(s => ({
1161
- ...s,
1162
- status: 'pending',
1163
- pendingMatchIds: pendingMatches.map(d => d.id),
1164
- matchesById: this.#mergeMatches(s.matchesById, pendingMatches)
1165
- }));
1166
- });
1167
- try {
1168
- // Load the matches
1169
- try {
1170
- await this.loadMatches(pendingMatches.map(d => d.id));
1171
- } catch (err) {
1172
- // swallow this error, since we'll display the
1173
- // errors on the route components
1174
- }
899
+ // TODO:
900
+ // injectedHtml: (string | (() => Promise<string> | string))[] = []
1175
901
 
1176
- // Only apply the latest transition
1177
- if (latestPromise = checkLatest()) {
1178
- return latestPromise;
1179
- }
1180
- const exitingMatchIds = this.state.matchIds.filter(id => !this.state.pendingMatchIds.includes(id));
1181
- const enteringMatchIds = this.state.pendingMatchIds.filter(id => !this.state.matchIds.includes(id));
1182
- const stayingMatchIds = this.state.matchIds.filter(id => this.state.pendingMatchIds.includes(id));
1183
- this.__store.setState(s => ({
1184
- ...s,
1185
- status: 'idle',
1186
- resolvedLocation: s.location,
1187
- matchIds: s.pendingMatchIds,
1188
- pendingMatchIds: []
1189
- }));
1190
- [[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matchIds, hook]) => {
1191
- matchIds.forEach(id => {
1192
- const match = this.getRouteMatch(id);
1193
- const route = this.getRoute(match.routeId);
1194
- route.options[hook]?.(match);
1195
- });
1196
- });
1197
- this.#emit({
1198
- type: 'onLoad',
1199
- from: prevLocation,
1200
- to: this.state.location,
1201
- pathChanged: pathDidChange
1202
- });
1203
- resolve();
1204
- } catch (err) {
1205
- // Only apply the latest transition
1206
- if (latestPromise = checkLatest()) {
1207
- return latestPromise;
1208
- }
1209
- reject(err);
1210
- }
1211
- });
1212
- this.latestLoadPromise = promise;
1213
- this.latestLoadPromise.then(() => {
1214
- this.cleanMatches();
1215
- });
1216
- return this.latestLoadPromise;
902
+ // TODO:
903
+ // injectHtml = async (html: string | (() => Promise<string> | string)) => {
904
+ // this.injectedHtml.push(html)
905
+ // }
906
+
907
+ // TODO:
908
+ // dehydrateData = <T>(key: any, getData: T | (() => Promise<T> | T)) => {
909
+ // if (typeof document === 'undefined') {
910
+ // const strKey = typeof key === 'string' ? key : JSON.stringify(key)
911
+
912
+ // this.injectHtml(async () => {
913
+ // const id = `__TSR_DEHYDRATED__${strKey}`
914
+ // const data =
915
+ // typeof getData === 'function' ? await (getData as any)() : getData
916
+ // return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(
917
+ // strKey,
918
+ // )}"] = ${JSON.stringify(data)}
919
+ // ;(() => {
920
+ // var el = document.getElementById('${id}')
921
+ // el.parentElement.removeChild(el)
922
+ // })()
923
+ // </script>`
924
+ // })
925
+
926
+ // return () => this.hydrateData<T>(key)
927
+ // }
928
+
929
+ // return () => undefined
930
+ // }
931
+
932
+ // hydrateData = <T = unknown>(key: any) => {
933
+ // if (typeof document !== 'undefined') {
934
+ // const strKey = typeof key === 'string' ? key : JSON.stringify(key)
935
+
936
+ // return window[`__TSR_DEHYDRATED__${strKey}` as any] as T
937
+ // }
938
+
939
+ // return undefined
940
+ // }
941
+
942
+ // resolveMatchPromise = (matchId: string, key: string, value: any) => {
943
+ // state.matches
944
+ // .find((d) => d.id === matchId)
945
+ // ?.__promisesByKey[key]?.resolve(value)
946
+ // }
947
+
948
+ // setRouteMatch = (
949
+ // id: string,
950
+ // pending: boolean,
951
+ // updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
952
+ // ) => {
953
+ // const key = pending ? 'pendingMatches' : 'matches'
954
+
955
+ // this.setState((prev) => {
956
+ // return {
957
+ // ...prev,
958
+ // [key]: prev[key].map((d) => {
959
+ // if (d.id === id) {
960
+ // return functionalUpdate(updater, d)
961
+ // }
962
+
963
+ // return d
964
+ // }),
965
+ // }
966
+ // })
967
+ // }
968
+
969
+ // setPendingRouteMatch = (
970
+ // id: string,
971
+ // updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
972
+ // ) => {
973
+ // this.setRouteMatch(id, true, updater)
974
+ // }
975
+ }
976
+
977
+ // A function that takes an import() argument which is a function and returns a new function that will
978
+ // proxy arguments from the caller to the imported function, retaining all type
979
+ // information along the way
980
+ function lazyFn(fn, key) {
981
+ return async (...args) => {
982
+ const imported = await fn();
983
+ return imported[key || 'default'](...args);
1217
984
  };
1218
- #mergeMatches = (prevMatchesById, nextMatches) => {
1219
- let matchesById = {
1220
- ...prevMatchesById
1221
- };
1222
- nextMatches.forEach(match => {
1223
- if (!matchesById[match.id]) {
1224
- matchesById[match.id] = match;
1225
- }
1226
- matchesById[match.id] = {
1227
- ...matchesById[match.id],
1228
- ...match
1229
- };
1230
- });
1231
- return matchesById;
985
+ }
986
+
987
+ // Detect if we're in the DOM
988
+
989
+ function redirect(opts) {
990
+ opts.isRedirect = true;
991
+ return opts;
992
+ }
993
+ function isRedirect(obj) {
994
+ return !!obj?.isRedirect;
995
+ }
996
+
997
+ const preloadWarning = 'Error preloading route! ☝️';
998
+ const routerContext = /*#__PURE__*/React__namespace.createContext(null);
999
+ function getInitialRouterState(location) {
1000
+ return {
1001
+ status: 'idle',
1002
+ isFetching: false,
1003
+ resolvedLocation: location,
1004
+ location: location,
1005
+ matches: [],
1006
+ pendingMatches: [],
1007
+ lastUpdated: Date.now()
1232
1008
  };
1233
- getRoute = id => {
1234
- const route = this.routesById[id];
1235
- invariant(route, `Route with id "${id}" not found`);
1236
- return route;
1009
+ }
1010
+ function RouterProvider({
1011
+ router,
1012
+ ...rest
1013
+ }) {
1014
+ const options = {
1015
+ ...router.options,
1016
+ ...rest,
1017
+ meta: {
1018
+ ...router.options.meta,
1019
+ ...rest?.meta
1020
+ }
1237
1021
  };
1238
- preloadRoute = async (navigateOpts = this.state.location) => {
1239
- let next = this.buildLocation(navigateOpts);
1240
- const matches = this.matchRoutes(next.pathname, next.search, {
1241
- throwOnError: true
1242
- });
1243
- this.__store.setState(s => {
1022
+ const history = React__namespace.useState(() => options.history ?? createBrowserHistory())[0];
1023
+ const tempLocationKeyRef = React__namespace.useRef(`${Math.round(Math.random() * 10000000)}`);
1024
+ const resetNextScrollRef = React__namespace.useRef(false);
1025
+ const navigateTimeoutRef = React__namespace.useRef(null);
1026
+ const parseLocation = useStableCallback(previousLocation => {
1027
+ const parse = ({
1028
+ pathname,
1029
+ search,
1030
+ hash,
1031
+ state
1032
+ }) => {
1033
+ const parsedSearch = options.parseSearch(search);
1244
1034
  return {
1245
- ...s,
1246
- matchesById: this.#mergeMatches(s.matchesById, matches)
1035
+ pathname: pathname,
1036
+ searchStr: search,
1037
+ search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1038
+ hash: hash.split('#').reverse()[0] ?? '',
1039
+ href: `${pathname}${search}${hash}`,
1040
+ state: replaceEqualDeep(previousLocation?.state, state)
1247
1041
  };
1248
- });
1249
- await this.loadMatches(matches.map(d => d.id), {
1250
- preload: true,
1251
- maxAge: navigateOpts.maxAge
1252
- });
1253
- return [last(matches), matches];
1254
- };
1255
- cleanMatches = () => {
1256
- const now = Date.now();
1257
- const outdatedMatchIds = Object.values(this.state.matchesById).filter(match => {
1258
- const route = this.getRoute(match.routeId);
1259
- return !this.state.matchIds.includes(match.id) && !this.state.pendingMatchIds.includes(match.id) && (match.preloadMaxAge > -1 ? match.updatedAt + match.preloadMaxAge < now : true) && (route.options.gcMaxAge ? match.updatedAt + route.options.gcMaxAge < now : true);
1260
- }).map(d => d.id);
1261
- if (outdatedMatchIds.length) {
1262
- this.__store.setState(s => {
1263
- const matchesById = {
1264
- ...s.matchesById
1265
- };
1266
- outdatedMatchIds.forEach(id => {
1267
- delete matchesById[id];
1042
+ };
1043
+ const location = parse(history.location);
1044
+ let {
1045
+ __tempLocation,
1046
+ __tempKey
1047
+ } = location.state;
1048
+ if (__tempLocation && (!__tempKey || __tempKey === tempLocationKeyRef.current)) {
1049
+ // Sync up the location keys
1050
+ const parsedTempLocation = parse(__tempLocation);
1051
+ parsedTempLocation.state.key = location.state.key;
1052
+ delete parsedTempLocation.state.__tempLocation;
1053
+ return {
1054
+ ...parsedTempLocation,
1055
+ maskedLocation: location
1056
+ };
1057
+ }
1058
+ return location;
1059
+ });
1060
+ const [state, setState] = React__namespace.useState(() => getInitialRouterState(parseLocation()));
1061
+ const basepath = `/${trimPath(options.basepath ?? '') ?? ''}`;
1062
+ const resolvePathWithBase = useStableCallback((from, path) => {
1063
+ return resolvePath(basepath, from, cleanPath(path));
1064
+ });
1065
+ const [routesById, routesByPath] = React__namespace.useMemo(() => {
1066
+ const routesById = {};
1067
+ const routesByPath = {};
1068
+ const recurseRoutes = routes => {
1069
+ routes.forEach((route, i) => {
1070
+ route.init({
1071
+ originalIndex: i
1268
1072
  });
1269
- return {
1270
- ...s,
1271
- matchesById
1272
- };
1073
+ const existingRoute = routesById[route.id];
1074
+ invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
1075
+ routesById[route.id] = route;
1076
+ if (!route.isRoot && route.path) {
1077
+ const trimmedFullPath = trimPathRight(route.fullPath);
1078
+ if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
1079
+ routesByPath[trimmedFullPath] = route;
1080
+ }
1081
+ }
1082
+ const children = route.children;
1083
+ if (children?.length) {
1084
+ recurseRoutes(children);
1085
+ }
1273
1086
  });
1087
+ };
1088
+ recurseRoutes([router.routeTree]);
1089
+ return [routesById, routesByPath];
1090
+ }, []);
1091
+ const looseRoutesById = routesById;
1092
+ const flatRoutes = React__namespace.useMemo(() => Object.values(routesByPath).map((d, i) => {
1093
+ const trimmed = trimPath(d.fullPath);
1094
+ const parsed = parsePathname(trimmed);
1095
+ while (parsed.length > 1 && parsed[0]?.value === '/') {
1096
+ parsed.shift();
1097
+ }
1098
+ const score = parsed.map(d => {
1099
+ if (d.type === 'param') {
1100
+ return 0.5;
1101
+ }
1102
+ if (d.type === 'wildcard') {
1103
+ return 0.25;
1104
+ }
1105
+ return 1;
1106
+ });
1107
+ return {
1108
+ child: d,
1109
+ trimmed,
1110
+ parsed,
1111
+ index: i,
1112
+ score
1113
+ };
1114
+ }).sort((a, b) => {
1115
+ let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
1116
+ if (isIndex !== 0) return isIndex;
1117
+ const length = Math.min(a.score.length, b.score.length);
1118
+
1119
+ // Sort by length of score
1120
+ if (a.score.length !== b.score.length) {
1121
+ return b.score.length - a.score.length;
1274
1122
  }
1275
- };
1276
- matchRoutes = (pathname, locationSearch, opts) => {
1123
+
1124
+ // Sort by min available score
1125
+ for (let i = 0; i < length; i++) {
1126
+ if (a.score[i] !== b.score[i]) {
1127
+ return b.score[i] - a.score[i];
1128
+ }
1129
+ }
1130
+
1131
+ // Sort by min available parsed value
1132
+ for (let i = 0; i < length; i++) {
1133
+ if (a.parsed[i].value !== b.parsed[i].value) {
1134
+ return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
1135
+ }
1136
+ }
1137
+
1138
+ // Sort by length of trimmed full path
1139
+ if (a.trimmed !== b.trimmed) {
1140
+ return a.trimmed > b.trimmed ? 1 : -1;
1141
+ }
1142
+
1143
+ // Sort by original index
1144
+ return a.index - b.index;
1145
+ }).map((d, i) => {
1146
+ d.child.rank = i;
1147
+ return d.child;
1148
+ }), [routesByPath]);
1149
+ const latestLoadPromiseRef = React__namespace.useRef(Promise.resolve());
1150
+ const matchRoutes = useStableCallback((pathname, locationSearch, opts) => {
1277
1151
  let routeParams = {};
1278
- let foundRoute = this.flatRoutes.find(route => {
1279
- const matchedParams = matchPathname(this.basepath, trimPathRight(pathname), {
1152
+ let foundRoute = flatRoutes.find(route => {
1153
+ const matchedParams = matchPathname(basepath, trimPathRight(pathname), {
1280
1154
  to: route.fullPath,
1281
- caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive
1155
+ caseSensitive: route.options.caseSensitive ?? options.caseSensitive,
1156
+ fuzzy: false
1282
1157
  });
1283
1158
  if (matchedParams) {
1284
1159
  routeParams = matchedParams;
@@ -1286,7 +1161,7 @@
1286
1161
  }
1287
1162
  return false;
1288
1163
  });
1289
- let routeCursor = foundRoute || this.routesById['__root__'];
1164
+ let routeCursor = foundRoute || routesById['__root__'];
1290
1165
  let matchedRoutes = [routeCursor];
1291
1166
  // let includingLayouts = true
1292
1167
  while (routeCursor?.parentRoute) {
@@ -1318,24 +1193,12 @@
1318
1193
  });
1319
1194
  const matches = matchedRoutes.map((route, index) => {
1320
1195
  const interpolatedPath = interpolatePath(route.path, routeParams);
1321
- const loaderContext = route.options.loaderContext ? route.options.loaderContext({
1322
- search: locationSearch
1323
- }) : undefined;
1324
- const matchId = JSON.stringify([interpolatePath(route.id, routeParams, true), loaderContext].filter(d => d !== undefined), (key, value) => {
1325
- if (typeof value === 'function') {
1326
- console.info(route);
1327
- invariant(false, `Cannot return functions and other non-serializable values from routeOptions.loaderContext! Please use routeOptions.beforeLoad to do this. Route info is logged above 👆`);
1328
- }
1329
- if (typeof value === 'object' && value !== null) {
1330
- return Object.fromEntries(Object.keys(value).sort().map(key => [key, value[key]]));
1331
- }
1332
- return value;
1333
- });
1196
+ const matchId = interpolatePath(route.id, routeParams, true);
1334
1197
 
1335
1198
  // Waste not, want not. If we already have a match for this route,
1336
1199
  // reuse it. This is important for layout routes, which might stick
1337
1200
  // around between navigation actions that only change leaf routes.
1338
- const existingMatch = this.getRouteMatch(matchId);
1201
+ const existingMatch = getRouteMatch(state, matchId);
1339
1202
  if (existingMatch) {
1340
1203
  return {
1341
1204
  ...existingMatch
@@ -1343,16 +1206,13 @@
1343
1206
  }
1344
1207
 
1345
1208
  // Create a fresh route match
1346
- const hasLoaders = !!(route.options.loader || componentTypes.some(d => route.options[d]?.preload));
1209
+ const hasLoaders = !!(route.options.load || componentTypes.some(d => route.options[d]?.preload));
1347
1210
  const routeMatch = {
1348
1211
  id: matchId,
1349
- loaderContext,
1350
1212
  routeId: route.id,
1351
1213
  params: routeParams,
1352
- pathname: joinPaths([this.basepath, interpolatedPath]),
1214
+ pathname: joinPaths([basepath, interpolatedPath]),
1353
1215
  updatedAt: Date.now(),
1354
- maxAge: -1,
1355
- preloadMaxAge: -1,
1356
1216
  routeSearch: {},
1357
1217
  search: {},
1358
1218
  status: hasLoaders ? 'pending' : 'success',
@@ -1361,21 +1221,20 @@
1361
1221
  error: undefined,
1362
1222
  paramsError: parseErrors[index],
1363
1223
  searchError: undefined,
1364
- loaderData: undefined,
1365
1224
  loadPromise: Promise.resolve(),
1366
- context: undefined,
1225
+ meta: undefined,
1367
1226
  abortController: new AbortController(),
1368
1227
  fetchedAt: 0
1369
1228
  };
1370
1229
  return routeMatch;
1371
1230
  });
1372
1231
 
1373
- // Take each match and resolve its search params and context
1232
+ // Take each match and resolve its search params and meta
1374
1233
  // This has to happen after the matches are created or found
1375
- // so that we can use the parent match's search params and context
1234
+ // so that we can use the parent match's search params and meta
1376
1235
  matches.forEach((match, i) => {
1377
1236
  const parentMatch = matches[i - 1];
1378
- const route = this.getRoute(match.routeId);
1237
+ const route = looseRoutesById[match.routeId];
1379
1238
  const searchInfo = (() => {
1380
1239
  // Validate the search params and stabilize them
1381
1240
  const parentSearchInfo = {
@@ -1409,117 +1268,268 @@
1409
1268
  Object.assign(match, searchInfo);
1410
1269
  });
1411
1270
  return matches;
1412
- };
1413
- loadMatches = async (matchIds, opts) => {
1414
- const getFreshMatches = () => matchIds.map(d => this.getRouteMatch(d));
1415
- if (!opts?.preload) {
1416
- getFreshMatches().forEach(match => {
1417
- // Update each match with its latest route data
1418
- this.setRouteMatch(match.id, s => ({
1419
- ...s,
1420
- routeSearch: match.routeSearch,
1421
- search: match.search,
1422
- context: match.context,
1423
- error: match.error,
1424
- paramsError: match.paramsError,
1425
- searchError: match.searchError,
1426
- params: match.params,
1427
- preloadMaxAge: 0
1428
- }));
1429
- });
1430
- }
1431
- let firstBadMatchIndex;
1271
+ });
1272
+ const cancelMatch = useStableCallback(id => {
1273
+ getRouteMatch(state, id)?.abortController?.abort();
1274
+ });
1275
+ const cancelMatches = useStableCallback(state => {
1276
+ state.matches.forEach(match => {
1277
+ cancelMatch(match.id);
1278
+ });
1279
+ });
1280
+ const buildLocation = useStableCallback((opts = {}) => {
1281
+ const build = (dest = {}, matches) => {
1282
+ const from = latestLocationRef.current;
1283
+ const fromPathname = dest.from ?? from.pathname;
1284
+ let pathname = resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
1285
+ const fromMatches = matchRoutes(fromPathname, from.search);
1286
+ const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
1287
+ const prevParams = {
1288
+ ...last(fromMatches)?.params
1289
+ };
1290
+ let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1291
+ if (nextParams) {
1292
+ matches?.map(d => looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
1293
+ nextParams = {
1294
+ ...nextParams,
1295
+ ...fn(nextParams)
1296
+ };
1297
+ });
1298
+ }
1299
+ pathname = interpolatePath(pathname, nextParams ?? {});
1300
+ const preSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
1301
+ const postSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
1432
1302
 
1433
- // Check each match middleware to see if the route can be accessed
1434
- try {
1435
- for (const [index, match] of getFreshMatches().entries()) {
1436
- const parentMatch = getFreshMatches()[index - 1];
1437
- const route = this.getRoute(match.routeId);
1438
- const handleError = (err, code) => {
1439
- err.routerCode = code;
1440
- firstBadMatchIndex = firstBadMatchIndex ?? index;
1441
- if (isRedirect(err)) {
1442
- throw err;
1443
- }
1444
- try {
1445
- route.options.onError?.(err);
1446
- } catch (errorHandlerErr) {
1447
- err = errorHandlerErr;
1448
- if (isRedirect(errorHandlerErr)) {
1449
- throw errorHandlerErr;
1450
- }
1303
+ // Pre filters first
1304
+ const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
1305
+
1306
+ // Then the link/navigate function
1307
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1308
+ : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
1309
+ : preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
1310
+ : {};
1311
+
1312
+ // Then post filters
1313
+ const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1314
+ const search = replaceEqualDeep(from.search, postFilteredSearch);
1315
+ const searchStr = options.stringifySearch(search);
1316
+ const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
1317
+ const hashStr = hash ? `#${hash}` : '';
1318
+ let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
1319
+ nextState = replaceEqualDeep(from.state, nextState);
1320
+ return {
1321
+ pathname,
1322
+ search,
1323
+ searchStr,
1324
+ state: nextState,
1325
+ hash,
1326
+ href: history.createHref(`${pathname}${searchStr}${hashStr}`),
1327
+ unmaskOnReload: dest.unmaskOnReload
1328
+ };
1329
+ };
1330
+ const buildWithMatches = (dest = {}, maskedDest) => {
1331
+ let next = build(dest);
1332
+ let maskedNext = maskedDest ? build(maskedDest) : undefined;
1333
+ if (!maskedNext) {
1334
+ let params = {};
1335
+ let foundMask = options.routeMasks?.find(d => {
1336
+ const match = matchPathname(basepath, next.pathname, {
1337
+ to: d.from,
1338
+ caseSensitive: false,
1339
+ fuzzy: false
1340
+ });
1341
+ if (match) {
1342
+ params = match;
1343
+ return true;
1451
1344
  }
1452
- this.setRouteMatch(match.id, s => ({
1453
- ...s,
1454
- error: err,
1455
- status: 'error',
1456
- updatedAt: Date.now()
1457
- }));
1458
- };
1459
- if (match.paramsError) {
1460
- handleError(match.paramsError, 'PARSE_PARAMS');
1461
- }
1462
- if (match.searchError) {
1463
- handleError(match.searchError, 'VALIDATE_SEARCH');
1464
- }
1465
- let didError = false;
1466
- const parentContext = parentMatch?.context ?? this?.options.context ?? {};
1467
- try {
1468
- const beforeLoadContext = (await route.options.beforeLoad?.({
1469
- abortController: match.abortController,
1470
- params: match.params,
1471
- preload: !!opts?.preload,
1472
- context: {
1473
- ...parentContext,
1474
- ...match.loaderContext
1475
- }
1476
- })) ?? {};
1477
- const context = {
1478
- ...parentContext,
1479
- ...match.loaderContext,
1480
- ...beforeLoadContext
1345
+ return false;
1346
+ });
1347
+ if (foundMask) {
1348
+ foundMask = {
1349
+ ...foundMask,
1350
+ from: interpolatePath(foundMask.from, params)
1481
1351
  };
1482
- this.setRouteMatch(match.id, s => ({
1483
- ...s,
1484
- context: replaceEqualDeep(s.context, context)
1485
- }));
1486
- } catch (err) {
1487
- handleError(err, 'BEFORE_LOAD');
1488
- didError = true;
1489
- }
1490
-
1491
- // If we errored, do not run the next matches' middleware
1492
- if (didError) {
1493
- break;
1352
+ maskedDest = foundMask;
1353
+ maskedNext = build(maskedDest);
1494
1354
  }
1495
1355
  }
1496
- } catch (err) {
1497
- if (isRedirect(err)) {
1498
- if (!opts?.preload) this.navigate(err);
1499
- return;
1356
+ const nextMatches = matchRoutes(next.pathname, next.search);
1357
+ const maskedMatches = maskedNext ? matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
1358
+ const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
1359
+ const final = build(dest, nextMatches);
1360
+ if (maskedFinal) {
1361
+ final.maskedLocation = maskedFinal;
1500
1362
  }
1501
- throw err;
1502
- }
1503
- const validResolvedMatches = getFreshMatches().slice(0, firstBadMatchIndex);
1504
- const matchPromises = [];
1505
- validResolvedMatches.forEach((match, index) => {
1506
- matchPromises.push((async () => {
1507
- const parentMatchPromise = matchPromises[index - 1];
1508
- const route = this.getRoute(match.routeId);
1509
- if (match.isFetching || match.status === 'success' && !isMatchInvalid(match, {
1510
- preload: opts?.preload
1511
- })) {
1512
- return this.getRouteMatch(match.id)?.loadPromise;
1363
+ return final;
1364
+ };
1365
+ if (opts.mask) {
1366
+ return buildWithMatches(opts, {
1367
+ ...pick(opts, ['from']),
1368
+ ...opts.mask
1369
+ });
1370
+ }
1371
+ return buildWithMatches(opts);
1372
+ });
1373
+ const commitLocation = useStableCallback(async next => {
1374
+ if (navigateTimeoutRef.current) clearTimeout(navigateTimeoutRef.current);
1375
+ const isSameUrl = latestLocationRef.current.href === next.href;
1376
+
1377
+ // If the next urls are the same and we're not replacing,
1378
+ // do nothing
1379
+ if (!isSameUrl || !next.replace) {
1380
+ let {
1381
+ maskedLocation,
1382
+ ...nextHistory
1383
+ } = next;
1384
+ if (maskedLocation) {
1385
+ nextHistory = {
1386
+ ...maskedLocation,
1387
+ state: {
1388
+ ...maskedLocation.state,
1389
+ __tempKey: undefined,
1390
+ __tempLocation: {
1391
+ ...nextHistory,
1392
+ search: nextHistory.searchStr,
1393
+ state: {
1394
+ ...nextHistory.state,
1395
+ __tempKey: undefined,
1396
+ __tempLocation: undefined,
1397
+ key: undefined
1398
+ }
1399
+ }
1400
+ }
1401
+ };
1402
+ if (nextHistory.unmaskOnReload ?? options.unmaskOnReload ?? false) {
1403
+ nextHistory.state.__tempKey = tempLocationKeyRef.current;
1404
+ }
1405
+ }
1406
+ history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
1407
+ }
1408
+ resetNextScrollRef.current = next.resetScroll ?? true;
1409
+ return latestLoadPromiseRef.current;
1410
+ });
1411
+ const buildAndCommitLocation = useStableCallback(({
1412
+ replace,
1413
+ resetScroll,
1414
+ ...rest
1415
+ } = {}) => {
1416
+ const location = buildLocation(rest);
1417
+ return commitLocation({
1418
+ ...location,
1419
+ replace,
1420
+ resetScroll
1421
+ });
1422
+ });
1423
+ const navigate = useStableCallback(({
1424
+ from,
1425
+ to = '',
1426
+ ...rest
1427
+ }) => {
1428
+ // If this link simply reloads the current route,
1429
+ // make sure it has a new key so it will trigger a data refresh
1430
+
1431
+ // If this `to` is a valid external URL, return
1432
+ // null for LinkUtils
1433
+ const toString = String(to);
1434
+ const fromString = typeof from === 'undefined' ? from : String(from);
1435
+ let isExternal;
1436
+ try {
1437
+ new URL(`${toString}`);
1438
+ isExternal = true;
1439
+ } catch (e) {}
1440
+ invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1441
+ return buildAndCommitLocation({
1442
+ ...rest,
1443
+ from: fromString,
1444
+ to: toString
1445
+ });
1446
+ });
1447
+ const loadMatches = useStableCallback(async ({
1448
+ matches,
1449
+ preload
1450
+ }) => {
1451
+ let firstBadMatchIndex;
1452
+
1453
+ // Check each match middleware to see if the route can be accessed
1454
+ try {
1455
+ for (let [index, match] of matches.entries()) {
1456
+ const parentMatch = matches[index - 1];
1457
+ const route = looseRoutesById[match.routeId];
1458
+ const handleError = (err, code) => {
1459
+ err.routerCode = code;
1460
+ firstBadMatchIndex = firstBadMatchIndex ?? index;
1461
+ if (isRedirect(err)) {
1462
+ throw err;
1463
+ }
1464
+ try {
1465
+ route.options.onError?.(err);
1466
+ } catch (errorHandlerErr) {
1467
+ err = errorHandlerErr;
1468
+ if (isRedirect(errorHandlerErr)) {
1469
+ throw errorHandlerErr;
1470
+ }
1471
+ }
1472
+ matches[index] = match = {
1473
+ ...match,
1474
+ error: err,
1475
+ status: 'error',
1476
+ updatedAt: Date.now()
1477
+ };
1478
+ };
1479
+ try {
1480
+ if (match.paramsError) {
1481
+ handleError(match.paramsError, 'PARSE_PARAMS');
1482
+ }
1483
+ if (match.searchError) {
1484
+ handleError(match.searchError, 'VALIDATE_SEARCH');
1485
+ }
1486
+ const parentMeta = parentMatch?.meta ?? options.meta ?? {};
1487
+ const beforeLoadMeta = (await route.options.beforeLoad?.({
1488
+ search: match.search,
1489
+ abortController: match.abortController,
1490
+ params: match.params,
1491
+ preload: !!preload,
1492
+ meta: parentMeta,
1493
+ location: state.location // TODO: This might need to be latestLocationRef.current...?
1494
+ })) ?? {};
1495
+ const meta = {
1496
+ ...parentMeta,
1497
+ ...beforeLoadMeta
1498
+ };
1499
+ matches[index] = match = {
1500
+ ...match,
1501
+ meta: replaceEqualDeep(match.meta, meta)
1502
+ };
1503
+ } catch (err) {
1504
+ handleError(err, 'BEFORE_LOAD');
1505
+ break;
1506
+ }
1507
+ }
1508
+ } catch (err) {
1509
+ if (isRedirect(err)) {
1510
+ if (!preload) navigate(err);
1511
+ return;
1512
+ }
1513
+ throw err;
1514
+ }
1515
+ const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
1516
+ const matchPromises = [];
1517
+ validResolvedMatches.forEach((match, index) => {
1518
+ matchPromises.push((async () => {
1519
+ const parentMatchPromise = matchPromises[index - 1];
1520
+ const route = looseRoutesById[match.routeId];
1521
+ if (match.isFetching) {
1522
+ return getRouteMatch(state, match.id)?.loadPromise;
1513
1523
  }
1514
1524
  const fetchedAt = Date.now();
1515
1525
  const checkLatest = () => {
1516
- const latest = this.getRouteMatch(match.id);
1526
+ const latest = getRouteMatch(state, match.id);
1517
1527
  return latest && latest.fetchedAt !== fetchedAt ? latest.loadPromise : undefined;
1518
1528
  };
1519
1529
  const handleIfRedirect = err => {
1520
1530
  if (isRedirect(err)) {
1521
- if (!opts?.preload) {
1522
- this.navigate(err);
1531
+ if (!preload) {
1532
+ navigate(err);
1523
1533
  }
1524
1534
  return true;
1525
1535
  }
@@ -1534,16 +1544,23 @@
1534
1544
  await component.preload();
1535
1545
  }
1536
1546
  }));
1537
- const loaderPromise = route.options.loader?.({
1547
+ const loaderPromise = route.options.load?.({
1538
1548
  params: match.params,
1539
- preload: !!opts?.preload,
1549
+ search: match.search,
1550
+ preload: !!preload,
1540
1551
  parentMatchPromise,
1541
1552
  abortController: match.abortController,
1542
- context: match.context
1553
+ meta: match.meta
1543
1554
  });
1544
- const [_, loader] = await Promise.all([componentsPromise, loaderPromise]);
1555
+ await Promise.all([componentsPromise, loaderPromise]);
1545
1556
  if (latestPromise = checkLatest()) return await latestPromise;
1546
- this.setRouteMatchData(match.id, () => loader, opts);
1557
+ matches[index] = match = {
1558
+ ...match,
1559
+ error: undefined,
1560
+ status: 'success',
1561
+ isFetching: false,
1562
+ updatedAt: Date.now()
1563
+ };
1547
1564
  } catch (error) {
1548
1565
  if (latestPromise = checkLatest()) return await latestPromise;
1549
1566
  if (handleIfRedirect(error)) return;
@@ -1553,88 +1570,150 @@
1553
1570
  error = onErrorError;
1554
1571
  if (handleIfRedirect(onErrorError)) return;
1555
1572
  }
1556
- this.setRouteMatch(match.id, s => ({
1557
- ...s,
1573
+ matches[index] = match = {
1574
+ ...match,
1558
1575
  error,
1559
1576
  status: 'error',
1560
1577
  isFetching: false,
1561
1578
  updatedAt: Date.now()
1562
- }));
1579
+ };
1563
1580
  }
1564
1581
  };
1565
1582
  let loadPromise;
1566
- this.__store.batch(() => {
1567
- this.setRouteMatch(match.id, s => ({
1568
- ...s,
1569
- // status: s.status !== 'success' ? 'pending' : s.status,
1570
- isFetching: true,
1571
- fetchedAt,
1572
- invalid: false
1573
- }));
1574
- loadPromise = load();
1575
- this.setRouteMatch(match.id, s => ({
1576
- ...s,
1577
- loadPromise
1578
- }));
1579
- });
1583
+ matches[index] = match = {
1584
+ ...match,
1585
+ isFetching: true,
1586
+ fetchedAt,
1587
+ invalid: false
1588
+ };
1589
+ loadPromise = load();
1590
+ matches[index] = match = {
1591
+ ...match,
1592
+ loadPromise
1593
+ };
1580
1594
  await loadPromise;
1581
1595
  })());
1582
1596
  });
1583
1597
  await Promise.all(matchPromises);
1584
- };
1585
- resolvePath = (from, path) => {
1586
- return resolvePath(this.basepath, from, cleanPath(path));
1587
- };
1588
- navigate = async ({
1589
- from,
1590
- to = '',
1591
- ...rest
1592
- }) => {
1593
- // If this link simply reloads the current route,
1594
- // make sure it has a new key so it will trigger a data refresh
1598
+ });
1599
+ const load = useStableCallback(async opts => {
1600
+ const promise = new Promise(async (resolve, reject) => {
1601
+ const prevLocation = state.resolvedLocation;
1602
+ const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
1603
+ let latestPromise;
1604
+ const checkLatest = () => {
1605
+ return latestLoadPromiseRef.current !== promise ? latestLoadPromiseRef.current : undefined;
1606
+ };
1595
1607
 
1596
- // If this `to` is a valid external URL, return
1597
- // null for LinkUtils
1598
- const toString = String(to);
1599
- const fromString = typeof from === 'undefined' ? from : String(from);
1600
- let isExternal;
1601
- try {
1602
- new URL(`${toString}`);
1603
- isExternal = true;
1604
- } catch (e) {}
1605
- invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1606
- return this.#buildAndCommitLocation({
1607
- ...rest,
1608
- from: fromString,
1609
- to: toString
1608
+ // Cancel any pending matches
1609
+ cancelMatches(state);
1610
+ router.emit({
1611
+ type: 'onBeforeLoad',
1612
+ from: prevLocation,
1613
+ to: opts?.next ?? state.location,
1614
+ pathChanged: pathDidChange
1615
+ });
1616
+ if (opts?.next) {
1617
+ // Ingest the new location
1618
+ setState(s => ({
1619
+ ...s,
1620
+ location: opts.next
1621
+ }));
1622
+ }
1623
+
1624
+ // Match the routes
1625
+ const matches = matchRoutes(state.location.pathname, state.location.search, {
1626
+ throwOnError: opts?.throwOnError,
1627
+ debug: true
1628
+ });
1629
+ setState(s => ({
1630
+ ...s,
1631
+ status: 'pending',
1632
+ matches
1633
+ }));
1634
+ try {
1635
+ // Load the matches
1636
+ try {
1637
+ await loadMatches({
1638
+ matches
1639
+ });
1640
+ } catch (err) {
1641
+ // swallow this error, since we'll display the
1642
+ // errors on the route components
1643
+ }
1644
+
1645
+ // Only apply the latest transition
1646
+ if (latestPromise = checkLatest()) {
1647
+ return latestPromise;
1648
+ }
1649
+
1650
+ // TODO:
1651
+ // const exitingMatchIds = previousMatches.filter(
1652
+ // (id) => !state.pendingMatches.includes(id),
1653
+ // )
1654
+ // const enteringMatchIds = state.pendingMatches.filter(
1655
+ // (id) => !previousMatches.includes(id),
1656
+ // )
1657
+ // const stayingMatchIds = previousMatches.filter((id) =>
1658
+ // state.pendingMatches.includes(id),
1659
+ // )
1660
+
1661
+ setState(s => ({
1662
+ ...s,
1663
+ status: 'idle',
1664
+ resolvedLocation: s.location
1665
+ }));
1666
+
1667
+ // TODO:
1668
+ // ;(
1669
+ // [
1670
+ // [exitingMatchIds, 'onLeave'],
1671
+ // [enteringMatchIds, 'onEnter'],
1672
+ // [stayingMatchIds, 'onTransition'],
1673
+ // ] as const
1674
+ // ).forEach(([matches, hook]) => {
1675
+ // matches.forEach((match) => {
1676
+ // const route = this.getRoute(match.routeId)
1677
+ // route.options[hook]?.(match)
1678
+ // })
1679
+ // })
1680
+ router.emit({
1681
+ type: 'onLoad',
1682
+ from: prevLocation,
1683
+ to: state.location,
1684
+ pathChanged: pathDidChange
1685
+ });
1686
+ resolve();
1687
+ } catch (err) {
1688
+ // Only apply the latest transition
1689
+ if (latestPromise = checkLatest()) {
1690
+ return latestPromise;
1691
+ }
1692
+ reject(err);
1693
+ }
1610
1694
  });
1611
- };
1612
- matchRoute = (location, opts) => {
1613
- location = {
1614
- ...location,
1615
- to: location.to ? this.resolvePath(location.from ?? '', location.to) : undefined
1616
- };
1617
- const next = this.buildLocation(location);
1618
- if (opts?.pending && this.state.status !== 'pending') {
1619
- return false;
1620
- }
1621
- const baseLocation = opts?.pending ? this.state.location : this.state.resolvedLocation;
1622
- if (!baseLocation) {
1623
- return false;
1695
+ latestLoadPromiseRef.current = promise;
1696
+ return latestLoadPromiseRef.current;
1697
+ });
1698
+ const safeLoad = React__namespace.useCallback(async () => {
1699
+ try {
1700
+ return load();
1701
+ } catch (err) {
1702
+ // Don't do anything
1624
1703
  }
1625
- const match = matchPathname(this.basepath, baseLocation.pathname, {
1626
- ...opts,
1627
- to: next.pathname
1704
+ }, []);
1705
+ const preloadRoute = useStableCallback(async (navigateOpts = state.location) => {
1706
+ let next = buildLocation(navigateOpts);
1707
+ let matches = matchRoutes(next.pathname, next.search, {
1708
+ throwOnError: true
1628
1709
  });
1629
- if (!match) {
1630
- return false;
1631
- }
1632
- if (opts?.includeSearch ?? true) {
1633
- return partialDeepEqual(baseLocation.search, next.search) ? match : false;
1634
- }
1635
- return match;
1636
- };
1637
- buildLink = dest => {
1710
+ await loadMatches({
1711
+ matches,
1712
+ preload: true
1713
+ });
1714
+ return [last(matches), matches];
1715
+ });
1716
+ const buildLink = useStableCallback((state, dest) => {
1638
1717
  // If this link simply reloads the current route,
1639
1718
  // make sure it has a new key so it will trigger a data refresh
1640
1719
 
@@ -1659,18 +1738,18 @@
1659
1738
  };
1660
1739
  } catch (e) {}
1661
1740
  const nextOpts = dest;
1662
- const next = this.buildLocation(nextOpts);
1663
- const preload = userPreload ?? this.options.defaultPreload;
1664
- const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
1741
+ const next = buildLocation(nextOpts);
1742
+ const preload = userPreload ?? options.defaultPreload;
1743
+ const preloadDelay = userPreloadDelay ?? options.defaultPreloadDelay ?? 0;
1665
1744
 
1666
1745
  // Compare path/hash for matches
1667
- const currentPathSplit = this.state.location.pathname.split('/');
1746
+ const currentPathSplit = latestLocationRef.current.pathname.split('/');
1668
1747
  const nextPathSplit = next.pathname.split('/');
1669
1748
  const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
1670
1749
  // Combine the matches based on user options
1671
- const pathTest = activeOptions?.exact ? this.state.location.pathname === next.pathname : pathIsFuzzyEqual;
1672
- const hashTest = activeOptions?.includeHash ? this.state.location.hash === next.hash : true;
1673
- const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(this.state.location.search, next.search) : true;
1750
+ const pathTest = activeOptions?.exact ? latestLocationRef.current.pathname === next.pathname : pathIsFuzzyEqual;
1751
+ const hashTest = activeOptions?.includeHash ? latestLocationRef.current.hash === next.hash : true;
1752
+ const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(latestLocationRef.current.search, next.search) : true;
1674
1753
 
1675
1754
  // The final "active" test
1676
1755
  const isActive = pathTest && hashTest && searchTest;
@@ -1681,7 +1760,7 @@
1681
1760
  e.preventDefault();
1682
1761
 
1683
1762
  // All is well? Navigate!
1684
- this.#commitLocation({
1763
+ commitLocation({
1685
1764
  ...next,
1686
1765
  replace,
1687
1766
  resetScroll
@@ -1692,14 +1771,14 @@
1692
1771
  // The click handler
1693
1772
  const handleFocus = e => {
1694
1773
  if (preload) {
1695
- this.preloadRoute(nextOpts).catch(err => {
1774
+ preloadRoute(nextOpts).catch(err => {
1696
1775
  console.warn(err);
1697
1776
  console.warn(preloadWarning);
1698
1777
  });
1699
1778
  }
1700
1779
  };
1701
1780
  const handleTouchStart = e => {
1702
- this.preloadRoute(nextOpts).catch(err => {
1781
+ preloadRoute(nextOpts).catch(err => {
1703
1782
  console.warn(err);
1704
1783
  console.warn(preloadWarning);
1705
1784
  });
@@ -1712,7 +1791,7 @@
1712
1791
  }
1713
1792
  target.preloadTimeout = setTimeout(() => {
1714
1793
  target.preloadTimeout = null;
1715
- this.preloadRoute(nextOpts).catch(err => {
1794
+ preloadRoute(nextOpts).catch(err => {
1716
1795
  console.warn(err);
1717
1796
  console.warn(preloadWarning);
1718
1797
  });
@@ -1737,663 +1816,95 @@
1737
1816
  isActive,
1738
1817
  disabled
1739
1818
  };
1740
- };
1741
- dehydrate = () => {
1742
- return {
1743
- state: {
1744
- matchIds: this.state.matchIds,
1745
- dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', 'preloadMaxAge', 'maxAge', 'id', 'loaderData', 'status', 'updatedAt']))
1746
- }
1747
- };
1748
- };
1749
- hydrate = async __do_not_use_server_ctx => {
1750
- let _ctx = __do_not_use_server_ctx;
1751
- // Client hydrates from window
1752
- if (typeof document !== 'undefined') {
1753
- _ctx = window.__TSR_DEHYDRATED__;
1754
- }
1755
- invariant(_ctx, 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?');
1756
- const ctx = _ctx;
1757
- this.dehydratedData = ctx.payload;
1758
- this.options.hydrate?.(ctx.payload);
1759
- const dehydratedState = ctx.router.state;
1760
- let matches = this.matchRoutes(this.state.location.pathname, this.state.location.search).map(match => {
1761
- const dehydratedMatch = dehydratedState.dehydratedMatches.find(d => d.id === match.id);
1762
- invariant(dehydratedMatch, `Could not find a client-side match for dehydrated match with id: ${match.id}!`);
1763
- if (dehydratedMatch) {
1764
- return {
1765
- ...match,
1766
- ...dehydratedMatch
1767
- };
1768
- }
1769
- return match;
1819
+ });
1820
+ const latestLocationRef = React__namespace.useRef(state.location);
1821
+ React__namespace.useLayoutEffect(() => {
1822
+ const unsub = history.subscribe(() => {
1823
+ latestLocationRef.current = parseLocation(latestLocationRef.current);
1824
+ React__namespace.startTransition(() => {
1825
+ setState(s => ({
1826
+ ...s,
1827
+ location: latestLocationRef.current
1828
+ }));
1829
+ });
1770
1830
  });
1771
- this.__store.setState(s => {
1772
- return {
1773
- ...s,
1774
- matchIds: dehydratedState.matchIds,
1775
- matches,
1776
- matchesById: this.#mergeMatches(s.matchesById, matches)
1777
- };
1831
+ const nextLocation = buildLocation({
1832
+ search: true,
1833
+ params: true,
1834
+ hash: true,
1835
+ state: true
1778
1836
  });
1779
- };
1780
- injectedHtml = [];
1781
- injectHtml = async html => {
1782
- this.injectedHtml.push(html);
1783
- };
1784
- dehydrateData = (key, getData) => {
1785
- if (typeof document === 'undefined') {
1786
- const strKey = typeof key === 'string' ? key : JSON.stringify(key);
1787
- this.injectHtml(async () => {
1788
- const id = `__TSR_DEHYDRATED__${strKey}`;
1789
- const data = typeof getData === 'function' ? await getData() : getData;
1790
- return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
1791
- ;(() => {
1792
- var el = document.getElementById('${id}')
1793
- el.parentElement.removeChild(el)
1794
- })()
1795
- </script>`;
1837
+ if (state.location.href !== nextLocation.href) {
1838
+ commitLocation({
1839
+ ...nextLocation,
1840
+ replace: true
1796
1841
  });
1797
- return () => this.hydrateData(key);
1798
- }
1799
- return () => undefined;
1800
- };
1801
- hydrateData = key => {
1802
- if (typeof document !== 'undefined') {
1803
- const strKey = typeof key === 'string' ? key : JSON.stringify(key);
1804
- return window[`__TSR_DEHYDRATED__${strKey}`];
1805
- }
1806
- return undefined;
1807
- };
1808
-
1809
- // resolveMatchPromise = (matchId: string, key: string, value: any) => {
1810
- // this.state.matches
1811
- // .find((d) => d.id === matchId)
1812
- // ?.__promisesByKey[key]?.resolve(value)
1813
- // }
1814
-
1815
- #processRoutes = routeTree => {
1816
- this.routeTree = routeTree;
1817
- this.routesById = {};
1818
- this.routesByPath = {};
1819
- this.flatRoutes = [];
1820
- const recurseRoutes = routes => {
1821
- routes.forEach((route, i) => {
1822
- route.init({
1823
- originalIndex: i,
1824
- router: this
1825
- });
1826
- const existingRoute = this.routesById[route.id];
1827
- invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
1828
- this.routesById[route.id] = route;
1829
- if (!route.isRoot && route.path) {
1830
- const trimmedFullPath = trimPathRight(route.fullPath);
1831
- if (!this.routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
1832
- this.routesByPath[trimmedFullPath] = route;
1833
- }
1834
- }
1835
- const children = route.children;
1836
- if (children?.length) {
1837
- recurseRoutes(children);
1838
- }
1839
- });
1840
- };
1841
- recurseRoutes([routeTree]);
1842
- this.flatRoutes = Object.values(this.routesByPath).map((d, i) => {
1843
- const trimmed = trimPath(d.fullPath);
1844
- const parsed = parsePathname(trimmed);
1845
- while (parsed.length > 1 && parsed[0]?.value === '/') {
1846
- parsed.shift();
1847
- }
1848
- const score = parsed.map(d => {
1849
- if (d.type === 'param') {
1850
- return 0.5;
1851
- }
1852
- if (d.type === 'wildcard') {
1853
- return 0.25;
1854
- }
1855
- return 1;
1856
- });
1857
- return {
1858
- child: d,
1859
- trimmed,
1860
- parsed,
1861
- index: i,
1862
- score
1863
- };
1864
- }).sort((a, b) => {
1865
- let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
1866
- if (isIndex !== 0) return isIndex;
1867
- const length = Math.min(a.score.length, b.score.length);
1868
-
1869
- // Sort by length of score
1870
- if (a.score.length !== b.score.length) {
1871
- return b.score.length - a.score.length;
1872
- }
1873
-
1874
- // Sort by min available score
1875
- for (let i = 0; i < length; i++) {
1876
- if (a.score[i] !== b.score[i]) {
1877
- return b.score[i] - a.score[i];
1878
- }
1879
- }
1880
-
1881
- // Sort by min available parsed value
1882
- for (let i = 0; i < length; i++) {
1883
- if (a.parsed[i].value !== b.parsed[i].value) {
1884
- return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
1885
- }
1886
- }
1887
-
1888
- // Sort by length of trimmed full path
1889
- if (a.trimmed !== b.trimmed) {
1890
- return a.trimmed > b.trimmed ? 1 : -1;
1891
- }
1892
-
1893
- // Sort by original index
1894
- return a.index - b.index;
1895
- }).map((d, i) => {
1896
- d.child.rank = i;
1897
- return d.child;
1898
- });
1899
- };
1900
- #parseLocation = previousLocation => {
1901
- const parse = ({
1902
- pathname,
1903
- search,
1904
- hash,
1905
- state
1906
- }) => {
1907
- const parsedSearch = this.options.parseSearch(search);
1908
- return {
1909
- pathname: pathname,
1910
- searchStr: search,
1911
- search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1912
- hash: hash.split('#').reverse()[0] ?? '',
1913
- href: `${pathname}${search}${hash}`,
1914
- state: replaceEqualDeep(previousLocation?.state, state)
1915
- };
1916
- };
1917
- const location = parse(this.history.location);
1918
- let {
1919
- __tempLocation,
1920
- __tempKey
1921
- } = location.state;
1922
- if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
1923
- // Sync up the location keys
1924
- const parsedTempLocation = parse(__tempLocation);
1925
- parsedTempLocation.state.key = location.state.key;
1926
- delete parsedTempLocation.state.__tempLocation;
1927
- return {
1928
- ...parsedTempLocation,
1929
- maskedLocation: location
1930
- };
1931
- }
1932
- return location;
1933
- };
1934
- buildLocation = (opts = {}) => {
1935
- const build = (dest = {}, matches) => {
1936
- const from = this.state.location;
1937
- const fromPathname = dest.from ?? from.pathname;
1938
- let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? ''}`);
1939
- const fromMatches = this.matchRoutes(fromPathname, from.search);
1940
- const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
1941
- const prevParams = {
1942
- ...last(fromMatches)?.params
1943
- };
1944
- let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1945
- if (nextParams) {
1946
- matches?.map(d => this.getRoute(d.routeId).options.stringifyParams).filter(Boolean).forEach(fn => {
1947
- nextParams = {
1948
- ...nextParams,
1949
- ...fn(nextParams)
1950
- };
1951
- });
1952
- }
1953
- pathname = interpolatePath(pathname, nextParams ?? {});
1954
- const preSearchFilters = stayingMatches?.map(match => this.getRoute(match.routeId).options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
1955
- const postSearchFilters = stayingMatches?.map(match => this.getRoute(match.routeId).options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
1956
-
1957
- // Pre filters first
1958
- const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
1959
-
1960
- // Then the link/navigate function
1961
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1962
- : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
1963
- : preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
1964
- : {};
1965
-
1966
- // Then post filters
1967
- const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1968
- const search = replaceEqualDeep(from.search, postFilteredSearch);
1969
- const searchStr = this.options.stringifySearch(search);
1970
- const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
1971
- const hashStr = hash ? `#${hash}` : '';
1972
- let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
1973
- nextState = replaceEqualDeep(from.state, nextState);
1974
- return {
1975
- pathname,
1976
- search,
1977
- searchStr,
1978
- state: nextState,
1979
- hash,
1980
- href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
1981
- unmaskOnReload: dest.unmaskOnReload
1982
- };
1983
- };
1984
- const buildWithMatches = (dest = {}, maskedDest) => {
1985
- let next = build(dest);
1986
- let maskedNext = maskedDest ? build(maskedDest) : undefined;
1987
- if (!maskedNext) {
1988
- let params = {};
1989
- let foundMask = this.options.routeMasks?.find(d => {
1990
- const match = matchPathname(this.basepath, next.pathname, {
1991
- to: d.from,
1992
- fuzzy: false
1993
- });
1994
- if (match) {
1995
- params = match;
1996
- return true;
1997
- }
1998
- return false;
1999
- });
2000
- if (foundMask) {
2001
- foundMask = {
2002
- ...foundMask,
2003
- from: interpolatePath(foundMask.from, params)
2004
- };
2005
- maskedDest = foundMask;
2006
- maskedNext = build(maskedDest);
2007
- }
2008
- }
2009
- const nextMatches = this.matchRoutes(next.pathname, next.search);
2010
- const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
2011
- const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
2012
- const final = build(dest, nextMatches);
2013
- if (maskedFinal) {
2014
- final.maskedLocation = maskedFinal;
2015
- }
2016
- return final;
2017
- };
2018
- if (opts.mask) {
2019
- return buildWithMatches(opts, {
2020
- ...pick(opts, ['from']),
2021
- ...opts.mask
2022
- });
2023
- }
2024
- return buildWithMatches(opts);
2025
- };
2026
- #buildAndCommitLocation = ({
2027
- replace,
2028
- resetScroll,
2029
- ...rest
2030
- } = {}) => {
2031
- const location = this.buildLocation(rest);
2032
- return this.#commitLocation({
2033
- ...location,
2034
- replace,
2035
- resetScroll
2036
- });
2037
- };
2038
- #commitLocation = async next => {
2039
- if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
2040
- const isSameUrl = this.state.location.href === next.href;
2041
-
2042
- // If the next urls are the same and we're not replacing,
2043
- // do nothing
2044
- if (!isSameUrl || !next.replace) {
2045
- let {
2046
- maskedLocation,
2047
- ...nextHistory
2048
- } = next;
2049
- if (maskedLocation) {
2050
- nextHistory = {
2051
- ...maskedLocation,
2052
- state: {
2053
- ...maskedLocation.state,
2054
- __tempKey: undefined,
2055
- __tempLocation: {
2056
- ...nextHistory,
2057
- search: nextHistory.searchStr,
2058
- state: {
2059
- ...nextHistory.state,
2060
- __tempKey: undefined,
2061
- __tempLocation: undefined,
2062
- key: undefined
2063
- }
2064
- }
2065
- }
2066
- };
2067
- if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
2068
- nextHistory.state.__tempKey = this.tempLocationKey;
2069
- }
2070
- }
2071
- this.history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
2072
- }
2073
- this.resetNextScroll = next.resetScroll ?? true;
2074
- return this.latestLoadPromise;
2075
- };
2076
- getRouteMatch = id => {
2077
- return this.state.matchesById[id];
2078
- };
2079
- setRouteMatch = (id, updater) => {
2080
- this.__store.setState(prev => {
2081
- if (!prev.matchesById[id]) {
2082
- return prev;
2083
- }
2084
- return {
2085
- ...prev,
2086
- matchesById: {
2087
- ...prev.matchesById,
2088
- [id]: updater(prev.matchesById[id])
2089
- }
2090
- };
2091
- });
2092
- };
2093
- setRouteMatchData = (id, updater, opts) => {
2094
- const match = this.getRouteMatch(id);
2095
- if (!match) return;
2096
- const route = this.getRoute(match.routeId);
2097
- const updatedAt = opts?.updatedAt ?? Date.now();
2098
- const preloadMaxAge = opts?.maxAge ?? route.options.preloadMaxAge ?? this.options.defaultPreloadMaxAge ?? 5000;
2099
- const maxAge = opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? -1;
2100
- this.setRouteMatch(id, s => ({
2101
- ...s,
2102
- error: undefined,
2103
- status: 'success',
2104
- isFetching: false,
2105
- updatedAt: updatedAt,
2106
- loaderData: functionalUpdate(updater, s.loaderData),
2107
- preloadMaxAge,
2108
- maxAge
2109
- }));
2110
- };
2111
- invalidate = async opts => {
2112
- if (opts?.matchId) {
2113
- this.setRouteMatch(opts.matchId, s => ({
2114
- ...s,
2115
- invalid: true
2116
- }));
2117
- const matchIndex = this.state.matches.findIndex(d => d.id === opts.matchId);
2118
- const childMatch = this.state.matches[matchIndex + 1];
2119
- if (childMatch) {
2120
- return this.invalidate({
2121
- matchId: childMatch.id,
2122
- reload: false,
2123
- __fromFocus: opts.__fromFocus
2124
- });
2125
- }
2126
- } else {
2127
- this.__store.batch(() => {
2128
- Object.values(this.state.matchesById).forEach(match => {
2129
- const route = this.getRoute(match.routeId);
2130
- const shouldInvalidate = opts?.__fromFocus ? route.options.reloadOnWindowFocus ?? true : true;
2131
- if (shouldInvalidate) {
2132
- this.setRouteMatch(match.id, s => ({
2133
- ...s,
2134
- invalid: true
2135
- }));
2136
- }
2137
- });
2138
- });
2139
- }
2140
- if (opts?.reload ?? true) {
2141
- return this.load();
2142
- }
2143
- };
2144
- }
2145
-
2146
- // Detect if we're in the DOM
2147
- const isServer = typeof window === 'undefined' || !window.document.createElement;
2148
- function getInitialRouterState() {
2149
- return {
2150
- status: 'idle',
2151
- isFetching: false,
2152
- resolvedLocation: null,
2153
- location: null,
2154
- matchesById: {},
2155
- matchIds: [],
2156
- pendingMatchIds: [],
2157
- matches: [],
2158
- pendingMatches: [],
2159
- renderedMatchIds: [],
2160
- renderedMatches: [],
2161
- lastUpdated: Date.now()
2162
- };
2163
- }
2164
- function isCtrlEvent(e) {
2165
- return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2166
- }
2167
- function redirect(opts) {
2168
- opts.isRedirect = true;
2169
- return opts;
2170
- }
2171
- function isRedirect(obj) {
2172
- return !!obj?.isRedirect;
2173
- }
2174
- class SearchParamError extends Error {}
2175
- class PathParamError extends Error {}
2176
- function escapeJSON(jsonString) {
2177
- return jsonString.replace(/\\/g, '\\\\') // Escape backslashes
2178
- .replace(/'/g, "\\'") // Escape single quotes
2179
- .replace(/"/g, '\\"'); // Escape double quotes
2180
- }
2181
-
2182
- // A function that takes an import() argument which is a function and returns a new function that will
2183
- // proxy arguments from the caller to the imported function, retaining all type
2184
- // information along the way
2185
- function lazyFn(fn, key) {
2186
- return async (...args) => {
2187
- const imported = await fn();
2188
- return imported[key || 'default'](...args);
2189
- };
2190
- }
2191
- function isMatchInvalid(match, opts) {
2192
- const now = Date.now();
2193
- if (match.invalid) {
2194
- return true;
2195
- }
2196
- if (opts?.preload) {
2197
- return match.preloadMaxAge < 0 ? false : match.updatedAt + match.preloadMaxAge < now;
2198
- }
2199
- return match.maxAge < 0 ? false : match.updatedAt + match.maxAge < now;
2200
- }
2201
-
2202
- const windowKey = 'window';
2203
- const delimiter = '___';
2204
- let weakScrolledElementsByRestoreKey = {};
2205
- let cache;
2206
- let pathDidChange = false;
2207
- const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
2208
- const defaultGetKey = location => location.state.key;
2209
- function watchScrollPositions(router, opts) {
2210
- const getKey = opts?.getKey || defaultGetKey;
2211
- if (sessionsStorage) {
2212
- if (!cache) {
2213
- cache = (() => {
2214
- const storageKey = 'tsr-scroll-restoration-v1';
2215
- const current = JSON.parse(window.sessionStorage.getItem(storageKey) || '{}');
2216
- return {
2217
- current,
2218
- set: (key, value) => {
2219
- current[key] = value;
2220
- window.sessionStorage.setItem(storageKey, JSON.stringify(cache));
2221
- }
2222
- };
2223
- })();
2224
- }
2225
- }
2226
- const {
2227
- history
2228
- } = window;
2229
- if (history.scrollRestoration) {
2230
- history.scrollRestoration = 'manual';
2231
- }
2232
- const onScroll = event => {
2233
- const restoreKey = getKey(router.state.resolvedLocation);
2234
- if (!weakScrolledElementsByRestoreKey[restoreKey]) {
2235
- weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet();
2236
- }
2237
- const set = weakScrolledElementsByRestoreKey[restoreKey];
2238
- if (set.has(event.target)) return;
2239
- set.add(event.target);
2240
- const cacheKey = [restoreKey, event.target === document || event.target === window ? windowKey : getCssSelector(event.target)].join(delimiter);
2241
- if (!cache.current[cacheKey]) {
2242
- cache.set(cacheKey, {
2243
- scrollX: NaN,
2244
- scrollY: NaN
2245
- });
2246
- }
2247
- };
2248
- const getCssSelector = el => {
2249
- let path = [],
2250
- parent;
2251
- while (parent = el.parentNode) {
2252
- path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`);
2253
- el = parent;
2254
- }
2255
- return `${path.join(' > ')}`.toLowerCase();
2256
- };
2257
- const onPathWillChange = from => {
2258
- const restoreKey = getKey(from);
2259
- for (const cacheKey in cache.current) {
2260
- const entry = cache.current[cacheKey];
2261
- const [key, elementSelector] = cacheKey.split(delimiter);
2262
- if (restoreKey === key) {
2263
- if (elementSelector === windowKey) {
2264
- entry.scrollX = window.scrollX || 0;
2265
- entry.scrollY = window.scrollY || 0;
2266
- } else if (elementSelector) {
2267
- const element = document.querySelector(elementSelector);
2268
- entry.scrollX = element?.scrollLeft || 0;
2269
- entry.scrollY = element?.scrollTop || 0;
2270
- }
2271
- cache.set(cacheKey, entry);
2272
- }
2273
- }
2274
- };
2275
- const onPathChange = () => {
2276
- pathDidChange = true;
2277
- };
2278
- if (typeof document !== 'undefined') {
2279
- document.addEventListener('scroll', onScroll, true);
2280
- }
2281
- const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
2282
- if (event.pathChanged) onPathWillChange(event.from);
2283
- });
2284
- const unsubOnLoad = router.subscribe('onLoad', event => {
2285
- if (event.pathChanged) onPathChange();
2286
- });
2287
- return () => {
2288
- document.removeEventListener('scroll', onScroll);
2289
- unsubOnBeforeLoad();
2290
- unsubOnLoad();
2291
- };
2292
- }
2293
- function restoreScrollPositions(router, opts) {
2294
- if (pathDidChange) {
2295
- if (!router.resetNextScroll) {
2296
- return;
2297
- }
2298
- const getKey = opts?.getKey || defaultGetKey;
2299
- pathDidChange = false;
2300
- const restoreKey = getKey(router.state.location);
2301
- let windowRestored = false;
2302
- for (const cacheKey in cache.current) {
2303
- const entry = cache.current[cacheKey];
2304
- const [key, elementSelector] = cacheKey.split(delimiter);
2305
- if (key === restoreKey) {
2306
- if (elementSelector === windowKey) {
2307
- windowRestored = true;
2308
- window.scrollTo(entry.scrollX, entry.scrollY);
2309
- } else if (elementSelector) {
2310
- const element = document.querySelector(elementSelector);
2311
- if (element) {
2312
- element.scrollLeft = entry.scrollX;
2313
- element.scrollTop = entry.scrollY;
2314
- }
2315
- }
2316
- }
2317
- }
2318
- if (!windowRestored) {
2319
- window.scrollTo(0, 0);
2320
1842
  }
1843
+ return () => {
1844
+ unsub();
1845
+ };
1846
+ }, [history]);
1847
+ const initialLoad = React__namespace.useRef(true);
1848
+ if (initialLoad.current) {
1849
+ initialLoad.current = false;
1850
+ safeLoad();
2321
1851
  }
2322
- }
2323
-
2324
- function defer(_promise) {
2325
- const promise = _promise;
2326
- if (!promise.__deferredState) {
2327
- promise.__deferredState = {
2328
- uid: Math.random().toString(36).slice(2),
2329
- status: 'pending'
1852
+ React__namespace.useLayoutEffect(() => {
1853
+ if (state.resolvedLocation !== state.location) {
1854
+ safeLoad();
1855
+ }
1856
+ }, [state.location]);
1857
+ React__namespace.useMemo(() => [...state.matches, ...state.pendingMatches].some(d => d.isFetching), [state.matches, state.pendingMatches]);
1858
+ const matchRoute = useStableCallback((state, location, opts) => {
1859
+ location = {
1860
+ ...location,
1861
+ to: location.to ? resolvePathWithBase(location.from || '', location.to) : undefined
2330
1862
  };
2331
- const state = promise.__deferredState;
2332
- promise.then(data => {
2333
- state.status = 'success';
2334
- state.data = data;
2335
- }).catch(error => {
2336
- state.status = 'error';
2337
- state.error = error;
1863
+ const next = buildLocation(location);
1864
+ if (opts?.pending && state.status !== 'pending') {
1865
+ return false;
1866
+ }
1867
+ const baseLocation = opts?.pending ? latestLocationRef.current : state.resolvedLocation;
1868
+ if (!baseLocation) {
1869
+ return false;
1870
+ }
1871
+ const match = matchPathname(basepath, baseLocation.pathname, {
1872
+ ...opts,
1873
+ to: next.pathname
2338
1874
  });
2339
- }
2340
- return promise;
2341
- }
2342
- function isDehydratedDeferred(obj) {
2343
- return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
2344
- }
2345
-
2346
- function _extends() {
2347
- _extends = Object.assign ? Object.assign.bind() : function (target) {
2348
- for (var i = 1; i < arguments.length; i++) {
2349
- var source = arguments[i];
2350
- for (var key in source) {
2351
- if (Object.prototype.hasOwnProperty.call(source, key)) {
2352
- target[key] = source[key];
2353
- }
2354
- }
1875
+ if (!match) {
1876
+ return false;
2355
1877
  }
2356
- return target;
1878
+ if (opts?.includeSearch ?? true) {
1879
+ return partialDeepEqual(baseLocation.search, next.search) ? match : false;
1880
+ }
1881
+ return match;
1882
+ });
1883
+ const routerContextValue = {
1884
+ routeTree: router.routeTree,
1885
+ navigate,
1886
+ buildLink,
1887
+ state,
1888
+ matchRoute,
1889
+ routesById,
1890
+ options,
1891
+ history,
1892
+ load
2357
1893
  };
2358
- return _extends.apply(this, arguments);
1894
+ return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
1895
+ value: routerContextValue
1896
+ }, /*#__PURE__*/React__namespace.createElement(Matches, null));
1897
+ }
1898
+ function isCtrlEvent(e) {
1899
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1900
+ }
1901
+ class SearchParamError extends Error {}
1902
+ class PathParamError extends Error {}
1903
+ function getRouteMatch(state, id) {
1904
+ return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
2359
1905
  }
2360
1906
 
2361
- const useLayoutEffect$1 = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
2362
- Route.__onInit = route => {
2363
- Object.assign(route, {
2364
- useMatch: (opts = {}) => {
2365
- return useMatch({
2366
- ...opts,
2367
- from: route.id
2368
- });
2369
- },
2370
- useLoader: (opts = {}) => {
2371
- return useLoader({
2372
- ...opts,
2373
- from: route.id
2374
- });
2375
- },
2376
- useRouteContext: (opts = {}) => {
2377
- return useMatch({
2378
- ...opts,
2379
- from: route.id,
2380
- select: d => opts?.select ? opts.select(d.context) : d.context
2381
- });
2382
- },
2383
- useSearch: (opts = {}) => {
2384
- return useSearch({
2385
- ...opts,
2386
- from: route.id
2387
- });
2388
- },
2389
- useParams: (opts = {}) => {
2390
- return useParams({
2391
- ...opts,
2392
- from: route.id
2393
- });
2394
- }
2395
- });
2396
- };
1907
+ const useLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
2397
1908
 
2398
1909
  //
2399
1910
 
@@ -2418,7 +1929,10 @@
2418
1929
  //
2419
1930
 
2420
1931
  function useLinkProps(options) {
2421
- const router = useRouter();
1932
+ const {
1933
+ buildLink,
1934
+ state: routerState
1935
+ } = useRouter();
2422
1936
  const match = useMatch({
2423
1937
  strict: false
2424
1938
  });
@@ -2452,7 +1966,7 @@
2452
1966
  onTouchStart,
2453
1967
  ...rest
2454
1968
  } = options;
2455
- const linkInfo = router.buildLink({
1969
+ const linkInfo = buildLink(routerState, {
2456
1970
  from: options.to ? match.pathname : undefined,
2457
1971
  ...options
2458
1972
  });
@@ -2528,92 +2042,48 @@
2528
2042
  }));
2529
2043
  });
2530
2044
  function Navigate(props) {
2531
- const router = useRouter();
2045
+ const {
2046
+ navigate
2047
+ } = useRouter();
2532
2048
  const match = useMatch({
2533
2049
  strict: false
2534
2050
  });
2535
- useLayoutEffect$1(() => {
2536
- router.navigate({
2051
+ useLayoutEffect(() => {
2052
+ navigate({
2537
2053
  from: props.to ? match.pathname : undefined,
2538
2054
  ...props
2539
2055
  });
2540
2056
  }, []);
2541
2057
  return null;
2542
2058
  }
2543
- const matchIdsContext = /*#__PURE__*/React__namespace.createContext(null);
2544
- const routerContext = /*#__PURE__*/React__namespace.createContext(null);
2545
- function useRouterState(opts) {
2546
- const router = useRouter();
2547
- return useStore(router.__store, opts?.select);
2548
- }
2549
- function RouterProvider({
2550
- router,
2551
- ...rest
2552
- }) {
2553
- router.update(rest);
2554
- React__namespace.useEffect(() => {
2555
- let unsub;
2556
- React__namespace.startTransition(() => {
2557
- unsub = router.mount();
2558
- });
2559
- return unsub;
2560
- }, [router]);
2561
- const Wrap = router.options.Wrap || React__namespace.Fragment;
2562
- return /*#__PURE__*/React__namespace.createElement(Wrap, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2563
- value: router
2564
- }, /*#__PURE__*/React__namespace.createElement(Matches, null)));
2565
- }
2566
- function Matches() {
2567
- const router = useRouter();
2568
- const matchIds = useRouterState({
2569
- select: state => {
2570
- return state.renderedMatchIds;
2571
- }
2572
- });
2573
- const locationKey = useRouterState({
2574
- select: d => d.resolvedLocation.state?.key
2575
- });
2576
- const route = router.getRoute(rootRouteId);
2577
- const errorComponent = React__namespace.useCallback(props => {
2578
- return /*#__PURE__*/React__namespace.createElement(ErrorComponent, {
2579
- ...props,
2580
- useMatch: route.useMatch,
2581
- useRouteContext: route.useRouteContext,
2582
- useSearch: route.useSearch,
2583
- useParams: route.useParams
2584
- });
2585
- }, [route]);
2586
- return /*#__PURE__*/React__namespace.createElement(matchIdsContext.Provider, {
2587
- value: [undefined, ...matchIds]
2588
- }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
2589
- resetKey: locationKey,
2590
- errorComponent: errorComponent,
2591
- onCatch: () => {
2592
- warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
2593
- }
2594
- }, /*#__PURE__*/React__namespace.createElement(Outlet, null)));
2595
- }
2059
+ const matchesContext = /*#__PURE__*/React__namespace.createContext(null);
2596
2060
  function useRouter() {
2597
2061
  const value = React__namespace.useContext(routerContext);
2598
- warning(value, 'useRouter must be used inside a <Router> component!');
2062
+ warning(value, 'useRouter must be used inside a <RouterProvider> component!');
2599
2063
  return value;
2600
2064
  }
2065
+ function useRouterState(opts) {
2066
+ const {
2067
+ state
2068
+ } = useRouter();
2069
+ // return useStore(router.__store, opts?.select as any)
2070
+ return opts?.select ? opts.select(state) : state;
2071
+ }
2601
2072
  function useMatches(opts) {
2602
- const matchIds = React__namespace.useContext(matchIdsContext);
2073
+ const contextMatches = React__namespace.useContext(matchesContext);
2603
2074
  return useRouterState({
2604
2075
  select: state => {
2605
- const matches = state.renderedMatches.slice(state.renderedMatches.findIndex(d => d.id === matchIds[0]));
2076
+ const matches = state.matches.slice(state.matches.findIndex(d => d.id === contextMatches[0]?.id));
2606
2077
  return opts?.select ? opts.select(matches) : matches;
2607
2078
  }
2608
2079
  });
2609
2080
  }
2610
2081
  function useMatch(opts) {
2611
- const router = useRouter();
2612
- const nearestMatchId = React__namespace.useContext(matchIdsContext)[0];
2613
- const nearestMatchRouteId = router.getRouteMatch(nearestMatchId)?.routeId;
2082
+ const nearestMatch = React__namespace.useContext(matchesContext)[0];
2083
+ const nearestMatchRouteId = nearestMatch?.routeId;
2614
2084
  const matchRouteId = useRouterState({
2615
2085
  select: state => {
2616
- const match = opts?.from ? state.renderedMatches.find(d => d.routeId === opts?.from) : state.renderedMatches.find(d => d.id === nearestMatchId);
2086
+ const match = opts?.from ? state.matches.find(d => d.routeId === opts?.from) : state.matches.find(d => d.id === nearestMatch.id);
2617
2087
  return match.routeId;
2618
2088
  }
2619
2089
  });
@@ -2622,29 +2092,17 @@
2622
2092
  }
2623
2093
  const matchSelection = useRouterState({
2624
2094
  select: state => {
2625
- const match = opts?.from ? state.renderedMatches.find(d => d.routeId === opts?.from) : state.renderedMatches.find(d => d.id === nearestMatchId);
2095
+ const match = opts?.from ? state.matches.find(d => d.routeId === opts?.from) : state.matches.find(d => d.id === nearestMatch.id);
2626
2096
  invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
2627
2097
  return opts?.select ? opts.select(match) : match;
2628
2098
  }
2629
2099
  });
2630
2100
  return matchSelection;
2631
2101
  }
2632
- function useLoader(opts) {
2633
- return useMatch({
2634
- ...opts,
2635
- select: match => opts?.select ? opts?.select(match.loaderData) : match.loaderData
2636
- });
2637
- }
2638
- function useRouterContext(opts) {
2639
- return useMatch({
2640
- ...opts,
2641
- select: match => opts?.select ? opts.select(match.context) : match.context
2642
- });
2643
- }
2644
- function useRouteContext(opts) {
2102
+ function useRouteMeta(opts) {
2645
2103
  return useMatch({
2646
2104
  ...opts,
2647
- select: match => opts?.select ? opts.select(match.context) : match.context
2105
+ select: match => opts?.select ? opts.select(match.meta) : match.meta
2648
2106
  });
2649
2107
  }
2650
2108
  function useSearch(opts) {
@@ -2658,18 +2116,20 @@
2658
2116
  function useParams(opts) {
2659
2117
  return useRouterState({
2660
2118
  select: state => {
2661
- const params = last(state.renderedMatches)?.params;
2119
+ const params = last(state.matches)?.params;
2662
2120
  return opts?.select ? opts.select(params) : params;
2663
2121
  }
2664
2122
  });
2665
2123
  }
2666
2124
  function useNavigate(defaultOpts) {
2667
- const router = useRouter();
2125
+ const {
2126
+ navigate
2127
+ } = useRouter();
2668
2128
  const match = useMatch({
2669
2129
  strict: false
2670
2130
  });
2671
2131
  return React__namespace.useCallback(opts => {
2672
- return router.navigate({
2132
+ return navigate({
2673
2133
  from: opts?.to ? match.pathname : undefined,
2674
2134
  ...defaultOpts,
2675
2135
  ...opts
@@ -2677,19 +2137,62 @@
2677
2137
  }, []);
2678
2138
  }
2679
2139
  function useMatchRoute() {
2680
- const router = useRouter();
2140
+ const {
2141
+ state,
2142
+ matchRoute
2143
+ } = useRouter();
2681
2144
  return React__namespace.useCallback(opts => {
2682
2145
  const {
2683
2146
  pending,
2684
2147
  caseSensitive,
2685
2148
  ...rest
2686
2149
  } = opts;
2687
- return router.matchRoute(rest, {
2150
+ return matchRoute(state, rest, {
2688
2151
  pending,
2689
2152
  caseSensitive
2690
2153
  });
2691
2154
  }, []);
2692
2155
  }
2156
+ function Matches() {
2157
+ const {
2158
+ routesById,
2159
+ state
2160
+ } = useRouter();
2161
+
2162
+ // const matches = useRouterState({
2163
+ // select: (state) => {
2164
+ // return state.matches
2165
+ // },
2166
+ // })
2167
+
2168
+ const {
2169
+ matches
2170
+ } = state;
2171
+ const locationKey = useRouterState({
2172
+ select: d => d.resolvedLocation.state?.key
2173
+ });
2174
+ const route = routesById[rootRouteId];
2175
+ const errorComponent = React__namespace.useCallback(props => {
2176
+ return /*#__PURE__*/React__namespace.createElement(ErrorComponent, {
2177
+ ...props,
2178
+ useMatch: route.useMatch,
2179
+ useRouteMeta: route.useRouteMeta,
2180
+ useSearch: route.useSearch,
2181
+ useParams: route.useParams
2182
+ });
2183
+ }, [route]);
2184
+ return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
2185
+ value: matches
2186
+ }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
2187
+ resetKey: locationKey,
2188
+ errorComponent: errorComponent,
2189
+ onCatch: () => {
2190
+ warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
2191
+ }
2192
+ }, matches.length ? /*#__PURE__*/React__namespace.createElement(Match, {
2193
+ matches: matches
2194
+ }) : null));
2195
+ }
2693
2196
  function MatchRoute(props) {
2694
2197
  const matchRoute = useMatchRoute();
2695
2198
  const params = matchRoute(props);
@@ -2699,44 +2202,47 @@
2699
2202
  return !!params ? props.children : null;
2700
2203
  }
2701
2204
  function Outlet() {
2702
- const matchIds = React__namespace.useContext(matchIdsContext).slice(1);
2703
- if (!matchIds[0]) {
2205
+ const matches = React__namespace.useContext(matchesContext).slice(1);
2206
+ if (!matches[0]) {
2704
2207
  return null;
2705
2208
  }
2706
2209
  return /*#__PURE__*/React__namespace.createElement(Match, {
2707
- matchIds: matchIds
2210
+ matches: matches
2708
2211
  });
2709
2212
  }
2710
2213
  const defaultPending = () => null;
2711
2214
  function Match({
2712
- matchIds
2215
+ matches
2713
2216
  }) {
2714
- const router = useRouter();
2715
- const matchId = matchIds[0];
2716
- const routeId = router.getRouteMatch(matchId).routeId;
2717
- const route = router.getRoute(routeId);
2217
+ const {
2218
+ options,
2219
+ routesById
2220
+ } = useRouter();
2221
+ const match = matches[0];
2222
+ const routeId = match?.routeId;
2223
+ const route = routesById[routeId];
2718
2224
  const locationKey = useRouterState({
2719
2225
  select: s => s.resolvedLocation.state?.key
2720
2226
  });
2721
- const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
2722
- const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent;
2227
+ const PendingComponent = route.options.pendingComponent ?? options.defaultPendingComponent ?? defaultPending;
2228
+ const routeErrorComponent = route.options.errorComponent ?? options.defaultErrorComponent ?? ErrorComponent;
2723
2229
  const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? !route.isRoot ? React__namespace.Suspense : SafeFragment;
2724
2230
  const ResolvedCatchBoundary = !!routeErrorComponent ? CatchBoundary : SafeFragment;
2725
2231
  const errorComponent = React__namespace.useCallback(props => {
2726
2232
  return /*#__PURE__*/React__namespace.createElement(routeErrorComponent, {
2727
2233
  ...props,
2728
2234
  useMatch: route.useMatch,
2729
- useRouteContext: route.useRouteContext,
2235
+ useRouteMeta: route.useRouteMeta,
2730
2236
  useSearch: route.useSearch,
2731
2237
  useParams: route.useParams
2732
2238
  });
2733
2239
  }, [route]);
2734
- return /*#__PURE__*/React__namespace.createElement(matchIdsContext.Provider, {
2735
- value: matchIds
2240
+ return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
2241
+ value: matches
2736
2242
  }, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
2737
2243
  fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, {
2738
2244
  useMatch: route.useMatch,
2739
- useRouteContext: route.useRouteContext,
2245
+ useRouteMeta: route.useRouteMeta,
2740
2246
  useSearch: route.useSearch,
2741
2247
  useParams: route.useParams
2742
2248
  })
@@ -2744,44 +2250,32 @@
2744
2250
  resetKey: locationKey,
2745
2251
  errorComponent: errorComponent,
2746
2252
  onCatch: () => {
2747
- warning(false, `Error in route match: ${matchId}`);
2253
+ warning(false, `Error in route match: ${match.id}`);
2748
2254
  }
2749
2255
  }, /*#__PURE__*/React__namespace.createElement(MatchInner, {
2750
- matchId: matchId,
2751
- PendingComponent: PendingComponent
2256
+ match: match
2752
2257
  }))));
2753
2258
  }
2754
2259
  function MatchInner({
2755
- matchId,
2756
- PendingComponent
2260
+ match
2757
2261
  }) {
2758
- const router = useRouter();
2759
- const match = useRouterState({
2760
- select: d => {
2761
- const match = d.matchesById[matchId];
2762
- return pick(match, ['status', 'loadPromise', 'routeId', 'error']);
2763
- }
2764
- });
2765
- const route = router.getRoute(match.routeId);
2262
+ const {
2263
+ options,
2264
+ routesById
2265
+ } = useRouter();
2266
+ const route = routesById[match.routeId];
2766
2267
  if (match.status === 'error') {
2767
2268
  throw match.error;
2768
2269
  }
2769
2270
  if (match.status === 'pending') {
2770
- return /*#__PURE__*/React__namespace.createElement(PendingComponent, {
2771
- useLoader: route.useLoader,
2772
- useMatch: route.useMatch,
2773
- useRouteContext: route.useRouteContext,
2774
- useSearch: route.useSearch,
2775
- useParams: route.useParams
2776
- });
2271
+ throw match.loadPromise;
2777
2272
  }
2778
2273
  if (match.status === 'success') {
2779
- let comp = route.options.component ?? router.options.defaultComponent;
2274
+ let comp = route.options.component ?? options.defaultComponent;
2780
2275
  if (comp) {
2781
2276
  return /*#__PURE__*/React__namespace.createElement(comp, {
2782
- useLoader: route.useLoader,
2783
2277
  useMatch: route.useMatch,
2784
- useRouteContext: route.useRouteContext,
2278
+ useRouteMeta: route.useRouteMeta,
2785
2279
  useSearch: route.useSearch,
2786
2280
  useParams: route.useParams
2787
2281
  });
@@ -2793,24 +2287,37 @@
2793
2287
  function SafeFragment(props) {
2794
2288
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
2795
2289
  }
2796
- function useInjectHtml() {
2797
- const router = useRouter();
2798
- return React__namespace.useCallback(html => {
2799
- router.injectHtml(html);
2800
- }, []);
2801
- }
2802
- function useDehydrate() {
2803
- const router = useRouter();
2804
- return React__namespace.useCallback(function dehydrate(key, data) {
2805
- return router.dehydrateData(key, data);
2806
- }, []);
2807
- }
2808
- function useHydrate() {
2809
- const router = useRouter();
2810
- return function hydrate(key) {
2811
- return router.hydrateData(key);
2812
- };
2813
- }
2290
+
2291
+ // export function useInjectHtml() {
2292
+ // const { } = useRouter()
2293
+
2294
+ // return React.useCallback(
2295
+ // (html: string | (() => Promise<string> | string)) => {
2296
+ // router.injectHtml(html)
2297
+ // },
2298
+ // [],
2299
+ // )
2300
+ // }
2301
+
2302
+ // export function useDehydrate() {
2303
+ // const { } = useRouter()
2304
+
2305
+ // return React.useCallback(function dehydrate<T>(
2306
+ // key: any,
2307
+ // data: T | (() => Promise<T> | T),
2308
+ // ) {
2309
+ // return router.dehydrateData(key, data)
2310
+ // },
2311
+ // [])
2312
+ // }
2313
+
2314
+ // export function useHydrate() {
2315
+ // const { } = useRouter()
2316
+
2317
+ // return function hydrate<T = unknown>(key: any) {
2318
+ // return router.hydrateData(key) as T
2319
+ // }
2320
+ // }
2814
2321
 
2815
2322
  // This is the messiest thing ever... I'm either seriously tired (likely) or
2816
2323
  // there has to be a better way to reset error boundaries when the
@@ -2901,10 +2408,12 @@
2901
2408
  }, error.message ? /*#__PURE__*/React__namespace.createElement("code", null, error.message) : null)) : null);
2902
2409
  }
2903
2410
  function useBlocker(message, condition = true) {
2904
- const router = useRouter();
2411
+ const {
2412
+ history
2413
+ } = useRouter();
2905
2414
  React__namespace.useEffect(() => {
2906
2415
  if (!condition) return;
2907
- let unblock = router.history.block((retry, cancel) => {
2416
+ let unblock = history.block((retry, cancel) => {
2908
2417
  if (window.confirm(message)) {
2909
2418
  unblock();
2910
2419
  retry();
@@ -2940,47 +2449,125 @@
2940
2449
  return true;
2941
2450
  }
2942
2451
 
2943
- const useLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
2944
- function useScrollRestoration(options) {
2945
- const router = useRouter();
2946
- useLayoutEffect(() => {
2947
- return watchScrollPositions(router, options);
2948
- }, []);
2949
- useLayoutEffect(() => {
2950
- restoreScrollPositions(router, options);
2951
- });
2952
- }
2953
- function ScrollRestoration(props) {
2954
- useScrollRestoration(props);
2955
- return null;
2956
- }
2452
+ const rootRouteId = '__root__';
2957
2453
 
2958
- function useAwaited({
2959
- promise
2960
- }) {
2961
- const router = useRouter();
2962
- let state = promise.__deferredState;
2963
- const key = `__TSR__DEFERRED__${state.uid}`;
2964
- if (isDehydratedDeferred(promise)) {
2965
- state = router.hydrateData(key);
2966
- promise = Promise.resolve(state.data);
2967
- promise.__deferredState = state;
2968
- }
2969
- if (state.status === 'pending') {
2970
- throw promise;
2454
+ // export type MetaOptions = keyof PickRequired<RouteMeta> extends never
2455
+ // ? {
2456
+ // meta?: RouteMeta
2457
+ // }
2458
+ // : {
2459
+ // meta: RouteMeta
2460
+ // }
2461
+ // The parse type here allows a zod schema to be passed directly to the validator
2462
+ class Route {
2463
+ // Set up in this.init()
2464
+
2465
+ // customId!: TCustomId
2466
+
2467
+ // Optional
2468
+
2469
+ constructor(options) {
2470
+ this.options = options || {};
2471
+ this.isRoot = !options?.getParentRoute;
2472
+ Route.__onInit(this);
2971
2473
  }
2972
- if (state.status === 'error') {
2973
- throw state.error;
2474
+ init = opts => {
2475
+ this.originalIndex = opts.originalIndex;
2476
+ const options = this.options;
2477
+ const isRoot = !options?.path && !options?.id;
2478
+ this.parentRoute = this.options?.getParentRoute?.();
2479
+ if (isRoot) {
2480
+ this.path = rootRouteId;
2481
+ } else {
2482
+ invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
2483
+ }
2484
+ let path = isRoot ? rootRouteId : options.path;
2485
+
2486
+ // If the path is anything other than an index path, trim it up
2487
+ if (path && path !== '/') {
2488
+ path = trimPath(path);
2489
+ }
2490
+ const customId = options?.id || path;
2491
+
2492
+ // Strip the parentId prefix from the first level of children
2493
+ let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
2494
+ if (path === rootRouteId) {
2495
+ path = '/';
2496
+ }
2497
+ if (id !== rootRouteId) {
2498
+ id = joinPaths(['/', id]);
2499
+ }
2500
+ const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
2501
+ this.path = path;
2502
+ this.id = id;
2503
+ // this.customId = customId as TCustomId
2504
+ this.fullPath = fullPath;
2505
+ this.to = fullPath;
2506
+ };
2507
+ addChildren = children => {
2508
+ this.children = children;
2509
+ return this;
2510
+ };
2511
+ update = options => {
2512
+ Object.assign(this.options, options);
2513
+ return this;
2514
+ };
2515
+ static __onInit = route => {
2516
+ // This is a dummy static method that should get
2517
+ // replaced by a framework specific implementation if necessary
2518
+ };
2519
+ useMatch = opts => {
2520
+ return useMatch({
2521
+ ...opts,
2522
+ from: this.id
2523
+ });
2524
+ };
2525
+ useRouteMeta = opts => {
2526
+ return useMatch({
2527
+ ...opts,
2528
+ from: this.id,
2529
+ select: d => opts?.select ? opts.select(d.meta) : d.meta
2530
+ });
2531
+ };
2532
+ useSearch = opts => {
2533
+ return useSearch({
2534
+ ...opts,
2535
+ from: this.id
2536
+ });
2537
+ };
2538
+ useParams = opts => {
2539
+ return useParams({
2540
+ ...opts,
2541
+ from: this.id
2542
+ });
2543
+ };
2544
+ }
2545
+ class RouterMeta {
2546
+ constructor() {}
2547
+ createRootRoute = options => {
2548
+ return new RootRoute(options);
2549
+ };
2550
+ }
2551
+ class RootRoute extends Route {
2552
+ constructor(options) {
2553
+ super(options);
2974
2554
  }
2975
- router.dehydrateData(key, state);
2976
- return [state.data];
2977
2555
  }
2978
- function Await(props) {
2979
- const awaited = useAwaited(props);
2980
- return props.children(...awaited);
2556
+ function createRouteMask(opts) {
2557
+ return opts;
2558
+ }
2559
+
2560
+ class FileRoute {
2561
+ constructor(path) {
2562
+ this.path = path;
2563
+ }
2564
+ createRoute = options => {
2565
+ const route = new Route(options);
2566
+ route.isRoot = false;
2567
+ return route;
2568
+ };
2981
2569
  }
2982
2570
 
2983
- exports.Await = Await;
2984
2571
  exports.Block = Block;
2985
2572
  exports.CatchBoundary = CatchBoundary;
2986
2573
  exports.CatchBoundaryImpl = CatchBoundaryImpl;
@@ -2988,15 +2575,15 @@
2988
2575
  exports.FileRoute = FileRoute;
2989
2576
  exports.Link = Link;
2990
2577
  exports.MatchRoute = MatchRoute;
2578
+ exports.Matches = Matches;
2991
2579
  exports.Navigate = Navigate;
2992
2580
  exports.Outlet = Outlet;
2993
2581
  exports.PathParamError = PathParamError;
2994
2582
  exports.RootRoute = RootRoute;
2995
2583
  exports.Route = Route;
2996
2584
  exports.Router = Router;
2997
- exports.RouterContext = RouterContext;
2585
+ exports.RouterMeta = RouterMeta;
2998
2586
  exports.RouterProvider = RouterProvider;
2999
- exports.ScrollRestoration = ScrollRestoration;
3000
2587
  exports.SearchParamError = SearchParamError;
3001
2588
  exports.cleanPath = cleanPath;
3002
2589
  exports.componentTypes = componentTypes;
@@ -3007,22 +2594,22 @@
3007
2594
  exports.decode = decode;
3008
2595
  exports.defaultParseSearch = defaultParseSearch;
3009
2596
  exports.defaultStringifySearch = defaultStringifySearch;
3010
- exports.defer = defer;
3011
2597
  exports.encode = encode;
3012
2598
  exports.functionalUpdate = functionalUpdate;
2599
+ exports.getInitialRouterState = getInitialRouterState;
2600
+ exports.getRouteMatch = getRouteMatch;
3013
2601
  exports.interpolatePath = interpolatePath;
3014
2602
  exports.invariant = invariant;
3015
- exports.isDehydratedDeferred = isDehydratedDeferred;
3016
- exports.isMatchInvalid = isMatchInvalid;
3017
2603
  exports.isPlainObject = isPlainObject;
3018
2604
  exports.isRedirect = isRedirect;
2605
+ exports.isServer = isServer;
3019
2606
  exports.joinPaths = joinPaths;
3020
2607
  exports.last = last;
3021
2608
  exports.lazyFn = lazyFn;
3022
2609
  exports.lazyRouteComponent = lazyRouteComponent;
3023
2610
  exports.matchByPath = matchByPath;
3024
- exports.matchIdsContext = matchIdsContext;
3025
2611
  exports.matchPathname = matchPathname;
2612
+ exports.matchesContext = matchesContext;
3026
2613
  exports.parsePathname = parsePathname;
3027
2614
  exports.parseSearchWith = parseSearchWith;
3028
2615
  exports.partialDeepEqual = partialDeepEqual;
@@ -3030,7 +2617,6 @@
3030
2617
  exports.redirect = redirect;
3031
2618
  exports.replaceEqualDeep = replaceEqualDeep;
3032
2619
  exports.resolvePath = resolvePath;
3033
- exports.restoreScrollPositions = restoreScrollPositions;
3034
2620
  exports.rootRouteId = rootRouteId;
3035
2621
  exports.routerContext = routerContext;
3036
2622
  exports.shallow = shallow;
@@ -3038,27 +2624,19 @@
3038
2624
  exports.trimPath = trimPath;
3039
2625
  exports.trimPathLeft = trimPathLeft;
3040
2626
  exports.trimPathRight = trimPathRight;
3041
- exports.useAwaited = useAwaited;
3042
2627
  exports.useBlocker = useBlocker;
3043
- exports.useDehydrate = useDehydrate;
3044
- exports.useHydrate = useHydrate;
3045
- exports.useInjectHtml = useInjectHtml;
3046
2628
  exports.useLinkProps = useLinkProps;
3047
- exports.useLoader = useLoader;
3048
2629
  exports.useMatch = useMatch;
3049
2630
  exports.useMatchRoute = useMatchRoute;
3050
2631
  exports.useMatches = useMatches;
3051
2632
  exports.useNavigate = useNavigate;
3052
2633
  exports.useParams = useParams;
3053
- exports.useRouteContext = useRouteContext;
2634
+ exports.useRouteMeta = useRouteMeta;
3054
2635
  exports.useRouter = useRouter;
3055
- exports.useRouterContext = useRouterContext;
3056
2636
  exports.useRouterState = useRouterState;
3057
- exports.useScrollRestoration = useScrollRestoration;
3058
2637
  exports.useSearch = useSearch;
3059
- exports.useStore = useStore;
2638
+ exports.useStableCallback = useStableCallback;
3060
2639
  exports.warning = warning;
3061
- exports.watchScrollPositions = watchScrollPositions;
3062
2640
 
3063
2641
  Object.defineProperty(exports, '__esModule', { value: true });
3064
2642