@tanstack/react-router 0.0.1-beta.14 → 0.0.1-beta.145

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