@tanstack/react-router 0.0.1-beta.5 → 0.0.1-beta.51

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