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

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
+ matchId: opts.matchId,
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,1290 @@
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
976
  }
1741
-
1742
977
  const searchStr = encode(search).toString();
1743
- return searchStr ? "?" + searchStr : '';
978
+ return searchStr ? `?${searchStr}` : '';
1744
979
  };
1745
980
  }
1746
981
 
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
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
+ })
1766
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.history = this.options?.history ?? createBrowserHistory();
1022
+ this.store = createStore(getInitialRouterState());
1023
+ this.basepath = '';
1024
+ this.update(options);
1767
1025
 
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.
1818
-
1819
-
1820
- if (next.href !== router.location.href) {
1821
- router.__.commitLocation(next, true);
1026
+ // Allow frameworks to hook into the router creation
1027
+ this.options.createRouter?.(this);
1028
+ }
1029
+ reset = () => {
1030
+ this.store.setState(s => Object.assign(s, getInitialRouterState()));
1031
+ };
1032
+ mount = () => {
1033
+ // Mount only does anything on the client
1034
+ if (!isServer) {
1035
+ // If the router matches are empty, load the matches
1036
+ if (!this.store.state.currentMatches.length) {
1037
+ this.load();
1822
1038
  }
1039
+ const unsubHistory = this.history.listen(() => {
1040
+ this.load(this.#parseLocation(this.store.state.latestLocation));
1041
+ });
1042
+ const visibilityChangeEvent = 'visibilitychange';
1043
+ const focusEvent = 'focus';
1823
1044
 
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
1045
+ // addEventListener does not exist in React Native, but window does
1046
+ // In the future, we might need to invert control here for more adapters
1829
1047
  // 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);
1048
+ if (window.addEventListener) {
1049
+ // Listen to visibilitychange and focus
1050
+ window.addEventListener(visibilityChangeEvent, this.#onFocus, false);
1051
+ window.addEventListener(focusEvent, this.#onFocus, false);
1835
1052
  }
1836
-
1837
1053
  return () => {
1838
- unsub(); // Be sure to unsubscribe if a new handler is set
1839
-
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;
1054
+ unsubHistory();
1055
+ if (window.removeEventListener) {
1056
+ // Be sure to unsubscribe if a new handler is set
1849
1057
 
1850
- if (!router.location || newHistory) {
1851
- if (opts != null && opts.history) {
1852
- router.history = opts.history;
1058
+ window.removeEventListener(visibilityChangeEvent, this.#onFocus);
1059
+ window.removeEventListener(focusEvent, this.#onFocus);
1853
1060
  }
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();
1061
+ };
1062
+ }
1063
+ return () => {};
1064
+ };
1065
+ update = opts => {
1066
+ if (!this.store.state.latestLocation) {
1067
+ this.store.setState(s => {
1068
+ s.latestLocation = this.#parseLocation();
1069
+ s.currentLocation = s.latestLocation;
1877
1070
  });
1878
- },
1879
- loadLocation: async next => {
1880
- const id = Math.random();
1881
- router.startedLoadingAt = id;
1882
-
1071
+ }
1072
+ Object.assign(this.options, opts);
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
-
1214
+ }
2011
1215
 
2012
- delete router.matchCache[matchId];
1216
+ // Everything else gets removed
1217
+ delete s.matchCache[matchId];
2013
1218
  });
2014
- },
2015
- loadRoute: async function loadRoute(navigateOpts) {
2016
- if (navigateOpts === void 0) {
2017
- navigateOpts = router.location;
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) {
1249
+ return matches;
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;
1275
+ }
1276
+ }
1277
+ params = {
1278
+ ...params,
1279
+ ...parsedParams
1280
+ };
1281
+ }
1282
+ if (!!matchParams) {
1283
+ foundRoutes = [...parentRoutes, route];
1284
+ }
1285
+ return !!foundRoutes.length;
1286
+ });
1287
+ return !!foundRoutes.length;
1288
+ };
1289
+ findMatchInRoutes([], filteredRoutes);
1290
+ if (!foundRoutes.length) {
1291
+ return;
2018
1292
  }
2019
-
2020
- const next = router.buildNext(navigateOpts);
2021
- const matches = router.matchRoutes(next.pathname, {
2022
- strictParseParams: true
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
+ matchId,
1298
+ params,
1299
+ pathname: joinPaths([this.basepath, interpolatedPath])
1300
+ });
1301
+ matches.push(match);
2023
1302
  });
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;
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
+ });
2029
1318
 
2030
- if (navigateOpts === void 0) {
2031
- navigateOpts = router.location;
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;
2032
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'
2033
1363
 
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
2042
- });
2043
- return matches;
2044
- },
2045
- matchRoutes: (pathname, opts) => {
2046
- var _router$state$pending3, _router$state$pending4;
1364
+ // New:
1365
+ // '/dashboard/invoices/456'
2047
1366
 
2048
- router.cleanMatchCache();
2049
- const matches = [];
1367
+ // TODO: batch requests when possible
2050
1368
 
2051
- if (!router.routeTree) {
2052
- return matches;
1369
+ return this.options.fetchServerDataFn({
1370
+ router: this,
1371
+ routeMatch
1372
+ });
1373
+ }
1374
+ };
1375
+ invalidateRoute = async opts => {
1376
+ const next = this.buildNext(opts);
1377
+ const unloadedMatchIds = this.matchRoutes(next.pathname).map(d => d.id);
1378
+ await Promise.allSettled([...this.store.state.currentMatches, ...(this.store.state.pendingMatches ?? [])].map(async match => {
1379
+ if (unloadedMatchIds.includes(match.id)) {
1380
+ return match.invalidate();
2053
1381
  }
1382
+ }));
1383
+ };
1384
+ reload = () => {
1385
+ this.navigate({
1386
+ fromCurrent: true,
1387
+ replace: true,
1388
+ search: true
1389
+ });
1390
+ };
1391
+ resolvePath = (from, path) => {
1392
+ return resolvePath(this.basepath, from, cleanPath(path));
1393
+ };
1394
+ navigate = async ({
1395
+ from,
1396
+ to = '.',
1397
+ search,
1398
+ hash,
1399
+ replace,
1400
+ params
1401
+ }) => {
1402
+ // If this link simply reloads the current route,
1403
+ // make sure it has a new key so it will trigger a data refresh
1404
+
1405
+ // If this `to` is a valid external URL, return
1406
+ // null for LinkUtils
1407
+ const toString = String(to);
1408
+ const fromString = String(from);
1409
+ let isExternal;
1410
+ try {
1411
+ new URL(`${toString}`);
1412
+ isExternal = true;
1413
+ } catch (e) {}
1414
+ invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1415
+ return this.#commitLocation({
1416
+ from: fromString,
1417
+ to: toString,
1418
+ search,
1419
+ hash,
1420
+ replace,
1421
+ params
1422
+ });
1423
+ };
1424
+ matchRoute = (location, opts) => {
1425
+ location = {
1426
+ ...location,
1427
+ to: location.to ? this.resolvePath(location.from ?? '', location.to) : undefined
1428
+ };
1429
+ const next = this.buildNext(location);
1430
+ if (opts?.pending) {
1431
+ if (!this.store.state.pendingLocation) {
1432
+ return false;
1433
+ }
1434
+ return matchPathname(this.basepath, this.store.state.pendingLocation.pathname, {
1435
+ ...opts,
1436
+ to: next.pathname
1437
+ });
1438
+ }
1439
+ return matchPathname(this.basepath, this.store.state.currentLocation.pathname, {
1440
+ ...opts,
1441
+ to: next.pathname
1442
+ });
1443
+ };
1444
+ buildLink = ({
1445
+ from,
1446
+ to = '.',
1447
+ search,
1448
+ params,
1449
+ hash,
1450
+ target,
1451
+ replace,
1452
+ activeOptions,
1453
+ preload,
1454
+ preloadMaxAge: userPreloadMaxAge,
1455
+ preloadGcMaxAge: userPreloadGcMaxAge,
1456
+ preloadDelay: userPreloadDelay,
1457
+ disabled
1458
+ }) => {
1459
+ // If this link simply reloads the current route,
1460
+ // make sure it has a new key so it will trigger a data refresh
1461
+
1462
+ // If this `to` is a valid external URL, return
1463
+ // null for LinkUtils
2054
1464
 
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;
1465
+ try {
1466
+ new URL(`${to}`);
1467
+ return {
1468
+ type: 'external',
1469
+ href: to
1470
+ };
1471
+ } catch (e) {}
1472
+ const nextOpts = {
1473
+ from,
1474
+ to,
1475
+ search,
1476
+ params,
1477
+ hash,
1478
+ replace
1479
+ };
1480
+ const next = this.buildNext(nextOpts);
1481
+ preload = preload ?? this.options.defaultPreload;
1482
+ const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
1483
+
1484
+ // Compare path/hash for matches
1485
+ const pathIsEqual = this.store.state.currentLocation.pathname === next.pathname;
1486
+ const currentPathSplit = this.store.state.currentLocation.pathname.split('/');
1487
+ const nextPathSplit = next.pathname.split('/');
1488
+ const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
1489
+ const hashIsEqual = this.store.state.currentLocation.hash === next.hash;
1490
+ // Combine the matches based on user options
1491
+ const pathTest = activeOptions?.exact ? pathIsEqual : pathIsFuzzyEqual;
1492
+ const hashTest = activeOptions?.includeHash ? hashIsEqual : true;
1493
+
1494
+ // The final "active" test
1495
+ const isActive = pathTest && hashTest;
1496
+
1497
+ // The click handler
1498
+ const handleClick = e => {
1499
+ if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
1500
+ e.preventDefault();
1501
+ if (pathIsEqual && !search && !hash) {
1502
+ this.invalidateRoute(nextOpts);
1503
+ }
2059
1504
 
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 = [];
1505
+ // All is well? Navigate!
1506
+ this.#commitLocation(nextOpts);
1507
+ }
1508
+ };
2064
1509
 
2065
- const findMatchInRoutes = (parentRoutes, routes) => {
2066
- routes.some(route => {
2067
- var _route$childRoutes, _route$childRoutes2, _route$options$caseSe;
1510
+ // The click handler
1511
+ const handleFocus = e => {
1512
+ if (preload) {
1513
+ this.preloadRoute(nextOpts, {
1514
+ maxAge: userPreloadMaxAge,
1515
+ gcMaxAge: userPreloadGcMaxAge
1516
+ }).catch(err => {
1517
+ console.warn(err);
1518
+ console.warn('Error preloading route! ☝️');
1519
+ });
1520
+ }
1521
+ };
1522
+ const handleEnter = e => {
1523
+ const target = e.target || {};
1524
+ if (preload) {
1525
+ if (target.preloadTimeout) {
1526
+ return;
1527
+ }
1528
+ target.preloadTimeout = setTimeout(() => {
1529
+ target.preloadTimeout = null;
1530
+ this.preloadRoute(nextOpts, {
1531
+ maxAge: userPreloadMaxAge,
1532
+ gcMaxAge: userPreloadGcMaxAge
1533
+ }).catch(err => {
1534
+ console.warn(err);
1535
+ console.warn('Error preloading route! ☝️');
1536
+ });
1537
+ }, preloadDelay);
1538
+ }
1539
+ };
1540
+ const handleLeave = e => {
1541
+ const target = e.target || {};
1542
+ if (target.preloadTimeout) {
1543
+ clearTimeout(target.preloadTimeout);
1544
+ target.preloadTimeout = null;
1545
+ }
1546
+ };
1547
+ return {
1548
+ type: 'internal',
1549
+ next,
1550
+ handleFocus,
1551
+ handleClick,
1552
+ handleEnter,
1553
+ handleLeave,
1554
+ isActive,
1555
+ disabled
1556
+ };
1557
+ };
1558
+ dehydrate = () => {
1559
+ return {
1560
+ state: {
1561
+ ...pick(this.store.state, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
1562
+ currentMatches: this.store.state.currentMatches.map(match => ({
1563
+ matchId: match.id,
1564
+ state: {
1565
+ ...pick(match.store.state, ['status', 'routeLoaderData', 'invalidAt', 'invalid'])
1566
+ }
1567
+ }))
1568
+ },
1569
+ context: this.options.context
1570
+ };
1571
+ };
1572
+ hydrate = dehydratedRouter => {
1573
+ this.store.setState(s => {
1574
+ // Update the context TODO: make this part of state?
1575
+ this.options.context = dehydratedRouter.context;
2068
1576
 
2069
- if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
2070
- return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
1577
+ // Match the routes
1578
+ const currentMatches = this.matchRoutes(dehydratedRouter.state.latestLocation.pathname, {
1579
+ strictParseParams: true
1580
+ });
1581
+ currentMatches.forEach((match, index) => {
1582
+ const dehydratedMatch = dehydratedRouter.state.currentMatches[index];
1583
+ invariant(dehydratedMatch && dehydratedMatch.matchId === match.id, 'Oh no! There was a hydration mismatch when attempting to rethis.store the state of the router! 😬');
1584
+ Object.assign(match, dehydratedMatch);
1585
+ });
1586
+ currentMatches.forEach(match => match.__validate());
1587
+ Object.assign(s, {
1588
+ ...dehydratedRouter.state,
1589
+ currentMatches
1590
+ });
1591
+ });
1592
+ };
1593
+ getLoader = opts => {
1594
+ const id = opts.from || '/';
1595
+ const route = this.getRoute(id);
1596
+ if (!route) return undefined;
1597
+ let loader = this.store.state.loaders[id] || (() => {
1598
+ this.store.setState(s => {
1599
+ s.loaders[id] = {
1600
+ pending: [],
1601
+ fetch: async loaderContext => {
1602
+ if (!route) {
1603
+ return;
2071
1604
  }
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
1605
+ const loaderState = {
1606
+ loadedAt: Date.now(),
1607
+ loaderContext
1608
+ };
1609
+ this.store.setState(s => {
1610
+ s.loaders[id].current = loaderState;
1611
+ s.loaders[id].latest = loaderState;
1612
+ s.loaders[id].pending.push(loaderState);
2078
1613
  });
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
- }
2091
- }
2092
-
2093
- params = _extends({}, params, parsedParams);
2094
- }
2095
-
2096
- if (!!matchParams) {
2097
- foundRoutes = [...parentRoutes, route];
1614
+ try {
1615
+ return await route.options.loader?.(loaderContext);
1616
+ } finally {
1617
+ this.store.setState(s => {
1618
+ s.loaders[id].pending = s.loaders[id].pending.filter(d => d !== loaderState);
1619
+ });
2098
1620
  }
2099
-
2100
- return !!foundRoutes.length;
2101
- });
2102
- return !!foundRoutes.length;
1621
+ }
2103
1622
  };
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
- });
2123
- const foundRoute = last(foundRoutes);
2124
-
2125
- if ((_foundRoute$childRout = foundRoute.childRoutes) != null && _foundRoute$childRout.length) {
2126
- recurse(foundRoute.childRoutes);
2127
- }
2128
- };
2129
-
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();
2138
-
2139
- match.load(loaderOpts);
2140
-
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
2145
-
2146
- await match.__.loadPromise;
2147
- }
2148
1623
  });
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();
1624
+ return this.store.state.loaders[id];
1625
+ })();
1626
+ return loader;
1627
+ };
1628
+ #buildRouteTree = rootRouteConfig => {
1629
+ const recurseRoutes = (routeConfigs, parent) => {
1630
+ return routeConfigs.map((routeConfig, i) => {
1631
+ const routeOptions = routeConfig.options;
1632
+ const route = new Route(routeConfig, routeOptions, i, parent, this);
1633
+ const existingRoute = this.routesById[route.id];
1634
+ if (existingRoute) {
1635
+ {
1636
+ console.warn(`Duplicate routes found with id: ${String(route.id)}`, this.routesById, route);
1637
+ }
1638
+ throw new Error();
2160
1639
  }
1640
+ this.routesById[route.id] = route;
1641
+ const children = routeConfig.children;
1642
+ route.childRoutes = children.length ? recurseRoutes(children, route) : undefined;
1643
+ return route;
2161
1644
  });
2162
- },
2163
- reload: () => router.__.navigate({
2164
- fromCurrent: true,
2165
- replace: true,
2166
- 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
1645
+ };
1646
+ const routes = recurseRoutes([rootRouteConfig]);
1647
+ return routes[0];
1648
+ };
1649
+ #parseLocation = previousLocation => {
1650
+ let {
1651
+ pathname,
1652
+ search,
1653
+ hash,
1654
+ state
1655
+ } = this.history.location;
1656
+ const parsedSearch = this.options.parseSearch(search);
1657
+ return {
1658
+ pathname: pathname,
1659
+ searchStr: search,
1660
+ search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1661
+ hash: hash.split('#').reverse()[0] ?? '',
1662
+ href: `${pathname}${search}${hash}`,
1663
+ state: state,
1664
+ key: state?.key || '__init__'
1665
+ };
1666
+ };
1667
+ #onFocus = () => {
1668
+ this.load();
1669
+ };
1670
+ #buildLocation = (dest = {}) => {
1671
+ const fromPathname = dest.fromCurrent ? this.store.state.latestLocation.pathname : dest.from ?? this.store.state.latestLocation.pathname;
1672
+ let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
1673
+ const fromMatches = this.matchRoutes(this.store.state.latestLocation.pathname, {
1674
+ strictParseParams: true
1675
+ });
1676
+ const toMatches = this.matchRoutes(pathname);
1677
+ const prevParams = {
1678
+ ...last(fromMatches)?.params
1679
+ };
1680
+ let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1681
+ if (nextParams) {
1682
+ toMatches.map(d => d.route.options.stringifyParams).filter(Boolean).forEach(fn => {
1683
+ Object.assign({}, nextParams, fn(nextParams));
2177
1684
  });
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
- }));
2190
- }
1685
+ }
1686
+ pathname = interpolatePath(pathname, nextParams ?? {});
1687
+
1688
+ // Pre filters first
1689
+ const preFilteredSearch = dest.__preSearchFilters?.length ? dest.__preSearchFilters?.reduce((prev, next) => next(prev), this.store.state.latestLocation.search) : this.store.state.latestLocation.search;
1690
+
1691
+ // Then the link/navigate function
1692
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1693
+ : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
1694
+ : dest.__preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
1695
+ : {};
1696
+
1697
+ // Then post filters
1698
+ const postFilteredSearch = dest.__postSearchFilters?.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1699
+ const search = replaceEqualDeep(this.store.state.latestLocation.search, postFilteredSearch);
1700
+ const searchStr = this.options.stringifySearch(search);
1701
+ let hash = dest.hash === true ? this.store.state.latestLocation.hash : functionalUpdate(dest.hash, this.store.state.latestLocation.hash);
1702
+ hash = hash ? `#${hash}` : '';
1703
+ return {
1704
+ pathname,
1705
+ search,
1706
+ searchStr,
1707
+ state: this.store.state.latestLocation.state,
1708
+ hash,
1709
+ href: `${pathname}${searchStr}${hash}`,
1710
+ key: dest.key
1711
+ };
1712
+ };
1713
+ #commitLocation = location => {
1714
+ const next = this.buildNext(location);
1715
+ const id = '' + Date.now() + Math.random();
1716
+ if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
1717
+ let nextAction = 'replace';
1718
+ if (!location.replace) {
1719
+ nextAction = 'push';
1720
+ }
1721
+ const isSameUrl = this.store.state.latestLocation.href === next.href;
1722
+ if (isSameUrl && !next.key) {
1723
+ nextAction = 'replace';
1724
+ }
1725
+ const href = `${next.pathname}${next.searchStr}${next.hash ? `#${next.hash}` : ''}`;
1726
+ this.history[nextAction === 'push' ? 'push' : 'replace'](href, {
1727
+ id,
1728
+ ...next.state
1729
+ });
1730
+ this.load(this.#parseLocation(this.store.state.latestLocation));
1731
+ return this.navigationPromise = new Promise(resolve => {
1732
+ const previousNavigationResolve = this.resolveNavigation;
1733
+ this.resolveNavigation = () => {
1734
+ previousNavigationResolve();
1735
+ resolve();
1736
+ };
1737
+ });
1738
+ };
1739
+ }
2191
1740
 
2192
- return !!matchPathname(router.state.location.pathname, _extends({}, opts, {
2193
- to: next.pathname
2194
- }));
1741
+ // Detect if we're in the DOM
1742
+ const isServer = typeof window === 'undefined' || !window.document.createElement;
1743
+ function getInitialRouterState() {
1744
+ return {
1745
+ status: 'idle',
1746
+ latestLocation: null,
1747
+ currentLocation: null,
1748
+ currentMatches: [],
1749
+ loaders: {},
1750
+ lastUpdated: Date.now(),
1751
+ matchCache: {},
1752
+ get isFetching() {
1753
+ return this.status === 'loading' || this.currentMatches.some(d => d.store.state.isFetching);
2195
1754
  },
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;
1755
+ get isPreloading() {
1756
+ return Object.values(this.matchCache).some(d => d.match.store.state.isFetching && !this.currentMatches.find(dd => dd.id === d.match.id));
1757
+ }
1758
+ };
1759
+ }
1760
+ function isCtrlEvent(e) {
1761
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1762
+ }
1763
+ function linkMatches(matches) {
1764
+ matches.forEach((match, index) => {
1765
+ const parent = matches[index - 1];
1766
+ if (parent) {
1767
+ match.__setParentMatch(parent);
1768
+ }
1769
+ });
1770
+ }
2212
1771
 
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
1772
+ // createRouterAction is a constrained identify function that takes options: key, action, onSuccess, onError, onSettled, etc
1773
+ function createAction(options) {
1774
+ const store = createStore({
1775
+ submissions: []
1776
+ }, options.debug);
1777
+ return {
1778
+ options,
1779
+ store,
1780
+ reset: () => {
1781
+ store.setState(s => {
1782
+ s.submissions = [];
2226
1783
  });
2227
1784
  },
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
-
2290
-
2291
- router.__.navigate(nextOpts);
2292
- }
2293
- }; // The click handler
2294
-
2295
-
2296
- const handleFocus = e => {
2297
- if (preload) {
2298
- router.preloadRoute(nextOpts, {
2299
- maxAge: userPreloadMaxAge,
2300
- gcMaxAge: userPreloadGcMaxAge
1785
+ submit: async payload => {
1786
+ const submission = {
1787
+ submittedAt: Date.now(),
1788
+ status: 'pending',
1789
+ payload: payload,
1790
+ invalidate: () => {
1791
+ setSubmission(s => {
1792
+ s.isInvalid = true;
2301
1793
  });
2302
- }
2303
- };
2304
-
2305
- const handleEnter = e => {
2306
- const target = e.target || {};
2307
-
2308
- if (preload) {
2309
- if (target.preloadTimeout) {
2310
- return;
2311
- }
2312
-
2313
- target.preloadTimeout = setTimeout(() => {
2314
- target.preloadTimeout = null;
2315
- router.preloadRoute(nextOpts, {
2316
- maxAge: userPreloadMaxAge,
2317
- gcMaxAge: userPreloadGcMaxAge
2318
- });
2319
- }, preloadDelay);
2320
- }
1794
+ },
1795
+ getIsLatest: () => store.state.submissions[store.state.submissions.length - 1]?.submittedAt === submission.submittedAt
2321
1796
  };
2322
-
2323
- const handleLeave = e => {
2324
- const target = e.target || {};
2325
-
2326
- if (target.preloadTimeout) {
2327
- clearTimeout(target.preloadTimeout);
2328
- target.preloadTimeout = null;
2329
- }
1797
+ const setSubmission = updater => {
1798
+ store.setState(s => {
1799
+ const a = s.submissions.find(d => d.submittedAt === submission.submittedAt);
1800
+ invariant(a, 'Could not find submission in store');
1801
+ updater(a);
1802
+ });
2330
1803
  };
2331
-
2332
- return {
2333
- type: 'internal',
2334
- next,
2335
- handleFocus,
2336
- handleClick,
2337
- handleEnter,
2338
- handleLeave,
2339
- isActive,
2340
- disabled
1804
+ store.setState(s => {
1805
+ s.submissions.push(submission);
1806
+ s.submissions.reverse();
1807
+ s.submissions = s.submissions.slice(0, options.maxSubmissions ?? 10);
1808
+ s.submissions.reverse();
1809
+ });
1810
+ const after = async () => {
1811
+ options.onEachSettled?.(submission);
1812
+ if (submission.getIsLatest()) await options.onLatestSettled?.(submission);
2341
1813
  };
2342
- },
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);
2359
-
2360
- return router.__.buildLocation(_extends({}, opts, {
2361
- __preSearchFilters,
2362
- __postSearchFilters
2363
- }));
2364
- },
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;
2388
- });
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
1814
+ try {
1815
+ const res = await options.action?.(submission.payload);
1816
+ setSubmission(s => {
1817
+ s.response = res;
2427
1818
  });
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
- };
1819
+ await options.onEachSuccess?.(submission);
1820
+ if (submission.getIsLatest()) await options.onLatestSuccess?.(submission);
1821
+ await after();
1822
+ setSubmission(s => {
1823
+ s.status = 'success';
2504
1824
  });
2505
- return router.navigationPromise;
1825
+ return res;
1826
+ } catch (err) {
1827
+ console.error(err);
1828
+ setSubmission(s => {
1829
+ s.error = err;
1830
+ });
1831
+ await options.onEachError?.(submission);
1832
+ if (submission.getIsLatest()) await options.onLatestError?.(submission);
1833
+ await after();
1834
+ setSubmission(s => {
1835
+ s.status = 'error';
1836
+ });
1837
+ throw err;
2506
1838
  }
2507
1839
  }
2508
1840
  };
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
1841
  }
2514
1842
 
2515
- function isCtrlEvent(e) {
2516
- return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1843
+ function useStore(store, selector = d => d, compareShallow) {
1844
+ const slice = withSelector.useSyncExternalStoreWithSelector(store.subscribe, () => store.state, () => store.state, selector, compareShallow ? shallow : undefined);
1845
+ return slice;
2517
1846
  }
1847
+ function shallow(objA, objB) {
1848
+ if (Object.is(objA, objB)) {
1849
+ return true;
1850
+ }
1851
+ if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
1852
+ return false;
1853
+ }
2518
1854
 
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
1855
+ // if (objA instanceof Map && objB instanceof Map) {
1856
+ // if (objA.size !== objB.size) return false
2525
1857
 
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
- }
1858
+ // for (const [key, value] of objA) {
1859
+ // if (!Object.is(value, objB.get(key))) {
1860
+ // return false
1861
+ // }
1862
+ // }
1863
+ // return true
1864
+ // }
2531
1865
 
2532
- const useRouterSubscription = router => {
2533
- shim.useSyncExternalStore(cb => router.subscribe(() => cb()), () => router.state, () => router.state);
2534
- };
1866
+ // if (objA instanceof Set && objB instanceof Set) {
1867
+ // if (objA.size !== objB.size) return false
2535
1868
 
2536
- function createReactRouter(opts) {
2537
- const makeRouteExt = (route, router) => {
2538
- return {
2539
- useRoute: function useRoute(subRouteId) {
2540
- if (subRouteId === void 0) {
2541
- subRouteId = '.';
2542
- }
1869
+ // for (const value of objA) {
1870
+ // if (!objB.has(value)) {
1871
+ // return false
1872
+ // }
1873
+ // }
1874
+ // return true
1875
+ // }
2543
1876
 
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
- }
1877
+ const keysA = Object.keys(objA);
1878
+ if (keysA.length !== Object.keys(objB).length) {
1879
+ return false;
1880
+ }
1881
+ for (let i = 0; i < keysA.length; i++) {
1882
+ if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
1883
+ return false;
1884
+ }
1885
+ }
1886
+ return true;
1887
+ }
2581
1888
 
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
- });
1889
+ //
2640
1890
 
2641
- if (!params) {
2642
- return null;
2643
- }
1891
+ function lazy(importer) {
1892
+ const lazyComp = /*#__PURE__*/React__namespace.lazy(importer);
1893
+ const finalComp = lazyComp;
1894
+ finalComp.preload = async () => {
1895
+ {
1896
+ await importer();
1897
+ }
1898
+ };
1899
+ return finalComp;
1900
+ }
1901
+ //
2644
1902
 
2645
- return typeof opts.children === 'function' ? opts.children(params) : opts.children;
2646
- }
1903
+ function useLinkProps(options) {
1904
+ const router = useRouter();
1905
+ const {
1906
+ // custom props
1907
+ type,
1908
+ children,
1909
+ target,
1910
+ activeProps = () => ({
1911
+ className: 'active'
1912
+ }),
1913
+ inactiveProps = () => ({}),
1914
+ activeOptions,
1915
+ disabled,
1916
+ // fromCurrent,
1917
+ hash,
1918
+ search,
1919
+ params,
1920
+ to = '.',
1921
+ preload,
1922
+ preloadDelay,
1923
+ preloadMaxAge,
1924
+ replace,
1925
+ // element props
1926
+ style,
1927
+ className,
1928
+ onClick,
1929
+ onFocus,
1930
+ onMouseEnter,
1931
+ onMouseLeave,
1932
+ onTouchStart,
1933
+ onTouchEnd,
1934
+ ...rest
1935
+ } = options;
1936
+ const linkInfo = router.buildLink(options);
1937
+ if (linkInfo.type === 'external') {
1938
+ const {
1939
+ href
1940
+ } = linkInfo;
1941
+ return {
1942
+ href
2647
1943
  };
1944
+ }
1945
+ const {
1946
+ handleClick,
1947
+ handleFocus,
1948
+ handleEnter,
1949
+ handleLeave,
1950
+ isActive,
1951
+ next
1952
+ } = linkInfo;
1953
+ const reactHandleClick = e => {
1954
+ if (React__namespace.startTransition) {
1955
+ // This is a hack for react < 18
1956
+ React__namespace.startTransition(() => {
1957
+ handleClick(e);
1958
+ });
1959
+ } else {
1960
+ handleClick(e);
1961
+ }
1962
+ };
1963
+ const composeHandlers = handlers => e => {
1964
+ if (e.persist) e.persist();
1965
+ handlers.filter(Boolean).forEach(handler => {
1966
+ if (e.defaultPrevented) return;
1967
+ handler(e);
1968
+ });
2648
1969
  };
2649
1970
 
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
- }
1971
+ // Get the active props
1972
+ const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {};
2670
1973
 
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);
1974
+ // Get the inactive props
1975
+ const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
1976
+ return {
1977
+ ...resolvedActiveProps,
1978
+ ...resolvedInactiveProps,
1979
+ ...rest,
1980
+ href: disabled ? undefined : next.href,
1981
+ onClick: composeHandlers([onClick, reactHandleClick]),
1982
+ onFocus: composeHandlers([onFocus, handleFocus]),
1983
+ onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
1984
+ onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
1985
+ target,
1986
+ style: {
1987
+ ...style,
1988
+ ...resolvedActiveProps.style,
1989
+ ...resolvedInactiveProps.style
2684
1990
  },
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;
1991
+ className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
1992
+ ...(disabled ? {
1993
+ role: 'link',
1994
+ 'aria-disabled': true
1995
+ } : undefined),
1996
+ ['data-status']: isActive ? 'active' : undefined
1997
+ };
1998
+ }
1999
+ const Link = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
2000
+ const linkProps = useLinkProps(props);
2001
+ return /*#__PURE__*/React__namespace.createElement("a", _extends({
2002
+ ref: ref
2003
+ }, linkProps, {
2004
+ children: typeof props.children === 'function' ? props.children({
2005
+ isActive: linkProps['data-status'] === 'active'
2006
+ }) : props.children
2007
+ }));
2008
+ });
2009
+ const matchesContext = /*#__PURE__*/React__namespace.createContext(null);
2010
+ const routerContext = /*#__PURE__*/React__namespace.createContext(null);
2011
+ class ReactRouter extends Router {
2012
+ constructor(opts) {
2013
+ super({
2014
+ ...opts,
2015
+ loadComponent: async component => {
2016
+ if (component.preload) {
2017
+ await component.preload();
2693
2018
  }
2019
+ return component;
2694
2020
  }
2695
-
2696
- return element;
2697
- }
2698
- }));
2699
- return coreRouter;
2021
+ });
2022
+ }
2700
2023
  }
2701
- function RouterProvider(_ref2) {
2702
- let {
2703
- children,
2704
- router
2705
- } = _ref2,
2706
- rest = _objectWithoutPropertiesLoose(_ref2, _excluded3);
2707
-
2024
+ function RouterProvider({
2025
+ router,
2026
+ ...rest
2027
+ }) {
2708
2028
  router.update(rest);
2709
- useRouterSubscription(router);
2710
- useLayoutEffect(() => {
2711
- return router.mount();
2712
- }, [router]);
2713
- return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2029
+ const [,, currentMatches] = useStore(router.store, s => [s.status, s.pendingMatches, s.currentMatches], true);
2030
+ React__namespace.useEffect(router.mount, [router]);
2031
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2714
2032
  value: {
2715
- router
2033
+ router: router
2716
2034
  }
2717
- }, /*#__PURE__*/React__namespace.createElement(MatchesProvider, {
2718
- value: router.state.matches
2719
- }, children != null ? children : /*#__PURE__*/React__namespace.createElement(Outlet, null)));
2035
+ }, /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
2036
+ value: [undefined, ...currentMatches]
2037
+ }, /*#__PURE__*/React__namespace.createElement(Outlet, null))));
2720
2038
  }
2721
-
2722
2039
  function useRouter() {
2723
2040
  const value = React__namespace.useContext(routerContext);
2724
2041
  warning(!value, 'useRouter must be used inside a <Router> component!');
2725
- useRouterSubscription(value.router);
2726
2042
  return value.router;
2727
2043
  }
2728
-
2044
+ function useRouterStore(selector, shallow) {
2045
+ const router = useRouter();
2046
+ return useStore(router.store, selector, shallow);
2047
+ }
2729
2048
  function useMatches() {
2730
2049
  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
2050
  }
2747
-
2051
+ function useMatch(opts) {
2052
+ const router = useRouter();
2053
+ const nearestMatch = useMatches()[0];
2054
+ const match = opts?.from ? router.store.state.currentMatches.find(d => d.route.id === opts?.from) : nearestMatch;
2055
+ invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
2056
+ if (opts?.strict ?? true) {
2057
+ 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?`);
2058
+ }
2059
+ useStore(match.store, d => opts?.track?.(match) ?? match, opts?.shallow);
2060
+ return match;
2061
+ }
2062
+ function useRoute(routeId) {
2063
+ const router = useRouter();
2064
+ const resolvedRoute = router.getRoute(routeId);
2065
+ invariant(resolvedRoute, `Could not find a route for route "${routeId}"! Did you forget to add it to your route config?`);
2066
+ return resolvedRoute;
2067
+ }
2068
+ function useLoaderData(opts) {
2069
+ const match = useMatch(opts);
2070
+ invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
2071
+ useStore(match.store, d => opts?.track?.(d.loaderData) ?? d.loaderData);
2072
+ return match.store.state.loaderData;
2073
+ }
2074
+ function useSearch(opts) {
2075
+ const match = useMatch(opts);
2076
+ useStore(match.store, d => opts?.track?.(d.search) ?? d.search);
2077
+ return match.store.state.search;
2078
+ }
2079
+ function useParams(opts) {
2080
+ const router = useRouter();
2081
+ useStore(router.store, d => {
2082
+ const params = last(d.currentMatches)?.params;
2083
+ return opts?.track?.(params) ?? params;
2084
+ });
2085
+ return last(router.store.state.currentMatches)?.params;
2086
+ }
2087
+ function useNavigate(defaultOpts) {
2088
+ const router = useRouter();
2089
+ return opts => {
2090
+ return router.navigate({
2091
+ ...defaultOpts,
2092
+ ...opts
2093
+ });
2094
+ };
2095
+ }
2096
+ function useMatchRoute() {
2097
+ const router = useRouter();
2098
+ return opts => {
2099
+ const {
2100
+ pending,
2101
+ caseSensitive,
2102
+ ...rest
2103
+ } = opts;
2104
+ return router.matchRoute(rest, {
2105
+ pending,
2106
+ caseSensitive
2107
+ });
2108
+ };
2109
+ }
2110
+ function MatchRoute(props) {
2111
+ const matchRoute = useMatchRoute();
2112
+ const params = matchRoute(props);
2113
+ if (!params) {
2114
+ return null;
2115
+ }
2116
+ if (typeof props.children === 'function') {
2117
+ return props.children(params);
2118
+ }
2119
+ return params ? props.children : null;
2120
+ }
2748
2121
  function Outlet() {
2749
- var _childMatch$options$c;
2750
-
2122
+ const matches = useMatches().slice(1);
2123
+ const match = matches[0];
2124
+ if (!match) {
2125
+ return null;
2126
+ }
2127
+ return /*#__PURE__*/React__namespace.createElement(SubOutlet, {
2128
+ matches: matches,
2129
+ match: match
2130
+ });
2131
+ }
2132
+ function SubOutlet({
2133
+ matches,
2134
+ match
2135
+ }) {
2751
2136
  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;
2137
+ useStore(match.store);
2138
+ const defaultPending = React__namespace.useCallback(() => null, []);
2139
+ const Inner = React__namespace.useCallback(props => {
2140
+ if (props.match.store.state.status === 'error') {
2141
+ throw props.match.store.state.error;
2761
2142
  }
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
- });
2143
+ if (props.match.store.state.status === 'success') {
2144
+ return /*#__PURE__*/React__namespace.createElement(props.match.component ?? router.options.defaultComponent ?? Outlet);
2777
2145
  }
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;
2146
+ if (props.match.store.state.status === 'loading') {
2147
+ throw props.match.__loadPromise;
2793
2148
  }
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
2149
+ invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
2150
+ }, []);
2151
+ const PendingComponent = match.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
2152
+ const errorComponent = match.errorComponent ?? router.options.defaultErrorComponent;
2153
+ return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
2154
+ value: matches
2155
+ }, /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
2156
+ fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, null)
2802
2157
  }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
2803
- catchElement: catchElement
2804
- }, element));
2158
+ key: match.route.id,
2159
+ errorComponent: errorComponent,
2160
+ match: match
2161
+ }, /*#__PURE__*/React__namespace.createElement(Inner, {
2162
+ match: match
2163
+ }))));
2805
2164
  }
2806
-
2807
2165
  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
-
2166
+ state = {
2167
+ error: false,
2168
+ info: undefined
2169
+ };
2822
2170
  componentDidCatch(error, info) {
2171
+ console.error(`Error in route match: ${this.props.match.id}`);
2823
2172
  console.error(error);
2824
2173
  this.setState({
2825
2174
  error,
2826
2175
  info
2827
2176
  });
2828
2177
  }
2829
-
2830
2178
  render() {
2831
- var _this$props$catchElem;
2179
+ return /*#__PURE__*/React__namespace.createElement(CatchBoundaryInner, _extends({}, this.props, {
2180
+ errorState: this.state,
2181
+ reset: () => this.setState({})
2182
+ }));
2183
+ }
2184
+ }
2832
2185
 
2833
- const catchElement = (_this$props$catchElem = this.props.catchElement) != null ? _this$props$catchElem : DefaultErrorBoundary;
2186
+ // This is the messiest thing ever... I'm either seriously tired (likely) or
2187
+ // there has to be a better way to reset error boundaries when the
2188
+ // router's location key changes.
2189
+ function CatchBoundaryInner(props) {
2190
+ const [activeErrorState, setActiveErrorState] = React__namespace.useState(props.errorState);
2191
+ useRouter();
2192
+ const errorComponent = props.errorComponent ?? DefaultErrorBoundary;
2193
+
2194
+ // React.useEffect(() => {
2195
+ // if (activeErrorState) {
2196
+ // let prevKey = router.store.currentLocation.key
2197
+ // return createRoot((dispose) => {
2198
+ // createEffect(() => {
2199
+ // if (router.store.currentLocation.key !== prevKey) {
2200
+ // prevKey = router.store.currentLocation.key
2201
+ // setActiveErrorState({} as any)
2202
+ // }
2203
+ // })
2204
+
2205
+ // return dispose
2206
+ // })
2207
+ // }
2834
2208
 
2835
- if (this.state.error) {
2836
- return typeof catchElement === 'function' ? catchElement(this.state) : catchElement;
2837
- }
2209
+ // return
2210
+ // }, [activeErrorState])
2838
2211
 
2839
- return this.props.children;
2212
+ React__namespace.useEffect(() => {
2213
+ if (props.errorState.error) {
2214
+ setActiveErrorState(props.errorState);
2215
+ }
2216
+ props.reset();
2217
+ }, [props.errorState.error]);
2218
+ if (props.errorState.error) {
2219
+ return /*#__PURE__*/React__namespace.createElement(errorComponent, activeErrorState);
2840
2220
  }
2841
-
2221
+ return props.children;
2842
2222
  }
2843
-
2844
- function DefaultErrorBoundary(_ref5) {
2845
- let {
2846
- error
2847
- } = _ref5;
2223
+ function DefaultErrorBoundary({
2224
+ error
2225
+ }) {
2848
2226
  return /*#__PURE__*/React__namespace.createElement("div", {
2849
2227
  style: {
2850
2228
  padding: '.5rem',
@@ -2866,60 +2244,65 @@
2866
2244
  padding: '.5rem',
2867
2245
  color: 'red'
2868
2246
  }
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]);
2247
+ }, error.message) : null)));
2896
2248
  }
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;
2249
+ function useAction(action, opts) {
2250
+ useStore(action.store, d => opts?.track?.(d) ?? d, true);
2251
+ const [ref] = React__namespace.useState({});
2252
+ Object.assign(ref, {
2253
+ ...action,
2254
+ latestSubmission: action.store.state.submissions[action.store.state.submissions.length - 1],
2255
+ pendingSubmissions: React__namespace.useMemo(() => action.store.state.submissions.filter(d => d.status === 'pending'), [action.store.state.submissions])
2256
+ });
2257
+ return ref;
2905
2258
  }
2906
2259
 
2260
+ // TODO: While we migrate away from the history package, these need to be disabled
2261
+ // export function usePrompt(message: string, when: boolean | any): void {
2262
+ // const router = useRouter()
2263
+
2264
+ // React.useEffect(() => {
2265
+ // if (!when) return
2266
+
2267
+ // let unblock = router.getHistory().block((transition) => {
2268
+ // if (window.confirm(message)) {
2269
+ // unblock()
2270
+ // transition.retry()
2271
+ // } else {
2272
+ // router.setStore((s) => {
2273
+ // s.currentLocation.pathname = window.location.pathname
2274
+ // })
2275
+ // }
2276
+ // })
2277
+
2278
+ // return unblock
2279
+ // }, [when, message])
2280
+ // }
2281
+
2282
+ // export function Prompt({ message, when, children }: PromptProps) {
2283
+ // usePrompt(message, when ?? true)
2284
+ // return (children ?? null) as ReactNode
2285
+ // }
2286
+
2907
2287
  exports.DefaultErrorBoundary = DefaultErrorBoundary;
2908
- exports.MatchesProvider = MatchesProvider;
2288
+ exports.Link = Link;
2289
+ exports.MatchRoute = MatchRoute;
2909
2290
  exports.Outlet = Outlet;
2910
- exports.Prompt = Prompt;
2291
+ exports.ReactRouter = ReactRouter;
2292
+ exports.Route = Route;
2293
+ exports.RouteMatch = RouteMatch;
2294
+ exports.Router = Router;
2911
2295
  exports.RouterProvider = RouterProvider;
2912
- exports.cascadeLoaderData = cascadeLoaderData;
2296
+ exports.batch = batch;
2913
2297
  exports.cleanPath = cleanPath;
2298
+ exports.createAction = createAction;
2914
2299
  exports.createBrowserHistory = createBrowserHistory;
2915
2300
  exports.createHashHistory = createHashHistory;
2916
2301
  exports.createMemoryHistory = createMemoryHistory;
2917
- exports.createReactRouter = createReactRouter;
2918
- exports.createRoute = createRoute;
2919
2302
  exports.createRouteConfig = createRouteConfig;
2920
- exports.createRouteMatch = createRouteMatch;
2921
- exports.createRouter = createRouter;
2303
+ exports.createStore = createStore;
2922
2304
  exports.decode = decode;
2305
+ exports.defaultFetchServerDataFn = defaultFetchServerDataFn;
2923
2306
  exports.defaultParseSearch = defaultParseSearch;
2924
2307
  exports.defaultStringifySearch = defaultStringifySearch;
2925
2308
  exports.encode = encode;
@@ -2928,18 +2311,35 @@
2928
2311
  exports.invariant = invariant;
2929
2312
  exports.joinPaths = joinPaths;
2930
2313
  exports.last = last;
2314
+ exports.lazy = lazy;
2931
2315
  exports.matchByPath = matchByPath;
2932
2316
  exports.matchPathname = matchPathname;
2317
+ exports.matchesContext = matchesContext;
2933
2318
  exports.parsePathname = parsePathname;
2934
2319
  exports.parseSearchWith = parseSearchWith;
2320
+ exports.pick = pick;
2935
2321
  exports.replaceEqualDeep = replaceEqualDeep;
2936
2322
  exports.resolvePath = resolvePath;
2937
2323
  exports.rootRouteId = rootRouteId;
2324
+ exports.routerContext = routerContext;
2938
2325
  exports.stringifySearchWith = stringifySearchWith;
2326
+ exports.trackDeep = trackDeep;
2939
2327
  exports.trimPath = trimPath;
2940
2328
  exports.trimPathLeft = trimPathLeft;
2941
2329
  exports.trimPathRight = trimPathRight;
2942
- exports.usePrompt = usePrompt;
2330
+ exports.useAction = useAction;
2331
+ exports.useLinkProps = useLinkProps;
2332
+ exports.useLoaderData = useLoaderData;
2333
+ exports.useMatch = useMatch;
2334
+ exports.useMatchRoute = useMatchRoute;
2335
+ exports.useMatches = useMatches;
2336
+ exports.useNavigate = useNavigate;
2337
+ exports.useParams = useParams;
2338
+ exports.useRoute = useRoute;
2339
+ exports.useRouter = useRouter;
2340
+ exports.useRouterStore = useRouterStore;
2341
+ exports.useSearch = useSearch;
2342
+ exports.useStore = useStore;
2943
2343
  exports.warning = warning;
2944
2344
 
2945
2345
  Object.defineProperty(exports, '__esModule', { value: true });