@tanstack/router-core 0.0.1-alpha.8 → 0.0.1-beta.1

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.
@@ -1260,6 +1260,40 @@
1260
1260
  return router.state.actions[id];
1261
1261
  })();
1262
1262
 
1263
+ const loader = router.state.loaders[id] || (() => {
1264
+ router.state.loaders[id] = {
1265
+ pending: [],
1266
+ fetch: async loaderContext => {
1267
+ if (!route) {
1268
+ return;
1269
+ }
1270
+
1271
+ const loaderState = {
1272
+ loadedAt: Date.now(),
1273
+ loaderContext
1274
+ };
1275
+ loader.current = loaderState;
1276
+ loader.latest = loaderState;
1277
+ loader.pending.push(loaderState); // router.state = {
1278
+ // ...router.state,
1279
+ // currentAction: loaderState,
1280
+ // latestAction: loaderState,
1281
+ // }
1282
+
1283
+ router.notify();
1284
+
1285
+ try {
1286
+ return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
1287
+ } finally {
1288
+ loader.pending = loader.pending.filter(d => d !== loaderState); // router.removeActionQueue.push({ loader, loaderState })
1289
+
1290
+ router.notify();
1291
+ }
1292
+ }
1293
+ };
1294
+ return router.state.loaders[id];
1295
+ })();
1296
+
1263
1297
  let route = {
1264
1298
  routeId: id,
1265
1299
  routeRouteId: routeId,
@@ -1270,6 +1304,7 @@
1270
1304
  childRoutes: undefined,
1271
1305
  parentRoute: parent,
1272
1306
  action,
1307
+ loader: loader,
1273
1308
  buildLink: options => {
1274
1309
  return router.buildLink(_extends({}, options, {
1275
1310
  from: fullPath
@@ -1365,12 +1400,10 @@
1365
1400
  isPending: false,
1366
1401
  isFetching: false,
1367
1402
  isInvalid: false,
1403
+ invalidAt: Infinity,
1368
1404
  getIsInvalid: () => {
1369
- var _ref, _routeMatch$options$l;
1370
-
1371
1405
  const now = Date.now();
1372
- const maxAge = (_ref = (_routeMatch$options$l = routeMatch.options.loaderMaxAge) != null ? _routeMatch$options$l : router.options.defaultLoaderMaxAge) != null ? _ref : 0;
1373
- return routeMatch.isInvalid || routeMatch.updatedAt + maxAge < now;
1406
+ return routeMatch.isInvalid || routeMatch.invalidAt < now;
1374
1407
  },
1375
1408
  __: {
1376
1409
  abortController: new AbortController(),
@@ -1459,9 +1492,33 @@
1459
1492
  routeMatch.isInvalid = true;
1460
1493
  },
1461
1494
  hasLoaders: () => {
1462
- return !!(route.options.loader || route.options.import || elementTypes.some(d => typeof route.options[d] === 'function'));
1495
+ return !!(route.options.loader || elementTypes.some(d => typeof route.options[d] === 'function'));
1496
+ },
1497
+ load: async loaderOpts => {
1498
+ const now = Date.now();
1499
+ 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
1500
+
1501
+ if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
1502
+ // If the match is currently active, don't preload it
1503
+ if (router.state.matches.find(d => d.matchId === routeMatch.matchId)) {
1504
+ return;
1505
+ }
1506
+
1507
+ router.matchCache[routeMatch.matchId] = {
1508
+ gc: now + loaderOpts.gcMaxAge,
1509
+ match: routeMatch
1510
+ };
1511
+ } // If the match is invalid, errored or idle, trigger it to load
1512
+
1513
+
1514
+ if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
1515
+ const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
1516
+ routeMatch.fetch({
1517
+ maxAge
1518
+ });
1519
+ }
1463
1520
  },
1464
- load: async () => {
1521
+ fetch: async opts => {
1465
1522
  const id = '' + Date.now() + Math.random();
1466
1523
  routeMatch.__.latestId = id; // If the match was in an error state, set it
1467
1524
  // to a loading state again. Otherwise, keep it
@@ -1480,21 +1537,7 @@
1480
1537
  routeMatch.__.resolve = resolve;
1481
1538
 
1482
1539
  const loaderPromise = (async () => {
1483
- const importer = routeMatch.options.import; // First, run any importers
1484
-
1485
- if (importer) {
1486
- routeMatch.__.importPromise = importer({
1487
- params: routeMatch.params // search: routeMatch.search,
1488
-
1489
- }).then(imported => {
1490
- routeMatch.__ = _extends({}, routeMatch.__, imported);
1491
- });
1492
- } // Wait for the importer to finish before
1493
- // attempting to load elements and data
1494
-
1495
-
1496
- await routeMatch.__.importPromise; // Next, load the elements and data in parallel
1497
-
1540
+ // Load the elements and data in parallel
1498
1541
  routeMatch.__.elementsPromise = (async () => {
1499
1542
  // then run all element and data loaders in parallel
1500
1543
  // For each element type, potentially load it asynchronously
@@ -1505,17 +1548,14 @@
1505
1548
  return;
1506
1549
  }
1507
1550
 
1508
- if (typeof routeElement === 'function') {
1509
- const res = await routeElement(routeMatch);
1510
- routeMatch.__[type] = res;
1511
- } else {
1512
- routeMatch.__[type] = routeMatch.options[type];
1513
- }
1551
+ routeMatch.__[type] = await router.options.createElement(routeElement);
1514
1552
  }));
1515
1553
  })();
1516
1554
 
1517
1555
  routeMatch.__.dataPromise = Promise.resolve().then(async () => {
1518
1556
  try {
1557
+ var _ref, _ref2, _opts$maxAge;
1558
+
1519
1559
  if (routeMatch.options.loader) {
1520
1560
  const data = await routeMatch.options.loader({
1521
1561
  params: routeMatch.params,
@@ -1533,6 +1573,7 @@
1533
1573
  routeMatch.error = undefined;
1534
1574
  routeMatch.status = 'success';
1535
1575
  routeMatch.updatedAt = Date.now();
1576
+ 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);
1536
1577
  } catch (err) {
1537
1578
  if (id !== routeMatch.__.latestId) {
1538
1579
  return routeMatch.__.loaderPromise;
@@ -1655,13 +1696,15 @@
1655
1696
  const originalOptions = _extends({
1656
1697
  defaultLoaderGcMaxAge: 5 * 60 * 1000,
1657
1698
  defaultLoaderMaxAge: 0,
1658
- defaultLinkPreloadDelay: 50
1699
+ defaultPreloadMaxAge: 2000,
1700
+ defaultPreloadDelay: 50
1659
1701
  }, userOptions, {
1660
1702
  stringifySearch: (_userOptions$stringif = userOptions == null ? void 0 : userOptions.stringifySearch) != null ? _userOptions$stringif : defaultStringifySearch,
1661
1703
  parseSearch: (_userOptions$parseSea = userOptions == null ? void 0 : userOptions.parseSearch) != null ? _userOptions$parseSea : defaultParseSearch
1662
1704
  });
1663
1705
 
1664
1706
  let router = {
1707
+ history,
1665
1708
  options: originalOptions,
1666
1709
  listeners: [],
1667
1710
  removeActionQueue: [],
@@ -1680,6 +1723,7 @@
1680
1723
  location: null,
1681
1724
  matches: [],
1682
1725
  actions: {},
1726
+ loaders: {},
1683
1727
  loaderData: {},
1684
1728
  lastUpdated: Date.now(),
1685
1729
  isFetching: false,
@@ -1704,21 +1748,22 @@
1704
1748
  router.listeners.forEach(listener => listener());
1705
1749
  },
1706
1750
  mount: () => {
1707
- const next = router.buildLocation({
1751
+ const next = router.__.buildLocation({
1708
1752
  to: '.',
1709
1753
  search: true,
1710
1754
  hash: true
1711
1755
  }); // If the current location isn't updated, trigger a navigation
1712
1756
  // to the current location. Otherwise, load the current location.
1713
1757
 
1758
+
1714
1759
  if (next.href !== router.location.href) {
1715
- router.commitLocation(next, true);
1760
+ router.__.commitLocation(next, true);
1716
1761
  } else {
1717
1762
  router.loadLocation();
1718
1763
  }
1719
1764
 
1720
1765
  const unsub = history.listen(event => {
1721
- router.loadLocation(router.parseLocation(event.location, router.location));
1766
+ router.loadLocation(router.__.parseLocation(event.location, router.location));
1722
1767
  }); // addEventListener does not exist in React Native, but window does
1723
1768
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1724
1769
 
@@ -1748,169 +1793,11 @@
1748
1793
 
1749
1794
  if (routeConfig) {
1750
1795
  router.routesById = {};
1751
- router.routeTree = router.buildRouteTree(routeConfig);
1796
+ router.routeTree = router.__.buildRouteTree(routeConfig);
1752
1797
  }
1753
1798
 
1754
1799
  return router;
1755
1800
  },
1756
- buildRouteTree: rootRouteConfig => {
1757
- const recurseRoutes = (routeConfigs, parent) => {
1758
- return routeConfigs.map(routeConfig => {
1759
- const routeOptions = routeConfig.options;
1760
- const route = createRoute(routeConfig, routeOptions, parent, router); // {
1761
- // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
1762
- // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
1763
- // }
1764
-
1765
- const existingRoute = router.routesById[route.routeId];
1766
-
1767
- if (existingRoute) {
1768
- {
1769
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
1770
- }
1771
-
1772
- throw new Error();
1773
- }
1774
- router.routesById[route.routeId] = route;
1775
- const children = routeConfig.children;
1776
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
1777
- return route;
1778
- });
1779
- };
1780
-
1781
- const routes = recurseRoutes([rootRouteConfig]);
1782
- return routes[0];
1783
- },
1784
- parseLocation: (location, previousLocation) => {
1785
- var _location$hash$split$;
1786
-
1787
- const parsedSearch = router.options.parseSearch(location.search);
1788
- return {
1789
- pathname: location.pathname,
1790
- searchStr: location.search,
1791
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
1792
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
1793
- href: "" + location.pathname + location.search + location.hash,
1794
- state: location.state,
1795
- key: location.key
1796
- };
1797
- },
1798
- buildLocation: function buildLocation(dest) {
1799
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
1800
-
1801
- if (dest === void 0) {
1802
- dest = {};
1803
- }
1804
-
1805
- // const resolvedFrom: Location = {
1806
- // ...router.location,
1807
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
1808
-
1809
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1810
-
1811
- const fromMatches = router.matchRoutes(router.location.pathname, {
1812
- strictParseParams: true
1813
- });
1814
- const toMatches = router.matchRoutes(pathname);
1815
-
1816
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1817
-
1818
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1819
-
1820
- if (nextParams) {
1821
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
1822
- Object.assign({}, nextParams, fn(nextParams));
1823
- });
1824
- }
1825
-
1826
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
1827
-
1828
- 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
1829
-
1830
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1831
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
1832
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
1833
- : {}; // Then post filters
1834
-
1835
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1836
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
1837
- const searchStr = router.options.stringifySearch(search);
1838
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
1839
- hash = hash ? "#" + hash : '';
1840
- return {
1841
- pathname,
1842
- search,
1843
- searchStr,
1844
- state: router.location.state,
1845
- hash,
1846
- href: "" + pathname + searchStr + hash,
1847
- key: dest.key
1848
- };
1849
- },
1850
- commitLocation: (next, replace) => {
1851
- const id = '' + Date.now() + Math.random();
1852
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
1853
- let nextAction = 'replace';
1854
-
1855
- if (!replace) {
1856
- nextAction = 'push';
1857
- }
1858
-
1859
- const isSameUrl = router.parseLocation(history.location).href === next.href;
1860
-
1861
- if (isSameUrl && !next.key) {
1862
- nextAction = 'replace';
1863
- }
1864
-
1865
- if (nextAction === 'replace') {
1866
- history.replace({
1867
- pathname: next.pathname,
1868
- hash: next.hash,
1869
- search: next.searchStr
1870
- }, {
1871
- id
1872
- });
1873
- } else {
1874
- history.push({
1875
- pathname: next.pathname,
1876
- hash: next.hash,
1877
- search: next.searchStr
1878
- }, {
1879
- id
1880
- });
1881
- }
1882
-
1883
- router.navigationPromise = new Promise(resolve => {
1884
- const previousNavigationResolve = router.resolveNavigation;
1885
-
1886
- router.resolveNavigation = () => {
1887
- previousNavigationResolve();
1888
- resolve();
1889
- };
1890
- });
1891
- return router.navigationPromise;
1892
- },
1893
- buildNext: opts => {
1894
- const next = router.buildLocation(opts);
1895
- const matches = router.matchRoutes(next.pathname);
1896
-
1897
- const __preSearchFilters = matches.map(match => {
1898
- var _match$options$preSea;
1899
-
1900
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
1901
- }).flat().filter(Boolean);
1902
-
1903
- const __postSearchFilters = matches.map(match => {
1904
- var _match$options$postSe;
1905
-
1906
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
1907
- }).flat().filter(Boolean);
1908
-
1909
- return router.buildLocation(_extends({}, opts, {
1910
- __preSearchFilters,
1911
- __postSearchFilters
1912
- }));
1913
- },
1914
1801
  cancelMatches: () => {
1915
1802
  var _router$state$pending, _router$state$pending2;
1916
1803
  [...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 => {
@@ -2013,6 +1900,7 @@
2013
1900
  params: d.params,
2014
1901
  search: d.search
2015
1902
  });
1903
+ delete router.matchCache[d.matchId];
2016
1904
  });
2017
1905
 
2018
1906
  if (matches.some(d => d.status === 'loading')) {
@@ -2052,7 +1940,21 @@
2052
1940
  delete router.matchCache[matchId];
2053
1941
  });
2054
1942
  },
2055
- loadRoute: async function loadRoute(navigateOpts, loaderOpts) {
1943
+ loadRoute: async function loadRoute(navigateOpts) {
1944
+ if (navigateOpts === void 0) {
1945
+ navigateOpts = router.location;
1946
+ }
1947
+
1948
+ const next = router.buildNext(navigateOpts);
1949
+ const matches = router.matchRoutes(next.pathname, {
1950
+ strictParseParams: true
1951
+ });
1952
+ await router.loadMatches(matches);
1953
+ return matches;
1954
+ },
1955
+ preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
1956
+ var _ref4, _ref5, _loaderOpts$maxAge, _ref6, _ref7, _loaderOpts$gcMaxAge;
1957
+
2056
1958
  if (navigateOpts === void 0) {
2057
1959
  navigateOpts = router.location;
2058
1960
  }
@@ -2063,7 +1965,8 @@
2063
1965
  });
2064
1966
  await router.loadMatches(matches, {
2065
1967
  preload: true,
2066
- maxAge: loaderOpts.maxAge
1968
+ maxAge: (_ref4 = (_ref5 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref5 : router.options.defaultLoaderMaxAge) != null ? _ref4 : 0,
1969
+ gcMaxAge: (_ref6 = (_ref7 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0
2067
1970
  });
2068
1971
  return matches;
2069
1972
  },
@@ -2157,33 +2060,11 @@
2157
2060
  return matches;
2158
2061
  },
2159
2062
  loadMatches: async (resolvedMatches, loaderOpts) => {
2160
- const now = Date.now();
2161
2063
  const matchPromises = resolvedMatches.map(async match => {
2162
2064
  // Validate the match (loads search params etc)
2163
- match.__.validate(); // // If the match doesn't have a loader, don't attempt to load it
2164
- // if (!match.hasLoaders()) {
2165
- // return
2166
- // }
2167
- // If this is a preload, add it to the preload cache
2168
-
2169
-
2170
- if (loaderOpts != null && loaderOpts.preload && (loaderOpts == null ? void 0 : loaderOpts.maxAge) > 0) {
2171
- // If the match is currently active, don't preload it
2172
- if (router.state.matches.find(d => d.matchId === match.matchId)) {
2173
- return;
2174
- }
2175
-
2176
- router.matchCache[match.matchId] = {
2177
- gc: now + loaderOpts.maxAge,
2178
- // TODO: Should this use the route's maxAge?
2179
- match
2180
- };
2181
- } // If the match is invalid, errored or idle, trigger it to load
2182
-
2065
+ match.__.validate();
2183
2066
 
2184
- if (match.status === 'success' && match.getIsInvalid() || match.status === 'error' || match.status === 'idle') {
2185
- match.load();
2186
- }
2067
+ match.load(loaderOpts);
2187
2068
 
2188
2069
  if (match.status === 'loading') {
2189
2070
  // If requested, start the pending timers
@@ -2207,7 +2088,7 @@
2207
2088
  }
2208
2089
  });
2209
2090
  },
2210
- reload: () => router._navigate({
2091
+ reload: () => router.__.navigate({
2211
2092
  fromCurrent: true,
2212
2093
  replace: true,
2213
2094
  search: true
@@ -2240,11 +2121,7 @@
2240
2121
  to: next.pathname
2241
2122
  }));
2242
2123
  },
2243
- _navigate: location => {
2244
- const next = router.buildNext(location);
2245
- return router.commitLocation(next, location.replace);
2246
- },
2247
- navigate: async _ref4 => {
2124
+ navigate: async _ref8 => {
2248
2125
  let {
2249
2126
  from,
2250
2127
  to = '.',
@@ -2252,7 +2129,7 @@
2252
2129
  hash,
2253
2130
  replace,
2254
2131
  params
2255
- } = _ref4;
2132
+ } = _ref8;
2256
2133
  // If this link simply reloads the current route,
2257
2134
  // make sure it has a new key so it will trigger a data refresh
2258
2135
  // If this `to` is a valid external URL, return
@@ -2267,7 +2144,7 @@
2267
2144
  } catch (e) {}
2268
2145
 
2269
2146
  invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2270
- return router._navigate({
2147
+ return router.__.navigate({
2271
2148
  from: fromString,
2272
2149
  to: toString,
2273
2150
  search,
@@ -2276,8 +2153,8 @@
2276
2153
  params
2277
2154
  });
2278
2155
  },
2279
- buildLink: _ref5 => {
2280
- var _preload, _ref6, _ref7, _ref8;
2156
+ buildLink: _ref9 => {
2157
+ var _preload, _ref10;
2281
2158
 
2282
2159
  let {
2283
2160
  from,
@@ -2290,9 +2167,10 @@
2290
2167
  activeOptions,
2291
2168
  preload,
2292
2169
  preloadMaxAge: userPreloadMaxAge,
2170
+ preloadGcMaxAge: userPreloadGcMaxAge,
2293
2171
  preloadDelay: userPreloadDelay,
2294
2172
  disabled
2295
- } = _ref5;
2173
+ } = _ref9;
2296
2174
 
2297
2175
  // If this link simply reloads the current route,
2298
2176
  // make sure it has a new key so it will trigger a data refresh
@@ -2315,9 +2193,8 @@
2315
2193
  replace
2316
2194
  };
2317
2195
  const next = router.buildNext(nextOpts);
2318
- preload = (_preload = preload) != null ? _preload : router.options.defaultLinkPreload;
2319
- const preloadMaxAge = (_ref6 = (_ref7 = userPreloadMaxAge != null ? userPreloadMaxAge : router.options.defaultLinkPreloadMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0;
2320
- const preloadDelay = (_ref8 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultLinkPreloadDelay) != null ? _ref8 : 0; // Compare path/hash for matches
2196
+ preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
2197
+ const preloadDelay = (_ref10 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref10 : 0; // Compare path/hash for matches
2321
2198
 
2322
2199
  const pathIsEqual = router.state.location.pathname === next.pathname;
2323
2200
  const currentPathSplit = router.state.location.pathname.split('/');
@@ -2339,15 +2216,16 @@
2339
2216
  } // All is well? Navigate!)
2340
2217
 
2341
2218
 
2342
- router._navigate(nextOpts);
2219
+ router.__.navigate(nextOpts);
2343
2220
  }
2344
2221
  }; // The click handler
2345
2222
 
2346
2223
 
2347
2224
  const handleFocus = e => {
2348
- if (preload && preloadMaxAge > 0) {
2349
- router.loadRoute(nextOpts, {
2350
- maxAge: preloadMaxAge
2225
+ if (preload) {
2226
+ router.preloadRoute(nextOpts, {
2227
+ maxAge: userPreloadMaxAge,
2228
+ gcMaxAge: userPreloadGcMaxAge
2351
2229
  });
2352
2230
  }
2353
2231
  };
@@ -2355,15 +2233,16 @@
2355
2233
  const handleEnter = e => {
2356
2234
  const target = e.target || {};
2357
2235
 
2358
- if (preload && preloadMaxAge > 0) {
2236
+ if (preload) {
2359
2237
  if (target.preloadTimeout) {
2360
2238
  return;
2361
2239
  }
2362
2240
 
2363
2241
  target.preloadTimeout = setTimeout(() => {
2364
2242
  target.preloadTimeout = null;
2365
- router.loadRoute(nextOpts, {
2366
- maxAge: preloadMaxAge
2243
+ router.preloadRoute(nextOpts, {
2244
+ maxAge: userPreloadMaxAge,
2245
+ gcMaxAge: userPreloadGcMaxAge
2367
2246
  });
2368
2247
  }, preloadDelay);
2369
2248
  }
@@ -2388,9 +2267,174 @@
2388
2267
  isActive,
2389
2268
  disabled
2390
2269
  };
2270
+ },
2271
+ buildNext: opts => {
2272
+ const next = router.__.buildLocation(opts);
2273
+
2274
+ const matches = router.matchRoutes(next.pathname);
2275
+
2276
+ const __preSearchFilters = matches.map(match => {
2277
+ var _match$options$preSea;
2278
+
2279
+ return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
2280
+ }).flat().filter(Boolean);
2281
+
2282
+ const __postSearchFilters = matches.map(match => {
2283
+ var _match$options$postSe;
2284
+
2285
+ return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
2286
+ }).flat().filter(Boolean);
2287
+
2288
+ return router.__.buildLocation(_extends({}, opts, {
2289
+ __preSearchFilters,
2290
+ __postSearchFilters
2291
+ }));
2292
+ },
2293
+ __: {
2294
+ buildRouteTree: rootRouteConfig => {
2295
+ const recurseRoutes = (routeConfigs, parent) => {
2296
+ return routeConfigs.map(routeConfig => {
2297
+ const routeOptions = routeConfig.options;
2298
+ const route = createRoute(routeConfig, routeOptions, parent, router); // {
2299
+ // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
2300
+ // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
2301
+ // }
2302
+
2303
+ const existingRoute = router.routesById[route.routeId];
2304
+
2305
+ if (existingRoute) {
2306
+ {
2307
+ console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
2308
+ }
2309
+
2310
+ throw new Error();
2311
+ }
2312
+ router.routesById[route.routeId] = route;
2313
+ const children = routeConfig.children;
2314
+ route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2315
+ return route;
2316
+ });
2317
+ };
2318
+
2319
+ const routes = recurseRoutes([rootRouteConfig]);
2320
+ return routes[0];
2321
+ },
2322
+ parseLocation: (location, previousLocation) => {
2323
+ var _location$hash$split$;
2324
+
2325
+ const parsedSearch = router.options.parseSearch(location.search);
2326
+ return {
2327
+ pathname: location.pathname,
2328
+ searchStr: location.search,
2329
+ search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2330
+ hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
2331
+ href: "" + location.pathname + location.search + location.hash,
2332
+ state: location.state,
2333
+ key: location.key
2334
+ };
2335
+ },
2336
+ navigate: location => {
2337
+ const next = router.buildNext(location);
2338
+ return router.__.commitLocation(next, location.replace);
2339
+ },
2340
+ buildLocation: function buildLocation(dest) {
2341
+ var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
2342
+
2343
+ if (dest === void 0) {
2344
+ dest = {};
2345
+ }
2346
+
2347
+ // const resolvedFrom: Location = {
2348
+ // ...router.location,
2349
+ const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
2350
+
2351
+ let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
2352
+
2353
+ const fromMatches = router.matchRoutes(router.location.pathname, {
2354
+ strictParseParams: true
2355
+ });
2356
+ const toMatches = router.matchRoutes(pathname);
2357
+
2358
+ const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
2359
+
2360
+ let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
2361
+
2362
+ if (nextParams) {
2363
+ toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2364
+ Object.assign({}, nextParams, fn(nextParams));
2365
+ });
2366
+ }
2367
+
2368
+ pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
2369
+
2370
+ 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
2371
+
2372
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2373
+ : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
2374
+ : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2375
+ : {}; // Then post filters
2376
+
2377
+ const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2378
+ const search = replaceEqualDeep(router.location.search, postFilteredSearch);
2379
+ const searchStr = router.options.stringifySearch(search);
2380
+ let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
2381
+ hash = hash ? "#" + hash : '';
2382
+ return {
2383
+ pathname,
2384
+ search,
2385
+ searchStr,
2386
+ state: router.location.state,
2387
+ hash,
2388
+ href: "" + pathname + searchStr + hash,
2389
+ key: dest.key
2390
+ };
2391
+ },
2392
+ commitLocation: (next, replace) => {
2393
+ const id = '' + Date.now() + Math.random();
2394
+ if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
2395
+ let nextAction = 'replace';
2396
+
2397
+ if (!replace) {
2398
+ nextAction = 'push';
2399
+ }
2400
+
2401
+ const isSameUrl = router.__.parseLocation(history.location).href === next.href;
2402
+
2403
+ if (isSameUrl && !next.key) {
2404
+ nextAction = 'replace';
2405
+ }
2406
+
2407
+ if (nextAction === 'replace') {
2408
+ history.replace({
2409
+ pathname: next.pathname,
2410
+ hash: next.hash,
2411
+ search: next.searchStr
2412
+ }, {
2413
+ id
2414
+ });
2415
+ } else {
2416
+ history.push({
2417
+ pathname: next.pathname,
2418
+ hash: next.hash,
2419
+ search: next.searchStr
2420
+ }, {
2421
+ id
2422
+ });
2423
+ }
2424
+
2425
+ router.navigationPromise = new Promise(resolve => {
2426
+ const previousNavigationResolve = router.resolveNavigation;
2427
+
2428
+ router.resolveNavigation = () => {
2429
+ previousNavigationResolve();
2430
+ resolve();
2431
+ };
2432
+ });
2433
+ return router.navigationPromise;
2434
+ }
2391
2435
  }
2392
2436
  };
2393
- router.location = router.parseLocation(history.location);
2437
+ router.location = router.__.parseLocation(history.location);
2394
2438
  router.state.location = router.location;
2395
2439
  router.update(userOptions); // Allow frameworks to hook into the router creation
2396
2440