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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/build/cjs/RouterProvider.js +963 -0
  2. package/build/cjs/RouterProvider.js.map +1 -0
  3. package/build/cjs/fileRoute.js +29 -0
  4. package/build/cjs/fileRoute.js.map +1 -0
  5. package/build/cjs/index.js +69 -21
  6. package/build/cjs/index.js.map +1 -1
  7. package/build/cjs/path.js +211 -0
  8. package/build/cjs/path.js.map +1 -0
  9. package/build/cjs/qss.js +65 -0
  10. package/build/cjs/qss.js.map +1 -0
  11. package/build/cjs/react.js +148 -190
  12. package/build/cjs/react.js.map +1 -1
  13. package/build/cjs/redirects.js +27 -0
  14. package/build/cjs/redirects.js.map +1 -0
  15. package/build/cjs/route.js +136 -0
  16. package/build/cjs/route.js.map +1 -0
  17. package/build/cjs/router.js +203 -0
  18. package/build/cjs/router.js.map +1 -0
  19. package/build/cjs/searchParams.js +83 -0
  20. package/build/cjs/searchParams.js.map +1 -0
  21. package/build/cjs/utils.js +196 -0
  22. package/build/cjs/utils.js.map +1 -0
  23. package/build/esm/index.js +1801 -211
  24. package/build/esm/index.js.map +1 -1
  25. package/build/stats-html.html +1 -1
  26. package/build/stats-react.json +385 -164
  27. package/build/types/RouteMatch.d.ts +23 -0
  28. package/build/types/RouterProvider.d.ts +54 -0
  29. package/build/types/awaited.d.ts +0 -8
  30. package/build/types/defer.d.ts +0 -0
  31. package/build/types/fileRoute.d.ts +17 -0
  32. package/build/types/history.d.ts +7 -0
  33. package/build/types/index.d.ts +17 -4
  34. package/build/types/link.d.ts +98 -0
  35. package/build/types/location.d.ts +14 -0
  36. package/build/types/path.d.ts +16 -0
  37. package/build/types/qss.d.ts +2 -0
  38. package/build/types/react.d.ts +23 -83
  39. package/build/types/redirects.d.ts +10 -0
  40. package/build/types/route.d.ts +222 -0
  41. package/build/types/routeInfo.d.ts +22 -0
  42. package/build/types/router.d.ts +115 -0
  43. package/build/types/scroll-restoration.d.ts +0 -3
  44. package/build/types/searchParams.d.ts +7 -0
  45. package/build/types/utils.d.ts +48 -0
  46. package/build/umd/index.development.js +1118 -1540
  47. package/build/umd/index.development.js.map +1 -1
  48. package/build/umd/index.production.js +2 -33
  49. package/build/umd/index.production.js.map +1 -1
  50. package/package.json +2 -4
  51. package/src/RouteMatch.ts +28 -0
  52. package/src/RouterProvider.tsx +1390 -0
  53. package/src/awaited.tsx +40 -40
  54. package/src/defer.ts +55 -0
  55. package/src/fileRoute.ts +143 -0
  56. package/src/history.ts +8 -0
  57. package/src/index.tsx +18 -5
  58. package/src/link.ts +347 -0
  59. package/src/location.ts +14 -0
  60. package/src/path.ts +256 -0
  61. package/src/qss.ts +53 -0
  62. package/src/react.tsx +174 -422
  63. package/src/redirects.ts +31 -0
  64. package/src/route.ts +710 -0
  65. package/src/routeInfo.ts +68 -0
  66. package/src/router.ts +373 -0
  67. package/src/scroll-restoration.tsx +205 -27
  68. package/src/searchParams.ts +78 -0
  69. package/src/utils.ts +257 -0
  70. package/build/cjs/awaited.js +0 -45
  71. package/build/cjs/awaited.js.map +0 -1
  72. package/build/cjs/scroll-restoration.js +0 -56
  73. package/build/cjs/scroll-restoration.js.map +0 -1
@@ -8,13 +8,396 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { useStore } from '@tanstack/react-store';
12
- export { useStore } from '@tanstack/react-store';
13
- import { Route, functionalUpdate, rootRouteId, last, pick, watchScrollPositions, restoreScrollPositions, isDehydratedDeferred } from '@tanstack/router-core';
14
- export * from '@tanstack/router-core';
15
- import * as React from 'react';
11
+ import { createBrowserHistory } from '@tanstack/history';
12
+ export * from '@tanstack/history';
16
13
  import invariant from 'tiny-invariant';
14
+ export { default as invariant } from 'tiny-invariant';
17
15
  import warning from 'tiny-warning';
16
+ export { default as warning } from 'tiny-warning';
17
+ import * as React from 'react';
18
+
19
+ // export type Expand<T> = T
20
+
21
+ // type Compute<T> = { [K in keyof T]: T[K] } | never
22
+
23
+ // type AllKeys<T> = T extends any ? keyof T : never
24
+
25
+ // export type MergeUnion<T, Keys extends keyof T = keyof T> = Compute<
26
+ // {
27
+ // [K in Keys]: T[Keys]
28
+ // } & {
29
+ // [K in AllKeys<T>]?: T extends any
30
+ // ? K extends keyof T
31
+ // ? T[K]
32
+ // : never
33
+ // : never
34
+ // }
35
+ // >
36
+ // // Sample types to merge
37
+ // type TypeA = {
38
+ // shared: string
39
+ // onlyInA: string
40
+ // nested: {
41
+ // shared: string
42
+ // aProp: string
43
+ // }
44
+ // array: string[]
45
+ // }
46
+ // type TypeB = {
47
+ // shared: number
48
+ // onlyInB: number
49
+ // nested: {
50
+ // shared: number
51
+ // bProp: number
52
+ // }
53
+ // array: number[]
54
+ // }
55
+ // type TypeC = {
56
+ // shared: boolean
57
+ // onlyInC: boolean
58
+ // nested: {
59
+ // shared: boolean
60
+ // cProp: boolean
61
+ // }
62
+ // array: boolean[]
63
+ // }
64
+ // type Test = Expand<Assign<TypeA, TypeB>>
65
+ // // Using DeepMerge to merge TypeA and TypeB
66
+ // type MergedType = Expand<AssignAll<[TypeA, TypeB, TypeC]>>
67
+ //
68
+
69
+ const isServer = typeof document === 'undefined';
70
+ function last(arr) {
71
+ return arr[arr.length - 1];
72
+ }
73
+ function isFunction(d) {
74
+ return typeof d === 'function';
75
+ }
76
+ function functionalUpdate(updater, previous) {
77
+ if (isFunction(updater)) {
78
+ return updater(previous);
79
+ }
80
+ return updater;
81
+ }
82
+ function pick(parent, keys) {
83
+ return keys.reduce((obj, key) => {
84
+ obj[key] = parent[key];
85
+ return obj;
86
+ }, {});
87
+ }
88
+
89
+ /**
90
+ * This function returns `a` if `b` is deeply equal.
91
+ * If not, it will replace any deeply equal children of `b` with those of `a`.
92
+ * This can be used for structural sharing between immutable JSON values for example.
93
+ * Do not use this with signals
94
+ */
95
+ function replaceEqualDeep(prev, _next) {
96
+ if (prev === _next) {
97
+ return prev;
98
+ }
99
+ const next = _next;
100
+ const array = Array.isArray(prev) && Array.isArray(next);
101
+ if (array || isPlainObject(prev) && isPlainObject(next)) {
102
+ const prevSize = array ? prev.length : Object.keys(prev).length;
103
+ const nextItems = array ? next : Object.keys(next);
104
+ const nextSize = nextItems.length;
105
+ const copy = array ? [] : {};
106
+ let equalItems = 0;
107
+ for (let i = 0; i < nextSize; i++) {
108
+ const key = array ? i : nextItems[i];
109
+ copy[key] = replaceEqualDeep(prev[key], next[key]);
110
+ if (copy[key] === prev[key]) {
111
+ equalItems++;
112
+ }
113
+ }
114
+ return prevSize === nextSize && equalItems === prevSize ? prev : copy;
115
+ }
116
+ return next;
117
+ }
118
+
119
+ // Copied from: https://github.com/jonschlinkert/is-plain-object
120
+ function isPlainObject(o) {
121
+ if (!hasObjectPrototype(o)) {
122
+ return false;
123
+ }
124
+
125
+ // If has modified constructor
126
+ const ctor = o.constructor;
127
+ if (typeof ctor === 'undefined') {
128
+ return true;
129
+ }
130
+
131
+ // If has modified prototype
132
+ const prot = ctor.prototype;
133
+ if (!hasObjectPrototype(prot)) {
134
+ return false;
135
+ }
136
+
137
+ // If constructor does not have an Object-specific method
138
+ if (!prot.hasOwnProperty('isPrototypeOf')) {
139
+ return false;
140
+ }
141
+
142
+ // Most likely a plain Object
143
+ return true;
144
+ }
145
+ function hasObjectPrototype(o) {
146
+ return Object.prototype.toString.call(o) === '[object Object]';
147
+ }
148
+ function partialDeepEqual(a, b) {
149
+ if (a === b) {
150
+ return true;
151
+ }
152
+ if (typeof a !== typeof b) {
153
+ return false;
154
+ }
155
+ if (isPlainObject(a) && isPlainObject(b)) {
156
+ return !Object.keys(b).some(key => !partialDeepEqual(a[key], b[key]));
157
+ }
158
+ if (Array.isArray(a) && Array.isArray(b)) {
159
+ return a.length === b.length && a.every((item, index) => partialDeepEqual(item, b[index]));
160
+ }
161
+ return false;
162
+ }
163
+ function useStableCallback(fn) {
164
+ const fnRef = React.useRef(fn);
165
+ fnRef.current = fn;
166
+ const ref = React.useRef((...args) => fnRef.current(...args));
167
+ return ref.current;
168
+ }
169
+
170
+ function joinPaths(paths) {
171
+ return cleanPath(paths.filter(Boolean).join('/'));
172
+ }
173
+ function cleanPath(path) {
174
+ // remove double slashes
175
+ return path.replace(/\/{2,}/g, '/');
176
+ }
177
+ function trimPathLeft(path) {
178
+ return path === '/' ? path : path.replace(/^\/{1,}/, '');
179
+ }
180
+ function trimPathRight(path) {
181
+ return path === '/' ? path : path.replace(/\/{1,}$/, '');
182
+ }
183
+ function trimPath(path) {
184
+ return trimPathRight(trimPathLeft(path));
185
+ }
186
+ function resolvePath(basepath, base, to) {
187
+ base = base.replace(new RegExp(`^${basepath}`), '/');
188
+ to = to.replace(new RegExp(`^${basepath}`), '/');
189
+ let baseSegments = parsePathname(base);
190
+ const toSegments = parsePathname(to);
191
+ toSegments.forEach((toSegment, index) => {
192
+ if (toSegment.value === '/') {
193
+ if (!index) {
194
+ // Leading slash
195
+ baseSegments = [toSegment];
196
+ } else if (index === toSegments.length - 1) {
197
+ // Trailing Slash
198
+ baseSegments.push(toSegment);
199
+ } else ;
200
+ } else if (toSegment.value === '..') {
201
+ // Extra trailing slash? pop it off
202
+ if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {
203
+ baseSegments.pop();
204
+ }
205
+ baseSegments.pop();
206
+ } else if (toSegment.value === '.') {
207
+ return;
208
+ } else {
209
+ baseSegments.push(toSegment);
210
+ }
211
+ });
212
+ const joined = joinPaths([basepath, ...baseSegments.map(d => d.value)]);
213
+ return cleanPath(joined);
214
+ }
215
+ function parsePathname(pathname) {
216
+ if (!pathname) {
217
+ return [];
218
+ }
219
+ pathname = cleanPath(pathname);
220
+ const segments = [];
221
+ if (pathname.slice(0, 1) === '/') {
222
+ pathname = pathname.substring(1);
223
+ segments.push({
224
+ type: 'pathname',
225
+ value: '/'
226
+ });
227
+ }
228
+ if (!pathname) {
229
+ return segments;
230
+ }
231
+
232
+ // Remove empty segments and '.' segments
233
+ const split = pathname.split('/').filter(Boolean);
234
+ segments.push(...split.map(part => {
235
+ if (part === '$' || part === '*') {
236
+ return {
237
+ type: 'wildcard',
238
+ value: part
239
+ };
240
+ }
241
+ if (part.charAt(0) === '$') {
242
+ return {
243
+ type: 'param',
244
+ value: part
245
+ };
246
+ }
247
+ return {
248
+ type: 'pathname',
249
+ value: part
250
+ };
251
+ }));
252
+ if (pathname.slice(-1) === '/') {
253
+ pathname = pathname.substring(1);
254
+ segments.push({
255
+ type: 'pathname',
256
+ value: '/'
257
+ });
258
+ }
259
+ return segments;
260
+ }
261
+ function interpolatePath(path, params, leaveWildcards = false) {
262
+ const interpolatedPathSegments = parsePathname(path);
263
+ return joinPaths(interpolatedPathSegments.map(segment => {
264
+ if (segment.type === 'wildcard') {
265
+ const value = params[segment.value];
266
+ if (leaveWildcards) return `${segment.value}${value ?? ''}`;
267
+ return value;
268
+ }
269
+ if (segment.type === 'param') {
270
+ return params[segment.value.substring(1)] ?? '';
271
+ }
272
+ return segment.value;
273
+ }));
274
+ }
275
+ function matchPathname(basepath, currentPathname, matchLocation) {
276
+ const pathParams = matchByPath(basepath, currentPathname, matchLocation);
277
+ // const searchMatched = matchBySearch(location.search, matchLocation)
278
+
279
+ if (matchLocation.to && !pathParams) {
280
+ return;
281
+ }
282
+ return pathParams ?? {};
283
+ }
284
+ function matchByPath(basepath, from, matchLocation) {
285
+ // Remove the base path from the pathname
286
+ from = basepath != '/' ? from.substring(basepath.length) : from;
287
+ // Default to to $ (wildcard)
288
+ const to = `${matchLocation.to ?? '$'}`;
289
+ // Parse the from and to
290
+ const baseSegments = parsePathname(from);
291
+ const routeSegments = parsePathname(to);
292
+ if (!from.startsWith('/')) {
293
+ baseSegments.unshift({
294
+ type: 'pathname',
295
+ value: '/'
296
+ });
297
+ }
298
+ if (!to.startsWith('/')) {
299
+ routeSegments.unshift({
300
+ type: 'pathname',
301
+ value: '/'
302
+ });
303
+ }
304
+ const params = {};
305
+ let isMatch = (() => {
306
+ for (let i = 0; i < Math.max(baseSegments.length, routeSegments.length); i++) {
307
+ const baseSegment = baseSegments[i];
308
+ const routeSegment = routeSegments[i];
309
+ const isLastBaseSegment = i >= baseSegments.length - 1;
310
+ const isLastRouteSegment = i >= routeSegments.length - 1;
311
+ if (routeSegment) {
312
+ if (routeSegment.type === 'wildcard') {
313
+ if (baseSegment?.value) {
314
+ params['*'] = joinPaths(baseSegments.slice(i).map(d => d.value));
315
+ return true;
316
+ }
317
+ return false;
318
+ }
319
+ if (routeSegment.type === 'pathname') {
320
+ if (routeSegment.value === '/' && !baseSegment?.value) {
321
+ return true;
322
+ }
323
+ if (baseSegment) {
324
+ if (matchLocation.caseSensitive) {
325
+ if (routeSegment.value !== baseSegment.value) {
326
+ return false;
327
+ }
328
+ } else if (routeSegment.value.toLowerCase() !== baseSegment.value.toLowerCase()) {
329
+ return false;
330
+ }
331
+ }
332
+ }
333
+ if (!baseSegment) {
334
+ return false;
335
+ }
336
+ if (routeSegment.type === 'param') {
337
+ if (baseSegment?.value === '/') {
338
+ return false;
339
+ }
340
+ if (baseSegment.value.charAt(0) !== '$') {
341
+ params[routeSegment.value.substring(1)] = baseSegment.value;
342
+ }
343
+ }
344
+ }
345
+ if (!isLastBaseSegment && isLastRouteSegment) {
346
+ return !!matchLocation.fuzzy;
347
+ }
348
+ }
349
+ return true;
350
+ })();
351
+ return isMatch ? params : undefined;
352
+ }
353
+
354
+ // @ts-nocheck
355
+
356
+ // qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
357
+
358
+ function encode(obj, pfx) {
359
+ var k,
360
+ i,
361
+ tmp,
362
+ str = '';
363
+ for (k in obj) {
364
+ if ((tmp = obj[k]) !== void 0) {
365
+ if (Array.isArray(tmp)) {
366
+ for (i = 0; i < tmp.length; i++) {
367
+ str && (str += '&');
368
+ str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i]);
369
+ }
370
+ } else {
371
+ str && (str += '&');
372
+ str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
373
+ }
374
+ }
375
+ }
376
+ return (pfx || '') + str;
377
+ }
378
+ function toValue(mix) {
379
+ if (!mix) return '';
380
+ var str = decodeURIComponent(mix);
381
+ if (str === 'false') return false;
382
+ if (str === 'true') return true;
383
+ return +str * 0 === 0 && +str + '' === str ? +str : str;
384
+ }
385
+ function decode(str) {
386
+ var tmp,
387
+ k,
388
+ out = {},
389
+ arr = str.split('&');
390
+ while (tmp = arr.shift()) {
391
+ tmp = tmp.split('=');
392
+ k = tmp.shift();
393
+ if (out[k] !== void 0) {
394
+ out[k] = [].concat(out[k], toValue(tmp.shift()));
395
+ } else {
396
+ out[k] = toValue(tmp.shift());
397
+ }
398
+ }
399
+ return out;
400
+ }
18
401
 
19
402
  function _extends() {
20
403
  _extends = Object.assign ? Object.assign.bind() : function (target) {
@@ -31,42 +414,1172 @@ function _extends() {
31
414
  return _extends.apply(this, arguments);
32
415
  }
33
416
 
34
- const useLayoutEffect$1 = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
35
- Route.__onInit = route => {
36
- Object.assign(route, {
37
- useMatch: (opts = {}) => {
38
- return useMatch({
39
- ...opts,
40
- from: route.id
417
+ const defaultParseSearch = parseSearchWith(JSON.parse);
418
+ const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
419
+ function parseSearchWith(parser) {
420
+ return searchStr => {
421
+ if (searchStr.substring(0, 1) === '?') {
422
+ searchStr = searchStr.substring(1);
423
+ }
424
+ let query = decode(searchStr);
425
+
426
+ // Try to parse any query params that might be json
427
+ for (let key in query) {
428
+ const value = query[key];
429
+ if (typeof value === 'string') {
430
+ try {
431
+ query[key] = parser(value);
432
+ } catch (err) {
433
+ //
434
+ }
435
+ }
436
+ }
437
+ return query;
438
+ };
439
+ }
440
+ function stringifySearchWith(stringify, parser) {
441
+ function stringifyValue(val) {
442
+ if (typeof val === 'object' && val !== null) {
443
+ try {
444
+ return stringify(val);
445
+ } catch (err) {
446
+ // silent
447
+ }
448
+ } else if (typeof val === 'string' && typeof parser === 'function') {
449
+ try {
450
+ // Check if it's a valid parseable string.
451
+ // If it is, then stringify it again.
452
+ parser(val);
453
+ return stringify(val);
454
+ } catch (err) {
455
+ // silent
456
+ }
457
+ }
458
+ return val;
459
+ }
460
+ return search => {
461
+ search = {
462
+ ...search
463
+ };
464
+ if (search) {
465
+ Object.keys(search).forEach(key => {
466
+ const val = search[key];
467
+ if (typeof val === 'undefined' || val === undefined) {
468
+ delete search[key];
469
+ } else {
470
+ search[key] = stringifyValue(val);
471
+ }
41
472
  });
42
- },
43
- useLoader: (opts = {}) => {
44
- return useLoader({
45
- ...opts,
46
- from: route.id
473
+ }
474
+ const searchStr = encode(search).toString();
475
+ return searchStr ? `?${searchStr}` : '';
476
+ };
477
+ }
478
+
479
+ //
480
+
481
+ //
482
+
483
+ const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
484
+ class Router {
485
+ // dehydratedData?: TDehydrated
486
+ // resetNextScroll = false
487
+ // tempLocationKey = `${Math.round(Math.random() * 10000000)}`
488
+ constructor(options) {
489
+ this.options = {
490
+ defaultPreloadDelay: 50,
491
+ meta: undefined,
492
+ ...options,
493
+ stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
494
+ parseSearch: options?.parseSearch ?? defaultParseSearch
495
+ };
496
+ this.routeTree = this.options.routeTree;
497
+ }
498
+ subscribers = new Set();
499
+ subscribe = (eventType, fn) => {
500
+ const listener = {
501
+ eventType,
502
+ fn
503
+ };
504
+ this.subscribers.add(listener);
505
+ return () => {
506
+ this.subscribers.delete(listener);
507
+ };
508
+ };
509
+ emit = routerEvent => {
510
+ this.subscribers.forEach(listener => {
511
+ if (listener.eventType === routerEvent.type) {
512
+ listener.fn(routerEvent);
513
+ }
514
+ });
515
+ };
516
+
517
+ // dehydrate = (): DehydratedRouter => {
518
+ // return {
519
+ // state: {
520
+ // dehydratedMatches: state.matches.map((d) =>
521
+ // pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt']),
522
+ // ),
523
+ // },
524
+ // }
525
+ // }
526
+
527
+ // hydrate = async (__do_not_use_server_ctx?: HydrationCtx) => {
528
+ // let _ctx = __do_not_use_server_ctx
529
+ // // Client hydrates from window
530
+ // if (typeof document !== 'undefined') {
531
+ // _ctx = window.__TSR_DEHYDRATED__
532
+ // }
533
+
534
+ // invariant(
535
+ // _ctx,
536
+ // 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?',
537
+ // )
538
+
539
+ // const ctx = _ctx
540
+ // this.dehydratedData = ctx.payload as any
541
+ // this.options.hydrate?.(ctx.payload as any)
542
+ // const dehydratedState = ctx.router.state
543
+
544
+ // let matches = this.matchRoutes(
545
+ // state.location.pathname,
546
+ // state.location.search,
547
+ // ).map((match) => {
548
+ // const dehydratedMatch = dehydratedState.dehydratedMatches.find(
549
+ // (d) => d.id === match.id,
550
+ // )
551
+
552
+ // invariant(
553
+ // dehydratedMatch,
554
+ // `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
555
+ // )
556
+
557
+ // if (dehydratedMatch) {
558
+ // return {
559
+ // ...match,
560
+ // ...dehydratedMatch,
561
+ // }
562
+ // }
563
+ // return match
564
+ // })
565
+
566
+ // this.setState((s) => {
567
+ // return {
568
+ // ...s,
569
+ // matches: dehydratedState.dehydratedMatches as any,
570
+ // }
571
+ // })
572
+ // }
573
+
574
+ // TODO:
575
+ // injectedHtml: (string | (() => Promise<string> | string))[] = []
576
+
577
+ // TODO:
578
+ // injectHtml = async (html: string | (() => Promise<string> | string)) => {
579
+ // this.injectedHtml.push(html)
580
+ // }
581
+
582
+ // TODO:
583
+ // dehydrateData = <T>(key: any, getData: T | (() => Promise<T> | T)) => {
584
+ // if (typeof document === 'undefined') {
585
+ // const strKey = typeof key === 'string' ? key : JSON.stringify(key)
586
+
587
+ // this.injectHtml(async () => {
588
+ // const id = `__TSR_DEHYDRATED__${strKey}`
589
+ // const data =
590
+ // typeof getData === 'function' ? await (getData as any)() : getData
591
+ // return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(
592
+ // strKey,
593
+ // )}"] = ${JSON.stringify(data)}
594
+ // ;(() => {
595
+ // var el = document.getElementById('${id}')
596
+ // el.parentElement.removeChild(el)
597
+ // })()
598
+ // </script>`
599
+ // })
600
+
601
+ // return () => this.hydrateData<T>(key)
602
+ // }
603
+
604
+ // return () => undefined
605
+ // }
606
+
607
+ // hydrateData = <T = unknown>(key: any) => {
608
+ // if (typeof document !== 'undefined') {
609
+ // const strKey = typeof key === 'string' ? key : JSON.stringify(key)
610
+
611
+ // return window[`__TSR_DEHYDRATED__${strKey}` as any] as T
612
+ // }
613
+
614
+ // return undefined
615
+ // }
616
+
617
+ // resolveMatchPromise = (matchId: string, key: string, value: any) => {
618
+ // state.matches
619
+ // .find((d) => d.id === matchId)
620
+ // ?.__promisesByKey[key]?.resolve(value)
621
+ // }
622
+
623
+ // setRouteMatch = (
624
+ // id: string,
625
+ // pending: boolean,
626
+ // updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
627
+ // ) => {
628
+ // const key = pending ? 'pendingMatches' : 'matches'
629
+
630
+ // this.setState((prev) => {
631
+ // return {
632
+ // ...prev,
633
+ // [key]: prev[key].map((d) => {
634
+ // if (d.id === id) {
635
+ // return functionalUpdate(updater, d)
636
+ // }
637
+
638
+ // return d
639
+ // }),
640
+ // }
641
+ // })
642
+ // }
643
+
644
+ // setPendingRouteMatch = (
645
+ // id: string,
646
+ // updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
647
+ // ) => {
648
+ // this.setRouteMatch(id, true, updater)
649
+ // }
650
+ }
651
+
652
+ // A function that takes an import() argument which is a function and returns a new function that will
653
+ // proxy arguments from the caller to the imported function, retaining all type
654
+ // information along the way
655
+ function lazyFn(fn, key) {
656
+ return async (...args) => {
657
+ const imported = await fn();
658
+ return imported[key || 'default'](...args);
659
+ };
660
+ }
661
+
662
+ // Detect if we're in the DOM
663
+
664
+ function redirect(opts) {
665
+ opts.isRedirect = true;
666
+ return opts;
667
+ }
668
+ function isRedirect(obj) {
669
+ return !!obj?.isRedirect;
670
+ }
671
+
672
+ const preloadWarning = 'Error preloading route! ☝️';
673
+ const routerContext = /*#__PURE__*/React.createContext(null);
674
+ function getInitialRouterState(location) {
675
+ return {
676
+ status: 'idle',
677
+ isFetching: false,
678
+ resolvedLocation: location,
679
+ location: location,
680
+ matches: [],
681
+ pendingMatches: [],
682
+ lastUpdated: Date.now()
683
+ };
684
+ }
685
+ function RouterProvider({
686
+ router,
687
+ ...rest
688
+ }) {
689
+ const options = {
690
+ ...router.options,
691
+ ...rest,
692
+ meta: {
693
+ ...router.options.meta,
694
+ ...rest?.meta
695
+ }
696
+ };
697
+ const history = React.useState(() => options.history ?? createBrowserHistory())[0];
698
+ const tempLocationKeyRef = React.useRef(`${Math.round(Math.random() * 10000000)}`);
699
+ const resetNextScrollRef = React.useRef(false);
700
+ const navigateTimeoutRef = React.useRef(null);
701
+ const parseLocation = useStableCallback(previousLocation => {
702
+ const parse = ({
703
+ pathname,
704
+ search,
705
+ hash,
706
+ state
707
+ }) => {
708
+ const parsedSearch = options.parseSearch(search);
709
+ return {
710
+ pathname: pathname,
711
+ searchStr: search,
712
+ search: replaceEqualDeep(previousLocation?.search, parsedSearch),
713
+ hash: hash.split('#').reverse()[0] ?? '',
714
+ href: `${pathname}${search}${hash}`,
715
+ state: replaceEqualDeep(previousLocation?.state, state)
716
+ };
717
+ };
718
+ const location = parse(history.location);
719
+ let {
720
+ __tempLocation,
721
+ __tempKey
722
+ } = location.state;
723
+ if (__tempLocation && (!__tempKey || __tempKey === tempLocationKeyRef.current)) {
724
+ // Sync up the location keys
725
+ const parsedTempLocation = parse(__tempLocation);
726
+ parsedTempLocation.state.key = location.state.key;
727
+ delete parsedTempLocation.state.__tempLocation;
728
+ return {
729
+ ...parsedTempLocation,
730
+ maskedLocation: location
731
+ };
732
+ }
733
+ return location;
734
+ });
735
+ const [state, setState] = React.useState(() => getInitialRouterState(parseLocation()));
736
+ const basepath = `/${trimPath(options.basepath ?? '') ?? ''}`;
737
+ const resolvePathWithBase = useStableCallback((from, path) => {
738
+ return resolvePath(basepath, from, cleanPath(path));
739
+ });
740
+ const [routesById, routesByPath] = React.useMemo(() => {
741
+ const routesById = {};
742
+ const routesByPath = {};
743
+ const recurseRoutes = routes => {
744
+ routes.forEach((route, i) => {
745
+ route.init({
746
+ originalIndex: i
747
+ });
748
+ const existingRoute = routesById[route.id];
749
+ invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
750
+ routesById[route.id] = route;
751
+ if (!route.isRoot && route.path) {
752
+ const trimmedFullPath = trimPathRight(route.fullPath);
753
+ if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
754
+ routesByPath[trimmedFullPath] = route;
755
+ }
756
+ }
757
+ const children = route.children;
758
+ if (children?.length) {
759
+ recurseRoutes(children);
760
+ }
47
761
  });
48
- },
49
- useRouteContext: (opts = {}) => {
50
- return useMatch({
51
- ...opts,
52
- from: route.id,
53
- select: d => opts?.select ? opts.select(d.context) : d.context
762
+ };
763
+ recurseRoutes([router.routeTree]);
764
+ return [routesById, routesByPath];
765
+ }, []);
766
+ const looseRoutesById = routesById;
767
+ const flatRoutes = React.useMemo(() => Object.values(routesByPath).map((d, i) => {
768
+ const trimmed = trimPath(d.fullPath);
769
+ const parsed = parsePathname(trimmed);
770
+ while (parsed.length > 1 && parsed[0]?.value === '/') {
771
+ parsed.shift();
772
+ }
773
+ const score = parsed.map(d => {
774
+ if (d.type === 'param') {
775
+ return 0.5;
776
+ }
777
+ if (d.type === 'wildcard') {
778
+ return 0.25;
779
+ }
780
+ return 1;
781
+ });
782
+ return {
783
+ child: d,
784
+ trimmed,
785
+ parsed,
786
+ index: i,
787
+ score
788
+ };
789
+ }).sort((a, b) => {
790
+ let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
791
+ if (isIndex !== 0) return isIndex;
792
+ const length = Math.min(a.score.length, b.score.length);
793
+
794
+ // Sort by length of score
795
+ if (a.score.length !== b.score.length) {
796
+ return b.score.length - a.score.length;
797
+ }
798
+
799
+ // Sort by min available score
800
+ for (let i = 0; i < length; i++) {
801
+ if (a.score[i] !== b.score[i]) {
802
+ return b.score[i] - a.score[i];
803
+ }
804
+ }
805
+
806
+ // Sort by min available parsed value
807
+ for (let i = 0; i < length; i++) {
808
+ if (a.parsed[i].value !== b.parsed[i].value) {
809
+ return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
810
+ }
811
+ }
812
+
813
+ // Sort by length of trimmed full path
814
+ if (a.trimmed !== b.trimmed) {
815
+ return a.trimmed > b.trimmed ? 1 : -1;
816
+ }
817
+
818
+ // Sort by original index
819
+ return a.index - b.index;
820
+ }).map((d, i) => {
821
+ d.child.rank = i;
822
+ return d.child;
823
+ }), [routesByPath]);
824
+ const latestLoadPromiseRef = React.useRef(Promise.resolve());
825
+ const matchRoutes = useStableCallback((pathname, locationSearch, opts) => {
826
+ let routeParams = {};
827
+ let foundRoute = flatRoutes.find(route => {
828
+ const matchedParams = matchPathname(basepath, trimPathRight(pathname), {
829
+ to: route.fullPath,
830
+ caseSensitive: route.options.caseSensitive ?? options.caseSensitive,
831
+ fuzzy: false
54
832
  });
55
- },
56
- useSearch: (opts = {}) => {
57
- return useSearch({
58
- ...opts,
59
- from: route.id
833
+ if (matchedParams) {
834
+ routeParams = matchedParams;
835
+ return true;
836
+ }
837
+ return false;
838
+ });
839
+ let routeCursor = foundRoute || routesById['__root__'];
840
+ let matchedRoutes = [routeCursor];
841
+ // let includingLayouts = true
842
+ while (routeCursor?.parentRoute) {
843
+ routeCursor = routeCursor.parentRoute;
844
+ if (routeCursor) matchedRoutes.unshift(routeCursor);
845
+ }
846
+
847
+ // Existing matches are matches that are already loaded along with
848
+ // pending matches that are still loading
849
+
850
+ const parseErrors = matchedRoutes.map(route => {
851
+ let parsedParamsError;
852
+ if (route.options.parseParams) {
853
+ try {
854
+ const parsedParams = route.options.parseParams(routeParams);
855
+ // Add the parsed params to the accumulated params bag
856
+ Object.assign(routeParams, parsedParams);
857
+ } catch (err) {
858
+ parsedParamsError = new PathParamError(err.message, {
859
+ cause: err
860
+ });
861
+ if (opts?.throwOnError) {
862
+ throw parsedParamsError;
863
+ }
864
+ return parsedParamsError;
865
+ }
866
+ }
867
+ return;
868
+ });
869
+ const matches = matchedRoutes.map((route, index) => {
870
+ const interpolatedPath = interpolatePath(route.path, routeParams);
871
+ const matchId = interpolatePath(route.id, routeParams, true);
872
+
873
+ // Waste not, want not. If we already have a match for this route,
874
+ // reuse it. This is important for layout routes, which might stick
875
+ // around between navigation actions that only change leaf routes.
876
+ const existingMatch = getRouteMatch(state, matchId);
877
+ if (existingMatch) {
878
+ return {
879
+ ...existingMatch
880
+ };
881
+ }
882
+
883
+ // Create a fresh route match
884
+ const hasLoaders = !!(route.options.load || componentTypes.some(d => route.options[d]?.preload));
885
+ const routeMatch = {
886
+ id: matchId,
887
+ routeId: route.id,
888
+ params: routeParams,
889
+ pathname: joinPaths([basepath, interpolatedPath]),
890
+ updatedAt: Date.now(),
891
+ routeSearch: {},
892
+ search: {},
893
+ status: hasLoaders ? 'pending' : 'success',
894
+ isFetching: false,
895
+ invalid: false,
896
+ error: undefined,
897
+ paramsError: parseErrors[index],
898
+ searchError: undefined,
899
+ loadPromise: Promise.resolve(),
900
+ meta: undefined,
901
+ abortController: new AbortController(),
902
+ fetchedAt: 0
903
+ };
904
+ return routeMatch;
905
+ });
906
+
907
+ // Take each match and resolve its search params and meta
908
+ // This has to happen after the matches are created or found
909
+ // so that we can use the parent match's search params and meta
910
+ matches.forEach((match, i) => {
911
+ const parentMatch = matches[i - 1];
912
+ const route = looseRoutesById[match.routeId];
913
+ const searchInfo = (() => {
914
+ // Validate the search params and stabilize them
915
+ const parentSearchInfo = {
916
+ search: parentMatch?.search ?? locationSearch,
917
+ routeSearch: parentMatch?.routeSearch ?? locationSearch
918
+ };
919
+ try {
920
+ const validator = typeof route.options.validateSearch === 'object' ? route.options.validateSearch.parse : route.options.validateSearch;
921
+ let routeSearch = validator?.(parentSearchInfo.search) ?? {};
922
+ let search = {
923
+ ...parentSearchInfo.search,
924
+ ...routeSearch
925
+ };
926
+ routeSearch = replaceEqualDeep(match.routeSearch, routeSearch);
927
+ search = replaceEqualDeep(match.search, search);
928
+ return {
929
+ routeSearch,
930
+ search,
931
+ searchDidChange: match.routeSearch !== routeSearch
932
+ };
933
+ } catch (err) {
934
+ match.searchError = new SearchParamError(err.message, {
935
+ cause: err
936
+ });
937
+ if (opts?.throwOnError) {
938
+ throw match.searchError;
939
+ }
940
+ return parentSearchInfo;
941
+ }
942
+ })();
943
+ Object.assign(match, searchInfo);
944
+ });
945
+ return matches;
946
+ });
947
+ const cancelMatch = useStableCallback(id => {
948
+ getRouteMatch(state, id)?.abortController?.abort();
949
+ });
950
+ const cancelMatches = useStableCallback(state => {
951
+ state.matches.forEach(match => {
952
+ cancelMatch(match.id);
953
+ });
954
+ });
955
+ const buildLocation = useStableCallback((opts = {}) => {
956
+ const build = (dest = {}, matches) => {
957
+ const from = latestLocationRef.current;
958
+ const fromPathname = dest.from ?? from.pathname;
959
+ let pathname = resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
960
+ const fromMatches = matchRoutes(fromPathname, from.search);
961
+ const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
962
+ const prevParams = {
963
+ ...last(fromMatches)?.params
964
+ };
965
+ let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
966
+ if (nextParams) {
967
+ matches?.map(d => looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
968
+ nextParams = {
969
+ ...nextParams,
970
+ ...fn(nextParams)
971
+ };
972
+ });
973
+ }
974
+ pathname = interpolatePath(pathname, nextParams ?? {});
975
+ const preSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
976
+ const postSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
977
+
978
+ // Pre filters first
979
+ const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
980
+
981
+ // Then the link/navigate function
982
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
983
+ : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
984
+ : preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
985
+ : {};
986
+
987
+ // Then post filters
988
+ const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
989
+ const search = replaceEqualDeep(from.search, postFilteredSearch);
990
+ const searchStr = options.stringifySearch(search);
991
+ const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
992
+ const hashStr = hash ? `#${hash}` : '';
993
+ let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
994
+ nextState = replaceEqualDeep(from.state, nextState);
995
+ return {
996
+ pathname,
997
+ search,
998
+ searchStr,
999
+ state: nextState,
1000
+ hash,
1001
+ href: history.createHref(`${pathname}${searchStr}${hashStr}`),
1002
+ unmaskOnReload: dest.unmaskOnReload
1003
+ };
1004
+ };
1005
+ const buildWithMatches = (dest = {}, maskedDest) => {
1006
+ let next = build(dest);
1007
+ let maskedNext = maskedDest ? build(maskedDest) : undefined;
1008
+ if (!maskedNext) {
1009
+ let params = {};
1010
+ let foundMask = options.routeMasks?.find(d => {
1011
+ const match = matchPathname(basepath, next.pathname, {
1012
+ to: d.from,
1013
+ caseSensitive: false,
1014
+ fuzzy: false
1015
+ });
1016
+ if (match) {
1017
+ params = match;
1018
+ return true;
1019
+ }
1020
+ return false;
1021
+ });
1022
+ if (foundMask) {
1023
+ foundMask = {
1024
+ ...foundMask,
1025
+ from: interpolatePath(foundMask.from, params)
1026
+ };
1027
+ maskedDest = foundMask;
1028
+ maskedNext = build(maskedDest);
1029
+ }
1030
+ }
1031
+ const nextMatches = matchRoutes(next.pathname, next.search);
1032
+ const maskedMatches = maskedNext ? matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
1033
+ const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
1034
+ const final = build(dest, nextMatches);
1035
+ if (maskedFinal) {
1036
+ final.maskedLocation = maskedFinal;
1037
+ }
1038
+ return final;
1039
+ };
1040
+ if (opts.mask) {
1041
+ return buildWithMatches(opts, {
1042
+ ...pick(opts, ['from']),
1043
+ ...opts.mask
60
1044
  });
61
- },
62
- useParams: (opts = {}) => {
63
- return useParams({
64
- ...opts,
65
- from: route.id
1045
+ }
1046
+ return buildWithMatches(opts);
1047
+ });
1048
+ const commitLocation = useStableCallback(async next => {
1049
+ if (navigateTimeoutRef.current) clearTimeout(navigateTimeoutRef.current);
1050
+ const isSameUrl = latestLocationRef.current.href === next.href;
1051
+
1052
+ // If the next urls are the same and we're not replacing,
1053
+ // do nothing
1054
+ if (!isSameUrl || !next.replace) {
1055
+ let {
1056
+ maskedLocation,
1057
+ ...nextHistory
1058
+ } = next;
1059
+ if (maskedLocation) {
1060
+ nextHistory = {
1061
+ ...maskedLocation,
1062
+ state: {
1063
+ ...maskedLocation.state,
1064
+ __tempKey: undefined,
1065
+ __tempLocation: {
1066
+ ...nextHistory,
1067
+ search: nextHistory.searchStr,
1068
+ state: {
1069
+ ...nextHistory.state,
1070
+ __tempKey: undefined,
1071
+ __tempLocation: undefined,
1072
+ key: undefined
1073
+ }
1074
+ }
1075
+ }
1076
+ };
1077
+ if (nextHistory.unmaskOnReload ?? options.unmaskOnReload ?? false) {
1078
+ nextHistory.state.__tempKey = tempLocationKeyRef.current;
1079
+ }
1080
+ }
1081
+ history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
1082
+ }
1083
+ resetNextScrollRef.current = next.resetScroll ?? true;
1084
+ return latestLoadPromiseRef.current;
1085
+ });
1086
+ const buildAndCommitLocation = useStableCallback(({
1087
+ replace,
1088
+ resetScroll,
1089
+ ...rest
1090
+ } = {}) => {
1091
+ const location = buildLocation(rest);
1092
+ return commitLocation({
1093
+ ...location,
1094
+ replace,
1095
+ resetScroll
1096
+ });
1097
+ });
1098
+ const navigate = useStableCallback(({
1099
+ from,
1100
+ to = '',
1101
+ ...rest
1102
+ }) => {
1103
+ // If this link simply reloads the current route,
1104
+ // make sure it has a new key so it will trigger a data refresh
1105
+
1106
+ // If this `to` is a valid external URL, return
1107
+ // null for LinkUtils
1108
+ const toString = String(to);
1109
+ const fromString = typeof from === 'undefined' ? from : String(from);
1110
+ let isExternal;
1111
+ try {
1112
+ new URL(`${toString}`);
1113
+ isExternal = true;
1114
+ } catch (e) {}
1115
+ invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1116
+ return buildAndCommitLocation({
1117
+ ...rest,
1118
+ from: fromString,
1119
+ to: toString
1120
+ });
1121
+ });
1122
+ const loadMatches = useStableCallback(async ({
1123
+ matches,
1124
+ preload
1125
+ }) => {
1126
+ let firstBadMatchIndex;
1127
+
1128
+ // Check each match middleware to see if the route can be accessed
1129
+ try {
1130
+ for (let [index, match] of matches.entries()) {
1131
+ const parentMatch = matches[index - 1];
1132
+ const route = looseRoutesById[match.routeId];
1133
+ const handleError = (err, code) => {
1134
+ err.routerCode = code;
1135
+ firstBadMatchIndex = firstBadMatchIndex ?? index;
1136
+ if (isRedirect(err)) {
1137
+ throw err;
1138
+ }
1139
+ try {
1140
+ route.options.onError?.(err);
1141
+ } catch (errorHandlerErr) {
1142
+ err = errorHandlerErr;
1143
+ if (isRedirect(errorHandlerErr)) {
1144
+ throw errorHandlerErr;
1145
+ }
1146
+ }
1147
+ matches[index] = match = {
1148
+ ...match,
1149
+ error: err,
1150
+ status: 'error',
1151
+ updatedAt: Date.now()
1152
+ };
1153
+ };
1154
+ try {
1155
+ if (match.paramsError) {
1156
+ handleError(match.paramsError, 'PARSE_PARAMS');
1157
+ }
1158
+ if (match.searchError) {
1159
+ handleError(match.searchError, 'VALIDATE_SEARCH');
1160
+ }
1161
+ const parentMeta = parentMatch?.meta ?? options.meta ?? {};
1162
+ const beforeLoadMeta = (await route.options.beforeLoad?.({
1163
+ search: match.search,
1164
+ abortController: match.abortController,
1165
+ params: match.params,
1166
+ preload: !!preload,
1167
+ meta: parentMeta,
1168
+ location: state.location // TODO: This might need to be latestLocationRef.current...?
1169
+ })) ?? {};
1170
+ const meta = {
1171
+ ...parentMeta,
1172
+ ...beforeLoadMeta
1173
+ };
1174
+ matches[index] = match = {
1175
+ ...match,
1176
+ meta: replaceEqualDeep(match.meta, meta)
1177
+ };
1178
+ } catch (err) {
1179
+ handleError(err, 'BEFORE_LOAD');
1180
+ break;
1181
+ }
1182
+ }
1183
+ } catch (err) {
1184
+ if (isRedirect(err)) {
1185
+ if (!preload) navigate(err);
1186
+ return;
1187
+ }
1188
+ throw err;
1189
+ }
1190
+ const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
1191
+ const matchPromises = [];
1192
+ validResolvedMatches.forEach((match, index) => {
1193
+ matchPromises.push((async () => {
1194
+ const parentMatchPromise = matchPromises[index - 1];
1195
+ const route = looseRoutesById[match.routeId];
1196
+ if (match.isFetching) {
1197
+ return getRouteMatch(state, match.id)?.loadPromise;
1198
+ }
1199
+ const fetchedAt = Date.now();
1200
+ const checkLatest = () => {
1201
+ const latest = getRouteMatch(state, match.id);
1202
+ return latest && latest.fetchedAt !== fetchedAt ? latest.loadPromise : undefined;
1203
+ };
1204
+ const handleIfRedirect = err => {
1205
+ if (isRedirect(err)) {
1206
+ if (!preload) {
1207
+ navigate(err);
1208
+ }
1209
+ return true;
1210
+ }
1211
+ return false;
1212
+ };
1213
+ const load = async () => {
1214
+ let latestPromise;
1215
+ try {
1216
+ const componentsPromise = Promise.all(componentTypes.map(async type => {
1217
+ const component = route.options[type];
1218
+ if (component?.preload) {
1219
+ await component.preload();
1220
+ }
1221
+ }));
1222
+ const loaderPromise = route.options.load?.({
1223
+ params: match.params,
1224
+ search: match.search,
1225
+ preload: !!preload,
1226
+ parentMatchPromise,
1227
+ abortController: match.abortController,
1228
+ meta: match.meta
1229
+ });
1230
+ await Promise.all([componentsPromise, loaderPromise]);
1231
+ if (latestPromise = checkLatest()) return await latestPromise;
1232
+ matches[index] = match = {
1233
+ ...match,
1234
+ error: undefined,
1235
+ status: 'success',
1236
+ isFetching: false,
1237
+ updatedAt: Date.now()
1238
+ };
1239
+ } catch (error) {
1240
+ if (latestPromise = checkLatest()) return await latestPromise;
1241
+ if (handleIfRedirect(error)) return;
1242
+ try {
1243
+ route.options.onError?.(error);
1244
+ } catch (onErrorError) {
1245
+ error = onErrorError;
1246
+ if (handleIfRedirect(onErrorError)) return;
1247
+ }
1248
+ matches[index] = match = {
1249
+ ...match,
1250
+ error,
1251
+ status: 'error',
1252
+ isFetching: false,
1253
+ updatedAt: Date.now()
1254
+ };
1255
+ }
1256
+ };
1257
+ let loadPromise;
1258
+ matches[index] = match = {
1259
+ ...match,
1260
+ isFetching: true,
1261
+ fetchedAt,
1262
+ invalid: false
1263
+ };
1264
+ loadPromise = load();
1265
+ matches[index] = match = {
1266
+ ...match,
1267
+ loadPromise
1268
+ };
1269
+ await loadPromise;
1270
+ })());
1271
+ });
1272
+ await Promise.all(matchPromises);
1273
+ });
1274
+ const load = useStableCallback(async opts => {
1275
+ const promise = new Promise(async (resolve, reject) => {
1276
+ const prevLocation = state.resolvedLocation;
1277
+ const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
1278
+ let latestPromise;
1279
+ const checkLatest = () => {
1280
+ return latestLoadPromiseRef.current !== promise ? latestLoadPromiseRef.current : undefined;
1281
+ };
1282
+
1283
+ // Cancel any pending matches
1284
+ cancelMatches(state);
1285
+ router.emit({
1286
+ type: 'onBeforeLoad',
1287
+ from: prevLocation,
1288
+ to: opts?.next ?? state.location,
1289
+ pathChanged: pathDidChange
1290
+ });
1291
+ if (opts?.next) {
1292
+ // Ingest the new location
1293
+ setState(s => ({
1294
+ ...s,
1295
+ location: opts.next
1296
+ }));
1297
+ }
1298
+
1299
+ // Match the routes
1300
+ const matches = matchRoutes(state.location.pathname, state.location.search, {
1301
+ throwOnError: opts?.throwOnError,
1302
+ debug: true
1303
+ });
1304
+ setState(s => ({
1305
+ ...s,
1306
+ status: 'pending',
1307
+ matches
1308
+ }));
1309
+ try {
1310
+ // Load the matches
1311
+ try {
1312
+ await loadMatches({
1313
+ matches
1314
+ });
1315
+ } catch (err) {
1316
+ // swallow this error, since we'll display the
1317
+ // errors on the route components
1318
+ }
1319
+
1320
+ // Only apply the latest transition
1321
+ if (latestPromise = checkLatest()) {
1322
+ return latestPromise;
1323
+ }
1324
+
1325
+ // TODO:
1326
+ // const exitingMatchIds = previousMatches.filter(
1327
+ // (id) => !state.pendingMatches.includes(id),
1328
+ // )
1329
+ // const enteringMatchIds = state.pendingMatches.filter(
1330
+ // (id) => !previousMatches.includes(id),
1331
+ // )
1332
+ // const stayingMatchIds = previousMatches.filter((id) =>
1333
+ // state.pendingMatches.includes(id),
1334
+ // )
1335
+
1336
+ setState(s => ({
1337
+ ...s,
1338
+ status: 'idle',
1339
+ resolvedLocation: s.location
1340
+ }));
1341
+
1342
+ // TODO:
1343
+ // ;(
1344
+ // [
1345
+ // [exitingMatchIds, 'onLeave'],
1346
+ // [enteringMatchIds, 'onEnter'],
1347
+ // [stayingMatchIds, 'onTransition'],
1348
+ // ] as const
1349
+ // ).forEach(([matches, hook]) => {
1350
+ // matches.forEach((match) => {
1351
+ // const route = this.getRoute(match.routeId)
1352
+ // route.options[hook]?.(match)
1353
+ // })
1354
+ // })
1355
+ router.emit({
1356
+ type: 'onLoad',
1357
+ from: prevLocation,
1358
+ to: state.location,
1359
+ pathChanged: pathDidChange
1360
+ });
1361
+ resolve();
1362
+ } catch (err) {
1363
+ // Only apply the latest transition
1364
+ if (latestPromise = checkLatest()) {
1365
+ return latestPromise;
1366
+ }
1367
+ reject(err);
1368
+ }
1369
+ });
1370
+ latestLoadPromiseRef.current = promise;
1371
+ return latestLoadPromiseRef.current;
1372
+ });
1373
+ const safeLoad = React.useCallback(async () => {
1374
+ try {
1375
+ return load();
1376
+ } catch (err) {
1377
+ // Don't do anything
1378
+ }
1379
+ }, []);
1380
+ const preloadRoute = useStableCallback(async (navigateOpts = state.location) => {
1381
+ let next = buildLocation(navigateOpts);
1382
+ let matches = matchRoutes(next.pathname, next.search, {
1383
+ throwOnError: true
1384
+ });
1385
+ await loadMatches({
1386
+ matches,
1387
+ preload: true
1388
+ });
1389
+ return [last(matches), matches];
1390
+ });
1391
+ const buildLink = useStableCallback((state, dest) => {
1392
+ // If this link simply reloads the current route,
1393
+ // make sure it has a new key so it will trigger a data refresh
1394
+
1395
+ // If this `to` is a valid external URL, return
1396
+ // null for LinkUtils
1397
+
1398
+ const {
1399
+ to,
1400
+ preload: userPreload,
1401
+ preloadDelay: userPreloadDelay,
1402
+ activeOptions,
1403
+ disabled,
1404
+ target,
1405
+ replace,
1406
+ resetScroll
1407
+ } = dest;
1408
+ try {
1409
+ new URL(`${to}`);
1410
+ return {
1411
+ type: 'external',
1412
+ href: to
1413
+ };
1414
+ } catch (e) {}
1415
+ const nextOpts = dest;
1416
+ const next = buildLocation(nextOpts);
1417
+ const preload = userPreload ?? options.defaultPreload;
1418
+ const preloadDelay = userPreloadDelay ?? options.defaultPreloadDelay ?? 0;
1419
+
1420
+ // Compare path/hash for matches
1421
+ const currentPathSplit = latestLocationRef.current.pathname.split('/');
1422
+ const nextPathSplit = next.pathname.split('/');
1423
+ const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
1424
+ // Combine the matches based on user options
1425
+ const pathTest = activeOptions?.exact ? latestLocationRef.current.pathname === next.pathname : pathIsFuzzyEqual;
1426
+ const hashTest = activeOptions?.includeHash ? latestLocationRef.current.hash === next.hash : true;
1427
+ const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(latestLocationRef.current.search, next.search) : true;
1428
+
1429
+ // The final "active" test
1430
+ const isActive = pathTest && hashTest && searchTest;
1431
+
1432
+ // The click handler
1433
+ const handleClick = e => {
1434
+ if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
1435
+ e.preventDefault();
1436
+
1437
+ // All is well? Navigate!
1438
+ commitLocation({
1439
+ ...next,
1440
+ replace,
1441
+ resetScroll
1442
+ });
1443
+ }
1444
+ };
1445
+
1446
+ // The click handler
1447
+ const handleFocus = e => {
1448
+ if (preload) {
1449
+ preloadRoute(nextOpts).catch(err => {
1450
+ console.warn(err);
1451
+ console.warn(preloadWarning);
1452
+ });
1453
+ }
1454
+ };
1455
+ const handleTouchStart = e => {
1456
+ preloadRoute(nextOpts).catch(err => {
1457
+ console.warn(err);
1458
+ console.warn(preloadWarning);
66
1459
  });
1460
+ };
1461
+ const handleEnter = e => {
1462
+ const target = e.target || {};
1463
+ if (preload) {
1464
+ if (target.preloadTimeout) {
1465
+ return;
1466
+ }
1467
+ target.preloadTimeout = setTimeout(() => {
1468
+ target.preloadTimeout = null;
1469
+ preloadRoute(nextOpts).catch(err => {
1470
+ console.warn(err);
1471
+ console.warn(preloadWarning);
1472
+ });
1473
+ }, preloadDelay);
1474
+ }
1475
+ };
1476
+ const handleLeave = e => {
1477
+ const target = e.target || {};
1478
+ if (target.preloadTimeout) {
1479
+ clearTimeout(target.preloadTimeout);
1480
+ target.preloadTimeout = null;
1481
+ }
1482
+ };
1483
+ return {
1484
+ type: 'internal',
1485
+ next,
1486
+ handleFocus,
1487
+ handleClick,
1488
+ handleEnter,
1489
+ handleLeave,
1490
+ handleTouchStart,
1491
+ isActive,
1492
+ disabled
1493
+ };
1494
+ });
1495
+ const latestLocationRef = React.useRef(state.location);
1496
+ React.useLayoutEffect(() => {
1497
+ const unsub = history.subscribe(() => {
1498
+ latestLocationRef.current = parseLocation(latestLocationRef.current);
1499
+ React.startTransition(() => {
1500
+ setState(s => ({
1501
+ ...s,
1502
+ location: latestLocationRef.current
1503
+ }));
1504
+ });
1505
+ });
1506
+ const nextLocation = buildLocation({
1507
+ search: true,
1508
+ params: true,
1509
+ hash: true,
1510
+ state: true
1511
+ });
1512
+ if (state.location.href !== nextLocation.href) {
1513
+ commitLocation({
1514
+ ...nextLocation,
1515
+ replace: true
1516
+ });
1517
+ }
1518
+ return () => {
1519
+ unsub();
1520
+ };
1521
+ }, [history]);
1522
+ const initialLoad = React.useRef(true);
1523
+ if (initialLoad.current) {
1524
+ initialLoad.current = false;
1525
+ safeLoad();
1526
+ }
1527
+ React.useLayoutEffect(() => {
1528
+ if (state.resolvedLocation !== state.location) {
1529
+ safeLoad();
1530
+ }
1531
+ }, [state.location]);
1532
+ React.useMemo(() => [...state.matches, ...state.pendingMatches].some(d => d.isFetching), [state.matches, state.pendingMatches]);
1533
+ const matchRoute = useStableCallback((state, location, opts) => {
1534
+ location = {
1535
+ ...location,
1536
+ to: location.to ? resolvePathWithBase(location.from || '', location.to) : undefined
1537
+ };
1538
+ const next = buildLocation(location);
1539
+ if (opts?.pending && state.status !== 'pending') {
1540
+ return false;
67
1541
  }
1542
+ const baseLocation = opts?.pending ? latestLocationRef.current : state.resolvedLocation;
1543
+ if (!baseLocation) {
1544
+ return false;
1545
+ }
1546
+ const match = matchPathname(basepath, baseLocation.pathname, {
1547
+ ...opts,
1548
+ to: next.pathname
1549
+ });
1550
+ if (!match) {
1551
+ return false;
1552
+ }
1553
+ if (opts?.includeSearch ?? true) {
1554
+ return partialDeepEqual(baseLocation.search, next.search) ? match : false;
1555
+ }
1556
+ return match;
68
1557
  });
69
- };
1558
+ const routerContextValue = {
1559
+ routeTree: router.routeTree,
1560
+ navigate,
1561
+ buildLink,
1562
+ state,
1563
+ matchRoute,
1564
+ routesById,
1565
+ options,
1566
+ history,
1567
+ load
1568
+ };
1569
+ return /*#__PURE__*/React.createElement(routerContext.Provider, {
1570
+ value: routerContextValue
1571
+ }, /*#__PURE__*/React.createElement(Matches, null));
1572
+ }
1573
+ function isCtrlEvent(e) {
1574
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1575
+ }
1576
+ class SearchParamError extends Error {}
1577
+ class PathParamError extends Error {}
1578
+ function getRouteMatch(state, id) {
1579
+ return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
1580
+ }
1581
+
1582
+ const useLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
70
1583
 
71
1584
  //
72
1585
 
@@ -91,7 +1604,10 @@ function lazyRouteComponent(importer, exportName) {
91
1604
  //
92
1605
 
93
1606
  function useLinkProps(options) {
94
- const router = useRouter();
1607
+ const {
1608
+ buildLink,
1609
+ state: routerState
1610
+ } = useRouter();
95
1611
  const match = useMatch({
96
1612
  strict: false
97
1613
  });
@@ -125,7 +1641,7 @@ function useLinkProps(options) {
125
1641
  onTouchStart,
126
1642
  ...rest
127
1643
  } = options;
128
- const linkInfo = router.buildLink({
1644
+ const linkInfo = buildLink(routerState, {
129
1645
  from: options.to ? match.pathname : undefined,
130
1646
  ...options
131
1647
  });
@@ -201,92 +1717,48 @@ const Link = /*#__PURE__*/React.forwardRef((props, ref) => {
201
1717
  }));
202
1718
  });
203
1719
  function Navigate(props) {
204
- const router = useRouter();
1720
+ const {
1721
+ navigate
1722
+ } = useRouter();
205
1723
  const match = useMatch({
206
1724
  strict: false
207
1725
  });
208
- useLayoutEffect$1(() => {
209
- router.navigate({
1726
+ useLayoutEffect(() => {
1727
+ navigate({
210
1728
  from: props.to ? match.pathname : undefined,
211
1729
  ...props
212
1730
  });
213
1731
  }, []);
214
1732
  return null;
215
1733
  }
216
- const matchIdsContext = /*#__PURE__*/React.createContext(null);
217
- const routerContext = /*#__PURE__*/React.createContext(null);
218
- function useRouterState(opts) {
219
- const router = useRouter();
220
- return useStore(router.__store, opts?.select);
221
- }
222
- function RouterProvider({
223
- router,
224
- ...rest
225
- }) {
226
- router.update(rest);
227
- React.useEffect(() => {
228
- let unsub;
229
- React.startTransition(() => {
230
- unsub = router.mount();
231
- });
232
- return unsub;
233
- }, [router]);
234
- const Wrap = router.options.Wrap || React.Fragment;
235
- return /*#__PURE__*/React.createElement(Wrap, null, /*#__PURE__*/React.createElement(routerContext.Provider, {
236
- value: router
237
- }, /*#__PURE__*/React.createElement(Matches, null)));
238
- }
239
- function Matches() {
240
- const router = useRouter();
241
- const matchIds = useRouterState({
242
- select: state => {
243
- return state.renderedMatchIds;
244
- }
245
- });
246
- const locationKey = useRouterState({
247
- select: d => d.resolvedLocation.state?.key
248
- });
249
- const route = router.getRoute(rootRouteId);
250
- const errorComponent = React.useCallback(props => {
251
- return /*#__PURE__*/React.createElement(ErrorComponent, {
252
- ...props,
253
- useMatch: route.useMatch,
254
- useRouteContext: route.useRouteContext,
255
- useSearch: route.useSearch,
256
- useParams: route.useParams
257
- });
258
- }, [route]);
259
- return /*#__PURE__*/React.createElement(matchIdsContext.Provider, {
260
- value: [undefined, ...matchIds]
261
- }, /*#__PURE__*/React.createElement(CatchBoundary, {
262
- resetKey: locationKey,
263
- errorComponent: errorComponent,
264
- onCatch: () => {
265
- warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
266
- }
267
- }, /*#__PURE__*/React.createElement(Outlet, null)));
268
- }
1734
+ const matchesContext = /*#__PURE__*/React.createContext(null);
269
1735
  function useRouter() {
270
1736
  const value = React.useContext(routerContext);
271
- warning(value, 'useRouter must be used inside a <Router> component!');
1737
+ warning(value, 'useRouter must be used inside a <RouterProvider> component!');
272
1738
  return value;
273
1739
  }
1740
+ function useRouterState(opts) {
1741
+ const {
1742
+ state
1743
+ } = useRouter();
1744
+ // return useStore(router.__store, opts?.select as any)
1745
+ return opts?.select ? opts.select(state) : state;
1746
+ }
274
1747
  function useMatches(opts) {
275
- const matchIds = React.useContext(matchIdsContext);
1748
+ const contextMatches = React.useContext(matchesContext);
276
1749
  return useRouterState({
277
1750
  select: state => {
278
- const matches = state.renderedMatches.slice(state.renderedMatches.findIndex(d => d.id === matchIds[0]));
1751
+ const matches = state.matches.slice(state.matches.findIndex(d => d.id === contextMatches[0]?.id));
279
1752
  return opts?.select ? opts.select(matches) : matches;
280
1753
  }
281
1754
  });
282
1755
  }
283
1756
  function useMatch(opts) {
284
- const router = useRouter();
285
- const nearestMatchId = React.useContext(matchIdsContext)[0];
286
- const nearestMatchRouteId = router.getRouteMatch(nearestMatchId)?.routeId;
1757
+ const nearestMatch = React.useContext(matchesContext)[0];
1758
+ const nearestMatchRouteId = nearestMatch?.routeId;
287
1759
  const matchRouteId = useRouterState({
288
1760
  select: state => {
289
- const match = opts?.from ? state.renderedMatches.find(d => d.routeId === opts?.from) : state.renderedMatches.find(d => d.id === nearestMatchId);
1761
+ const match = opts?.from ? state.matches.find(d => d.routeId === opts?.from) : state.matches.find(d => d.id === nearestMatch.id);
290
1762
  return match.routeId;
291
1763
  }
292
1764
  });
@@ -295,29 +1767,17 @@ function useMatch(opts) {
295
1767
  }
296
1768
  const matchSelection = useRouterState({
297
1769
  select: state => {
298
- const match = opts?.from ? state.renderedMatches.find(d => d.routeId === opts?.from) : state.renderedMatches.find(d => d.id === nearestMatchId);
1770
+ const match = opts?.from ? state.matches.find(d => d.routeId === opts?.from) : state.matches.find(d => d.id === nearestMatch.id);
299
1771
  invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
300
1772
  return opts?.select ? opts.select(match) : match;
301
1773
  }
302
1774
  });
303
1775
  return matchSelection;
304
1776
  }
305
- function useLoader(opts) {
306
- return useMatch({
307
- ...opts,
308
- select: match => opts?.select ? opts?.select(match.loaderData) : match.loaderData
309
- });
310
- }
311
- function useRouterContext(opts) {
1777
+ function useRouteMeta(opts) {
312
1778
  return useMatch({
313
1779
  ...opts,
314
- select: match => opts?.select ? opts.select(match.context) : match.context
315
- });
316
- }
317
- function useRouteContext(opts) {
318
- return useMatch({
319
- ...opts,
320
- select: match => opts?.select ? opts.select(match.context) : match.context
1780
+ select: match => opts?.select ? opts.select(match.meta) : match.meta
321
1781
  });
322
1782
  }
323
1783
  function useSearch(opts) {
@@ -331,18 +1791,20 @@ function useSearch(opts) {
331
1791
  function useParams(opts) {
332
1792
  return useRouterState({
333
1793
  select: state => {
334
- const params = last(state.renderedMatches)?.params;
1794
+ const params = last(state.matches)?.params;
335
1795
  return opts?.select ? opts.select(params) : params;
336
1796
  }
337
1797
  });
338
1798
  }
339
1799
  function useNavigate(defaultOpts) {
340
- const router = useRouter();
1800
+ const {
1801
+ navigate
1802
+ } = useRouter();
341
1803
  const match = useMatch({
342
1804
  strict: false
343
1805
  });
344
1806
  return React.useCallback(opts => {
345
- return router.navigate({
1807
+ return navigate({
346
1808
  from: opts?.to ? match.pathname : undefined,
347
1809
  ...defaultOpts,
348
1810
  ...opts
@@ -350,19 +1812,62 @@ function useNavigate(defaultOpts) {
350
1812
  }, []);
351
1813
  }
352
1814
  function useMatchRoute() {
353
- const router = useRouter();
1815
+ const {
1816
+ state,
1817
+ matchRoute
1818
+ } = useRouter();
354
1819
  return React.useCallback(opts => {
355
1820
  const {
356
1821
  pending,
357
1822
  caseSensitive,
358
1823
  ...rest
359
1824
  } = opts;
360
- return router.matchRoute(rest, {
1825
+ return matchRoute(state, rest, {
361
1826
  pending,
362
1827
  caseSensitive
363
1828
  });
364
1829
  }, []);
365
1830
  }
1831
+ function Matches() {
1832
+ const {
1833
+ routesById,
1834
+ state
1835
+ } = useRouter();
1836
+
1837
+ // const matches = useRouterState({
1838
+ // select: (state) => {
1839
+ // return state.matches
1840
+ // },
1841
+ // })
1842
+
1843
+ const {
1844
+ matches
1845
+ } = state;
1846
+ const locationKey = useRouterState({
1847
+ select: d => d.resolvedLocation.state?.key
1848
+ });
1849
+ const route = routesById[rootRouteId];
1850
+ const errorComponent = React.useCallback(props => {
1851
+ return /*#__PURE__*/React.createElement(ErrorComponent, {
1852
+ ...props,
1853
+ useMatch: route.useMatch,
1854
+ useRouteMeta: route.useRouteMeta,
1855
+ useSearch: route.useSearch,
1856
+ useParams: route.useParams
1857
+ });
1858
+ }, [route]);
1859
+ return /*#__PURE__*/React.createElement(matchesContext.Provider, {
1860
+ value: matches
1861
+ }, /*#__PURE__*/React.createElement(CatchBoundary, {
1862
+ resetKey: locationKey,
1863
+ errorComponent: errorComponent,
1864
+ onCatch: () => {
1865
+ warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
1866
+ }
1867
+ }, matches.length ? /*#__PURE__*/React.createElement(Match, {
1868
+ matches: matches
1869
+ }) : null));
1870
+ }
366
1871
  function MatchRoute(props) {
367
1872
  const matchRoute = useMatchRoute();
368
1873
  const params = matchRoute(props);
@@ -372,44 +1877,47 @@ function MatchRoute(props) {
372
1877
  return !!params ? props.children : null;
373
1878
  }
374
1879
  function Outlet() {
375
- const matchIds = React.useContext(matchIdsContext).slice(1);
376
- if (!matchIds[0]) {
1880
+ const matches = React.useContext(matchesContext).slice(1);
1881
+ if (!matches[0]) {
377
1882
  return null;
378
1883
  }
379
1884
  return /*#__PURE__*/React.createElement(Match, {
380
- matchIds: matchIds
1885
+ matches: matches
381
1886
  });
382
1887
  }
383
1888
  const defaultPending = () => null;
384
1889
  function Match({
385
- matchIds
1890
+ matches
386
1891
  }) {
387
- const router = useRouter();
388
- const matchId = matchIds[0];
389
- const routeId = router.getRouteMatch(matchId).routeId;
390
- const route = router.getRoute(routeId);
1892
+ const {
1893
+ options,
1894
+ routesById
1895
+ } = useRouter();
1896
+ const match = matches[0];
1897
+ const routeId = match?.routeId;
1898
+ const route = routesById[routeId];
391
1899
  const locationKey = useRouterState({
392
1900
  select: s => s.resolvedLocation.state?.key
393
1901
  });
394
- const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
395
- const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent;
1902
+ const PendingComponent = route.options.pendingComponent ?? options.defaultPendingComponent ?? defaultPending;
1903
+ const routeErrorComponent = route.options.errorComponent ?? options.defaultErrorComponent ?? ErrorComponent;
396
1904
  const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? !route.isRoot ? React.Suspense : SafeFragment;
397
1905
  const ResolvedCatchBoundary = !!routeErrorComponent ? CatchBoundary : SafeFragment;
398
1906
  const errorComponent = React.useCallback(props => {
399
1907
  return /*#__PURE__*/React.createElement(routeErrorComponent, {
400
1908
  ...props,
401
1909
  useMatch: route.useMatch,
402
- useRouteContext: route.useRouteContext,
1910
+ useRouteMeta: route.useRouteMeta,
403
1911
  useSearch: route.useSearch,
404
1912
  useParams: route.useParams
405
1913
  });
406
1914
  }, [route]);
407
- return /*#__PURE__*/React.createElement(matchIdsContext.Provider, {
408
- value: matchIds
1915
+ return /*#__PURE__*/React.createElement(matchesContext.Provider, {
1916
+ value: matches
409
1917
  }, /*#__PURE__*/React.createElement(ResolvedSuspenseBoundary, {
410
1918
  fallback: /*#__PURE__*/React.createElement(PendingComponent, {
411
1919
  useMatch: route.useMatch,
412
- useRouteContext: route.useRouteContext,
1920
+ useRouteMeta: route.useRouteMeta,
413
1921
  useSearch: route.useSearch,
414
1922
  useParams: route.useParams
415
1923
  })
@@ -417,44 +1925,32 @@ function Match({
417
1925
  resetKey: locationKey,
418
1926
  errorComponent: errorComponent,
419
1927
  onCatch: () => {
420
- warning(false, `Error in route match: ${matchId}`);
1928
+ warning(false, `Error in route match: ${match.id}`);
421
1929
  }
422
1930
  }, /*#__PURE__*/React.createElement(MatchInner, {
423
- matchId: matchId,
424
- PendingComponent: PendingComponent
1931
+ match: match
425
1932
  }))));
426
1933
  }
427
1934
  function MatchInner({
428
- matchId,
429
- PendingComponent
1935
+ match
430
1936
  }) {
431
- const router = useRouter();
432
- const match = useRouterState({
433
- select: d => {
434
- const match = d.matchesById[matchId];
435
- return pick(match, ['status', 'loadPromise', 'routeId', 'error']);
436
- }
437
- });
438
- const route = router.getRoute(match.routeId);
1937
+ const {
1938
+ options,
1939
+ routesById
1940
+ } = useRouter();
1941
+ const route = routesById[match.routeId];
439
1942
  if (match.status === 'error') {
440
1943
  throw match.error;
441
1944
  }
442
1945
  if (match.status === 'pending') {
443
- return /*#__PURE__*/React.createElement(PendingComponent, {
444
- useLoader: route.useLoader,
445
- useMatch: route.useMatch,
446
- useRouteContext: route.useRouteContext,
447
- useSearch: route.useSearch,
448
- useParams: route.useParams
449
- });
1946
+ throw match.loadPromise;
450
1947
  }
451
1948
  if (match.status === 'success') {
452
- let comp = route.options.component ?? router.options.defaultComponent;
1949
+ let comp = route.options.component ?? options.defaultComponent;
453
1950
  if (comp) {
454
1951
  return /*#__PURE__*/React.createElement(comp, {
455
- useLoader: route.useLoader,
456
1952
  useMatch: route.useMatch,
457
- useRouteContext: route.useRouteContext,
1953
+ useRouteMeta: route.useRouteMeta,
458
1954
  useSearch: route.useSearch,
459
1955
  useParams: route.useParams
460
1956
  });
@@ -466,24 +1962,37 @@ function MatchInner({
466
1962
  function SafeFragment(props) {
467
1963
  return /*#__PURE__*/React.createElement(React.Fragment, null, props.children);
468
1964
  }
469
- function useInjectHtml() {
470
- const router = useRouter();
471
- return React.useCallback(html => {
472
- router.injectHtml(html);
473
- }, []);
474
- }
475
- function useDehydrate() {
476
- const router = useRouter();
477
- return React.useCallback(function dehydrate(key, data) {
478
- return router.dehydrateData(key, data);
479
- }, []);
480
- }
481
- function useHydrate() {
482
- const router = useRouter();
483
- return function hydrate(key) {
484
- return router.hydrateData(key);
485
- };
486
- }
1965
+
1966
+ // export function useInjectHtml() {
1967
+ // const { } = useRouter()
1968
+
1969
+ // return React.useCallback(
1970
+ // (html: string | (() => Promise<string> | string)) => {
1971
+ // router.injectHtml(html)
1972
+ // },
1973
+ // [],
1974
+ // )
1975
+ // }
1976
+
1977
+ // export function useDehydrate() {
1978
+ // const { } = useRouter()
1979
+
1980
+ // return React.useCallback(function dehydrate<T>(
1981
+ // key: any,
1982
+ // data: T | (() => Promise<T> | T),
1983
+ // ) {
1984
+ // return router.dehydrateData(key, data)
1985
+ // },
1986
+ // [])
1987
+ // }
1988
+
1989
+ // export function useHydrate() {
1990
+ // const { } = useRouter()
1991
+
1992
+ // return function hydrate<T = unknown>(key: any) {
1993
+ // return router.hydrateData(key) as T
1994
+ // }
1995
+ // }
487
1996
 
488
1997
  // This is the messiest thing ever... I'm either seriously tired (likely) or
489
1998
  // there has to be a better way to reset error boundaries when the
@@ -574,10 +2083,12 @@ function ErrorComponent({
574
2083
  }, error.message ? /*#__PURE__*/React.createElement("code", null, error.message) : null)) : null);
575
2084
  }
576
2085
  function useBlocker(message, condition = true) {
577
- const router = useRouter();
2086
+ const {
2087
+ history
2088
+ } = useRouter();
578
2089
  React.useEffect(() => {
579
2090
  if (!condition) return;
580
- let unblock = router.history.block((retry, cancel) => {
2091
+ let unblock = history.block((retry, cancel) => {
581
2092
  if (window.confirm(message)) {
582
2093
  unblock();
583
2094
  retry();
@@ -613,45 +2124,124 @@ function shallow(objA, objB) {
613
2124
  return true;
614
2125
  }
615
2126
 
616
- const useLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
617
- function useScrollRestoration(options) {
618
- const router = useRouter();
619
- useLayoutEffect(() => {
620
- return watchScrollPositions(router, options);
621
- }, []);
622
- useLayoutEffect(() => {
623
- restoreScrollPositions(router, options);
624
- });
625
- }
626
- function ScrollRestoration(props) {
627
- useScrollRestoration(props);
628
- return null;
629
- }
2127
+ const rootRouteId = '__root__';
630
2128
 
631
- function useAwaited({
632
- promise
633
- }) {
634
- const router = useRouter();
635
- let state = promise.__deferredState;
636
- const key = `__TSR__DEFERRED__${state.uid}`;
637
- if (isDehydratedDeferred(promise)) {
638
- state = router.hydrateData(key);
639
- promise = Promise.resolve(state.data);
640
- promise.__deferredState = state;
641
- }
642
- if (state.status === 'pending') {
643
- throw promise;
2129
+ // export type MetaOptions = keyof PickRequired<RouteMeta> extends never
2130
+ // ? {
2131
+ // meta?: RouteMeta
2132
+ // }
2133
+ // : {
2134
+ // meta: RouteMeta
2135
+ // }
2136
+ // The parse type here allows a zod schema to be passed directly to the validator
2137
+ class Route {
2138
+ // Set up in this.init()
2139
+
2140
+ // customId!: TCustomId
2141
+
2142
+ // Optional
2143
+
2144
+ constructor(options) {
2145
+ this.options = options || {};
2146
+ this.isRoot = !options?.getParentRoute;
2147
+ Route.__onInit(this);
644
2148
  }
645
- if (state.status === 'error') {
646
- throw state.error;
2149
+ init = opts => {
2150
+ this.originalIndex = opts.originalIndex;
2151
+ const options = this.options;
2152
+ const isRoot = !options?.path && !options?.id;
2153
+ this.parentRoute = this.options?.getParentRoute?.();
2154
+ if (isRoot) {
2155
+ this.path = rootRouteId;
2156
+ } else {
2157
+ invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
2158
+ }
2159
+ let path = isRoot ? rootRouteId : options.path;
2160
+
2161
+ // If the path is anything other than an index path, trim it up
2162
+ if (path && path !== '/') {
2163
+ path = trimPath(path);
2164
+ }
2165
+ const customId = options?.id || path;
2166
+
2167
+ // Strip the parentId prefix from the first level of children
2168
+ let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
2169
+ if (path === rootRouteId) {
2170
+ path = '/';
2171
+ }
2172
+ if (id !== rootRouteId) {
2173
+ id = joinPaths(['/', id]);
2174
+ }
2175
+ const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
2176
+ this.path = path;
2177
+ this.id = id;
2178
+ // this.customId = customId as TCustomId
2179
+ this.fullPath = fullPath;
2180
+ this.to = fullPath;
2181
+ };
2182
+ addChildren = children => {
2183
+ this.children = children;
2184
+ return this;
2185
+ };
2186
+ update = options => {
2187
+ Object.assign(this.options, options);
2188
+ return this;
2189
+ };
2190
+ static __onInit = route => {
2191
+ // This is a dummy static method that should get
2192
+ // replaced by a framework specific implementation if necessary
2193
+ };
2194
+ useMatch = opts => {
2195
+ return useMatch({
2196
+ ...opts,
2197
+ from: this.id
2198
+ });
2199
+ };
2200
+ useRouteMeta = opts => {
2201
+ return useMatch({
2202
+ ...opts,
2203
+ from: this.id,
2204
+ select: d => opts?.select ? opts.select(d.meta) : d.meta
2205
+ });
2206
+ };
2207
+ useSearch = opts => {
2208
+ return useSearch({
2209
+ ...opts,
2210
+ from: this.id
2211
+ });
2212
+ };
2213
+ useParams = opts => {
2214
+ return useParams({
2215
+ ...opts,
2216
+ from: this.id
2217
+ });
2218
+ };
2219
+ }
2220
+ class RouterMeta {
2221
+ constructor() {}
2222
+ createRootRoute = options => {
2223
+ return new RootRoute(options);
2224
+ };
2225
+ }
2226
+ class RootRoute extends Route {
2227
+ constructor(options) {
2228
+ super(options);
647
2229
  }
648
- router.dehydrateData(key, state);
649
- return [state.data];
650
2230
  }
651
- function Await(props) {
652
- const awaited = useAwaited(props);
653
- return props.children(...awaited);
2231
+ function createRouteMask(opts) {
2232
+ return opts;
2233
+ }
2234
+
2235
+ class FileRoute {
2236
+ constructor(path) {
2237
+ this.path = path;
2238
+ }
2239
+ createRoute = options => {
2240
+ const route = new Route(options);
2241
+ route.isRoot = false;
2242
+ return route;
2243
+ };
654
2244
  }
655
2245
 
656
- export { Await, Block, CatchBoundary, CatchBoundaryImpl, ErrorComponent, Link, MatchRoute, Navigate, Outlet, RouterProvider, ScrollRestoration, lazyRouteComponent, matchIdsContext, routerContext, shallow, useAwaited, useBlocker, useDehydrate, useHydrate, useInjectHtml, useLinkProps, useLoader, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useRouteContext, useRouter, useRouterContext, useRouterState, useScrollRestoration, useSearch };
2246
+ export { Block, CatchBoundary, CatchBoundaryImpl, ErrorComponent, FileRoute, Link, MatchRoute, Matches, Navigate, Outlet, PathParamError, RootRoute, Route, Router, RouterMeta, RouterProvider, SearchParamError, cleanPath, componentTypes, createRouteMask, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, getInitialRouterState, getRouteMatch, interpolatePath, isPlainObject, isRedirect, isServer, joinPaths, last, lazyFn, lazyRouteComponent, matchByPath, matchPathname, matchesContext, parsePathname, parseSearchWith, partialDeepEqual, pick, redirect, replaceEqualDeep, resolvePath, rootRouteId, routerContext, shallow, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, useBlocker, useLinkProps, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useRouteMeta, useRouter, useRouterState, useSearch, useStableCallback };
657
2247
  //# sourceMappingURL=index.js.map