@tanstack/react-router 0.0.1-beta.203 → 0.0.1-beta.205

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 +961 -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 +1799 -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 +1116 -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 +4 -4
  51. package/src/RouteMatch.ts +28 -0
  52. package/src/RouterProvider.tsx +1384 -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 = state.location;
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 = state.location.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
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 = state.location.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 ? state.location.pathname === next.pathname : pathIsFuzzyEqual;
1751
+ const hashTest = activeOptions?.includeHash ? state.location.hash === next.hash : true;
1752
+ const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(state.location.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,93 @@
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
+ React__namespace.useLayoutEffect(() => {
1821
+ const unsub = history.subscribe(() => {
1822
+ React__namespace.startTransition(() => {
1823
+ setState(s => ({
1824
+ ...s,
1825
+ location: parseLocation(state.location)
1826
+ }));
1827
+ });
1770
1828
  });
1771
- this.__store.setState(s => {
1772
- return {
1773
- ...s,
1774
- matchIds: dehydratedState.matchIds,
1775
- matches,
1776
- matchesById: this.#mergeMatches(s.matchesById, matches)
1777
- };
1829
+ const nextLocation = buildLocation({
1830
+ search: true,
1831
+ params: true,
1832
+ hash: true,
1833
+ state: true
1778
1834
  });
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>`;
1835
+ if (state.location.href !== nextLocation.href) {
1836
+ commitLocation({
1837
+ ...nextLocation,
1838
+ replace: true
1796
1839
  });
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
1840
  }
1841
+ return () => {
1842
+ unsub();
1843
+ };
1844
+ }, [history]);
1845
+ const initialLoad = React__namespace.useRef(true);
1846
+ if (initialLoad.current) {
1847
+ initialLoad.current = false;
1848
+ safeLoad();
2321
1849
  }
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'
1850
+ React__namespace.useLayoutEffect(() => {
1851
+ if (state.resolvedLocation !== state.location) {
1852
+ safeLoad();
1853
+ }
1854
+ }, [state.location]);
1855
+ React__namespace.useMemo(() => [...state.matches, ...state.pendingMatches].some(d => d.isFetching), [state.matches, state.pendingMatches]);
1856
+ const matchRoute = useStableCallback((state, location, opts) => {
1857
+ location = {
1858
+ ...location,
1859
+ to: location.to ? resolvePathWithBase(location.from || '', location.to) : undefined
2330
1860
  };
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;
1861
+ const next = buildLocation(location);
1862
+ if (opts?.pending && state.status !== 'pending') {
1863
+ return false;
1864
+ }
1865
+ const baseLocation = opts?.pending ? state.location : state.resolvedLocation;
1866
+ if (!baseLocation) {
1867
+ return false;
1868
+ }
1869
+ const match = matchPathname(basepath, baseLocation.pathname, {
1870
+ ...opts,
1871
+ to: next.pathname
2338
1872
  });
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
- }
1873
+ if (!match) {
1874
+ return false;
2355
1875
  }
2356
- return target;
1876
+ if (opts?.includeSearch ?? true) {
1877
+ return partialDeepEqual(baseLocation.search, next.search) ? match : false;
1878
+ }
1879
+ return match;
1880
+ });
1881
+ const routerContextValue = {
1882
+ routeTree: router.routeTree,
1883
+ navigate,
1884
+ buildLink,
1885
+ state,
1886
+ matchRoute,
1887
+ routesById,
1888
+ options,
1889
+ history,
1890
+ load
2357
1891
  };
2358
- return _extends.apply(this, arguments);
1892
+ return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
1893
+ value: routerContextValue
1894
+ }, /*#__PURE__*/React__namespace.createElement(Matches, null));
1895
+ }
1896
+ function isCtrlEvent(e) {
1897
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1898
+ }
1899
+ class SearchParamError extends Error {}
1900
+ class PathParamError extends Error {}
1901
+ function getRouteMatch(state, id) {
1902
+ return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
2359
1903
  }
2360
1904
 
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
- };
1905
+ const useLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
2397
1906
 
2398
1907
  //
2399
1908
 
@@ -2418,7 +1927,10 @@
2418
1927
  //
2419
1928
 
2420
1929
  function useLinkProps(options) {
2421
- const router = useRouter();
1930
+ const {
1931
+ buildLink,
1932
+ state: routerState
1933
+ } = useRouter();
2422
1934
  const match = useMatch({
2423
1935
  strict: false
2424
1936
  });
@@ -2452,7 +1964,7 @@
2452
1964
  onTouchStart,
2453
1965
  ...rest
2454
1966
  } = options;
2455
- const linkInfo = router.buildLink({
1967
+ const linkInfo = buildLink(routerState, {
2456
1968
  from: options.to ? match.pathname : undefined,
2457
1969
  ...options
2458
1970
  });
@@ -2528,92 +2040,48 @@
2528
2040
  }));
2529
2041
  });
2530
2042
  function Navigate(props) {
2531
- const router = useRouter();
2043
+ const {
2044
+ navigate
2045
+ } = useRouter();
2532
2046
  const match = useMatch({
2533
2047
  strict: false
2534
2048
  });
2535
- useLayoutEffect$1(() => {
2536
- router.navigate({
2049
+ useLayoutEffect(() => {
2050
+ navigate({
2537
2051
  from: props.to ? match.pathname : undefined,
2538
2052
  ...props
2539
2053
  });
2540
2054
  }, []);
2541
2055
  return null;
2542
2056
  }
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
- }
2057
+ const matchesContext = /*#__PURE__*/React__namespace.createContext(null);
2596
2058
  function useRouter() {
2597
2059
  const value = React__namespace.useContext(routerContext);
2598
- warning(value, 'useRouter must be used inside a <Router> component!');
2060
+ warning(value, 'useRouter must be used inside a <RouterProvider> component!');
2599
2061
  return value;
2600
2062
  }
2063
+ function useRouterState(opts) {
2064
+ const {
2065
+ state
2066
+ } = useRouter();
2067
+ // return useStore(router.__store, opts?.select as any)
2068
+ return opts?.select ? opts.select(state) : state;
2069
+ }
2601
2070
  function useMatches(opts) {
2602
- const matchIds = React__namespace.useContext(matchIdsContext);
2071
+ const contextMatches = React__namespace.useContext(matchesContext);
2603
2072
  return useRouterState({
2604
2073
  select: state => {
2605
- const matches = state.renderedMatches.slice(state.renderedMatches.findIndex(d => d.id === matchIds[0]));
2074
+ const matches = state.matches.slice(state.matches.findIndex(d => d.id === contextMatches[0]?.id));
2606
2075
  return opts?.select ? opts.select(matches) : matches;
2607
2076
  }
2608
2077
  });
2609
2078
  }
2610
2079
  function useMatch(opts) {
2611
- const router = useRouter();
2612
- const nearestMatchId = React__namespace.useContext(matchIdsContext)[0];
2613
- const nearestMatchRouteId = router.getRouteMatch(nearestMatchId)?.routeId;
2080
+ const nearestMatch = React__namespace.useContext(matchesContext)[0];
2081
+ const nearestMatchRouteId = nearestMatch?.routeId;
2614
2082
  const matchRouteId = useRouterState({
2615
2083
  select: state => {
2616
- const match = opts?.from ? state.renderedMatches.find(d => d.routeId === opts?.from) : state.renderedMatches.find(d => d.id === nearestMatchId);
2084
+ const match = opts?.from ? state.matches.find(d => d.routeId === opts?.from) : state.matches.find(d => d.id === nearestMatch.id);
2617
2085
  return match.routeId;
2618
2086
  }
2619
2087
  });
@@ -2622,29 +2090,17 @@
2622
2090
  }
2623
2091
  const matchSelection = useRouterState({
2624
2092
  select: state => {
2625
- const match = opts?.from ? state.renderedMatches.find(d => d.routeId === opts?.from) : state.renderedMatches.find(d => d.id === nearestMatchId);
2093
+ const match = opts?.from ? state.matches.find(d => d.routeId === opts?.from) : state.matches.find(d => d.id === nearestMatch.id);
2626
2094
  invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
2627
2095
  return opts?.select ? opts.select(match) : match;
2628
2096
  }
2629
2097
  });
2630
2098
  return matchSelection;
2631
2099
  }
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) {
2100
+ function useRouteMeta(opts) {
2645
2101
  return useMatch({
2646
2102
  ...opts,
2647
- select: match => opts?.select ? opts.select(match.context) : match.context
2103
+ select: match => opts?.select ? opts.select(match.meta) : match.meta
2648
2104
  });
2649
2105
  }
2650
2106
  function useSearch(opts) {
@@ -2658,18 +2114,20 @@
2658
2114
  function useParams(opts) {
2659
2115
  return useRouterState({
2660
2116
  select: state => {
2661
- const params = last(state.renderedMatches)?.params;
2117
+ const params = last(state.matches)?.params;
2662
2118
  return opts?.select ? opts.select(params) : params;
2663
2119
  }
2664
2120
  });
2665
2121
  }
2666
2122
  function useNavigate(defaultOpts) {
2667
- const router = useRouter();
2123
+ const {
2124
+ navigate
2125
+ } = useRouter();
2668
2126
  const match = useMatch({
2669
2127
  strict: false
2670
2128
  });
2671
2129
  return React__namespace.useCallback(opts => {
2672
- return router.navigate({
2130
+ return navigate({
2673
2131
  from: opts?.to ? match.pathname : undefined,
2674
2132
  ...defaultOpts,
2675
2133
  ...opts
@@ -2677,19 +2135,62 @@
2677
2135
  }, []);
2678
2136
  }
2679
2137
  function useMatchRoute() {
2680
- const router = useRouter();
2138
+ const {
2139
+ state,
2140
+ matchRoute
2141
+ } = useRouter();
2681
2142
  return React__namespace.useCallback(opts => {
2682
2143
  const {
2683
2144
  pending,
2684
2145
  caseSensitive,
2685
2146
  ...rest
2686
2147
  } = opts;
2687
- return router.matchRoute(rest, {
2148
+ return matchRoute(state, rest, {
2688
2149
  pending,
2689
2150
  caseSensitive
2690
2151
  });
2691
2152
  }, []);
2692
2153
  }
2154
+ function Matches() {
2155
+ const {
2156
+ routesById,
2157
+ state
2158
+ } = useRouter();
2159
+
2160
+ // const matches = useRouterState({
2161
+ // select: (state) => {
2162
+ // return state.matches
2163
+ // },
2164
+ // })
2165
+
2166
+ const {
2167
+ matches
2168
+ } = state;
2169
+ const locationKey = useRouterState({
2170
+ select: d => d.resolvedLocation.state?.key
2171
+ });
2172
+ const route = routesById[rootRouteId];
2173
+ const errorComponent = React__namespace.useCallback(props => {
2174
+ return /*#__PURE__*/React__namespace.createElement(ErrorComponent, {
2175
+ ...props,
2176
+ useMatch: route.useMatch,
2177
+ useRouteMeta: route.useRouteMeta,
2178
+ useSearch: route.useSearch,
2179
+ useParams: route.useParams
2180
+ });
2181
+ }, [route]);
2182
+ return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
2183
+ value: matches
2184
+ }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
2185
+ resetKey: locationKey,
2186
+ errorComponent: errorComponent,
2187
+ onCatch: () => {
2188
+ warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
2189
+ }
2190
+ }, matches.length ? /*#__PURE__*/React__namespace.createElement(Match, {
2191
+ matches: matches
2192
+ }) : null));
2193
+ }
2693
2194
  function MatchRoute(props) {
2694
2195
  const matchRoute = useMatchRoute();
2695
2196
  const params = matchRoute(props);
@@ -2699,44 +2200,47 @@
2699
2200
  return !!params ? props.children : null;
2700
2201
  }
2701
2202
  function Outlet() {
2702
- const matchIds = React__namespace.useContext(matchIdsContext).slice(1);
2703
- if (!matchIds[0]) {
2203
+ const matches = React__namespace.useContext(matchesContext).slice(1);
2204
+ if (!matches[0]) {
2704
2205
  return null;
2705
2206
  }
2706
2207
  return /*#__PURE__*/React__namespace.createElement(Match, {
2707
- matchIds: matchIds
2208
+ matches: matches
2708
2209
  });
2709
2210
  }
2710
2211
  const defaultPending = () => null;
2711
2212
  function Match({
2712
- matchIds
2213
+ matches
2713
2214
  }) {
2714
- const router = useRouter();
2715
- const matchId = matchIds[0];
2716
- const routeId = router.getRouteMatch(matchId).routeId;
2717
- const route = router.getRoute(routeId);
2215
+ const {
2216
+ options,
2217
+ routesById
2218
+ } = useRouter();
2219
+ const match = matches[0];
2220
+ const routeId = match?.routeId;
2221
+ const route = routesById[routeId];
2718
2222
  const locationKey = useRouterState({
2719
2223
  select: s => s.resolvedLocation.state?.key
2720
2224
  });
2721
- const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
2722
- const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent;
2225
+ const PendingComponent = route.options.pendingComponent ?? options.defaultPendingComponent ?? defaultPending;
2226
+ const routeErrorComponent = route.options.errorComponent ?? options.defaultErrorComponent ?? ErrorComponent;
2723
2227
  const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? !route.isRoot ? React__namespace.Suspense : SafeFragment;
2724
2228
  const ResolvedCatchBoundary = !!routeErrorComponent ? CatchBoundary : SafeFragment;
2725
2229
  const errorComponent = React__namespace.useCallback(props => {
2726
2230
  return /*#__PURE__*/React__namespace.createElement(routeErrorComponent, {
2727
2231
  ...props,
2728
2232
  useMatch: route.useMatch,
2729
- useRouteContext: route.useRouteContext,
2233
+ useRouteMeta: route.useRouteMeta,
2730
2234
  useSearch: route.useSearch,
2731
2235
  useParams: route.useParams
2732
2236
  });
2733
2237
  }, [route]);
2734
- return /*#__PURE__*/React__namespace.createElement(matchIdsContext.Provider, {
2735
- value: matchIds
2238
+ return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
2239
+ value: matches
2736
2240
  }, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
2737
2241
  fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, {
2738
2242
  useMatch: route.useMatch,
2739
- useRouteContext: route.useRouteContext,
2243
+ useRouteMeta: route.useRouteMeta,
2740
2244
  useSearch: route.useSearch,
2741
2245
  useParams: route.useParams
2742
2246
  })
@@ -2744,44 +2248,32 @@
2744
2248
  resetKey: locationKey,
2745
2249
  errorComponent: errorComponent,
2746
2250
  onCatch: () => {
2747
- warning(false, `Error in route match: ${matchId}`);
2251
+ warning(false, `Error in route match: ${match.id}`);
2748
2252
  }
2749
2253
  }, /*#__PURE__*/React__namespace.createElement(MatchInner, {
2750
- matchId: matchId,
2751
- PendingComponent: PendingComponent
2254
+ match: match
2752
2255
  }))));
2753
2256
  }
2754
2257
  function MatchInner({
2755
- matchId,
2756
- PendingComponent
2258
+ match
2757
2259
  }) {
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);
2260
+ const {
2261
+ options,
2262
+ routesById
2263
+ } = useRouter();
2264
+ const route = routesById[match.routeId];
2766
2265
  if (match.status === 'error') {
2767
2266
  throw match.error;
2768
2267
  }
2769
2268
  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
- });
2269
+ throw match.loadPromise;
2777
2270
  }
2778
2271
  if (match.status === 'success') {
2779
- let comp = route.options.component ?? router.options.defaultComponent;
2272
+ let comp = route.options.component ?? options.defaultComponent;
2780
2273
  if (comp) {
2781
2274
  return /*#__PURE__*/React__namespace.createElement(comp, {
2782
- useLoader: route.useLoader,
2783
2275
  useMatch: route.useMatch,
2784
- useRouteContext: route.useRouteContext,
2276
+ useRouteMeta: route.useRouteMeta,
2785
2277
  useSearch: route.useSearch,
2786
2278
  useParams: route.useParams
2787
2279
  });
@@ -2793,24 +2285,37 @@
2793
2285
  function SafeFragment(props) {
2794
2286
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
2795
2287
  }
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
- }
2288
+
2289
+ // export function useInjectHtml() {
2290
+ // const { } = useRouter()
2291
+
2292
+ // return React.useCallback(
2293
+ // (html: string | (() => Promise<string> | string)) => {
2294
+ // router.injectHtml(html)
2295
+ // },
2296
+ // [],
2297
+ // )
2298
+ // }
2299
+
2300
+ // export function useDehydrate() {
2301
+ // const { } = useRouter()
2302
+
2303
+ // return React.useCallback(function dehydrate<T>(
2304
+ // key: any,
2305
+ // data: T | (() => Promise<T> | T),
2306
+ // ) {
2307
+ // return router.dehydrateData(key, data)
2308
+ // },
2309
+ // [])
2310
+ // }
2311
+
2312
+ // export function useHydrate() {
2313
+ // const { } = useRouter()
2314
+
2315
+ // return function hydrate<T = unknown>(key: any) {
2316
+ // return router.hydrateData(key) as T
2317
+ // }
2318
+ // }
2814
2319
 
2815
2320
  // This is the messiest thing ever... I'm either seriously tired (likely) or
2816
2321
  // there has to be a better way to reset error boundaries when the
@@ -2901,10 +2406,12 @@
2901
2406
  }, error.message ? /*#__PURE__*/React__namespace.createElement("code", null, error.message) : null)) : null);
2902
2407
  }
2903
2408
  function useBlocker(message, condition = true) {
2904
- const router = useRouter();
2409
+ const {
2410
+ history
2411
+ } = useRouter();
2905
2412
  React__namespace.useEffect(() => {
2906
2413
  if (!condition) return;
2907
- let unblock = router.history.block((retry, cancel) => {
2414
+ let unblock = history.block((retry, cancel) => {
2908
2415
  if (window.confirm(message)) {
2909
2416
  unblock();
2910
2417
  retry();
@@ -2940,47 +2447,125 @@
2940
2447
  return true;
2941
2448
  }
2942
2449
 
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
- }
2450
+ const rootRouteId = '__root__';
2957
2451
 
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;
2452
+ // export type MetaOptions = keyof PickRequired<RouteMeta> extends never
2453
+ // ? {
2454
+ // meta?: RouteMeta
2455
+ // }
2456
+ // : {
2457
+ // meta: RouteMeta
2458
+ // }
2459
+ // The parse type here allows a zod schema to be passed directly to the validator
2460
+ class Route {
2461
+ // Set up in this.init()
2462
+
2463
+ // customId!: TCustomId
2464
+
2465
+ // Optional
2466
+
2467
+ constructor(options) {
2468
+ this.options = options || {};
2469
+ this.isRoot = !options?.getParentRoute;
2470
+ Route.__onInit(this);
2971
2471
  }
2972
- if (state.status === 'error') {
2973
- throw state.error;
2472
+ init = opts => {
2473
+ this.originalIndex = opts.originalIndex;
2474
+ const options = this.options;
2475
+ const isRoot = !options?.path && !options?.id;
2476
+ this.parentRoute = this.options?.getParentRoute?.();
2477
+ if (isRoot) {
2478
+ this.path = rootRouteId;
2479
+ } else {
2480
+ invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
2481
+ }
2482
+ let path = isRoot ? rootRouteId : options.path;
2483
+
2484
+ // If the path is anything other than an index path, trim it up
2485
+ if (path && path !== '/') {
2486
+ path = trimPath(path);
2487
+ }
2488
+ const customId = options?.id || path;
2489
+
2490
+ // Strip the parentId prefix from the first level of children
2491
+ let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
2492
+ if (path === rootRouteId) {
2493
+ path = '/';
2494
+ }
2495
+ if (id !== rootRouteId) {
2496
+ id = joinPaths(['/', id]);
2497
+ }
2498
+ const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
2499
+ this.path = path;
2500
+ this.id = id;
2501
+ // this.customId = customId as TCustomId
2502
+ this.fullPath = fullPath;
2503
+ this.to = fullPath;
2504
+ };
2505
+ addChildren = children => {
2506
+ this.children = children;
2507
+ return this;
2508
+ };
2509
+ update = options => {
2510
+ Object.assign(this.options, options);
2511
+ return this;
2512
+ };
2513
+ static __onInit = route => {
2514
+ // This is a dummy static method that should get
2515
+ // replaced by a framework specific implementation if necessary
2516
+ };
2517
+ useMatch = opts => {
2518
+ return useMatch({
2519
+ ...opts,
2520
+ from: this.id
2521
+ });
2522
+ };
2523
+ useRouteMeta = opts => {
2524
+ return useMatch({
2525
+ ...opts,
2526
+ from: this.id,
2527
+ select: d => opts?.select ? opts.select(d.meta) : d.meta
2528
+ });
2529
+ };
2530
+ useSearch = opts => {
2531
+ return useSearch({
2532
+ ...opts,
2533
+ from: this.id
2534
+ });
2535
+ };
2536
+ useParams = opts => {
2537
+ return useParams({
2538
+ ...opts,
2539
+ from: this.id
2540
+ });
2541
+ };
2542
+ }
2543
+ class RouterMeta {
2544
+ constructor() {}
2545
+ createRootRoute = options => {
2546
+ return new RootRoute(options);
2547
+ };
2548
+ }
2549
+ class RootRoute extends Route {
2550
+ constructor(options) {
2551
+ super(options);
2974
2552
  }
2975
- router.dehydrateData(key, state);
2976
- return [state.data];
2977
2553
  }
2978
- function Await(props) {
2979
- const awaited = useAwaited(props);
2980
- return props.children(...awaited);
2554
+ function createRouteMask(opts) {
2555
+ return opts;
2556
+ }
2557
+
2558
+ class FileRoute {
2559
+ constructor(path) {
2560
+ this.path = path;
2561
+ }
2562
+ createRoute = options => {
2563
+ const route = new Route(options);
2564
+ route.isRoot = false;
2565
+ return route;
2566
+ };
2981
2567
  }
2982
2568
 
2983
- exports.Await = Await;
2984
2569
  exports.Block = Block;
2985
2570
  exports.CatchBoundary = CatchBoundary;
2986
2571
  exports.CatchBoundaryImpl = CatchBoundaryImpl;
@@ -2988,15 +2573,15 @@
2988
2573
  exports.FileRoute = FileRoute;
2989
2574
  exports.Link = Link;
2990
2575
  exports.MatchRoute = MatchRoute;
2576
+ exports.Matches = Matches;
2991
2577
  exports.Navigate = Navigate;
2992
2578
  exports.Outlet = Outlet;
2993
2579
  exports.PathParamError = PathParamError;
2994
2580
  exports.RootRoute = RootRoute;
2995
2581
  exports.Route = Route;
2996
2582
  exports.Router = Router;
2997
- exports.RouterContext = RouterContext;
2583
+ exports.RouterMeta = RouterMeta;
2998
2584
  exports.RouterProvider = RouterProvider;
2999
- exports.ScrollRestoration = ScrollRestoration;
3000
2585
  exports.SearchParamError = SearchParamError;
3001
2586
  exports.cleanPath = cleanPath;
3002
2587
  exports.componentTypes = componentTypes;
@@ -3007,22 +2592,22 @@
3007
2592
  exports.decode = decode;
3008
2593
  exports.defaultParseSearch = defaultParseSearch;
3009
2594
  exports.defaultStringifySearch = defaultStringifySearch;
3010
- exports.defer = defer;
3011
2595
  exports.encode = encode;
3012
2596
  exports.functionalUpdate = functionalUpdate;
2597
+ exports.getInitialRouterState = getInitialRouterState;
2598
+ exports.getRouteMatch = getRouteMatch;
3013
2599
  exports.interpolatePath = interpolatePath;
3014
2600
  exports.invariant = invariant;
3015
- exports.isDehydratedDeferred = isDehydratedDeferred;
3016
- exports.isMatchInvalid = isMatchInvalid;
3017
2601
  exports.isPlainObject = isPlainObject;
3018
2602
  exports.isRedirect = isRedirect;
2603
+ exports.isServer = isServer;
3019
2604
  exports.joinPaths = joinPaths;
3020
2605
  exports.last = last;
3021
2606
  exports.lazyFn = lazyFn;
3022
2607
  exports.lazyRouteComponent = lazyRouteComponent;
3023
2608
  exports.matchByPath = matchByPath;
3024
- exports.matchIdsContext = matchIdsContext;
3025
2609
  exports.matchPathname = matchPathname;
2610
+ exports.matchesContext = matchesContext;
3026
2611
  exports.parsePathname = parsePathname;
3027
2612
  exports.parseSearchWith = parseSearchWith;
3028
2613
  exports.partialDeepEqual = partialDeepEqual;
@@ -3030,7 +2615,6 @@
3030
2615
  exports.redirect = redirect;
3031
2616
  exports.replaceEqualDeep = replaceEqualDeep;
3032
2617
  exports.resolvePath = resolvePath;
3033
- exports.restoreScrollPositions = restoreScrollPositions;
3034
2618
  exports.rootRouteId = rootRouteId;
3035
2619
  exports.routerContext = routerContext;
3036
2620
  exports.shallow = shallow;
@@ -3038,27 +2622,19 @@
3038
2622
  exports.trimPath = trimPath;
3039
2623
  exports.trimPathLeft = trimPathLeft;
3040
2624
  exports.trimPathRight = trimPathRight;
3041
- exports.useAwaited = useAwaited;
3042
2625
  exports.useBlocker = useBlocker;
3043
- exports.useDehydrate = useDehydrate;
3044
- exports.useHydrate = useHydrate;
3045
- exports.useInjectHtml = useInjectHtml;
3046
2626
  exports.useLinkProps = useLinkProps;
3047
- exports.useLoader = useLoader;
3048
2627
  exports.useMatch = useMatch;
3049
2628
  exports.useMatchRoute = useMatchRoute;
3050
2629
  exports.useMatches = useMatches;
3051
2630
  exports.useNavigate = useNavigate;
3052
2631
  exports.useParams = useParams;
3053
- exports.useRouteContext = useRouteContext;
2632
+ exports.useRouteMeta = useRouteMeta;
3054
2633
  exports.useRouter = useRouter;
3055
- exports.useRouterContext = useRouterContext;
3056
2634
  exports.useRouterState = useRouterState;
3057
- exports.useScrollRestoration = useScrollRestoration;
3058
2635
  exports.useSearch = useSearch;
3059
- exports.useStore = useStore;
2636
+ exports.useStableCallback = useStableCallback;
3060
2637
  exports.warning = warning;
3061
- exports.watchScrollPositions = watchScrollPositions;
3062
2638
 
3063
2639
  Object.defineProperty(exports, '__esModule', { value: true });
3064
2640