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

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