@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.
@@ -1305,6 +1305,40 @@ function createRoute(routeConfig, options, parent, router) {
1305
1305
  return router.state.actions[id];
1306
1306
  })();
1307
1307
 
1308
+ const loader = router.state.loaders[id] || (() => {
1309
+ router.state.loaders[id] = {
1310
+ pending: [],
1311
+ fetch: async loaderContext => {
1312
+ if (!route) {
1313
+ return;
1314
+ }
1315
+
1316
+ const loaderState = {
1317
+ loadedAt: Date.now(),
1318
+ loaderContext
1319
+ };
1320
+ loader.current = loaderState;
1321
+ loader.latest = loaderState;
1322
+ loader.pending.push(loaderState); // router.state = {
1323
+ // ...router.state,
1324
+ // currentAction: loaderState,
1325
+ // latestAction: loaderState,
1326
+ // }
1327
+
1328
+ router.notify();
1329
+
1330
+ try {
1331
+ return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
1332
+ } finally {
1333
+ loader.pending = loader.pending.filter(d => d !== loaderState); // router.removeActionQueue.push({ loader, loaderState })
1334
+
1335
+ router.notify();
1336
+ }
1337
+ }
1338
+ };
1339
+ return router.state.loaders[id];
1340
+ })();
1341
+
1308
1342
  let route = {
1309
1343
  routeId: id,
1310
1344
  routeRouteId: routeId,
@@ -1315,6 +1349,7 @@ function createRoute(routeConfig, options, parent, router) {
1315
1349
  childRoutes: undefined,
1316
1350
  parentRoute: parent,
1317
1351
  action,
1352
+ loader: loader,
1318
1353
  buildLink: options => {
1319
1354
  return router.buildLink(_extends({}, options, {
1320
1355
  from: fullPath
@@ -1410,12 +1445,10 @@ function createRouteMatch(router, route, opts) {
1410
1445
  isPending: false,
1411
1446
  isFetching: false,
1412
1447
  isInvalid: false,
1448
+ invalidAt: Infinity,
1413
1449
  getIsInvalid: () => {
1414
- var _ref, _routeMatch$options$l;
1415
-
1416
1450
  const now = Date.now();
1417
- const maxAge = (_ref = (_routeMatch$options$l = routeMatch.options.loaderMaxAge) != null ? _routeMatch$options$l : router.options.defaultLoaderMaxAge) != null ? _ref : 0;
1418
- return routeMatch.isInvalid || routeMatch.updatedAt + maxAge < now;
1451
+ return routeMatch.isInvalid || routeMatch.invalidAt < now;
1419
1452
  },
1420
1453
  __: {
1421
1454
  abortController: new AbortController(),
@@ -1504,9 +1537,33 @@ function createRouteMatch(router, route, opts) {
1504
1537
  routeMatch.isInvalid = true;
1505
1538
  },
1506
1539
  hasLoaders: () => {
1507
- return !!(route.options.loader || route.options.import || elementTypes.some(d => typeof route.options[d] === 'function'));
1540
+ return !!(route.options.loader || elementTypes.some(d => typeof route.options[d] === 'function'));
1508
1541
  },
1509
- load: async () => {
1542
+ load: async loaderOpts => {
1543
+ const now = Date.now();
1544
+ 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
1545
+
1546
+ if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
1547
+ // If the match is currently active, don't preload it
1548
+ if (router.state.matches.find(d => d.matchId === routeMatch.matchId)) {
1549
+ return;
1550
+ }
1551
+
1552
+ router.matchCache[routeMatch.matchId] = {
1553
+ gc: now + loaderOpts.gcMaxAge,
1554
+ match: routeMatch
1555
+ };
1556
+ } // If the match is invalid, errored or idle, trigger it to load
1557
+
1558
+
1559
+ if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
1560
+ const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
1561
+ routeMatch.fetch({
1562
+ maxAge
1563
+ });
1564
+ }
1565
+ },
1566
+ fetch: async opts => {
1510
1567
  const id = '' + Date.now() + Math.random();
1511
1568
  routeMatch.__.latestId = id; // If the match was in an error state, set it
1512
1569
  // to a loading state again. Otherwise, keep it
@@ -1525,21 +1582,7 @@ function createRouteMatch(router, route, opts) {
1525
1582
  routeMatch.__.resolve = resolve;
1526
1583
 
1527
1584
  const loaderPromise = (async () => {
1528
- const importer = routeMatch.options.import; // First, run any importers
1529
-
1530
- if (importer) {
1531
- routeMatch.__.importPromise = importer({
1532
- params: routeMatch.params // search: routeMatch.search,
1533
-
1534
- }).then(imported => {
1535
- routeMatch.__ = _extends({}, routeMatch.__, imported);
1536
- });
1537
- } // Wait for the importer to finish before
1538
- // attempting to load elements and data
1539
-
1540
-
1541
- await routeMatch.__.importPromise; // Next, load the elements and data in parallel
1542
-
1585
+ // Load the elements and data in parallel
1543
1586
  routeMatch.__.elementsPromise = (async () => {
1544
1587
  // then run all element and data loaders in parallel
1545
1588
  // For each element type, potentially load it asynchronously
@@ -1550,17 +1593,14 @@ function createRouteMatch(router, route, opts) {
1550
1593
  return;
1551
1594
  }
1552
1595
 
1553
- if (typeof routeElement === 'function') {
1554
- const res = await routeElement(routeMatch);
1555
- routeMatch.__[type] = res;
1556
- } else {
1557
- routeMatch.__[type] = routeMatch.options[type];
1558
- }
1596
+ routeMatch.__[type] = await router.options.createElement(routeElement);
1559
1597
  }));
1560
1598
  })();
1561
1599
 
1562
1600
  routeMatch.__.dataPromise = Promise.resolve().then(async () => {
1563
1601
  try {
1602
+ var _ref, _ref2, _opts$maxAge;
1603
+
1564
1604
  if (routeMatch.options.loader) {
1565
1605
  const data = await routeMatch.options.loader({
1566
1606
  params: routeMatch.params,
@@ -1578,6 +1618,7 @@ function createRouteMatch(router, route, opts) {
1578
1618
  routeMatch.error = undefined;
1579
1619
  routeMatch.status = 'success';
1580
1620
  routeMatch.updatedAt = Date.now();
1621
+ 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);
1581
1622
  } catch (err) {
1582
1623
  if (id !== routeMatch.__.latestId) {
1583
1624
  return routeMatch.__.loaderPromise;
@@ -1700,13 +1741,15 @@ function createRouter(userOptions) {
1700
1741
  const originalOptions = _extends({
1701
1742
  defaultLoaderGcMaxAge: 5 * 60 * 1000,
1702
1743
  defaultLoaderMaxAge: 0,
1703
- defaultLinkPreloadDelay: 50
1744
+ defaultPreloadMaxAge: 2000,
1745
+ defaultPreloadDelay: 50
1704
1746
  }, userOptions, {
1705
1747
  stringifySearch: (_userOptions$stringif = userOptions == null ? void 0 : userOptions.stringifySearch) != null ? _userOptions$stringif : defaultStringifySearch,
1706
1748
  parseSearch: (_userOptions$parseSea = userOptions == null ? void 0 : userOptions.parseSearch) != null ? _userOptions$parseSea : defaultParseSearch
1707
1749
  });
1708
1750
 
1709
1751
  let router = {
1752
+ history,
1710
1753
  options: originalOptions,
1711
1754
  listeners: [],
1712
1755
  removeActionQueue: [],
@@ -1725,6 +1768,7 @@ function createRouter(userOptions) {
1725
1768
  location: null,
1726
1769
  matches: [],
1727
1770
  actions: {},
1771
+ loaders: {},
1728
1772
  loaderData: {},
1729
1773
  lastUpdated: Date.now(),
1730
1774
  isFetching: false,
@@ -1749,21 +1793,22 @@ function createRouter(userOptions) {
1749
1793
  router.listeners.forEach(listener => listener());
1750
1794
  },
1751
1795
  mount: () => {
1752
- const next = router.buildLocation({
1796
+ const next = router.__.buildLocation({
1753
1797
  to: '.',
1754
1798
  search: true,
1755
1799
  hash: true
1756
1800
  }); // If the current location isn't updated, trigger a navigation
1757
1801
  // to the current location. Otherwise, load the current location.
1758
1802
 
1803
+
1759
1804
  if (next.href !== router.location.href) {
1760
- router.commitLocation(next, true);
1805
+ router.__.commitLocation(next, true);
1761
1806
  } else {
1762
1807
  router.loadLocation();
1763
1808
  }
1764
1809
 
1765
1810
  const unsub = history.listen(event => {
1766
- router.loadLocation(router.parseLocation(event.location, router.location));
1811
+ router.loadLocation(router.__.parseLocation(event.location, router.location));
1767
1812
  }); // addEventListener does not exist in React Native, but window does
1768
1813
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1769
1814
 
@@ -1793,169 +1838,11 @@ function createRouter(userOptions) {
1793
1838
 
1794
1839
  if (routeConfig) {
1795
1840
  router.routesById = {};
1796
- router.routeTree = router.buildRouteTree(routeConfig);
1841
+ router.routeTree = router.__.buildRouteTree(routeConfig);
1797
1842
  }
1798
1843
 
1799
1844
  return router;
1800
1845
  },
1801
- buildRouteTree: rootRouteConfig => {
1802
- const recurseRoutes = (routeConfigs, parent) => {
1803
- return routeConfigs.map(routeConfig => {
1804
- const routeOptions = routeConfig.options;
1805
- const route = createRoute(routeConfig, routeOptions, parent, router); // {
1806
- // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
1807
- // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
1808
- // }
1809
-
1810
- const existingRoute = router.routesById[route.routeId];
1811
-
1812
- if (existingRoute) {
1813
- if (process.env.NODE_ENV !== 'production') {
1814
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
1815
- }
1816
-
1817
- throw new Error();
1818
- }
1819
- router.routesById[route.routeId] = route;
1820
- const children = routeConfig.children;
1821
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
1822
- return route;
1823
- });
1824
- };
1825
-
1826
- const routes = recurseRoutes([rootRouteConfig]);
1827
- return routes[0];
1828
- },
1829
- parseLocation: (location, previousLocation) => {
1830
- var _location$hash$split$;
1831
-
1832
- const parsedSearch = router.options.parseSearch(location.search);
1833
- return {
1834
- pathname: location.pathname,
1835
- searchStr: location.search,
1836
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
1837
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
1838
- href: "" + location.pathname + location.search + location.hash,
1839
- state: location.state,
1840
- key: location.key
1841
- };
1842
- },
1843
- buildLocation: function buildLocation(dest) {
1844
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
1845
-
1846
- if (dest === void 0) {
1847
- dest = {};
1848
- }
1849
-
1850
- // const resolvedFrom: Location = {
1851
- // ...router.location,
1852
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
1853
-
1854
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1855
-
1856
- const fromMatches = router.matchRoutes(router.location.pathname, {
1857
- strictParseParams: true
1858
- });
1859
- const toMatches = router.matchRoutes(pathname);
1860
-
1861
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1862
-
1863
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1864
-
1865
- if (nextParams) {
1866
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
1867
- Object.assign({}, nextParams, fn(nextParams));
1868
- });
1869
- }
1870
-
1871
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
1872
-
1873
- 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
1874
-
1875
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1876
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
1877
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
1878
- : {}; // Then post filters
1879
-
1880
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1881
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
1882
- const searchStr = router.options.stringifySearch(search);
1883
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
1884
- hash = hash ? "#" + hash : '';
1885
- return {
1886
- pathname,
1887
- search,
1888
- searchStr,
1889
- state: router.location.state,
1890
- hash,
1891
- href: "" + pathname + searchStr + hash,
1892
- key: dest.key
1893
- };
1894
- },
1895
- commitLocation: (next, replace) => {
1896
- const id = '' + Date.now() + Math.random();
1897
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
1898
- let nextAction = 'replace';
1899
-
1900
- if (!replace) {
1901
- nextAction = 'push';
1902
- }
1903
-
1904
- const isSameUrl = router.parseLocation(history.location).href === next.href;
1905
-
1906
- if (isSameUrl && !next.key) {
1907
- nextAction = 'replace';
1908
- }
1909
-
1910
- if (nextAction === 'replace') {
1911
- history.replace({
1912
- pathname: next.pathname,
1913
- hash: next.hash,
1914
- search: next.searchStr
1915
- }, {
1916
- id
1917
- });
1918
- } else {
1919
- history.push({
1920
- pathname: next.pathname,
1921
- hash: next.hash,
1922
- search: next.searchStr
1923
- }, {
1924
- id
1925
- });
1926
- }
1927
-
1928
- router.navigationPromise = new Promise(resolve => {
1929
- const previousNavigationResolve = router.resolveNavigation;
1930
-
1931
- router.resolveNavigation = () => {
1932
- previousNavigationResolve();
1933
- resolve();
1934
- };
1935
- });
1936
- return router.navigationPromise;
1937
- },
1938
- buildNext: opts => {
1939
- const next = router.buildLocation(opts);
1940
- const matches = router.matchRoutes(next.pathname);
1941
-
1942
- const __preSearchFilters = matches.map(match => {
1943
- var _match$options$preSea;
1944
-
1945
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
1946
- }).flat().filter(Boolean);
1947
-
1948
- const __postSearchFilters = matches.map(match => {
1949
- var _match$options$postSe;
1950
-
1951
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
1952
- }).flat().filter(Boolean);
1953
-
1954
- return router.buildLocation(_extends({}, opts, {
1955
- __preSearchFilters,
1956
- __postSearchFilters
1957
- }));
1958
- },
1959
1846
  cancelMatches: () => {
1960
1847
  var _router$state$pending, _router$state$pending2;
1961
1848
  [...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 => {
@@ -2058,6 +1945,7 @@ function createRouter(userOptions) {
2058
1945
  params: d.params,
2059
1946
  search: d.search
2060
1947
  });
1948
+ delete router.matchCache[d.matchId];
2061
1949
  });
2062
1950
 
2063
1951
  if (matches.some(d => d.status === 'loading')) {
@@ -2097,7 +1985,21 @@ function createRouter(userOptions) {
2097
1985
  delete router.matchCache[matchId];
2098
1986
  });
2099
1987
  },
2100
- loadRoute: async function loadRoute(navigateOpts, loaderOpts) {
1988
+ loadRoute: async function loadRoute(navigateOpts) {
1989
+ if (navigateOpts === void 0) {
1990
+ navigateOpts = router.location;
1991
+ }
1992
+
1993
+ const next = router.buildNext(navigateOpts);
1994
+ const matches = router.matchRoutes(next.pathname, {
1995
+ strictParseParams: true
1996
+ });
1997
+ await router.loadMatches(matches);
1998
+ return matches;
1999
+ },
2000
+ preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
2001
+ var _ref4, _ref5, _loaderOpts$maxAge, _ref6, _ref7, _loaderOpts$gcMaxAge;
2002
+
2101
2003
  if (navigateOpts === void 0) {
2102
2004
  navigateOpts = router.location;
2103
2005
  }
@@ -2108,7 +2010,8 @@ function createRouter(userOptions) {
2108
2010
  });
2109
2011
  await router.loadMatches(matches, {
2110
2012
  preload: true,
2111
- maxAge: loaderOpts.maxAge
2013
+ maxAge: (_ref4 = (_ref5 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref5 : router.options.defaultLoaderMaxAge) != null ? _ref4 : 0,
2014
+ gcMaxAge: (_ref6 = (_ref7 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0
2112
2015
  });
2113
2016
  return matches;
2114
2017
  },
@@ -2202,33 +2105,11 @@ function createRouter(userOptions) {
2202
2105
  return matches;
2203
2106
  },
2204
2107
  loadMatches: async (resolvedMatches, loaderOpts) => {
2205
- const now = Date.now();
2206
2108
  const matchPromises = resolvedMatches.map(async match => {
2207
2109
  // Validate the match (loads search params etc)
2208
- match.__.validate(); // // If the match doesn't have a loader, don't attempt to load it
2209
- // if (!match.hasLoaders()) {
2210
- // return
2211
- // }
2212
- // If this is a preload, add it to the preload cache
2213
-
2214
-
2215
- if (loaderOpts != null && loaderOpts.preload && (loaderOpts == null ? void 0 : loaderOpts.maxAge) > 0) {
2216
- // If the match is currently active, don't preload it
2217
- if (router.state.matches.find(d => d.matchId === match.matchId)) {
2218
- return;
2219
- }
2110
+ match.__.validate();
2220
2111
 
2221
- router.matchCache[match.matchId] = {
2222
- gc: now + loaderOpts.maxAge,
2223
- // TODO: Should this use the route's maxAge?
2224
- match
2225
- };
2226
- } // If the match is invalid, errored or idle, trigger it to load
2227
-
2228
-
2229
- if (match.status === 'success' && match.getIsInvalid() || match.status === 'error' || match.status === 'idle') {
2230
- match.load();
2231
- }
2112
+ match.load(loaderOpts);
2232
2113
 
2233
2114
  if (match.status === 'loading') {
2234
2115
  // If requested, start the pending timers
@@ -2252,7 +2133,7 @@ function createRouter(userOptions) {
2252
2133
  }
2253
2134
  });
2254
2135
  },
2255
- reload: () => router._navigate({
2136
+ reload: () => router.__.navigate({
2256
2137
  fromCurrent: true,
2257
2138
  replace: true,
2258
2139
  search: true
@@ -2285,11 +2166,7 @@ function createRouter(userOptions) {
2285
2166
  to: next.pathname
2286
2167
  }));
2287
2168
  },
2288
- _navigate: location => {
2289
- const next = router.buildNext(location);
2290
- return router.commitLocation(next, location.replace);
2291
- },
2292
- navigate: async _ref4 => {
2169
+ navigate: async _ref8 => {
2293
2170
  let {
2294
2171
  from,
2295
2172
  to = '.',
@@ -2297,7 +2174,7 @@ function createRouter(userOptions) {
2297
2174
  hash,
2298
2175
  replace,
2299
2176
  params
2300
- } = _ref4;
2177
+ } = _ref8;
2301
2178
  // If this link simply reloads the current route,
2302
2179
  // make sure it has a new key so it will trigger a data refresh
2303
2180
  // If this `to` is a valid external URL, return
@@ -2312,7 +2189,7 @@ function createRouter(userOptions) {
2312
2189
  } catch (e) {}
2313
2190
 
2314
2191
  invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2315
- return router._navigate({
2192
+ return router.__.navigate({
2316
2193
  from: fromString,
2317
2194
  to: toString,
2318
2195
  search,
@@ -2321,8 +2198,8 @@ function createRouter(userOptions) {
2321
2198
  params
2322
2199
  });
2323
2200
  },
2324
- buildLink: _ref5 => {
2325
- var _preload, _ref6, _ref7, _ref8;
2201
+ buildLink: _ref9 => {
2202
+ var _preload, _ref10;
2326
2203
 
2327
2204
  let {
2328
2205
  from,
@@ -2335,9 +2212,10 @@ function createRouter(userOptions) {
2335
2212
  activeOptions,
2336
2213
  preload,
2337
2214
  preloadMaxAge: userPreloadMaxAge,
2215
+ preloadGcMaxAge: userPreloadGcMaxAge,
2338
2216
  preloadDelay: userPreloadDelay,
2339
2217
  disabled
2340
- } = _ref5;
2218
+ } = _ref9;
2341
2219
 
2342
2220
  // If this link simply reloads the current route,
2343
2221
  // make sure it has a new key so it will trigger a data refresh
@@ -2360,9 +2238,8 @@ function createRouter(userOptions) {
2360
2238
  replace
2361
2239
  };
2362
2240
  const next = router.buildNext(nextOpts);
2363
- preload = (_preload = preload) != null ? _preload : router.options.defaultLinkPreload;
2364
- const preloadMaxAge = (_ref6 = (_ref7 = userPreloadMaxAge != null ? userPreloadMaxAge : router.options.defaultLinkPreloadMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0;
2365
- const preloadDelay = (_ref8 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultLinkPreloadDelay) != null ? _ref8 : 0; // Compare path/hash for matches
2241
+ preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
2242
+ const preloadDelay = (_ref10 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref10 : 0; // Compare path/hash for matches
2366
2243
 
2367
2244
  const pathIsEqual = router.state.location.pathname === next.pathname;
2368
2245
  const currentPathSplit = router.state.location.pathname.split('/');
@@ -2384,15 +2261,16 @@ function createRouter(userOptions) {
2384
2261
  } // All is well? Navigate!)
2385
2262
 
2386
2263
 
2387
- router._navigate(nextOpts);
2264
+ router.__.navigate(nextOpts);
2388
2265
  }
2389
2266
  }; // The click handler
2390
2267
 
2391
2268
 
2392
2269
  const handleFocus = e => {
2393
- if (preload && preloadMaxAge > 0) {
2394
- router.loadRoute(nextOpts, {
2395
- maxAge: preloadMaxAge
2270
+ if (preload) {
2271
+ router.preloadRoute(nextOpts, {
2272
+ maxAge: userPreloadMaxAge,
2273
+ gcMaxAge: userPreloadGcMaxAge
2396
2274
  });
2397
2275
  }
2398
2276
  };
@@ -2400,15 +2278,16 @@ function createRouter(userOptions) {
2400
2278
  const handleEnter = e => {
2401
2279
  const target = e.target || {};
2402
2280
 
2403
- if (preload && preloadMaxAge > 0) {
2281
+ if (preload) {
2404
2282
  if (target.preloadTimeout) {
2405
2283
  return;
2406
2284
  }
2407
2285
 
2408
2286
  target.preloadTimeout = setTimeout(() => {
2409
2287
  target.preloadTimeout = null;
2410
- router.loadRoute(nextOpts, {
2411
- maxAge: preloadMaxAge
2288
+ router.preloadRoute(nextOpts, {
2289
+ maxAge: userPreloadMaxAge,
2290
+ gcMaxAge: userPreloadGcMaxAge
2412
2291
  });
2413
2292
  }, preloadDelay);
2414
2293
  }
@@ -2433,9 +2312,174 @@ function createRouter(userOptions) {
2433
2312
  isActive,
2434
2313
  disabled
2435
2314
  };
2315
+ },
2316
+ buildNext: opts => {
2317
+ const next = router.__.buildLocation(opts);
2318
+
2319
+ const matches = router.matchRoutes(next.pathname);
2320
+
2321
+ const __preSearchFilters = matches.map(match => {
2322
+ var _match$options$preSea;
2323
+
2324
+ return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
2325
+ }).flat().filter(Boolean);
2326
+
2327
+ const __postSearchFilters = matches.map(match => {
2328
+ var _match$options$postSe;
2329
+
2330
+ return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
2331
+ }).flat().filter(Boolean);
2332
+
2333
+ return router.__.buildLocation(_extends({}, opts, {
2334
+ __preSearchFilters,
2335
+ __postSearchFilters
2336
+ }));
2337
+ },
2338
+ __: {
2339
+ buildRouteTree: rootRouteConfig => {
2340
+ const recurseRoutes = (routeConfigs, parent) => {
2341
+ return routeConfigs.map(routeConfig => {
2342
+ const routeOptions = routeConfig.options;
2343
+ const route = createRoute(routeConfig, routeOptions, parent, router); // {
2344
+ // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
2345
+ // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
2346
+ // }
2347
+
2348
+ const existingRoute = router.routesById[route.routeId];
2349
+
2350
+ if (existingRoute) {
2351
+ if (process.env.NODE_ENV !== 'production') {
2352
+ console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
2353
+ }
2354
+
2355
+ throw new Error();
2356
+ }
2357
+ router.routesById[route.routeId] = route;
2358
+ const children = routeConfig.children;
2359
+ route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2360
+ return route;
2361
+ });
2362
+ };
2363
+
2364
+ const routes = recurseRoutes([rootRouteConfig]);
2365
+ return routes[0];
2366
+ },
2367
+ parseLocation: (location, previousLocation) => {
2368
+ var _location$hash$split$;
2369
+
2370
+ const parsedSearch = router.options.parseSearch(location.search);
2371
+ return {
2372
+ pathname: location.pathname,
2373
+ searchStr: location.search,
2374
+ search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2375
+ hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
2376
+ href: "" + location.pathname + location.search + location.hash,
2377
+ state: location.state,
2378
+ key: location.key
2379
+ };
2380
+ },
2381
+ navigate: location => {
2382
+ const next = router.buildNext(location);
2383
+ return router.__.commitLocation(next, location.replace);
2384
+ },
2385
+ buildLocation: function buildLocation(dest) {
2386
+ var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
2387
+
2388
+ if (dest === void 0) {
2389
+ dest = {};
2390
+ }
2391
+
2392
+ // const resolvedFrom: Location = {
2393
+ // ...router.location,
2394
+ const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
2395
+
2396
+ let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
2397
+
2398
+ const fromMatches = router.matchRoutes(router.location.pathname, {
2399
+ strictParseParams: true
2400
+ });
2401
+ const toMatches = router.matchRoutes(pathname);
2402
+
2403
+ const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
2404
+
2405
+ let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
2406
+
2407
+ if (nextParams) {
2408
+ toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2409
+ Object.assign({}, nextParams, fn(nextParams));
2410
+ });
2411
+ }
2412
+
2413
+ pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
2414
+
2415
+ 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
2416
+
2417
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2418
+ : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
2419
+ : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2420
+ : {}; // Then post filters
2421
+
2422
+ const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2423
+ const search = replaceEqualDeep(router.location.search, postFilteredSearch);
2424
+ const searchStr = router.options.stringifySearch(search);
2425
+ let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
2426
+ hash = hash ? "#" + hash : '';
2427
+ return {
2428
+ pathname,
2429
+ search,
2430
+ searchStr,
2431
+ state: router.location.state,
2432
+ hash,
2433
+ href: "" + pathname + searchStr + hash,
2434
+ key: dest.key
2435
+ };
2436
+ },
2437
+ commitLocation: (next, replace) => {
2438
+ const id = '' + Date.now() + Math.random();
2439
+ if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
2440
+ let nextAction = 'replace';
2441
+
2442
+ if (!replace) {
2443
+ nextAction = 'push';
2444
+ }
2445
+
2446
+ const isSameUrl = router.__.parseLocation(history.location).href === next.href;
2447
+
2448
+ if (isSameUrl && !next.key) {
2449
+ nextAction = 'replace';
2450
+ }
2451
+
2452
+ if (nextAction === 'replace') {
2453
+ history.replace({
2454
+ pathname: next.pathname,
2455
+ hash: next.hash,
2456
+ search: next.searchStr
2457
+ }, {
2458
+ id
2459
+ });
2460
+ } else {
2461
+ history.push({
2462
+ pathname: next.pathname,
2463
+ hash: next.hash,
2464
+ search: next.searchStr
2465
+ }, {
2466
+ id
2467
+ });
2468
+ }
2469
+
2470
+ router.navigationPromise = new Promise(resolve => {
2471
+ const previousNavigationResolve = router.resolveNavigation;
2472
+
2473
+ router.resolveNavigation = () => {
2474
+ previousNavigationResolve();
2475
+ resolve();
2476
+ };
2477
+ });
2478
+ return router.navigationPromise;
2479
+ }
2436
2480
  }
2437
2481
  };
2438
- router.location = router.parseLocation(history.location);
2482
+ router.location = router.__.parseLocation(history.location);
2439
2483
  router.state.location = router.location;
2440
2484
  router.update(userOptions); // Allow frameworks to hook into the router creation
2441
2485
 
@@ -2467,6 +2511,17 @@ const useRouterSubscription = router => {
2467
2511
  function createReactRouter(opts) {
2468
2512
  const makeRouteExt = (route, router) => {
2469
2513
  return {
2514
+ useRoute: function useRoute(subRouteId) {
2515
+ if (subRouteId === void 0) {
2516
+ subRouteId = '.';
2517
+ }
2518
+
2519
+ const resolvedRouteId = router.resolvePath(route.routeId, subRouteId);
2520
+ const resolvedRoute = router.getRoute(resolvedRouteId);
2521
+ useRouterSubscription(router);
2522
+ invariant(resolvedRoute, "Could not find a route for route \"" + resolvedRouteId + "\"! Did you forget to add it to your route config?");
2523
+ return resolvedRoute;
2524
+ },
2470
2525
  linkProps: options => {
2471
2526
  var _functionalUpdate, _functionalUpdate2;
2472
2527
 
@@ -2574,12 +2629,6 @@ function createReactRouter(opts) {
2574
2629
  useRouterSubscription(router);
2575
2630
  return router.state;
2576
2631
  },
2577
- useRoute: routeId => {
2578
- const route = router.getRoute(routeId);
2579
- useRouterSubscription(router);
2580
- invariant(route, "Could not find a route for route \"" + routeId + "\"! Did you forget to add it to your route config?");
2581
- return route;
2582
- },
2583
2632
  useMatch: routeId => {
2584
2633
  useRouterSubscription(router);
2585
2634
  invariant(routeId !== rootRouteId, "\"" + rootRouteId + "\" cannot be used with useMatch! Did you mean to useRoute(\"" + rootRouteId + "\")?");
@@ -2607,6 +2656,19 @@ function createReactRouter(opts) {
2607
2656
  } = _ref;
2608
2657
  const routeExt = makeRouteExt(route, router);
2609
2658
  Object.assign(route, routeExt);
2659
+ },
2660
+ createElement: async element => {
2661
+ if (typeof element === 'function') {
2662
+ const res = await element(); // Support direct import() calls
2663
+
2664
+ if (typeof res === 'object' && res.default) {
2665
+ return /*#__PURE__*/React.createElement(res.default);
2666
+ } else {
2667
+ return res;
2668
+ }
2669
+ }
2670
+
2671
+ return element;
2610
2672
  }
2611
2673
  }));
2612
2674
  return coreRouter;
@@ -2791,7 +2853,31 @@ function DefaultErrorBoundary(_ref5) {
2791
2853
  opacity: 0.5
2792
2854
  }
2793
2855
  }, "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."));
2794
- } // TODO: Add prompt
2856
+ }
2857
+ function usePrompt(message, when) {
2858
+ const router = useRouter();
2859
+ React.useEffect(() => {
2860
+ if (!when) return;
2861
+ let unblock = router.history.block(transition => {
2862
+ if (window.confirm(message)) {
2863
+ unblock();
2864
+ transition.retry();
2865
+ } else {
2866
+ router.location.pathname = window.location.pathname;
2867
+ }
2868
+ });
2869
+ return unblock;
2870
+ }, [when, location, message]);
2871
+ }
2872
+ function Prompt(_ref6) {
2873
+ let {
2874
+ message,
2875
+ when,
2876
+ children
2877
+ } = _ref6;
2878
+ usePrompt(message, when != null ? when : true);
2879
+ return children != null ? children : null;
2880
+ }
2795
2881
 
2796
- export { DefaultErrorBoundary, MatchesProvider, Outlet, RouterProvider, cascadeLoaderData, cleanPath, createBrowserHistory, createHashHistory, createMemoryHistory, createReactRouter, createRoute, createRouteConfig, createRouteMatch, createRouter, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, invariant, joinPaths, last, matchByPath, matchPathname, parsePathname, parseSearchWith, replaceEqualDeep, resolvePath, rootRouteId, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, warning };
2882
+ export { DefaultErrorBoundary, MatchesProvider, Outlet, Prompt, RouterProvider, cascadeLoaderData, cleanPath, createBrowserHistory, createHashHistory, createMemoryHistory, createReactRouter, createRoute, createRouteConfig, createRouteMatch, createRouter, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, invariant, joinPaths, last, matchByPath, matchPathname, parsePathname, parseSearchWith, replaceEqualDeep, resolvePath, rootRouteId, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, usePrompt, warning };
2797
2883
  //# sourceMappingURL=index.js.map