@tanstack/react-router 0.0.1-beta.16 → 0.0.1-beta.160

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
- }
277
-
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
148
  }
149
+ return true;
150
+ }
290
151
 
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
168
+ var text = "Warning: " + message;
330
169
 
331
-
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,1650 +696,1862 @@
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
- }
1266
-
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
- }
1284
-
1285
- const invalidate = (_actionOpts$invalidat = actionOpts == null ? void 0 : actionOpts.invalidate) != null ? _actionOpts$invalidat : true;
1286
-
1287
- if (!(actionOpts != null && actionOpts.multi)) {
1288
- action.submissions = action.submissions.filter(d => d.isMulti);
1289
- }
1290
-
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();
1301
-
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
- }
725
+ const rootRouteId = '__root__';
1313
726
 
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
- })();
727
+ // The parse type here allows a zod schema to be passed directly to the validator
1327
728
 
1328
- const loader = router.state.loaders[id] || (() => {
1329
- router.state.loaders[id] = {
1330
- pending: [],
1331
- fetch: async loaderContext => {
1332
- if (!route) {
1333
- return;
1334
- }
729
+ class Route {
730
+ // Set up in this.init()
1335
731
 
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
- // }
732
+ // customId!: TCustomId
1347
733
 
1348
- router.notify();
734
+ // Optional
1349
735
 
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 })
736
+ constructor(options) {
737
+ this.options = options || {};
738
+ this.isRoot = !options?.getParentRoute;
739
+ Route.__onInit(this);
740
+ }
741
+ init = opts => {
742
+ this.originalIndex = opts.originalIndex;
743
+ this.router = opts.router;
744
+ const options = this.options;
745
+ const isRoot = !options?.path && !options?.id;
746
+ this.parentRoute = this.options?.getParentRoute?.();
747
+ if (isRoot) {
748
+ this.path = rootRouteId;
749
+ } else {
750
+ invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
751
+ }
752
+ let path = isRoot ? rootRouteId : options.path;
1354
753
 
1355
- router.notify();
1356
- }
1357
- }
1358
- };
1359
- return router.state.loaders[id];
1360
- })();
754
+ // If the path is anything other than an index path, trim it up
755
+ if (path && path !== '/') {
756
+ path = trimPath(path);
757
+ }
758
+ const customId = options?.id || path;
1361
759
 
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);
760
+ // Strip the parentId prefix from the first level of children
761
+ let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
762
+ if (path === rootRouteId) {
763
+ path = '/';
764
+ }
765
+ if (id !== rootRouteId) {
766
+ id = joinPaths(['/', id]);
1387
767
  }
768
+ const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
769
+ this.path = path;
770
+ this.id = id;
771
+ // this.customId = customId as TCustomId
772
+ this.fullPath = fullPath;
773
+ this.to = fullPath;
774
+ };
775
+ addChildren = children => {
776
+ this.children = children;
777
+ return this;
778
+ };
779
+ update = options => {
780
+ Object.assign(this.options, options);
781
+ return this;
782
+ };
783
+ static __onInit = route => {
784
+ // This is a dummy static method that should get
785
+ // replaced by a framework specific implementation if necessary
1388
786
  };
1389
- router.options.createRoute == null ? void 0 : router.options.createRoute({
1390
- router,
1391
- route
1392
- });
1393
- return route;
1394
787
  }
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 = '/';
788
+ class RouterContext {
789
+ constructor() {}
790
+ createRootRoute = options => {
791
+ return new RootRoute(options);
792
+ };
793
+ }
794
+ class RootRoute extends Route {
795
+ constructor(options) {
796
+ super(options);
1426
797
  }
798
+ }
1427
799
 
1428
- if (id !== rootRouteId) {
1429
- id = joinPaths(['/', id]);
800
+ class FileRoute {
801
+ constructor(path) {
802
+ this.path = path;
1430
803
  }
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)
804
+ createRoute = options => {
805
+ const route = new Route(options);
806
+ route.isRoot = false;
807
+ return route;
1443
808
  };
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
- var _routeMatch$parentMat3;
1589
-
1590
- const data = await routeMatch.options.loader({
1591
- parentLoaderPromise: (_routeMatch$parentMat3 = routeMatch.parentMatch) == null ? void 0 : _routeMatch$parentMat3.__.dataPromise,
1592
- params: routeMatch.params,
1593
- search: routeMatch.routeSearch,
1594
- signal: routeMatch.__.abortController.signal
1595
- });
1596
-
1597
- if (id !== routeMatch.__.latestId) {
1598
- return routeMatch.__.loadPromise;
1599
- }
1600
-
1601
- routeMatch.routeLoaderData = replaceEqualDeep(routeMatch.routeLoaderData, data);
1602
- }
1603
-
1604
- routeMatch.error = undefined;
1605
- routeMatch.status = 'success';
1606
- routeMatch.updatedAt = Date.now();
1607
- 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);
1608
- return routeMatch.routeLoaderData;
1609
- } catch (err) {
1610
- if (id !== routeMatch.__.latestId) {
1611
- return routeMatch.__.loadPromise;
1612
- }
1613
-
1614
- {
1615
- console.error(err);
1616
- }
1617
-
1618
- routeMatch.error = err;
1619
- routeMatch.status = 'error';
1620
- routeMatch.updatedAt = Date.now();
1621
- throw err;
1622
- }
1623
- });
1624
-
1625
- try {
1626
- await Promise.all([routeMatch.__.componentsPromise, routeMatch.__.dataPromise.catch(() => {})]);
1627
-
1628
- if (id !== routeMatch.__.latestId) {
1629
- return routeMatch.__.loadPromise;
1630
- }
1631
- } finally {
1632
- if (id !== routeMatch.__.latestId) {
1633
- return routeMatch.__.loadPromise;
1634
- }
1635
-
1636
- routeMatch.isFetching = false;
1637
-
1638
- routeMatch.__.notify();
1639
- }
1640
- });
1641
- await routeMatch.__.loadPromise;
1642
-
1643
- if (id !== routeMatch.__.latestId) {
1644
- return routeMatch.__.loadPromise;
1645
- }
1646
-
1647
- delete routeMatch.__.loadPromise;
1648
- }
1649
- });
1650
-
1651
- if (!routeMatch.hasLoaders()) {
1652
- routeMatch.status = 'success';
1653
- }
1654
-
1655
- return routeMatch;
1656
809
  }
1657
810
 
1658
811
  const defaultParseSearch = parseSearchWith(JSON.parse);
1659
- const defaultStringifySearch = stringifySearchWith(JSON.stringify);
812
+ const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
1660
813
  function parseSearchWith(parser) {
1661
814
  return searchStr => {
1662
815
  if (searchStr.substring(0, 1) === '?') {
1663
816
  searchStr = searchStr.substring(1);
1664
817
  }
818
+ let query = decode(searchStr);
1665
819
 
1666
- let query = decode(searchStr); // Try to parse any query params that might be json
1667
-
820
+ // Try to parse any query params that might be json
1668
821
  for (let key in query) {
1669
822
  const value = query[key];
1670
-
1671
823
  if (typeof value === 'string') {
1672
824
  try {
1673
825
  query[key] = parser(value);
1674
- } catch (err) {//
826
+ } catch (err) {
827
+ //
1675
828
  }
1676
829
  }
1677
830
  }
1678
-
1679
831
  return query;
1680
832
  };
1681
833
  }
1682
- function stringifySearchWith(stringify) {
834
+ function stringifySearchWith(stringify, parser) {
835
+ function stringifyValue(val) {
836
+ if (typeof val === 'object' && val !== null) {
837
+ try {
838
+ return stringify(val);
839
+ } catch (err) {
840
+ // silent
841
+ }
842
+ } else if (typeof val === 'string' && typeof parser === 'function') {
843
+ try {
844
+ // Check if it's a valid parseable string.
845
+ // If it is, then stringify it again.
846
+ parser(val);
847
+ return stringify(val);
848
+ } catch (err) {
849
+ // silent
850
+ }
851
+ }
852
+ return val;
853
+ }
1683
854
  return search => {
1684
- search = _extends({}, search);
1685
-
855
+ search = {
856
+ ...search
857
+ };
1686
858
  if (search) {
1687
859
  Object.keys(search).forEach(key => {
1688
860
  const val = search[key];
1689
-
1690
861
  if (typeof val === 'undefined' || val === undefined) {
1691
862
  delete search[key];
1692
- } else if (val && typeof val === 'object' && val !== null) {
1693
- try {
1694
- search[key] = stringify(val);
1695
- } catch (err) {// silent
1696
- }
863
+ } else if (Array.isArray(val)) {
864
+ search[key] = val.map(stringifyValue);
865
+ } else {
866
+ search[key] = stringifyValue(val);
1697
867
  }
1698
868
  });
1699
869
  }
1700
-
1701
870
  const searchStr = encode(search).toString();
1702
- return searchStr ? "?" + searchStr : '';
871
+ return searchStr ? `?${searchStr}` : '';
1703
872
  };
1704
873
  }
1705
874
 
1706
- var _window$document;
1707
- // Detect if we're in the DOM
1708
- const isServer = typeof window === 'undefined' || !((_window$document = window.document) != null && _window$document.createElement); // This is the default history object if none is defined
1709
-
1710
- const createDefaultHistory = () => isServer ? createMemoryHistory() : createBrowserHistory();
1711
-
1712
- function getInitialRouterState() {
1713
- return {
1714
- status: 'idle',
1715
- location: null,
1716
- matches: [],
1717
- actions: {},
1718
- loaders: {},
1719
- lastUpdated: Date.now(),
1720
- isFetching: false,
1721
- isPreloading: false
1722
- };
1723
- }
1724
-
1725
- function createRouter(userOptions) {
1726
- var _userOptions$stringif, _userOptions$parseSea;
1727
-
1728
- const history = (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory();
1729
-
1730
- const originalOptions = _extends({
1731
- defaultLoaderGcMaxAge: 5 * 60 * 1000,
1732
- defaultLoaderMaxAge: 0,
1733
- defaultPreloadMaxAge: 2000,
1734
- defaultPreloadDelay: 50
1735
- }, userOptions, {
1736
- stringifySearch: (_userOptions$stringif = userOptions == null ? void 0 : userOptions.stringifySearch) != null ? _userOptions$stringif : defaultStringifySearch,
1737
- parseSearch: (_userOptions$parseSea = userOptions == null ? void 0 : userOptions.parseSearch) != null ? _userOptions$parseSea : defaultParseSearch
1738
- });
875
+ //
1739
876
 
1740
- let router = {
1741
- history,
1742
- options: originalOptions,
1743
- listeners: [],
1744
- // Resolved after construction
1745
- basepath: '',
1746
- routeTree: undefined,
1747
- routesById: {},
1748
- location: undefined,
1749
- allRouteInfo: undefined,
1750
- //
1751
- navigationPromise: Promise.resolve(),
1752
- resolveNavigation: () => {},
1753
- matchCache: {},
1754
- state: getInitialRouterState(),
1755
- reset: () => {
1756
- router.state = getInitialRouterState();
1757
- router.notify();
1758
- },
1759
- startedLoadingAt: Date.now(),
1760
- subscribe: listener => {
1761
- router.listeners.push(listener);
1762
- return () => {
1763
- router.listeners = router.listeners.filter(x => x !== listener);
1764
- };
1765
- },
1766
- getRoute: id => {
1767
- return router.routesById[id];
1768
- },
1769
- notify: () => {
1770
- const isFetching = router.state.status === 'loading' || router.state.matches.some(d => d.isFetching);
1771
- const isPreloading = Object.values(router.matchCache).some(d => d.match.isFetching && !router.state.matches.find(dd => dd.matchId === d.match.matchId));
1772
-
1773
- if (router.state.isFetching !== isFetching || router.state.isPreloading !== isPreloading) {
1774
- router.state = _extends({}, router.state, {
1775
- isFetching,
1776
- isPreloading
1777
- });
1778
- }
877
+ const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
878
+ class Router {
879
+ #unsubHistory;
880
+ constructor(options) {
881
+ this.options = {
882
+ defaultPreloadDelay: 50,
883
+ context: undefined,
884
+ ...options,
885
+ stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
886
+ parseSearch: options?.parseSearch ?? defaultParseSearch
887
+ // fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn,
888
+ };
1779
889
 
1780
- cascadeLoaderData(router.state.matches);
1781
- router.listeners.forEach(listener => listener(router));
1782
- },
1783
- dehydrateState: () => {
1784
- return _extends({}, pick(router.state, ['status', 'location', 'lastUpdated']), {
1785
- matches: router.state.matches.map(match => pick(match, ['matchId', 'status', 'routeLoaderData', 'loaderData', 'isInvalid', 'invalidAt']))
1786
- });
1787
- },
1788
- hydrateState: dehydratedState => {
1789
- // Match the routes
1790
- const matches = router.matchRoutes(router.location.pathname, {
1791
- strictParseParams: true
1792
- });
1793
- matches.forEach((match, index) => {
1794
- const dehydratedMatch = dehydratedState.matches[index];
1795
- invariant(dehydratedMatch, 'Oh no! Dehydrated route matches did not match the active state of the router 😬');
1796
- Object.assign(match, dehydratedMatch);
1797
- });
1798
- matches.forEach(match => match.__.validate());
1799
- router.state = _extends({}, router.state, dehydratedState, {
1800
- matches
890
+ this.__store = new Store(getInitialRouterState(), {
891
+ onUpdate: () => {
892
+ const prev = this.state;
893
+ const next = this.__store.state;
894
+ console.log(Object.values(next.matchesById).find(d => d.status === 'error'));
895
+ const matchesByIdChanged = prev.matchesById !== next.matchesById;
896
+ let matchesChanged;
897
+ let pendingMatchesChanged;
898
+ if (!matchesByIdChanged) {
899
+ matchesChanged = prev.matchIds.length !== next.matchIds.length || prev.matchIds.some((d, i) => d !== next.matchIds[i]);
900
+ pendingMatchesChanged = prev.pendingMatchIds.length !== next.pendingMatchIds.length || prev.pendingMatchIds.some((d, i) => d !== next.pendingMatchIds[i]);
901
+ }
902
+ if (matchesByIdChanged || matchesChanged) {
903
+ next.matches = next.matchIds.map(id => {
904
+ return next.matchesById[id];
905
+ });
906
+ }
907
+ if (matchesByIdChanged || pendingMatchesChanged) {
908
+ next.pendingMatches = next.pendingMatchIds.map(id => {
909
+ return next.matchesById[id];
910
+ });
911
+ }
912
+ next.isFetching = [...next.matches, ...next.pendingMatches].some(d => d.isFetching);
913
+ this.state = next;
914
+ },
915
+ defaultPriority: 'low'
916
+ });
917
+ this.state = this.__store.state;
918
+ this.update(options);
919
+ const next = this.buildNext({
920
+ hash: true,
921
+ fromCurrent: true,
922
+ search: true,
923
+ state: true
924
+ });
925
+ if (this.state.location.href !== next.href) {
926
+ this.#commitLocation({
927
+ ...next,
928
+ replace: true
1801
929
  });
1802
- },
1803
- mount: () => {
1804
- const next = router.__.buildLocation({
1805
- to: '.',
1806
- search: true,
1807
- hash: true
1808
- }); // If the current location isn't updated, trigger a navigation
1809
- // to the current location. Otherwise, load the current location.
1810
-
1811
-
1812
- if (next.href !== router.location.href) {
1813
- router.__.commitLocation(next, true);
1814
- }
930
+ }
931
+ }
932
+ reset = () => {
933
+ this.__store.setState(s => Object.assign(s, getInitialRouterState()));
934
+ };
935
+ mount = () => {
936
+ // If the router matches are empty, start loading the matches
937
+ // if (!this.state.matches.length) {
938
+ this.safeLoad();
939
+ // }
940
+ };
1815
941
 
1816
- if (!router.state.matches.length) {
1817
- router.load();
942
+ update = opts => {
943
+ this.options = {
944
+ ...this.options,
945
+ ...opts,
946
+ context: {
947
+ ...this.options.context,
948
+ ...opts?.context
1818
949
  }
1819
-
1820
- const unsub = router.history.listen(event => {
1821
- router.load(router.__.parseLocation(event.location, router.location));
1822
- }); // addEventListener does not exist in React Native, but window does
1823
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1824
-
1825
- if (!isServer && window.addEventListener) {
1826
- // Listen to visibillitychange and focus
1827
- window.addEventListener('visibilitychange', router.onFocus, false);
1828
- window.addEventListener('focus', router.onFocus, false);
950
+ };
951
+ if (!this.history || this.options.history && this.options.history !== this.history) {
952
+ if (this.#unsubHistory) {
953
+ this.#unsubHistory();
1829
954
  }
955
+ this.history = this.options.history ?? (isServer ? createMemoryHistory() : createBrowserHistory());
956
+ const parsedLocation = this.#parseLocation();
957
+ this.__store.setState(s => ({
958
+ ...s,
959
+ resolvedLocation: parsedLocation,
960
+ location: parsedLocation
961
+ }));
962
+ this.#unsubHistory = this.history.listen(() => {
963
+ this.safeLoad({
964
+ next: this.#parseLocation(this.state.location)
965
+ });
966
+ });
967
+ }
968
+ const {
969
+ basepath,
970
+ routeTree
971
+ } = this.options;
972
+ this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
973
+ if (routeTree && routeTree !== this.routeTree) {
974
+ this.#buildRouteTree(routeTree);
975
+ }
976
+ return this;
977
+ };
978
+ buildNext = opts => {
979
+ const next = this.#buildLocation(opts);
980
+ const __matches = this.matchRoutes(next.pathname, next.search);
981
+ return this.#buildLocation({
982
+ ...opts,
983
+ __matches
984
+ });
985
+ };
986
+ cancelMatches = () => {
987
+ this.state.matches.forEach(match => {
988
+ this.cancelMatch(match.id);
989
+ });
990
+ };
991
+ cancelMatch = id => {
992
+ this.getRouteMatch(id)?.abortController?.abort();
993
+ };
994
+ safeLoad = async opts => {
995
+ try {
996
+ return this.load(opts);
997
+ } catch (err) {
998
+ // Don't do anything
999
+ }
1000
+ };
1001
+ latestLoadPromise = Promise.resolve();
1002
+ load = async opts => {
1003
+ const promise = new Promise(async (resolve, reject) => {
1004
+ let latestPromise;
1005
+ const checkLatest = () => {
1006
+ return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
1007
+ };
1830
1008
 
1831
- return () => {
1832
- unsub();
1009
+ // Cancel any pending matches
1010
+ // this.cancelMatches()
1833
1011
 
1834
- if (!isServer && window.removeEventListener) {
1835
- // Be sure to unsubscribe if a new handler is set
1836
- window.removeEventListener('visibilitychange', router.onFocus);
1837
- window.removeEventListener('focus', router.onFocus);
1012
+ let pendingMatches;
1013
+ this.__store.batch(() => {
1014
+ if (opts?.next) {
1015
+ // Ingest the new location
1016
+ this.__store.setState(s => ({
1017
+ ...s,
1018
+ location: opts.next
1019
+ }));
1838
1020
  }
1839
- };
1840
- },
1841
- onFocus: () => {
1842
- router.load();
1843
- },
1844
- update: opts => {
1845
- const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
1846
1021
 
1847
- if (!router.location || newHistory) {
1848
- if (opts != null && opts.history) {
1849
- router.history = opts.history;
1022
+ // Match the routes
1023
+ pendingMatches = this.matchRoutes(this.state.location.pathname, this.state.location.search, {
1024
+ throwOnError: opts?.throwOnError,
1025
+ debug: true
1026
+ });
1027
+ this.__store.setState(s => ({
1028
+ ...s,
1029
+ status: 'pending',
1030
+ pendingMatchIds: pendingMatches.map(d => d.id),
1031
+ matchesById: this.#mergeMatches(s.matchesById, pendingMatches)
1032
+ }));
1033
+ });
1034
+ try {
1035
+ // Load the matches
1036
+ try {
1037
+ await this.loadMatches(pendingMatches);
1038
+ } catch (err) {
1039
+ // swallow this error, since we'll display the
1040
+ // errors on the route components
1850
1041
  }
1851
1042
 
1852
- router.location = router.__.parseLocation(router.history.location);
1853
- router.state.location = router.location;
1854
- }
1855
-
1856
- Object.assign(router.options, opts);
1857
- const {
1858
- basepath,
1859
- routeConfig
1860
- } = router.options;
1861
- router.basepath = cleanPath("/" + (basepath != null ? basepath : ''));
1862
-
1863
- if (routeConfig) {
1864
- router.routesById = {};
1865
- router.routeTree = router.__.buildRouteTree(routeConfig);
1043
+ // Only apply the latest transition
1044
+ if (latestPromise = checkLatest()) {
1045
+ return latestPromise;
1046
+ }
1047
+ const prevLocation = this.state.resolvedLocation;
1048
+ this.__store.setState(s => ({
1049
+ ...s,
1050
+ status: 'idle',
1051
+ resolvedLocation: s.location,
1052
+ matchIds: s.pendingMatchIds,
1053
+ pendingMatchIds: []
1054
+ }));
1055
+ if (prevLocation.href !== this.state.location.href) {
1056
+ this.options.onRouteChange?.();
1057
+ }
1058
+ resolve();
1059
+ } catch (err) {
1060
+ // Only apply the latest transition
1061
+ if (latestPromise = checkLatest()) {
1062
+ return latestPromise;
1063
+ }
1064
+ reject(err);
1866
1065
  }
1867
-
1868
- return router;
1869
- },
1870
- cancelMatches: () => {
1871
- var _router$state$pending, _router$state$pending2;
1872
- [...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 => {
1873
- match.cancel();
1066
+ });
1067
+ this.latestLoadPromise = promise;
1068
+ return this.latestLoadPromise;
1069
+ };
1070
+ #mergeMatches = (prevMatchesById, nextMatches) => {
1071
+ const nextMatchesById = {
1072
+ ...prevMatchesById
1073
+ };
1074
+ let hadNew = false;
1075
+ nextMatches.forEach(match => {
1076
+ if (!nextMatchesById[match.id]) {
1077
+ hadNew = true;
1078
+ nextMatchesById[match.id] = match;
1079
+ }
1080
+ });
1081
+ if (!hadNew) {
1082
+ return prevMatchesById;
1083
+ }
1084
+ return nextMatchesById;
1085
+ };
1086
+ getRoute = id => {
1087
+ const route = this.routesById[id];
1088
+ invariant(route, `Route with id "${id}" not found`);
1089
+ return route;
1090
+ };
1091
+ preloadRoute = async (navigateOpts = this.state.location) => {
1092
+ const next = this.buildNext(navigateOpts);
1093
+ const matches = this.matchRoutes(next.pathname, next.search, {
1094
+ throwOnError: true
1095
+ });
1096
+ this.__store.setState(s => {
1097
+ return {
1098
+ ...s,
1099
+ matchesById: this.#mergeMatches(s.matchesById, matches)
1100
+ };
1101
+ });
1102
+ await this.loadMatches(matches, {
1103
+ preload: true,
1104
+ maxAge: navigateOpts.maxAge
1105
+ });
1106
+ return matches;
1107
+ };
1108
+ cleanMatches = () => {
1109
+ const now = Date.now();
1110
+ const outdatedMatchIds = Object.values(this.state.matchesById).filter(match => {
1111
+ const route = this.getRoute(match.routeId);
1112
+ 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);
1113
+ }).map(d => d.id);
1114
+ if (outdatedMatchIds.length) {
1115
+ this.__store.setState(s => {
1116
+ const matchesById = {
1117
+ ...s.matchesById
1118
+ };
1119
+ outdatedMatchIds.forEach(id => {
1120
+ delete matchesById[id];
1121
+ });
1122
+ return {
1123
+ ...s,
1124
+ matchesById
1125
+ };
1874
1126
  });
1875
- },
1876
- load: async next => {
1877
- const id = Math.random();
1878
- router.startedLoadingAt = id;
1879
-
1880
- if (next) {
1881
- // Ingest the new location
1882
- router.location = next;
1883
- } // Cancel any pending matches
1884
-
1885
-
1886
- router.cancelMatches(); // Match the routes
1887
-
1888
- const matches = router.matchRoutes(router.location.pathname, {
1889
- strictParseParams: true
1127
+ }
1128
+ };
1129
+ matchRoutes = (pathname, locationSearch, opts) => {
1130
+ let routeParams = {};
1131
+ let foundRoute = this.flatRoutes.find(route => {
1132
+ const matchedParams = matchPathname(this.basepath, trimPathRight(pathname), {
1133
+ to: route.fullPath,
1134
+ caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive
1890
1135
  });
1891
-
1892
- if (typeof document !== 'undefined') {
1893
- router.state = _extends({}, router.state, {
1894
- pending: {
1895
- matches: matches,
1896
- location: router.location
1897
- },
1898
- status: 'loading'
1899
- });
1900
- } else {
1901
- router.state = _extends({}, router.state, {
1902
- matches: matches,
1903
- location: router.location,
1904
- status: 'loading'
1905
- });
1136
+ if (matchedParams) {
1137
+ routeParams = matchedParams;
1138
+ return true;
1906
1139
  }
1140
+ return false;
1141
+ });
1142
+ let routeCursor = foundRoute || this.routesById['__root__'];
1143
+ let matchedRoutes = [routeCursor];
1144
+ // let includingLayouts = true
1145
+ while (routeCursor?.parentRoute) {
1146
+ routeCursor = routeCursor.parentRoute;
1147
+ if (routeCursor) matchedRoutes.unshift(routeCursor);
1148
+ }
1907
1149
 
1908
- router.notify(); // Load the matches
1909
-
1910
- await router.loadMatches(matches);
1911
-
1912
- if (router.startedLoadingAt !== id) {
1913
- // Ignore side-effects of match loading
1914
- return router.navigationPromise;
1915
- }
1150
+ // Existing matches are matches that are already loaded along with
1151
+ // pending matches that are still loading
1916
1152
 
1917
- const previousMatches = router.state.matches;
1918
- const exiting = [],
1919
- staying = [];
1920
- previousMatches.forEach(d => {
1921
- if (matches.find(dd => dd.matchId === d.matchId)) {
1922
- staying.push(d);
1923
- } else {
1924
- exiting.push(d);
1925
- }
1926
- });
1927
- const entering = matches.filter(d => {
1928
- return !previousMatches.find(dd => dd.matchId === d.matchId);
1929
- });
1930
- const now = Date.now();
1931
- exiting.forEach(d => {
1932
- var _ref, _d$options$loaderGcMa, _ref2, _d$options$loaderMaxA;
1933
-
1934
- d.__.onExit == null ? void 0 : d.__.onExit({
1935
- params: d.params,
1936
- search: d.routeSearch
1937
- }); // Clear idle error states when match leaves
1938
-
1939
- if (d.status === 'error' && !d.isFetching) {
1940
- d.status = 'idle';
1941
- d.error = undefined;
1153
+ const parseErrors = matchedRoutes.map(route => {
1154
+ let parsedParamsError;
1155
+ if (route.options.parseParams) {
1156
+ try {
1157
+ const parsedParams = route.options.parseParams(routeParams);
1158
+ // Add the parsed params to the accumulated params bag
1159
+ Object.assign(routeParams, parsedParams);
1160
+ } catch (err) {
1161
+ parsedParamsError = new PathParamError(err.message, {
1162
+ cause: err
1163
+ });
1164
+ if (opts?.throwOnError) {
1165
+ throw parsedParamsError;
1166
+ }
1167
+ return parsedParamsError;
1942
1168
  }
1169
+ }
1170
+ return;
1171
+ });
1172
+ const matches = matchedRoutes.map((route, index) => {
1173
+ const interpolatedPath = interpolatePath(route.path, routeParams);
1174
+ const key = route.options.key ? route.options.key({
1175
+ params: routeParams,
1176
+ search: locationSearch
1177
+ }) ?? '' : '';
1178
+ const stringifiedKey = key ? JSON.stringify(key) : '';
1179
+ const matchId = interpolatePath(route.id, routeParams, true) + stringifiedKey;
1180
+
1181
+ // Waste not, want not. If we already have a match for this route,
1182
+ // reuse it. This is important for layout routes, which might stick
1183
+ // around between navigation actions that only change leaf routes.
1184
+ const existingMatch = this.getRouteMatch(matchId);
1185
+ if (existingMatch) {
1186
+ return {
1187
+ ...existingMatch
1188
+ };
1189
+ }
1943
1190
 
1944
- 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);
1191
+ // Create a fresh route match
1192
+ const hasLoaders = !!(route.options.loader || componentTypes.some(d => route.options[d]?.preload));
1193
+ const routeMatch = {
1194
+ id: matchId,
1195
+ key: stringifiedKey,
1196
+ routeId: route.id,
1197
+ params: routeParams,
1198
+ pathname: joinPaths([this.basepath, interpolatedPath]),
1199
+ updatedAt: Date.now(),
1200
+ invalidAt: Infinity,
1201
+ preloadInvalidAt: Infinity,
1202
+ routeSearch: {},
1203
+ search: {},
1204
+ status: hasLoaders ? 'pending' : 'success',
1205
+ isFetching: false,
1206
+ invalid: false,
1207
+ error: undefined,
1208
+ paramsError: parseErrors[index],
1209
+ searchError: undefined,
1210
+ loaderData: undefined,
1211
+ loadPromise: Promise.resolve(),
1212
+ routeContext: undefined,
1213
+ context: undefined,
1214
+ abortController: new AbortController(),
1215
+ fetchedAt: 0
1216
+ };
1217
+ return routeMatch;
1218
+ });
1945
1219
 
1946
- if (gc > 0) {
1947
- router.matchCache[d.matchId] = {
1948
- gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
1949
- match: d
1220
+ // Take each match and resolve its search params and context
1221
+ // This has to happen after the matches are created or found
1222
+ // so that we can use the parent match's search params and context
1223
+ matches.forEach((match, i) => {
1224
+ const parentMatch = matches[i - 1];
1225
+ const route = this.getRoute(match.routeId);
1226
+ const searchInfo = (() => {
1227
+ // Validate the search params and stabilize them
1228
+ const parentSearchInfo = {
1229
+ search: parentMatch?.search ?? locationSearch,
1230
+ routeSearch: parentMatch?.routeSearch ?? locationSearch
1231
+ };
1232
+ try {
1233
+ const validator = typeof route.options.validateSearch === 'object' ? route.options.validateSearch.parse : route.options.validateSearch;
1234
+ const routeSearch = validator?.(parentSearchInfo.search) ?? {};
1235
+ const search = {
1236
+ ...parentSearchInfo.search,
1237
+ ...routeSearch
1950
1238
  };
1239
+ return {
1240
+ routeSearch: replaceEqualDeep(match.routeSearch, routeSearch),
1241
+ search: replaceEqualDeep(match.search, search)
1242
+ };
1243
+ } catch (err) {
1244
+ match.searchError = new SearchParamError(err.message, {
1245
+ cause: err
1246
+ });
1247
+ if (opts?.throwOnError) {
1248
+ throw match.searchError;
1249
+ }
1250
+ return parentSearchInfo;
1951
1251
  }
1252
+ })();
1253
+ Object.assign(match, {
1254
+ ...searchInfo
1952
1255
  });
1953
- staying.forEach(d => {
1954
- d.options.onTransition == null ? void 0 : d.options.onTransition({
1955
- params: d.params,
1956
- search: d.routeSearch
1957
- });
1958
- });
1959
- entering.forEach(d => {
1960
- d.__.onExit = d.options.onMatch == null ? void 0 : d.options.onMatch({
1961
- params: d.params,
1962
- search: d.search
1963
- });
1964
- delete router.matchCache[d.matchId];
1965
- });
1966
-
1967
- if (router.startedLoadingAt !== id) {
1968
- // Ignore side-effects of match loading
1969
- return;
1970
- }
1971
-
1972
- matches.forEach(match => {
1973
- // Clear actions
1974
- if (match.action) {
1975
- match.action.current = undefined;
1976
- match.action.submissions = [];
1256
+ const contextInfo = (() => {
1257
+ try {
1258
+ const routeContext = route.options.getContext?.({
1259
+ parentContext: parentMatch?.routeContext ?? {},
1260
+ context: parentMatch?.context ?? this?.options.context ?? {},
1261
+ params: match.params,
1262
+ search: match.search
1263
+ }) || {};
1264
+ const context = {
1265
+ ...(parentMatch?.context ?? this?.options.context),
1266
+ ...routeContext
1267
+ };
1268
+ return {
1269
+ context,
1270
+ routeContext
1271
+ };
1272
+ } catch (err) {
1273
+ route.options.onError?.(err);
1274
+ throw err;
1977
1275
  }
1276
+ })();
1277
+ Object.assign(match, {
1278
+ ...contextInfo
1978
1279
  });
1979
- router.state = _extends({}, router.state, {
1980
- location: router.location,
1981
- matches,
1982
- pending: undefined,
1983
- status: 'idle'
1984
- });
1985
- router.notify();
1986
- router.resolveNavigation();
1987
- },
1988
- cleanMatchCache: () => {
1989
- const now = Date.now();
1990
- Object.keys(router.matchCache).forEach(matchId => {
1991
- const entry = router.matchCache[matchId]; // Don't remove loading matches
1992
-
1993
- if (entry.match.status === 'loading') {
1994
- return;
1995
- } // Do not remove successful matches that are still valid
1996
-
1997
-
1998
- if (entry.gc > 0 && entry.gc > now) {
1999
- return;
2000
- } // Everything else gets removed
2001
-
2002
-
2003
- delete router.matchCache[matchId];
2004
- });
2005
- },
2006
- loadRoute: async function loadRoute(navigateOpts) {
2007
- if (navigateOpts === void 0) {
2008
- navigateOpts = router.location;
2009
- }
2010
-
2011
- const next = router.buildNext(navigateOpts);
2012
- const matches = router.matchRoutes(next.pathname, {
2013
- strictParseParams: true
2014
- });
2015
- await router.loadMatches(matches);
2016
- return matches;
2017
- },
2018
- preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
2019
- var _ref3, _ref4, _loaderOpts$maxAge, _ref5, _ref6, _loaderOpts$gcMaxAge;
2020
-
2021
- if (navigateOpts === void 0) {
2022
- navigateOpts = router.location;
2023
- }
2024
-
2025
- const next = router.buildNext(navigateOpts);
2026
- const matches = router.matchRoutes(next.pathname, {
2027
- strictParseParams: true
2028
- });
2029
- await router.loadMatches(matches, {
2030
- preload: true,
2031
- maxAge: (_ref3 = (_ref4 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref4 : router.options.defaultLoaderMaxAge) != null ? _ref3 : 0,
2032
- gcMaxAge: (_ref5 = (_ref6 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref6 : router.options.defaultLoaderGcMaxAge) != null ? _ref5 : 0
1280
+ });
1281
+ return matches;
1282
+ };
1283
+ loadMatches = async (resolvedMatches, opts) => {
1284
+ this.cleanMatches();
1285
+ if (!opts?.preload) {
1286
+ resolvedMatches.forEach(match => {
1287
+ // Update each match with its latest route data
1288
+ this.setRouteMatch(match.id, s => ({
1289
+ ...s,
1290
+ routeSearch: match.routeSearch,
1291
+ search: match.search,
1292
+ routeContext: match.routeContext,
1293
+ context: match.context,
1294
+ error: match.error,
1295
+ paramsError: match.paramsError,
1296
+ searchError: match.searchError,
1297
+ params: match.params
1298
+ }));
2033
1299
  });
2034
- return matches;
2035
- },
2036
- matchRoutes: (pathname, opts) => {
2037
- var _router$state$pending3, _router$state$pending4;
2038
-
2039
- router.cleanMatchCache();
2040
- const matches = [];
2041
-
2042
- if (!router.routeTree) {
2043
- return matches;
2044
- }
2045
-
2046
- 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 : [])];
2047
-
2048
- const recurse = async routes => {
2049
- var _parentMatch$params, _router$options$filte, _foundRoute$childRout;
2050
-
2051
- const parentMatch = last(matches);
2052
- let params = (_parentMatch$params = parentMatch == null ? void 0 : parentMatch.params) != null ? _parentMatch$params : {};
2053
- const filteredRoutes = (_router$options$filte = router.options.filterRoutes == null ? void 0 : router.options.filterRoutes(routes)) != null ? _router$options$filte : routes;
2054
- let foundRoutes = [];
2055
-
2056
- const findMatchInRoutes = (parentRoutes, routes) => {
2057
- routes.some(route => {
2058
- var _route$childRoutes, _route$childRoutes2, _route$options$caseSe;
2059
-
2060
- if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
2061
- return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
2062
- }
2063
-
2064
- const fuzzy = !!(route.routePath !== '/' || (_route$childRoutes2 = route.childRoutes) != null && _route$childRoutes2.length);
2065
- const matchParams = matchPathname(pathname, {
2066
- to: route.fullPath,
2067
- fuzzy,
2068
- caseSensitive: (_route$options$caseSe = route.options.caseSensitive) != null ? _route$options$caseSe : router.options.caseSensitive
2069
- });
2070
-
2071
- if (matchParams) {
2072
- let parsedParams;
2073
-
2074
- try {
2075
- var _route$options$parseP;
2076
-
2077
- parsedParams = (_route$options$parseP = route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) != null ? _route$options$parseP : matchParams;
2078
- } catch (err) {
2079
- if (opts != null && opts.strictParseParams) {
2080
- throw err;
2081
- }
2082
- }
2083
-
2084
- params = _extends({}, params, parsedParams);
2085
- }
1300
+ }
1301
+ let firstBadMatchIndex;
2086
1302
 
2087
- if (!!matchParams) {
2088
- foundRoutes = [...parentRoutes, route];
1303
+ // Check each match middleware to see if the route can be accessed
1304
+ try {
1305
+ for (const [index, match] of resolvedMatches.entries()) {
1306
+ const route = this.getRoute(match.routeId);
1307
+ const handleError = (err, handler) => {
1308
+ firstBadMatchIndex = firstBadMatchIndex ?? index;
1309
+ handler = handler || route.options.onError;
1310
+ if (isRedirect(err)) {
1311
+ throw err;
1312
+ }
1313
+ try {
1314
+ handler?.(err);
1315
+ } catch (errorHandlerErr) {
1316
+ err = errorHandlerErr;
1317
+ if (isRedirect(errorHandlerErr)) {
1318
+ throw errorHandlerErr;
2089
1319
  }
2090
-
2091
- return !!foundRoutes.length;
2092
- });
2093
- return !!foundRoutes.length;
1320
+ }
1321
+ console.log('set error');
1322
+ this.setRouteMatch(match.id, s => ({
1323
+ ...s,
1324
+ error: err,
1325
+ status: 'error',
1326
+ updatedAt: Date.now()
1327
+ }));
2094
1328
  };
2095
-
2096
- findMatchInRoutes([], filteredRoutes);
2097
-
2098
- if (!foundRoutes.length) {
2099
- return;
1329
+ if (match.paramsError) {
1330
+ handleError(match.paramsError, route.options.onParseParamsError);
2100
1331
  }
2101
-
2102
- foundRoutes.forEach(foundRoute => {
2103
- var _router$matchCache$ma;
2104
-
2105
- const interpolatedPath = interpolatePath(foundRoute.routePath, params);
2106
- const matchId = interpolatePath(foundRoute.routeId, params, true);
2107
- const match = existingMatches.find(d => d.matchId === matchId) || ((_router$matchCache$ma = router.matchCache[matchId]) == null ? void 0 : _router$matchCache$ma.match) || createRouteMatch(router, foundRoute, {
2108
- parentMatch,
2109
- matchId,
2110
- params,
2111
- pathname: joinPaths([pathname, interpolatedPath])
1332
+ if (match.searchError) {
1333
+ handleError(match.searchError, route.options.onValidateSearchError);
1334
+ }
1335
+ let didError = false;
1336
+ try {
1337
+ await route.options.beforeLoad?.({
1338
+ ...match,
1339
+ preload: !!opts?.preload
2112
1340
  });
2113
- matches.push(match);
2114
- });
2115
- const foundRoute = last(foundRoutes);
2116
-
2117
- if ((_foundRoute$childRout = foundRoute.childRoutes) != null && _foundRoute$childRout.length) {
2118
- recurse(foundRoute.childRoutes);
1341
+ } catch (err) {
1342
+ handleError(err, route.options.onBeforeLoadError);
1343
+ didError = true;
2119
1344
  }
2120
- };
2121
-
2122
- recurse([router.routeTree]);
2123
- cascadeLoaderData(matches);
2124
- return matches;
2125
- },
2126
- loadMatches: async (resolvedMatches, loaderOpts) => {
2127
- const matchPromises = resolvedMatches.map(async match => {
2128
- // Validate the match (loads search params etc)
2129
- match.__.validate();
2130
-
2131
- match.load(loaderOpts);
2132
1345
 
2133
- if (match.__.loadPromise) {
2134
- // Wait for the first sign of activity from the match
2135
- await match.__.loadPromise;
1346
+ // If we errored, do not run the next matches' middleware
1347
+ if (didError) {
1348
+ break;
2136
1349
  }
2137
- });
2138
- router.notify();
2139
- await Promise.all(matchPromises);
2140
- },
2141
- invalidateRoute: opts => {
2142
- var _router$state$pending5, _router$state$pending6;
2143
-
2144
- const next = router.buildNext(opts);
2145
- const unloadedMatchIds = router.matchRoutes(next.pathname).map(d => d.matchId);
2146
- [...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 => {
2147
- if (unloadedMatchIds.includes(match.matchId)) {
2148
- match.invalidate();
1350
+ }
1351
+ } catch (err) {
1352
+ if (!opts?.preload) {
1353
+ this.navigate(err);
1354
+ }
1355
+ throw err;
1356
+ }
1357
+ const validResolvedMatches = resolvedMatches.slice(0, firstBadMatchIndex);
1358
+ const matchPromises = [];
1359
+ validResolvedMatches.forEach((match, index) => {
1360
+ matchPromises.push((async () => {
1361
+ const parentMatchPromise = matchPromises[index - 1];
1362
+ const route = this.getRoute(match.routeId);
1363
+ if (match.isFetching || match.status === 'success' && !this.getIsInvalid({
1364
+ matchId: match.id,
1365
+ preload: opts?.preload
1366
+ })) {
1367
+ return this.getRouteMatch(match.id)?.loadPromise;
2149
1368
  }
2150
- });
2151
- },
2152
- reload: () => router.__.navigate({
1369
+ const fetchedAt = Date.now();
1370
+ const checkLatest = () => {
1371
+ const latest = this.getRouteMatch(match.id);
1372
+ return latest && latest.fetchedAt !== fetchedAt ? latest.loadPromise : undefined;
1373
+ };
1374
+ const load = async () => {
1375
+ let latestPromise;
1376
+ const handleError = err => {
1377
+ if (isRedirect(err)) {
1378
+ if (!opts?.preload) {
1379
+ this.navigate(err);
1380
+ }
1381
+ return true;
1382
+ }
1383
+ return false;
1384
+ };
1385
+ try {
1386
+ const componentsPromise = Promise.all(componentTypes.map(async type => {
1387
+ const component = route.options[type];
1388
+ if (component?.preload) {
1389
+ await component.preload();
1390
+ }
1391
+ }));
1392
+ const loaderPromise = route.options.loader?.({
1393
+ ...match,
1394
+ preload: !!opts?.preload,
1395
+ parentMatchPromise
1396
+ });
1397
+ const [_, loader] = await Promise.all([componentsPromise, loaderPromise]);
1398
+ if (latestPromise = checkLatest()) return await latestPromise;
1399
+ this.setRouteMatchData(match.id, () => loader, opts);
1400
+ } catch (loaderError) {
1401
+ if (latestPromise = checkLatest()) return await latestPromise;
1402
+ handleError(loaderError);
1403
+ let error = loaderError;
1404
+ try {
1405
+ if (route.options.onLoadError) {
1406
+ route.options.onLoadError?.(loaderError);
1407
+ } else {
1408
+ route.options.onError?.(loaderError);
1409
+ }
1410
+ } catch (errorHandlerErr) {
1411
+ error = errorHandlerErr;
1412
+ handleError(error);
1413
+ }
1414
+ console.log('set error');
1415
+ this.setRouteMatch(match.id, s => ({
1416
+ ...s,
1417
+ error: error,
1418
+ status: 'error',
1419
+ isFetching: false,
1420
+ updatedAt: Date.now()
1421
+ }));
1422
+ console.log(this.getRouteMatch(match.id)?.status);
1423
+ }
1424
+ };
1425
+ const loadPromise = load();
1426
+ this.setRouteMatch(match.id, s => ({
1427
+ ...s,
1428
+ status: s.status !== 'success' ? 'pending' : s.status,
1429
+ isFetching: true,
1430
+ loadPromise,
1431
+ fetchedAt,
1432
+ invalid: false
1433
+ }));
1434
+ await loadPromise;
1435
+ })());
1436
+ });
1437
+ await Promise.all(matchPromises);
1438
+ };
1439
+ reload = () => {
1440
+ return this.navigate({
2153
1441
  fromCurrent: true,
2154
1442
  replace: true,
2155
1443
  search: true
2156
- }),
2157
- resolvePath: (from, path) => {
2158
- return resolvePath(router.basepath, from, cleanPath(path));
2159
- },
2160
- matchRoute: (location, opts) => {
2161
- var _location$from;
2162
-
2163
- // const location = router.buildNext(opts)
2164
- location = _extends({}, location, {
2165
- to: location.to ? router.resolvePath((_location$from = location.from) != null ? _location$from : '', location.to) : undefined
2166
- });
2167
- const next = router.buildNext(location);
2168
-
2169
- if (opts != null && opts.pending) {
2170
- var _router$state$pending7;
2171
-
2172
- if (!((_router$state$pending7 = router.state.pending) != null && _router$state$pending7.location)) {
2173
- return false;
2174
- }
1444
+ });
1445
+ };
1446
+ resolvePath = (from, path) => {
1447
+ return resolvePath(this.basepath, from, cleanPath(path));
1448
+ };
1449
+ navigate = async ({
1450
+ from,
1451
+ to = '',
1452
+ search,
1453
+ hash,
1454
+ replace,
1455
+ params
1456
+ }) => {
1457
+ // If this link simply reloads the current route,
1458
+ // make sure it has a new key so it will trigger a data refresh
1459
+
1460
+ // If this `to` is a valid external URL, return
1461
+ // null for LinkUtils
1462
+ const toString = String(to);
1463
+ const fromString = typeof from === 'undefined' ? from : String(from);
1464
+ let isExternal;
1465
+ try {
1466
+ new URL(`${toString}`);
1467
+ isExternal = true;
1468
+ } catch (e) {}
1469
+ invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1470
+ return this.#commitLocation({
1471
+ from: fromString,
1472
+ to: toString,
1473
+ search,
1474
+ hash,
1475
+ replace,
1476
+ params
1477
+ });
1478
+ };
1479
+ matchRoute = (location, opts) => {
1480
+ location = {
1481
+ ...location,
1482
+ to: location.to ? this.resolvePath(location.from ?? '', location.to) : undefined
1483
+ };
1484
+ const next = this.buildNext(location);
1485
+ if (opts?.pending && this.state.status !== 'pending') {
1486
+ return false;
1487
+ }
1488
+ const baseLocation = opts?.pending ? this.state.location : this.state.resolvedLocation;
1489
+ if (!baseLocation) {
1490
+ return false;
1491
+ }
1492
+ const match = matchPathname(this.basepath, baseLocation.pathname, {
1493
+ ...opts,
1494
+ to: next.pathname
1495
+ });
1496
+ if (!match) {
1497
+ return false;
1498
+ }
1499
+ if (opts?.includeSearch ?? true) {
1500
+ return partialDeepEqual(baseLocation.search, next.search) ? match : false;
1501
+ }
1502
+ return match;
1503
+ };
1504
+ buildLink = ({
1505
+ from,
1506
+ to = '.',
1507
+ search,
1508
+ params,
1509
+ hash,
1510
+ target,
1511
+ replace,
1512
+ activeOptions,
1513
+ preload,
1514
+ preloadDelay: userPreloadDelay,
1515
+ disabled,
1516
+ state
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
2175
1523
 
2176
- return !!matchPathname(router.state.pending.location.pathname, _extends({}, opts, {
2177
- to: next.pathname
2178
- }));
1524
+ try {
1525
+ new URL(`${to}`);
1526
+ return {
1527
+ type: 'external',
1528
+ href: to
1529
+ };
1530
+ } catch (e) {}
1531
+ const nextOpts = {
1532
+ from,
1533
+ to,
1534
+ search,
1535
+ params,
1536
+ hash,
1537
+ replace,
1538
+ state
1539
+ };
1540
+ const next = this.buildNext(nextOpts);
1541
+ preload = preload ?? this.options.defaultPreload;
1542
+ const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
1543
+
1544
+ // Compare path/hash for matches
1545
+ const currentPathSplit = this.state.location.pathname.split('/');
1546
+ const nextPathSplit = next.pathname.split('/');
1547
+ const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
1548
+ // Combine the matches based on user options
1549
+ const pathTest = activeOptions?.exact ? this.state.location.pathname === next.pathname : pathIsFuzzyEqual;
1550
+ const hashTest = activeOptions?.includeHash ? this.state.location.hash === next.hash : true;
1551
+ const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(this.state.location.search, next.search) : true;
1552
+
1553
+ // The final "active" test
1554
+ const isActive = pathTest && hashTest && searchTest;
1555
+
1556
+ // The click handler
1557
+ const handleClick = e => {
1558
+ if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
1559
+ e.preventDefault();
1560
+
1561
+ // All is well? Navigate!
1562
+ this.#commitLocation(nextOpts);
2179
1563
  }
1564
+ };
2180
1565
 
2181
- return !!matchPathname(router.state.location.pathname, _extends({}, opts, {
2182
- to: next.pathname
2183
- }));
2184
- },
2185
- navigate: async _ref7 => {
2186
- let {
2187
- from,
2188
- to = '.',
2189
- search,
2190
- hash,
2191
- replace,
2192
- params
2193
- } = _ref7;
2194
- // If this link simply reloads the current route,
2195
- // make sure it has a new key so it will trigger a data refresh
2196
- // If this `to` is a valid external URL, return
2197
- // null for LinkUtils
2198
- const toString = String(to);
2199
- const fromString = String(from);
2200
- let isExternal;
2201
-
2202
- try {
2203
- new URL("" + toString);
2204
- isExternal = true;
2205
- } catch (e) {}
2206
-
2207
- invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2208
- return router.__.navigate({
2209
- from: fromString,
2210
- to: toString,
2211
- search,
2212
- hash,
2213
- replace,
2214
- params
1566
+ // The click handler
1567
+ const handleFocus = e => {
1568
+ if (preload) {
1569
+ this.preloadRoute(nextOpts).catch(err => {
1570
+ console.warn(err);
1571
+ console.warn('Error preloading route! ☝️');
1572
+ });
1573
+ }
1574
+ };
1575
+ const handleTouchStart = e => {
1576
+ this.preloadRoute(nextOpts).catch(err => {
1577
+ console.warn(err);
1578
+ console.warn('Error preloading route! ☝️');
2215
1579
  });
2216
- },
2217
- buildLink: _ref8 => {
2218
- var _preload, _ref9;
2219
-
2220
- let {
2221
- from,
2222
- to = '.',
2223
- search,
2224
- params,
2225
- hash,
2226
- target,
2227
- replace,
2228
- activeOptions,
2229
- preload,
2230
- preloadMaxAge: userPreloadMaxAge,
2231
- preloadGcMaxAge: userPreloadGcMaxAge,
2232
- preloadDelay: userPreloadDelay,
2233
- disabled
2234
- } = _ref8;
2235
-
2236
- // If this link simply reloads the current route,
2237
- // make sure it has a new key so it will trigger a data refresh
2238
- // If this `to` is a valid external URL, return
2239
- // null for LinkUtils
2240
- try {
2241
- new URL("" + to);
2242
- return {
2243
- type: 'external',
2244
- href: to
2245
- };
2246
- } catch (e) {}
2247
-
2248
- const nextOpts = {
2249
- from,
2250
- to,
2251
- search,
2252
- params,
2253
- hash,
2254
- replace
2255
- };
2256
- const next = router.buildNext(nextOpts);
2257
- preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
2258
- const preloadDelay = (_ref9 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref9 : 0; // Compare path/hash for matches
2259
-
2260
- const pathIsEqual = router.state.location.pathname === next.pathname;
2261
- const currentPathSplit = router.state.location.pathname.split('/');
2262
- const nextPathSplit = next.pathname.split('/');
2263
- const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
2264
- const hashIsEqual = router.state.location.hash === next.hash; // Combine the matches based on user options
2265
-
2266
- const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
2267
- const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true; // The final "active" test
2268
-
2269
- const isActive = pathTest && hashTest; // The click handler
2270
-
2271
- const handleClick = e => {
2272
- if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
2273
- e.preventDefault();
2274
-
2275
- if (pathIsEqual && !search && !hash) {
2276
- router.invalidateRoute(nextOpts);
2277
- } // All is well? Navigate!)
2278
-
2279
-
2280
- router.__.navigate(nextOpts);
2281
- }
2282
- }; // The click handler
2283
-
2284
-
2285
- const handleFocus = e => {
2286
- if (preload) {
2287
- router.preloadRoute(nextOpts, {
2288
- maxAge: userPreloadMaxAge,
2289
- gcMaxAge: userPreloadGcMaxAge
2290
- });
2291
- }
2292
- };
2293
-
2294
- const handleEnter = e => {
2295
- const target = e.target || {};
2296
-
2297
- if (preload) {
2298
- if (target.preloadTimeout) {
2299
- return;
2300
- }
2301
-
2302
- target.preloadTimeout = setTimeout(() => {
2303
- target.preloadTimeout = null;
2304
- router.preloadRoute(nextOpts, {
2305
- maxAge: userPreloadMaxAge,
2306
- gcMaxAge: userPreloadGcMaxAge
2307
- });
2308
- }, preloadDelay);
2309
- }
2310
- };
2311
-
2312
- const handleLeave = e => {
2313
- const target = e.target || {};
2314
-
1580
+ };
1581
+ const handleEnter = e => {
1582
+ const target = e.target || {};
1583
+ if (preload) {
2315
1584
  if (target.preloadTimeout) {
2316
- clearTimeout(target.preloadTimeout);
2317
- target.preloadTimeout = null;
1585
+ return;
2318
1586
  }
2319
- };
2320
-
1587
+ target.preloadTimeout = setTimeout(() => {
1588
+ target.preloadTimeout = null;
1589
+ this.preloadRoute(nextOpts).catch(err => {
1590
+ console.warn(err);
1591
+ console.warn('Error preloading route! ☝️');
1592
+ });
1593
+ }, preloadDelay);
1594
+ }
1595
+ };
1596
+ const handleLeave = e => {
1597
+ const target = e.target || {};
1598
+ if (target.preloadTimeout) {
1599
+ clearTimeout(target.preloadTimeout);
1600
+ target.preloadTimeout = null;
1601
+ }
1602
+ };
1603
+ return {
1604
+ type: 'internal',
1605
+ next,
1606
+ handleFocus,
1607
+ handleClick,
1608
+ handleEnter,
1609
+ handleLeave,
1610
+ handleTouchStart,
1611
+ isActive,
1612
+ disabled
1613
+ };
1614
+ };
1615
+ dehydrate = () => {
1616
+ return {
1617
+ state: pick(this.state, ['location', 'status', 'lastUpdated'])
1618
+ };
1619
+ };
1620
+ hydrate = async __do_not_use_server_ctx => {
1621
+ let _ctx = __do_not_use_server_ctx;
1622
+ // Client hydrates from window
1623
+ if (typeof document !== 'undefined') {
1624
+ _ctx = window.__TSR_DEHYDRATED__;
1625
+ }
1626
+ invariant(_ctx, 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?');
1627
+ const ctx = _ctx;
1628
+ this.dehydratedData = ctx.payload;
1629
+ this.options.hydrate?.(ctx.payload);
1630
+ const routerState = ctx.router.state;
1631
+ this.__store.setState(s => {
2321
1632
  return {
2322
- type: 'internal',
2323
- next,
2324
- handleFocus,
2325
- handleClick,
2326
- handleEnter,
2327
- handleLeave,
2328
- isActive,
2329
- disabled
1633
+ ...s,
1634
+ ...routerState,
1635
+ resolvedLocation: routerState.location
2330
1636
  };
2331
- },
2332
- buildNext: opts => {
2333
- const next = router.__.buildLocation(opts);
2334
-
2335
- const matches = router.matchRoutes(next.pathname);
2336
-
2337
- const __preSearchFilters = matches.map(match => {
2338
- var _match$options$preSea;
2339
-
2340
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
2341
- }).flat().filter(Boolean);
2342
-
2343
- const __postSearchFilters = matches.map(match => {
2344
- var _match$options$postSe;
2345
-
2346
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
2347
- }).flat().filter(Boolean);
2348
-
2349
- return router.__.buildLocation(_extends({}, opts, {
2350
- __preSearchFilters,
2351
- __postSearchFilters
2352
- }));
2353
- },
2354
- __: {
2355
- buildRouteTree: rootRouteConfig => {
2356
- const recurseRoutes = (routeConfigs, parent) => {
2357
- return routeConfigs.map(routeConfig => {
2358
- const routeOptions = routeConfig.options;
2359
- const route = createRoute(routeConfig, routeOptions, parent, router);
2360
- const existingRoute = router.routesById[route.routeId];
2361
-
2362
- if (existingRoute) {
2363
- {
2364
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
2365
- }
2366
-
2367
- throw new Error();
2368
- }
2369
- router.routesById[route.routeId] = route;
2370
- const children = routeConfig.children;
2371
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2372
- return route;
2373
- });
2374
- };
2375
-
2376
- const routes = recurseRoutes([rootRouteConfig]);
2377
- return routes[0];
2378
- },
2379
- parseLocation: (location, previousLocation) => {
2380
- var _location$hash$split$;
2381
-
2382
- const parsedSearch = router.options.parseSearch(location.search);
2383
- return {
2384
- pathname: location.pathname,
2385
- searchStr: location.search,
2386
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2387
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
2388
- href: "" + location.pathname + location.search + location.hash,
2389
- state: location.state,
2390
- key: location.key
2391
- };
2392
- },
2393
- navigate: location => {
2394
- const next = router.buildNext(location);
2395
- return router.__.commitLocation(next, location.replace);
2396
- },
2397
- buildLocation: function buildLocation(dest) {
2398
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
2399
-
2400
- if (dest === void 0) {
2401
- dest = {};
2402
- }
2403
-
2404
- // const resolvedFrom: Location = {
2405
- // ...router.location,
2406
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
1637
+ });
1638
+ await this.load();
1639
+ return;
1640
+ };
1641
+ injectedHtml = [];
1642
+ injectHtml = async html => {
1643
+ this.injectedHtml.push(html);
1644
+ };
1645
+ dehydrateData = (key, getData) => {
1646
+ if (typeof document === 'undefined') {
1647
+ const strKey = typeof key === 'string' ? key : JSON.stringify(key);
1648
+ this.injectHtml(async () => {
1649
+ const id = `__TSR_DEHYDRATED__${strKey}`;
1650
+ const data = typeof getData === 'function' ? await getData() : getData;
1651
+ return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
1652
+ ;(() => {
1653
+ var el = document.getElementById('${id}')
1654
+ el.parentElement.removeChild(el)
1655
+ })()
1656
+ </script>`;
1657
+ });
1658
+ return () => this.hydrateData(key);
1659
+ }
1660
+ return () => undefined;
1661
+ };
1662
+ hydrateData = key => {
1663
+ if (typeof document !== 'undefined') {
1664
+ const strKey = typeof key === 'string' ? key : JSON.stringify(key);
1665
+ return window[`__TSR_DEHYDRATED__${strKey}`];
1666
+ }
1667
+ return undefined;
1668
+ };
2407
1669
 
2408
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1670
+ // resolveMatchPromise = (matchId: string, key: string, value: any) => {
1671
+ // this.state.matches
1672
+ // .find((d) => d.id === matchId)
1673
+ // ?.__promisesByKey[key]?.resolve(value)
1674
+ // }
2409
1675
 
2410
- const fromMatches = router.matchRoutes(router.location.pathname, {
2411
- strictParseParams: true
1676
+ #buildRouteTree = routeTree => {
1677
+ this.routeTree = routeTree;
1678
+ this.routesById = {};
1679
+ this.routesByPath = {};
1680
+ this.flatRoutes = [];
1681
+ const recurseRoutes = routes => {
1682
+ routes.forEach((route, i) => {
1683
+ route.init({
1684
+ originalIndex: i,
1685
+ router: this
2412
1686
  });
2413
- const toMatches = router.matchRoutes(pathname);
2414
-
2415
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
2416
-
2417
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
2418
-
2419
- if (nextParams) {
2420
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2421
- Object.assign({}, nextParams, fn(nextParams));
2422
- });
1687
+ const existingRoute = this.routesById[route.id];
1688
+ invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
1689
+ this.routesById[route.id] = route;
1690
+ if (!route.isRoot && route.path) {
1691
+ const trimmedFullPath = trimPathRight(route.fullPath);
1692
+ if (!this.routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
1693
+ this.routesByPath[trimmedFullPath] = route;
1694
+ }
2423
1695
  }
2424
-
2425
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
2426
-
2427
- 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
2428
-
2429
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2430
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
2431
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2432
- : {}; // Then post filters
2433
-
2434
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2435
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
2436
- const searchStr = router.options.stringifySearch(search);
2437
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
2438
- hash = hash ? "#" + hash : '';
2439
- return {
2440
- pathname,
2441
- search,
2442
- searchStr,
2443
- state: router.location.state,
2444
- hash,
2445
- href: "" + pathname + searchStr + hash,
2446
- key: dest.key
2447
- };
2448
- },
2449
- commitLocation: (next, replace) => {
2450
- const id = '' + Date.now() + Math.random();
2451
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
2452
- let nextAction = 'replace';
2453
-
2454
- if (!replace) {
2455
- nextAction = 'push';
1696
+ const children = route.children;
1697
+ if (children?.length) {
1698
+ recurseRoutes(children);
2456
1699
  }
1700
+ });
1701
+ };
1702
+ recurseRoutes([routeTree]);
1703
+ this.flatRoutes = Object.values(this.routesByPath).map((d, i) => {
1704
+ const trimmed = trimPath(d.fullPath);
1705
+ const parsed = parsePathname(trimmed);
1706
+ while (parsed.length > 1 && parsed[0]?.value === '/') {
1707
+ parsed.shift();
1708
+ }
1709
+ const score = parsed.map(d => {
1710
+ if (d.type === 'param') {
1711
+ return 0.5;
1712
+ }
1713
+ if (d.type === 'wildcard') {
1714
+ return 0.25;
1715
+ }
1716
+ return 1;
1717
+ });
1718
+ return {
1719
+ child: d,
1720
+ trimmed,
1721
+ parsed,
1722
+ index: i,
1723
+ score
1724
+ };
1725
+ }).sort((a, b) => {
1726
+ let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
1727
+ if (isIndex !== 0) return isIndex;
1728
+ const length = Math.min(a.score.length, b.score.length);
1729
+
1730
+ // Sort by length of score
1731
+ if (a.score.length !== b.score.length) {
1732
+ return b.score.length - a.score.length;
1733
+ }
2457
1734
 
2458
- const isSameUrl = router.__.parseLocation(history.location).href === next.href;
2459
-
2460
- if (isSameUrl && !next.key) {
2461
- nextAction = 'replace';
1735
+ // Sort by min available score
1736
+ for (let i = 0; i < length; i++) {
1737
+ if (a.score[i] !== b.score[i]) {
1738
+ return b.score[i] - a.score[i];
2462
1739
  }
1740
+ }
2463
1741
 
2464
- if (nextAction === 'replace') {
2465
- history.replace({
2466
- pathname: next.pathname,
2467
- hash: next.hash,
2468
- search: next.searchStr
2469
- }, _extends({
2470
- id
2471
- }, next.state));
2472
- } else {
2473
- history.push({
2474
- pathname: next.pathname,
2475
- hash: next.hash,
2476
- search: next.searchStr
2477
- }, {
2478
- id
2479
- });
1742
+ // Sort by min available parsed value
1743
+ for (let i = 0; i < length; i++) {
1744
+ if (a.parsed[i].value !== b.parsed[i].value) {
1745
+ return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
2480
1746
  }
1747
+ }
2481
1748
 
2482
- router.navigationPromise = new Promise(resolve => {
2483
- const previousNavigationResolve = router.resolveNavigation;
1749
+ // Sort by length of trimmed full path
1750
+ if (a.trimmed !== b.trimmed) {
1751
+ return a.trimmed > b.trimmed ? 1 : -1;
1752
+ }
2484
1753
 
2485
- router.resolveNavigation = () => {
2486
- previousNavigationResolve();
2487
- resolve();
2488
- };
1754
+ // Sort by original index
1755
+ return a.index - b.index;
1756
+ }).map((d, i) => {
1757
+ d.child.rank = i;
1758
+ return d.child;
1759
+ });
1760
+ };
1761
+ #parseLocation = previousLocation => {
1762
+ let {
1763
+ pathname,
1764
+ search,
1765
+ hash,
1766
+ state
1767
+ } = this.history.location;
1768
+ const parsedSearch = this.options.parseSearch(search);
1769
+ return {
1770
+ pathname: pathname,
1771
+ searchStr: search,
1772
+ search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1773
+ hash: hash.split('#').reverse()[0] ?? '',
1774
+ href: `${pathname}${search}${hash}`,
1775
+ state: state,
1776
+ key: state?.key || '__init__'
1777
+ };
1778
+ };
1779
+ #buildLocation = (dest = {}) => {
1780
+ dest.fromCurrent = dest.fromCurrent ?? dest.to === '';
1781
+ const fromPathname = dest.fromCurrent ? this.state.location.pathname : dest.from ?? this.state.location.pathname;
1782
+ let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? ''}`);
1783
+ const fromMatches = this.matchRoutes(this.state.location.pathname, this.state.location.search);
1784
+ const prevParams = {
1785
+ ...last(fromMatches)?.params
1786
+ };
1787
+ let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1788
+ if (nextParams) {
1789
+ dest.__matches?.map(d => this.getRoute(d.routeId).options.stringifyParams).filter(Boolean).forEach(fn => {
1790
+ nextParams = {
1791
+ ...nextParams,
1792
+ ...fn(nextParams)
1793
+ };
1794
+ });
1795
+ }
1796
+ pathname = interpolatePath(pathname, nextParams ?? {});
1797
+ const preSearchFilters = dest.__matches?.map(match => this.getRoute(match.routeId).options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
1798
+ const postSearchFilters = dest.__matches?.map(match => this.getRoute(match.routeId).options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
1799
+
1800
+ // Pre filters first
1801
+ const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), this.state.location.search) : this.state.location.search;
1802
+
1803
+ // Then the link/navigate function
1804
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1805
+ : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
1806
+ : preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
1807
+ : {};
1808
+
1809
+ // Then post filters
1810
+ const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1811
+ const search = replaceEqualDeep(this.state.location.search, postFilteredSearch);
1812
+ const searchStr = this.options.stringifySearch(search);
1813
+ const hash = dest.hash === true ? this.state.location.hash : functionalUpdate(dest.hash, this.state.location.hash);
1814
+ const hashStr = hash ? `#${hash}` : '';
1815
+ const nextState = dest.state === true ? this.state.location.state : functionalUpdate(dest.state, this.state.location.state);
1816
+ return {
1817
+ pathname,
1818
+ search,
1819
+ searchStr,
1820
+ state: nextState,
1821
+ hash,
1822
+ href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
1823
+ key: dest.key
1824
+ };
1825
+ };
1826
+ #commitLocation = async location => {
1827
+ const next = this.buildNext(location);
1828
+ const id = '' + Date.now() + Math.random();
1829
+ if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
1830
+ let nextAction = 'replace';
1831
+ if (!location.replace) {
1832
+ nextAction = 'push';
1833
+ }
1834
+ const isSameUrl = this.state.location.href === next.href;
1835
+ if (isSameUrl && !next.key) {
1836
+ nextAction = 'replace';
1837
+ }
1838
+ const href = `${next.pathname}${next.searchStr}${next.hash ? `#${next.hash}` : ''}`;
1839
+ this.history[nextAction === 'push' ? 'push' : 'replace'](href, {
1840
+ id,
1841
+ ...next.state
1842
+ });
1843
+ return this.latestLoadPromise;
1844
+ };
1845
+ getRouteMatch = id => {
1846
+ return this.state.matchesById[id];
1847
+ };
1848
+ setRouteMatch = (id, updater) => {
1849
+ this.__store.setState(prev => {
1850
+ if (!prev.matchesById[id]) {
1851
+ console.warn(`No match found with id: ${id}`);
1852
+ }
1853
+ return {
1854
+ ...prev,
1855
+ matchesById: {
1856
+ ...prev.matchesById,
1857
+ [id]: updater(prev.matchesById[id])
1858
+ }
1859
+ };
1860
+ });
1861
+ };
1862
+ setRouteMatchData = (id, updater, opts) => {
1863
+ const match = this.getRouteMatch(id);
1864
+ if (!match) return;
1865
+ const route = this.getRoute(match.routeId);
1866
+ const updatedAt = opts?.updatedAt ?? Date.now();
1867
+ const preloadInvalidAt = updatedAt + (opts?.maxAge ?? route.options.preloadMaxAge ?? this.options.defaultPreloadMaxAge ?? 5000);
1868
+ const invalidAt = updatedAt + (opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? Infinity);
1869
+ console.log('set success');
1870
+ this.setRouteMatch(id, s => ({
1871
+ ...s,
1872
+ error: undefined,
1873
+ status: 'success',
1874
+ isFetching: false,
1875
+ updatedAt: Date.now(),
1876
+ loaderData: functionalUpdate(updater, s.loaderData),
1877
+ preloadInvalidAt,
1878
+ invalidAt
1879
+ }));
1880
+ if (this.state.matches.find(d => d.id === id)) ;
1881
+ };
1882
+ invalidate = async opts => {
1883
+ if (opts?.matchId) {
1884
+ this.setRouteMatch(opts.matchId, s => ({
1885
+ ...s,
1886
+ invalid: true
1887
+ }));
1888
+ const matchIndex = this.state.matches.findIndex(d => d.id === opts.matchId);
1889
+ const childMatch = this.state.matches[matchIndex + 1];
1890
+ if (childMatch) {
1891
+ return this.invalidate({
1892
+ matchId: childMatch.id,
1893
+ reload: false
2489
1894
  });
2490
- return router.navigationPromise;
2491
1895
  }
1896
+ } else {
1897
+ this.__store.batch(() => {
1898
+ Object.values(this.state.matchesById).forEach(match => {
1899
+ this.setRouteMatch(match.id, s => ({
1900
+ ...s,
1901
+ invalid: true
1902
+ }));
1903
+ });
1904
+ });
1905
+ }
1906
+ if (opts?.reload ?? true) {
1907
+ return this.reload();
2492
1908
  }
2493
1909
  };
2494
- router.update(userOptions); // Allow frameworks to hook into the router creation
2495
-
2496
- router.options.createRouter == null ? void 0 : router.options.createRouter(router);
2497
- return router;
1910
+ getIsInvalid = opts => {
1911
+ if (!opts?.matchId) {
1912
+ return !!this.state.matches.find(d => this.getIsInvalid({
1913
+ matchId: d.id,
1914
+ preload: opts?.preload
1915
+ }));
1916
+ }
1917
+ const match = this.getRouteMatch(opts?.matchId);
1918
+ if (!match) {
1919
+ return false;
1920
+ }
1921
+ const now = Date.now();
1922
+ return match.invalid || (opts?.preload ? match.preloadInvalidAt : match.invalidAt) < now;
1923
+ };
2498
1924
  }
2499
1925
 
1926
+ // Detect if we're in the DOM
1927
+ const isServer = typeof window === 'undefined' || !window.document.createElement;
1928
+ function getInitialRouterState() {
1929
+ return {
1930
+ status: 'idle',
1931
+ isFetching: false,
1932
+ resolvedLocation: null,
1933
+ location: null,
1934
+ matchesById: {},
1935
+ matchIds: [],
1936
+ pendingMatchIds: [],
1937
+ matches: [],
1938
+ pendingMatches: [],
1939
+ lastUpdated: Date.now()
1940
+ };
1941
+ }
2500
1942
  function isCtrlEvent(e) {
2501
1943
  return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2502
1944
  }
1945
+ function redirect(opts) {
1946
+ opts.isRedirect = true;
1947
+ return opts;
1948
+ }
1949
+ function isRedirect(obj) {
1950
+ return !!obj?.isRedirect;
1951
+ }
1952
+ class SearchParamError extends Error {}
1953
+ class PathParamError extends Error {}
1954
+ function escapeJSON(jsonString) {
1955
+ return jsonString.replace(/\\/g, '\\\\') // Escape backslashes
1956
+ .replace(/'/g, "\\'") // Escape single quotes
1957
+ .replace(/"/g, '\\"'); // Escape double quotes
1958
+ }
2503
1959
 
2504
- function cascadeLoaderData(matches) {
2505
- matches.forEach((match, index) => {
2506
- const parent = matches[index - 1];
1960
+ // A function that takes an import() argument which is a function and returns a new function that will
1961
+ // proxy arguments from the caller to the imported function, retaining all type
1962
+ // information along the way
1963
+ function lazyFn(fn, key) {
1964
+ return async (...args) => {
1965
+ const imported = await fn();
1966
+ return imported[key || 'default'](...args);
1967
+ };
1968
+ }
2507
1969
 
2508
- if (parent) {
2509
- match.loaderData = replaceEqualDeep(match.loaderData, _extends({}, parent.loaderData, match.routeLoaderData));
1970
+ Route.__onInit = route => {
1971
+ Object.assign(route, {
1972
+ useMatch: (opts = {}) => {
1973
+ return useMatch({
1974
+ ...opts,
1975
+ from: route.id
1976
+ });
1977
+ },
1978
+ useLoader: (opts = {}) => {
1979
+ return useLoader({
1980
+ ...opts,
1981
+ from: route.id
1982
+ });
1983
+ },
1984
+ useContext: (opts = {}) => {
1985
+ return useMatch({
1986
+ ...opts,
1987
+ from: route.id,
1988
+ select: d => opts?.select?.(d.context) ?? d.context
1989
+ });
1990
+ },
1991
+ useRouteContext: (opts = {}) => {
1992
+ return useMatch({
1993
+ ...opts,
1994
+ from: route.id,
1995
+ select: d => opts?.select?.(d.routeContext) ?? d.routeContext
1996
+ });
1997
+ },
1998
+ useSearch: (opts = {}) => {
1999
+ return useSearch({
2000
+ ...opts,
2001
+ from: route.id
2002
+ });
2003
+ },
2004
+ useParams: (opts = {}) => {
2005
+ return useParams({
2006
+ ...opts,
2007
+ from: route.id
2008
+ });
2510
2009
  }
2511
2010
  });
2512
- }
2011
+ };
2513
2012
 
2514
- 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"],
2515
- _excluded2 = ["pending", "caseSensitive", "children"],
2516
- _excluded3 = ["children", "router"];
2517
2013
  //
2518
- const matchesContext = /*#__PURE__*/React__namespace.createContext(null);
2519
- const routerContext = /*#__PURE__*/React__namespace.createContext(null); // Detect if we're in the DOM
2520
- function MatchesProvider(props) {
2521
- return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, props);
2522
- }
2523
2014
 
2524
- const useRouterSubscription = router => {
2525
- shim.useSyncExternalStore(cb => router.subscribe(() => cb()), () => router.state, () => router.state);
2526
- };
2527
-
2528
- function createReactRouter(opts) {
2529
- const makeRouteExt = (route, router) => {
2015
+ function lazyRouteComponent(importer, exportName) {
2016
+ let loadPromise;
2017
+ const load = () => {
2018
+ if (!loadPromise) {
2019
+ loadPromise = importer();
2020
+ }
2021
+ return loadPromise;
2022
+ };
2023
+ const lazyComp = /*#__PURE__*/React__namespace.lazy(async () => {
2024
+ const moduleExports = await load();
2025
+ const comp = moduleExports[exportName ?? 'default'];
2530
2026
  return {
2531
- useRoute: function useRoute(subRouteId) {
2532
- if (subRouteId === void 0) {
2533
- subRouteId = '.';
2534
- }
2535
-
2536
- const resolvedRouteId = router.resolvePath(route.routeId, subRouteId);
2537
- const resolvedRoute = router.getRoute(resolvedRouteId);
2538
- useRouterSubscription(router);
2539
- invariant(resolvedRoute, "Could not find a route for route \"" + resolvedRouteId + "\"! Did you forget to add it to your route config?");
2540
- return resolvedRoute;
2541
- },
2542
- linkProps: options => {
2543
- var _functionalUpdate, _functionalUpdate2;
2544
-
2545
- const {
2546
- // custom props
2547
- target,
2548
- activeProps = () => ({
2549
- className: 'active'
2550
- }),
2551
- inactiveProps = () => ({}),
2552
- disabled,
2553
- // element props
2554
- style,
2555
- className,
2556
- onClick,
2557
- onFocus,
2558
- onMouseEnter,
2559
- onMouseLeave
2560
- } = options,
2561
- rest = _objectWithoutPropertiesLoose(options, _excluded);
2562
-
2563
- const linkInfo = route.buildLink(options);
2564
-
2565
- if (linkInfo.type === 'external') {
2566
- const {
2567
- href
2568
- } = linkInfo;
2569
- return {
2570
- href
2571
- };
2572
- }
2573
-
2574
- const {
2575
- handleClick,
2576
- handleFocus,
2577
- handleEnter,
2578
- handleLeave,
2579
- isActive,
2580
- next
2581
- } = linkInfo;
2582
-
2583
- const reactHandleClick = e => {
2584
- React__namespace.startTransition(() => {
2585
- handleClick(e);
2586
- });
2587
- };
2588
-
2589
- const composeHandlers = handlers => e => {
2590
- e.persist();
2591
- handlers.forEach(handler => {
2592
- if (handler) handler(e);
2593
- });
2594
- }; // Get the active props
2595
-
2596
-
2597
- const resolvedActiveProps = isActive ? (_functionalUpdate = functionalUpdate(activeProps, {})) != null ? _functionalUpdate : {} : {}; // Get the inactive props
2598
-
2599
- const resolvedInactiveProps = isActive ? {} : (_functionalUpdate2 = functionalUpdate(inactiveProps, {})) != null ? _functionalUpdate2 : {};
2600
- return _extends$2({}, resolvedActiveProps, resolvedInactiveProps, rest, {
2601
- href: disabled ? undefined : next.href,
2602
- onClick: composeHandlers([reactHandleClick, onClick]),
2603
- onFocus: composeHandlers([handleFocus, onFocus]),
2604
- onMouseEnter: composeHandlers([handleEnter, onMouseEnter]),
2605
- onMouseLeave: composeHandlers([handleLeave, onMouseLeave]),
2606
- target,
2607
- style: _extends$2({}, style, resolvedActiveProps.style, resolvedInactiveProps.style),
2608
- className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined
2609
- }, disabled ? {
2610
- role: 'link',
2611
- 'aria-disabled': true
2612
- } : undefined, {
2613
- ['data-status']: isActive ? 'active' : undefined
2614
- });
2615
- },
2616
- Link: /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
2617
- const linkProps = route.linkProps(props);
2618
- useRouterSubscription(router);
2619
- return /*#__PURE__*/React__namespace.createElement("a", _extends$2({
2620
- ref: ref
2621
- }, linkProps, {
2622
- children: typeof props.children === 'function' ? props.children({
2623
- isActive: linkProps['data-status'] === 'active'
2624
- }) : props.children
2625
- }));
2626
- }),
2627
- MatchRoute: opts => {
2628
- const {
2629
- pending,
2630
- caseSensitive
2631
- } = opts,
2632
- rest = _objectWithoutPropertiesLoose(opts, _excluded2);
2633
-
2634
- const params = route.matchRoute(rest, {
2635
- pending,
2636
- caseSensitive
2637
- });
2638
-
2639
- if (!params) {
2640
- return null;
2641
- }
2027
+ default: comp
2028
+ };
2029
+ });
2030
+ lazyComp.preload = load;
2031
+ return lazyComp;
2032
+ }
2033
+ //
2642
2034
 
2643
- return typeof opts.children === 'function' ? opts.children(params) : opts.children;
2644
- }
2035
+ function useLinkProps(options) {
2036
+ const router = useRouter();
2037
+ const {
2038
+ // custom props
2039
+ type,
2040
+ children,
2041
+ target,
2042
+ activeProps = () => ({
2043
+ className: 'active'
2044
+ }),
2045
+ inactiveProps = () => ({}),
2046
+ activeOptions,
2047
+ disabled,
2048
+ // fromCurrent,
2049
+ hash,
2050
+ search,
2051
+ params,
2052
+ to = '.',
2053
+ preload,
2054
+ preloadDelay,
2055
+ replace,
2056
+ // element props
2057
+ style,
2058
+ className,
2059
+ onClick,
2060
+ onFocus,
2061
+ onMouseEnter,
2062
+ onMouseLeave,
2063
+ onTouchStart,
2064
+ ...rest
2065
+ } = options;
2066
+ const linkInfo = router.buildLink(options);
2067
+ if (linkInfo.type === 'external') {
2068
+ const {
2069
+ href
2070
+ } = linkInfo;
2071
+ return {
2072
+ href
2645
2073
  };
2074
+ }
2075
+ const {
2076
+ handleClick,
2077
+ handleFocus,
2078
+ handleEnter,
2079
+ handleLeave,
2080
+ handleTouchStart,
2081
+ isActive,
2082
+ next
2083
+ } = linkInfo;
2084
+ const handleReactClick = e => {
2085
+ if (options.startTransition ?? true) {
2086
+ (React__namespace.startTransition || (d => d))(() => {
2087
+ handleClick(e);
2088
+ });
2089
+ }
2090
+ };
2091
+ const composeHandlers = handlers => e => {
2092
+ if (e.persist) e.persist();
2093
+ handlers.filter(Boolean).forEach(handler => {
2094
+ if (e.defaultPrevented) return;
2095
+ handler(e);
2096
+ });
2646
2097
  };
2647
2098
 
2648
- const coreRouter = createRouter(_extends$2({}, opts, {
2649
- createRouter: router => {
2650
- const routerExt = {
2651
- useState: () => {
2652
- useRouterSubscription(router);
2653
- return router.state;
2654
- },
2655
- useMatch: (routeId, opts) => {
2656
- var _useMatches, _opts$strict;
2657
-
2658
- useRouterSubscription(router);
2659
- invariant(routeId !== rootRouteId, "\"" + rootRouteId + "\" cannot be used with useMatch! Did you mean to useRoute(\"" + rootRouteId + "\")?");
2660
- const runtimeMatch = (_useMatches = useMatches()) == null ? void 0 : _useMatches[0];
2661
- const match = router.state.matches.find(d => d.routeId === routeId);
2662
-
2663
- if ((_opts$strict = opts == null ? void 0 : opts.strict) != null ? _opts$strict : true) {
2664
- invariant(match, "Could not find an active match for \"" + routeId + "\"!");
2665
- 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?");
2666
- }
2099
+ // Get the active props
2100
+ const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {};
2667
2101
 
2668
- return match;
2669
- }
2670
- };
2671
- const routeExt = makeRouteExt(router.getRoute('/'), router);
2672
- Object.assign(router, routerExt, routeExt);
2673
- },
2674
- createRoute: _ref => {
2675
- let {
2676
- router,
2677
- route
2678
- } = _ref;
2679
- const routeExt = makeRouteExt(route, router);
2680
- Object.assign(route, routeExt);
2102
+ // Get the inactive props
2103
+ const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
2104
+ return {
2105
+ ...resolvedActiveProps,
2106
+ ...resolvedInactiveProps,
2107
+ ...rest,
2108
+ href: disabled ? undefined : next.href,
2109
+ onClick: composeHandlers([onClick, handleReactClick]),
2110
+ onFocus: composeHandlers([onFocus, handleFocus]),
2111
+ onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
2112
+ onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
2113
+ onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
2114
+ target,
2115
+ style: {
2116
+ ...style,
2117
+ ...resolvedActiveProps.style,
2118
+ ...resolvedInactiveProps.style
2681
2119
  },
2682
- loadComponent: async component => {
2683
- if (component.preload && typeof document !== 'undefined') {
2684
- component.preload(); // return await component.preload()
2685
- }
2686
-
2687
- return component;
2688
- }
2120
+ className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
2121
+ ...(disabled ? {
2122
+ role: 'link',
2123
+ 'aria-disabled': true
2124
+ } : undefined),
2125
+ ['data-status']: isActive ? 'active' : undefined
2126
+ };
2127
+ }
2128
+ const Link = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
2129
+ const linkProps = useLinkProps(props);
2130
+ return /*#__PURE__*/React__namespace.createElement("a", _extends({
2131
+ ref: ref
2132
+ }, linkProps, {
2133
+ children: typeof props.children === 'function' ? props.children({
2134
+ isActive: linkProps['data-status'] === 'active'
2135
+ }) : props.children
2689
2136
  }));
2690
- return coreRouter;
2137
+ });
2138
+ function Navigate(props) {
2139
+ const router = useRouter();
2140
+ React__namespace.useLayoutEffect(() => {
2141
+ router.navigate(props);
2142
+ }, []);
2143
+ return null;
2691
2144
  }
2692
- function RouterProvider(_ref2) {
2693
- let {
2694
- children,
2695
- router
2696
- } = _ref2,
2697
- rest = _objectWithoutPropertiesLoose(_ref2, _excluded3);
2698
-
2145
+ const matchIdsContext = /*#__PURE__*/React__namespace.createContext(null);
2146
+ const routerContext = /*#__PURE__*/React__namespace.createContext(null);
2147
+ function useRouterState(opts) {
2148
+ const router = useRouter();
2149
+ return useStore(router.__store, opts?.select);
2150
+ }
2151
+ function RouterProvider({
2152
+ router,
2153
+ ...rest
2154
+ }) {
2699
2155
  router.update(rest);
2700
- useRouterSubscription(router);
2701
2156
  React__namespace.useEffect(() => {
2702
- return router.mount();
2157
+ let unsub;
2158
+ React__namespace.startTransition(() => {
2159
+ unsub = router.mount();
2160
+ });
2161
+ return unsub;
2703
2162
  }, [router]);
2704
- return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2705
- value: {
2706
- router
2163
+ const Wrap = router.options.Wrap || React__namespace.Fragment;
2164
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
2165
+ fallback: null
2166
+ }, /*#__PURE__*/React__namespace.createElement(Wrap, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2167
+ value: router
2168
+ }, /*#__PURE__*/React__namespace.createElement(Matches, null))));
2169
+ }
2170
+ function Matches() {
2171
+ const router = useRouter();
2172
+ const matchIds = useRouterState({
2173
+ select: state => {
2174
+ const hasPendingComponent = state.pendingMatches.some(d => {
2175
+ const route = router.getRoute(d.routeId);
2176
+ return !!route?.options.pendingComponent;
2177
+ });
2178
+ if (hasPendingComponent) {
2179
+ console.log('hasPending');
2180
+ return state.pendingMatchIds;
2181
+ }
2182
+ return state.matchIds;
2183
+ }
2184
+ });
2185
+ return /*#__PURE__*/React__namespace.createElement(matchIdsContext.Provider, {
2186
+ value: [undefined, ...matchIds]
2187
+ }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
2188
+ errorComponent: ErrorComponent,
2189
+ onCatch: () => {
2190
+ warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
2707
2191
  }
2708
- }, /*#__PURE__*/React__namespace.createElement(MatchesProvider, {
2709
- value: router.state.matches
2710
- }, children != null ? children : /*#__PURE__*/React__namespace.createElement(Outlet, null)));
2192
+ }, /*#__PURE__*/React__namespace.createElement(Outlet, null)));
2711
2193
  }
2712
2194
  function useRouter() {
2713
2195
  const value = React__namespace.useContext(routerContext);
2714
- warning(!value, 'useRouter must be used inside a <Router> component!');
2715
- useRouterSubscription(value.router);
2716
- return value.router;
2196
+ warning(value, 'useRouter must be used inside a <Router> component!');
2197
+ return value;
2717
2198
  }
2718
- function useMatches() {
2719
- return React__namespace.useContext(matchesContext);
2199
+ function useMatches(opts) {
2200
+ const matchIds = React__namespace.useContext(matchIdsContext);
2201
+ return useRouterState({
2202
+ select: state => {
2203
+ const matches = state.matches.slice(state.matches.findIndex(d => d.id === matchIds[0]));
2204
+ return opts?.select?.(matches) ?? matches;
2205
+ }
2206
+ });
2720
2207
  }
2721
- function Outlet() {
2722
- var _ref3, _match$__$pendingComp, _match$__$errorCompon;
2723
-
2208
+ function useMatch(opts) {
2724
2209
  const router = useRouter();
2725
- const matches = useMatches().slice(1);
2726
- const match = matches[0];
2727
- const defaultPending = React__namespace.useCallback(() => null, []);
2728
-
2729
- if (!match) {
2210
+ const nearestMatchId = React__namespace.useContext(matchIdsContext)[0];
2211
+ const nearestMatchRouteId = router.getRouteMatch(nearestMatchId)?.routeId;
2212
+ const matchRouteId = useRouterState({
2213
+ select: state => {
2214
+ const matches = state.matches;
2215
+ const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatchId);
2216
+ return match.routeId;
2217
+ }
2218
+ });
2219
+ if (opts?.strict ?? true) {
2220
+ 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?`);
2221
+ }
2222
+ const match = useRouterState({
2223
+ select: state => {
2224
+ const matches = state.matches;
2225
+ const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatchId);
2226
+ invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
2227
+ return opts?.select?.(match) ?? match;
2228
+ }
2229
+ });
2230
+ return match;
2231
+ }
2232
+ function useLoader(opts) {
2233
+ return useMatch({
2234
+ ...opts,
2235
+ select: match => opts?.select?.(match.loaderData) ?? match.loaderData
2236
+ });
2237
+ }
2238
+ function useRouterContext(opts) {
2239
+ return useMatch({
2240
+ ...opts,
2241
+ select: match => opts?.select?.(match.context) ?? match.context
2242
+ });
2243
+ }
2244
+ function useRouteContext(opts) {
2245
+ return useMatch({
2246
+ ...opts,
2247
+ select: match => opts?.select?.(match.routeContext) ?? match.routeContext
2248
+ });
2249
+ }
2250
+ function useSearch(opts) {
2251
+ return useMatch({
2252
+ ...opts,
2253
+ select: match => {
2254
+ return opts?.select?.(match.search) ?? match.search;
2255
+ }
2256
+ });
2257
+ }
2258
+ function useParams(opts) {
2259
+ return useRouterState({
2260
+ select: state => {
2261
+ const params = last(state.matches)?.params;
2262
+ return opts?.select?.(params) ?? params;
2263
+ }
2264
+ });
2265
+ }
2266
+ function useNavigate(defaultOpts) {
2267
+ const router = useRouter();
2268
+ return React__namespace.useCallback(opts => {
2269
+ return router.navigate({
2270
+ ...defaultOpts,
2271
+ ...opts
2272
+ });
2273
+ }, []);
2274
+ }
2275
+ function useMatchRoute() {
2276
+ const router = useRouter();
2277
+ return React__namespace.useCallback(opts => {
2278
+ const {
2279
+ pending,
2280
+ caseSensitive,
2281
+ ...rest
2282
+ } = opts;
2283
+ return router.matchRoute(rest, {
2284
+ pending,
2285
+ caseSensitive
2286
+ });
2287
+ }, []);
2288
+ }
2289
+ function MatchRoute(props) {
2290
+ const matchRoute = useMatchRoute();
2291
+ const params = matchRoute(props);
2292
+ if (typeof props.children === 'function') {
2293
+ return props.children(params);
2294
+ }
2295
+ return !!params ? props.children : null;
2296
+ }
2297
+ function Outlet() {
2298
+ const matchIds = React__namespace.useContext(matchIdsContext).slice(1);
2299
+ if (!matchIds[0]) {
2730
2300
  return null;
2731
2301
  }
2732
-
2733
- const PendingComponent = (_ref3 = (_match$__$pendingComp = match.__.pendingComponent) != null ? _match$__$pendingComp : router.options.defaultPendingComponent) != null ? _ref3 : defaultPending;
2734
- const errorComponent = (_match$__$errorCompon = match.__.errorComponent) != null ? _match$__$errorCompon : router.options.defaultErrorComponent;
2735
- return /*#__PURE__*/React__namespace.createElement(MatchesProvider, {
2736
- value: matches
2737
- }, /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
2738
- fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, null)
2739
- }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
2740
- errorComponent: errorComponent
2741
- }, (() => {
2742
- if (match.status === 'error') {
2743
- throw match.error;
2302
+ return /*#__PURE__*/React__namespace.createElement(Match, {
2303
+ matchIds: matchIds
2304
+ });
2305
+ }
2306
+ const defaultPending = () => null;
2307
+ function Match({
2308
+ matchIds
2309
+ }) {
2310
+ const router = useRouter();
2311
+ const matchId = matchIds[0];
2312
+ const routeId = router.getRouteMatch(matchId).routeId;
2313
+ const route = router.getRoute(routeId);
2314
+ const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
2315
+ const errorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent;
2316
+ const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? !route.isRoot ? React__namespace.Suspense : SafeFragment;
2317
+ const ResolvedCatchBoundary = !!errorComponent ? CatchBoundary : SafeFragment;
2318
+ return /*#__PURE__*/React__namespace.createElement(matchIdsContext.Provider, {
2319
+ value: matchIds
2320
+ }, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
2321
+ fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, {
2322
+ useLoader: route.useLoader,
2323
+ useMatch: route.useMatch,
2324
+ useContext: route.useContext,
2325
+ useRouteContext: route.useRouteContext,
2326
+ useSearch: route.useSearch,
2327
+ useParams: route.useParams
2328
+ })
2329
+ }, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
2330
+ key: route.id,
2331
+ errorComponent: errorComponent,
2332
+ onCatch: () => {
2333
+ warning(false, `Error in route match: ${matchId}`);
2744
2334
  }
2745
-
2746
- if (match.status === 'success') {
2747
- var _ref4, _ref5;
2748
-
2749
- return /*#__PURE__*/React__namespace.createElement((_ref4 = (_ref5 = match.__.component) != null ? _ref5 : router.options.defaultComponent) != null ? _ref4 : Outlet);
2335
+ }, /*#__PURE__*/React__namespace.createElement(MatchInner, {
2336
+ matchId: matchId,
2337
+ PendingComponent: PendingComponent
2338
+ }))));
2339
+ }
2340
+ function MatchInner({
2341
+ matchId,
2342
+ PendingComponent
2343
+ }) {
2344
+ const router = useRouter();
2345
+ const match = useRouterState({
2346
+ select: d => {
2347
+ const match = d.matchesById[matchId];
2348
+ return pick(match, ['status', 'loadPromise', 'routeId', 'error']);
2750
2349
  }
2751
-
2752
- if (match.__.loadPromise) {
2753
- console.log(match.matchId, 'suspend');
2754
- throw match.__.loadPromise;
2350
+ });
2351
+ const route = router.getRoute(match.routeId);
2352
+ if (match.status === 'error') {
2353
+ throw match.error;
2354
+ }
2355
+ if (match.status === 'pending') {
2356
+ return /*#__PURE__*/React__namespace.createElement(PendingComponent, {
2357
+ useLoader: route.useLoader,
2358
+ useMatch: route.useMatch,
2359
+ useContext: route.useContext,
2360
+ useRouteContext: route.useRouteContext,
2361
+ useSearch: route.useSearch,
2362
+ useParams: route.useParams
2363
+ });
2364
+ }
2365
+ if (match.status === 'success') {
2366
+ let comp = route.options.component ?? router.options.defaultComponent;
2367
+ if (comp) {
2368
+ return /*#__PURE__*/React__namespace.createElement(comp, {
2369
+ useLoader: route.useLoader,
2370
+ useMatch: route.useMatch,
2371
+ useContext: route.useContext,
2372
+ useRouteContext: route.useRouteContext,
2373
+ useSearch: route.useSearch,
2374
+ useParams: route.useParams
2375
+ });
2755
2376
  }
2756
-
2757
- invariant(false, 'This should never happen!');
2758
- })())));
2377
+ return /*#__PURE__*/React__namespace.createElement(Outlet, null);
2378
+ }
2379
+ invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
2380
+ }
2381
+ function SafeFragment(props) {
2382
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
2383
+ }
2384
+ function useInjectHtml() {
2385
+ const router = useRouter();
2386
+ return React__namespace.useCallback(html => {
2387
+ router.injectHtml(html);
2388
+ }, []);
2389
+ }
2390
+ function useDehydrate() {
2391
+ const router = useRouter();
2392
+ return React__namespace.useCallback(function dehydrate(key, data) {
2393
+ return router.dehydrateData(key, data);
2394
+ }, []);
2395
+ }
2396
+ function useHydrate() {
2397
+ const router = useRouter();
2398
+ return function hydrate(key) {
2399
+ return router.hydrateData(key);
2400
+ };
2759
2401
  }
2760
2402
 
2761
- class CatchBoundary extends React__namespace.Component {
2762
- constructor() {
2763
- super(...arguments);
2764
- this.state = {
2765
- error: false
2766
- };
2767
- }
2403
+ // This is the messiest thing ever... I'm either seriously tired (likely) or
2404
+ // there has to be a better way to reset error boundaries when the
2405
+ // router's location key changes.
2768
2406
 
2407
+ class CatchBoundary extends React__namespace.Component {
2408
+ state = {
2409
+ error: false,
2410
+ info: undefined
2411
+ };
2769
2412
  componentDidCatch(error, info) {
2770
- console.error(error);
2413
+ this.props.onCatch(error, info);
2771
2414
  this.setState({
2772
2415
  error,
2773
2416
  info
2774
2417
  });
2775
2418
  }
2776
-
2777
2419
  render() {
2778
- var _this$props$errorComp;
2779
-
2780
- const errorComponent = (_this$props$errorComp = this.props.errorComponent) != null ? _this$props$errorComp : DefaultErrorBoundary;
2781
-
2782
- if (this.state.error) {
2783
- return /*#__PURE__*/React__namespace.createElement(errorComponent, this.state);
2420
+ return /*#__PURE__*/React__namespace.createElement(CatchBoundaryInner, _extends({}, this.props, {
2421
+ errorState: this.state,
2422
+ reset: () => this.setState({})
2423
+ }));
2424
+ }
2425
+ }
2426
+ function CatchBoundaryInner(props) {
2427
+ const locationKey = useRouterState({
2428
+ select: d => d.resolvedLocation.key
2429
+ });
2430
+ const [activeErrorState, setActiveErrorState] = React__namespace.useState(props.errorState);
2431
+ const errorComponent = props.errorComponent ?? ErrorComponent;
2432
+ const prevKeyRef = React__namespace.useRef('');
2433
+ React__namespace.useEffect(() => {
2434
+ if (activeErrorState) {
2435
+ if (locationKey !== prevKeyRef.current) {
2436
+ setActiveErrorState({});
2437
+ }
2784
2438
  }
2785
-
2786
- return this.props.children;
2439
+ prevKeyRef.current = locationKey;
2440
+ }, [activeErrorState, locationKey]);
2441
+ React__namespace.useEffect(() => {
2442
+ if (props.errorState.error) {
2443
+ setActiveErrorState(props.errorState);
2444
+ }
2445
+ // props.reset()
2446
+ }, [props.errorState.error]);
2447
+ if (props.errorState.error && activeErrorState.error) {
2448
+ return /*#__PURE__*/React__namespace.createElement(errorComponent, activeErrorState);
2787
2449
  }
2788
-
2450
+ return props.children;
2789
2451
  }
2790
-
2791
- function DefaultErrorBoundary(_ref6) {
2792
- let {
2793
- error
2794
- } = _ref6;
2452
+ function ErrorComponent({
2453
+ error
2454
+ }) {
2455
+ const [show, setShow] = React__namespace.useState("development" !== 'production');
2795
2456
  return /*#__PURE__*/React__namespace.createElement("div", {
2796
2457
  style: {
2797
2458
  padding: '.5rem',
2798
2459
  maxWidth: '100%'
2799
2460
  }
2461
+ }, /*#__PURE__*/React__namespace.createElement("div", {
2462
+ style: {
2463
+ display: 'flex',
2464
+ alignItems: 'center',
2465
+ gap: '.5rem'
2466
+ }
2800
2467
  }, /*#__PURE__*/React__namespace.createElement("strong", {
2801
2468
  style: {
2802
- fontSize: '1.2rem'
2469
+ fontSize: '1rem'
2803
2470
  }
2804
- }, "Something went wrong!"), /*#__PURE__*/React__namespace.createElement("div", {
2471
+ }, "Something went wrong!"), /*#__PURE__*/React__namespace.createElement("button", {
2805
2472
  style: {
2806
- height: '.5rem'
2473
+ appearance: 'none',
2474
+ fontSize: '.6em',
2475
+ border: '1px solid currentColor',
2476
+ padding: '.1rem .2rem',
2477
+ fontWeight: 'bold',
2478
+ borderRadius: '.25rem'
2479
+ },
2480
+ onClick: () => setShow(d => !d)
2481
+ }, show ? 'Hide Error' : 'Show Error')), /*#__PURE__*/React__namespace.createElement("div", {
2482
+ style: {
2483
+ height: '.25rem'
2807
2484
  }
2808
- }), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("pre", null, error.message ? /*#__PURE__*/React__namespace.createElement("code", {
2485
+ }), show ? /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("pre", {
2809
2486
  style: {
2810
2487
  fontSize: '.7em',
2811
2488
  border: '1px solid red',
2812
2489
  borderRadius: '.25rem',
2813
- padding: '.5rem',
2814
- color: 'red'
2490
+ padding: '.3rem',
2491
+ color: 'red',
2492
+ overflow: 'auto'
2815
2493
  }
2816
- }, error.message) : null)));
2494
+ }, error.message ? /*#__PURE__*/React__namespace.createElement("code", null, error.message) : null)) : null);
2817
2495
  }
2818
- function usePrompt(message, when) {
2496
+ function useBlocker(message, condition = true) {
2819
2497
  const router = useRouter();
2820
2498
  React__namespace.useEffect(() => {
2821
- if (!when) return;
2822
- let unblock = router.history.block(transition => {
2499
+ if (!condition) return;
2500
+ let unblock = router.history.block((retry, cancel) => {
2823
2501
  if (window.confirm(message)) {
2824
2502
  unblock();
2825
- transition.retry();
2826
- } else {
2827
- router.location.pathname = window.location.pathname;
2503
+ retry();
2828
2504
  }
2829
2505
  });
2830
2506
  return unblock;
2831
- }, [when, location, message]);
2507
+ });
2508
+ }
2509
+ function Block({
2510
+ message,
2511
+ condition,
2512
+ children
2513
+ }) {
2514
+ useBlocker(message, condition);
2515
+ return children ?? null;
2832
2516
  }
2833
- function Prompt(_ref7) {
2834
- let {
2835
- message,
2836
- when,
2837
- children
2838
- } = _ref7;
2839
- usePrompt(message, when != null ? when : true);
2840
- return children != null ? children : null;
2517
+ function shallow(objA, objB) {
2518
+ if (Object.is(objA, objB)) {
2519
+ return true;
2520
+ }
2521
+ if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
2522
+ return false;
2523
+ }
2524
+ const keysA = Object.keys(objA);
2525
+ if (keysA.length !== Object.keys(objB).length) {
2526
+ return false;
2527
+ }
2528
+ for (let i = 0; i < keysA.length; i++) {
2529
+ if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
2530
+ return false;
2531
+ }
2532
+ }
2533
+ return true;
2841
2534
  }
2842
2535
 
2843
- Object.defineProperty(exports, 'lazy', {
2844
- enumerable: true,
2845
- get: function () { return index.lazyWithPreload; }
2846
- });
2847
- exports.DefaultErrorBoundary = DefaultErrorBoundary;
2848
- exports.MatchesProvider = MatchesProvider;
2536
+ exports.Block = Block;
2537
+ exports.ErrorComponent = ErrorComponent;
2538
+ exports.FileRoute = FileRoute;
2539
+ exports.Link = Link;
2540
+ exports.MatchRoute = MatchRoute;
2541
+ exports.Navigate = Navigate;
2849
2542
  exports.Outlet = Outlet;
2850
- exports.Prompt = Prompt;
2543
+ exports.PathParamError = PathParamError;
2544
+ exports.RootRoute = RootRoute;
2545
+ exports.Route = Route;
2546
+ exports.Router = Router;
2547
+ exports.RouterContext = RouterContext;
2851
2548
  exports.RouterProvider = RouterProvider;
2549
+ exports.SearchParamError = SearchParamError;
2852
2550
  exports.cleanPath = cleanPath;
2551
+ exports.componentTypes = componentTypes;
2853
2552
  exports.createBrowserHistory = createBrowserHistory;
2854
2553
  exports.createHashHistory = createHashHistory;
2855
2554
  exports.createMemoryHistory = createMemoryHistory;
2856
- exports.createReactRouter = createReactRouter;
2857
- exports.createRoute = createRoute;
2858
- exports.createRouteConfig = createRouteConfig;
2859
- exports.createRouteMatch = createRouteMatch;
2860
- exports.createRouter = createRouter;
2861
2555
  exports.decode = decode;
2862
2556
  exports.defaultParseSearch = defaultParseSearch;
2863
2557
  exports.defaultStringifySearch = defaultStringifySearch;
@@ -2865,23 +2559,46 @@
2865
2559
  exports.functionalUpdate = functionalUpdate;
2866
2560
  exports.interpolatePath = interpolatePath;
2867
2561
  exports.invariant = invariant;
2562
+ exports.isPlainObject = isPlainObject;
2563
+ exports.isRedirect = isRedirect;
2868
2564
  exports.joinPaths = joinPaths;
2869
2565
  exports.last = last;
2566
+ exports.lazyFn = lazyFn;
2567
+ exports.lazyRouteComponent = lazyRouteComponent;
2870
2568
  exports.matchByPath = matchByPath;
2569
+ exports.matchIdsContext = matchIdsContext;
2871
2570
  exports.matchPathname = matchPathname;
2872
2571
  exports.parsePathname = parsePathname;
2873
2572
  exports.parseSearchWith = parseSearchWith;
2573
+ exports.partialDeepEqual = partialDeepEqual;
2874
2574
  exports.pick = pick;
2575
+ exports.redirect = redirect;
2875
2576
  exports.replaceEqualDeep = replaceEqualDeep;
2876
2577
  exports.resolvePath = resolvePath;
2877
2578
  exports.rootRouteId = rootRouteId;
2579
+ exports.routerContext = routerContext;
2580
+ exports.shallow = shallow;
2878
2581
  exports.stringifySearchWith = stringifySearchWith;
2879
2582
  exports.trimPath = trimPath;
2880
2583
  exports.trimPathLeft = trimPathLeft;
2881
2584
  exports.trimPathRight = trimPathRight;
2585
+ exports.useBlocker = useBlocker;
2586
+ exports.useDehydrate = useDehydrate;
2587
+ exports.useHydrate = useHydrate;
2588
+ exports.useInjectHtml = useInjectHtml;
2589
+ exports.useLinkProps = useLinkProps;
2590
+ exports.useLoader = useLoader;
2591
+ exports.useMatch = useMatch;
2592
+ exports.useMatchRoute = useMatchRoute;
2882
2593
  exports.useMatches = useMatches;
2883
- exports.usePrompt = usePrompt;
2594
+ exports.useNavigate = useNavigate;
2595
+ exports.useParams = useParams;
2596
+ exports.useRouteContext = useRouteContext;
2884
2597
  exports.useRouter = useRouter;
2598
+ exports.useRouterContext = useRouterContext;
2599
+ exports.useRouterState = useRouterState;
2600
+ exports.useSearch = useSearch;
2601
+ exports.useStore = useStore;
2885
2602
  exports.warning = warning;
2886
2603
 
2887
2604
  Object.defineProperty(exports, '__esModule', { value: true });