@tanstack/react-router 0.0.1-beta.24 → 0.0.1-beta.240

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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/build/cjs/CatchBoundary.js +123 -0
  3. package/build/cjs/CatchBoundary.js.map +1 -0
  4. package/build/cjs/Matches.js +232 -0
  5. package/build/cjs/Matches.js.map +1 -0
  6. package/build/cjs/RouterProvider.js +159 -0
  7. package/build/cjs/RouterProvider.js.map +1 -0
  8. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +2 -22
  9. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
  10. package/build/cjs/awaited.js +43 -0
  11. package/build/cjs/awaited.js.map +1 -0
  12. package/build/cjs/defer.js +37 -0
  13. package/build/cjs/defer.js.map +1 -0
  14. package/build/cjs/fileRoute.js +27 -0
  15. package/build/cjs/fileRoute.js.map +1 -0
  16. package/build/cjs/index.js +123 -0
  17. package/build/cjs/index.js.map +1 -0
  18. package/build/cjs/lazyRouteComponent.js +54 -0
  19. package/build/cjs/lazyRouteComponent.js.map +1 -0
  20. package/build/cjs/link.js +148 -0
  21. package/build/cjs/link.js.map +1 -0
  22. package/build/cjs/path.js +209 -0
  23. package/build/cjs/path.js.map +1 -0
  24. package/build/cjs/qss.js +63 -0
  25. package/build/cjs/qss.js.map +1 -0
  26. package/build/cjs/redirects.js +25 -0
  27. package/build/cjs/redirects.js.map +1 -0
  28. package/build/cjs/route.js +134 -0
  29. package/build/cjs/route.js.map +1 -0
  30. package/build/cjs/router.js +1113 -0
  31. package/build/cjs/router.js.map +1 -0
  32. package/build/cjs/scroll-restoration.js +202 -0
  33. package/build/cjs/scroll-restoration.js.map +1 -0
  34. package/build/cjs/searchParams.js +81 -0
  35. package/build/cjs/searchParams.js.map +1 -0
  36. package/build/cjs/useBlocker.js +61 -0
  37. package/build/cjs/useBlocker.js.map +1 -0
  38. package/build/cjs/useNavigate.js +75 -0
  39. package/build/cjs/useNavigate.js.map +1 -0
  40. package/build/cjs/useParams.js +26 -0
  41. package/build/cjs/useParams.js.map +1 -0
  42. package/build/cjs/useSearch.js +25 -0
  43. package/build/cjs/useSearch.js.map +1 -0
  44. package/build/cjs/utils.js +239 -0
  45. package/build/cjs/utils.js.map +1 -0
  46. package/build/esm/index.js +2159 -2534
  47. package/build/esm/index.js.map +1 -1
  48. package/build/stats-html.html +3498 -2694
  49. package/build/stats-react.json +1210 -44
  50. package/build/types/CatchBoundary.d.ts +33 -0
  51. package/build/types/Matches.d.ts +57 -0
  52. package/build/types/RouterProvider.d.ts +36 -0
  53. package/build/types/awaited.d.ts +9 -0
  54. package/build/types/defer.d.ts +19 -0
  55. package/build/types/fileRoute.d.ts +35 -0
  56. package/build/types/history.d.ts +7 -0
  57. package/build/types/index.d.ts +27 -108
  58. package/build/types/injectHtml.d.ts +0 -0
  59. package/build/types/lazyRouteComponent.d.ts +2 -0
  60. package/build/types/link.d.ts +105 -0
  61. package/build/types/location.d.ts +14 -0
  62. package/build/types/path.d.ts +16 -0
  63. package/build/types/qss.d.ts +2 -0
  64. package/build/types/redirects.d.ts +10 -0
  65. package/build/types/route.d.ts +278 -0
  66. package/build/types/routeInfo.d.ts +22 -0
  67. package/build/types/router.d.ts +182 -0
  68. package/build/types/scroll-restoration.d.ts +18 -0
  69. package/build/types/searchParams.d.ts +7 -0
  70. package/build/types/useBlocker.d.ts +8 -0
  71. package/build/types/useNavigate.d.ts +20 -0
  72. package/build/types/useParams.d.ts +7 -0
  73. package/build/types/useSearch.d.ts +7 -0
  74. package/build/types/utils.d.ts +66 -0
  75. package/build/umd/index.development.js +2714 -2485
  76. package/build/umd/index.development.js.map +1 -1
  77. package/build/umd/index.production.js +4 -4
  78. package/build/umd/index.production.js.map +1 -1
  79. package/package.json +11 -10
  80. package/src/CatchBoundary.tsx +98 -0
  81. package/src/Matches.tsx +401 -0
  82. package/src/RouterProvider.tsx +241 -0
  83. package/src/awaited.tsx +40 -0
  84. package/src/defer.ts +55 -0
  85. package/src/fileRoute.ts +154 -0
  86. package/src/history.ts +8 -0
  87. package/src/index.tsx +28 -708
  88. package/src/injectHtml.ts +28 -0
  89. package/src/lazyRouteComponent.tsx +33 -0
  90. package/src/link.tsx +508 -0
  91. package/src/location.ts +15 -0
  92. package/src/path.ts +256 -0
  93. package/src/qss.ts +53 -0
  94. package/src/redirects.ts +31 -0
  95. package/src/route.ts +861 -0
  96. package/src/routeInfo.ts +68 -0
  97. package/src/router.ts +1700 -0
  98. package/src/scroll-restoration.tsx +230 -0
  99. package/src/searchParams.ts +79 -0
  100. package/src/useBlocker.tsx +34 -0
  101. package/src/useNavigate.tsx +109 -0
  102. package/src/useParams.tsx +25 -0
  103. package/src/useSearch.tsx +25 -0
  104. package/src/utils.ts +350 -0
  105. package/build/cjs/react-router/src/index.js +0 -473
  106. package/build/cjs/react-router/src/index.js.map +0 -1
  107. package/build/cjs/router-core/build/esm/index.js +0 -2528
  108. package/build/cjs/router-core/build/esm/index.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router
2
+ * @tanstack/react-router/src/index.tsx
3
3
  *
4
4
  * Copyright (c) TanStack
5
5
  *
@@ -8,972 +8,292 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
+ import { createBrowserHistory, createMemoryHistory } from '@tanstack/history';
12
+ export * from '@tanstack/history';
13
+ import invariant from 'tiny-invariant';
14
+ export { default as invariant } from 'tiny-invariant';
15
+ import warning from 'tiny-warning';
16
+ export { default as warning } from 'tiny-warning';
11
17
  import * as React from 'react';
12
- import { useSyncExternalStore } from 'use-sync-external-store/shim';
13
-
14
- function _extends$2() {
15
- _extends$2 = Object.assign ? Object.assign.bind() : function (target) {
16
- for (var i = 1; i < arguments.length; i++) {
17
- var source = arguments[i];
18
-
19
- for (var key in source) {
20
- if (Object.prototype.hasOwnProperty.call(source, key)) {
21
- target[key] = source[key];
22
- }
18
+ import { useStore } from '@tanstack/react-store';
19
+ import { Store } from '@tanstack/store';
20
+
21
+ function CatchBoundary(props) {
22
+ const errorComponent = props.errorComponent ?? ErrorComponent;
23
+ return /*#__PURE__*/React.createElement(CatchBoundaryImpl, {
24
+ resetKey: props.resetKey,
25
+ onCatch: props.onCatch,
26
+ children: ({
27
+ error
28
+ }) => {
29
+ if (error) {
30
+ return /*#__PURE__*/React.createElement(errorComponent, {
31
+ error
32
+ });
23
33
  }
34
+ return props.children;
24
35
  }
25
-
26
- return target;
27
- };
28
- return _extends$2.apply(this, arguments);
29
- }
30
-
31
- function _objectWithoutPropertiesLoose(source, excluded) {
32
- if (source == null) return {};
33
- var target = {};
34
- var sourceKeys = Object.keys(source);
35
- var key, i;
36
-
37
- for (i = 0; i < sourceKeys.length; i++) {
38
- key = sourceKeys[i];
39
- if (excluded.indexOf(key) >= 0) continue;
40
- target[key] = source[key];
41
- }
42
-
43
- return target;
36
+ });
44
37
  }
45
-
46
- /**
47
- * router-core
48
- *
49
- * Copyright (c) TanStack
50
- *
51
- * This source code is licensed under the MIT license found in the
52
- * LICENSE.md file in the root directory of this source tree.
53
- *
54
- * @license MIT
55
- */
56
- function _extends$1() {
57
- _extends$1 = Object.assign ? Object.assign.bind() : function (target) {
58
- for (var i = 1; i < arguments.length; i++) {
59
- var source = arguments[i];
60
-
61
- for (var key in source) {
62
- if (Object.prototype.hasOwnProperty.call(source, key)) {
63
- target[key] = source[key];
64
- }
65
- }
66
- }
67
-
68
- return target;
38
+ class CatchBoundaryImpl extends React.Component {
39
+ state = {
40
+ error: null
69
41
  };
70
- return _extends$1.apply(this, arguments);
71
- }
72
-
73
- /**
74
- * Actions represent the type of change to a location value.
75
- *
76
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#action
77
- */
78
- var Action;
79
-
80
- (function (Action) {
81
- /**
82
- * A POP indicates a change to an arbitrary index in the history stack, such
83
- * as a back or forward navigation. It does not describe the direction of the
84
- * navigation, only that the current index changed.
85
- *
86
- * Note: This is the default action for newly created history objects.
87
- */
88
- Action["Pop"] = "POP";
89
- /**
90
- * A PUSH indicates a new entry being added to the history stack, such as when
91
- * a link is clicked and a new page loads. When this happens, all subsequent
92
- * entries in the stack are lost.
93
- */
94
-
95
- Action["Push"] = "PUSH";
96
- /**
97
- * A REPLACE indicates the entry at the current index in the history stack
98
- * being replaced by a new one.
99
- */
100
-
101
- Action["Replace"] = "REPLACE";
102
- })(Action || (Action = {}));
103
-
104
- var readOnly = process.env.NODE_ENV !== "production" ? function (obj) {
105
- return Object.freeze(obj);
106
- } : function (obj) {
107
- return obj;
108
- };
109
-
110
- function warning$1(cond, message) {
111
- if (!cond) {
112
- // eslint-disable-next-line no-console
113
- if (typeof console !== 'undefined') console.warn(message);
114
-
115
- try {
116
- // Welcome to debugging history!
117
- //
118
- // This error is thrown as a convenience so you can more easily
119
- // find the source for a warning that appears in the console by
120
- // enabling "pause on exceptions" in your JavaScript debugger.
121
- throw new Error(message); // eslint-disable-next-line no-empty
122
- } catch (e) {}
123
- }
124
- }
125
-
126
- var BeforeUnloadEventType = 'beforeunload';
127
- var HashChangeEventType = 'hashchange';
128
- var PopStateEventType = 'popstate';
129
- /**
130
- * Browser history stores the location in regular URLs. This is the standard for
131
- * most web apps, but it requires some configuration on the server to ensure you
132
- * serve the same app at multiple URLs.
133
- *
134
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createbrowserhistory
135
- */
136
-
137
- function createBrowserHistory(options) {
138
- if (options === void 0) {
139
- options = {};
140
- }
141
-
142
- var _options = options,
143
- _options$window = _options.window,
144
- window = _options$window === void 0 ? document.defaultView : _options$window;
145
- var globalHistory = window.history;
146
-
147
- function getIndexAndLocation() {
148
- var _window$location = window.location,
149
- pathname = _window$location.pathname,
150
- search = _window$location.search,
151
- hash = _window$location.hash;
152
- var state = globalHistory.state || {};
153
- return [state.idx, readOnly({
154
- pathname: pathname,
155
- search: search,
156
- hash: hash,
157
- state: state.usr || null,
158
- key: state.key || 'default'
159
- })];
160
- }
161
-
162
- var blockedPopTx = null;
163
-
164
- function handlePop() {
165
- if (blockedPopTx) {
166
- blockers.call(blockedPopTx);
167
- blockedPopTx = null;
168
- } else {
169
- var nextAction = Action.Pop;
170
-
171
- var _getIndexAndLocation = getIndexAndLocation(),
172
- nextIndex = _getIndexAndLocation[0],
173
- nextLocation = _getIndexAndLocation[1];
174
-
175
- if (blockers.length) {
176
- if (nextIndex != null) {
177
- var delta = index - nextIndex;
178
-
179
- if (delta) {
180
- // Revert the POP
181
- blockedPopTx = {
182
- action: nextAction,
183
- location: nextLocation,
184
- retry: function retry() {
185
- go(delta * -1);
186
- }
187
- };
188
- go(delta);
189
- }
190
- } else {
191
- // Trying to POP to a location with no index. We did not create
192
- // this location, so we can't effectively block the navigation.
193
- process.env.NODE_ENV !== "production" ? warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
194
- // detail and link to it here so people can understand better what
195
- // is going on and how to avoid it.
196
- "You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation.") : void 0;
197
- }
198
- } else {
199
- applyTx(nextAction);
200
- }
201
- }
202
- }
203
-
204
- window.addEventListener(PopStateEventType, handlePop);
205
- var action = Action.Pop;
206
-
207
- var _getIndexAndLocation2 = getIndexAndLocation(),
208
- index = _getIndexAndLocation2[0],
209
- location = _getIndexAndLocation2[1];
210
-
211
- var listeners = createEvents();
212
- var blockers = createEvents();
213
-
214
- if (index == null) {
215
- index = 0;
216
- globalHistory.replaceState(_extends$1({}, globalHistory.state, {
217
- idx: index
218
- }), '');
219
- }
220
-
221
- function createHref(to) {
222
- return typeof to === 'string' ? to : createPath(to);
223
- } // state defaults to `null` because `window.history.state` does
224
-
225
-
226
- function getNextLocation(to, state) {
227
- if (state === void 0) {
228
- state = null;
229
- }
230
-
231
- return readOnly(_extends$1({
232
- pathname: location.pathname,
233
- hash: '',
234
- search: ''
235
- }, typeof to === 'string' ? parsePath(to) : to, {
236
- state: state,
237
- key: createKey()
238
- }));
239
- }
240
-
241
- function getHistoryStateAndUrl(nextLocation, index) {
242
- return [{
243
- usr: nextLocation.state,
244
- key: nextLocation.key,
245
- idx: index
246
- }, createHref(nextLocation)];
247
- }
248
-
249
- function allowTx(action, location, retry) {
250
- return !blockers.length || (blockers.call({
251
- action: action,
252
- location: location,
253
- retry: retry
254
- }), false);
255
- }
256
-
257
- function applyTx(nextAction) {
258
- action = nextAction;
259
-
260
- var _getIndexAndLocation3 = getIndexAndLocation();
261
-
262
- index = _getIndexAndLocation3[0];
263
- location = _getIndexAndLocation3[1];
264
- listeners.call({
265
- action: action,
266
- location: location
267
- });
268
- }
269
-
270
- function push(to, state) {
271
- var nextAction = Action.Push;
272
- var nextLocation = getNextLocation(to, state);
273
-
274
- function retry() {
275
- push(to, state);
276
- }
277
-
278
- if (allowTx(nextAction, nextLocation, retry)) {
279
- var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1),
280
- historyState = _getHistoryStateAndUr[0],
281
- url = _getHistoryStateAndUr[1]; // TODO: Support forced reloading
282
- // try...catch because iOS limits us to 100 pushState calls :/
283
-
284
-
285
- try {
286
- globalHistory.pushState(historyState, '', url);
287
- } catch (error) {
288
- // They are going to lose state here, but there is no real
289
- // way to warn them about it since the page will refresh...
290
- window.location.assign(url);
291
- }
292
-
293
- applyTx(nextAction);
294
- }
295
- }
296
-
297
- function replace(to, state) {
298
- var nextAction = Action.Replace;
299
- var nextLocation = getNextLocation(to, state);
300
-
301
- function retry() {
302
- replace(to, state);
303
- }
304
-
305
- if (allowTx(nextAction, nextLocation, retry)) {
306
- var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index),
307
- historyState = _getHistoryStateAndUr2[0],
308
- url = _getHistoryStateAndUr2[1]; // TODO: Support forced reloading
309
-
310
-
311
- globalHistory.replaceState(historyState, '', url);
312
- applyTx(nextAction);
313
- }
314
- }
315
-
316
- function go(delta) {
317
- globalHistory.go(delta);
318
- }
319
-
320
- var history = {
321
- get action() {
322
- return action;
323
- },
324
-
325
- get location() {
326
- return location;
327
- },
328
-
329
- createHref: createHref,
330
- push: push,
331
- replace: replace,
332
- go: go,
333
- back: function back() {
334
- go(-1);
335
- },
336
- forward: function forward() {
337
- go(1);
338
- },
339
- listen: function listen(listener) {
340
- return listeners.push(listener);
341
- },
342
- block: function block(blocker) {
343
- var unblock = blockers.push(blocker);
344
-
345
- if (blockers.length === 1) {
346
- window.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
347
- }
348
-
349
- return function () {
350
- unblock(); // Remove the beforeunload listener so the document may
351
- // still be salvageable in the pagehide event.
352
- // See https://html.spec.whatwg.org/#unloading-documents
353
-
354
- if (!blockers.length) {
355
- window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
356
- }
357
- };
358
- }
359
- };
360
- return history;
361
- }
362
- /**
363
- * Hash history stores the location in window.location.hash. This makes it ideal
364
- * for situations where you don't want to send the location to the server for
365
- * some reason, either because you do cannot configure it or the URL space is
366
- * reserved for something else.
367
- *
368
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createhashhistory
369
- */
370
-
371
- function createHashHistory(options) {
372
- if (options === void 0) {
373
- options = {};
374
- }
375
-
376
- var _options2 = options,
377
- _options2$window = _options2.window,
378
- window = _options2$window === void 0 ? document.defaultView : _options2$window;
379
- var globalHistory = window.history;
380
-
381
- function getIndexAndLocation() {
382
- var _parsePath = parsePath(window.location.hash.substr(1)),
383
- _parsePath$pathname = _parsePath.pathname,
384
- pathname = _parsePath$pathname === void 0 ? '/' : _parsePath$pathname,
385
- _parsePath$search = _parsePath.search,
386
- search = _parsePath$search === void 0 ? '' : _parsePath$search,
387
- _parsePath$hash = _parsePath.hash,
388
- hash = _parsePath$hash === void 0 ? '' : _parsePath$hash;
389
-
390
- var state = globalHistory.state || {};
391
- return [state.idx, readOnly({
392
- pathname: pathname,
393
- search: search,
394
- hash: hash,
395
- state: state.usr || null,
396
- key: state.key || 'default'
397
- })];
398
- }
399
-
400
- var blockedPopTx = null;
401
-
402
- function handlePop() {
403
- if (blockedPopTx) {
404
- blockers.call(blockedPopTx);
405
- blockedPopTx = null;
406
- } else {
407
- var nextAction = Action.Pop;
408
-
409
- var _getIndexAndLocation4 = getIndexAndLocation(),
410
- nextIndex = _getIndexAndLocation4[0],
411
- nextLocation = _getIndexAndLocation4[1];
412
-
413
- if (blockers.length) {
414
- if (nextIndex != null) {
415
- var delta = index - nextIndex;
416
-
417
- if (delta) {
418
- // Revert the POP
419
- blockedPopTx = {
420
- action: nextAction,
421
- location: nextLocation,
422
- retry: function retry() {
423
- go(delta * -1);
424
- }
425
- };
426
- go(delta);
427
- }
428
- } else {
429
- // Trying to POP to a location with no index. We did not create
430
- // this location, so we can't effectively block the navigation.
431
- process.env.NODE_ENV !== "production" ? warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
432
- // detail and link to it here so people can understand better
433
- // what is going on and how to avoid it.
434
- "You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation.") : void 0;
435
- }
436
- } else {
437
- applyTx(nextAction);
438
- }
439
- }
440
- }
441
-
442
- window.addEventListener(PopStateEventType, handlePop); // popstate does not fire on hashchange in IE 11 and old (trident) Edge
443
- // https://developer.mozilla.org/de/docs/Web/API/Window/popstate_event
444
-
445
- window.addEventListener(HashChangeEventType, function () {
446
- var _getIndexAndLocation5 = getIndexAndLocation(),
447
- nextLocation = _getIndexAndLocation5[1]; // Ignore extraneous hashchange events.
448
-
449
-
450
- if (createPath(nextLocation) !== createPath(location)) {
451
- handlePop();
452
- }
453
- });
454
- var action = Action.Pop;
455
-
456
- var _getIndexAndLocation6 = getIndexAndLocation(),
457
- index = _getIndexAndLocation6[0],
458
- location = _getIndexAndLocation6[1];
459
-
460
- var listeners = createEvents();
461
- var blockers = createEvents();
462
-
463
- if (index == null) {
464
- index = 0;
465
- globalHistory.replaceState(_extends$1({}, globalHistory.state, {
466
- idx: index
467
- }), '');
468
- }
469
-
470
- function getBaseHref() {
471
- var base = document.querySelector('base');
472
- var href = '';
473
-
474
- if (base && base.getAttribute('href')) {
475
- var url = window.location.href;
476
- var hashIndex = url.indexOf('#');
477
- href = hashIndex === -1 ? url : url.slice(0, hashIndex);
478
- }
479
-
480
- return href;
481
- }
482
-
483
- function createHref(to) {
484
- return getBaseHref() + '#' + (typeof to === 'string' ? to : createPath(to));
485
- }
486
-
487
- function getNextLocation(to, state) {
488
- if (state === void 0) {
489
- state = null;
490
- }
491
-
492
- return readOnly(_extends$1({
493
- pathname: location.pathname,
494
- hash: '',
495
- search: ''
496
- }, typeof to === 'string' ? parsePath(to) : to, {
497
- state: state,
498
- key: createKey()
499
- }));
500
- }
501
-
502
- function getHistoryStateAndUrl(nextLocation, index) {
503
- return [{
504
- usr: nextLocation.state,
505
- key: nextLocation.key,
506
- idx: index
507
- }, createHref(nextLocation)];
508
- }
509
-
510
- function allowTx(action, location, retry) {
511
- return !blockers.length || (blockers.call({
512
- action: action,
513
- location: location,
514
- retry: retry
515
- }), false);
516
- }
517
-
518
- function applyTx(nextAction) {
519
- action = nextAction;
520
-
521
- var _getIndexAndLocation7 = getIndexAndLocation();
522
-
523
- index = _getIndexAndLocation7[0];
524
- location = _getIndexAndLocation7[1];
525
- listeners.call({
526
- action: action,
527
- location: location
528
- });
42
+ static getDerivedStateFromError(error) {
43
+ return {
44
+ error
45
+ };
529
46
  }
530
-
531
- function push(to, state) {
532
- var nextAction = Action.Push;
533
- var nextLocation = getNextLocation(to, state);
534
-
535
- function retry() {
536
- push(to, state);
537
- }
538
-
539
- process.env.NODE_ENV !== "production" ? warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.push(" + JSON.stringify(to) + ")") : void 0;
540
-
541
- if (allowTx(nextAction, nextLocation, retry)) {
542
- var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1),
543
- historyState = _getHistoryStateAndUr3[0],
544
- url = _getHistoryStateAndUr3[1]; // TODO: Support forced reloading
545
- // try...catch because iOS limits us to 100 pushState calls :/
546
-
547
-
548
- try {
549
- globalHistory.pushState(historyState, '', url);
550
- } catch (error) {
551
- // They are going to lose state here, but there is no real
552
- // way to warn them about it since the page will refresh...
553
- window.location.assign(url);
554
- }
555
-
556
- applyTx(nextAction);
47
+ componentDidUpdate(prevProps, prevState) {
48
+ if (prevState.error && prevProps.resetKey !== this.props.resetKey) {
49
+ this.setState({
50
+ error: null
51
+ });
557
52
  }
558
53
  }
559
-
560
- function replace(to, state) {
561
- var nextAction = Action.Replace;
562
- var nextLocation = getNextLocation(to, state);
563
-
564
- function retry() {
565
- replace(to, state);
566
- }
567
-
568
- process.env.NODE_ENV !== "production" ? warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.replace(" + JSON.stringify(to) + ")") : void 0;
569
-
570
- if (allowTx(nextAction, nextLocation, retry)) {
571
- var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index),
572
- historyState = _getHistoryStateAndUr4[0],
573
- url = _getHistoryStateAndUr4[1]; // TODO: Support forced reloading
574
-
575
-
576
- globalHistory.replaceState(historyState, '', url);
577
- applyTx(nextAction);
578
- }
54
+ componentDidCatch(error) {
55
+ console.error(error);
56
+ this.props.onCatch?.(error);
579
57
  }
580
-
581
- function go(delta) {
582
- globalHistory.go(delta);
58
+ render() {
59
+ return this.props.children(this.state);
583
60
  }
584
-
585
- var history = {
586
- get action() {
587
- return action;
588
- },
589
-
590
- get location() {
591
- return location;
592
- },
593
-
594
- createHref: createHref,
595
- push: push,
596
- replace: replace,
597
- go: go,
598
- back: function back() {
599
- go(-1);
600
- },
601
- forward: function forward() {
602
- go(1);
603
- },
604
- listen: function listen(listener) {
605
- return listeners.push(listener);
606
- },
607
- block: function block(blocker) {
608
- var unblock = blockers.push(blocker);
609
-
610
- if (blockers.length === 1) {
611
- window.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
612
- }
613
-
614
- return function () {
615
- unblock(); // Remove the beforeunload listener so the document may
616
- // still be salvageable in the pagehide event.
617
- // See https://html.spec.whatwg.org/#unloading-documents
618
-
619
- if (!blockers.length) {
620
- window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
621
- }
622
- };
623
- }
624
- };
625
- return history;
626
61
  }
627
- /**
628
- * Memory history stores the current location in memory. It is designed for use
629
- * in stateful non-browser environments like tests and React Native.
630
- *
631
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#creatememoryhistory
632
- */
633
-
634
- function createMemoryHistory(options) {
635
- if (options === void 0) {
636
- options = {};
637
- }
638
-
639
- var _options3 = options,
640
- _options3$initialEntr = _options3.initialEntries,
641
- initialEntries = _options3$initialEntr === void 0 ? ['/'] : _options3$initialEntr,
642
- initialIndex = _options3.initialIndex;
643
- var entries = initialEntries.map(function (entry) {
644
- var location = readOnly(_extends$1({
645
- pathname: '/',
646
- search: '',
647
- hash: '',
648
- state: null,
649
- key: createKey()
650
- }, typeof entry === 'string' ? parsePath(entry) : entry));
651
- process.env.NODE_ENV !== "production" ? warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: " + JSON.stringify(entry) + ")") : void 0;
652
- return location;
653
- });
654
- var index = clamp(initialIndex == null ? entries.length - 1 : initialIndex, 0, entries.length - 1);
655
- var action = Action.Pop;
656
- var location = entries[index];
657
- var listeners = createEvents();
658
- var blockers = createEvents();
659
-
660
- function createHref(to) {
661
- return typeof to === 'string' ? to : createPath(to);
662
- }
663
-
664
- function getNextLocation(to, state) {
665
- if (state === void 0) {
666
- state = null;
667
- }
668
-
669
- return readOnly(_extends$1({
670
- pathname: location.pathname,
671
- search: '',
672
- hash: ''
673
- }, typeof to === 'string' ? parsePath(to) : to, {
674
- state: state,
675
- key: createKey()
676
- }));
677
- }
678
-
679
- function allowTx(action, location, retry) {
680
- return !blockers.length || (blockers.call({
681
- action: action,
682
- location: location,
683
- retry: retry
684
- }), false);
685
- }
686
-
687
- function applyTx(nextAction, nextLocation) {
688
- action = nextAction;
689
- location = nextLocation;
690
- listeners.call({
691
- action: action,
692
- location: location
693
- });
694
- }
695
-
696
- function push(to, state) {
697
- var nextAction = Action.Push;
698
- var nextLocation = getNextLocation(to, state);
699
-
700
- function retry() {
701
- push(to, state);
702
- }
703
-
704
- process.env.NODE_ENV !== "production" ? warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.push(" + JSON.stringify(to) + ")") : void 0;
705
-
706
- if (allowTx(nextAction, nextLocation, retry)) {
707
- index += 1;
708
- entries.splice(index, entries.length, nextLocation);
709
- applyTx(nextAction, nextLocation);
710
- }
711
- }
712
-
713
- function replace(to, state) {
714
- var nextAction = Action.Replace;
715
- var nextLocation = getNextLocation(to, state);
716
-
717
- function retry() {
718
- replace(to, state);
719
- }
720
-
721
- process.env.NODE_ENV !== "production" ? warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.replace(" + JSON.stringify(to) + ")") : void 0;
722
-
723
- if (allowTx(nextAction, nextLocation, retry)) {
724
- entries[index] = nextLocation;
725
- applyTx(nextAction, nextLocation);
62
+ function ErrorComponent({
63
+ error
64
+ }) {
65
+ const [show, setShow] = React.useState(process.env.NODE_ENV !== 'production');
66
+ return /*#__PURE__*/React.createElement("div", {
67
+ style: {
68
+ padding: '.5rem',
69
+ maxWidth: '100%'
726
70
  }
727
- }
728
-
729
- function go(delta) {
730
- var nextIndex = clamp(index + delta, 0, entries.length - 1);
731
- var nextAction = Action.Pop;
732
- var nextLocation = entries[nextIndex];
733
-
734
- function retry() {
735
- go(delta);
71
+ }, /*#__PURE__*/React.createElement("div", {
72
+ style: {
73
+ display: 'flex',
74
+ alignItems: 'center',
75
+ gap: '.5rem'
736
76
  }
737
-
738
- if (allowTx(nextAction, nextLocation, retry)) {
739
- index = nextIndex;
740
- applyTx(nextAction, nextLocation);
77
+ }, /*#__PURE__*/React.createElement("strong", {
78
+ style: {
79
+ fontSize: '1rem'
741
80
  }
742
- }
743
-
744
- var history = {
745
- get index() {
746
- return index;
747
- },
748
-
749
- get action() {
750
- return action;
751
- },
752
-
753
- get location() {
754
- return location;
755
- },
756
-
757
- createHref: createHref,
758
- push: push,
759
- replace: replace,
760
- go: go,
761
- back: function back() {
762
- go(-1);
763
- },
764
- forward: function forward() {
765
- go(1);
766
- },
767
- listen: function listen(listener) {
768
- return listeners.push(listener);
81
+ }, "Something went wrong!"), /*#__PURE__*/React.createElement("button", {
82
+ style: {
83
+ appearance: 'none',
84
+ fontSize: '.6em',
85
+ border: '1px solid currentColor',
86
+ padding: '.1rem .2rem',
87
+ fontWeight: 'bold',
88
+ borderRadius: '.25rem'
769
89
  },
770
- block: function block(blocker) {
771
- return blockers.push(blocker);
90
+ onClick: () => setShow(d => !d)
91
+ }, show ? 'Hide Error' : 'Show Error')), /*#__PURE__*/React.createElement("div", {
92
+ style: {
93
+ height: '.25rem'
772
94
  }
773
- };
774
- return history;
775
- } ////////////////////////////////////////////////////////////////////////////////
776
- // UTILS
777
- ////////////////////////////////////////////////////////////////////////////////
778
-
779
- function clamp(n, lowerBound, upperBound) {
780
- return Math.min(Math.max(n, lowerBound), upperBound);
95
+ }), show ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("pre", {
96
+ style: {
97
+ fontSize: '.7em',
98
+ border: '1px solid red',
99
+ borderRadius: '.25rem',
100
+ padding: '.3rem',
101
+ color: 'red',
102
+ overflow: 'auto'
103
+ }
104
+ }, error.message ? /*#__PURE__*/React.createElement("code", null, error.message) : null)) : null);
781
105
  }
782
106
 
783
- function promptBeforeUnload(event) {
784
- // Cancel the event.
785
- event.preventDefault(); // Chrome (and legacy IE) requires returnValue to be set.
107
+ // export type Expand<T> = T
108
+
109
+ // type Compute<T> = { [K in keyof T]: T[K] } | never
110
+
111
+ // type AllKeys<T> = T extends any ? keyof T : never
112
+
113
+ // export type MergeUnion<T, Keys extends keyof T = keyof T> = Compute<
114
+ // {
115
+ // [K in Keys]: T[Keys]
116
+ // } & {
117
+ // [K in AllKeys<T>]?: T extends any
118
+ // ? K extends keyof T
119
+ // ? T[K]
120
+ // : never
121
+ // : never
122
+ // }
123
+ // >
124
+
125
+ // // Sample types to merge
126
+ // type TypeA = {
127
+ // shared: string
128
+ // onlyInA: string
129
+ // nested: {
130
+ // shared: string
131
+ // aProp: string
132
+ // }
133
+ // array: string[]
134
+ // }
135
+
136
+ // type TypeB = {
137
+ // shared: number
138
+ // onlyInB: number
139
+ // nested: {
140
+ // shared: number
141
+ // bProp: number
142
+ // }
143
+ // array: number[]
144
+ // }
145
+
146
+ // type TypeC = {
147
+ // shared: boolean
148
+ // onlyInC: boolean
149
+ // nested: {
150
+ // shared: boolean
151
+ // cProp: boolean
152
+ // }
153
+ // array: boolean[]
154
+ // }
155
+
156
+ // type Test = Expand<Assign<TypeA, TypeB>>
157
+
158
+ // // Using DeepMerge to merge TypeA and TypeB
159
+ // type MergedType = Expand<AssignAll<[TypeA, TypeB, TypeC]>>
786
160
 
787
- event.returnValue = '';
788
- }
789
-
790
- function createEvents() {
791
- var handlers = [];
792
- return {
793
- get length() {
794
- return handlers.length;
795
- },
161
+ //
796
162
 
797
- push: function push(fn) {
798
- handlers.push(fn);
799
- return function () {
800
- handlers = handlers.filter(function (handler) {
801
- return handler !== fn;
802
- });
803
- };
804
- },
805
- call: function call(arg) {
806
- handlers.forEach(function (fn) {
807
- return fn && fn(arg);
808
- });
809
- }
810
- };
163
+ const isServer = typeof document === 'undefined';
164
+ function last(arr) {
165
+ return arr[arr.length - 1];
811
166
  }
812
-
813
- function createKey() {
814
- return Math.random().toString(36).substr(2, 8);
167
+ function isFunction(d) {
168
+ return typeof d === 'function';
815
169
  }
816
- /**
817
- * Creates a string URL path from the given pathname, search, and hash components.
818
- *
819
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createpath
820
- */
821
-
822
-
823
- function createPath(_ref) {
824
- var _ref$pathname = _ref.pathname,
825
- pathname = _ref$pathname === void 0 ? '/' : _ref$pathname,
826
- _ref$search = _ref.search,
827
- search = _ref$search === void 0 ? '' : _ref$search,
828
- _ref$hash = _ref.hash,
829
- hash = _ref$hash === void 0 ? '' : _ref$hash;
830
- if (search && search !== '?') pathname += search.charAt(0) === '?' ? search : '?' + search;
831
- if (hash && hash !== '#') pathname += hash.charAt(0) === '#' ? hash : '#' + hash;
832
- return pathname;
833
- }
834
- /**
835
- * Parses a string URL path into its separate pathname, search, and hash components.
836
- *
837
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#parsepath
838
- */
839
-
840
- function parsePath(path) {
841
- var parsedPath = {};
842
-
843
- if (path) {
844
- var hashIndex = path.indexOf('#');
845
-
846
- if (hashIndex >= 0) {
847
- parsedPath.hash = path.substr(hashIndex);
848
- path = path.substr(0, hashIndex);
849
- }
850
-
851
- var searchIndex = path.indexOf('?');
852
-
853
- if (searchIndex >= 0) {
854
- parsedPath.search = path.substr(searchIndex);
855
- path = path.substr(0, searchIndex);
856
- }
857
-
858
- if (path) {
859
- parsedPath.pathname = path;
860
- }
170
+ function functionalUpdate(updater, previous) {
171
+ if (isFunction(updater)) {
172
+ return updater(previous);
861
173
  }
862
-
863
- return parsedPath;
174
+ return updater;
864
175
  }
865
-
866
- var isProduction = process.env.NODE_ENV === 'production';
867
- var prefix = 'Invariant failed';
868
- function invariant(condition, message) {
869
- if (condition) {
870
- return;
871
- }
872
- if (isProduction) {
873
- throw new Error(prefix);
874
- }
875
- var provided = typeof message === 'function' ? message() : message;
876
- var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
877
- throw new Error(value);
176
+ function pick(parent, keys) {
177
+ return keys.reduce((obj, key) => {
178
+ obj[key] = parent[key];
179
+ return obj;
180
+ }, {});
878
181
  }
879
182
 
880
183
  /**
881
184
  * This function returns `a` if `b` is deeply equal.
882
185
  * If not, it will replace any deeply equal children of `b` with those of `a`.
883
- * This can be used for structural sharing between JSON values for example.
186
+ * This can be used for structural sharing between immutable JSON values for example.
187
+ * Do not use this with signals
884
188
  */
885
- function replaceEqualDeep(prev, next) {
886
- if (prev === next) {
189
+ function replaceEqualDeep(prev, _next) {
190
+ if (prev === _next) {
887
191
  return prev;
888
192
  }
889
-
193
+ const next = _next;
890
194
  const array = Array.isArray(prev) && Array.isArray(next);
891
-
892
195
  if (array || isPlainObject(prev) && isPlainObject(next)) {
893
- const aSize = array ? prev.length : Object.keys(prev).length;
894
- const bItems = array ? next : Object.keys(next);
895
- const bSize = bItems.length;
196
+ const prevSize = array ? prev.length : Object.keys(prev).length;
197
+ const nextItems = array ? next : Object.keys(next);
198
+ const nextSize = nextItems.length;
896
199
  const copy = array ? [] : {};
897
200
  let equalItems = 0;
898
-
899
- for (let i = 0; i < bSize; i++) {
900
- const key = array ? i : bItems[i];
201
+ for (let i = 0; i < nextSize; i++) {
202
+ const key = array ? i : nextItems[i];
901
203
  copy[key] = replaceEqualDeep(prev[key], next[key]);
902
-
903
204
  if (copy[key] === prev[key]) {
904
205
  equalItems++;
905
206
  }
906
207
  }
907
-
908
- return aSize === bSize && equalItems === aSize ? prev : copy;
208
+ return prevSize === nextSize && equalItems === prevSize ? prev : copy;
909
209
  }
910
-
911
210
  return next;
912
- } // Copied from: https://github.com/jonschlinkert/is-plain-object
211
+ }
913
212
 
213
+ // Copied from: https://github.com/jonschlinkert/is-plain-object
914
214
  function isPlainObject(o) {
915
215
  if (!hasObjectPrototype(o)) {
916
216
  return false;
917
- } // If has modified constructor
918
-
217
+ }
919
218
 
219
+ // If has modified constructor
920
220
  const ctor = o.constructor;
921
-
922
221
  if (typeof ctor === 'undefined') {
923
222
  return true;
924
- } // If has modified prototype
925
-
223
+ }
926
224
 
225
+ // If has modified prototype
927
226
  const prot = ctor.prototype;
928
-
929
227
  if (!hasObjectPrototype(prot)) {
930
228
  return false;
931
- } // If constructor does not have an Object-specific method
932
-
229
+ }
933
230
 
231
+ // If constructor does not have an Object-specific method
934
232
  if (!prot.hasOwnProperty('isPrototypeOf')) {
935
233
  return false;
936
- } // Most likely a plain Object
937
-
938
-
939
- return true;
940
- }
941
-
942
- function hasObjectPrototype(o) {
943
- return Object.prototype.toString.call(o) === '[object Object]';
944
- }
945
-
946
- function last(arr) {
947
- return arr[arr.length - 1];
948
- }
949
- function warning(cond, message) {
950
- if (cond) {
951
- if (typeof console !== 'undefined') console.warn(message);
952
-
953
- try {
954
- throw new Error(message);
955
- } catch (_unused) {}
956
234
  }
957
235
 
236
+ // Most likely a plain Object
958
237
  return true;
959
238
  }
960
-
961
- function isFunction(d) {
962
- return typeof d === 'function';
239
+ function hasObjectPrototype(o) {
240
+ return Object.prototype.toString.call(o) === '[object Object]';
963
241
  }
964
-
965
- function functionalUpdate(updater, previous) {
966
- if (isFunction(updater)) {
967
- return updater(previous);
242
+ function deepEqual(a, b, partial = false) {
243
+ if (a === b) {
244
+ return true;
968
245
  }
969
-
970
- return updater;
246
+ if (typeof a !== typeof b) {
247
+ return false;
248
+ }
249
+ if (isPlainObject(a) && isPlainObject(b)) {
250
+ const aKeys = Object.keys(a);
251
+ const bKeys = Object.keys(b);
252
+ if (!partial && aKeys.length !== bKeys.length) {
253
+ return false;
254
+ }
255
+ return !bKeys.some(key => !(key in a) || !deepEqual(a[key], b[key], partial));
256
+ }
257
+ if (Array.isArray(a) && Array.isArray(b)) {
258
+ return !a.some((item, index) => !deepEqual(item, b[index], partial));
259
+ }
260
+ return false;
971
261
  }
972
- function pick(parent, keys) {
973
- return keys.reduce((obj, key) => {
974
- obj[key] = parent[key];
975
- return obj;
976
- }, {});
262
+ function useStableCallback(fn) {
263
+ const fnRef = React.useRef(fn);
264
+ fnRef.current = fn;
265
+ const ref = React.useRef((...args) => fnRef.current(...args));
266
+ return ref.current;
267
+ }
268
+ function shallow(objA, objB) {
269
+ if (Object.is(objA, objB)) {
270
+ return true;
271
+ }
272
+ if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
273
+ return false;
274
+ }
275
+ const keysA = Object.keys(objA);
276
+ if (keysA.length !== Object.keys(objB).length) {
277
+ return false;
278
+ }
279
+ for (let i = 0; i < keysA.length; i++) {
280
+ if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
281
+ return false;
282
+ }
283
+ }
284
+ return true;
285
+ }
286
+ function useRouteContext(opts) {
287
+ return useMatch({
288
+ ...opts,
289
+ select: match => opts?.select ? opts.select(match.context) : match.context
290
+ });
291
+ }
292
+ const useLayoutEffect$1 = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
293
+ function escapeJSON(jsonString) {
294
+ return jsonString.replace(/\\/g, '\\\\') // Escape backslashes
295
+ .replace(/'/g, "\\'") // Escape single quotes
296
+ .replace(/"/g, '\\"'); // Escape double quotes
977
297
  }
978
298
 
979
299
  function joinPaths(paths) {
@@ -993,8 +313,8 @@ function trimPath(path) {
993
313
  return trimPathRight(trimPathLeft(path));
994
314
  }
995
315
  function resolvePath(basepath, base, to) {
996
- base = base.replace(new RegExp("^" + basepath), '/');
997
- to = to.replace(new RegExp("^" + basepath), '/');
316
+ base = base.replace(new RegExp(`^${basepath}`), '/');
317
+ to = to.replace(new RegExp(`^${basepath}`), '/');
998
318
  let baseSegments = parsePathname(base);
999
319
  const toSegments = parsePathname(to);
1000
320
  toSegments.forEach((toSegment, index) => {
@@ -1007,13 +327,10 @@ function resolvePath(basepath, base, to) {
1007
327
  baseSegments.push(toSegment);
1008
328
  } else ;
1009
329
  } else if (toSegment.value === '..') {
1010
- var _last;
1011
-
1012
330
  // Extra trailing slash? pop it off
1013
- if (baseSegments.length > 1 && ((_last = last(baseSegments)) == null ? void 0 : _last.value) === '/') {
331
+ if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {
1014
332
  baseSegments.pop();
1015
333
  }
1016
-
1017
334
  baseSegments.pop();
1018
335
  } else if (toSegment.value === '.') {
1019
336
  return;
@@ -1028,10 +345,8 @@ function parsePathname(pathname) {
1028
345
  if (!pathname) {
1029
346
  return [];
1030
347
  }
1031
-
1032
348
  pathname = cleanPath(pathname);
1033
349
  const segments = [];
1034
-
1035
350
  if (pathname.slice(0, 1) === '/') {
1036
351
  pathname = pathname.substring(1);
1037
352
  segments.push({
@@ -1039,34 +354,30 @@ function parsePathname(pathname) {
1039
354
  value: '/'
1040
355
  });
1041
356
  }
1042
-
1043
357
  if (!pathname) {
1044
358
  return segments;
1045
- } // Remove empty segments and '.' segments
1046
-
359
+ }
1047
360
 
361
+ // Remove empty segments and '.' segments
1048
362
  const split = pathname.split('/').filter(Boolean);
1049
363
  segments.push(...split.map(part => {
1050
- if (part.startsWith('*')) {
364
+ if (part === '$' || part === '*') {
1051
365
  return {
1052
366
  type: 'wildcard',
1053
367
  value: part
1054
368
  };
1055
369
  }
1056
-
1057
- if (part.charAt(0) === ':') {
370
+ if (part.charAt(0) === '$') {
1058
371
  return {
1059
372
  type: 'param',
1060
373
  value: part
1061
374
  };
1062
375
  }
1063
-
1064
376
  return {
1065
377
  type: 'pathname',
1066
378
  value: part
1067
379
  };
1068
380
  }));
1069
-
1070
381
  if (pathname.slice(-1) === '/') {
1071
382
  pathname = pathname.substring(1);
1072
383
  segments.push({
@@ -1074,63 +385,70 @@ function parsePathname(pathname) {
1074
385
  value: '/'
1075
386
  });
1076
387
  }
1077
-
1078
388
  return segments;
1079
389
  }
1080
- function interpolatePath(path, params, leaveWildcard) {
390
+ function interpolatePath(path, params, leaveWildcards = false) {
1081
391
  const interpolatedPathSegments = parsePathname(path);
1082
392
  return joinPaths(interpolatedPathSegments.map(segment => {
1083
- if (segment.value === '*' && !leaveWildcard) {
1084
- return '';
393
+ if (segment.type === 'wildcard') {
394
+ const value = params[segment.value];
395
+ if (leaveWildcards) return `${segment.value}${value ?? ''}`;
396
+ return value;
1085
397
  }
1086
-
1087
398
  if (segment.type === 'param') {
1088
- var _segment$value$substr;
1089
-
1090
- return (_segment$value$substr = params[segment.value.substring(1)]) != null ? _segment$value$substr : '';
399
+ return params[segment.value.substring(1)] ?? '';
1091
400
  }
1092
-
1093
401
  return segment.value;
1094
402
  }));
1095
403
  }
1096
- function matchPathname(currentPathname, matchLocation) {
1097
- const pathParams = matchByPath(currentPathname, matchLocation); // const searchMatched = matchBySearch(currentLocation.search, matchLocation)
404
+ function matchPathname(basepath, currentPathname, matchLocation) {
405
+ const pathParams = matchByPath(basepath, currentPathname, matchLocation);
406
+ // const searchMatched = matchBySearch(location.search, matchLocation)
1098
407
 
1099
408
  if (matchLocation.to && !pathParams) {
1100
409
  return;
1101
410
  }
1102
-
1103
- return pathParams != null ? pathParams : {};
411
+ return pathParams ?? {};
1104
412
  }
1105
- function matchByPath(from, matchLocation) {
1106
- var _matchLocation$to;
1107
-
413
+ function matchByPath(basepath, from, matchLocation) {
414
+ // Remove the base path from the pathname
415
+ from = basepath != '/' ? from.substring(basepath.length) : from;
416
+ // Default to to $ (wildcard)
417
+ const to = `${matchLocation.to ?? '$'}`;
418
+ // Parse the from and to
1108
419
  const baseSegments = parsePathname(from);
1109
- const routeSegments = parsePathname("" + ((_matchLocation$to = matchLocation.to) != null ? _matchLocation$to : '*'));
420
+ const routeSegments = parsePathname(to);
421
+ if (!from.startsWith('/')) {
422
+ baseSegments.unshift({
423
+ type: 'pathname',
424
+ value: '/'
425
+ });
426
+ }
427
+ if (!to.startsWith('/')) {
428
+ routeSegments.unshift({
429
+ type: 'pathname',
430
+ value: '/'
431
+ });
432
+ }
1110
433
  const params = {};
1111
-
1112
434
  let isMatch = (() => {
1113
435
  for (let i = 0; i < Math.max(baseSegments.length, routeSegments.length); i++) {
1114
436
  const baseSegment = baseSegments[i];
1115
437
  const routeSegment = routeSegments[i];
1116
- const isLastRouteSegment = i === routeSegments.length - 1;
1117
- const isLastBaseSegment = i === baseSegments.length - 1;
1118
-
438
+ const isLastBaseSegment = i >= baseSegments.length - 1;
439
+ const isLastRouteSegment = i >= routeSegments.length - 1;
1119
440
  if (routeSegment) {
1120
441
  if (routeSegment.type === 'wildcard') {
1121
- if (baseSegment != null && baseSegment.value) {
442
+ if (baseSegment?.value) {
1122
443
  params['*'] = joinPaths(baseSegments.slice(i).map(d => d.value));
1123
444
  return true;
1124
445
  }
1125
-
1126
446
  return false;
1127
447
  }
1128
-
1129
448
  if (routeSegment.type === 'pathname') {
1130
- if (routeSegment.value === '/' && !(baseSegment != null && baseSegment.value)) {
449
+ if (routeSegment.value === '/' && !baseSegment?.value) {
1131
450
  return true;
1132
451
  }
1133
-
1134
452
  if (baseSegment) {
1135
453
  if (matchLocation.caseSensitive) {
1136
454
  if (routeSegment.value !== baseSegment.value) {
@@ -1141,41 +459,664 @@ function matchByPath(from, matchLocation) {
1141
459
  }
1142
460
  }
1143
461
  }
1144
-
1145
462
  if (!baseSegment) {
1146
463
  return false;
1147
464
  }
1148
-
1149
465
  if (routeSegment.type === 'param') {
1150
- if ((baseSegment == null ? void 0 : baseSegment.value) === '/') {
466
+ if (baseSegment?.value === '/') {
1151
467
  return false;
1152
468
  }
1153
-
1154
- if (!baseSegment.value.startsWith(':')) {
469
+ if (baseSegment.value.charAt(0) !== '$') {
1155
470
  params[routeSegment.value.substring(1)] = baseSegment.value;
1156
471
  }
1157
472
  }
1158
473
  }
1159
-
1160
- if (isLastRouteSegment && !isLastBaseSegment) {
474
+ if (!isLastBaseSegment && isLastRouteSegment) {
1161
475
  return !!matchLocation.fuzzy;
1162
476
  }
1163
477
  }
1164
-
1165
478
  return true;
1166
479
  })();
1167
-
1168
480
  return isMatch ? params : undefined;
1169
481
  }
1170
482
 
483
+ function useParams(opts) {
484
+ return useRouterState({
485
+ select: state => {
486
+ const params = last(state.matches)?.params;
487
+ return opts?.select ? opts.select(params) : params;
488
+ }
489
+ });
490
+ }
491
+
492
+ function useSearch(opts) {
493
+ return useMatch({
494
+ ...opts,
495
+ select: match => {
496
+ return opts?.select ? opts.select(match.search) : match.search;
497
+ }
498
+ });
499
+ }
500
+
501
+ const rootRouteId = '__root__';
502
+
503
+ // The parse type here allows a zod schema to be passed directly to the validator
504
+
505
+ class Route {
506
+ // Set up in this.init()
507
+
508
+ // customId!: TCustomId
509
+
510
+ // Optional
511
+
512
+ constructor(options) {
513
+ this.options = options || {};
514
+ this.isRoot = !options?.getParentRoute;
515
+ Route.__onInit(this);
516
+ this.$$typeof = Symbol.for('react.memo');
517
+ }
518
+ init = opts => {
519
+ this.originalIndex = opts.originalIndex;
520
+ const options = this.options;
521
+ const isRoot = !options?.path && !options?.id;
522
+ this.parentRoute = this.options?.getParentRoute?.();
523
+ if (isRoot) {
524
+ this.path = rootRouteId;
525
+ } else {
526
+ invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
527
+ }
528
+ let path = isRoot ? rootRouteId : options.path;
529
+
530
+ // If the path is anything other than an index path, trim it up
531
+ if (path && path !== '/') {
532
+ path = trimPath(path);
533
+ }
534
+ const customId = options?.id || path;
535
+
536
+ // Strip the parentId prefix from the first level of children
537
+ let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
538
+ if (path === rootRouteId) {
539
+ path = '/';
540
+ }
541
+ if (id !== rootRouteId) {
542
+ id = joinPaths(['/', id]);
543
+ }
544
+ const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
545
+ this.path = path;
546
+ this.id = id;
547
+ // this.customId = customId as TCustomId
548
+ this.fullPath = fullPath;
549
+ this.to = fullPath;
550
+ };
551
+ addChildren = children => {
552
+ this.children = children;
553
+ return this;
554
+ };
555
+ update = options => {
556
+ Object.assign(this.options, options);
557
+ return this;
558
+ };
559
+ static __onInit = route => {
560
+ // This is a dummy static method that should get
561
+ // replaced by a framework specific implementation if necessary
562
+ };
563
+ useMatch = opts => {
564
+ return useMatch({
565
+ ...opts,
566
+ from: this.id
567
+ });
568
+ };
569
+ useRouteContext = opts => {
570
+ return useMatch({
571
+ ...opts,
572
+ from: this.id,
573
+ select: d => opts?.select ? opts.select(d.context) : d.context
574
+ });
575
+ };
576
+ useSearch = opts => {
577
+ return useSearch({
578
+ ...opts,
579
+ from: this.id
580
+ });
581
+ };
582
+ useParams = opts => {
583
+ return useParams({
584
+ ...opts,
585
+ from: this.id
586
+ });
587
+ };
588
+ useLoaderData = opts => {
589
+ return useLoaderData({
590
+ ...opts,
591
+ from: this.id
592
+ });
593
+ };
594
+ }
595
+ function rootRouteWithContext() {
596
+ return options => {
597
+ return new RootRoute(options);
598
+ };
599
+ }
600
+ class RootRoute extends Route {
601
+ constructor(options) {
602
+ super(options);
603
+ }
604
+ }
605
+ function createRouteMask(opts) {
606
+ return opts;
607
+ }
608
+
609
+ //
610
+
611
+ function Matches() {
612
+ const router = useRouter();
613
+ const routerState = useRouterState();
614
+ const matches = routerState.pendingMatches?.some(d => d.showPending) ? routerState.pendingMatches : routerState.matches;
615
+ const locationKey = routerState.resolvedLocation.state.key;
616
+ const route = router.routesById[rootRouteId];
617
+ const errorComponent = React.useCallback(props => {
618
+ return /*#__PURE__*/React.createElement(ErrorComponent, {
619
+ ...props,
620
+ useMatch: route.useMatch,
621
+ useRouteContext: route.useRouteContext,
622
+ useSearch: route.useSearch,
623
+ useParams: route.useParams
624
+ });
625
+ }, [route]);
626
+ return /*#__PURE__*/React.createElement(matchesContext.Provider, {
627
+ value: matches
628
+ }, /*#__PURE__*/React.createElement(CatchBoundary, {
629
+ resetKey: locationKey,
630
+ errorComponent: errorComponent,
631
+ onCatch: () => {
632
+ warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
633
+ }
634
+ }, matches.length ? /*#__PURE__*/React.createElement(Match, {
635
+ matches: matches
636
+ }) : null));
637
+ }
638
+ function SafeFragment(props) {
639
+ return /*#__PURE__*/React.createElement(React.Fragment, null, props.children);
640
+ }
641
+ function Match({
642
+ matches
643
+ }) {
644
+ const {
645
+ options,
646
+ routesById
647
+ } = useRouter();
648
+ const match = matches[0];
649
+ const routeId = match?.routeId;
650
+ const route = routesById[routeId];
651
+ useRouter();
652
+ const locationKey = useRouterState().resolvedLocation.state?.key;
653
+ const PendingComponent = route.options.pendingComponent ?? options.defaultPendingComponent;
654
+ const pendingElement = PendingComponent ? /*#__PURE__*/React.createElement(PendingComponent, {
655
+ useMatch: route.useMatch,
656
+ useRouteContext: route.useRouteContext,
657
+ useSearch: route.useSearch,
658
+ useParams: route.useParams
659
+ }) : undefined;
660
+ const routeErrorComponent = route.options.errorComponent ?? options.defaultErrorComponent ?? ErrorComponent;
661
+ const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? pendingElement ? React.Suspense : SafeFragment;
662
+ const errorComponent = routeErrorComponent ? React.useCallback(props => {
663
+ return /*#__PURE__*/React.createElement(routeErrorComponent, {
664
+ ...props,
665
+ useMatch: route.useMatch,
666
+ useRouteContext: route.useRouteContext,
667
+ useSearch: route.useSearch,
668
+ useParams: route.useParams
669
+ });
670
+ }, [route]) : undefined;
671
+ const ResolvedCatchBoundary = errorComponent ? CatchBoundary : SafeFragment;
672
+ return /*#__PURE__*/React.createElement(matchesContext.Provider, {
673
+ value: matches
674
+ }, /*#__PURE__*/React.createElement(ResolvedSuspenseBoundary, {
675
+ fallback: pendingElement
676
+ }, /*#__PURE__*/React.createElement(ResolvedCatchBoundary, {
677
+ resetKey: locationKey,
678
+ errorComponent: errorComponent,
679
+ onCatch: () => {
680
+ warning(false, `Error in route match: ${match.id}`);
681
+ }
682
+ }, /*#__PURE__*/React.createElement(MatchInner, {
683
+ match: match,
684
+ pendingElement: pendingElement
685
+ }))));
686
+ }
687
+ function MatchInner({
688
+ match,
689
+ pendingElement
690
+ }) {
691
+ const {
692
+ options,
693
+ routesById
694
+ } = useRouter();
695
+ const route = routesById[match.routeId];
696
+ if (match.status === 'error') {
697
+ throw match.error;
698
+ }
699
+ if (match.status === 'pending') {
700
+ if (match.showPending) {
701
+ return pendingElement || null;
702
+ }
703
+ throw match.loadPromise;
704
+ }
705
+ if (match.status === 'success') {
706
+ let comp = route.options.component ?? options.defaultComponent;
707
+ if (comp) {
708
+ return /*#__PURE__*/React.createElement(comp, {
709
+ useMatch: route.useMatch,
710
+ useRouteContext: route.useRouteContext,
711
+ useSearch: route.useSearch,
712
+ useParams: route.useParams,
713
+ useLoaderData: route.useLoaderData
714
+ });
715
+ }
716
+ return /*#__PURE__*/React.createElement(Outlet, null);
717
+ }
718
+ invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
719
+ }
720
+ function Outlet() {
721
+ const matches = React.useContext(matchesContext).slice(1);
722
+ if (!matches[0]) {
723
+ return null;
724
+ }
725
+ return /*#__PURE__*/React.createElement(Match, {
726
+ matches: matches
727
+ });
728
+ }
729
+ function useMatchRoute() {
730
+ const {
731
+ matchRoute
732
+ } = useRouter();
733
+ return React.useCallback(opts => {
734
+ const {
735
+ pending,
736
+ caseSensitive,
737
+ ...rest
738
+ } = opts;
739
+ return matchRoute(rest, {
740
+ pending,
741
+ caseSensitive
742
+ });
743
+ }, []);
744
+ }
745
+ function MatchRoute(props) {
746
+ const matchRoute = useMatchRoute();
747
+ const params = matchRoute(props);
748
+ if (typeof props.children === 'function') {
749
+ return props.children(params);
750
+ }
751
+ return !!params ? props.children : null;
752
+ }
753
+ function useMatch(opts) {
754
+ const nearestMatch = React.useContext(matchesContext)[0];
755
+ const nearestMatchRouteId = nearestMatch?.routeId;
756
+ const matchRouteId = useRouterState({
757
+ select: state => {
758
+ const matches = state.pendingMatches?.some(d => d.showPending) ? state.pendingMatches : state.matches;
759
+ const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatch.id);
760
+ return match.routeId;
761
+ }
762
+ });
763
+ if (opts?.strict ?? true) {
764
+ invariant(nearestMatchRouteId == matchRouteId, `useMatch("${matchRouteId}") is being called in a component that is meant to render the '${nearestMatchRouteId}' route. Did you mean to 'useMatch("${matchRouteId}", { strict: false })' or 'useRoute("${matchRouteId}")' instead?`);
765
+ }
766
+ const matchSelection = useRouterState({
767
+ select: state => {
768
+ const matches = state.pendingMatches?.some(d => d.showPending) ? state.pendingMatches : state.matches;
769
+ const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatch.id);
770
+ invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
771
+ return opts?.select ? opts.select(match) : match;
772
+ }
773
+ });
774
+ return matchSelection;
775
+ }
776
+ const matchesContext = /*#__PURE__*/React.createContext(null);
777
+ function useMatches(opts) {
778
+ const contextMatches = React.useContext(matchesContext);
779
+ return useRouterState({
780
+ select: state => {
781
+ let matches = state.pendingMatches?.some(d => d.showPending) ? state.pendingMatches : state.matches;
782
+ matches = matches.slice(matches.findIndex(d => d.id === contextMatches[0]?.id));
783
+ return opts?.select ? opts.select(matches) : matches;
784
+ }
785
+ });
786
+ }
787
+ function useLoaderData(opts) {
788
+ const match = useMatch({
789
+ ...opts,
790
+ select: undefined
791
+ });
792
+ return typeof opts.select === 'function' ? opts.select(match?.loaderData) : match?.loaderData;
793
+ }
794
+
795
+ const routerContext = /*#__PURE__*/React.createContext(null);
796
+ if (typeof document !== 'undefined') {
797
+ window.__TSR_ROUTER_CONTEXT__ = routerContext;
798
+ }
799
+ function RouterProvider({
800
+ router,
801
+ ...rest
802
+ }) {
803
+ // Allow the router to update options on the router instance
804
+ router.update({
805
+ ...router.options,
806
+ ...rest,
807
+ context: {
808
+ ...router.options.context,
809
+ ...rest?.context
810
+ }
811
+ });
812
+ const inner = /*#__PURE__*/React.createElement(routerContext.Provider, {
813
+ value: router
814
+ }, /*#__PURE__*/React.createElement(Matches, null), /*#__PURE__*/React.createElement(Transitioner, null));
815
+ if (router.options.Wrap) {
816
+ return /*#__PURE__*/React.createElement(router.options.Wrap, null, inner);
817
+ }
818
+ return inner;
819
+ }
820
+ function Transitioner() {
821
+ const router = useRouter();
822
+ const routerState = useRouterState({
823
+ select: s => pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning'])
824
+ });
825
+ const [isTransitioning, startReactTransition] = React.useTransition();
826
+ router.startReactTransition = startReactTransition;
827
+ React.useEffect(() => {
828
+ if (isTransitioning) {
829
+ router.__store.setState(s => ({
830
+ ...s,
831
+ isTransitioning
832
+ }));
833
+ }
834
+ }, [isTransitioning]);
835
+ const tryLoad = () => {
836
+ const apply = cb => {
837
+ if (!routerState.isTransitioning) {
838
+ startReactTransition(() => cb());
839
+ } else {
840
+ cb();
841
+ }
842
+ };
843
+ apply(() => {
844
+ try {
845
+ router.load();
846
+ } catch (err) {
847
+ console.error(err);
848
+ }
849
+ });
850
+ };
851
+ useLayoutEffect$1(() => {
852
+ const unsub = router.history.subscribe(() => {
853
+ router.latestLocation = router.parseLocation(router.latestLocation);
854
+ if (routerState.location !== router.latestLocation) {
855
+ tryLoad();
856
+ }
857
+ });
858
+ const nextLocation = router.buildLocation({
859
+ search: true,
860
+ params: true,
861
+ hash: true,
862
+ state: true
863
+ });
864
+ if (routerState.location.href !== nextLocation.href) {
865
+ router.commitLocation({
866
+ ...nextLocation,
867
+ replace: true
868
+ });
869
+ }
870
+ return () => {
871
+ unsub();
872
+ };
873
+ }, [router.history]);
874
+ useLayoutEffect$1(() => {
875
+ if (routerState.isTransitioning && !isTransitioning && !routerState.isLoading && routerState.resolvedLocation !== routerState.location) {
876
+ router.emit({
877
+ type: 'onResolved',
878
+ fromLocation: routerState.resolvedLocation,
879
+ toLocation: routerState.location,
880
+ pathChanged: routerState.location.href !== routerState.resolvedLocation?.href
881
+ });
882
+ router.pendingMatches = [];
883
+ router.__store.setState(s => ({
884
+ ...s,
885
+ isTransitioning: false,
886
+ resolvedLocation: s.location
887
+ }));
888
+ }
889
+ }, [routerState.isTransitioning, isTransitioning, routerState.isLoading, routerState.resolvedLocation, routerState.location]);
890
+ useLayoutEffect$1(() => {
891
+ if (!window.__TSR_DEHYDRATED__) {
892
+ tryLoad();
893
+ }
894
+ }, []);
895
+ return null;
896
+ }
897
+ function getRouteMatch(state, id) {
898
+ return [...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
899
+ }
900
+ function useRouterState(opts) {
901
+ const router = useRouter();
902
+ return useStore(router.__store, opts?.select);
903
+ }
904
+ function useRouter() {
905
+ const resolvedContext = typeof document !== 'undefined' ? window.__TSR_ROUTER_CONTEXT__ || routerContext : routerContext;
906
+ const value = React.useContext(resolvedContext);
907
+ warning(value, 'useRouter must be used inside a <RouterProvider> component!');
908
+ return value;
909
+ }
910
+
911
+ function defer(_promise) {
912
+ const promise = _promise;
913
+ if (!promise.__deferredState) {
914
+ promise.__deferredState = {
915
+ uid: Math.random().toString(36).slice(2),
916
+ status: 'pending'
917
+ };
918
+ const state = promise.__deferredState;
919
+ promise.then(data => {
920
+ state.status = 'success';
921
+ state.data = data;
922
+ }).catch(error => {
923
+ state.status = 'error';
924
+ state.error = error;
925
+ });
926
+ }
927
+ return promise;
928
+ }
929
+ function isDehydratedDeferred(obj) {
930
+ return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
931
+ }
932
+
933
+ function useAwaited({
934
+ promise
935
+ }) {
936
+ const router = useRouter();
937
+ let state = promise.__deferredState;
938
+ const key = `__TSR__DEFERRED__${state.uid}`;
939
+ if (isDehydratedDeferred(promise)) {
940
+ state = router.hydrateData(key);
941
+ promise = Promise.resolve(state.data);
942
+ promise.__deferredState = state;
943
+ }
944
+ if (state.status === 'pending') {
945
+ throw new Promise(r => setTimeout(r, 1)).then(() => promise);
946
+ }
947
+ if (state.status === 'error') {
948
+ throw state.error;
949
+ }
950
+ router.dehydrateData(key, state);
951
+ return [state.data];
952
+ }
953
+ function Await(props) {
954
+ const awaited = useAwaited(props);
955
+ return props.children(...awaited);
956
+ }
957
+
958
+ class FileRoute {
959
+ constructor(path) {
960
+ this.path = path;
961
+ }
962
+ createRoute = options => {
963
+ const route = new Route(options);
964
+ route.isRoot = false;
965
+ return route;
966
+ };
967
+ }
968
+
969
+ function lazyRouteComponent(importer, exportName) {
970
+ let loadPromise;
971
+ const load = () => {
972
+ if (!loadPromise) {
973
+ loadPromise = importer();
974
+ }
975
+ return loadPromise;
976
+ };
977
+ const lazyComp = /*#__PURE__*/React.lazy(async () => {
978
+ const moduleExports = await load();
979
+ const comp = moduleExports[exportName ?? 'default'];
980
+ return {
981
+ default: comp
982
+ };
983
+ });
984
+ lazyComp.preload = load;
985
+ return lazyComp;
986
+ }
987
+
988
+ function _extends() {
989
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
990
+ for (var i = 1; i < arguments.length; i++) {
991
+ var source = arguments[i];
992
+ for (var key in source) {
993
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
994
+ target[key] = source[key];
995
+ }
996
+ }
997
+ }
998
+ return target;
999
+ };
1000
+ return _extends.apply(this, arguments);
1001
+ }
1002
+
1003
+ function useLinkProps(options) {
1004
+ const {
1005
+ buildLink
1006
+ } = useRouter();
1007
+ const match = useMatch({
1008
+ strict: false
1009
+ });
1010
+ const {
1011
+ // custom props
1012
+ type,
1013
+ children,
1014
+ target,
1015
+ activeProps = () => ({
1016
+ className: 'active'
1017
+ }),
1018
+ inactiveProps = () => ({}),
1019
+ activeOptions,
1020
+ disabled,
1021
+ hash,
1022
+ search,
1023
+ params,
1024
+ to,
1025
+ state,
1026
+ mask,
1027
+ preload,
1028
+ preloadDelay,
1029
+ replace,
1030
+ startTransition,
1031
+ resetScroll,
1032
+ // element props
1033
+ style,
1034
+ className,
1035
+ onClick,
1036
+ onFocus,
1037
+ onMouseEnter,
1038
+ onMouseLeave,
1039
+ onTouchStart,
1040
+ ...rest
1041
+ } = options;
1042
+ const linkInfo = buildLink({
1043
+ from: options.to ? match.pathname : undefined,
1044
+ ...options
1045
+ });
1046
+ if (linkInfo.type === 'external') {
1047
+ const {
1048
+ href
1049
+ } = linkInfo;
1050
+ return {
1051
+ href
1052
+ };
1053
+ }
1054
+ const {
1055
+ handleClick,
1056
+ handleFocus,
1057
+ handleEnter,
1058
+ handleLeave,
1059
+ handleTouchStart,
1060
+ isActive,
1061
+ next
1062
+ } = linkInfo;
1063
+ const composeHandlers = handlers => e => {
1064
+ if (e.persist) e.persist();
1065
+ handlers.filter(Boolean).forEach(handler => {
1066
+ if (e.defaultPrevented) return;
1067
+ handler(e);
1068
+ });
1069
+ };
1070
+
1071
+ // Get the active props
1072
+ const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {};
1073
+
1074
+ // Get the inactive props
1075
+ const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
1076
+ return {
1077
+ ...resolvedActiveProps,
1078
+ ...resolvedInactiveProps,
1079
+ ...rest,
1080
+ href: disabled ? undefined : next.maskedLocation ? next.maskedLocation.href : next.href,
1081
+ onClick: composeHandlers([onClick, handleClick]),
1082
+ onFocus: composeHandlers([onFocus, handleFocus]),
1083
+ onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
1084
+ onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
1085
+ onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
1086
+ target,
1087
+ style: {
1088
+ ...style,
1089
+ ...resolvedActiveProps.style,
1090
+ ...resolvedInactiveProps.style
1091
+ },
1092
+ className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
1093
+ ...(disabled ? {
1094
+ role: 'link',
1095
+ 'aria-disabled': true
1096
+ } : undefined),
1097
+ ['data-status']: isActive ? 'active' : undefined
1098
+ };
1099
+ }
1100
+ const Link = /*#__PURE__*/React.forwardRef((props, ref) => {
1101
+ const linkProps = useLinkProps(props);
1102
+ return /*#__PURE__*/React.createElement("a", _extends({
1103
+ ref: ref
1104
+ }, linkProps, {
1105
+ children: typeof props.children === 'function' ? props.children({
1106
+ isActive: linkProps['data-status'] === 'active'
1107
+ }) : props.children
1108
+ }));
1109
+ });
1110
+
1171
1111
  // @ts-nocheck
1112
+
1172
1113
  // 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.
1114
+
1173
1115
  function encode(obj, pfx) {
1174
1116
  var k,
1175
- i,
1176
- tmp,
1177
- str = '';
1178
-
1117
+ i,
1118
+ tmp,
1119
+ str = '';
1179
1120
  for (k in obj) {
1180
1121
  if ((tmp = obj[k]) !== void 0) {
1181
1122
  if (Array.isArray(tmp)) {
@@ -1189,1726 +1130,1410 @@ function encode(obj, pfx) {
1189
1130
  }
1190
1131
  }
1191
1132
  }
1192
-
1193
1133
  return (pfx || '') + str;
1194
1134
  }
1195
-
1196
1135
  function toValue(mix) {
1197
1136
  if (!mix) return '';
1198
1137
  var str = decodeURIComponent(mix);
1199
1138
  if (str === 'false') return false;
1200
1139
  if (str === 'true') return true;
1201
- if (str.charAt(0) === '0') return str;
1202
- return +str * 0 === 0 ? +str : str;
1140
+ return +str * 0 === 0 && +str + '' === str ? +str : str;
1203
1141
  }
1204
-
1205
1142
  function decode(str) {
1206
1143
  var tmp,
1207
- k,
1208
- out = {},
1209
- arr = str.split('&');
1210
-
1144
+ k,
1145
+ out = {},
1146
+ arr = str.split('&');
1211
1147
  while (tmp = arr.shift()) {
1212
1148
  tmp = tmp.split('=');
1213
1149
  k = tmp.shift();
1214
-
1215
1150
  if (out[k] !== void 0) {
1216
1151
  out[k] = [].concat(out[k], toValue(tmp.shift()));
1217
1152
  } else {
1218
1153
  out[k] = toValue(tmp.shift());
1219
1154
  }
1220
1155
  }
1221
-
1222
1156
  return out;
1223
1157
  }
1224
1158
 
1225
- function _extends() {
1226
- _extends = Object.assign ? Object.assign.bind() : function (target) {
1227
- for (var i = 1; i < arguments.length; i++) {
1228
- var source = arguments[i];
1229
-
1230
- for (var key in source) {
1231
- if (Object.prototype.hasOwnProperty.call(source, key)) {
1232
- target[key] = source[key];
1233
- }
1234
- }
1235
- }
1236
-
1237
- return target;
1238
- };
1239
- return _extends.apply(this, arguments);
1240
- }
1241
-
1242
- function createRoute(routeConfig, options, parent, router) {
1243
- const {
1244
- id,
1245
- routeId,
1246
- path: routePath,
1247
- fullPath
1248
- } = routeConfig;
1249
-
1250
- const action = router.state.actions[id] || (() => {
1251
- router.state.actions[id] = {
1252
- submissions: [],
1253
- submit: async (submission, actionOpts) => {
1254
- var _actionOpts$invalidat;
1255
-
1256
- if (!route) {
1257
- return;
1258
- }
1259
-
1260
- const invalidate = (_actionOpts$invalidat = actionOpts == null ? void 0 : actionOpts.invalidate) != null ? _actionOpts$invalidat : true;
1261
-
1262
- if (!(actionOpts != null && actionOpts.multi)) {
1263
- action.submissions = action.submissions.filter(d => d.isMulti);
1264
- }
1265
-
1266
- const actionState = {
1267
- submittedAt: Date.now(),
1268
- status: 'pending',
1269
- submission,
1270
- isMulti: !!(actionOpts != null && actionOpts.multi)
1271
- };
1272
- action.current = actionState;
1273
- action.latest = actionState;
1274
- action.submissions.push(actionState);
1275
- router.notify();
1276
-
1277
- try {
1278
- const res = await (route.options.action == null ? void 0 : route.options.action(submission));
1279
- actionState.data = res;
1280
-
1281
- if (invalidate) {
1282
- router.invalidateRoute({
1283
- to: '.',
1284
- fromCurrent: true
1285
- });
1286
- await router.reload();
1287
- }
1288
-
1289
- actionState.status = 'success';
1290
- return res;
1291
- } catch (err) {
1292
- console.error(err);
1293
- actionState.error = err;
1294
- actionState.status = 'error';
1295
- } finally {
1296
- router.notify();
1297
- }
1298
- }
1299
- };
1300
- return router.state.actions[id];
1301
- })();
1302
-
1303
- const loader = router.state.loaders[id] || (() => {
1304
- router.state.loaders[id] = {
1305
- pending: [],
1306
- fetch: async loaderContext => {
1307
- if (!route) {
1308
- return;
1309
- }
1310
-
1311
- const loaderState = {
1312
- loadedAt: Date.now(),
1313
- loaderContext
1314
- };
1315
- loader.current = loaderState;
1316
- loader.latest = loaderState;
1317
- loader.pending.push(loaderState); // router.state = {
1318
- // ...router.state,
1319
- // currentAction: loaderState,
1320
- // latestAction: loaderState,
1321
- // }
1322
-
1323
- router.notify();
1324
-
1325
- try {
1326
- return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
1327
- } finally {
1328
- loader.pending = loader.pending.filter(d => d !== loaderState); // router.removeActionQueue.push({ loader, loaderState })
1329
-
1330
- router.notify();
1331
- }
1332
- }
1333
- };
1334
- return router.state.loaders[id];
1335
- })();
1159
+ // Detect if we're in the DOM
1336
1160
 
1337
- let route = {
1338
- routeInfo: undefined,
1339
- routeId: id,
1340
- routeRouteId: routeId,
1341
- routePath,
1342
- fullPath,
1343
- options,
1344
- router,
1345
- childRoutes: undefined,
1346
- parentRoute: parent,
1347
- action,
1348
- loader: loader,
1349
- buildLink: options => {
1350
- return router.buildLink(_extends({}, options, {
1351
- from: fullPath
1352
- }));
1353
- },
1354
- navigate: options => {
1355
- return router.navigate(_extends({}, options, {
1356
- from: fullPath
1357
- }));
1358
- },
1359
- matchRoute: (matchLocation, opts) => {
1360
- return router.matchRoute(_extends({}, matchLocation, {
1361
- from: fullPath
1362
- }), opts);
1363
- }
1364
- };
1365
- router.options.createRoute == null ? void 0 : router.options.createRoute({
1366
- router,
1367
- route
1368
- });
1369
- return route;
1161
+ function redirect(opts) {
1162
+ opts.isRedirect = true;
1163
+ return opts;
1370
1164
  }
1371
-
1372
- const rootRouteId = '__root__';
1373
- const createRouteConfig = function createRouteConfig(options, children, isRoot, parentId, parentPath) {
1374
- if (options === void 0) {
1375
- options = {};
1376
- }
1377
-
1378
- if (isRoot === void 0) {
1379
- isRoot = true;
1380
- }
1381
-
1382
- if (isRoot) {
1383
- options.path = rootRouteId;
1384
- } // Strip the root from parentIds
1385
-
1386
-
1387
- if (parentId === rootRouteId) {
1388
- parentId = '';
1389
- }
1390
-
1391
- let path = isRoot ? rootRouteId : options.path; // If the path is anything other than an index path, trim it up
1392
-
1393
- if (path && path !== '/') {
1394
- path = trimPath(path);
1395
- }
1396
-
1397
- const routeId = path || options.id;
1398
- let id = joinPaths([parentId, routeId]);
1399
-
1400
- if (path === rootRouteId) {
1401
- path = '/';
1402
- }
1403
-
1404
- if (id !== rootRouteId) {
1405
- id = joinPaths(['/', id]);
1406
- }
1407
-
1408
- const fullPath = id === rootRouteId ? '/' : trimPathRight(joinPaths([parentPath, path]));
1409
- return {
1410
- id: id,
1411
- routeId: routeId,
1412
- path: path,
1413
- fullPath: fullPath,
1414
- options: options,
1415
- children,
1416
- createChildren: cb => createRouteConfig(options, cb(childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath)), false, parentId, parentPath),
1417
- addChildren: children => createRouteConfig(options, children, false, parentId, parentPath),
1418
- createRoute: childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath)
1419
- };
1420
- };
1421
-
1422
- const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
1423
- function createRouteMatch(router, route, opts) {
1424
- const routeMatch = _extends({}, route, opts, {
1425
- router,
1426
- routeSearch: {},
1427
- search: {},
1428
- childMatches: [],
1429
- status: 'idle',
1430
- routeLoaderData: {},
1431
- loaderData: {},
1432
- isFetching: false,
1433
- isInvalid: false,
1434
- invalidAt: Infinity,
1435
- // pendingActions: [],
1436
- getIsInvalid: () => {
1437
- const now = Date.now();
1438
- return routeMatch.isInvalid || routeMatch.invalidAt < now;
1439
- },
1440
- __: {
1441
- abortController: new AbortController(),
1442
- latestId: '',
1443
- resolve: () => {},
1444
- notify: () => {
1445
- routeMatch.__.resolve();
1446
-
1447
- routeMatch.router.notify();
1448
- },
1449
- validate: () => {
1450
- var _routeMatch$parentMat, _routeMatch$parentMat2;
1451
-
1452
- // Validate the search params and stabilize them
1453
- const parentSearch = (_routeMatch$parentMat = (_routeMatch$parentMat2 = routeMatch.parentMatch) == null ? void 0 : _routeMatch$parentMat2.search) != null ? _routeMatch$parentMat : router.location.search;
1454
-
1455
- try {
1456
- var _validator;
1457
-
1458
- const prevSearch = routeMatch.routeSearch;
1459
- const validator = typeof routeMatch.options.validateSearch === 'object' ? routeMatch.options.validateSearch.parse : routeMatch.options.validateSearch;
1460
- let nextSearch = replaceEqualDeep(prevSearch, (_validator = validator == null ? void 0 : validator(parentSearch)) != null ? _validator : {}); // Invalidate route matches when search param stability changes
1461
-
1462
- if (prevSearch !== nextSearch) {
1463
- routeMatch.isInvalid = true;
1464
- }
1465
-
1466
- routeMatch.routeSearch = nextSearch;
1467
- routeMatch.search = replaceEqualDeep(parentSearch, _extends({}, parentSearch, nextSearch));
1468
- componentTypes.map(async type => {
1469
- const component = routeMatch.options[type];
1470
-
1471
- if (typeof routeMatch.__[type] !== 'function') {
1472
- routeMatch.__[type] = component;
1473
- }
1474
- });
1475
- } catch (err) {
1476
- console.error(err);
1477
- const error = new Error('Invalid search params found', {
1478
- cause: err
1479
- });
1480
- error.code = 'INVALID_SEARCH_PARAMS';
1481
- routeMatch.status = 'error';
1482
- routeMatch.error = error; // Do not proceed with loading the route
1483
-
1484
- return;
1485
- }
1486
- }
1487
- },
1488
- cancel: () => {
1489
- var _routeMatch$__$abortC;
1490
-
1491
- (_routeMatch$__$abortC = routeMatch.__.abortController) == null ? void 0 : _routeMatch$__$abortC.abort();
1492
- },
1493
- invalidate: () => {
1494
- routeMatch.isInvalid = true;
1495
- },
1496
- hasLoaders: () => {
1497
- return !!(route.options.loader || componentTypes.some(d => {
1498
- var _route$options$d;
1499
-
1500
- return (_route$options$d = route.options[d]) == null ? void 0 : _route$options$d.preload;
1501
- }));
1502
- },
1503
- load: async loaderOpts => {
1504
- const now = Date.now();
1505
- const minMaxAge = loaderOpts != null && loaderOpts.preload ? Math.max(loaderOpts == null ? void 0 : loaderOpts.maxAge, loaderOpts == null ? void 0 : loaderOpts.gcMaxAge) : 0; // If this is a preload, add it to the preload cache
1506
-
1507
- if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
1508
- // If the match is currently active, don't preload it
1509
- if (router.state.matches.find(d => d.matchId === routeMatch.matchId)) {
1510
- return;
1511
- }
1512
-
1513
- router.matchCache[routeMatch.matchId] = {
1514
- gc: now + loaderOpts.gcMaxAge,
1515
- match: routeMatch
1516
- };
1517
- } // If the match is invalid, errored or idle, trigger it to load
1518
-
1519
-
1520
- if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
1521
- const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
1522
- await routeMatch.fetch({
1523
- maxAge
1524
- });
1525
- }
1526
- },
1527
- fetch: async opts => {
1528
- const loadId = '' + Date.now() + Math.random();
1529
- routeMatch.__.latestId = loadId;
1530
-
1531
- const checkLatest = async () => {
1532
- if (loadId !== routeMatch.__.latestId) {
1533
- // warning(true, 'Data loader is out of date!')
1534
- return new Promise(() => {});
1535
- }
1536
- }; // If the match was in an error state, set it
1537
- // to a loading state again. Otherwise, keep it
1538
- // as loading or resolved
1539
-
1540
-
1541
- if (routeMatch.status === 'idle') {
1542
- routeMatch.status = 'loading';
1543
- } // We started loading the route, so it's no longer invalid
1544
-
1545
-
1546
- routeMatch.isInvalid = false;
1547
- routeMatch.__.loadPromise = new Promise(async resolve => {
1548
- // We are now fetching, even if it's in the background of a
1549
- // resolved state
1550
- routeMatch.isFetching = true;
1551
- routeMatch.__.resolve = resolve;
1552
-
1553
- routeMatch.__.componentsPromise = (async () => {
1554
- // then run all component and data loaders in parallel
1555
- // For each component type, potentially load it asynchronously
1556
- await Promise.all(componentTypes.map(async type => {
1557
- var _routeMatch$__$type;
1558
-
1559
- const component = routeMatch.options[type];
1560
-
1561
- if ((_routeMatch$__$type = routeMatch.__[type]) != null && _routeMatch$__$type.preload) {
1562
- routeMatch.__[type] = await router.options.loadComponent(component);
1563
- }
1564
- }));
1565
- })();
1566
-
1567
- routeMatch.__.dataPromise = Promise.resolve().then(async () => {
1568
- try {
1569
- var _ref, _ref2, _opts$maxAge;
1570
-
1571
- if (routeMatch.options.loader) {
1572
- const data = await router.loadMatchData(routeMatch);
1573
- await checkLatest();
1574
- routeMatch.routeLoaderData = replaceEqualDeep(routeMatch.routeLoaderData, data);
1575
- }
1576
-
1577
- routeMatch.error = undefined;
1578
- routeMatch.status = 'success';
1579
- routeMatch.updatedAt = Date.now();
1580
- routeMatch.invalidAt = routeMatch.updatedAt + ((_ref = (_ref2 = (_opts$maxAge = opts == null ? void 0 : opts.maxAge) != null ? _opts$maxAge : routeMatch.options.loaderMaxAge) != null ? _ref2 : router.options.defaultLoaderMaxAge) != null ? _ref : 0);
1581
- return routeMatch.routeLoaderData;
1582
- } catch (err) {
1583
- await checkLatest();
1584
-
1585
- if (process.env.NODE_ENV !== 'production') {
1586
- console.error(err);
1587
- }
1588
-
1589
- routeMatch.error = err;
1590
- routeMatch.status = 'error';
1591
- routeMatch.updatedAt = Date.now();
1592
- throw err;
1593
- }
1594
- });
1595
-
1596
- const after = async () => {
1597
- await checkLatest();
1598
- routeMatch.isFetching = false;
1599
- delete routeMatch.__.loadPromise;
1600
-
1601
- routeMatch.__.notify();
1602
- };
1603
-
1604
- try {
1605
- await Promise.all([routeMatch.__.componentsPromise, routeMatch.__.dataPromise.catch(() => {})]);
1606
- after();
1607
- } catch (_unused) {
1608
- after();
1609
- }
1610
- });
1611
- await routeMatch.__.loadPromise;
1612
- await checkLatest();
1613
- }
1614
- });
1615
-
1616
- if (!routeMatch.hasLoaders()) {
1617
- routeMatch.status = 'success';
1618
- }
1619
-
1620
- return routeMatch;
1165
+ function isRedirect(obj) {
1166
+ return !!obj?.isRedirect;
1621
1167
  }
1622
1168
 
1623
1169
  const defaultParseSearch = parseSearchWith(JSON.parse);
1624
- const defaultStringifySearch = stringifySearchWith(JSON.stringify);
1170
+ const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
1625
1171
  function parseSearchWith(parser) {
1626
1172
  return searchStr => {
1627
1173
  if (searchStr.substring(0, 1) === '?') {
1628
1174
  searchStr = searchStr.substring(1);
1629
1175
  }
1176
+ let query = decode(searchStr);
1630
1177
 
1631
- let query = decode(searchStr); // Try to parse any query params that might be json
1632
-
1178
+ // Try to parse any query params that might be json
1633
1179
  for (let key in query) {
1634
1180
  const value = query[key];
1635
-
1636
1181
  if (typeof value === 'string') {
1637
1182
  try {
1638
1183
  query[key] = parser(value);
1639
- } catch (err) {//
1184
+ } catch (err) {
1185
+ //
1640
1186
  }
1641
1187
  }
1642
1188
  }
1643
-
1644
1189
  return query;
1645
1190
  };
1646
1191
  }
1647
- function stringifySearchWith(stringify) {
1648
- return search => {
1649
- search = _extends({}, search);
1650
-
1651
- if (search) {
1652
- Object.keys(search).forEach(key => {
1653
- const val = search[key];
1654
-
1655
- if (typeof val === 'undefined' || val === undefined) {
1656
- delete search[key];
1657
- } else if (val && typeof val === 'object' && val !== null) {
1658
- try {
1659
- search[key] = stringify(val);
1660
- } catch (err) {// silent
1661
- }
1662
- }
1663
- });
1664
- }
1665
-
1666
- const searchStr = encode(search).toString();
1667
- return searchStr ? "?" + searchStr : '';
1668
- };
1669
- }
1670
-
1671
- var _window$document;
1672
- // Detect if we're in the DOM
1673
- const isServer = typeof window === 'undefined' || !((_window$document = window.document) != null && _window$document.createElement); // This is the default history object if none is defined
1674
-
1675
- const createDefaultHistory = () => isServer ? createMemoryHistory() : createBrowserHistory();
1676
-
1677
- function getInitialRouterState() {
1678
- return {
1679
- status: 'idle',
1680
- location: null,
1681
- matches: [],
1682
- actions: {},
1683
- loaders: {},
1684
- lastUpdated: Date.now(),
1685
- isFetching: false,
1686
- isPreloading: false
1687
- };
1688
- }
1689
-
1690
- function createRouter(userOptions) {
1691
- var _userOptions$stringif, _userOptions$parseSea;
1692
-
1693
- const history = (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory();
1694
-
1695
- const originalOptions = _extends({
1696
- defaultLoaderGcMaxAge: 5 * 60 * 1000,
1697
- defaultLoaderMaxAge: 0,
1698
- defaultPreloadMaxAge: 2000,
1699
- defaultPreloadDelay: 50
1700
- }, userOptions, {
1701
- stringifySearch: (_userOptions$stringif = userOptions == null ? void 0 : userOptions.stringifySearch) != null ? _userOptions$stringif : defaultStringifySearch,
1702
- parseSearch: (_userOptions$parseSea = userOptions == null ? void 0 : userOptions.parseSearch) != null ? _userOptions$parseSea : defaultParseSearch
1703
- });
1704
-
1705
- let router = {
1706
- types: undefined,
1707
- // public api
1708
- history,
1709
- options: originalOptions,
1710
- listeners: [],
1711
- // Resolved after construction
1712
- context: {},
1713
- basepath: '',
1714
- routeTree: undefined,
1715
- routesById: {},
1716
- location: undefined,
1717
- //
1718
- navigationPromise: Promise.resolve(),
1719
- resolveNavigation: () => {},
1720
- matchCache: {},
1721
- state: getInitialRouterState(),
1722
- reset: () => {
1723
- router.state = getInitialRouterState();
1724
- router.notify();
1725
- },
1726
- startedLoadingAt: Date.now(),
1727
- subscribe: listener => {
1728
- router.listeners.push(listener);
1729
- return () => {
1730
- router.listeners = router.listeners.filter(x => x !== listener);
1731
- };
1732
- },
1733
- getRoute: id => {
1734
- return router.routesById[id];
1735
- },
1736
- notify: () => {
1737
- const isFetching = router.state.status === 'loading' || router.state.matches.some(d => d.isFetching);
1738
- const isPreloading = Object.values(router.matchCache).some(d => d.match.isFetching && !router.state.matches.find(dd => dd.matchId === d.match.matchId));
1739
-
1740
- if (router.state.isFetching !== isFetching || router.state.isPreloading !== isPreloading) {
1741
- router.state = _extends({}, router.state, {
1742
- isFetching,
1743
- isPreloading
1744
- });
1745
- }
1746
-
1747
- cascadeLoaderData(router.state.matches);
1748
- router.listeners.forEach(listener => listener(router));
1749
- },
1750
- dehydrateState: () => {
1751
- return _extends({}, pick(router.state, ['status', 'location', 'lastUpdated']), {
1752
- matches: router.state.matches.map(match => pick(match, ['matchId', 'status', 'routeLoaderData', 'loaderData', 'isInvalid', 'invalidAt']))
1753
- });
1754
- },
1755
- hydrateState: dehydratedState => {
1756
- // Match the routes
1757
- const matches = router.matchRoutes(router.location.pathname, {
1758
- strictParseParams: true
1759
- });
1760
- matches.forEach((match, index) => {
1761
- const dehydratedMatch = dehydratedState.matches[index];
1762
- invariant(dehydratedMatch, 'Oh no! Dehydrated route matches did not match the active state of the router 😬');
1763
- Object.assign(match, dehydratedMatch);
1764
- });
1765
- matches.forEach(match => match.__.validate());
1766
- router.state = _extends({}, router.state, dehydratedState, {
1767
- matches
1768
- });
1769
- },
1770
- mount: () => {
1771
- const next = router.__.buildLocation({
1772
- to: '.',
1773
- search: true,
1774
- hash: true
1775
- }); // If the current location isn't updated, trigger a navigation
1776
- // to the current location. Otherwise, load the current location.
1777
-
1778
-
1779
- if (next.href !== router.location.href) {
1780
- router.__.commitLocation(next, true);
1781
- }
1782
-
1783
- if (!router.state.matches.length) {
1784
- router.load();
1785
- }
1786
-
1787
- const unsub = router.history.listen(event => {
1788
- router.load(router.__.parseLocation(event.location, router.location));
1789
- }); // addEventListener does not exist in React Native, but window does
1790
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1791
-
1792
- if (!isServer && window.addEventListener) {
1793
- // Listen to visibillitychange and focus
1794
- window.addEventListener('visibilitychange', router.onFocus, false);
1795
- window.addEventListener('focus', router.onFocus, false);
1796
- }
1797
-
1798
- return () => {
1799
- unsub();
1800
-
1801
- if (!isServer && window.removeEventListener) {
1802
- // Be sure to unsubscribe if a new handler is set
1803
- window.removeEventListener('visibilitychange', router.onFocus);
1804
- window.removeEventListener('focus', router.onFocus);
1805
- }
1806
- };
1807
- },
1808
- onFocus: () => {
1809
- router.load();
1810
- },
1811
- update: opts => {
1812
- const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
1813
-
1814
- if (!router.location || newHistory) {
1815
- if (opts != null && opts.history) {
1816
- router.history = opts.history;
1817
- }
1818
-
1819
- router.location = router.__.parseLocation(router.history.location);
1820
- router.state.location = router.location;
1821
- }
1822
-
1823
- Object.assign(router.options, opts);
1824
- const {
1825
- basepath,
1826
- routeConfig
1827
- } = router.options;
1828
- router.basepath = cleanPath("/" + (basepath != null ? basepath : ''));
1829
-
1830
- if (routeConfig) {
1831
- router.routesById = {};
1832
- router.routeTree = router.__.buildRouteTree(routeConfig);
1833
- }
1834
-
1835
- return router;
1836
- },
1837
- cancelMatches: () => {
1838
- var _router$state$pending, _router$state$pending2;
1839
- [...router.state.matches, ...((_router$state$pending = (_router$state$pending2 = router.state.pending) == null ? void 0 : _router$state$pending2.matches) != null ? _router$state$pending : [])].forEach(match => {
1840
- match.cancel();
1841
- });
1842
- },
1843
- load: async next => {
1844
- const id = Math.random();
1845
- router.startedLoadingAt = id;
1846
-
1847
- if (next) {
1848
- // Ingest the new location
1849
- router.location = next;
1850
- } // Cancel any pending matches
1851
-
1852
-
1853
- router.cancelMatches(); // Match the routes
1854
-
1855
- const matches = router.matchRoutes(router.location.pathname, {
1856
- strictParseParams: true
1857
- }); // Check if each match middleware to see if the route can be accessed
1858
-
1192
+ function stringifySearchWith(stringify, parser) {
1193
+ function stringifyValue(val) {
1194
+ if (typeof val === 'object' && val !== null) {
1859
1195
  try {
1860
- await Promise.all(matches.map(match => match.options.beforeLoad == null ? void 0 : match.options.beforeLoad({
1861
- context: router.context
1862
- })));
1196
+ return stringify(val);
1863
1197
  } catch (err) {
1864
- if (err != null && err.then) {
1865
- await new Promise(() => {});
1866
- }
1867
-
1868
- throw err;
1869
- }
1870
-
1871
- if (typeof document !== 'undefined') {
1872
- router.state = _extends({}, router.state, {
1873
- pending: {
1874
- matches: matches,
1875
- location: router.location
1876
- },
1877
- status: 'loading'
1878
- });
1879
- } else {
1880
- router.state = _extends({}, router.state, {
1881
- matches: matches,
1882
- location: router.location,
1883
- status: 'loading'
1884
- });
1198
+ // silent
1885
1199
  }
1886
-
1887
- router.notify(); // Load the matches
1888
-
1889
- await router.loadMatches(matches);
1890
-
1891
- if (router.startedLoadingAt !== id) {
1892
- // Ignore side-effects of match loading
1893
- return router.navigationPromise;
1200
+ } else if (typeof val === 'string' && typeof parser === 'function') {
1201
+ try {
1202
+ // Check if it's a valid parseable string.
1203
+ // If it is, then stringify it again.
1204
+ parser(val);
1205
+ return stringify(val);
1206
+ } catch (err) {
1207
+ // silent
1894
1208
  }
1895
-
1896
- const previousMatches = router.state.matches;
1897
- const exiting = [],
1898
- staying = [];
1899
- previousMatches.forEach(d => {
1900
- if (matches.find(dd => dd.matchId === d.matchId)) {
1901
- staying.push(d);
1209
+ }
1210
+ return val;
1211
+ }
1212
+ return search => {
1213
+ search = {
1214
+ ...search
1215
+ };
1216
+ if (search) {
1217
+ Object.keys(search).forEach(key => {
1218
+ const val = search[key];
1219
+ if (typeof val === 'undefined' || val === undefined) {
1220
+ delete search[key];
1902
1221
  } else {
1903
- exiting.push(d);
1222
+ search[key] = stringifyValue(val);
1904
1223
  }
1905
1224
  });
1906
- const entering = matches.filter(d => {
1907
- return !previousMatches.find(dd => dd.matchId === d.matchId);
1908
- });
1909
- const now = Date.now();
1910
- exiting.forEach(d => {
1911
- var _ref, _d$options$loaderGcMa, _ref2, _d$options$loaderMaxA;
1912
-
1913
- d.__.onExit == null ? void 0 : d.__.onExit({
1914
- params: d.params,
1915
- search: d.routeSearch
1916
- }); // Clear idle error states when match leaves
1917
-
1918
- if (d.status === 'error' && !d.isFetching) {
1919
- d.status = 'idle';
1920
- d.error = undefined;
1921
- }
1225
+ }
1226
+ const searchStr = encode(search).toString();
1227
+ return searchStr ? `?${searchStr}` : '';
1228
+ };
1229
+ }
1922
1230
 
1923
- const gc = Math.max((_ref = (_d$options$loaderGcMa = d.options.loaderGcMaxAge) != null ? _d$options$loaderGcMa : router.options.defaultLoaderGcMaxAge) != null ? _ref : 0, (_ref2 = (_d$options$loaderMaxA = d.options.loaderMaxAge) != null ? _d$options$loaderMaxA : router.options.defaultLoaderMaxAge) != null ? _ref2 : 0);
1231
+ // import warning from 'tiny-warning'
1924
1232
 
1925
- if (gc > 0) {
1926
- router.matchCache[d.matchId] = {
1927
- gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
1928
- match: d
1233
+ //
1234
+
1235
+ const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
1236
+ const preloadWarning = 'Error preloading route! ☝️';
1237
+ class Router {
1238
+ // Option-independent properties
1239
+ tempLocationKey = `${Math.round(Math.random() * 10000000)}`;
1240
+ resetNextScroll = true;
1241
+ navigateTimeout = null;
1242
+ latestLoadPromise = Promise.resolve();
1243
+ subscribers = new Set();
1244
+ pendingMatches = [];
1245
+ injectedHtml = [];
1246
+
1247
+ // Must build in constructor
1248
+
1249
+ constructor(options) {
1250
+ this.update({
1251
+ defaultPreloadDelay: 50,
1252
+ defaultPendingMs: 1000,
1253
+ defaultPendingMinMs: 500,
1254
+ context: undefined,
1255
+ ...options,
1256
+ stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
1257
+ parseSearch: options?.parseSearch ?? defaultParseSearch
1258
+ });
1259
+ }
1260
+
1261
+ // These are default implementations that can optionally be overridden
1262
+ // by the router provider once rendered. We provide these so that the
1263
+ // router can be used in a non-react environment if necessary
1264
+ startReactTransition = fn => fn();
1265
+ update = newOptions => {
1266
+ this.options = {
1267
+ ...this.options,
1268
+ ...newOptions
1269
+ };
1270
+ this.basepath = `/${trimPath(newOptions.basepath ?? '') ?? ''}`;
1271
+ if (!this.history || this.options.history && this.options.history !== this.history) {
1272
+ this.history = this.options.history ?? (typeof document !== 'undefined' ? createBrowserHistory() : createMemoryHistory());
1273
+ this.latestLocation = this.parseLocation();
1274
+ }
1275
+ if (this.options.routeTree !== this.routeTree) {
1276
+ this.routeTree = this.options.routeTree;
1277
+ this.buildRouteTree();
1278
+ }
1279
+ if (!this.__store) {
1280
+ this.__store = new Store(getInitialRouterState(this.latestLocation), {
1281
+ onUpdate: () => {
1282
+ this.__store.state = {
1283
+ ...this.state,
1284
+ status: this.state.isTransitioning || this.state.isLoading ? 'pending' : 'idle'
1929
1285
  };
1930
1286
  }
1931
1287
  });
1932
- staying.forEach(d => {
1933
- d.options.onTransition == null ? void 0 : d.options.onTransition({
1934
- params: d.params,
1935
- search: d.routeSearch
1936
- });
1937
- });
1938
- entering.forEach(d => {
1939
- d.__.onExit = d.options.onLoaded == null ? void 0 : d.options.onLoaded({
1940
- params: d.params,
1941
- search: d.search
1288
+ }
1289
+ };
1290
+ get state() {
1291
+ return this.__store.state;
1292
+ }
1293
+ buildRouteTree = () => {
1294
+ this.routesById = {};
1295
+ this.routesByPath = {};
1296
+ const recurseRoutes = childRoutes => {
1297
+ childRoutes.forEach((childRoute, i) => {
1298
+ // if (typeof childRoute === 'function') {
1299
+ // childRoute = (childRoute as any)()
1300
+ // }
1301
+ childRoute.init({
1302
+ originalIndex: i
1942
1303
  });
1943
- delete router.matchCache[d.matchId];
1304
+ const existingRoute = this.routesById[childRoute.id];
1305
+ invariant(!existingRoute, `Duplicate routes found with id: ${String(childRoute.id)}`);
1306
+ this.routesById[childRoute.id] = childRoute;
1307
+ if (!childRoute.isRoot && childRoute.path) {
1308
+ const trimmedFullPath = trimPathRight(childRoute.fullPath);
1309
+ if (!this.routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith('/')) {
1310
+ this.routesByPath[trimmedFullPath] = childRoute;
1311
+ }
1312
+ }
1313
+ const children = childRoute.children;
1314
+ if (children?.length) {
1315
+ recurseRoutes(children);
1316
+ }
1944
1317
  });
1945
-
1946
- if (router.startedLoadingAt !== id) {
1947
- // Ignore side-effects of match loading
1948
- return;
1318
+ };
1319
+ recurseRoutes([this.routeTree]);
1320
+ this.flatRoutes = Object.values(this.routesByPath).map((d, i) => {
1321
+ const trimmed = trimPath(d.fullPath);
1322
+ const parsed = parsePathname(trimmed);
1323
+ while (parsed.length > 1 && parsed[0]?.value === '/') {
1324
+ parsed.shift();
1949
1325
  }
1950
-
1951
- matches.forEach(match => {
1952
- // Clear actions
1953
- if (match.action) {
1954
- match.action.current = undefined;
1955
- match.action.submissions = [];
1326
+ const score = parsed.map(d => {
1327
+ if (d.type === 'param') {
1328
+ return 0.5;
1956
1329
  }
1330
+ if (d.type === 'wildcard') {
1331
+ return 0.25;
1332
+ }
1333
+ return 1;
1957
1334
  });
1958
- router.state = _extends({}, router.state, {
1959
- location: router.location,
1960
- matches,
1961
- pending: undefined,
1962
- status: 'idle'
1963
- });
1964
- router.notify();
1965
- router.resolveNavigation();
1966
- },
1967
- cleanMatchCache: () => {
1968
- const now = Date.now();
1969
- Object.keys(router.matchCache).forEach(matchId => {
1970
- const entry = router.matchCache[matchId]; // Don't remove loading matches
1971
-
1972
- if (entry.match.status === 'loading') {
1973
- return;
1974
- } // Do not remove successful matches that are still valid
1975
-
1976
-
1977
- if (entry.gc > 0 && entry.gc > now) {
1978
- return;
1979
- } // Everything else gets removed
1980
-
1335
+ return {
1336
+ child: d,
1337
+ trimmed,
1338
+ parsed,
1339
+ index: i,
1340
+ score
1341
+ };
1342
+ }).sort((a, b) => {
1343
+ let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
1344
+ if (isIndex !== 0) return isIndex;
1345
+ const length = Math.min(a.score.length, b.score.length);
1346
+
1347
+ // Sort by length of score
1348
+ if (a.score.length !== b.score.length) {
1349
+ return b.score.length - a.score.length;
1350
+ }
1981
1351
 
1982
- delete router.matchCache[matchId];
1983
- });
1984
- },
1985
- loadRoute: async function loadRoute(navigateOpts) {
1986
- if (navigateOpts === void 0) {
1987
- navigateOpts = router.location;
1352
+ // Sort by min available score
1353
+ for (let i = 0; i < length; i++) {
1354
+ if (a.score[i] !== b.score[i]) {
1355
+ return b.score[i] - a.score[i];
1356
+ }
1988
1357
  }
1989
1358
 
1990
- const next = router.buildNext(navigateOpts);
1991
- const matches = router.matchRoutes(next.pathname, {
1992
- strictParseParams: true
1993
- });
1994
- await router.loadMatches(matches);
1995
- return matches;
1996
- },
1997
- preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
1998
- var _ref3, _ref4, _loaderOpts$maxAge, _ref5, _ref6, _loaderOpts$gcMaxAge;
1359
+ // Sort by min available parsed value
1360
+ for (let i = 0; i < length; i++) {
1361
+ if (a.parsed[i].value !== b.parsed[i].value) {
1362
+ return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
1363
+ }
1364
+ }
1999
1365
 
2000
- if (navigateOpts === void 0) {
2001
- navigateOpts = router.location;
1366
+ // Sort by length of trimmed full path
1367
+ if (a.trimmed !== b.trimmed) {
1368
+ return a.trimmed > b.trimmed ? 1 : -1;
2002
1369
  }
2003
1370
 
2004
- const next = router.buildNext(navigateOpts);
2005
- const matches = router.matchRoutes(next.pathname, {
2006
- strictParseParams: true
2007
- });
2008
- await router.loadMatches(matches, {
2009
- preload: true,
2010
- maxAge: (_ref3 = (_ref4 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref4 : router.options.defaultLoaderMaxAge) != null ? _ref3 : 0,
2011
- gcMaxAge: (_ref5 = (_ref6 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref6 : router.options.defaultLoaderGcMaxAge) != null ? _ref5 : 0
1371
+ // Sort by original index
1372
+ return a.index - b.index;
1373
+ }).map((d, i) => {
1374
+ d.child.rank = i;
1375
+ return d.child;
1376
+ });
1377
+ };
1378
+ subscribe = (eventType, fn) => {
1379
+ const listener = {
1380
+ eventType,
1381
+ fn
1382
+ };
1383
+ this.subscribers.add(listener);
1384
+ return () => {
1385
+ this.subscribers.delete(listener);
1386
+ };
1387
+ };
1388
+ emit = routerEvent => {
1389
+ this.subscribers.forEach(listener => {
1390
+ if (listener.eventType === routerEvent.type) {
1391
+ listener.fn(routerEvent);
1392
+ }
1393
+ });
1394
+ };
1395
+ checkLatest = promise => {
1396
+ return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
1397
+ };
1398
+ parseLocation = previousLocation => {
1399
+ const parse = ({
1400
+ pathname,
1401
+ search,
1402
+ hash,
1403
+ state
1404
+ }) => {
1405
+ const parsedSearch = this.options.parseSearch(search);
1406
+ return {
1407
+ pathname: pathname,
1408
+ searchStr: search,
1409
+ search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1410
+ hash: hash.split('#').reverse()[0] ?? '',
1411
+ href: `${pathname}${search}${hash}`,
1412
+ state: replaceEqualDeep(previousLocation?.state, state)
1413
+ };
1414
+ };
1415
+ const location = parse(this.history.location);
1416
+ let {
1417
+ __tempLocation,
1418
+ __tempKey
1419
+ } = location.state;
1420
+ if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
1421
+ // Sync up the location keys
1422
+ const parsedTempLocation = parse(__tempLocation);
1423
+ parsedTempLocation.state.key = location.state.key;
1424
+ delete parsedTempLocation.state.__tempLocation;
1425
+ return {
1426
+ ...parsedTempLocation,
1427
+ maskedLocation: location
1428
+ };
1429
+ }
1430
+ return location;
1431
+ };
1432
+ resolvePathWithBase = (from, path) => {
1433
+ return resolvePath(this.basepath, from, cleanPath(path));
1434
+ };
1435
+ get looseRoutesById() {
1436
+ return this.routesById;
1437
+ }
1438
+ matchRoutes = (pathname, locationSearch, opts) => {
1439
+ let routeParams = {};
1440
+ let foundRoute = this.flatRoutes.find(route => {
1441
+ const matchedParams = matchPathname(this.basepath, trimPathRight(pathname), {
1442
+ to: route.fullPath,
1443
+ caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
1444
+ fuzzy: false
2012
1445
  });
2013
- return matches;
2014
- },
2015
- matchRoutes: (pathname, opts) => {
2016
- var _router$state$pending3, _router$state$pending4;
2017
-
2018
- router.cleanMatchCache();
2019
- const matches = [];
2020
-
2021
- if (!router.routeTree) {
2022
- return matches;
1446
+ if (matchedParams) {
1447
+ routeParams = matchedParams;
1448
+ return true;
2023
1449
  }
1450
+ return false;
1451
+ });
1452
+ let routeCursor = foundRoute || this.routesById['__root__'];
1453
+ let matchedRoutes = [routeCursor];
1454
+ // let includingLayouts = true
1455
+ while (routeCursor?.parentRoute) {
1456
+ routeCursor = routeCursor.parentRoute;
1457
+ if (routeCursor) matchedRoutes.unshift(routeCursor);
1458
+ }
2024
1459
 
2025
- const existingMatches = [...router.state.matches, ...((_router$state$pending3 = (_router$state$pending4 = router.state.pending) == null ? void 0 : _router$state$pending4.matches) != null ? _router$state$pending3 : [])];
2026
-
2027
- const recurse = async routes => {
2028
- var _parentMatch$params, _router$options$filte, _foundRoute$childRout;
2029
-
2030
- const parentMatch = last(matches);
2031
- let params = (_parentMatch$params = parentMatch == null ? void 0 : parentMatch.params) != null ? _parentMatch$params : {};
2032
- const filteredRoutes = (_router$options$filte = router.options.filterRoutes == null ? void 0 : router.options.filterRoutes(routes)) != null ? _router$options$filte : routes;
2033
- let foundRoutes = [];
2034
-
2035
- const findMatchInRoutes = (parentRoutes, routes) => {
2036
- routes.some(route => {
2037
- var _route$childRoutes, _route$childRoutes2, _route$options$caseSe;
2038
-
2039
- if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
2040
- return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
2041
- }
2042
-
2043
- const fuzzy = !!(route.routePath !== '/' || (_route$childRoutes2 = route.childRoutes) != null && _route$childRoutes2.length);
2044
- const matchParams = matchPathname(pathname, {
2045
- to: route.fullPath,
2046
- fuzzy,
2047
- caseSensitive: (_route$options$caseSe = route.options.caseSensitive) != null ? _route$options$caseSe : router.options.caseSensitive
2048
- });
2049
-
2050
- if (matchParams) {
2051
- let parsedParams;
2052
-
2053
- try {
2054
- var _route$options$parseP;
2055
-
2056
- parsedParams = (_route$options$parseP = route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) != null ? _route$options$parseP : matchParams;
2057
- } catch (err) {
2058
- if (opts != null && opts.strictParseParams) {
2059
- throw err;
2060
- }
2061
- }
2062
-
2063
- params = _extends({}, params, parsedParams);
2064
- }
2065
-
2066
- if (!!matchParams) {
2067
- foundRoutes = [...parentRoutes, route];
2068
- }
1460
+ // Existing matches are matches that are already loaded along with
1461
+ // pending matches that are still loading
2069
1462
 
2070
- return !!foundRoutes.length;
1463
+ const parseErrors = matchedRoutes.map(route => {
1464
+ let parsedParamsError;
1465
+ if (route.options.parseParams) {
1466
+ try {
1467
+ const parsedParams = route.options.parseParams(routeParams);
1468
+ // Add the parsed params to the accumulated params bag
1469
+ Object.assign(routeParams, parsedParams);
1470
+ } catch (err) {
1471
+ parsedParamsError = new PathParamError(err.message, {
1472
+ cause: err
2071
1473
  });
2072
- return !!foundRoutes.length;
2073
- };
2074
-
2075
- findMatchInRoutes([], filteredRoutes);
2076
-
2077
- if (!foundRoutes.length) {
2078
- return;
1474
+ if (opts?.throwOnError) {
1475
+ throw parsedParamsError;
1476
+ }
1477
+ return parsedParamsError;
2079
1478
  }
2080
-
2081
- foundRoutes.forEach(foundRoute => {
2082
- var _router$matchCache$ma;
2083
-
2084
- const interpolatedPath = interpolatePath(foundRoute.routePath, params);
2085
- const matchId = interpolatePath(foundRoute.routeId, params, true);
2086
- const match = existingMatches.find(d => d.matchId === matchId) || ((_router$matchCache$ma = router.matchCache[matchId]) == null ? void 0 : _router$matchCache$ma.match) || createRouteMatch(router, foundRoute, {
2087
- parentMatch,
2088
- matchId,
2089
- params,
2090
- pathname: joinPaths([pathname, interpolatedPath])
1479
+ }
1480
+ return;
1481
+ });
1482
+ const matches = [];
1483
+ matchedRoutes.forEach((route, index) => {
1484
+ // Take each matched route and resolve + validate its search params
1485
+ // This has to happen serially because each route's search params
1486
+ // can depend on the parent route's search params
1487
+ // It must also happen before we create the match so that we can
1488
+ // pass the search params to the route's potential key function
1489
+ // which is used to uniquely identify the route match in state
1490
+
1491
+ const parentMatch = matches[index - 1];
1492
+ const [preMatchSearch, searchError] = (() => {
1493
+ // Validate the search params and stabilize them
1494
+ const parentSearch = parentMatch?.search ?? locationSearch;
1495
+ try {
1496
+ const validator = typeof route.options.validateSearch === 'object' ? route.options.validateSearch.parse : route.options.validateSearch;
1497
+ let search = validator?.(parentSearch) ?? {};
1498
+ return [{
1499
+ ...parentSearch,
1500
+ ...search
1501
+ }, undefined];
1502
+ } catch (err) {
1503
+ const searchError = new SearchParamError(err.message, {
1504
+ cause: err
2091
1505
  });
2092
- matches.push(match);
2093
- });
2094
- const foundRoute = last(foundRoutes);
2095
-
2096
- if ((_foundRoute$childRout = foundRoute.childRoutes) != null && _foundRoute$childRout.length) {
2097
- recurse(foundRoute.childRoutes);
1506
+ if (opts?.throwOnError) {
1507
+ throw searchError;
1508
+ }
1509
+ return [parentSearch, searchError];
2098
1510
  }
1511
+ })();
1512
+ const interpolatedPath = interpolatePath(route.path, routeParams);
1513
+ const matchId = interpolatePath(route.id, routeParams, true) + (route.options.key?.({
1514
+ search: preMatchSearch,
1515
+ location: this.state.location
1516
+ }) ?? '');
1517
+
1518
+ // Waste not, want not. If we already have a match for this route,
1519
+ // reuse it. This is important for layout routes, which might stick
1520
+ // around between navigation actions that only change leaf routes.
1521
+ const existingMatch = getRouteMatch(this.state, matchId);
1522
+ const cause = this.state.matches.find(d => d.id === matchId) ? 'stay' : 'enter';
1523
+
1524
+ // Create a fresh route match
1525
+ const hasLoaders = !!(route.options.loader || componentTypes.some(d => route.options[d]?.preload));
1526
+ const match = existingMatch ? {
1527
+ ...existingMatch,
1528
+ cause
1529
+ } : {
1530
+ id: matchId,
1531
+ routeId: route.id,
1532
+ params: routeParams,
1533
+ pathname: joinPaths([this.basepath, interpolatedPath]),
1534
+ updatedAt: Date.now(),
1535
+ search: {},
1536
+ searchError: undefined,
1537
+ status: hasLoaders ? 'pending' : 'success',
1538
+ showPending: false,
1539
+ isFetching: false,
1540
+ invalid: false,
1541
+ error: undefined,
1542
+ paramsError: parseErrors[index],
1543
+ loadPromise: Promise.resolve(),
1544
+ context: undefined,
1545
+ abortController: new AbortController(),
1546
+ shouldReloadDeps: undefined,
1547
+ fetchedAt: 0,
1548
+ cause
2099
1549
  };
2100
1550
 
2101
- recurse([router.routeTree]);
2102
- cascadeLoaderData(matches);
2103
- return matches;
2104
- },
2105
- loadMatches: async (resolvedMatches, loaderOpts) => {
2106
- const matchPromises = resolvedMatches.map(async match => {
2107
- // Validate the match (loads search params etc)
2108
- match.__.validate();
2109
-
2110
- match.load(loaderOpts);
2111
- const search = match.search;
2112
-
2113
- if (search.__data && search.__data.matchId !== match.matchId) {
2114
- return;
2115
- }
2116
-
2117
- if (match.__.loadPromise) {
2118
- // Wait for the first sign of activity from the match
2119
- await match.__.loadPromise;
2120
- }
2121
- });
2122
- router.notify();
2123
- await Promise.all(matchPromises);
2124
- },
2125
- loadMatchData: async routeMatch => {
2126
- if (isServer || !router.options.useServerData) {
2127
- var _await$routeMatch$opt;
2128
-
2129
- return (_await$routeMatch$opt = await (routeMatch.options.loader == null ? void 0 : routeMatch.options.loader({
2130
- // parentLoaderPromise: routeMatch.parentMatch?.__.dataPromise,
2131
- params: routeMatch.params,
2132
- search: routeMatch.routeSearch,
2133
- signal: routeMatch.__.abortController.signal
2134
- }))) != null ? _await$routeMatch$opt : {};
2135
- } else {
2136
- const next = router.buildNext({
2137
- to: '.',
2138
- search: d => _extends({}, d != null ? d : {}, {
2139
- __data: {
2140
- matchId: routeMatch.matchId
2141
- }
2142
- })
2143
- });
2144
- const res = await fetch(next.href, {
2145
- method: 'GET' // signal: routeMatch.__.abortController.signal,
2146
-
1551
+ // Regardless of whether we're reusing an existing match or creating
1552
+ // a new one, we need to update the match's search params
1553
+ match.search = replaceEqualDeep(match.search, preMatchSearch);
1554
+ // And also update the searchError if there is one
1555
+ match.searchError = searchError;
1556
+ matches.push(match);
1557
+ });
1558
+ return matches;
1559
+ };
1560
+ cancelMatch = id => {
1561
+ getRouteMatch(this.state, id)?.abortController?.abort();
1562
+ };
1563
+ cancelMatches = () => {
1564
+ this.state.pendingMatches?.forEach(match => {
1565
+ this.cancelMatch(match.id);
1566
+ });
1567
+ };
1568
+ buildLocation = opts => {
1569
+ const build = (dest = {}, matches) => {
1570
+ const from = this.latestLocation;
1571
+ const fromPathname = dest.from ?? from.pathname;
1572
+ let pathname = this.resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
1573
+ const fromMatches = this.matchRoutes(fromPathname, from.search);
1574
+ const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
1575
+ const prevParams = {
1576
+ ...last(fromMatches)?.params
1577
+ };
1578
+ let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1579
+ if (nextParams) {
1580
+ matches?.map(d => this.looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
1581
+ nextParams = {
1582
+ ...nextParams,
1583
+ ...fn(nextParams)
1584
+ };
2147
1585
  });
2148
-
2149
- if (res.ok) {
2150
- return res.json();
2151
- }
2152
-
2153
- throw new Error('Failed to fetch match data');
2154
1586
  }
2155
- },
2156
- invalidateRoute: opts => {
2157
- var _router$state$pending5, _router$state$pending6;
2158
-
2159
- const next = router.buildNext(opts);
2160
- const unloadedMatchIds = router.matchRoutes(next.pathname).map(d => d.matchId);
2161
- [...router.state.matches, ...((_router$state$pending5 = (_router$state$pending6 = router.state.pending) == null ? void 0 : _router$state$pending6.matches) != null ? _router$state$pending5 : [])].forEach(match => {
2162
- if (unloadedMatchIds.includes(match.matchId)) {
2163
- match.invalidate();
2164
- }
2165
- });
2166
- },
2167
- reload: () => router.__.navigate({
2168
- fromCurrent: true,
2169
- replace: true,
2170
- search: true
2171
- }),
2172
- resolvePath: (from, path) => {
2173
- return resolvePath(router.basepath, from, cleanPath(path));
2174
- },
2175
- matchRoute: (location, opts) => {
2176
- var _location$from;
2177
-
2178
- // const location = router.buildNext(opts)
2179
- location = _extends({}, location, {
2180
- to: location.to ? router.resolvePath((_location$from = location.from) != null ? _location$from : '', location.to) : undefined
2181
- });
2182
- const next = router.buildNext(location);
2183
-
2184
- if (opts != null && opts.pending) {
2185
- var _router$state$pending7;
2186
-
2187
- if (!((_router$state$pending7 = router.state.pending) != null && _router$state$pending7.location)) {
1587
+ pathname = interpolatePath(pathname, nextParams ?? {});
1588
+ const preSearchFilters = stayingMatches?.map(match => this.looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
1589
+ const postSearchFilters = stayingMatches?.map(match => this.looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
1590
+
1591
+ // Pre filters first
1592
+ const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
1593
+
1594
+ // Then the link/navigate function
1595
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1596
+ : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
1597
+ : preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
1598
+ : {};
1599
+
1600
+ // Then post filters
1601
+ const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1602
+ const search = replaceEqualDeep(from.search, postFilteredSearch);
1603
+ const searchStr = this.options.stringifySearch(search);
1604
+ const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
1605
+ const hashStr = hash ? `#${hash}` : '';
1606
+ let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
1607
+ nextState = replaceEqualDeep(from.state, nextState);
1608
+ return {
1609
+ pathname,
1610
+ search,
1611
+ searchStr,
1612
+ state: nextState,
1613
+ hash,
1614
+ href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
1615
+ unmaskOnReload: dest.unmaskOnReload
1616
+ };
1617
+ };
1618
+ const buildWithMatches = (dest = {}, maskedDest) => {
1619
+ let next = build(dest);
1620
+ let maskedNext = maskedDest ? build(maskedDest) : undefined;
1621
+ if (!maskedNext) {
1622
+ let params = {};
1623
+ let foundMask = this.options.routeMasks?.find(d => {
1624
+ const match = matchPathname(this.basepath, next.pathname, {
1625
+ to: d.from,
1626
+ caseSensitive: false,
1627
+ fuzzy: false
1628
+ });
1629
+ if (match) {
1630
+ params = match;
1631
+ return true;
1632
+ }
2188
1633
  return false;
1634
+ });
1635
+ if (foundMask) {
1636
+ foundMask = {
1637
+ ...foundMask,
1638
+ from: interpolatePath(foundMask.from, params)
1639
+ };
1640
+ maskedDest = foundMask;
1641
+ maskedNext = build(maskedDest);
2189
1642
  }
2190
-
2191
- return !!matchPathname(router.state.pending.location.pathname, _extends({}, opts, {
2192
- to: next.pathname
2193
- }));
2194
1643
  }
2195
-
2196
- return !!matchPathname(router.state.location.pathname, _extends({}, opts, {
2197
- to: next.pathname
2198
- }));
2199
- },
2200
- navigate: async _ref7 => {
2201
- let {
2202
- from,
2203
- to = '.',
2204
- search,
2205
- hash,
2206
- replace,
2207
- params
2208
- } = _ref7;
2209
- // If this link simply reloads the current route,
2210
- // make sure it has a new key so it will trigger a data refresh
2211
- // If this `to` is a valid external URL, return
2212
- // null for LinkUtils
2213
- const toString = String(to);
2214
- const fromString = String(from);
2215
- let isExternal;
2216
-
2217
- try {
2218
- new URL("" + toString);
2219
- isExternal = true;
2220
- } catch (e) {}
2221
-
2222
- invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2223
- return router.__.navigate({
2224
- from: fromString,
2225
- to: toString,
2226
- search,
2227
- hash,
2228
- replace,
2229
- params
1644
+ const nextMatches = this.matchRoutes(next.pathname, next.search);
1645
+ const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
1646
+ const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
1647
+ const final = build(dest, nextMatches);
1648
+ if (maskedFinal) {
1649
+ final.maskedLocation = maskedFinal;
1650
+ }
1651
+ return final;
1652
+ };
1653
+ if (opts.mask) {
1654
+ return buildWithMatches(opts, {
1655
+ ...pick(opts, ['from']),
1656
+ ...opts.mask
2230
1657
  });
2231
- },
2232
- buildLink: _ref8 => {
2233
- var _preload, _ref9;
2234
-
1658
+ }
1659
+ return buildWithMatches(opts);
1660
+ };
1661
+ commitLocation = async ({
1662
+ startTransition,
1663
+ ...next
1664
+ }) => {
1665
+ if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
1666
+ const isSameUrl = this.latestLocation.href === next.href;
1667
+
1668
+ // If the next urls are the same and we're not replacing,
1669
+ // do nothing
1670
+ if (!isSameUrl || !next.replace) {
2235
1671
  let {
2236
- from,
2237
- to = '.',
2238
- search,
2239
- params,
2240
- hash,
2241
- target,
2242
- replace,
2243
- activeOptions,
2244
- preload,
2245
- preloadMaxAge: userPreloadMaxAge,
2246
- preloadGcMaxAge: userPreloadGcMaxAge,
2247
- preloadDelay: userPreloadDelay,
2248
- disabled
2249
- } = _ref8;
2250
-
2251
- // If this link simply reloads the current route,
2252
- // make sure it has a new key so it will trigger a data refresh
2253
- // If this `to` is a valid external URL, return
2254
- // null for LinkUtils
2255
- try {
2256
- new URL("" + to);
2257
- return {
2258
- type: 'external',
2259
- href: to
1672
+ maskedLocation,
1673
+ ...nextHistory
1674
+ } = next;
1675
+ if (maskedLocation) {
1676
+ nextHistory = {
1677
+ ...maskedLocation,
1678
+ state: {
1679
+ ...maskedLocation.state,
1680
+ __tempKey: undefined,
1681
+ __tempLocation: {
1682
+ ...nextHistory,
1683
+ search: nextHistory.searchStr,
1684
+ state: {
1685
+ ...nextHistory.state,
1686
+ __tempKey: undefined,
1687
+ __tempLocation: undefined,
1688
+ key: undefined
1689
+ }
1690
+ }
1691
+ }
2260
1692
  };
2261
- } catch (e) {}
2262
-
2263
- const nextOpts = {
2264
- from,
2265
- to,
2266
- search,
2267
- params,
2268
- hash,
2269
- replace
2270
- };
2271
- const next = router.buildNext(nextOpts);
2272
- preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
2273
- const preloadDelay = (_ref9 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref9 : 0; // Compare path/hash for matches
2274
-
2275
- const pathIsEqual = router.state.location.pathname === next.pathname;
2276
- const currentPathSplit = router.state.location.pathname.split('/');
2277
- const nextPathSplit = next.pathname.split('/');
2278
- const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
2279
- const hashIsEqual = router.state.location.hash === next.hash; // Combine the matches based on user options
2280
-
2281
- const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
2282
- const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true; // The final "active" test
2283
-
2284
- const isActive = pathTest && hashTest; // The click handler
2285
-
2286
- const handleClick = e => {
2287
- if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
2288
- e.preventDefault();
2289
-
2290
- if (pathIsEqual && !search && !hash) {
2291
- router.invalidateRoute(nextOpts);
2292
- } // All is well? Navigate!)
2293
-
2294
-
2295
- router.__.navigate(nextOpts);
2296
- }
2297
- }; // The click handler
2298
-
2299
-
2300
- const handleFocus = e => {
2301
- if (preload) {
2302
- router.preloadRoute(nextOpts, {
2303
- maxAge: userPreloadMaxAge,
2304
- gcMaxAge: userPreloadGcMaxAge
2305
- });
1693
+ if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
1694
+ nextHistory.state.__tempKey = this.tempLocationKey;
2306
1695
  }
1696
+ }
1697
+ const apply = () => {
1698
+ this.history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
2307
1699
  };
1700
+ if (startTransition ?? true) {
1701
+ this.startReactTransition(apply);
1702
+ } else {
1703
+ apply();
1704
+ }
1705
+ }
1706
+ this.resetNextScroll = next.resetScroll ?? true;
1707
+ return this.latestLoadPromise;
1708
+ };
1709
+ buildAndCommitLocation = ({
1710
+ replace,
1711
+ resetScroll,
1712
+ startTransition,
1713
+ ...rest
1714
+ } = {}) => {
1715
+ const location = this.buildLocation(rest);
1716
+ return this.commitLocation({
1717
+ ...location,
1718
+ startTransition,
1719
+ replace,
1720
+ resetScroll
1721
+ });
1722
+ };
1723
+ navigate = ({
1724
+ from,
1725
+ to = '',
1726
+ ...rest
1727
+ }) => {
1728
+ // If this link simply reloads the current route,
1729
+ // make sure it has a new key so it will trigger a data refresh
1730
+
1731
+ // If this `to` is a valid external URL, return
1732
+ // null for LinkUtils
1733
+ const toString = String(to);
1734
+ const fromString = typeof from === 'undefined' ? from : String(from);
1735
+ let isExternal;
1736
+ try {
1737
+ new URL(`${toString}`);
1738
+ isExternal = true;
1739
+ } catch (e) {}
1740
+ invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1741
+ return this.buildAndCommitLocation({
1742
+ ...rest,
1743
+ from: fromString,
1744
+ to: toString
1745
+ });
1746
+ };
1747
+ loadMatches = async ({
1748
+ checkLatest,
1749
+ matches,
1750
+ preload,
1751
+ invalidate
1752
+ }) => {
1753
+ let latestPromise;
1754
+ let firstBadMatchIndex;
1755
+ const updatePendingMatch = match => {
1756
+ this.__store.setState(s => ({
1757
+ ...s,
1758
+ pendingMatches: s.pendingMatches?.map(d => d.id === match.id ? match : d)
1759
+ }));
1760
+ };
2308
1761
 
2309
- const handleEnter = e => {
2310
- const target = e.target || {};
2311
-
2312
- if (preload) {
2313
- if (target.preloadTimeout) {
2314
- return;
1762
+ // Check each match middleware to see if the route can be accessed
1763
+ try {
1764
+ for (let [index, match] of matches.entries()) {
1765
+ const parentMatch = matches[index - 1];
1766
+ const route = this.looseRoutesById[match.routeId];
1767
+ const handleError = (err, code) => {
1768
+ err.routerCode = code;
1769
+ firstBadMatchIndex = firstBadMatchIndex ?? index;
1770
+ if (isRedirect(err)) {
1771
+ throw err;
2315
1772
  }
2316
-
2317
- target.preloadTimeout = setTimeout(() => {
2318
- target.preloadTimeout = null;
2319
- router.preloadRoute(nextOpts, {
2320
- maxAge: userPreloadMaxAge,
2321
- gcMaxAge: userPreloadGcMaxAge
2322
- });
2323
- }, preloadDelay);
2324
- }
2325
- };
2326
-
2327
- const handleLeave = e => {
2328
- const target = e.target || {};
2329
-
2330
- if (target.preloadTimeout) {
2331
- clearTimeout(target.preloadTimeout);
2332
- target.preloadTimeout = null;
1773
+ try {
1774
+ route.options.onError?.(err);
1775
+ } catch (errorHandlerErr) {
1776
+ err = errorHandlerErr;
1777
+ if (isRedirect(errorHandlerErr)) {
1778
+ throw errorHandlerErr;
1779
+ }
1780
+ }
1781
+ matches[index] = match = {
1782
+ ...match,
1783
+ error: err,
1784
+ status: 'error',
1785
+ updatedAt: Date.now()
1786
+ };
1787
+ };
1788
+ try {
1789
+ if (match.paramsError) {
1790
+ handleError(match.paramsError, 'PARSE_PARAMS');
1791
+ }
1792
+ if (match.searchError) {
1793
+ handleError(match.searchError, 'VALIDATE_SEARCH');
1794
+ }
1795
+ const parentContext = parentMatch?.context ?? this.options.context ?? {};
1796
+ const beforeLoadContext = (await route.options.beforeLoad?.({
1797
+ search: match.search,
1798
+ abortController: match.abortController,
1799
+ params: match.params,
1800
+ preload: !!preload,
1801
+ context: parentContext,
1802
+ location: this.state.location,
1803
+ // TOOD: just expose state and router, etc
1804
+ navigate: opts => this.navigate({
1805
+ ...opts,
1806
+ from: match.pathname
1807
+ }),
1808
+ buildLocation: this.buildLocation,
1809
+ cause: match.cause
1810
+ })) ?? {};
1811
+ const context = {
1812
+ ...parentContext,
1813
+ ...beforeLoadContext
1814
+ };
1815
+ matches[index] = match = {
1816
+ ...match,
1817
+ context: replaceEqualDeep(match.context, context)
1818
+ };
1819
+ } catch (err) {
1820
+ handleError(err, 'BEFORE_LOAD');
1821
+ break;
2333
1822
  }
2334
- };
2335
-
2336
- return {
2337
- type: 'internal',
2338
- next,
2339
- handleFocus,
2340
- handleClick,
2341
- handleEnter,
2342
- handleLeave,
2343
- isActive,
2344
- disabled
2345
- };
2346
- },
2347
- buildNext: opts => {
2348
- const next = router.__.buildLocation(opts);
2349
-
2350
- const matches = router.matchRoutes(next.pathname);
2351
-
2352
- const __preSearchFilters = matches.map(match => {
2353
- var _match$options$preSea;
2354
-
2355
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
2356
- }).flat().filter(Boolean);
2357
-
2358
- const __postSearchFilters = matches.map(match => {
2359
- var _match$options$postSe;
2360
-
2361
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
2362
- }).flat().filter(Boolean);
2363
-
2364
- return router.__.buildLocation(_extends({}, opts, {
2365
- __preSearchFilters,
2366
- __postSearchFilters
2367
- }));
2368
- },
2369
- __: {
2370
- buildRouteTree: rootRouteConfig => {
2371
- const recurseRoutes = (routeConfigs, parent) => {
2372
- return routeConfigs.map(routeConfig => {
2373
- const routeOptions = routeConfig.options;
2374
- const route = createRoute(routeConfig, routeOptions, parent, router);
2375
- const existingRoute = router.routesById[route.routeId];
2376
-
2377
- if (existingRoute) {
2378
- if (process.env.NODE_ENV !== 'production') {
2379
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
2380
- }
2381
-
2382
- throw new Error();
1823
+ }
1824
+ } catch (err) {
1825
+ if (isRedirect(err)) {
1826
+ if (!preload) this.navigate(err);
1827
+ return matches;
1828
+ }
1829
+ throw err;
1830
+ }
1831
+ const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
1832
+ const matchPromises = [];
1833
+ validResolvedMatches.forEach((match, index) => {
1834
+ matchPromises.push((async () => {
1835
+ const parentMatchPromise = matchPromises[index - 1];
1836
+ const route = this.looseRoutesById[match.routeId];
1837
+ const handleIfRedirect = err => {
1838
+ if (isRedirect(err)) {
1839
+ if (!preload) {
1840
+ this.navigate(err);
2383
1841
  }
2384
- router.routesById[route.routeId] = route;
2385
- const children = routeConfig.children;
2386
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2387
- return route;
2388
- });
1842
+ return true;
1843
+ }
1844
+ return false;
2389
1845
  };
2390
-
2391
- const routes = recurseRoutes([rootRouteConfig]);
2392
- return routes[0];
2393
- },
2394
- parseLocation: (location, previousLocation) => {
2395
- var _location$hash$split$;
2396
-
2397
- const parsedSearch = router.options.parseSearch(location.search);
2398
- return {
2399
- pathname: location.pathname,
2400
- searchStr: location.search,
2401
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2402
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
2403
- href: "" + location.pathname + location.search + location.hash,
2404
- state: location.state,
2405
- key: location.key
1846
+ let loadPromise;
1847
+ matches[index] = match = {
1848
+ ...match,
1849
+ fetchedAt: Date.now(),
1850
+ invalid: false,
1851
+ showPending: false
2406
1852
  };
2407
- },
2408
- navigate: location => {
2409
- const next = router.buildNext(location);
2410
- return router.__.commitLocation(next, location.replace);
2411
- },
2412
- buildLocation: function buildLocation(dest) {
2413
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
2414
-
2415
- if (dest === void 0) {
2416
- dest = {};
1853
+ const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
1854
+ let pendingPromise;
1855
+ if (!preload && pendingMs && (route.options.pendingComponent ?? this.options.defaultPendingComponent)) {
1856
+ pendingPromise = new Promise(r => setTimeout(r, pendingMs));
2417
1857
  }
1858
+ if (match.isFetching) {
1859
+ loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
1860
+ } else {
1861
+ const loaderContext = {
1862
+ params: match.params,
1863
+ search: match.search,
1864
+ preload: !!preload,
1865
+ parentMatchPromise,
1866
+ abortController: match.abortController,
1867
+ context: match.context,
1868
+ location: this.state.location,
1869
+ navigate: opts => this.navigate({
1870
+ ...opts,
1871
+ from: match.pathname
1872
+ }),
1873
+ cause: match.cause
1874
+ };
2418
1875
 
2419
- // const resolvedFrom: Location = {
2420
- // ...router.location,
2421
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
2422
-
2423
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
2424
-
2425
- const fromMatches = router.matchRoutes(router.location.pathname, {
2426
- strictParseParams: true
2427
- });
2428
- const toMatches = router.matchRoutes(pathname);
2429
-
2430
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1876
+ // Default to reloading the route all the time
1877
+ let shouldReload = true;
1878
+ let shouldReloadDeps = typeof route.options.shouldReload === 'function' ? route.options.shouldReload?.(loaderContext) : !!(route.options.shouldReload ?? true);
1879
+ if (match.cause === 'enter' || invalidate) {
1880
+ match.shouldReloadDeps = shouldReloadDeps;
1881
+ } else if (match.cause === 'stay') {
1882
+ if (typeof shouldReloadDeps === 'object') {
1883
+ // compare the deps to see if they've changed
1884
+ shouldReload = !deepEqual(shouldReloadDeps, match.shouldReloadDeps);
1885
+ match.shouldReloadDeps = shouldReloadDeps;
1886
+ } else {
1887
+ shouldReload = !!shouldReloadDeps;
1888
+ }
1889
+ }
2431
1890
 
2432
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1891
+ // If the user doesn't want the route to reload, just
1892
+ // resolve with the existing loader data
2433
1893
 
2434
- if (nextParams) {
2435
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2436
- Object.assign({}, nextParams, fn(nextParams));
2437
- });
1894
+ if (!shouldReload) {
1895
+ loadPromise = Promise.resolve(match.loaderData);
1896
+ } else {
1897
+ // Otherwise, load the route
1898
+ matches[index] = match = {
1899
+ ...match,
1900
+ isFetching: true
1901
+ };
1902
+ const componentsPromise = Promise.all(componentTypes.map(async type => {
1903
+ const component = route.options[type];
1904
+ if (component?.preload) {
1905
+ await component.preload();
1906
+ }
1907
+ }));
1908
+ const loaderPromise = route.options.loader?.(loaderContext);
1909
+ loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
1910
+ }
2438
1911
  }
2439
-
2440
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
2441
-
2442
- const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), router.location.search) : router.location.search; // Then the link/navigate function
2443
-
2444
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2445
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
2446
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2447
- : {}; // Then post filters
2448
-
2449
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2450
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
2451
- const searchStr = router.options.stringifySearch(search);
2452
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
2453
- hash = hash ? "#" + hash : '';
2454
- return {
2455
- pathname,
2456
- search,
2457
- searchStr,
2458
- state: router.location.state,
2459
- hash,
2460
- href: "" + pathname + searchStr + hash,
2461
- key: dest.key
1912
+ matches[index] = match = {
1913
+ ...match,
1914
+ loadPromise
2462
1915
  };
2463
- },
2464
- commitLocation: (next, replace) => {
2465
- const id = '' + Date.now() + Math.random();
2466
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
2467
- let nextAction = 'replace';
2468
-
2469
- if (!replace) {
2470
- nextAction = 'push';
1916
+ if (!preload) {
1917
+ updatePendingMatch(match);
2471
1918
  }
1919
+ let didShowPending = false;
1920
+ const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
1921
+ await new Promise(async resolve => {
1922
+ // If the route has a pending component and a pendingMs option,
1923
+ // forcefully show the pending component
1924
+ if (pendingPromise) {
1925
+ pendingPromise.then(() => {
1926
+ if (latestPromise = checkLatest()) return;
1927
+ didShowPending = true;
1928
+ matches[index] = match = {
1929
+ ...match,
1930
+ showPending: true
1931
+ };
1932
+ updatePendingMatch(match);
1933
+ resolve();
1934
+ });
1935
+ }
1936
+ try {
1937
+ const loaderData = await loadPromise;
1938
+ if (latestPromise = checkLatest()) return await latestPromise;
1939
+ if (didShowPending && pendingMinMs) {
1940
+ await new Promise(r => setTimeout(r, pendingMinMs));
1941
+ }
1942
+ if (latestPromise = checkLatest()) return await latestPromise;
1943
+ matches[index] = match = {
1944
+ ...match,
1945
+ error: undefined,
1946
+ status: 'success',
1947
+ isFetching: false,
1948
+ updatedAt: Date.now(),
1949
+ loaderData,
1950
+ loadPromise: undefined
1951
+ };
1952
+ } catch (error) {
1953
+ if (latestPromise = checkLatest()) return await latestPromise;
1954
+ if (handleIfRedirect(error)) return;
1955
+ try {
1956
+ route.options.onError?.(error);
1957
+ } catch (onErrorError) {
1958
+ error = onErrorError;
1959
+ if (handleIfRedirect(onErrorError)) return;
1960
+ }
1961
+ matches[index] = match = {
1962
+ ...match,
1963
+ error,
1964
+ status: 'error',
1965
+ isFetching: false,
1966
+ updatedAt: Date.now()
1967
+ };
1968
+ } finally {
1969
+ // If we showed the pending component, that means
1970
+ // we already moved the pendingMatches to the matches
1971
+ // state, so we need to update that specific match
1972
+ if (didShowPending && pendingMinMs && match.showPending) {
1973
+ this.__store.setState(s => ({
1974
+ ...s,
1975
+ matches: s.matches?.map(d => d.id === match.id ? match : d)
1976
+ }));
1977
+ }
1978
+ }
1979
+ if (!preload) {
1980
+ updatePendingMatch(match);
1981
+ }
1982
+ resolve();
1983
+ });
1984
+ })());
1985
+ });
1986
+ await Promise.all(matchPromises);
1987
+ return matches;
1988
+ };
1989
+ invalidate = () => this.load({
1990
+ invalidate: true
1991
+ });
1992
+ load = async opts => {
1993
+ const promise = new Promise(async (resolve, reject) => {
1994
+ const next = this.latestLocation;
1995
+ const prevLocation = this.state.resolvedLocation;
1996
+ const pathDidChange = prevLocation.href !== next.href;
1997
+ let latestPromise;
1998
+
1999
+ // Cancel any pending matches
2000
+ this.cancelMatches();
2001
+ this.emit({
2002
+ type: 'onBeforeLoad',
2003
+ fromLocation: prevLocation,
2004
+ toLocation: next,
2005
+ pathChanged: pathDidChange
2006
+ });
2472
2007
 
2473
- const isSameUrl = router.__.parseLocation(history.location).href === next.href;
2474
-
2475
- if (isSameUrl && !next.key) {
2476
- nextAction = 'replace';
2008
+ // Match the routes
2009
+ let pendingMatches = this.matchRoutes(next.pathname, next.search, {
2010
+ debug: true
2011
+ });
2012
+ const previousMatches = this.state.matches;
2013
+
2014
+ // Ingest the new matches
2015
+ this.__store.setState(s => ({
2016
+ ...s,
2017
+ isLoading: true,
2018
+ location: next,
2019
+ pendingMatches
2020
+ }));
2021
+ try {
2022
+ try {
2023
+ // Load the matches
2024
+ await this.loadMatches({
2025
+ matches: pendingMatches,
2026
+ checkLatest: () => this.checkLatest(promise),
2027
+ invalidate: opts?.invalidate
2028
+ });
2029
+ } catch (err) {
2030
+ // swallow this error, since we'll display the
2031
+ // errors on the route components
2477
2032
  }
2478
2033
 
2479
- if (nextAction === 'replace') {
2480
- history.replace({
2481
- pathname: next.pathname,
2482
- hash: next.hash,
2483
- search: next.searchStr
2484
- }, _extends({
2485
- id
2486
- }, next.state));
2487
- } else {
2488
- history.push({
2489
- pathname: next.pathname,
2490
- hash: next.hash,
2491
- search: next.searchStr
2492
- }, {
2493
- id
2034
+ // Only apply the latest transition
2035
+ if (latestPromise = this.checkLatest(promise)) {
2036
+ return latestPromise;
2037
+ }
2038
+ const exitingMatchIds = previousMatches.filter(id => !this.pendingMatches.includes(id));
2039
+ const enteringMatchIds = this.pendingMatches.filter(id => !previousMatches.includes(id));
2040
+ const stayingMatchIds = previousMatches.filter(id => this.pendingMatches.includes(id));
2041
+ this.__store.setState(s => ({
2042
+ ...s,
2043
+ isLoading: false,
2044
+ matches: pendingMatches,
2045
+ pendingMatches: undefined
2046
+ }))
2047
+
2048
+ //
2049
+ ;
2050
+ [[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matches, hook]) => {
2051
+ matches.forEach(match => {
2052
+ this.looseRoutesById[match.routeId].options[hook]?.(match);
2494
2053
  });
2054
+ });
2055
+ this.emit({
2056
+ type: 'onLoad',
2057
+ fromLocation: prevLocation,
2058
+ toLocation: next,
2059
+ pathChanged: pathDidChange
2060
+ });
2061
+ resolve();
2062
+ } catch (err) {
2063
+ // Only apply the latest transition
2064
+ if (latestPromise = this.checkLatest(promise)) {
2065
+ return latestPromise;
2495
2066
  }
2067
+ reject(err);
2068
+ }
2069
+ });
2070
+ this.latestLoadPromise = promise;
2071
+ return this.latestLoadPromise;
2072
+ };
2073
+ preloadRoute = async (navigateOpts = this.state.location) => {
2074
+ let next = this.buildLocation(navigateOpts);
2075
+ let matches = this.matchRoutes(next.pathname, next.search, {
2076
+ throwOnError: true
2077
+ });
2078
+ await this.loadMatches({
2079
+ matches,
2080
+ preload: true,
2081
+ checkLatest: () => undefined
2082
+ });
2083
+ return [last(matches), matches];
2084
+ };
2085
+ buildLink = dest => {
2086
+ // If this link simply reloads the current route,
2087
+ // make sure it has a new key so it will trigger a data refresh
2088
+
2089
+ // If this `to` is a valid external URL, return
2090
+ // null for LinkUtils
2091
+
2092
+ const {
2093
+ to,
2094
+ preload: userPreload,
2095
+ preloadDelay: userPreloadDelay,
2096
+ activeOptions,
2097
+ disabled,
2098
+ target,
2099
+ replace,
2100
+ resetScroll,
2101
+ startTransition
2102
+ } = dest;
2103
+ try {
2104
+ new URL(`${to}`);
2105
+ return {
2106
+ type: 'external',
2107
+ href: to
2108
+ };
2109
+ } catch (e) {}
2110
+ const nextOpts = dest;
2111
+ const next = this.buildLocation(nextOpts);
2112
+ const preload = userPreload ?? this.options.defaultPreload;
2113
+ const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
2114
+
2115
+ // Compare path/hash for matches
2116
+ const currentPathSplit = this.latestLocation.pathname.split('/');
2117
+ const nextPathSplit = next.pathname.split('/');
2118
+ const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
2119
+ // Combine the matches based on user this.options
2120
+ const pathTest = activeOptions?.exact ? this.latestLocation.pathname === next.pathname : pathIsFuzzyEqual;
2121
+ const hashTest = activeOptions?.includeHash ? this.latestLocation.hash === next.hash : true;
2122
+ const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(this.latestLocation.search, next.search, true) : true;
2123
+
2124
+ // The final "active" test
2125
+ const isActive = pathTest && hashTest && searchTest;
2126
+
2127
+ // The click handler
2128
+ const handleClick = e => {
2129
+ if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
2130
+ e.preventDefault();
2131
+
2132
+ // All is well? Navigate!
2133
+ this.commitLocation({
2134
+ ...next,
2135
+ replace,
2136
+ resetScroll,
2137
+ startTransition
2138
+ });
2139
+ }
2140
+ };
2496
2141
 
2497
- router.navigationPromise = new Promise(resolve => {
2498
- const previousNavigationResolve = router.resolveNavigation;
2499
-
2500
- router.resolveNavigation = () => {
2501
- previousNavigationResolve();
2502
- resolve();
2503
- };
2142
+ // The click handler
2143
+ const handleFocus = e => {
2144
+ if (preload) {
2145
+ this.preloadRoute(nextOpts).catch(err => {
2146
+ console.warn(err);
2147
+ console.warn(preloadWarning);
2504
2148
  });
2505
- return router.navigationPromise;
2506
2149
  }
2150
+ };
2151
+ const handleTouchStart = e => {
2152
+ this.preloadRoute(nextOpts).catch(err => {
2153
+ console.warn(err);
2154
+ console.warn(preloadWarning);
2155
+ });
2156
+ };
2157
+ const handleEnter = e => {
2158
+ const target = e.target || {};
2159
+ if (preload) {
2160
+ if (target.preloadTimeout) {
2161
+ return;
2162
+ }
2163
+ target.preloadTimeout = setTimeout(() => {
2164
+ target.preloadTimeout = null;
2165
+ this.preloadRoute(nextOpts).catch(err => {
2166
+ console.warn(err);
2167
+ console.warn(preloadWarning);
2168
+ });
2169
+ }, preloadDelay);
2170
+ }
2171
+ };
2172
+ const handleLeave = e => {
2173
+ const target = e.target || {};
2174
+ if (target.preloadTimeout) {
2175
+ clearTimeout(target.preloadTimeout);
2176
+ target.preloadTimeout = null;
2177
+ }
2178
+ };
2179
+ return {
2180
+ type: 'internal',
2181
+ next,
2182
+ handleFocus,
2183
+ handleClick,
2184
+ handleEnter,
2185
+ handleLeave,
2186
+ handleTouchStart,
2187
+ isActive,
2188
+ disabled
2189
+ };
2190
+ };
2191
+ matchRoute = (location, opts) => {
2192
+ location = {
2193
+ ...location,
2194
+ to: location.to ? this.resolvePathWithBase(location.from || '', location.to) : undefined
2195
+ };
2196
+ const next = this.buildLocation(location);
2197
+ if (opts?.pending && this.state.status !== 'pending') {
2198
+ return false;
2199
+ }
2200
+ const baseLocation = opts?.pending ? this.latestLocation : this.state.resolvedLocation;
2201
+ if (!baseLocation) {
2202
+ return false;
2203
+ }
2204
+ const match = matchPathname(this.basepath, baseLocation.pathname, {
2205
+ ...opts,
2206
+ to: next.pathname
2207
+ });
2208
+ if (!match) {
2209
+ return false;
2210
+ }
2211
+ if (match && (opts?.includeSearch ?? true)) {
2212
+ return deepEqual(baseLocation.search, next.search, true) ? match : false;
2213
+ }
2214
+ return match;
2215
+ };
2216
+ injectHtml = async html => {
2217
+ this.injectedHtml.push(html);
2218
+ };
2219
+ dehydrateData = (key, getData) => {
2220
+ if (typeof document === 'undefined') {
2221
+ const strKey = typeof key === 'string' ? key : JSON.stringify(key);
2222
+ this.injectHtml(async () => {
2223
+ const id = `__TSR_DEHYDRATED__${strKey}`;
2224
+ const data = typeof getData === 'function' ? await getData() : getData;
2225
+ return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
2226
+ ;(() => {
2227
+ var el = document.getElementById('${id}')
2228
+ el.parentElement.removeChild(el)
2229
+ })()
2230
+ </script>`;
2231
+ });
2232
+ return () => this.hydrateData(key);
2233
+ }
2234
+ return () => undefined;
2235
+ };
2236
+ hydrateData = key => {
2237
+ if (typeof document !== 'undefined') {
2238
+ const strKey = typeof key === 'string' ? key : JSON.stringify(key);
2239
+ return window[`__TSR_DEHYDRATED__${strKey}`];
2240
+ }
2241
+ return undefined;
2242
+ };
2243
+ dehydrate = () => {
2244
+ return {
2245
+ state: {
2246
+ dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt', 'loaderData']))
2247
+ }
2248
+ };
2249
+ };
2250
+ hydrate = async __do_not_use_server_ctx => {
2251
+ let _ctx = __do_not_use_server_ctx;
2252
+ // Client hydrates from window
2253
+ if (typeof document !== 'undefined') {
2254
+ _ctx = window.__TSR_DEHYDRATED__;
2507
2255
  }
2256
+ invariant(_ctx, 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?');
2257
+ const ctx = _ctx;
2258
+ this.dehydratedData = ctx.payload;
2259
+ this.options.hydrate?.(ctx.payload);
2260
+ const dehydratedState = ctx.router.state;
2261
+ let matches = this.matchRoutes(this.state.location.pathname, this.state.location.search).map(match => {
2262
+ const dehydratedMatch = dehydratedState.dehydratedMatches.find(d => d.id === match.id);
2263
+ invariant(dehydratedMatch, `Could not find a client-side match for dehydrated match with id: ${match.id}!`);
2264
+ if (dehydratedMatch) {
2265
+ return {
2266
+ ...match,
2267
+ ...dehydratedMatch
2268
+ };
2269
+ }
2270
+ return match;
2271
+ });
2272
+ this.__store.setState(s => {
2273
+ return {
2274
+ ...s,
2275
+ matches: matches
2276
+ };
2277
+ });
2508
2278
  };
2509
- router.update(userOptions); // Allow frameworks to hook into the router creation
2510
2279
 
2511
- router.options.createRouter == null ? void 0 : router.options.createRouter(router);
2512
- return router;
2280
+ // resolveMatchPromise = (matchId: string, key: string, value: any) => {
2281
+ // state.matches
2282
+ // .find((d) => d.id === matchId)
2283
+ // ?.__promisesByKey[key]?.resolve(value)
2284
+ // }
2513
2285
  }
2514
2286
 
2287
+ // A function that takes an import() argument which is a function and returns a new function that will
2288
+ // proxy arguments from the caller to the imported function, retaining all type
2289
+ // information along the way
2290
+ function lazyFn(fn, key) {
2291
+ return async (...args) => {
2292
+ const imported = await fn();
2293
+ return imported[key || 'default'](...args);
2294
+ };
2295
+ }
2515
2296
  function isCtrlEvent(e) {
2516
2297
  return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2517
2298
  }
2518
-
2519
- function cascadeLoaderData(matches) {
2520
- matches.forEach((match, index) => {
2521
- const parent = matches[index - 1];
2522
-
2523
- if (parent) {
2524
- match.loaderData = replaceEqualDeep(match.loaderData, _extends({}, parent.loaderData, match.routeLoaderData));
2525
- }
2526
- });
2299
+ class SearchParamError extends Error {}
2300
+ class PathParamError extends Error {}
2301
+ function getInitialRouterState(location) {
2302
+ return {
2303
+ isLoading: false,
2304
+ isTransitioning: false,
2305
+ status: 'idle',
2306
+ resolvedLocation: {
2307
+ ...location
2308
+ },
2309
+ location,
2310
+ matches: [],
2311
+ pendingMatches: [],
2312
+ lastUpdated: Date.now()
2313
+ };
2527
2314
  }
2528
2315
 
2529
- const _excluded = ["type", "children", "target", "activeProps", "inactiveProps", "activeOptions", "disabled", "hash", "search", "params", "to", "preload", "preloadDelay", "preloadMaxAge", "replace", "style", "className", "onClick", "onFocus", "onMouseEnter", "onMouseLeave", "onTouchStart", "onTouchEnd"],
2530
- _excluded2 = ["pending", "caseSensitive", "children"],
2531
- _excluded3 = ["children", "router"];
2532
- function lazy(importer) {
2533
- const lazyComp = /*#__PURE__*/React.lazy(importer);
2534
- let promise;
2535
- let resolvedComp;
2536
- const forwardedComp = /*#__PURE__*/React.forwardRef((props, ref) => {
2537
- const resolvedCompRef = React.useRef(resolvedComp || lazyComp);
2538
- return /*#__PURE__*/React.createElement(resolvedCompRef.current, _extends$2({}, ref ? {
2539
- ref
2540
- } : {}, props));
2541
- });
2542
- const finalComp = forwardedComp;
2543
-
2544
- finalComp.preload = () => {
2545
- if (!promise) {
2546
- promise = importer().then(module => {
2547
- resolvedComp = module.default;
2548
- return resolvedComp;
2549
- });
2316
+ const useLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
2317
+ const windowKey = 'window';
2318
+ const delimiter = '___';
2319
+ let weakScrolledElements = new WeakSet();
2320
+ const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
2321
+ let cache = sessionsStorage ? (() => {
2322
+ const storageKey = 'tsr-scroll-restoration-v2';
2323
+ const state = JSON.parse(window.sessionStorage.getItem(storageKey) || 'null') || {
2324
+ cached: {},
2325
+ next: {}
2326
+ };
2327
+ return {
2328
+ state,
2329
+ set: updater => {
2330
+ cache.state = functionalUpdate(updater, cache.state);
2331
+ window.sessionStorage.setItem(storageKey, JSON.stringify(cache.state));
2550
2332
  }
2551
-
2552
- return promise;
2553
2333
  };
2554
-
2555
- return finalComp;
2556
- }
2557
- //
2558
- function Link(props) {
2334
+ })() : undefined;
2335
+ const defaultGetKey = location => location.state.key;
2336
+ function useScrollRestoration(options) {
2559
2337
  const router = useRouter();
2560
- return /*#__PURE__*/React.createElement(router.Link, props);
2561
- }
2562
- const matchesContext = /*#__PURE__*/React.createContext(null);
2563
- const routerContext = /*#__PURE__*/React.createContext(null);
2564
- function MatchesProvider(props) {
2565
- return /*#__PURE__*/React.createElement(matchesContext.Provider, props);
2566
- }
2567
-
2568
- const useRouterSubscription = router => {
2569
- useSyncExternalStore(cb => router.subscribe(() => cb()), () => router.state, () => router.state);
2570
- };
2571
-
2572
- function createReactRouter(opts) {
2573
- const makeRouteExt = (route, router) => {
2574
- return {
2575
- useRoute: function useRoute(subRouteId) {
2576
- if (subRouteId === void 0) {
2577
- subRouteId = '.';
2578
- }
2579
-
2580
- const resolvedRouteId = router.resolvePath(route.routeId, subRouteId);
2581
- const resolvedRoute = router.getRoute(resolvedRouteId);
2582
- useRouterSubscription(router);
2583
- invariant(resolvedRoute, "Could not find a route for route \"" + resolvedRouteId + "\"! Did you forget to add it to your route config?");
2584
- return resolvedRoute;
2585
- },
2586
- linkProps: options => {
2587
- var _functionalUpdate, _functionalUpdate2;
2588
-
2589
- const {
2590
- // custom props
2591
- target,
2592
- activeProps = () => ({
2593
- className: 'active'
2594
- }),
2595
- inactiveProps = () => ({}),
2596
- disabled,
2597
- // element props
2598
- style,
2599
- className,
2600
- onClick,
2601
- onFocus,
2602
- onMouseEnter,
2603
- onMouseLeave
2604
- } = options,
2605
- rest = _objectWithoutPropertiesLoose(options, _excluded);
2606
-
2607
- const linkInfo = route.buildLink(options);
2608
-
2609
- if (linkInfo.type === 'external') {
2610
- const {
2611
- href
2612
- } = linkInfo;
2613
- return {
2614
- href
2615
- };
2338
+ useLayoutEffect(() => {
2339
+ const getKey = options?.getKey || defaultGetKey;
2340
+ const {
2341
+ history
2342
+ } = window;
2343
+ if (history.scrollRestoration) {
2344
+ history.scrollRestoration = 'manual';
2345
+ }
2346
+ const onScroll = event => {
2347
+ if (weakScrolledElements.has(event.target)) return;
2348
+ weakScrolledElements.add(event.target);
2349
+ let elementSelector = '';
2350
+ if (event.target === document || event.target === window) {
2351
+ elementSelector = windowKey;
2352
+ } else {
2353
+ const attrId = event.target.getAttribute('data-scroll-restoration-id');
2354
+ if (attrId) {
2355
+ elementSelector = `[data-scroll-restoration-id="${attrId}"]`;
2356
+ } else {
2357
+ elementSelector = getCssSelector(event.target);
2616
2358
  }
2617
-
2618
- const {
2619
- handleClick,
2620
- handleFocus,
2621
- handleEnter,
2622
- handleLeave,
2623
- isActive,
2624
- next
2625
- } = linkInfo;
2626
-
2627
- const reactHandleClick = e => {
2628
- React.startTransition(() => {
2629
- handleClick(e);
2630
- });
2631
- };
2632
-
2633
- const composeHandlers = handlers => e => {
2634
- e.persist();
2635
- handlers.forEach(handler => {
2636
- if (handler) handler(e);
2637
- });
2638
- }; // Get the active props
2639
-
2640
-
2641
- const resolvedActiveProps = isActive ? (_functionalUpdate = functionalUpdate(activeProps, {})) != null ? _functionalUpdate : {} : {}; // Get the inactive props
2642
-
2643
- const resolvedInactiveProps = isActive ? {} : (_functionalUpdate2 = functionalUpdate(inactiveProps, {})) != null ? _functionalUpdate2 : {};
2644
- return _extends$2({}, resolvedActiveProps, resolvedInactiveProps, rest, {
2645
- href: disabled ? undefined : next.href,
2646
- onClick: composeHandlers([reactHandleClick, onClick]),
2647
- onFocus: composeHandlers([handleFocus, onFocus]),
2648
- onMouseEnter: composeHandlers([handleEnter, onMouseEnter]),
2649
- onMouseLeave: composeHandlers([handleLeave, onMouseLeave]),
2650
- target,
2651
- style: _extends$2({}, style, resolvedActiveProps.style, resolvedInactiveProps.style),
2652
- className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined
2653
- }, disabled ? {
2654
- role: 'link',
2655
- 'aria-disabled': true
2656
- } : undefined, {
2657
- ['data-status']: isActive ? 'active' : undefined
2658
- });
2659
- },
2660
- Link: /*#__PURE__*/React.forwardRef((props, ref) => {
2661
- const linkProps = route.linkProps(props);
2662
- useRouterSubscription(router);
2663
- return /*#__PURE__*/React.createElement("a", _extends$2({
2664
- ref: ref
2665
- }, linkProps, {
2666
- children: typeof props.children === 'function' ? props.children({
2667
- isActive: linkProps['data-status'] === 'active'
2668
- }) : props.children
2359
+ }
2360
+ if (!cache.state.next[elementSelector]) {
2361
+ cache.set(c => ({
2362
+ ...c,
2363
+ next: {
2364
+ ...c.next,
2365
+ [elementSelector]: {
2366
+ scrollX: NaN,
2367
+ scrollY: NaN
2368
+ }
2369
+ }
2669
2370
  }));
2670
- }),
2671
- MatchRoute: opts => {
2672
- const {
2673
- pending,
2674
- caseSensitive
2675
- } = opts,
2676
- rest = _objectWithoutPropertiesLoose(opts, _excluded2);
2677
-
2678
- const params = route.matchRoute(rest, {
2679
- pending,
2680
- caseSensitive
2681
- });
2682
-
2683
- if (!params) {
2684
- return null;
2685
- }
2686
-
2687
- return typeof opts.children === 'function' ? opts.children(params) : opts.children;
2688
2371
  }
2689
2372
  };
2690
- };
2691
-
2692
- const coreRouter = createRouter(_extends$2({}, opts, {
2693
- createRouter: router => {
2694
- const routerExt = {
2695
- useState: () => {
2696
- useRouterSubscription(router);
2697
- return router.state;
2698
- },
2699
- useMatch: (routeId, opts) => {
2700
- var _useMatches, _opts$strict;
2701
-
2702
- useRouterSubscription(router);
2703
- invariant(routeId !== rootRouteId, "\"" + rootRouteId + "\" cannot be used with useMatch! Did you mean to useRoute(\"" + rootRouteId + "\")?");
2704
- const runtimeMatch = (_useMatches = useMatches()) == null ? void 0 : _useMatches[0];
2705
- const match = router.state.matches.find(d => d.routeId === routeId);
2706
-
2707
- if ((_opts$strict = opts == null ? void 0 : opts.strict) != null ? _opts$strict : true) {
2708
- invariant(match, "Could not find an active match for \"" + routeId + "\"!");
2709
- invariant(runtimeMatch.routeId == (match == null ? void 0 : match.routeId), "useMatch(\"" + (match == null ? void 0 : match.routeId) + "\") is being called in a component that is meant to render the '" + runtimeMatch.routeId + "' route. Did you mean to 'useMatch(\"" + (match == null ? void 0 : match.routeId) + "\", { strict: false })' or 'useRoute(\"" + (match == null ? void 0 : match.routeId) + "\")' instead?");
2373
+ if (typeof document !== 'undefined') {
2374
+ document.addEventListener('scroll', onScroll, true);
2375
+ }
2376
+ const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
2377
+ if (event.pathChanged) {
2378
+ const restoreKey = getKey(event.fromLocation);
2379
+ for (const elementSelector in cache.state.next) {
2380
+ const entry = cache.state.next[elementSelector];
2381
+ if (elementSelector === windowKey) {
2382
+ entry.scrollX = window.scrollX || 0;
2383
+ entry.scrollY = window.scrollY || 0;
2384
+ } else if (elementSelector) {
2385
+ const element = document.querySelector(elementSelector);
2386
+ entry.scrollX = element?.scrollLeft || 0;
2387
+ entry.scrollY = element?.scrollTop || 0;
2710
2388
  }
2711
-
2712
- return match;
2389
+ cache.set(c => {
2390
+ const next = {
2391
+ ...c.next
2392
+ };
2393
+ delete next[elementSelector];
2394
+ return {
2395
+ ...c,
2396
+ next,
2397
+ cached: {
2398
+ ...c.cached,
2399
+ [[restoreKey, elementSelector].join(delimiter)]: entry
2400
+ }
2401
+ };
2402
+ });
2713
2403
  }
2714
- };
2715
- const routeExt = makeRouteExt(router.getRoute(rootRouteId), router);
2716
- Object.assign(router, routerExt, routeExt);
2717
- },
2718
- createRoute: _ref => {
2719
- let {
2720
- router,
2721
- route
2722
- } = _ref;
2723
- const routeExt = makeRouteExt(route, router);
2724
- Object.assign(route, routeExt);
2725
- },
2726
- loadComponent: async component => {
2727
- if (component.preload && typeof document !== 'undefined') {
2728
- component.preload(); // return await component.preload()
2729
2404
  }
2730
-
2731
- return component;
2732
- }
2733
- }));
2734
- return coreRouter;
2735
- }
2736
- function RouterProvider(_ref2) {
2737
- var _router$options$useCo;
2738
-
2739
- let {
2740
- children,
2741
- router
2742
- } = _ref2,
2743
- rest = _objectWithoutPropertiesLoose(_ref2, _excluded3);
2744
-
2745
- router.update(rest);
2746
- const defaultRouterContext = React.useRef({});
2747
- const userContext = (_router$options$useCo = router.options.useContext == null ? void 0 : router.options.useContext()) != null ? _router$options$useCo : defaultRouterContext.current;
2748
- router.context = userContext;
2749
- useRouterSubscription(router);
2750
- React.useEffect(() => {
2751
- return router.mount();
2752
- }, [router]);
2753
- return /*#__PURE__*/React.createElement(routerContext.Provider, {
2754
- value: {
2755
- router: router
2756
- }
2757
- }, /*#__PURE__*/React.createElement(MatchesProvider, {
2758
- value: router.state.matches
2759
- }, children != null ? children : /*#__PURE__*/React.createElement(Outlet, null)));
2760
- }
2761
- function useRouter() {
2762
- const value = React.useContext(routerContext);
2763
- warning(!value, 'useRouter must be used inside a <Router> component!');
2764
- useRouterSubscription(value.router);
2765
- return value.router;
2766
- }
2767
- function useMatches() {
2768
- return React.useContext(matchesContext);
2769
- }
2770
- function useMatch(routeId, opts) {
2771
- const router = useRouter();
2772
- return router.useMatch(routeId, opts);
2773
- }
2774
- function useNearestMatch() {
2775
- var _useMatches2;
2776
-
2777
- const runtimeMatch = (_useMatches2 = useMatches()) == null ? void 0 : _useMatches2[0];
2778
- invariant(runtimeMatch, "Could not find a nearest match!");
2779
- return runtimeMatch;
2780
- }
2781
- function useRoute(routeId) {
2782
- const router = useRouter();
2783
- return router.useRoute(routeId);
2784
- }
2785
- function useSearch(_routeId) {
2786
- return useRouter().state.location.search;
2787
- }
2788
- function linkProps(props) {
2789
- const router = useRouter();
2790
- return router.linkProps(props);
2405
+ });
2406
+ const unsubOnResolved = router.subscribe('onResolved', event => {
2407
+ if (event.pathChanged) {
2408
+ if (!router.resetNextScroll) {
2409
+ return;
2410
+ }
2411
+ router.resetNextScroll = true;
2412
+ const getKey = options?.getKey || defaultGetKey;
2413
+ const restoreKey = getKey(event.toLocation);
2414
+ let windowRestored = false;
2415
+ for (const cacheKey in cache.state.cached) {
2416
+ const entry = cache.state.cached[cacheKey];
2417
+ const [key, elementSelector] = cacheKey.split(delimiter);
2418
+ if (key === restoreKey) {
2419
+ if (elementSelector === windowKey) {
2420
+ windowRestored = true;
2421
+ window.scrollTo(entry.scrollX, entry.scrollY);
2422
+ } else if (elementSelector) {
2423
+ const element = document.querySelector(elementSelector);
2424
+ if (element) {
2425
+ element.scrollLeft = entry.scrollX;
2426
+ element.scrollTop = entry.scrollY;
2427
+ }
2428
+ }
2429
+ }
2430
+ }
2431
+ if (!windowRestored) {
2432
+ window.scrollTo(0, 0);
2433
+ }
2434
+ cache.set(c => ({
2435
+ ...c,
2436
+ next: {}
2437
+ }));
2438
+ weakScrolledElements = new WeakSet();
2439
+ }
2440
+ });
2441
+ return () => {
2442
+ document.removeEventListener('scroll', onScroll);
2443
+ unsubOnBeforeLoad();
2444
+ unsubOnResolved();
2445
+ };
2446
+ }, []);
2791
2447
  }
2792
- function MatchRoute(props) {
2793
- const router = useRouter();
2794
- return /*#__PURE__*/React.createElement(router.MatchRoute, props);
2448
+ function ScrollRestoration(props) {
2449
+ useScrollRestoration(props);
2450
+ return null;
2795
2451
  }
2796
- function Outlet() {
2797
- var _ref3, _match$__$pendingComp, _match$__$errorCompon;
2798
-
2452
+ function useElementScrollRestoration(options) {
2799
2453
  const router = useRouter();
2800
- const matches = useMatches().slice(1);
2801
- const match = matches[0];
2802
- const defaultPending = React.useCallback(() => null, []);
2803
-
2804
- if (!match) {
2805
- return null;
2806
- }
2807
-
2808
- const PendingComponent = (_ref3 = (_match$__$pendingComp = match.__.pendingComponent) != null ? _match$__$pendingComp : router.options.defaultPendingComponent) != null ? _ref3 : defaultPending;
2809
- const errorComponent = (_match$__$errorCompon = match.__.errorComponent) != null ? _match$__$errorCompon : router.options.defaultErrorComponent;
2810
- return /*#__PURE__*/React.createElement(MatchesProvider, {
2811
- value: matches
2812
- }, /*#__PURE__*/React.createElement(React.Suspense, {
2813
- fallback: /*#__PURE__*/React.createElement(PendingComponent, null)
2814
- }, /*#__PURE__*/React.createElement(CatchBoundary, {
2815
- errorComponent: errorComponent
2816
- }, (() => {
2817
- if (match.status === 'error') {
2818
- throw match.error;
2819
- }
2820
-
2821
- if (match.status === 'success') {
2822
- var _ref4, _ref5;
2823
-
2824
- return /*#__PURE__*/React.createElement((_ref4 = (_ref5 = match.__.component) != null ? _ref5 : router.options.defaultComponent) != null ? _ref4 : Outlet);
2454
+ const getKey = options?.getKey || defaultGetKey;
2455
+ let elementSelector = '';
2456
+ if (options.id) {
2457
+ elementSelector = `[data-scroll-restoration-id="${options.id}"]`;
2458
+ } else {
2459
+ const element = options.getElement?.();
2460
+ if (!element) {
2461
+ return;
2825
2462
  }
2826
-
2827
- throw match.__.loadPromise;
2828
- })())));
2829
- }
2830
-
2831
- class CatchBoundary extends React.Component {
2832
- constructor() {
2833
- super(...arguments);
2834
- this.state = {
2835
- error: false
2836
- };
2837
- }
2838
-
2839
- componentDidCatch(error, info) {
2840
- console.error(error);
2841
- this.setState({
2842
- error,
2843
- info
2844
- });
2463
+ elementSelector = getCssSelector(element);
2845
2464
  }
2846
-
2847
- render() {
2848
- var _this$props$errorComp;
2849
-
2850
- const errorComponent = (_this$props$errorComp = this.props.errorComponent) != null ? _this$props$errorComp : DefaultErrorBoundary;
2851
-
2852
- if (this.state.error) {
2853
- return /*#__PURE__*/React.createElement(errorComponent, this.state);
2854
- }
2855
-
2856
- return this.props.children;
2465
+ const restoreKey = getKey(router.latestLocation);
2466
+ const cacheKey = [restoreKey, elementSelector].join(delimiter);
2467
+ return cache.state.cached[cacheKey];
2468
+ }
2469
+ function getCssSelector(el) {
2470
+ let path = [],
2471
+ parent;
2472
+ while (parent = el.parentNode) {
2473
+ path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`);
2474
+ el = parent;
2857
2475
  }
2858
-
2476
+ return `${path.join(' > ')}`.toLowerCase();
2859
2477
  }
2860
2478
 
2861
- function DefaultErrorBoundary(_ref6) {
2862
- let {
2863
- error
2864
- } = _ref6;
2865
- return /*#__PURE__*/React.createElement("div", {
2866
- style: {
2867
- padding: '.5rem',
2868
- maxWidth: '100%'
2869
- }
2870
- }, /*#__PURE__*/React.createElement("strong", {
2871
- style: {
2872
- fontSize: '1.2rem'
2873
- }
2874
- }, "Something went wrong!"), /*#__PURE__*/React.createElement("div", {
2875
- style: {
2876
- height: '.5rem'
2877
- }
2878
- }), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("pre", null, error.message ? /*#__PURE__*/React.createElement("code", {
2879
- style: {
2880
- fontSize: '.7em',
2881
- border: '1px solid red',
2882
- borderRadius: '.25rem',
2883
- padding: '.5rem',
2884
- color: 'red'
2885
- }
2886
- }, error.message) : null)));
2887
- }
2888
- function usePrompt(message, when) {
2889
- const router = useRouter();
2479
+ function useBlocker(message, condition = true) {
2480
+ const {
2481
+ history
2482
+ } = useRouter();
2890
2483
  React.useEffect(() => {
2891
- if (!when) return;
2892
- let unblock = router.history.block(transition => {
2484
+ if (!condition) return;
2485
+ let unblock = history.block((retry, cancel) => {
2893
2486
  if (window.confirm(message)) {
2894
2487
  unblock();
2895
- transition.retry();
2896
- } else {
2897
- router.location.pathname = window.location.pathname;
2488
+ retry();
2898
2489
  }
2899
2490
  });
2900
2491
  return unblock;
2901
- }, [when, location, message]);
2492
+ });
2493
+ }
2494
+ function Block({
2495
+ message,
2496
+ condition,
2497
+ children
2498
+ }) {
2499
+ useBlocker(message, condition);
2500
+ return children ?? null;
2501
+ }
2502
+
2503
+ function useNavigate(defaultOpts) {
2504
+ const {
2505
+ navigate
2506
+ } = useRouter();
2507
+ const match = useMatch({
2508
+ strict: false
2509
+ });
2510
+ return React.useCallback(opts => {
2511
+ return navigate({
2512
+ from: opts?.to ? match.pathname : undefined,
2513
+ ...defaultOpts,
2514
+ ...opts
2515
+ });
2516
+ }, []);
2902
2517
  }
2903
- function Prompt(_ref7) {
2904
- let {
2905
- message,
2906
- when,
2907
- children
2908
- } = _ref7;
2909
- usePrompt(message, when != null ? when : true);
2910
- return children != null ? children : null;
2518
+ function typedNavigate(navigate) {
2519
+ return navigate;
2520
+ } //
2521
+
2522
+ function Navigate(props) {
2523
+ const {
2524
+ navigate
2525
+ } = useRouter();
2526
+ const match = useMatch({
2527
+ strict: false
2528
+ });
2529
+ useLayoutEffect$1(() => {
2530
+ navigate({
2531
+ from: props.to ? match.pathname : undefined,
2532
+ ...props
2533
+ });
2534
+ }, []);
2535
+ return null;
2911
2536
  }
2912
2537
 
2913
- export { DefaultErrorBoundary, Link, MatchRoute, MatchesProvider, Outlet, Prompt, RouterProvider, cleanPath, createBrowserHistory, createHashHistory, createMemoryHistory, createReactRouter, createRoute, createRouteConfig, createRouteMatch, createRouter, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, invariant, joinPaths, last, lazy, linkProps, matchByPath, matchPathname, matchesContext, parsePathname, parseSearchWith, pick, replaceEqualDeep, resolvePath, rootRouteId, routerContext, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, useMatch, useMatches, useNearestMatch, usePrompt, useRoute, useRouter, useSearch, warning };
2538
+ export { Await, Block, CatchBoundary, CatchBoundaryImpl, ErrorComponent, FileRoute, Link, Match, MatchRoute, Matches, Navigate, Outlet, PathParamError, RootRoute, Route, Router, RouterProvider, ScrollRestoration, SearchParamError, cleanPath, componentTypes, createRouteMask, decode, deepEqual, defaultParseSearch, defaultStringifySearch, defer, encode, escapeJSON, functionalUpdate, getInitialRouterState, getRouteMatch, interpolatePath, isDehydratedDeferred, isPlainObject, isRedirect, isServer, joinPaths, last, lazyFn, lazyRouteComponent, matchByPath, matchPathname, matchesContext, parsePathname, parseSearchWith, pick, redirect, replaceEqualDeep, resolvePath, rootRouteId, rootRouteWithContext, routerContext, shallow, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, typedNavigate, useAwaited, useBlocker, useElementScrollRestoration, useLayoutEffect$1 as useLayoutEffect, useLinkProps, useLoaderData, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useRouteContext, useRouter, useRouterState, useScrollRestoration, useSearch, useStableCallback };
2914
2539
  //# sourceMappingURL=index.js.map