@tanstack/react-router 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.
@@ -1274,6 +1274,40 @@ function createRoute(routeConfig, options, parent, router) {
1274
1274
  return router.state.actions[id];
1275
1275
  })();
1276
1276
 
1277
+ const loader = router.state.loaders[id] || (() => {
1278
+ router.state.loaders[id] = {
1279
+ pending: [],
1280
+ fetch: async loaderContext => {
1281
+ if (!route) {
1282
+ return;
1283
+ }
1284
+
1285
+ const loaderState = {
1286
+ loadedAt: Date.now(),
1287
+ loaderContext
1288
+ };
1289
+ loader.current = loaderState;
1290
+ loader.latest = loaderState;
1291
+ loader.pending.push(loaderState); // router.state = {
1292
+ // ...router.state,
1293
+ // currentAction: loaderState,
1294
+ // latestAction: loaderState,
1295
+ // }
1296
+
1297
+ router.notify();
1298
+
1299
+ try {
1300
+ return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
1301
+ } finally {
1302
+ loader.pending = loader.pending.filter(d => d !== loaderState); // router.removeActionQueue.push({ loader, loaderState })
1303
+
1304
+ router.notify();
1305
+ }
1306
+ }
1307
+ };
1308
+ return router.state.loaders[id];
1309
+ })();
1310
+
1277
1311
  let route = {
1278
1312
  routeId: id,
1279
1313
  routeRouteId: routeId,
@@ -1284,6 +1318,7 @@ function createRoute(routeConfig, options, parent, router) {
1284
1318
  childRoutes: undefined,
1285
1319
  parentRoute: parent,
1286
1320
  action,
1321
+ loader: loader,
1287
1322
  buildLink: options => {
1288
1323
  return router.buildLink(_extends({}, options, {
1289
1324
  from: fullPath
@@ -1379,12 +1414,10 @@ function createRouteMatch(router, route, opts) {
1379
1414
  isPending: false,
1380
1415
  isFetching: false,
1381
1416
  isInvalid: false,
1417
+ invalidAt: Infinity,
1382
1418
  getIsInvalid: () => {
1383
- var _ref, _routeMatch$options$l;
1384
-
1385
1419
  const now = Date.now();
1386
- const maxAge = (_ref = (_routeMatch$options$l = routeMatch.options.loaderMaxAge) != null ? _routeMatch$options$l : router.options.defaultLoaderMaxAge) != null ? _ref : 0;
1387
- return routeMatch.isInvalid || routeMatch.updatedAt + maxAge < now;
1420
+ return routeMatch.isInvalid || routeMatch.invalidAt < now;
1388
1421
  },
1389
1422
  __: {
1390
1423
  abortController: new AbortController(),
@@ -1473,9 +1506,33 @@ function createRouteMatch(router, route, opts) {
1473
1506
  routeMatch.isInvalid = true;
1474
1507
  },
1475
1508
  hasLoaders: () => {
1476
- return !!(route.options.loader || route.options.import || elementTypes.some(d => typeof route.options[d] === 'function'));
1509
+ return !!(route.options.loader || elementTypes.some(d => typeof route.options[d] === 'function'));
1510
+ },
1511
+ load: async loaderOpts => {
1512
+ const now = Date.now();
1513
+ 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
1514
+
1515
+ if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
1516
+ // If the match is currently active, don't preload it
1517
+ if (router.state.matches.find(d => d.matchId === routeMatch.matchId)) {
1518
+ return;
1519
+ }
1520
+
1521
+ router.matchCache[routeMatch.matchId] = {
1522
+ gc: now + loaderOpts.gcMaxAge,
1523
+ match: routeMatch
1524
+ };
1525
+ } // If the match is invalid, errored or idle, trigger it to load
1526
+
1527
+
1528
+ if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
1529
+ const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
1530
+ routeMatch.fetch({
1531
+ maxAge
1532
+ });
1533
+ }
1477
1534
  },
1478
- load: async () => {
1535
+ fetch: async opts => {
1479
1536
  const id = '' + Date.now() + Math.random();
1480
1537
  routeMatch.__.latestId = id; // If the match was in an error state, set it
1481
1538
  // to a loading state again. Otherwise, keep it
@@ -1494,21 +1551,7 @@ function createRouteMatch(router, route, opts) {
1494
1551
  routeMatch.__.resolve = resolve;
1495
1552
 
1496
1553
  const loaderPromise = (async () => {
1497
- const importer = routeMatch.options.import; // First, run any importers
1498
-
1499
- if (importer) {
1500
- routeMatch.__.importPromise = importer({
1501
- params: routeMatch.params // search: routeMatch.search,
1502
-
1503
- }).then(imported => {
1504
- routeMatch.__ = _extends({}, routeMatch.__, imported);
1505
- });
1506
- } // Wait for the importer to finish before
1507
- // attempting to load elements and data
1508
-
1509
-
1510
- await routeMatch.__.importPromise; // Next, load the elements and data in parallel
1511
-
1554
+ // Load the elements and data in parallel
1512
1555
  routeMatch.__.elementsPromise = (async () => {
1513
1556
  // then run all element and data loaders in parallel
1514
1557
  // For each element type, potentially load it asynchronously
@@ -1519,17 +1562,14 @@ function createRouteMatch(router, route, opts) {
1519
1562
  return;
1520
1563
  }
1521
1564
 
1522
- if (typeof routeElement === 'function') {
1523
- const res = await routeElement(routeMatch);
1524
- routeMatch.__[type] = res;
1525
- } else {
1526
- routeMatch.__[type] = routeMatch.options[type];
1527
- }
1565
+ routeMatch.__[type] = await router.options.createElement(routeElement);
1528
1566
  }));
1529
1567
  })();
1530
1568
 
1531
1569
  routeMatch.__.dataPromise = Promise.resolve().then(async () => {
1532
1570
  try {
1571
+ var _ref, _ref2, _opts$maxAge;
1572
+
1533
1573
  if (routeMatch.options.loader) {
1534
1574
  const data = await routeMatch.options.loader({
1535
1575
  params: routeMatch.params,
@@ -1547,6 +1587,7 @@ function createRouteMatch(router, route, opts) {
1547
1587
  routeMatch.error = undefined;
1548
1588
  routeMatch.status = 'success';
1549
1589
  routeMatch.updatedAt = Date.now();
1590
+ 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);
1550
1591
  } catch (err) {
1551
1592
  if (id !== routeMatch.__.latestId) {
1552
1593
  return routeMatch.__.loaderPromise;
@@ -1669,13 +1710,15 @@ function createRouter(userOptions) {
1669
1710
  const originalOptions = _extends({
1670
1711
  defaultLoaderGcMaxAge: 5 * 60 * 1000,
1671
1712
  defaultLoaderMaxAge: 0,
1672
- defaultLinkPreloadDelay: 50
1713
+ defaultPreloadMaxAge: 2000,
1714
+ defaultPreloadDelay: 50
1673
1715
  }, userOptions, {
1674
1716
  stringifySearch: (_userOptions$stringif = userOptions == null ? void 0 : userOptions.stringifySearch) != null ? _userOptions$stringif : defaultStringifySearch,
1675
1717
  parseSearch: (_userOptions$parseSea = userOptions == null ? void 0 : userOptions.parseSearch) != null ? _userOptions$parseSea : defaultParseSearch
1676
1718
  });
1677
1719
 
1678
1720
  let router = {
1721
+ history,
1679
1722
  options: originalOptions,
1680
1723
  listeners: [],
1681
1724
  removeActionQueue: [],
@@ -1694,6 +1737,7 @@ function createRouter(userOptions) {
1694
1737
  location: null,
1695
1738
  matches: [],
1696
1739
  actions: {},
1740
+ loaders: {},
1697
1741
  loaderData: {},
1698
1742
  lastUpdated: Date.now(),
1699
1743
  isFetching: false,
@@ -1718,21 +1762,22 @@ function createRouter(userOptions) {
1718
1762
  router.listeners.forEach(listener => listener());
1719
1763
  },
1720
1764
  mount: () => {
1721
- const next = router.buildLocation({
1765
+ const next = router.__.buildLocation({
1722
1766
  to: '.',
1723
1767
  search: true,
1724
1768
  hash: true
1725
1769
  }); // If the current location isn't updated, trigger a navigation
1726
1770
  // to the current location. Otherwise, load the current location.
1727
1771
 
1772
+
1728
1773
  if (next.href !== router.location.href) {
1729
- router.commitLocation(next, true);
1774
+ router.__.commitLocation(next, true);
1730
1775
  } else {
1731
1776
  router.loadLocation();
1732
1777
  }
1733
1778
 
1734
1779
  const unsub = history.listen(event => {
1735
- router.loadLocation(router.parseLocation(event.location, router.location));
1780
+ router.loadLocation(router.__.parseLocation(event.location, router.location));
1736
1781
  }); // addEventListener does not exist in React Native, but window does
1737
1782
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1738
1783
 
@@ -1762,169 +1807,11 @@ function createRouter(userOptions) {
1762
1807
 
1763
1808
  if (routeConfig) {
1764
1809
  router.routesById = {};
1765
- router.routeTree = router.buildRouteTree(routeConfig);
1810
+ router.routeTree = router.__.buildRouteTree(routeConfig);
1766
1811
  }
1767
1812
 
1768
1813
  return router;
1769
1814
  },
1770
- buildRouteTree: rootRouteConfig => {
1771
- const recurseRoutes = (routeConfigs, parent) => {
1772
- return routeConfigs.map(routeConfig => {
1773
- const routeOptions = routeConfig.options;
1774
- const route = createRoute(routeConfig, routeOptions, parent, router); // {
1775
- // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
1776
- // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
1777
- // }
1778
-
1779
- const existingRoute = router.routesById[route.routeId];
1780
-
1781
- if (existingRoute) {
1782
- if (process.env.NODE_ENV !== 'production') {
1783
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
1784
- }
1785
-
1786
- throw new Error();
1787
- }
1788
- router.routesById[route.routeId] = route;
1789
- const children = routeConfig.children;
1790
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
1791
- return route;
1792
- });
1793
- };
1794
-
1795
- const routes = recurseRoutes([rootRouteConfig]);
1796
- return routes[0];
1797
- },
1798
- parseLocation: (location, previousLocation) => {
1799
- var _location$hash$split$;
1800
-
1801
- const parsedSearch = router.options.parseSearch(location.search);
1802
- return {
1803
- pathname: location.pathname,
1804
- searchStr: location.search,
1805
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
1806
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
1807
- href: "" + location.pathname + location.search + location.hash,
1808
- state: location.state,
1809
- key: location.key
1810
- };
1811
- },
1812
- buildLocation: function buildLocation(dest) {
1813
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
1814
-
1815
- if (dest === void 0) {
1816
- dest = {};
1817
- }
1818
-
1819
- // const resolvedFrom: Location = {
1820
- // ...router.location,
1821
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
1822
-
1823
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1824
-
1825
- const fromMatches = router.matchRoutes(router.location.pathname, {
1826
- strictParseParams: true
1827
- });
1828
- const toMatches = router.matchRoutes(pathname);
1829
-
1830
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1831
-
1832
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1833
-
1834
- if (nextParams) {
1835
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
1836
- Object.assign({}, nextParams, fn(nextParams));
1837
- });
1838
- }
1839
-
1840
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
1841
-
1842
- 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
1843
-
1844
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1845
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
1846
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
1847
- : {}; // Then post filters
1848
-
1849
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1850
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
1851
- const searchStr = router.options.stringifySearch(search);
1852
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
1853
- hash = hash ? "#" + hash : '';
1854
- return {
1855
- pathname,
1856
- search,
1857
- searchStr,
1858
- state: router.location.state,
1859
- hash,
1860
- href: "" + pathname + searchStr + hash,
1861
- key: dest.key
1862
- };
1863
- },
1864
- commitLocation: (next, replace) => {
1865
- const id = '' + Date.now() + Math.random();
1866
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
1867
- let nextAction = 'replace';
1868
-
1869
- if (!replace) {
1870
- nextAction = 'push';
1871
- }
1872
-
1873
- const isSameUrl = router.parseLocation(history.location).href === next.href;
1874
-
1875
- if (isSameUrl && !next.key) {
1876
- nextAction = 'replace';
1877
- }
1878
-
1879
- if (nextAction === 'replace') {
1880
- history.replace({
1881
- pathname: next.pathname,
1882
- hash: next.hash,
1883
- search: next.searchStr
1884
- }, {
1885
- id
1886
- });
1887
- } else {
1888
- history.push({
1889
- pathname: next.pathname,
1890
- hash: next.hash,
1891
- search: next.searchStr
1892
- }, {
1893
- id
1894
- });
1895
- }
1896
-
1897
- router.navigationPromise = new Promise(resolve => {
1898
- const previousNavigationResolve = router.resolveNavigation;
1899
-
1900
- router.resolveNavigation = () => {
1901
- previousNavigationResolve();
1902
- resolve();
1903
- };
1904
- });
1905
- return router.navigationPromise;
1906
- },
1907
- buildNext: opts => {
1908
- const next = router.buildLocation(opts);
1909
- const matches = router.matchRoutes(next.pathname);
1910
-
1911
- const __preSearchFilters = matches.map(match => {
1912
- var _match$options$preSea;
1913
-
1914
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
1915
- }).flat().filter(Boolean);
1916
-
1917
- const __postSearchFilters = matches.map(match => {
1918
- var _match$options$postSe;
1919
-
1920
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
1921
- }).flat().filter(Boolean);
1922
-
1923
- return router.buildLocation(_extends({}, opts, {
1924
- __preSearchFilters,
1925
- __postSearchFilters
1926
- }));
1927
- },
1928
1815
  cancelMatches: () => {
1929
1816
  var _router$state$pending, _router$state$pending2;
1930
1817
  [...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 => {
@@ -2027,6 +1914,7 @@ function createRouter(userOptions) {
2027
1914
  params: d.params,
2028
1915
  search: d.search
2029
1916
  });
1917
+ delete router.matchCache[d.matchId];
2030
1918
  });
2031
1919
 
2032
1920
  if (matches.some(d => d.status === 'loading')) {
@@ -2066,7 +1954,21 @@ function createRouter(userOptions) {
2066
1954
  delete router.matchCache[matchId];
2067
1955
  });
2068
1956
  },
2069
- loadRoute: async function loadRoute(navigateOpts, loaderOpts) {
1957
+ loadRoute: async function loadRoute(navigateOpts) {
1958
+ if (navigateOpts === void 0) {
1959
+ navigateOpts = router.location;
1960
+ }
1961
+
1962
+ const next = router.buildNext(navigateOpts);
1963
+ const matches = router.matchRoutes(next.pathname, {
1964
+ strictParseParams: true
1965
+ });
1966
+ await router.loadMatches(matches);
1967
+ return matches;
1968
+ },
1969
+ preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
1970
+ var _ref4, _ref5, _loaderOpts$maxAge, _ref6, _ref7, _loaderOpts$gcMaxAge;
1971
+
2070
1972
  if (navigateOpts === void 0) {
2071
1973
  navigateOpts = router.location;
2072
1974
  }
@@ -2077,7 +1979,8 @@ function createRouter(userOptions) {
2077
1979
  });
2078
1980
  await router.loadMatches(matches, {
2079
1981
  preload: true,
2080
- maxAge: loaderOpts.maxAge
1982
+ maxAge: (_ref4 = (_ref5 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref5 : router.options.defaultLoaderMaxAge) != null ? _ref4 : 0,
1983
+ gcMaxAge: (_ref6 = (_ref7 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0
2081
1984
  });
2082
1985
  return matches;
2083
1986
  },
@@ -2171,33 +2074,11 @@ function createRouter(userOptions) {
2171
2074
  return matches;
2172
2075
  },
2173
2076
  loadMatches: async (resolvedMatches, loaderOpts) => {
2174
- const now = Date.now();
2175
2077
  const matchPromises = resolvedMatches.map(async match => {
2176
2078
  // Validate the match (loads search params etc)
2177
- match.__.validate(); // // If the match doesn't have a loader, don't attempt to load it
2178
- // if (!match.hasLoaders()) {
2179
- // return
2180
- // }
2181
- // If this is a preload, add it to the preload cache
2182
-
2183
-
2184
- if (loaderOpts != null && loaderOpts.preload && (loaderOpts == null ? void 0 : loaderOpts.maxAge) > 0) {
2185
- // If the match is currently active, don't preload it
2186
- if (router.state.matches.find(d => d.matchId === match.matchId)) {
2187
- return;
2188
- }
2189
-
2190
- router.matchCache[match.matchId] = {
2191
- gc: now + loaderOpts.maxAge,
2192
- // TODO: Should this use the route's maxAge?
2193
- match
2194
- };
2195
- } // If the match is invalid, errored or idle, trigger it to load
2196
-
2079
+ match.__.validate();
2197
2080
 
2198
- if (match.status === 'success' && match.getIsInvalid() || match.status === 'error' || match.status === 'idle') {
2199
- match.load();
2200
- }
2081
+ match.load(loaderOpts);
2201
2082
 
2202
2083
  if (match.status === 'loading') {
2203
2084
  // If requested, start the pending timers
@@ -2221,7 +2102,7 @@ function createRouter(userOptions) {
2221
2102
  }
2222
2103
  });
2223
2104
  },
2224
- reload: () => router._navigate({
2105
+ reload: () => router.__.navigate({
2225
2106
  fromCurrent: true,
2226
2107
  replace: true,
2227
2108
  search: true
@@ -2254,11 +2135,7 @@ function createRouter(userOptions) {
2254
2135
  to: next.pathname
2255
2136
  }));
2256
2137
  },
2257
- _navigate: location => {
2258
- const next = router.buildNext(location);
2259
- return router.commitLocation(next, location.replace);
2260
- },
2261
- navigate: async _ref4 => {
2138
+ navigate: async _ref8 => {
2262
2139
  let {
2263
2140
  from,
2264
2141
  to = '.',
@@ -2266,7 +2143,7 @@ function createRouter(userOptions) {
2266
2143
  hash,
2267
2144
  replace,
2268
2145
  params
2269
- } = _ref4;
2146
+ } = _ref8;
2270
2147
  // If this link simply reloads the current route,
2271
2148
  // make sure it has a new key so it will trigger a data refresh
2272
2149
  // If this `to` is a valid external URL, return
@@ -2281,7 +2158,7 @@ function createRouter(userOptions) {
2281
2158
  } catch (e) {}
2282
2159
 
2283
2160
  invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2284
- return router._navigate({
2161
+ return router.__.navigate({
2285
2162
  from: fromString,
2286
2163
  to: toString,
2287
2164
  search,
@@ -2290,8 +2167,8 @@ function createRouter(userOptions) {
2290
2167
  params
2291
2168
  });
2292
2169
  },
2293
- buildLink: _ref5 => {
2294
- var _preload, _ref6, _ref7, _ref8;
2170
+ buildLink: _ref9 => {
2171
+ var _preload, _ref10;
2295
2172
 
2296
2173
  let {
2297
2174
  from,
@@ -2304,9 +2181,10 @@ function createRouter(userOptions) {
2304
2181
  activeOptions,
2305
2182
  preload,
2306
2183
  preloadMaxAge: userPreloadMaxAge,
2184
+ preloadGcMaxAge: userPreloadGcMaxAge,
2307
2185
  preloadDelay: userPreloadDelay,
2308
2186
  disabled
2309
- } = _ref5;
2187
+ } = _ref9;
2310
2188
 
2311
2189
  // If this link simply reloads the current route,
2312
2190
  // make sure it has a new key so it will trigger a data refresh
@@ -2329,9 +2207,8 @@ function createRouter(userOptions) {
2329
2207
  replace
2330
2208
  };
2331
2209
  const next = router.buildNext(nextOpts);
2332
- preload = (_preload = preload) != null ? _preload : router.options.defaultLinkPreload;
2333
- const preloadMaxAge = (_ref6 = (_ref7 = userPreloadMaxAge != null ? userPreloadMaxAge : router.options.defaultLinkPreloadMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0;
2334
- const preloadDelay = (_ref8 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultLinkPreloadDelay) != null ? _ref8 : 0; // Compare path/hash for matches
2210
+ preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
2211
+ const preloadDelay = (_ref10 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref10 : 0; // Compare path/hash for matches
2335
2212
 
2336
2213
  const pathIsEqual = router.state.location.pathname === next.pathname;
2337
2214
  const currentPathSplit = router.state.location.pathname.split('/');
@@ -2353,15 +2230,16 @@ function createRouter(userOptions) {
2353
2230
  } // All is well? Navigate!)
2354
2231
 
2355
2232
 
2356
- router._navigate(nextOpts);
2233
+ router.__.navigate(nextOpts);
2357
2234
  }
2358
2235
  }; // The click handler
2359
2236
 
2360
2237
 
2361
2238
  const handleFocus = e => {
2362
- if (preload && preloadMaxAge > 0) {
2363
- router.loadRoute(nextOpts, {
2364
- maxAge: preloadMaxAge
2239
+ if (preload) {
2240
+ router.preloadRoute(nextOpts, {
2241
+ maxAge: userPreloadMaxAge,
2242
+ gcMaxAge: userPreloadGcMaxAge
2365
2243
  });
2366
2244
  }
2367
2245
  };
@@ -2369,15 +2247,16 @@ function createRouter(userOptions) {
2369
2247
  const handleEnter = e => {
2370
2248
  const target = e.target || {};
2371
2249
 
2372
- if (preload && preloadMaxAge > 0) {
2250
+ if (preload) {
2373
2251
  if (target.preloadTimeout) {
2374
2252
  return;
2375
2253
  }
2376
2254
 
2377
2255
  target.preloadTimeout = setTimeout(() => {
2378
2256
  target.preloadTimeout = null;
2379
- router.loadRoute(nextOpts, {
2380
- maxAge: preloadMaxAge
2257
+ router.preloadRoute(nextOpts, {
2258
+ maxAge: userPreloadMaxAge,
2259
+ gcMaxAge: userPreloadGcMaxAge
2381
2260
  });
2382
2261
  }, preloadDelay);
2383
2262
  }
@@ -2402,9 +2281,174 @@ function createRouter(userOptions) {
2402
2281
  isActive,
2403
2282
  disabled
2404
2283
  };
2284
+ },
2285
+ buildNext: opts => {
2286
+ const next = router.__.buildLocation(opts);
2287
+
2288
+ const matches = router.matchRoutes(next.pathname);
2289
+
2290
+ const __preSearchFilters = matches.map(match => {
2291
+ var _match$options$preSea;
2292
+
2293
+ return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
2294
+ }).flat().filter(Boolean);
2295
+
2296
+ const __postSearchFilters = matches.map(match => {
2297
+ var _match$options$postSe;
2298
+
2299
+ return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
2300
+ }).flat().filter(Boolean);
2301
+
2302
+ return router.__.buildLocation(_extends({}, opts, {
2303
+ __preSearchFilters,
2304
+ __postSearchFilters
2305
+ }));
2306
+ },
2307
+ __: {
2308
+ buildRouteTree: rootRouteConfig => {
2309
+ const recurseRoutes = (routeConfigs, parent) => {
2310
+ return routeConfigs.map(routeConfig => {
2311
+ const routeOptions = routeConfig.options;
2312
+ const route = createRoute(routeConfig, routeOptions, parent, router); // {
2313
+ // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
2314
+ // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
2315
+ // }
2316
+
2317
+ const existingRoute = router.routesById[route.routeId];
2318
+
2319
+ if (existingRoute) {
2320
+ if (process.env.NODE_ENV !== 'production') {
2321
+ console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
2322
+ }
2323
+
2324
+ throw new Error();
2325
+ }
2326
+ router.routesById[route.routeId] = route;
2327
+ const children = routeConfig.children;
2328
+ route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2329
+ return route;
2330
+ });
2331
+ };
2332
+
2333
+ const routes = recurseRoutes([rootRouteConfig]);
2334
+ return routes[0];
2335
+ },
2336
+ parseLocation: (location, previousLocation) => {
2337
+ var _location$hash$split$;
2338
+
2339
+ const parsedSearch = router.options.parseSearch(location.search);
2340
+ return {
2341
+ pathname: location.pathname,
2342
+ searchStr: location.search,
2343
+ search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2344
+ hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
2345
+ href: "" + location.pathname + location.search + location.hash,
2346
+ state: location.state,
2347
+ key: location.key
2348
+ };
2349
+ },
2350
+ navigate: location => {
2351
+ const next = router.buildNext(location);
2352
+ return router.__.commitLocation(next, location.replace);
2353
+ },
2354
+ buildLocation: function buildLocation(dest) {
2355
+ var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
2356
+
2357
+ if (dest === void 0) {
2358
+ dest = {};
2359
+ }
2360
+
2361
+ // const resolvedFrom: Location = {
2362
+ // ...router.location,
2363
+ const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
2364
+
2365
+ let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
2366
+
2367
+ const fromMatches = router.matchRoutes(router.location.pathname, {
2368
+ strictParseParams: true
2369
+ });
2370
+ const toMatches = router.matchRoutes(pathname);
2371
+
2372
+ const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
2373
+
2374
+ let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
2375
+
2376
+ if (nextParams) {
2377
+ toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2378
+ Object.assign({}, nextParams, fn(nextParams));
2379
+ });
2380
+ }
2381
+
2382
+ pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
2383
+
2384
+ 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
2385
+
2386
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2387
+ : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
2388
+ : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2389
+ : {}; // Then post filters
2390
+
2391
+ const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2392
+ const search = replaceEqualDeep(router.location.search, postFilteredSearch);
2393
+ const searchStr = router.options.stringifySearch(search);
2394
+ let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
2395
+ hash = hash ? "#" + hash : '';
2396
+ return {
2397
+ pathname,
2398
+ search,
2399
+ searchStr,
2400
+ state: router.location.state,
2401
+ hash,
2402
+ href: "" + pathname + searchStr + hash,
2403
+ key: dest.key
2404
+ };
2405
+ },
2406
+ commitLocation: (next, replace) => {
2407
+ const id = '' + Date.now() + Math.random();
2408
+ if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
2409
+ let nextAction = 'replace';
2410
+
2411
+ if (!replace) {
2412
+ nextAction = 'push';
2413
+ }
2414
+
2415
+ const isSameUrl = router.__.parseLocation(history.location).href === next.href;
2416
+
2417
+ if (isSameUrl && !next.key) {
2418
+ nextAction = 'replace';
2419
+ }
2420
+
2421
+ if (nextAction === 'replace') {
2422
+ history.replace({
2423
+ pathname: next.pathname,
2424
+ hash: next.hash,
2425
+ search: next.searchStr
2426
+ }, {
2427
+ id
2428
+ });
2429
+ } else {
2430
+ history.push({
2431
+ pathname: next.pathname,
2432
+ hash: next.hash,
2433
+ search: next.searchStr
2434
+ }, {
2435
+ id
2436
+ });
2437
+ }
2438
+
2439
+ router.navigationPromise = new Promise(resolve => {
2440
+ const previousNavigationResolve = router.resolveNavigation;
2441
+
2442
+ router.resolveNavigation = () => {
2443
+ previousNavigationResolve();
2444
+ resolve();
2445
+ };
2446
+ });
2447
+ return router.navigationPromise;
2448
+ }
2405
2449
  }
2406
2450
  };
2407
- router.location = router.parseLocation(history.location);
2451
+ router.location = router.__.parseLocation(history.location);
2408
2452
  router.state.location = router.location;
2409
2453
  router.update(userOptions); // Allow frameworks to hook into the router creation
2410
2454