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

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